diff options
author | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2021-12-27 00:00:00 +0000 |
---|---|---|
committer | Igor Pavlov <87184205+ip7z@users.noreply.github.com> | 2022-03-18 15:35:13 +0500 |
commit | f19f813537c7aea1c20749c914e756b54a9c3cf5 (patch) | |
tree | 816ba62ca7c0fa19f2eb46d9e9d6f7dd7c3a744d /C/Lzma2Enc.c | |
parent | 98e06a519b63b81986abe76d28887f6984a7732b (diff) | |
download | 7zip-21.07.tar.gz 7zip-21.07.tar.bz2 7zip-21.07.zip |
'21.07'21.07
Diffstat (limited to '')
-rw-r--r-- | C/Lzma2Enc.c | 803 |
1 files changed, 803 insertions, 0 deletions
diff --git a/C/Lzma2Enc.c b/C/Lzma2Enc.c new file mode 100644 index 0000000..e61a5df --- /dev/null +++ b/C/Lzma2Enc.c | |||
@@ -0,0 +1,803 @@ | |||
1 | /* Lzma2Enc.c -- LZMA2 Encoder | ||
2 | 2021-02-09 : Igor Pavlov : Public domain */ | ||
3 | |||
4 | #include "Precomp.h" | ||
5 | |||
6 | #include <string.h> | ||
7 | |||
8 | /* #define _7ZIP_ST */ | ||
9 | |||
10 | #include "Lzma2Enc.h" | ||
11 | |||
12 | #ifndef _7ZIP_ST | ||
13 | #include "MtCoder.h" | ||
14 | #else | ||
15 | #define MTCODER__THREADS_MAX 1 | ||
16 | #endif | ||
17 | |||
18 | #define LZMA2_CONTROL_LZMA (1 << 7) | ||
19 | #define LZMA2_CONTROL_COPY_NO_RESET 2 | ||
20 | #define LZMA2_CONTROL_COPY_RESET_DIC 1 | ||
21 | #define LZMA2_CONTROL_EOF 0 | ||
22 | |||
23 | #define LZMA2_LCLP_MAX 4 | ||
24 | |||
25 | #define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) | ||
26 | |||
27 | #define LZMA2_PACK_SIZE_MAX (1 << 16) | ||
28 | #define LZMA2_COPY_CHUNK_SIZE LZMA2_PACK_SIZE_MAX | ||
29 | #define LZMA2_UNPACK_SIZE_MAX (1 << 21) | ||
30 | #define LZMA2_KEEP_WINDOW_SIZE LZMA2_UNPACK_SIZE_MAX | ||
31 | |||
32 | #define LZMA2_CHUNK_SIZE_COMPRESSED_MAX ((1 << 16) + 16) | ||
33 | |||
34 | |||
35 | #define PRF(x) /* x */ | ||
36 | |||
37 | |||
38 | /* ---------- CLimitedSeqInStream ---------- */ | ||
39 | |||
40 | typedef struct | ||
41 | { | ||
42 | ISeqInStream vt; | ||
43 | ISeqInStream *realStream; | ||
44 | UInt64 limit; | ||
45 | UInt64 processed; | ||
46 | int finished; | ||
47 | } CLimitedSeqInStream; | ||
48 | |||
49 | static void LimitedSeqInStream_Init(CLimitedSeqInStream *p) | ||
50 | { | ||
51 | p->limit = (UInt64)(Int64)-1; | ||
52 | p->processed = 0; | ||
53 | p->finished = 0; | ||
54 | } | ||
55 | |||
56 | static SRes LimitedSeqInStream_Read(const ISeqInStream *pp, void *data, size_t *size) | ||
57 | { | ||
58 | CLimitedSeqInStream *p = CONTAINER_FROM_VTBL(pp, CLimitedSeqInStream, vt); | ||
59 | size_t size2 = *size; | ||
60 | SRes res = SZ_OK; | ||
61 | |||
62 | if (p->limit != (UInt64)(Int64)-1) | ||
63 | { | ||
64 | UInt64 rem = p->limit - p->processed; | ||
65 | if (size2 > rem) | ||
66 | size2 = (size_t)rem; | ||
67 | } | ||
68 | if (size2 != 0) | ||
69 | { | ||
70 | res = ISeqInStream_Read(p->realStream, data, &size2); | ||
71 | p->finished = (size2 == 0 ? 1 : 0); | ||
72 | p->processed += size2; | ||
73 | } | ||
74 | *size = size2; | ||
75 | return res; | ||
76 | } | ||
77 | |||
78 | |||
79 | /* ---------- CLzma2EncInt ---------- */ | ||
80 | |||
81 | typedef struct | ||
82 | { | ||
83 | CLzmaEncHandle enc; | ||
84 | Byte propsAreSet; | ||
85 | Byte propsByte; | ||
86 | Byte needInitState; | ||
87 | Byte needInitProp; | ||
88 | UInt64 srcPos; | ||
89 | } CLzma2EncInt; | ||
90 | |||
91 | |||
92 | static SRes Lzma2EncInt_InitStream(CLzma2EncInt *p, const CLzma2EncProps *props) | ||
93 | { | ||
94 | if (!p->propsAreSet) | ||
95 | { | ||
96 | SizeT propsSize = LZMA_PROPS_SIZE; | ||
97 | Byte propsEncoded[LZMA_PROPS_SIZE]; | ||
98 | RINOK(LzmaEnc_SetProps(p->enc, &props->lzmaProps)); | ||
99 | RINOK(LzmaEnc_WriteProperties(p->enc, propsEncoded, &propsSize)); | ||
100 | p->propsByte = propsEncoded[0]; | ||
101 | p->propsAreSet = True; | ||
102 | } | ||
103 | return SZ_OK; | ||
104 | } | ||
105 | |||
106 | static void Lzma2EncInt_InitBlock(CLzma2EncInt *p) | ||
107 | { | ||
108 | p->srcPos = 0; | ||
109 | p->needInitState = True; | ||
110 | p->needInitProp = True; | ||
111 | } | ||
112 | |||
113 | |||
114 | SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize, | ||
115 | ISzAllocPtr alloc, ISzAllocPtr allocBig); | ||
116 | SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, | ||
117 | UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig); | ||
118 | SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit, | ||
119 | Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize); | ||
120 | const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp); | ||
121 | void LzmaEnc_Finish(CLzmaEncHandle pp); | ||
122 | void LzmaEnc_SaveState(CLzmaEncHandle pp); | ||
123 | void LzmaEnc_RestoreState(CLzmaEncHandle pp); | ||
124 | |||
125 | /* | ||
126 | UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp); | ||
127 | */ | ||
128 | |||
129 | static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf, | ||
130 | size_t *packSizeRes, ISeqOutStream *outStream) | ||
131 | { | ||
132 | size_t packSizeLimit = *packSizeRes; | ||
133 | size_t packSize = packSizeLimit; | ||
134 | UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX; | ||
135 | unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0); | ||
136 | BoolInt useCopyBlock; | ||
137 | SRes res; | ||
138 | |||
139 | *packSizeRes = 0; | ||
140 | if (packSize < lzHeaderSize) | ||
141 | return SZ_ERROR_OUTPUT_EOF; | ||
142 | packSize -= lzHeaderSize; | ||
143 | |||
144 | LzmaEnc_SaveState(p->enc); | ||
145 | res = LzmaEnc_CodeOneMemBlock(p->enc, p->needInitState, | ||
146 | outBuf + lzHeaderSize, &packSize, LZMA2_PACK_SIZE_MAX, &unpackSize); | ||
147 | |||
148 | PRF(printf("\npackSize = %7d unpackSize = %7d ", packSize, unpackSize)); | ||
149 | |||
150 | if (unpackSize == 0) | ||
151 | return res; | ||
152 | |||
153 | if (res == SZ_OK) | ||
154 | useCopyBlock = (packSize + 2 >= unpackSize || packSize > (1 << 16)); | ||
155 | else | ||
156 | { | ||
157 | if (res != SZ_ERROR_OUTPUT_EOF) | ||
158 | return res; | ||
159 | res = SZ_OK; | ||
160 | useCopyBlock = True; | ||
161 | } | ||
162 | |||
163 | if (useCopyBlock) | ||
164 | { | ||
165 | size_t destPos = 0; | ||
166 | PRF(printf("################# COPY ")); | ||
167 | |||
168 | while (unpackSize > 0) | ||
169 | { | ||
170 | UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE; | ||
171 | if (packSizeLimit - destPos < u + 3) | ||
172 | return SZ_ERROR_OUTPUT_EOF; | ||
173 | outBuf[destPos++] = (Byte)(p->srcPos == 0 ? LZMA2_CONTROL_COPY_RESET_DIC : LZMA2_CONTROL_COPY_NO_RESET); | ||
174 | outBuf[destPos++] = (Byte)((u - 1) >> 8); | ||
175 | outBuf[destPos++] = (Byte)(u - 1); | ||
176 | memcpy(outBuf + destPos, LzmaEnc_GetCurBuf(p->enc) - unpackSize, u); | ||
177 | unpackSize -= u; | ||
178 | destPos += u; | ||
179 | p->srcPos += u; | ||
180 | |||
181 | if (outStream) | ||
182 | { | ||
183 | *packSizeRes += destPos; | ||
184 | if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos) | ||
185 | return SZ_ERROR_WRITE; | ||
186 | destPos = 0; | ||
187 | } | ||
188 | else | ||
189 | *packSizeRes = destPos; | ||
190 | /* needInitState = True; */ | ||
191 | } | ||
192 | |||
193 | LzmaEnc_RestoreState(p->enc); | ||
194 | return SZ_OK; | ||
195 | } | ||
196 | |||
197 | { | ||
198 | size_t destPos = 0; | ||
199 | UInt32 u = unpackSize - 1; | ||
200 | UInt32 pm = (UInt32)(packSize - 1); | ||
201 | unsigned mode = (p->srcPos == 0) ? 3 : (p->needInitState ? (p->needInitProp ? 2 : 1) : 0); | ||
202 | |||
203 | PRF(printf(" ")); | ||
204 | |||
205 | outBuf[destPos++] = (Byte)(LZMA2_CONTROL_LZMA | (mode << 5) | ((u >> 16) & 0x1F)); | ||
206 | outBuf[destPos++] = (Byte)(u >> 8); | ||
207 | outBuf[destPos++] = (Byte)u; | ||
208 | outBuf[destPos++] = (Byte)(pm >> 8); | ||
209 | outBuf[destPos++] = (Byte)pm; | ||
210 | |||
211 | if (p->needInitProp) | ||
212 | outBuf[destPos++] = p->propsByte; | ||
213 | |||
214 | p->needInitProp = False; | ||
215 | p->needInitState = False; | ||
216 | destPos += packSize; | ||
217 | p->srcPos += unpackSize; | ||
218 | |||
219 | if (outStream) | ||
220 | if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos) | ||
221 | return SZ_ERROR_WRITE; | ||
222 | |||
223 | *packSizeRes = destPos; | ||
224 | return SZ_OK; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | |||
229 | /* ---------- Lzma2 Props ---------- */ | ||
230 | |||
231 | void Lzma2EncProps_Init(CLzma2EncProps *p) | ||
232 | { | ||
233 | LzmaEncProps_Init(&p->lzmaProps); | ||
234 | p->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO; | ||
235 | p->numBlockThreads_Reduced = -1; | ||
236 | p->numBlockThreads_Max = -1; | ||
237 | p->numTotalThreads = -1; | ||
238 | } | ||
239 | |||
240 | void Lzma2EncProps_Normalize(CLzma2EncProps *p) | ||
241 | { | ||
242 | UInt64 fileSize; | ||
243 | int t1, t1n, t2, t2r, t3; | ||
244 | { | ||
245 | CLzmaEncProps lzmaProps = p->lzmaProps; | ||
246 | LzmaEncProps_Normalize(&lzmaProps); | ||
247 | t1n = lzmaProps.numThreads; | ||
248 | } | ||
249 | |||
250 | t1 = p->lzmaProps.numThreads; | ||
251 | t2 = p->numBlockThreads_Max; | ||
252 | t3 = p->numTotalThreads; | ||
253 | |||
254 | if (t2 > MTCODER__THREADS_MAX) | ||
255 | t2 = MTCODER__THREADS_MAX; | ||
256 | |||
257 | if (t3 <= 0) | ||
258 | { | ||
259 | if (t2 <= 0) | ||
260 | t2 = 1; | ||
261 | t3 = t1n * t2; | ||
262 | } | ||
263 | else if (t2 <= 0) | ||
264 | { | ||
265 | t2 = t3 / t1n; | ||
266 | if (t2 == 0) | ||
267 | { | ||
268 | t1 = 1; | ||
269 | t2 = t3; | ||
270 | } | ||
271 | if (t2 > MTCODER__THREADS_MAX) | ||
272 | t2 = MTCODER__THREADS_MAX; | ||
273 | } | ||
274 | else if (t1 <= 0) | ||
275 | { | ||
276 | t1 = t3 / t2; | ||
277 | if (t1 == 0) | ||
278 | t1 = 1; | ||
279 | } | ||
280 | else | ||
281 | t3 = t1n * t2; | ||
282 | |||
283 | p->lzmaProps.numThreads = t1; | ||
284 | |||
285 | t2r = t2; | ||
286 | |||
287 | fileSize = p->lzmaProps.reduceSize; | ||
288 | |||
289 | if ( p->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID | ||
290 | && p->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO | ||
291 | && (p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1)) | ||
292 | p->lzmaProps.reduceSize = p->blockSize; | ||
293 | |||
294 | LzmaEncProps_Normalize(&p->lzmaProps); | ||
295 | |||
296 | p->lzmaProps.reduceSize = fileSize; | ||
297 | |||
298 | t1 = p->lzmaProps.numThreads; | ||
299 | |||
300 | if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) | ||
301 | { | ||
302 | t2r = t2 = 1; | ||
303 | t3 = t1; | ||
304 | } | ||
305 | else if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO && t2 <= 1) | ||
306 | { | ||
307 | /* if there is no block multi-threading, we use SOLID block */ | ||
308 | p->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID; | ||
309 | } | ||
310 | else | ||
311 | { | ||
312 | if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) | ||
313 | { | ||
314 | const UInt32 kMinSize = (UInt32)1 << 20; | ||
315 | const UInt32 kMaxSize = (UInt32)1 << 28; | ||
316 | const UInt32 dictSize = p->lzmaProps.dictSize; | ||
317 | UInt64 blockSize = (UInt64)dictSize << 2; | ||
318 | if (blockSize < kMinSize) blockSize = kMinSize; | ||
319 | if (blockSize > kMaxSize) blockSize = kMaxSize; | ||
320 | if (blockSize < dictSize) blockSize = dictSize; | ||
321 | blockSize += (kMinSize - 1); | ||
322 | blockSize &= ~(UInt64)(kMinSize - 1); | ||
323 | p->blockSize = blockSize; | ||
324 | } | ||
325 | |||
326 | if (t2 > 1 && fileSize != (UInt64)(Int64)-1) | ||
327 | { | ||
328 | UInt64 numBlocks = fileSize / p->blockSize; | ||
329 | if (numBlocks * p->blockSize != fileSize) | ||
330 | numBlocks++; | ||
331 | if (numBlocks < (unsigned)t2) | ||
332 | { | ||
333 | t2r = (int)numBlocks; | ||
334 | if (t2r == 0) | ||
335 | t2r = 1; | ||
336 | t3 = t1 * t2r; | ||
337 | } | ||
338 | } | ||
339 | } | ||
340 | |||
341 | p->numBlockThreads_Max = t2; | ||
342 | p->numBlockThreads_Reduced = t2r; | ||
343 | p->numTotalThreads = t3; | ||
344 | } | ||
345 | |||
346 | |||
347 | static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize) | ||
348 | { | ||
349 | return (p && ICompressProgress_Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK; | ||
350 | } | ||
351 | |||
352 | |||
353 | /* ---------- Lzma2 ---------- */ | ||
354 | |||
355 | typedef struct | ||
356 | { | ||
357 | Byte propEncoded; | ||
358 | CLzma2EncProps props; | ||
359 | UInt64 expectedDataSize; | ||
360 | |||
361 | Byte *tempBufLzma; | ||
362 | |||
363 | ISzAllocPtr alloc; | ||
364 | ISzAllocPtr allocBig; | ||
365 | |||
366 | CLzma2EncInt coders[MTCODER__THREADS_MAX]; | ||
367 | |||
368 | #ifndef _7ZIP_ST | ||
369 | |||
370 | ISeqOutStream *outStream; | ||
371 | Byte *outBuf; | ||
372 | size_t outBuf_Rem; /* remainder in outBuf */ | ||
373 | |||
374 | size_t outBufSize; /* size of allocated outBufs[i] */ | ||
375 | size_t outBufsDataSizes[MTCODER__BLOCKS_MAX]; | ||
376 | BoolInt mtCoder_WasConstructed; | ||
377 | CMtCoder mtCoder; | ||
378 | Byte *outBufs[MTCODER__BLOCKS_MAX]; | ||
379 | |||
380 | #endif | ||
381 | |||
382 | } CLzma2Enc; | ||
383 | |||
384 | |||
385 | |||
386 | CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig) | ||
387 | { | ||
388 | CLzma2Enc *p = (CLzma2Enc *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Enc)); | ||
389 | if (!p) | ||
390 | return NULL; | ||
391 | Lzma2EncProps_Init(&p->props); | ||
392 | Lzma2EncProps_Normalize(&p->props); | ||
393 | p->expectedDataSize = (UInt64)(Int64)-1; | ||
394 | p->tempBufLzma = NULL; | ||
395 | p->alloc = alloc; | ||
396 | p->allocBig = allocBig; | ||
397 | { | ||
398 | unsigned i; | ||
399 | for (i = 0; i < MTCODER__THREADS_MAX; i++) | ||
400 | p->coders[i].enc = NULL; | ||
401 | } | ||
402 | |||
403 | #ifndef _7ZIP_ST | ||
404 | p->mtCoder_WasConstructed = False; | ||
405 | { | ||
406 | unsigned i; | ||
407 | for (i = 0; i < MTCODER__BLOCKS_MAX; i++) | ||
408 | p->outBufs[i] = NULL; | ||
409 | p->outBufSize = 0; | ||
410 | } | ||
411 | #endif | ||
412 | |||
413 | return p; | ||
414 | } | ||
415 | |||
416 | |||
417 | #ifndef _7ZIP_ST | ||
418 | |||
419 | static void Lzma2Enc_FreeOutBufs(CLzma2Enc *p) | ||
420 | { | ||
421 | unsigned i; | ||
422 | for (i = 0; i < MTCODER__BLOCKS_MAX; i++) | ||
423 | if (p->outBufs[i]) | ||
424 | { | ||
425 | ISzAlloc_Free(p->alloc, p->outBufs[i]); | ||
426 | p->outBufs[i] = NULL; | ||
427 | } | ||
428 | p->outBufSize = 0; | ||
429 | } | ||
430 | |||
431 | #endif | ||
432 | |||
433 | |||
434 | void Lzma2Enc_Destroy(CLzma2EncHandle pp) | ||
435 | { | ||
436 | CLzma2Enc *p = (CLzma2Enc *)pp; | ||
437 | unsigned i; | ||
438 | for (i = 0; i < MTCODER__THREADS_MAX; i++) | ||
439 | { | ||
440 | CLzma2EncInt *t = &p->coders[i]; | ||
441 | if (t->enc) | ||
442 | { | ||
443 | LzmaEnc_Destroy(t->enc, p->alloc, p->allocBig); | ||
444 | t->enc = NULL; | ||
445 | } | ||
446 | } | ||
447 | |||
448 | |||
449 | #ifndef _7ZIP_ST | ||
450 | if (p->mtCoder_WasConstructed) | ||
451 | { | ||
452 | MtCoder_Destruct(&p->mtCoder); | ||
453 | p->mtCoder_WasConstructed = False; | ||
454 | } | ||
455 | Lzma2Enc_FreeOutBufs(p); | ||
456 | #endif | ||
457 | |||
458 | ISzAlloc_Free(p->alloc, p->tempBufLzma); | ||
459 | p->tempBufLzma = NULL; | ||
460 | |||
461 | ISzAlloc_Free(p->alloc, pp); | ||
462 | } | ||
463 | |||
464 | |||
465 | SRes Lzma2Enc_SetProps(CLzma2EncHandle pp, const CLzma2EncProps *props) | ||
466 | { | ||
467 | CLzma2Enc *p = (CLzma2Enc *)pp; | ||
468 | CLzmaEncProps lzmaProps = props->lzmaProps; | ||
469 | LzmaEncProps_Normalize(&lzmaProps); | ||
470 | if (lzmaProps.lc + lzmaProps.lp > LZMA2_LCLP_MAX) | ||
471 | return SZ_ERROR_PARAM; | ||
472 | p->props = *props; | ||
473 | Lzma2EncProps_Normalize(&p->props); | ||
474 | return SZ_OK; | ||
475 | } | ||
476 | |||
477 | |||
478 | void Lzma2Enc_SetDataSize(CLzmaEncHandle pp, UInt64 expectedDataSiize) | ||
479 | { | ||
480 | CLzma2Enc *p = (CLzma2Enc *)pp; | ||
481 | p->expectedDataSize = expectedDataSiize; | ||
482 | } | ||
483 | |||
484 | |||
485 | Byte Lzma2Enc_WriteProperties(CLzma2EncHandle pp) | ||
486 | { | ||
487 | CLzma2Enc *p = (CLzma2Enc *)pp; | ||
488 | unsigned i; | ||
489 | UInt32 dicSize = LzmaEncProps_GetDictSize(&p->props.lzmaProps); | ||
490 | for (i = 0; i < 40; i++) | ||
491 | if (dicSize <= LZMA2_DIC_SIZE_FROM_PROP(i)) | ||
492 | break; | ||
493 | return (Byte)i; | ||
494 | } | ||
495 | |||
496 | |||
497 | static SRes Lzma2Enc_EncodeMt1( | ||
498 | CLzma2Enc *me, | ||
499 | CLzma2EncInt *p, | ||
500 | ISeqOutStream *outStream, | ||
501 | Byte *outBuf, size_t *outBufSize, | ||
502 | ISeqInStream *inStream, | ||
503 | const Byte *inData, size_t inDataSize, | ||
504 | int finished, | ||
505 | ICompressProgress *progress) | ||
506 | { | ||
507 | UInt64 unpackTotal = 0; | ||
508 | UInt64 packTotal = 0; | ||
509 | size_t outLim = 0; | ||
510 | CLimitedSeqInStream limitedInStream; | ||
511 | |||
512 | if (outBuf) | ||
513 | { | ||
514 | outLim = *outBufSize; | ||
515 | *outBufSize = 0; | ||
516 | } | ||
517 | |||
518 | if (!p->enc) | ||
519 | { | ||
520 | p->propsAreSet = False; | ||
521 | p->enc = LzmaEnc_Create(me->alloc); | ||
522 | if (!p->enc) | ||
523 | return SZ_ERROR_MEM; | ||
524 | } | ||
525 | |||
526 | limitedInStream.realStream = inStream; | ||
527 | if (inStream) | ||
528 | { | ||
529 | limitedInStream.vt.Read = LimitedSeqInStream_Read; | ||
530 | } | ||
531 | |||
532 | if (!outBuf) | ||
533 | { | ||
534 | // outStream version works only in one thread. So we use CLzma2Enc::tempBufLzma | ||
535 | if (!me->tempBufLzma) | ||
536 | { | ||
537 | me->tempBufLzma = (Byte *)ISzAlloc_Alloc(me->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX); | ||
538 | if (!me->tempBufLzma) | ||
539 | return SZ_ERROR_MEM; | ||
540 | } | ||
541 | } | ||
542 | |||
543 | RINOK(Lzma2EncInt_InitStream(p, &me->props)); | ||
544 | |||
545 | for (;;) | ||
546 | { | ||
547 | SRes res = SZ_OK; | ||
548 | size_t inSizeCur = 0; | ||
549 | |||
550 | Lzma2EncInt_InitBlock(p); | ||
551 | |||
552 | LimitedSeqInStream_Init(&limitedInStream); | ||
553 | limitedInStream.limit = me->props.blockSize; | ||
554 | |||
555 | if (inStream) | ||
556 | { | ||
557 | UInt64 expected = (UInt64)(Int64)-1; | ||
558 | // inStream version works only in one thread. So we use CLzma2Enc::expectedDataSize | ||
559 | if (me->expectedDataSize != (UInt64)(Int64)-1 | ||
560 | && me->expectedDataSize >= unpackTotal) | ||
561 | expected = me->expectedDataSize - unpackTotal; | ||
562 | if (me->props.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID | ||
563 | && expected > me->props.blockSize) | ||
564 | expected = (size_t)me->props.blockSize; | ||
565 | |||
566 | LzmaEnc_SetDataSize(p->enc, expected); | ||
567 | |||
568 | RINOK(LzmaEnc_PrepareForLzma2(p->enc, | ||
569 | &limitedInStream.vt, | ||
570 | LZMA2_KEEP_WINDOW_SIZE, | ||
571 | me->alloc, | ||
572 | me->allocBig)); | ||
573 | } | ||
574 | else | ||
575 | { | ||
576 | inSizeCur = inDataSize - (size_t)unpackTotal; | ||
577 | if (me->props.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID | ||
578 | && inSizeCur > me->props.blockSize) | ||
579 | inSizeCur = (size_t)me->props.blockSize; | ||
580 | |||
581 | // LzmaEnc_SetDataSize(p->enc, inSizeCur); | ||
582 | |||
583 | RINOK(LzmaEnc_MemPrepare(p->enc, | ||
584 | inData + (size_t)unpackTotal, inSizeCur, | ||
585 | LZMA2_KEEP_WINDOW_SIZE, | ||
586 | me->alloc, | ||
587 | me->allocBig)); | ||
588 | } | ||
589 | |||
590 | for (;;) | ||
591 | { | ||
592 | size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX; | ||
593 | if (outBuf) | ||
594 | packSize = outLim - (size_t)packTotal; | ||
595 | |||
596 | res = Lzma2EncInt_EncodeSubblock(p, | ||
597 | outBuf ? outBuf + (size_t)packTotal : me->tempBufLzma, &packSize, | ||
598 | outBuf ? NULL : outStream); | ||
599 | |||
600 | if (res != SZ_OK) | ||
601 | break; | ||
602 | |||
603 | packTotal += packSize; | ||
604 | if (outBuf) | ||
605 | *outBufSize = (size_t)packTotal; | ||
606 | |||
607 | res = Progress(progress, unpackTotal + p->srcPos, packTotal); | ||
608 | if (res != SZ_OK) | ||
609 | break; | ||
610 | |||
611 | /* | ||
612 | if (LzmaEnc_GetNumAvailableBytes(p->enc) == 0) | ||
613 | break; | ||
614 | */ | ||
615 | |||
616 | if (packSize == 0) | ||
617 | break; | ||
618 | } | ||
619 | |||
620 | LzmaEnc_Finish(p->enc); | ||
621 | |||
622 | unpackTotal += p->srcPos; | ||
623 | |||
624 | RINOK(res); | ||
625 | |||
626 | if (p->srcPos != (inStream ? limitedInStream.processed : inSizeCur)) | ||
627 | return SZ_ERROR_FAIL; | ||
628 | |||
629 | if (inStream ? limitedInStream.finished : (unpackTotal == inDataSize)) | ||
630 | { | ||
631 | if (finished) | ||
632 | { | ||
633 | if (outBuf) | ||
634 | { | ||
635 | const size_t destPos = *outBufSize; | ||
636 | if (destPos >= outLim) | ||
637 | return SZ_ERROR_OUTPUT_EOF; | ||
638 | outBuf[destPos] = LZMA2_CONTROL_EOF; // 0 | ||
639 | *outBufSize = destPos + 1; | ||
640 | } | ||
641 | else | ||
642 | { | ||
643 | const Byte b = LZMA2_CONTROL_EOF; // 0; | ||
644 | if (ISeqOutStream_Write(outStream, &b, 1) != 1) | ||
645 | return SZ_ERROR_WRITE; | ||
646 | } | ||
647 | } | ||
648 | return SZ_OK; | ||
649 | } | ||
650 | } | ||
651 | } | ||
652 | |||
653 | |||
654 | |||
655 | #ifndef _7ZIP_ST | ||
656 | |||
657 | static SRes Lzma2Enc_MtCallback_Code(void *pp, unsigned coderIndex, unsigned outBufIndex, | ||
658 | const Byte *src, size_t srcSize, int finished) | ||
659 | { | ||
660 | CLzma2Enc *me = (CLzma2Enc *)pp; | ||
661 | size_t destSize = me->outBufSize; | ||
662 | SRes res; | ||
663 | CMtProgressThunk progressThunk; | ||
664 | |||
665 | Byte *dest = me->outBufs[outBufIndex]; | ||
666 | |||
667 | me->outBufsDataSizes[outBufIndex] = 0; | ||
668 | |||
669 | if (!dest) | ||
670 | { | ||
671 | dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize); | ||
672 | if (!dest) | ||
673 | return SZ_ERROR_MEM; | ||
674 | me->outBufs[outBufIndex] = dest; | ||
675 | } | ||
676 | |||
677 | MtProgressThunk_CreateVTable(&progressThunk); | ||
678 | progressThunk.mtProgress = &me->mtCoder.mtProgress; | ||
679 | progressThunk.inSize = 0; | ||
680 | progressThunk.outSize = 0; | ||
681 | |||
682 | res = Lzma2Enc_EncodeMt1(me, | ||
683 | &me->coders[coderIndex], | ||
684 | NULL, dest, &destSize, | ||
685 | NULL, src, srcSize, | ||
686 | finished, | ||
687 | &progressThunk.vt); | ||
688 | |||
689 | me->outBufsDataSizes[outBufIndex] = destSize; | ||
690 | |||
691 | return res; | ||
692 | } | ||
693 | |||
694 | |||
695 | static SRes Lzma2Enc_MtCallback_Write(void *pp, unsigned outBufIndex) | ||
696 | { | ||
697 | CLzma2Enc *me = (CLzma2Enc *)pp; | ||
698 | size_t size = me->outBufsDataSizes[outBufIndex]; | ||
699 | const Byte *data = me->outBufs[outBufIndex]; | ||
700 | |||
701 | if (me->outStream) | ||
702 | return ISeqOutStream_Write(me->outStream, data, size) == size ? SZ_OK : SZ_ERROR_WRITE; | ||
703 | |||
704 | if (size > me->outBuf_Rem) | ||
705 | return SZ_ERROR_OUTPUT_EOF; | ||
706 | memcpy(me->outBuf, data, size); | ||
707 | me->outBuf_Rem -= size; | ||
708 | me->outBuf += size; | ||
709 | return SZ_OK; | ||
710 | } | ||
711 | |||
712 | #endif | ||
713 | |||
714 | |||
715 | |||
716 | SRes Lzma2Enc_Encode2(CLzma2EncHandle pp, | ||
717 | ISeqOutStream *outStream, | ||
718 | Byte *outBuf, size_t *outBufSize, | ||
719 | ISeqInStream *inStream, | ||
720 | const Byte *inData, size_t inDataSize, | ||
721 | ICompressProgress *progress) | ||
722 | { | ||
723 | CLzma2Enc *p = (CLzma2Enc *)pp; | ||
724 | |||
725 | if (inStream && inData) | ||
726 | return SZ_ERROR_PARAM; | ||
727 | |||
728 | if (outStream && outBuf) | ||
729 | return SZ_ERROR_PARAM; | ||
730 | |||
731 | { | ||
732 | unsigned i; | ||
733 | for (i = 0; i < MTCODER__THREADS_MAX; i++) | ||
734 | p->coders[i].propsAreSet = False; | ||
735 | } | ||
736 | |||
737 | #ifndef _7ZIP_ST | ||
738 | |||
739 | if (p->props.numBlockThreads_Reduced > 1) | ||
740 | { | ||
741 | IMtCoderCallback2 vt; | ||
742 | |||
743 | if (!p->mtCoder_WasConstructed) | ||
744 | { | ||
745 | p->mtCoder_WasConstructed = True; | ||
746 | MtCoder_Construct(&p->mtCoder); | ||
747 | } | ||
748 | |||
749 | vt.Code = Lzma2Enc_MtCallback_Code; | ||
750 | vt.Write = Lzma2Enc_MtCallback_Write; | ||
751 | |||
752 | p->outStream = outStream; | ||
753 | p->outBuf = NULL; | ||
754 | p->outBuf_Rem = 0; | ||
755 | if (!outStream) | ||
756 | { | ||
757 | p->outBuf = outBuf; | ||
758 | p->outBuf_Rem = *outBufSize; | ||
759 | *outBufSize = 0; | ||
760 | } | ||
761 | |||
762 | p->mtCoder.allocBig = p->allocBig; | ||
763 | p->mtCoder.progress = progress; | ||
764 | p->mtCoder.inStream = inStream; | ||
765 | p->mtCoder.inData = inData; | ||
766 | p->mtCoder.inDataSize = inDataSize; | ||
767 | p->mtCoder.mtCallback = &vt; | ||
768 | p->mtCoder.mtCallbackObject = p; | ||
769 | |||
770 | p->mtCoder.blockSize = (size_t)p->props.blockSize; | ||
771 | if (p->mtCoder.blockSize != p->props.blockSize) | ||
772 | return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */ | ||
773 | |||
774 | { | ||
775 | size_t destBlockSize = p->mtCoder.blockSize + (p->mtCoder.blockSize >> 10) + 16; | ||
776 | if (destBlockSize < p->mtCoder.blockSize) | ||
777 | return SZ_ERROR_PARAM; | ||
778 | if (p->outBufSize != destBlockSize) | ||
779 | Lzma2Enc_FreeOutBufs(p); | ||
780 | p->outBufSize = destBlockSize; | ||
781 | } | ||
782 | |||
783 | p->mtCoder.numThreadsMax = (unsigned)p->props.numBlockThreads_Max; | ||
784 | p->mtCoder.expectedDataSize = p->expectedDataSize; | ||
785 | |||
786 | { | ||
787 | SRes res = MtCoder_Code(&p->mtCoder); | ||
788 | if (!outStream) | ||
789 | *outBufSize = (size_t)(p->outBuf - outBuf); | ||
790 | return res; | ||
791 | } | ||
792 | } | ||
793 | |||
794 | #endif | ||
795 | |||
796 | |||
797 | return Lzma2Enc_EncodeMt1(p, | ||
798 | &p->coders[0], | ||
799 | outStream, outBuf, outBufSize, | ||
800 | inStream, inData, inDataSize, | ||
801 | True, /* finished */ | ||
802 | progress); | ||
803 | } | ||