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.

522 lines
13 KiB

  1. /* XzEnc.c -- Xz Encode
  2. 2014-12-30 : Igor Pavlov : Public domain */
  3. #include "Precomp.h"
  4. #include <stdlib.h>
  5. #include <string.h>
  6. #include "7zCrc.h"
  7. #include "Alloc.h"
  8. #include "Bra.h"
  9. #include "CpuArch.h"
  10. #ifdef USE_SUBBLOCK
  11. #include "Bcj3Enc.c"
  12. #include "SbFind.c"
  13. #include "SbEnc.c"
  14. #endif
  15. #include "XzEnc.h"
  16. static void *SzBigAlloc(void *p, size_t size) { p = p; return BigAlloc(size); }
  17. static void SzBigFree(void *p, void *address) { p = p; BigFree(address); }
  18. static ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
  19. static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
  20. static void SzFree(void *p, void *address) { p = p; MyFree(address); }
  21. static ISzAlloc g_Alloc = { SzAlloc, SzFree };
  22. #define XzBlock_ClearFlags(p) (p)->flags = 0;
  23. #define XzBlock_SetNumFilters(p, n) (p)->flags |= ((n) - 1);
  24. #define XzBlock_SetHasPackSize(p) (p)->flags |= XZ_BF_PACK_SIZE;
  25. #define XzBlock_SetHasUnpackSize(p) (p)->flags |= XZ_BF_UNPACK_SIZE;
  26. static SRes WriteBytes(ISeqOutStream *s, const void *buf, UInt32 size)
  27. {
  28. return (s->Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE;
  29. }
  30. static SRes WriteBytesAndCrc(ISeqOutStream *s, const void *buf, UInt32 size, UInt32 *crc)
  31. {
  32. *crc = CrcUpdate(*crc, buf, size);
  33. return WriteBytes(s, buf, size);
  34. }
  35. SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s)
  36. {
  37. UInt32 crc;
  38. Byte header[XZ_STREAM_HEADER_SIZE];
  39. memcpy(header, XZ_SIG, XZ_SIG_SIZE);
  40. header[XZ_SIG_SIZE] = (Byte)(f >> 8);
  41. header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF);
  42. crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE);
  43. SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc);
  44. return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE);
  45. }
  46. SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s)
  47. {
  48. Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
  49. unsigned pos = 1;
  50. int numFilters, i;
  51. header[pos++] = p->flags;
  52. if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize);
  53. if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize);
  54. numFilters = XzBlock_GetNumFilters(p);
  55. for (i = 0; i < numFilters; i++)
  56. {
  57. const CXzFilter *f = &p->filters[i];
  58. pos += Xz_WriteVarInt(header + pos, f->id);
  59. pos += Xz_WriteVarInt(header + pos, f->propsSize);
  60. memcpy(header + pos, f->props, f->propsSize);
  61. pos += f->propsSize;
  62. }
  63. while((pos & 3) != 0)
  64. header[pos++] = 0;
  65. header[0] = (Byte)(pos >> 2);
  66. SetUi32(header + pos, CrcCalc(header, pos));
  67. return WriteBytes(s, header, pos + 4);
  68. }
  69. SRes Xz_WriteFooter(CXzStream *p, ISeqOutStream *s)
  70. {
  71. Byte buf[32];
  72. UInt64 globalPos;
  73. {
  74. UInt32 crc = CRC_INIT_VAL;
  75. unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks);
  76. size_t i;
  77. globalPos = pos;
  78. buf[0] = 0;
  79. RINOK(WriteBytesAndCrc(s, buf, pos, &crc));
  80. for (i = 0; i < p->numBlocks; i++)
  81. {
  82. const CXzBlockSizes *block = &p->blocks[i];
  83. pos = Xz_WriteVarInt(buf, block->totalSize);
  84. pos += Xz_WriteVarInt(buf + pos, block->unpackSize);
  85. globalPos += pos;
  86. RINOK(WriteBytesAndCrc(s, buf, pos, &crc));
  87. }
  88. pos = ((unsigned)globalPos & 3);
  89. if (pos != 0)
  90. {
  91. buf[0] = buf[1] = buf[2] = 0;
  92. RINOK(WriteBytesAndCrc(s, buf, 4 - pos, &crc));
  93. globalPos += 4 - pos;
  94. }
  95. {
  96. SetUi32(buf, CRC_GET_DIGEST(crc));
  97. RINOK(WriteBytes(s, buf, 4));
  98. globalPos += 4;
  99. }
  100. }
  101. {
  102. UInt32 indexSize = (UInt32)((globalPos >> 2) - 1);
  103. SetUi32(buf + 4, indexSize);
  104. buf[8] = (Byte)(p->flags >> 8);
  105. buf[9] = (Byte)(p->flags & 0xFF);
  106. SetUi32(buf, CrcCalc(buf + 4, 6));
  107. memcpy(buf + 10, XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE);
  108. return WriteBytes(s, buf, 12);
  109. }
  110. }
  111. SRes Xz_AddIndexRecord(CXzStream *p, UInt64 unpackSize, UInt64 totalSize, ISzAlloc *alloc)
  112. {
  113. if (p->blocks == 0 || p->numBlocksAllocated == p->numBlocks)
  114. {
  115. size_t num = (p->numBlocks + 1) * 2;
  116. size_t newSize = sizeof(CXzBlockSizes) * num;
  117. CXzBlockSizes *blocks;
  118. if (newSize / sizeof(CXzBlockSizes) != num)
  119. return SZ_ERROR_MEM;
  120. blocks = (CXzBlockSizes *)alloc->Alloc(alloc, newSize);
  121. if (blocks == 0)
  122. return SZ_ERROR_MEM;
  123. if (p->numBlocks != 0)
  124. {
  125. memcpy(blocks, p->blocks, p->numBlocks * sizeof(CXzBlockSizes));
  126. Xz_Free(p, alloc);
  127. }
  128. p->blocks = blocks;
  129. p->numBlocksAllocated = num;
  130. }
  131. {
  132. CXzBlockSizes *block = &p->blocks[p->numBlocks++];
  133. block->totalSize = totalSize;
  134. block->unpackSize = unpackSize;
  135. }
  136. return SZ_OK;
  137. }
  138. /* ---------- CSeqCheckInStream ---------- */
  139. typedef struct
  140. {
  141. ISeqInStream p;
  142. ISeqInStream *realStream;
  143. UInt64 processed;
  144. CXzCheck check;
  145. } CSeqCheckInStream;
  146. void SeqCheckInStream_Init(CSeqCheckInStream *p, int mode)
  147. {
  148. p->processed = 0;
  149. XzCheck_Init(&p->check, mode);
  150. }
  151. void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest)
  152. {
  153. XzCheck_Final(&p->check, digest);
  154. }
  155. static SRes SeqCheckInStream_Read(void *pp, void *data, size_t *size)
  156. {
  157. CSeqCheckInStream *p = (CSeqCheckInStream *)pp;
  158. SRes res = p->realStream->Read(p->realStream, data, size);
  159. XzCheck_Update(&p->check, data, *size);
  160. p->processed += *size;
  161. return res;
  162. }
  163. /* ---------- CSeqSizeOutStream ---------- */
  164. typedef struct
  165. {
  166. ISeqOutStream p;
  167. ISeqOutStream *realStream;
  168. UInt64 processed;
  169. } CSeqSizeOutStream;
  170. static size_t MyWrite(void *pp, const void *data, size_t size)
  171. {
  172. CSeqSizeOutStream *p = (CSeqSizeOutStream *)pp;
  173. size = p->realStream->Write(p->realStream, data, size);
  174. p->processed += size;
  175. return size;
  176. }
  177. /* ---------- CSeqInFilter ---------- */
  178. #define FILTER_BUF_SIZE (1 << 20)
  179. typedef struct
  180. {
  181. ISeqInStream p;
  182. ISeqInStream *realStream;
  183. IStateCoder StateCoder;
  184. Byte *buf;
  185. size_t curPos;
  186. size_t endPos;
  187. int srcWasFinished;
  188. } CSeqInFilter;
  189. static SRes SeqInFilter_Read(void *pp, void *data, size_t *size)
  190. {
  191. CSeqInFilter *p = (CSeqInFilter *)pp;
  192. size_t sizeOriginal = *size;
  193. if (sizeOriginal == 0)
  194. return SZ_OK;
  195. *size = 0;
  196. for (;;)
  197. {
  198. if (!p->srcWasFinished && p->curPos == p->endPos)
  199. {
  200. p->curPos = 0;
  201. p->endPos = FILTER_BUF_SIZE;
  202. RINOK(p->realStream->Read(p->realStream, p->buf, &p->endPos));
  203. if (p->endPos == 0)
  204. p->srcWasFinished = 1;
  205. }
  206. {
  207. SizeT srcLen = p->endPos - p->curPos;
  208. int wasFinished;
  209. SRes res;
  210. *size = sizeOriginal;
  211. res = p->StateCoder.Code(p->StateCoder.p, data, size, p->buf + p->curPos, &srcLen,
  212. p->srcWasFinished, CODER_FINISH_ANY, &wasFinished);
  213. p->curPos += srcLen;
  214. if (*size != 0 || srcLen == 0 || res != 0)
  215. return res;
  216. }
  217. }
  218. }
  219. static void SeqInFilter_Construct(CSeqInFilter *p)
  220. {
  221. p->buf = NULL;
  222. p->p.Read = SeqInFilter_Read;
  223. }
  224. static void SeqInFilter_Free(CSeqInFilter *p)
  225. {
  226. if (p->buf)
  227. {
  228. g_Alloc.Free(&g_Alloc, p->buf);
  229. p->buf = NULL;
  230. }
  231. }
  232. SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAlloc *alloc);
  233. static SRes SeqInFilter_Init(CSeqInFilter *p, const CXzFilter *props)
  234. {
  235. if (!p->buf)
  236. {
  237. p->buf = g_Alloc.Alloc(&g_Alloc, FILTER_BUF_SIZE);
  238. if (!p->buf)
  239. return SZ_ERROR_MEM;
  240. }
  241. p->curPos = p->endPos = 0;
  242. p->srcWasFinished = 0;
  243. RINOK(BraState_SetFromMethod(&p->StateCoder, props->id, 1, &g_Alloc));
  244. RINOK(p->StateCoder.SetProps(p->StateCoder.p, props->props, props->propsSize, &g_Alloc));
  245. p->StateCoder.Init(p->StateCoder.p);
  246. return SZ_OK;
  247. }
  248. /* ---------- CSbEncInStream ---------- */
  249. #ifdef USE_SUBBLOCK
  250. typedef struct
  251. {
  252. ISeqInStream p;
  253. ISeqInStream *inStream;
  254. CSbEnc enc;
  255. } CSbEncInStream;
  256. static SRes SbEncInStream_Read(void *pp, void *data, size_t *size)
  257. {
  258. CSbEncInStream *p = (CSbEncInStream *)pp;
  259. size_t sizeOriginal = *size;
  260. if (sizeOriginal == 0)
  261. return S_OK;
  262. for (;;)
  263. {
  264. if (p->enc.needRead && !p->enc.readWasFinished)
  265. {
  266. size_t processed = p->enc.needReadSizeMax;
  267. RINOK(p->inStream->Read(p->inStream, p->enc.buf + p->enc.readPos, &processed));
  268. p->enc.readPos += processed;
  269. if (processed == 0)
  270. {
  271. p->enc.readWasFinished = True;
  272. p->enc.isFinalFinished = True;
  273. }
  274. p->enc.needRead = False;
  275. }
  276. *size = sizeOriginal;
  277. RINOK(SbEnc_Read(&p->enc, data, size));
  278. if (*size != 0 || !p->enc.needRead)
  279. return S_OK;
  280. }
  281. }
  282. void SbEncInStream_Construct(CSbEncInStream *p, ISzAlloc *alloc)
  283. {
  284. SbEnc_Construct(&p->enc, alloc);
  285. p->p.Read = SbEncInStream_Read;
  286. }
  287. SRes SbEncInStream_Init(CSbEncInStream *p)
  288. {
  289. return SbEnc_Init(&p->enc);
  290. }
  291. void SbEncInStream_Free(CSbEncInStream *p)
  292. {
  293. SbEnc_Free(&p->enc);
  294. }
  295. #endif
  296. typedef struct
  297. {
  298. CLzma2EncHandle lzma2;
  299. #ifdef USE_SUBBLOCK
  300. CSbEncInStream sb;
  301. #endif
  302. CSeqInFilter filter;
  303. ISzAlloc *alloc;
  304. ISzAlloc *bigAlloc;
  305. } CLzma2WithFilters;
  306. static void Lzma2WithFilters_Construct(CLzma2WithFilters *p, ISzAlloc *alloc, ISzAlloc *bigAlloc)
  307. {
  308. p->alloc = alloc;
  309. p->bigAlloc = bigAlloc;
  310. p->lzma2 = NULL;
  311. #ifdef USE_SUBBLOCK
  312. SbEncInStream_Construct(&p->sb, alloc);
  313. #endif
  314. SeqInFilter_Construct(&p->filter);
  315. }
  316. static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p)
  317. {
  318. p->lzma2 = Lzma2Enc_Create(p->alloc, p->bigAlloc);
  319. if (p->lzma2 == 0)
  320. return SZ_ERROR_MEM;
  321. return SZ_OK;
  322. }
  323. static void Lzma2WithFilters_Free(CLzma2WithFilters *p)
  324. {
  325. SeqInFilter_Free(&p->filter);
  326. #ifdef USE_SUBBLOCK
  327. SbEncInStream_Free(&p->sb);
  328. #endif
  329. if (p->lzma2)
  330. {
  331. Lzma2Enc_Destroy(p->lzma2);
  332. p->lzma2 = NULL;
  333. }
  334. }
  335. void XzProps_Init(CXzProps *p)
  336. {
  337. p->lzma2Props = 0;
  338. p->filterProps = 0;
  339. p->checkId = XZ_CHECK_CRC32;
  340. }
  341. void XzFilterProps_Init(CXzFilterProps *p)
  342. {
  343. p->id = 0;
  344. p->delta = 0;
  345. p->ip= 0;
  346. p->ipDefined = False;
  347. }
  348. static SRes Xz_Compress(CXzStream *xz, CLzma2WithFilters *lzmaf,
  349. ISeqOutStream *outStream, ISeqInStream *inStream,
  350. const CXzProps *props, ICompressProgress *progress)
  351. {
  352. xz->flags = (Byte)props->checkId;
  353. RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, props->lzma2Props));
  354. RINOK(Xz_WriteHeader(xz->flags, outStream));
  355. {
  356. CSeqCheckInStream checkInStream;
  357. CSeqSizeOutStream seqSizeOutStream;
  358. CXzBlock block;
  359. int filterIndex = 0;
  360. CXzFilter *filter = NULL;
  361. const CXzFilterProps *fp = props->filterProps;
  362. XzBlock_ClearFlags(&block);
  363. XzBlock_SetNumFilters(&block, 1 + (fp ? 1 : 0));
  364. if (fp)
  365. {
  366. filter = &block.filters[filterIndex++];
  367. filter->id = fp->id;
  368. filter->propsSize = 0;
  369. if (fp->id == XZ_ID_Delta)
  370. {
  371. filter->props[0] = (Byte)(fp->delta - 1);
  372. filter->propsSize = 1;
  373. }
  374. else if (fp->ipDefined)
  375. {
  376. SetUi32(filter->props, fp->ip);
  377. filter->propsSize = 4;
  378. }
  379. }
  380. {
  381. CXzFilter *f = &block.filters[filterIndex++];
  382. f->id = XZ_ID_LZMA2;
  383. f->propsSize = 1;
  384. f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2);
  385. }
  386. seqSizeOutStream.p.Write = MyWrite;
  387. seqSizeOutStream.realStream = outStream;
  388. seqSizeOutStream.processed = 0;
  389. RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.p));
  390. checkInStream.p.Read = SeqCheckInStream_Read;
  391. checkInStream.realStream = inStream;
  392. SeqCheckInStream_Init(&checkInStream, XzFlags_GetCheckType(xz->flags));
  393. if (fp)
  394. {
  395. #ifdef USE_SUBBLOCK
  396. if (fp->id == XZ_ID_Subblock)
  397. {
  398. lzmaf->sb.inStream = &checkInStream.p;
  399. RINOK(SbEncInStream_Init(&lzmaf->sb));
  400. }
  401. else
  402. #endif
  403. {
  404. lzmaf->filter.realStream = &checkInStream.p;
  405. RINOK(SeqInFilter_Init(&lzmaf->filter, filter));
  406. }
  407. }
  408. {
  409. UInt64 packPos = seqSizeOutStream.processed;
  410. SRes res = Lzma2Enc_Encode(lzmaf->lzma2, &seqSizeOutStream.p,
  411. fp ?
  412. #ifdef USE_SUBBLOCK
  413. (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.p:
  414. #endif
  415. &lzmaf->filter.p:
  416. &checkInStream.p,
  417. progress);
  418. RINOK(res);
  419. block.unpackSize = checkInStream.processed;
  420. block.packSize = seqSizeOutStream.processed - packPos;
  421. }
  422. {
  423. unsigned padSize = 0;
  424. Byte buf[128];
  425. while((((unsigned)block.packSize + padSize) & 3) != 0)
  426. buf[padSize++] = 0;
  427. SeqCheckInStream_GetDigest(&checkInStream, buf + padSize);
  428. RINOK(WriteBytes(&seqSizeOutStream.p, buf, padSize + XzFlags_GetCheckSize(xz->flags)));
  429. RINOK(Xz_AddIndexRecord(xz, block.unpackSize, seqSizeOutStream.processed - padSize, &g_Alloc));
  430. }
  431. }
  432. return Xz_WriteFooter(xz, outStream);
  433. }
  434. SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream,
  435. const CXzProps *props, ICompressProgress *progress)
  436. {
  437. SRes res;
  438. CXzStream xz;
  439. CLzma2WithFilters lzmaf;
  440. Xz_Construct(&xz);
  441. Lzma2WithFilters_Construct(&lzmaf, &g_Alloc, &g_BigAlloc);
  442. res = Lzma2WithFilters_Create(&lzmaf);
  443. if (res == SZ_OK)
  444. res = Xz_Compress(&xz, &lzmaf, outStream, inStream, props, progress);
  445. Lzma2WithFilters_Free(&lzmaf);
  446. Xz_Free(&xz, &g_Alloc);
  447. return res;
  448. }
  449. SRes Xz_EncodeEmpty(ISeqOutStream *outStream)
  450. {
  451. SRes res;
  452. CXzStream xz;
  453. Xz_Construct(&xz);
  454. res = Xz_WriteHeader(xz.flags, outStream);
  455. if (res == SZ_OK)
  456. res = Xz_WriteFooter(&xz, outStream);
  457. Xz_Free(&xz, &g_Alloc);
  458. return res;
  459. }