7zDecode.c 9.1 KB

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