Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

493 lines
13 KiB

  1. /* 7zDec.c -- Decoding from 7z folder
  2. 2014-06-16 : Igor Pavlov : Public domain */
  3. #include "Precomp.h"
  4. #include <string.h>
  5. /* #define _7ZIP_PPMD_SUPPPORT */
  6. #include "7z.h"
  7. #include "Bcj2.h"
  8. #include "Bra.h"
  9. #include "CpuArch.h"
  10. #include "LzmaDec.h"
  11. #include "Lzma2Dec.h"
  12. #ifdef _7ZIP_PPMD_SUPPPORT
  13. #include "Ppmd7.h"
  14. #endif
  15. #define k_Copy 0
  16. #define k_LZMA2 0x21
  17. #define k_LZMA 0x30101
  18. #define k_BCJ 0x03030103
  19. #define k_PPC 0x03030205
  20. #define k_ARM 0x03030501
  21. #define k_ARMT 0x03030701
  22. #define k_SPARC 0x03030805
  23. #define k_BCJ2 0x0303011B
  24. #ifdef _7ZIP_PPMD_SUPPPORT
  25. #define k_PPMD 0x30401
  26. typedef struct
  27. {
  28. IByteIn p;
  29. const Byte *cur;
  30. const Byte *end;
  31. const Byte *begin;
  32. UInt64 processed;
  33. Bool extra;
  34. SRes res;
  35. ILookInStream *inStream;
  36. } CByteInToLook;
  37. static Byte ReadByte(void *pp)
  38. {
  39. CByteInToLook *p = (CByteInToLook *)pp;
  40. if (p->cur != p->end)
  41. return *p->cur++;
  42. if (p->res == SZ_OK)
  43. {
  44. size_t size = p->cur - p->begin;
  45. p->processed += size;
  46. p->res = p->inStream->Skip(p->inStream, size);
  47. size = (1 << 25);
  48. p->res = p->inStream->Look(p->inStream, (const void **)&p->begin, &size);
  49. p->cur = p->begin;
  50. p->end = p->begin + size;
  51. if (size != 0)
  52. return *p->cur++;;
  53. }
  54. p->extra = True;
  55. return 0;
  56. }
  57. static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
  58. Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
  59. {
  60. CPpmd7 ppmd;
  61. CByteInToLook s;
  62. SRes res = SZ_OK;
  63. s.p.Read = ReadByte;
  64. s.inStream = inStream;
  65. s.begin = s.end = s.cur = NULL;
  66. s.extra = False;
  67. s.res = SZ_OK;
  68. s.processed = 0;
  69. if (propsSize != 5)
  70. return SZ_ERROR_UNSUPPORTED;
  71. {
  72. unsigned order = props[0];
  73. UInt32 memSize = GetUi32(props + 1);
  74. if (order < PPMD7_MIN_ORDER ||
  75. order > PPMD7_MAX_ORDER ||
  76. memSize < PPMD7_MIN_MEM_SIZE ||
  77. memSize > PPMD7_MAX_MEM_SIZE)
  78. return SZ_ERROR_UNSUPPORTED;
  79. Ppmd7_Construct(&ppmd);
  80. if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
  81. return SZ_ERROR_MEM;
  82. Ppmd7_Init(&ppmd, order);
  83. }
  84. {
  85. CPpmd7z_RangeDec rc;
  86. Ppmd7z_RangeDec_CreateVTable(&rc);
  87. rc.Stream = &s.p;
  88. if (!Ppmd7z_RangeDec_Init(&rc))
  89. res = SZ_ERROR_DATA;
  90. else if (s.extra)
  91. res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
  92. else
  93. {
  94. SizeT i;
  95. for (i = 0; i < outSize; i++)
  96. {
  97. int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.p);
  98. if (s.extra || sym < 0)
  99. break;
  100. outBuffer[i] = (Byte)sym;
  101. }
  102. if (i != outSize)
  103. res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
  104. else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc))
  105. res = SZ_ERROR_DATA;
  106. }
  107. }
  108. Ppmd7_Free(&ppmd, allocMain);
  109. return res;
  110. }
  111. #endif
  112. static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
  113. Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
  114. {
  115. CLzmaDec state;
  116. SRes res = SZ_OK;
  117. LzmaDec_Construct(&state);
  118. RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain));
  119. state.dic = outBuffer;
  120. state.dicBufSize = outSize;
  121. LzmaDec_Init(&state);
  122. for (;;)
  123. {
  124. Byte *inBuf = NULL;
  125. size_t lookahead = (1 << 18);
  126. if (lookahead > inSize)
  127. lookahead = (size_t)inSize;
  128. res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
  129. if (res != SZ_OK)
  130. break;
  131. {
  132. SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
  133. ELzmaStatus status;
  134. res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
  135. lookahead -= inProcessed;
  136. inSize -= inProcessed;
  137. if (res != SZ_OK)
  138. break;
  139. if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos))
  140. {
  141. if (state.dicBufSize != outSize || lookahead != 0 ||
  142. (status != LZMA_STATUS_FINISHED_WITH_MARK &&
  143. status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
  144. res = SZ_ERROR_DATA;
  145. break;
  146. }
  147. res = inStream->Skip((void *)inStream, inProcessed);
  148. if (res != SZ_OK)
  149. break;
  150. }
  151. }
  152. LzmaDec_FreeProbs(&state, allocMain);
  153. return res;
  154. }
  155. static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
  156. Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain)
  157. {
  158. CLzma2Dec state;
  159. SRes res = SZ_OK;
  160. Lzma2Dec_Construct(&state);
  161. if (propsSize != 1)
  162. return SZ_ERROR_DATA;
  163. RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain));
  164. state.decoder.dic = outBuffer;
  165. state.decoder.dicBufSize = outSize;
  166. Lzma2Dec_Init(&state);
  167. for (;;)
  168. {
  169. Byte *inBuf = NULL;
  170. size_t lookahead = (1 << 18);
  171. if (lookahead > inSize)
  172. lookahead = (size_t)inSize;
  173. res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead);
  174. if (res != SZ_OK)
  175. break;
  176. {
  177. SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
  178. ELzmaStatus status;
  179. res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status);
  180. lookahead -= inProcessed;
  181. inSize -= inProcessed;
  182. if (res != SZ_OK)
  183. break;
  184. if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos))
  185. {
  186. if (state.decoder.dicBufSize != outSize || lookahead != 0 ||
  187. (status != LZMA_STATUS_FINISHED_WITH_MARK))
  188. res = SZ_ERROR_DATA;
  189. break;
  190. }
  191. res = inStream->Skip((void *)inStream, inProcessed);
  192. if (res != SZ_OK)
  193. break;
  194. }
  195. }
  196. Lzma2Dec_FreeProbs(&state, allocMain);
  197. return res;
  198. }
  199. static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
  200. {
  201. while (inSize > 0)
  202. {
  203. void *inBuf;
  204. size_t curSize = (1 << 18);
  205. if (curSize > inSize)
  206. curSize = (size_t)inSize;
  207. RINOK(inStream->Look((void *)inStream, (const void **)&inBuf, &curSize));
  208. if (curSize == 0)
  209. return SZ_ERROR_INPUT_EOF;
  210. memcpy(outBuffer, inBuf, curSize);
  211. outBuffer += curSize;
  212. inSize -= curSize;
  213. RINOK(inStream->Skip((void *)inStream, curSize));
  214. }
  215. return SZ_OK;
  216. }
  217. static Bool IS_MAIN_METHOD(UInt32 m)
  218. {
  219. switch (m)
  220. {
  221. case k_Copy:
  222. case k_LZMA:
  223. case k_LZMA2:
  224. #ifdef _7ZIP_PPMD_SUPPPORT
  225. case k_PPMD:
  226. #endif
  227. return True;
  228. }
  229. return False;
  230. }
  231. static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c)
  232. {
  233. return
  234. c->NumInStreams == 1 &&
  235. c->NumOutStreams == 1 &&
  236. /* c->MethodID <= (UInt32)0xFFFFFFFF && */
  237. IS_MAIN_METHOD((UInt32)c->MethodID);
  238. }
  239. #define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1)
  240. static SRes CheckSupportedFolder(const CSzFolder *f)
  241. {
  242. if (f->NumCoders < 1 || f->NumCoders > 4)
  243. return SZ_ERROR_UNSUPPORTED;
  244. if (!IS_SUPPORTED_CODER(&f->Coders[0]))
  245. return SZ_ERROR_UNSUPPORTED;
  246. if (f->NumCoders == 1)
  247. {
  248. if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0)
  249. return SZ_ERROR_UNSUPPORTED;
  250. return SZ_OK;
  251. }
  252. if (f->NumCoders == 2)
  253. {
  254. const CSzCoderInfo *c = &f->Coders[1];
  255. if (
  256. /* c->MethodID > (UInt32)0xFFFFFFFF || */
  257. c->NumInStreams != 1 ||
  258. c->NumOutStreams != 1 ||
  259. f->NumPackStreams != 1 ||
  260. f->PackStreams[0] != 0 ||
  261. f->NumBindPairs != 1 ||
  262. f->BindPairs[0].InIndex != 1 ||
  263. f->BindPairs[0].OutIndex != 0)
  264. return SZ_ERROR_UNSUPPORTED;
  265. switch ((UInt32)c->MethodID)
  266. {
  267. case k_BCJ:
  268. case k_ARM:
  269. break;
  270. default:
  271. return SZ_ERROR_UNSUPPORTED;
  272. }
  273. return SZ_OK;
  274. }
  275. if (f->NumCoders == 4)
  276. {
  277. if (!IS_SUPPORTED_CODER(&f->Coders[1]) ||
  278. !IS_SUPPORTED_CODER(&f->Coders[2]) ||
  279. !IS_BCJ2(&f->Coders[3]))
  280. return SZ_ERROR_UNSUPPORTED;
  281. if (f->NumPackStreams != 4 ||
  282. f->PackStreams[0] != 2 ||
  283. f->PackStreams[1] != 6 ||
  284. f->PackStreams[2] != 1 ||
  285. f->PackStreams[3] != 0 ||
  286. f->NumBindPairs != 3 ||
  287. f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 ||
  288. f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 ||
  289. f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2)
  290. return SZ_ERROR_UNSUPPORTED;
  291. return SZ_OK;
  292. }
  293. return SZ_ERROR_UNSUPPORTED;
  294. }
  295. #define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
  296. static SRes SzFolder_Decode2(const CSzFolder *folder,
  297. const Byte *propsData,
  298. const UInt64 *unpackSizes,
  299. const UInt64 *packPositions,
  300. ILookInStream *inStream, UInt64 startPos,
  301. Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain,
  302. Byte *tempBuf[])
  303. {
  304. UInt32 ci;
  305. SizeT tempSizes[3] = { 0, 0, 0};
  306. SizeT tempSize3 = 0;
  307. Byte *tempBuf3 = 0;
  308. RINOK(CheckSupportedFolder(folder));
  309. for (ci = 0; ci < folder->NumCoders; ci++)
  310. {
  311. const CSzCoderInfo *coder = &folder->Coders[ci];
  312. if (IS_MAIN_METHOD((UInt32)coder->MethodID))
  313. {
  314. UInt32 si = 0;
  315. UInt64 offset;
  316. UInt64 inSize;
  317. Byte *outBufCur = outBuffer;
  318. SizeT outSizeCur = outSize;
  319. if (folder->NumCoders == 4)
  320. {
  321. UInt32 indices[] = { 3, 2, 0 };
  322. UInt64 unpackSize = unpackSizes[ci];
  323. si = indices[ci];
  324. if (ci < 2)
  325. {
  326. Byte *temp;
  327. outSizeCur = (SizeT)unpackSize;
  328. if (outSizeCur != unpackSize)
  329. return SZ_ERROR_MEM;
  330. temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur);
  331. if (temp == 0 && outSizeCur != 0)
  332. return SZ_ERROR_MEM;
  333. outBufCur = tempBuf[1 - ci] = temp;
  334. tempSizes[1 - ci] = outSizeCur;
  335. }
  336. else if (ci == 2)
  337. {
  338. if (unpackSize > outSize) /* check it */
  339. return SZ_ERROR_PARAM;
  340. tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
  341. tempSize3 = outSizeCur = (SizeT)unpackSize;
  342. }
  343. else
  344. return SZ_ERROR_UNSUPPORTED;
  345. }
  346. offset = packPositions[si];
  347. inSize = packPositions[si + 1] - offset;
  348. RINOK(LookInStream_SeekTo(inStream, startPos + offset));
  349. if (coder->MethodID == k_Copy)
  350. {
  351. if (inSize != outSizeCur) /* check it */
  352. return SZ_ERROR_DATA;
  353. RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
  354. }
  355. else if (coder->MethodID == k_LZMA)
  356. {
  357. RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
  358. }
  359. else if (coder->MethodID == k_LZMA2)
  360. {
  361. RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
  362. }
  363. else
  364. {
  365. #ifdef _7ZIP_PPMD_SUPPPORT
  366. RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
  367. #else
  368. return SZ_ERROR_UNSUPPORTED;
  369. #endif
  370. }
  371. }
  372. else if (coder->MethodID == k_BCJ2)
  373. {
  374. UInt64 offset = packPositions[1];
  375. UInt64 s3Size = packPositions[2] - offset;
  376. SRes res;
  377. if (ci != 3)
  378. return SZ_ERROR_UNSUPPORTED;
  379. RINOK(LookInStream_SeekTo(inStream, startPos + offset));
  380. tempSizes[2] = (SizeT)s3Size;
  381. if (tempSizes[2] != s3Size)
  382. return SZ_ERROR_MEM;
  383. tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]);
  384. if (tempBuf[2] == 0 && tempSizes[2] != 0)
  385. return SZ_ERROR_MEM;
  386. res = SzDecodeCopy(s3Size, inStream, tempBuf[2]);
  387. RINOK(res)
  388. res = Bcj2_Decode(
  389. tempBuf3, tempSize3,
  390. tempBuf[0], tempSizes[0],
  391. tempBuf[1], tempSizes[1],
  392. tempBuf[2], tempSizes[2],
  393. outBuffer, outSize);
  394. RINOK(res)
  395. }
  396. else
  397. {
  398. if (ci != 1)
  399. return SZ_ERROR_UNSUPPORTED;
  400. switch (coder->MethodID)
  401. {
  402. case k_BCJ:
  403. {
  404. UInt32 state;
  405. x86_Convert_Init(state);
  406. x86_Convert(outBuffer, outSize, 0, &state, 0);
  407. break;
  408. }
  409. CASE_BRA_CONV(ARM)
  410. default:
  411. return SZ_ERROR_UNSUPPORTED;
  412. }
  413. }
  414. }
  415. return SZ_OK;
  416. }
  417. SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
  418. ILookInStream *inStream, UInt64 startPos,
  419. Byte *outBuffer, size_t outSize,
  420. ISzAlloc *allocMain)
  421. {
  422. SRes res;
  423. CSzFolder folder;
  424. CSzData sd;
  425. CSzData sdSizes;
  426. const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex];
  427. sd.Data = data;
  428. sd.Size = p->FoCodersOffsets[folderIndex + 1] - p->FoCodersOffsets[folderIndex];
  429. sdSizes.Data = p->UnpackSizesData + p->FoSizesOffsets[folderIndex];
  430. sdSizes.Size =
  431. p->FoSizesOffsets[folderIndex + 1] -
  432. p->FoSizesOffsets[folderIndex];
  433. res = SzGetNextFolderItem(&folder, &sd, &sdSizes);
  434. if (res != SZ_OK)
  435. return res;
  436. if (sd.Size != 0 || outSize != folder.CodersUnpackSizes[folder.MainOutStream])
  437. return SZ_ERROR_FAIL;
  438. {
  439. int i;
  440. Byte *tempBuf[3] = { 0, 0, 0};
  441. res = SzFolder_Decode2(&folder, data, folder.CodersUnpackSizes,
  442. p->PackPositions + p->FoStartPackStreamIndex[folderIndex],
  443. inStream, startPos,
  444. outBuffer, (SizeT)outSize, allocMain, tempBuf);
  445. for (i = 0; i < 3; i++)
  446. IAlloc_Free(allocMain, tempBuf[i]);
  447. return res;
  448. }
  449. }