7zDecode.c 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. /* 7zDecode.c */
  2. #include <memory.h>
  3. /* BEGIN PHYSFS CHANGE */
  4. #include <string.h>
  5. /* END PHYSFS CHANGE */
  6. #include "7zDecode.h"
  7. #ifdef _SZ_ONE_DIRECTORY
  8. #include "LzmaDecode.h"
  9. #else
  10. #include "../../Compress/Lzma/LzmaDecode.h"
  11. #include "../../Compress/Branch/BranchX86.h"
  12. #include "../../Compress/Branch/BranchX86_2.h"
  13. #endif
  14. #define k_Copy 0
  15. #define k_LZMA 0x30101
  16. #define k_BCJ 0x03030103
  17. #define k_BCJ2 0x0303011B
  18. #ifdef _LZMA_IN_CB
  19. typedef struct _CLzmaInCallbackImp
  20. {
  21. ILzmaInCallback InCallback;
  22. ISzInStream *InStream;
  23. CFileSize Size;
  24. } CLzmaInCallbackImp;
  25. int LzmaReadImp(void *object, const unsigned char **buffer, SizeT *size)
  26. {
  27. CLzmaInCallbackImp *cb = (CLzmaInCallbackImp *)object;
  28. size_t processedSize;
  29. SZ_RESULT res;
  30. size_t curSize = (1 << 20);
  31. if (curSize > cb->Size)
  32. curSize = (size_t)cb->Size;
  33. *size = 0;
  34. res = cb->InStream->Read((void *)cb->InStream, (void **)buffer, curSize, &processedSize);
  35. *size = (SizeT)processedSize;
  36. if (processedSize > curSize)
  37. return (int)SZE_FAIL;
  38. cb->Size -= processedSize;
  39. if (res == SZ_OK)
  40. return 0;
  41. return (int)res;
  42. }
  43. #endif
  44. SZ_RESULT SzDecodeLzma(CCoderInfo *coder, CFileSize inSize,
  45. #ifdef _LZMA_IN_CB
  46. ISzInStream *inStream,
  47. #else
  48. const Byte *inBuffer,
  49. #endif
  50. Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
  51. {
  52. #ifdef _LZMA_IN_CB
  53. CLzmaInCallbackImp lzmaCallback;
  54. #else
  55. SizeT inProcessed;
  56. #endif
  57. CLzmaDecoderState state; /* it's about 24-80 bytes structure, if int is 32-bit */
  58. int result;
  59. SizeT outSizeProcessedLoc;
  60. #ifdef _LZMA_IN_CB
  61. lzmaCallback.Size = inSize;
  62. lzmaCallback.InStream = inStream;
  63. lzmaCallback.InCallback.Read = LzmaReadImp;
  64. #endif
  65. if (LzmaDecodeProperties(&state.Properties, coder->Properties.Items,
  66. (unsigned)coder->Properties.Capacity) != LZMA_RESULT_OK)
  67. return SZE_FAIL;
  68. state.Probs = (CProb *)allocMain->Alloc(LzmaGetNumProbs(&state.Properties) * sizeof(CProb));
  69. if (state.Probs == 0)
  70. return SZE_OUTOFMEMORY;
  71. #ifdef _LZMA_OUT_READ
  72. if (state.Properties.DictionarySize == 0)
  73. state.Dictionary = 0;
  74. else
  75. {
  76. state.Dictionary = (unsigned char *)allocMain->Alloc(state.Properties.DictionarySize);
  77. if (state.Dictionary == 0)
  78. {
  79. allocMain->Free(state.Probs);
  80. return SZE_OUTOFMEMORY;
  81. }
  82. }
  83. LzmaDecoderInit(&state);
  84. #endif
  85. result = LzmaDecode(&state,
  86. #ifdef _LZMA_IN_CB
  87. &lzmaCallback.InCallback,
  88. #else
  89. inBuffer, (SizeT)inSize, &inProcessed,
  90. #endif
  91. outBuffer, (SizeT)outSize, &outSizeProcessedLoc);
  92. allocMain->Free(state.Probs);
  93. #ifdef _LZMA_OUT_READ
  94. allocMain->Free(state.Dictionary);
  95. #endif
  96. if (result == LZMA_RESULT_DATA_ERROR)
  97. return SZE_DATA_ERROR;
  98. if (result != LZMA_RESULT_OK)
  99. return SZE_FAIL;
  100. return (outSizeProcessedLoc == outSize) ? SZ_OK : SZE_DATA_ERROR;
  101. }
  102. #ifdef _LZMA_IN_CB
  103. SZ_RESULT SzDecodeCopy(CFileSize inSize, ISzInStream *inStream, Byte *outBuffer)
  104. {
  105. while (inSize > 0)
  106. {
  107. void *inBuffer;
  108. size_t processedSize, curSize = (1 << 18);
  109. if (curSize > inSize)
  110. curSize = (size_t)(inSize);
  111. RINOK(inStream->Read((void *)inStream, (void **)&inBuffer, curSize, &processedSize));
  112. if (processedSize == 0)
  113. return SZE_DATA_ERROR;
  114. if (processedSize > curSize)
  115. return SZE_FAIL;
  116. memcpy(outBuffer, inBuffer, processedSize);
  117. outBuffer += processedSize;
  118. inSize -= processedSize;
  119. }
  120. return SZ_OK;
  121. }
  122. #endif
  123. #define IS_UNSUPPORTED_METHOD(m) ((m) != k_Copy && (m) != k_LZMA)
  124. #define IS_UNSUPPORTED_CODER(c) (IS_UNSUPPORTED_METHOD(c.MethodID) || c.NumInStreams != 1 || c.NumOutStreams != 1)
  125. #define IS_NO_BCJ(c) (c.MethodID != k_BCJ || c.NumInStreams != 1 || c.NumOutStreams != 1)
  126. #define IS_NO_BCJ2(c) (c.MethodID != k_BCJ2 || c.NumInStreams != 4 || c.NumOutStreams != 1)
  127. SZ_RESULT CheckSupportedFolder(const CFolder *f)
  128. {
  129. if (f->NumCoders < 1 || f->NumCoders > 4)
  130. return SZE_NOTIMPL;
  131. if (IS_UNSUPPORTED_CODER(f->Coders[0]))
  132. return SZE_NOTIMPL;
  133. if (f->NumCoders == 1)
  134. {
  135. if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0)
  136. return SZE_NOTIMPL;
  137. return SZ_OK;
  138. }
  139. if (f->NumCoders == 2)
  140. {
  141. if (IS_NO_BCJ(f->Coders[1]) ||
  142. f->NumPackStreams != 1 || f->PackStreams[0] != 0 ||
  143. f->NumBindPairs != 1 ||
  144. f->BindPairs[0].InIndex != 1 || f->BindPairs[0].OutIndex != 0)
  145. return SZE_NOTIMPL;
  146. return SZ_OK;
  147. }
  148. if (f->NumCoders == 4)
  149. {
  150. if (IS_UNSUPPORTED_CODER(f->Coders[1]) ||
  151. IS_UNSUPPORTED_CODER(f->Coders[2]) ||
  152. IS_NO_BCJ2(f->Coders[3]))
  153. return SZE_NOTIMPL;
  154. if (f->NumPackStreams != 4 ||
  155. f->PackStreams[0] != 2 ||
  156. f->PackStreams[1] != 6 ||
  157. f->PackStreams[2] != 1 ||
  158. f->PackStreams[3] != 0 ||
  159. f->NumBindPairs != 3 ||
  160. f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 ||
  161. f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 ||
  162. f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2)
  163. return SZE_NOTIMPL;
  164. return SZ_OK;
  165. }
  166. return SZE_NOTIMPL;
  167. }
  168. CFileSize GetSum(const CFileSize *values, UInt32 index)
  169. {
  170. CFileSize sum = 0;
  171. UInt32 i;
  172. for (i = 0; i < index; i++)
  173. sum += values[i];
  174. return sum;
  175. }
  176. SZ_RESULT SzDecode2(const CFileSize *packSizes, const CFolder *folder,
  177. #ifdef _LZMA_IN_CB
  178. ISzInStream *inStream, CFileSize startPos,
  179. #else
  180. const Byte *inBuffer,
  181. #endif
  182. Byte *outBuffer, size_t outSize, ISzAlloc *allocMain,
  183. Byte *tempBuf[])
  184. {
  185. UInt32 ci;
  186. size_t tempSizes[3] = { 0, 0, 0};
  187. size_t tempSize3 = 0;
  188. Byte *tempBuf3 = 0;
  189. RINOK(CheckSupportedFolder(folder));
  190. for (ci = 0; ci < folder->NumCoders; ci++)
  191. {
  192. CCoderInfo *coder = &folder->Coders[ci];
  193. if (coder->MethodID == k_Copy || coder->MethodID == k_LZMA)
  194. {
  195. UInt32 si = 0;
  196. CFileSize offset;
  197. CFileSize inSize;
  198. Byte *outBufCur = outBuffer;
  199. size_t outSizeCur = outSize;
  200. if (folder->NumCoders == 4)
  201. {
  202. UInt32 indices[] = { 3, 2, 0 };
  203. CFileSize unpackSize = folder->UnPackSizes[ci];
  204. si = indices[ci];
  205. if (ci < 2)
  206. {
  207. Byte *temp;
  208. outSizeCur = (size_t)unpackSize;
  209. if (outSizeCur != unpackSize)
  210. return SZE_OUTOFMEMORY;
  211. temp = (Byte *)allocMain->Alloc(outSizeCur);
  212. if (temp == 0 && outSizeCur != 0)
  213. return SZE_OUTOFMEMORY;
  214. outBufCur = tempBuf[1 - ci] = temp;
  215. tempSizes[1 - ci] = outSizeCur;
  216. }
  217. else if (ci == 2)
  218. {
  219. if (unpackSize > outSize)
  220. return SZE_OUTOFMEMORY;
  221. tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
  222. tempSize3 = outSizeCur = (size_t)unpackSize;
  223. }
  224. else
  225. return SZE_NOTIMPL;
  226. }
  227. offset = GetSum(packSizes, si);
  228. inSize = packSizes[si];
  229. #ifdef _LZMA_IN_CB
  230. RINOK(inStream->Seek(inStream, startPos + offset));
  231. #endif
  232. if (coder->MethodID == k_Copy)
  233. {
  234. if (inSize != outSizeCur)
  235. return SZE_DATA_ERROR;
  236. #ifdef _LZMA_IN_CB
  237. RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
  238. #else
  239. memcpy(outBufCur, inBuffer + (size_t)offset, (size_t)inSize);
  240. #endif
  241. }
  242. else
  243. {
  244. SZ_RESULT res = SzDecodeLzma(coder, inSize,
  245. #ifdef _LZMA_IN_CB
  246. inStream,
  247. #else
  248. inBuffer + (size_t)offset,
  249. #endif
  250. outBufCur, outSizeCur, allocMain);
  251. RINOK(res)
  252. }
  253. }
  254. else if (coder->MethodID == k_BCJ)
  255. {
  256. UInt32 state;
  257. if (ci != 1)
  258. return SZE_NOTIMPL;
  259. x86_Convert_Init(state);
  260. x86_Convert(outBuffer, outSize, 0, &state, 0);
  261. }
  262. else if (coder->MethodID == k_BCJ2)
  263. {
  264. CFileSize offset = GetSum(packSizes, 1);
  265. CFileSize s3Size = packSizes[1];
  266. SZ_RESULT res;
  267. if (ci != 3)
  268. return SZE_NOTIMPL;
  269. #ifdef _LZMA_IN_CB
  270. RINOK(inStream->Seek(inStream, startPos + offset));
  271. tempSizes[2] = (size_t)s3Size;
  272. if (tempSizes[2] != s3Size)
  273. return SZE_OUTOFMEMORY;
  274. tempBuf[2] = (Byte *)allocMain->Alloc(tempSizes[2]);
  275. if (tempBuf[2] == 0 && tempSizes[2] != 0)
  276. return SZE_OUTOFMEMORY;
  277. res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
  278. RINOK(res)
  279. #endif
  280. res = x86_2_Decode(
  281. tempBuf3, tempSize3,
  282. tempBuf[0], tempSizes[0],
  283. tempBuf[1], tempSizes[1],
  284. #ifdef _LZMA_IN_CB
  285. tempBuf[2], tempSizes[2],
  286. #else
  287. inBuffer + (size_t)offset, (size_t)s3Size,
  288. #endif
  289. outBuffer, outSize);
  290. RINOK(res)
  291. }
  292. else
  293. return SZE_NOTIMPL;
  294. }
  295. return SZ_OK;
  296. }
  297. SZ_RESULT SzDecode(const CFileSize *packSizes, const CFolder *folder,
  298. #ifdef _LZMA_IN_CB
  299. ISzInStream *inStream, CFileSize startPos,
  300. #else
  301. const Byte *inBuffer,
  302. #endif
  303. Byte *outBuffer, size_t outSize, ISzAlloc *allocMain)
  304. {
  305. Byte *tempBuf[3] = { 0, 0, 0};
  306. int i;
  307. SZ_RESULT res = SzDecode2(packSizes, folder,
  308. #ifdef _LZMA_IN_CB
  309. inStream, startPos,
  310. #else
  311. inBuffer,
  312. #endif
  313. outBuffer, outSize, allocMain, tempBuf);
  314. for (i = 0; i < 3; i++)
  315. allocMain->Free(tempBuf[i]);
  316. return res;
  317. }