/src/lzma-fuzz/sdk/C/Lzma2Enc.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Lzma2Enc.c -- LZMA2 Encoder |
2 | | 2018-07-04 : 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 | 74.1k | #define MTCODER__THREADS_MAX 1 |
16 | | #endif |
17 | | |
18 | 6.15k | #define LZMA2_CONTROL_LZMA (1 << 7) |
19 | 41 | #define LZMA2_CONTROL_COPY_NO_RESET 2 |
20 | 2.10k | #define LZMA2_CONTROL_COPY_RESET_DIC 1 |
21 | | #define LZMA2_CONTROL_EOF 0 |
22 | | |
23 | 8.24k | #define LZMA2_LCLP_MAX 4 |
24 | | |
25 | 205k | #define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) |
26 | | |
27 | 18.6k | #define LZMA2_PACK_SIZE_MAX (1 << 16) |
28 | 2.14k | #define LZMA2_COPY_CHUNK_SIZE LZMA2_PACK_SIZE_MAX |
29 | 16.5k | #define LZMA2_UNPACK_SIZE_MAX (1 << 21) |
30 | | #define LZMA2_KEEP_WINDOW_SIZE LZMA2_UNPACK_SIZE_MAX |
31 | | |
32 | 16.5k | #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 | 8.23k | { |
51 | 8.23k | p->limit = (UInt64)(Int64)-1; |
52 | 8.23k | p->processed = 0; |
53 | 8.23k | p->finished = 0; |
54 | 8.23k | } |
55 | | |
56 | | static SRes LimitedSeqInStream_Read(const ISeqInStream *pp, void *data, size_t *size) |
57 | 16.4k | { |
58 | 16.4k | CLimitedSeqInStream *p = CONTAINER_FROM_VTBL(pp, CLimitedSeqInStream, vt); |
59 | 16.4k | size_t size2 = *size; |
60 | 16.4k | SRes res = SZ_OK; |
61 | | |
62 | 16.4k | if (p->limit != (UInt64)(Int64)-1) |
63 | 0 | { |
64 | 0 | UInt64 rem = p->limit - p->processed; |
65 | 0 | if (size2 > rem) |
66 | 0 | size2 = (size_t)rem; |
67 | 0 | } |
68 | 16.4k | if (size2 != 0) |
69 | 16.4k | { |
70 | 16.4k | res = ISeqInStream_Read(p->realStream, data, &size2); |
71 | 16.4k | p->finished = (size2 == 0 ? 1 : 0); |
72 | 16.4k | p->processed += size2; |
73 | 16.4k | } |
74 | 16.4k | *size = size2; |
75 | 16.4k | return res; |
76 | 16.4k | } |
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 | 8.23k | { |
94 | 8.23k | if (!p->propsAreSet) |
95 | 8.23k | { |
96 | 8.23k | SizeT propsSize = LZMA_PROPS_SIZE; |
97 | 8.23k | Byte propsEncoded[LZMA_PROPS_SIZE]; |
98 | 8.23k | RINOK(LzmaEnc_SetProps(p->enc, &props->lzmaProps)); |
99 | 8.23k | RINOK(LzmaEnc_WriteProperties(p->enc, propsEncoded, &propsSize)); |
100 | 8.23k | p->propsByte = propsEncoded[0]; |
101 | 8.23k | p->propsAreSet = True; |
102 | 8.23k | } |
103 | 8.23k | return SZ_OK; |
104 | 8.23k | } |
105 | | |
106 | | static void Lzma2EncInt_InitBlock(CLzma2EncInt *p) |
107 | 8.23k | { |
108 | 8.23k | p->srcPos = 0; |
109 | 8.23k | p->needInitState = True; |
110 | 8.23k | p->needInitProp = True; |
111 | 8.23k | } |
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 | 16.5k | { |
132 | 16.5k | size_t packSizeLimit = *packSizeRes; |
133 | 16.5k | size_t packSize = packSizeLimit; |
134 | 16.5k | UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX; |
135 | 16.5k | unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0); |
136 | 16.5k | BoolInt useCopyBlock; |
137 | 16.5k | SRes res; |
138 | | |
139 | 16.5k | *packSizeRes = 0; |
140 | 16.5k | if (packSize < lzHeaderSize) |
141 | 0 | return SZ_ERROR_OUTPUT_EOF; |
142 | 16.5k | packSize -= lzHeaderSize; |
143 | | |
144 | 16.5k | LzmaEnc_SaveState(p->enc); |
145 | 16.5k | res = LzmaEnc_CodeOneMemBlock(p->enc, p->needInitState, |
146 | 16.5k | outBuf + lzHeaderSize, &packSize, LZMA2_PACK_SIZE_MAX, &unpackSize); |
147 | | |
148 | 16.5k | PRF(printf("\npackSize = %7d unpackSize = %7d ", packSize, unpackSize)); |
149 | | |
150 | 16.5k | if (unpackSize == 0) |
151 | 8.23k | return res; |
152 | | |
153 | 8.30k | if (res == SZ_OK) |
154 | 8.30k | useCopyBlock = (packSize + 2 >= unpackSize || packSize > (1 << 16)); |
155 | 0 | else |
156 | 0 | { |
157 | 0 | if (res != SZ_ERROR_OUTPUT_EOF) |
158 | 0 | return res; |
159 | 0 | res = SZ_OK; |
160 | 0 | useCopyBlock = True; |
161 | 0 | } |
162 | | |
163 | 8.30k | if (useCopyBlock) |
164 | 2.14k | { |
165 | 2.14k | size_t destPos = 0; |
166 | 2.14k | PRF(printf("################# COPY ")); |
167 | | |
168 | 4.29k | while (unpackSize > 0) |
169 | 2.14k | { |
170 | 2.14k | UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE; |
171 | 2.14k | if (packSizeLimit - destPos < u + 3) |
172 | 0 | return SZ_ERROR_OUTPUT_EOF; |
173 | 2.14k | outBuf[destPos++] = (Byte)(p->srcPos == 0 ? LZMA2_CONTROL_COPY_RESET_DIC : LZMA2_CONTROL_COPY_NO_RESET); |
174 | 2.14k | outBuf[destPos++] = (Byte)((u - 1) >> 8); |
175 | 2.14k | outBuf[destPos++] = (Byte)(u - 1); |
176 | 2.14k | memcpy(outBuf + destPos, LzmaEnc_GetCurBuf(p->enc) - unpackSize, u); |
177 | 2.14k | unpackSize -= u; |
178 | 2.14k | destPos += u; |
179 | 2.14k | p->srcPos += u; |
180 | | |
181 | 2.14k | if (outStream) |
182 | 2.14k | { |
183 | 2.14k | *packSizeRes += destPos; |
184 | 2.14k | if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos) |
185 | 0 | return SZ_ERROR_WRITE; |
186 | 2.14k | destPos = 0; |
187 | 2.14k | } |
188 | 0 | else |
189 | 0 | *packSizeRes = destPos; |
190 | | /* needInitState = True; */ |
191 | 2.14k | } |
192 | | |
193 | 2.14k | LzmaEnc_RestoreState(p->enc); |
194 | 2.14k | return SZ_OK; |
195 | 2.14k | } |
196 | | |
197 | 6.15k | { |
198 | 6.15k | size_t destPos = 0; |
199 | 6.15k | UInt32 u = unpackSize - 1; |
200 | 6.15k | UInt32 pm = (UInt32)(packSize - 1); |
201 | 6.15k | unsigned mode = (p->srcPos == 0) ? 3 : (p->needInitState ? (p->needInitProp ? 2 : 1) : 0); |
202 | | |
203 | 6.15k | PRF(printf(" ")); |
204 | | |
205 | 6.15k | outBuf[destPos++] = (Byte)(LZMA2_CONTROL_LZMA | (mode << 5) | ((u >> 16) & 0x1F)); |
206 | 6.15k | outBuf[destPos++] = (Byte)(u >> 8); |
207 | 6.15k | outBuf[destPos++] = (Byte)u; |
208 | 6.15k | outBuf[destPos++] = (Byte)(pm >> 8); |
209 | 6.15k | outBuf[destPos++] = (Byte)pm; |
210 | | |
211 | 6.15k | if (p->needInitProp) |
212 | 6.13k | outBuf[destPos++] = p->propsByte; |
213 | | |
214 | 6.15k | p->needInitProp = False; |
215 | 6.15k | p->needInitState = False; |
216 | 6.15k | destPos += packSize; |
217 | 6.15k | p->srcPos += unpackSize; |
218 | | |
219 | 6.15k | if (outStream) |
220 | 6.15k | if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos) |
221 | 0 | return SZ_ERROR_WRITE; |
222 | | |
223 | 6.15k | *packSizeRes = destPos; |
224 | 6.15k | return SZ_OK; |
225 | 6.15k | } |
226 | 6.15k | } |
227 | | |
228 | | |
229 | | /* ---------- Lzma2 Props ---------- */ |
230 | | |
231 | | void Lzma2EncProps_Init(CLzma2EncProps *p) |
232 | 16.4k | { |
233 | 16.4k | LzmaEncProps_Init(&p->lzmaProps); |
234 | 16.4k | p->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO; |
235 | 16.4k | p->numBlockThreads_Reduced = -1; |
236 | 16.4k | p->numBlockThreads_Max = -1; |
237 | 16.4k | p->numTotalThreads = -1; |
238 | 16.4k | } |
239 | | |
240 | | void Lzma2EncProps_Normalize(CLzma2EncProps *p) |
241 | 24.7k | { |
242 | 24.7k | UInt64 fileSize; |
243 | 24.7k | int t1, t1n, t2, t2r, t3; |
244 | 24.7k | { |
245 | 24.7k | CLzmaEncProps lzmaProps = p->lzmaProps; |
246 | 24.7k | LzmaEncProps_Normalize(&lzmaProps); |
247 | 24.7k | t1n = lzmaProps.numThreads; |
248 | 24.7k | } |
249 | | |
250 | 24.7k | t1 = p->lzmaProps.numThreads; |
251 | 24.7k | t2 = p->numBlockThreads_Max; |
252 | 24.7k | t3 = p->numTotalThreads; |
253 | | |
254 | 24.7k | if (t2 > MTCODER__THREADS_MAX) |
255 | 0 | t2 = MTCODER__THREADS_MAX; |
256 | | |
257 | 24.7k | if (t3 <= 0) |
258 | 16.4k | { |
259 | 16.4k | if (t2 <= 0) |
260 | 16.4k | t2 = 1; |
261 | 16.4k | t3 = t1n * t2; |
262 | 16.4k | } |
263 | 8.23k | else if (t2 <= 0) |
264 | 0 | { |
265 | 0 | t2 = t3 / t1n; |
266 | 0 | if (t2 == 0) |
267 | 0 | { |
268 | 0 | t1 = 1; |
269 | 0 | t2 = t3; |
270 | 0 | } |
271 | 0 | if (t2 > MTCODER__THREADS_MAX) |
272 | 0 | t2 = MTCODER__THREADS_MAX; |
273 | 0 | } |
274 | 8.23k | else if (t1 <= 0) |
275 | 0 | { |
276 | 0 | t1 = t3 / t2; |
277 | 0 | if (t1 == 0) |
278 | 0 | t1 = 1; |
279 | 0 | } |
280 | 8.23k | else |
281 | 8.23k | t3 = t1n * t2; |
282 | | |
283 | 24.7k | p->lzmaProps.numThreads = t1; |
284 | | |
285 | 24.7k | t2r = t2; |
286 | | |
287 | 24.7k | fileSize = p->lzmaProps.reduceSize; |
288 | | |
289 | 24.7k | if ( p->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID |
290 | 24.7k | && p->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO |
291 | 24.7k | && (p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1)) |
292 | 0 | p->lzmaProps.reduceSize = p->blockSize; |
293 | | |
294 | 24.7k | LzmaEncProps_Normalize(&p->lzmaProps); |
295 | | |
296 | 24.7k | p->lzmaProps.reduceSize = fileSize; |
297 | | |
298 | 24.7k | t1 = p->lzmaProps.numThreads; |
299 | | |
300 | 24.7k | if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) |
301 | 8.23k | { |
302 | 8.23k | t2r = t2 = 1; |
303 | 8.23k | t3 = t1; |
304 | 8.23k | } |
305 | 16.4k | else if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO && t2 <= 1) |
306 | 16.4k | { |
307 | | /* if there is no block multi-threading, we use SOLID block */ |
308 | 16.4k | p->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID; |
309 | 16.4k | } |
310 | 0 | else |
311 | 0 | { |
312 | 0 | if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) |
313 | 0 | { |
314 | 0 | const UInt32 kMinSize = (UInt32)1 << 20; |
315 | 0 | const UInt32 kMaxSize = (UInt32)1 << 28; |
316 | 0 | const UInt32 dictSize = p->lzmaProps.dictSize; |
317 | 0 | UInt64 blockSize = (UInt64)dictSize << 2; |
318 | 0 | if (blockSize < kMinSize) blockSize = kMinSize; |
319 | 0 | if (blockSize > kMaxSize) blockSize = kMaxSize; |
320 | 0 | if (blockSize < dictSize) blockSize = dictSize; |
321 | 0 | blockSize += (kMinSize - 1); |
322 | 0 | blockSize &= ~(UInt64)(kMinSize - 1); |
323 | 0 | p->blockSize = blockSize; |
324 | 0 | } |
325 | | |
326 | 0 | if (t2 > 1 && fileSize != (UInt64)(Int64)-1) |
327 | 0 | { |
328 | 0 | UInt64 numBlocks = fileSize / p->blockSize; |
329 | 0 | if (numBlocks * p->blockSize != fileSize) |
330 | 0 | numBlocks++; |
331 | 0 | if (numBlocks < (unsigned)t2) |
332 | 0 | { |
333 | 0 | t2r = (unsigned)numBlocks; |
334 | 0 | if (t2r == 0) |
335 | 0 | t2r = 1; |
336 | 0 | t3 = t1 * t2r; |
337 | 0 | } |
338 | 0 | } |
339 | 0 | } |
340 | | |
341 | 24.7k | p->numBlockThreads_Max = t2; |
342 | 24.7k | p->numBlockThreads_Reduced = t2r; |
343 | 24.7k | p->numTotalThreads = t3; |
344 | 24.7k | } |
345 | | |
346 | | |
347 | | static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize) |
348 | 16.5k | { |
349 | 16.5k | return (p && ICompressProgress_Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK; |
350 | 16.5k | } |
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 | 8.24k | { |
388 | 8.24k | CLzma2Enc *p = (CLzma2Enc *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Enc)); |
389 | 8.24k | if (!p) |
390 | 0 | return NULL; |
391 | 8.24k | Lzma2EncProps_Init(&p->props); |
392 | 8.24k | Lzma2EncProps_Normalize(&p->props); |
393 | 8.24k | p->expectedDataSize = (UInt64)(Int64)-1; |
394 | 8.24k | p->tempBufLzma = NULL; |
395 | 8.24k | p->alloc = alloc; |
396 | 8.24k | p->allocBig = allocBig; |
397 | 8.24k | { |
398 | 8.24k | unsigned i; |
399 | 16.4k | for (i = 0; i < MTCODER__THREADS_MAX; i++) |
400 | 8.24k | p->coders[i].enc = NULL; |
401 | 8.24k | } |
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 | 8.24k | return p; |
414 | 8.24k | } |
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 | 8.24k | { |
436 | 8.24k | CLzma2Enc *p = (CLzma2Enc *)pp; |
437 | 8.24k | unsigned i; |
438 | 16.4k | for (i = 0; i < MTCODER__THREADS_MAX; i++) |
439 | 8.24k | { |
440 | 8.24k | CLzma2EncInt *t = &p->coders[i]; |
441 | 8.24k | if (t->enc) |
442 | 8.23k | { |
443 | 8.23k | LzmaEnc_Destroy(t->enc, p->alloc, p->allocBig); |
444 | 8.23k | t->enc = NULL; |
445 | 8.23k | } |
446 | 8.24k | } |
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 | 8.24k | ISzAlloc_Free(p->alloc, p->tempBufLzma); |
459 | 8.24k | p->tempBufLzma = NULL; |
460 | | |
461 | 8.24k | ISzAlloc_Free(p->alloc, pp); |
462 | 8.24k | } |
463 | | |
464 | | |
465 | | SRes Lzma2Enc_SetProps(CLzma2EncHandle pp, const CLzma2EncProps *props) |
466 | 8.24k | { |
467 | 8.24k | CLzma2Enc *p = (CLzma2Enc *)pp; |
468 | 8.24k | CLzmaEncProps lzmaProps = props->lzmaProps; |
469 | 8.24k | LzmaEncProps_Normalize(&lzmaProps); |
470 | 8.24k | if (lzmaProps.lc + lzmaProps.lp > LZMA2_LCLP_MAX) |
471 | 14 | return SZ_ERROR_PARAM; |
472 | 8.23k | p->props = *props; |
473 | 8.23k | Lzma2EncProps_Normalize(&p->props); |
474 | 8.23k | return SZ_OK; |
475 | 8.24k | } |
476 | | |
477 | | |
478 | | void Lzma2Enc_SetDataSize(CLzmaEncHandle pp, UInt64 expectedDataSiize) |
479 | 8.23k | { |
480 | 8.23k | CLzma2Enc *p = (CLzma2Enc *)pp; |
481 | 8.23k | p->expectedDataSize = expectedDataSiize; |
482 | 8.23k | } |
483 | | |
484 | | |
485 | | Byte Lzma2Enc_WriteProperties(CLzma2EncHandle pp) |
486 | 8.23k | { |
487 | 8.23k | CLzma2Enc *p = (CLzma2Enc *)pp; |
488 | 8.23k | unsigned i; |
489 | 8.23k | UInt32 dicSize = LzmaEncProps_GetDictSize(&p->props.lzmaProps); |
490 | 205k | for (i = 0; i < 40; i++) |
491 | 205k | if (dicSize <= LZMA2_DIC_SIZE_FROM_PROP(i)) |
492 | 8.23k | break; |
493 | 8.23k | return (Byte)i; |
494 | 8.23k | } |
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 | 8.23k | { |
507 | 8.23k | UInt64 unpackTotal = 0; |
508 | 8.23k | UInt64 packTotal = 0; |
509 | 8.23k | size_t outLim = 0; |
510 | 8.23k | CLimitedSeqInStream limitedInStream; |
511 | | |
512 | 8.23k | if (outBuf) |
513 | 0 | { |
514 | 0 | outLim = *outBufSize; |
515 | 0 | *outBufSize = 0; |
516 | 0 | } |
517 | | |
518 | 8.23k | if (!p->enc) |
519 | 8.23k | { |
520 | 8.23k | p->propsAreSet = False; |
521 | 8.23k | p->enc = LzmaEnc_Create(me->alloc); |
522 | 8.23k | if (!p->enc) |
523 | 0 | return SZ_ERROR_MEM; |
524 | 8.23k | } |
525 | | |
526 | 8.23k | limitedInStream.realStream = inStream; |
527 | 8.23k | if (inStream) |
528 | 8.23k | { |
529 | 8.23k | limitedInStream.vt.Read = LimitedSeqInStream_Read; |
530 | 8.23k | } |
531 | | |
532 | 8.23k | if (!outBuf) |
533 | 8.23k | { |
534 | | // outStream version works only in one thread. So we use CLzma2Enc::tempBufLzma |
535 | 8.23k | if (!me->tempBufLzma) |
536 | 8.23k | { |
537 | 8.23k | me->tempBufLzma = (Byte *)ISzAlloc_Alloc(me->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX); |
538 | 8.23k | if (!me->tempBufLzma) |
539 | 0 | return SZ_ERROR_MEM; |
540 | 8.23k | } |
541 | 8.23k | } |
542 | | |
543 | 8.23k | RINOK(Lzma2EncInt_InitStream(p, &me->props)); |
544 | | |
545 | 8.23k | for (;;) |
546 | 8.23k | { |
547 | 8.23k | SRes res = SZ_OK; |
548 | 8.23k | size_t inSizeCur = 0; |
549 | | |
550 | 8.23k | Lzma2EncInt_InitBlock(p); |
551 | | |
552 | 8.23k | LimitedSeqInStream_Init(&limitedInStream); |
553 | 8.23k | limitedInStream.limit = me->props.blockSize; |
554 | | |
555 | 8.23k | if (inStream) |
556 | 8.23k | { |
557 | 8.23k | UInt64 expected = (UInt64)(Int64)-1; |
558 | | // inStream version works only in one thread. So we use CLzma2Enc::expectedDataSize |
559 | 8.23k | if (me->expectedDataSize != (UInt64)(Int64)-1 |
560 | 8.23k | && me->expectedDataSize >= unpackTotal) |
561 | 8.23k | expected = me->expectedDataSize - unpackTotal; |
562 | 8.23k | if (me->props.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID |
563 | 8.23k | && expected > me->props.blockSize) |
564 | 0 | expected = (size_t)me->props.blockSize; |
565 | | |
566 | 8.23k | LzmaEnc_SetDataSize(p->enc, expected); |
567 | | |
568 | 8.23k | RINOK(LzmaEnc_PrepareForLzma2(p->enc, |
569 | 8.23k | &limitedInStream.vt, |
570 | 8.23k | LZMA2_KEEP_WINDOW_SIZE, |
571 | 8.23k | me->alloc, |
572 | 8.23k | me->allocBig)); |
573 | 8.23k | } |
574 | 0 | else |
575 | 0 | { |
576 | 0 | inSizeCur = inDataSize - (size_t)unpackTotal; |
577 | 0 | if (me->props.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID |
578 | 0 | && inSizeCur > me->props.blockSize) |
579 | 0 | inSizeCur = (size_t)me->props.blockSize; |
580 | | |
581 | | // LzmaEnc_SetDataSize(p->enc, inSizeCur); |
582 | | |
583 | 0 | RINOK(LzmaEnc_MemPrepare(p->enc, |
584 | 0 | inData + (size_t)unpackTotal, inSizeCur, |
585 | 0 | LZMA2_KEEP_WINDOW_SIZE, |
586 | 0 | me->alloc, |
587 | 0 | me->allocBig)); |
588 | 0 | } |
589 | | |
590 | 8.23k | for (;;) |
591 | 16.5k | { |
592 | 16.5k | size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX; |
593 | 16.5k | if (outBuf) |
594 | 0 | packSize = outLim - (size_t)packTotal; |
595 | | |
596 | 16.5k | res = Lzma2EncInt_EncodeSubblock(p, |
597 | 16.5k | outBuf ? outBuf + (size_t)packTotal : me->tempBufLzma, &packSize, |
598 | 16.5k | outBuf ? NULL : outStream); |
599 | | |
600 | 16.5k | if (res != SZ_OK) |
601 | 0 | break; |
602 | | |
603 | 16.5k | packTotal += packSize; |
604 | 16.5k | if (outBuf) |
605 | 0 | *outBufSize = (size_t)packTotal; |
606 | | |
607 | 16.5k | res = Progress(progress, unpackTotal + p->srcPos, packTotal); |
608 | 16.5k | if (res != SZ_OK) |
609 | 0 | break; |
610 | | |
611 | | /* |
612 | | if (LzmaEnc_GetNumAvailableBytes(p->enc) == 0) |
613 | | break; |
614 | | */ |
615 | | |
616 | 16.5k | if (packSize == 0) |
617 | 8.23k | break; |
618 | 16.5k | } |
619 | | |
620 | 8.23k | LzmaEnc_Finish(p->enc); |
621 | | |
622 | 8.23k | unpackTotal += p->srcPos; |
623 | | |
624 | 8.23k | RINOK(res); |
625 | | |
626 | 8.23k | if (p->srcPos != (inStream ? limitedInStream.processed : inSizeCur)) |
627 | 0 | return SZ_ERROR_FAIL; |
628 | | |
629 | 8.23k | if (inStream ? limitedInStream.finished : (unpackTotal == inDataSize)) |
630 | 8.23k | { |
631 | 8.23k | if (finished) |
632 | 8.23k | { |
633 | 8.23k | if (outBuf) |
634 | 0 | { |
635 | 0 | size_t destPos = *outBufSize; |
636 | 0 | if (destPos >= outLim) |
637 | 0 | return SZ_ERROR_OUTPUT_EOF; |
638 | 0 | outBuf[destPos] = 0; |
639 | 0 | *outBufSize = destPos + 1; |
640 | 0 | } |
641 | 8.23k | else |
642 | 8.23k | { |
643 | 8.23k | Byte b = 0; |
644 | 8.23k | if (ISeqOutStream_Write(outStream, &b, 1) != 1) |
645 | 0 | return SZ_ERROR_WRITE; |
646 | 8.23k | } |
647 | 8.23k | } |
648 | 8.23k | return SZ_OK; |
649 | 8.23k | } |
650 | 8.23k | } |
651 | 8.23k | } |
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 | 8.23k | { |
723 | 8.23k | CLzma2Enc *p = (CLzma2Enc *)pp; |
724 | | |
725 | 8.23k | if (inStream && inData) |
726 | 0 | return SZ_ERROR_PARAM; |
727 | | |
728 | 8.23k | if (outStream && outBuf) |
729 | 0 | return SZ_ERROR_PARAM; |
730 | | |
731 | 8.23k | { |
732 | 8.23k | unsigned i; |
733 | 16.4k | for (i = 0; i < MTCODER__THREADS_MAX; i++) |
734 | 8.23k | p->coders[i].propsAreSet = False; |
735 | 8.23k | } |
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 = p->props.numBlockThreads_Max; |
784 | | p->mtCoder.expectedDataSize = p->expectedDataSize; |
785 | | |
786 | | { |
787 | | SRes res = MtCoder_Code(&p->mtCoder); |
788 | | if (!outStream) |
789 | | *outBufSize = p->outBuf - outBuf; |
790 | | return res; |
791 | | } |
792 | | } |
793 | | |
794 | | #endif |
795 | | |
796 | | |
797 | 8.23k | return Lzma2Enc_EncodeMt1(p, |
798 | 8.23k | &p->coders[0], |
799 | 8.23k | outStream, outBuf, outBufSize, |
800 | 8.23k | inStream, inData, inDataSize, |
801 | 8.23k | True, /* finished */ |
802 | 8.23k | progress); |
803 | 8.23k | } |