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/XzEnc.c | |
parent | 98e06a519b63b81986abe76d28887f6984a7732b (diff) | |
download | 7zip-f19f813537c7aea1c20749c914e756b54a9c3cf5.tar.gz 7zip-f19f813537c7aea1c20749c914e756b54a9c3cf5.tar.bz2 7zip-f19f813537c7aea1c20749c914e756b54a9c3cf5.zip |
'21.07'21.07
Diffstat (limited to 'C/XzEnc.c')
-rw-r--r-- | C/XzEnc.c | 1330 |
1 files changed, 1330 insertions, 0 deletions
diff --git a/C/XzEnc.c b/C/XzEnc.c new file mode 100644 index 0000000..be174cc --- /dev/null +++ b/C/XzEnc.c | |||
@@ -0,0 +1,1330 @@ | |||
1 | /* XzEnc.c -- Xz Encode | ||
2 | 2021-04-01 : Igor Pavlov : Public domain */ | ||
3 | |||
4 | #include "Precomp.h" | ||
5 | |||
6 | #include <stdlib.h> | ||
7 | #include <string.h> | ||
8 | |||
9 | #include "7zCrc.h" | ||
10 | #include "Bra.h" | ||
11 | #include "CpuArch.h" | ||
12 | |||
13 | #ifdef USE_SUBBLOCK | ||
14 | #include "Bcj3Enc.c" | ||
15 | #include "SbFind.c" | ||
16 | #include "SbEnc.c" | ||
17 | #endif | ||
18 | |||
19 | #include "XzEnc.h" | ||
20 | |||
21 | // #define _7ZIP_ST | ||
22 | |||
23 | #ifndef _7ZIP_ST | ||
24 | #include "MtCoder.h" | ||
25 | #else | ||
26 | #define MTCODER__THREADS_MAX 1 | ||
27 | #define MTCODER__BLOCKS_MAX 1 | ||
28 | #endif | ||
29 | |||
30 | #define XZ_GET_PAD_SIZE(dataSize) ((4 - ((unsigned)(dataSize) & 3)) & 3) | ||
31 | |||
32 | /* max pack size for LZMA2 block + check-64bytrs: */ | ||
33 | #define XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize) ((unpackSize) + ((unpackSize) >> 10) + 16 + 64) | ||
34 | |||
35 | #define XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(unpackSize) (XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize)) | ||
36 | |||
37 | |||
38 | #define XzBlock_ClearFlags(p) (p)->flags = 0; | ||
39 | #define XzBlock_SetNumFilters(p, n) (p)->flags = (Byte)((p)->flags | ((n) - 1)); | ||
40 | #define XzBlock_SetHasPackSize(p) (p)->flags |= XZ_BF_PACK_SIZE; | ||
41 | #define XzBlock_SetHasUnpackSize(p) (p)->flags |= XZ_BF_UNPACK_SIZE; | ||
42 | |||
43 | |||
44 | static SRes WriteBytes(ISeqOutStream *s, const void *buf, size_t size) | ||
45 | { | ||
46 | return (ISeqOutStream_Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE; | ||
47 | } | ||
48 | |||
49 | static SRes WriteBytesUpdateCrc(ISeqOutStream *s, const void *buf, size_t size, UInt32 *crc) | ||
50 | { | ||
51 | *crc = CrcUpdate(*crc, buf, size); | ||
52 | return WriteBytes(s, buf, size); | ||
53 | } | ||
54 | |||
55 | |||
56 | static SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s) | ||
57 | { | ||
58 | UInt32 crc; | ||
59 | Byte header[XZ_STREAM_HEADER_SIZE]; | ||
60 | memcpy(header, XZ_SIG, XZ_SIG_SIZE); | ||
61 | header[XZ_SIG_SIZE] = (Byte)(f >> 8); | ||
62 | header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF); | ||
63 | crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE); | ||
64 | SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc); | ||
65 | return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE); | ||
66 | } | ||
67 | |||
68 | |||
69 | static SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s) | ||
70 | { | ||
71 | Byte header[XZ_BLOCK_HEADER_SIZE_MAX]; | ||
72 | |||
73 | unsigned pos = 1; | ||
74 | unsigned numFilters, i; | ||
75 | header[pos++] = p->flags; | ||
76 | |||
77 | if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize); | ||
78 | if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize); | ||
79 | numFilters = XzBlock_GetNumFilters(p); | ||
80 | |||
81 | for (i = 0; i < numFilters; i++) | ||
82 | { | ||
83 | const CXzFilter *f = &p->filters[i]; | ||
84 | pos += Xz_WriteVarInt(header + pos, f->id); | ||
85 | pos += Xz_WriteVarInt(header + pos, f->propsSize); | ||
86 | memcpy(header + pos, f->props, f->propsSize); | ||
87 | pos += f->propsSize; | ||
88 | } | ||
89 | |||
90 | while ((pos & 3) != 0) | ||
91 | header[pos++] = 0; | ||
92 | |||
93 | header[0] = (Byte)(pos >> 2); | ||
94 | SetUi32(header + pos, CrcCalc(header, pos)); | ||
95 | return WriteBytes(s, header, pos + 4); | ||
96 | } | ||
97 | |||
98 | |||
99 | |||
100 | |||
101 | typedef struct | ||
102 | { | ||
103 | size_t numBlocks; | ||
104 | size_t size; | ||
105 | size_t allocated; | ||
106 | Byte *blocks; | ||
107 | } CXzEncIndex; | ||
108 | |||
109 | |||
110 | static void XzEncIndex_Construct(CXzEncIndex *p) | ||
111 | { | ||
112 | p->numBlocks = 0; | ||
113 | p->size = 0; | ||
114 | p->allocated = 0; | ||
115 | p->blocks = NULL; | ||
116 | } | ||
117 | |||
118 | static void XzEncIndex_Init(CXzEncIndex *p) | ||
119 | { | ||
120 | p->numBlocks = 0; | ||
121 | p->size = 0; | ||
122 | } | ||
123 | |||
124 | static void XzEncIndex_Free(CXzEncIndex *p, ISzAllocPtr alloc) | ||
125 | { | ||
126 | if (p->blocks) | ||
127 | { | ||
128 | ISzAlloc_Free(alloc, p->blocks); | ||
129 | p->blocks = NULL; | ||
130 | } | ||
131 | p->numBlocks = 0; | ||
132 | p->size = 0; | ||
133 | p->allocated = 0; | ||
134 | } | ||
135 | |||
136 | |||
137 | static SRes XzEncIndex_ReAlloc(CXzEncIndex *p, size_t newSize, ISzAllocPtr alloc) | ||
138 | { | ||
139 | Byte *blocks = (Byte *)ISzAlloc_Alloc(alloc, newSize); | ||
140 | if (!blocks) | ||
141 | return SZ_ERROR_MEM; | ||
142 | if (p->size != 0) | ||
143 | memcpy(blocks, p->blocks, p->size); | ||
144 | if (p->blocks) | ||
145 | ISzAlloc_Free(alloc, p->blocks); | ||
146 | p->blocks = blocks; | ||
147 | p->allocated = newSize; | ||
148 | return SZ_OK; | ||
149 | } | ||
150 | |||
151 | |||
152 | static SRes XzEncIndex_PreAlloc(CXzEncIndex *p, UInt64 numBlocks, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc) | ||
153 | { | ||
154 | UInt64 pos; | ||
155 | { | ||
156 | Byte buf[32]; | ||
157 | unsigned pos2 = Xz_WriteVarInt(buf, totalSize); | ||
158 | pos2 += Xz_WriteVarInt(buf + pos2, unpackSize); | ||
159 | pos = numBlocks * pos2; | ||
160 | } | ||
161 | |||
162 | if (pos <= p->allocated - p->size) | ||
163 | return SZ_OK; | ||
164 | { | ||
165 | UInt64 newSize64 = p->size + pos; | ||
166 | size_t newSize = (size_t)newSize64; | ||
167 | if (newSize != newSize64) | ||
168 | return SZ_ERROR_MEM; | ||
169 | return XzEncIndex_ReAlloc(p, newSize, alloc); | ||
170 | } | ||
171 | } | ||
172 | |||
173 | |||
174 | static SRes XzEncIndex_AddIndexRecord(CXzEncIndex *p, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc) | ||
175 | { | ||
176 | Byte buf[32]; | ||
177 | unsigned pos = Xz_WriteVarInt(buf, totalSize); | ||
178 | pos += Xz_WriteVarInt(buf + pos, unpackSize); | ||
179 | |||
180 | if (pos > p->allocated - p->size) | ||
181 | { | ||
182 | size_t newSize = p->allocated * 2 + 16 * 2; | ||
183 | if (newSize < p->size + pos) | ||
184 | return SZ_ERROR_MEM; | ||
185 | RINOK(XzEncIndex_ReAlloc(p, newSize, alloc)); | ||
186 | } | ||
187 | memcpy(p->blocks + p->size, buf, pos); | ||
188 | p->size += pos; | ||
189 | p->numBlocks++; | ||
190 | return SZ_OK; | ||
191 | } | ||
192 | |||
193 | |||
194 | static SRes XzEncIndex_WriteFooter(const CXzEncIndex *p, CXzStreamFlags flags, ISeqOutStream *s) | ||
195 | { | ||
196 | Byte buf[32]; | ||
197 | UInt64 globalPos; | ||
198 | UInt32 crc = CRC_INIT_VAL; | ||
199 | unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks); | ||
200 | |||
201 | globalPos = pos; | ||
202 | buf[0] = 0; | ||
203 | RINOK(WriteBytesUpdateCrc(s, buf, pos, &crc)); | ||
204 | RINOK(WriteBytesUpdateCrc(s, p->blocks, p->size, &crc)); | ||
205 | globalPos += p->size; | ||
206 | |||
207 | pos = XZ_GET_PAD_SIZE(globalPos); | ||
208 | buf[1] = 0; | ||
209 | buf[2] = 0; | ||
210 | buf[3] = 0; | ||
211 | globalPos += pos; | ||
212 | |||
213 | crc = CrcUpdate(crc, buf + 4 - pos, pos); | ||
214 | SetUi32(buf + 4, CRC_GET_DIGEST(crc)); | ||
215 | |||
216 | SetUi32(buf + 8 + 4, (UInt32)(globalPos >> 2)); | ||
217 | buf[8 + 8] = (Byte)(flags >> 8); | ||
218 | buf[8 + 9] = (Byte)(flags & 0xFF); | ||
219 | SetUi32(buf + 8, CrcCalc(buf + 8 + 4, 6)); | ||
220 | buf[8 + 10] = XZ_FOOTER_SIG_0; | ||
221 | buf[8 + 11] = XZ_FOOTER_SIG_1; | ||
222 | |||
223 | return WriteBytes(s, buf + 4 - pos, pos + 4 + 12); | ||
224 | } | ||
225 | |||
226 | |||
227 | |||
228 | /* ---------- CSeqCheckInStream ---------- */ | ||
229 | |||
230 | typedef struct | ||
231 | { | ||
232 | ISeqInStream vt; | ||
233 | ISeqInStream *realStream; | ||
234 | const Byte *data; | ||
235 | UInt64 limit; | ||
236 | UInt64 processed; | ||
237 | int realStreamFinished; | ||
238 | CXzCheck check; | ||
239 | } CSeqCheckInStream; | ||
240 | |||
241 | static void SeqCheckInStream_Init(CSeqCheckInStream *p, unsigned checkMode) | ||
242 | { | ||
243 | p->limit = (UInt64)(Int64)-1; | ||
244 | p->processed = 0; | ||
245 | p->realStreamFinished = 0; | ||
246 | XzCheck_Init(&p->check, checkMode); | ||
247 | } | ||
248 | |||
249 | static void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest) | ||
250 | { | ||
251 | XzCheck_Final(&p->check, digest); | ||
252 | } | ||
253 | |||
254 | static SRes SeqCheckInStream_Read(const ISeqInStream *pp, void *data, size_t *size) | ||
255 | { | ||
256 | CSeqCheckInStream *p = CONTAINER_FROM_VTBL(pp, CSeqCheckInStream, vt); | ||
257 | size_t size2 = *size; | ||
258 | SRes res = SZ_OK; | ||
259 | |||
260 | if (p->limit != (UInt64)(Int64)-1) | ||
261 | { | ||
262 | UInt64 rem = p->limit - p->processed; | ||
263 | if (size2 > rem) | ||
264 | size2 = (size_t)rem; | ||
265 | } | ||
266 | if (size2 != 0) | ||
267 | { | ||
268 | if (p->realStream) | ||
269 | { | ||
270 | res = ISeqInStream_Read(p->realStream, data, &size2); | ||
271 | p->realStreamFinished = (size2 == 0) ? 1 : 0; | ||
272 | } | ||
273 | else | ||
274 | memcpy(data, p->data + (size_t)p->processed, size2); | ||
275 | XzCheck_Update(&p->check, data, size2); | ||
276 | p->processed += size2; | ||
277 | } | ||
278 | *size = size2; | ||
279 | return res; | ||
280 | } | ||
281 | |||
282 | |||
283 | /* ---------- CSeqSizeOutStream ---------- */ | ||
284 | |||
285 | typedef struct | ||
286 | { | ||
287 | ISeqOutStream vt; | ||
288 | ISeqOutStream *realStream; | ||
289 | Byte *outBuf; | ||
290 | size_t outBufLimit; | ||
291 | UInt64 processed; | ||
292 | } CSeqSizeOutStream; | ||
293 | |||
294 | static size_t SeqSizeOutStream_Write(const ISeqOutStream *pp, const void *data, size_t size) | ||
295 | { | ||
296 | CSeqSizeOutStream *p = CONTAINER_FROM_VTBL(pp, CSeqSizeOutStream, vt); | ||
297 | if (p->realStream) | ||
298 | size = ISeqOutStream_Write(p->realStream, data, size); | ||
299 | else | ||
300 | { | ||
301 | if (size > p->outBufLimit - (size_t)p->processed) | ||
302 | return 0; | ||
303 | memcpy(p->outBuf + (size_t)p->processed, data, size); | ||
304 | } | ||
305 | p->processed += size; | ||
306 | return size; | ||
307 | } | ||
308 | |||
309 | |||
310 | /* ---------- CSeqInFilter ---------- */ | ||
311 | |||
312 | #define FILTER_BUF_SIZE (1 << 20) | ||
313 | |||
314 | typedef struct | ||
315 | { | ||
316 | ISeqInStream p; | ||
317 | ISeqInStream *realStream; | ||
318 | IStateCoder StateCoder; | ||
319 | Byte *buf; | ||
320 | size_t curPos; | ||
321 | size_t endPos; | ||
322 | int srcWasFinished; | ||
323 | } CSeqInFilter; | ||
324 | |||
325 | |||
326 | SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc); | ||
327 | |||
328 | static SRes SeqInFilter_Init(CSeqInFilter *p, const CXzFilter *props, ISzAllocPtr alloc) | ||
329 | { | ||
330 | if (!p->buf) | ||
331 | { | ||
332 | p->buf = (Byte *)ISzAlloc_Alloc(alloc, FILTER_BUF_SIZE); | ||
333 | if (!p->buf) | ||
334 | return SZ_ERROR_MEM; | ||
335 | } | ||
336 | p->curPos = p->endPos = 0; | ||
337 | p->srcWasFinished = 0; | ||
338 | RINOK(BraState_SetFromMethod(&p->StateCoder, props->id, 1, alloc)); | ||
339 | RINOK(p->StateCoder.SetProps(p->StateCoder.p, props->props, props->propsSize, alloc)); | ||
340 | p->StateCoder.Init(p->StateCoder.p); | ||
341 | return SZ_OK; | ||
342 | } | ||
343 | |||
344 | |||
345 | static SRes SeqInFilter_Read(const ISeqInStream *pp, void *data, size_t *size) | ||
346 | { | ||
347 | CSeqInFilter *p = CONTAINER_FROM_VTBL(pp, CSeqInFilter, p); | ||
348 | size_t sizeOriginal = *size; | ||
349 | if (sizeOriginal == 0) | ||
350 | return SZ_OK; | ||
351 | *size = 0; | ||
352 | |||
353 | for (;;) | ||
354 | { | ||
355 | if (!p->srcWasFinished && p->curPos == p->endPos) | ||
356 | { | ||
357 | p->curPos = 0; | ||
358 | p->endPos = FILTER_BUF_SIZE; | ||
359 | RINOK(ISeqInStream_Read(p->realStream, p->buf, &p->endPos)); | ||
360 | if (p->endPos == 0) | ||
361 | p->srcWasFinished = 1; | ||
362 | } | ||
363 | { | ||
364 | SizeT srcLen = p->endPos - p->curPos; | ||
365 | ECoderStatus status; | ||
366 | SRes res; | ||
367 | *size = sizeOriginal; | ||
368 | res = p->StateCoder.Code2(p->StateCoder.p, | ||
369 | (Byte *)data, size, | ||
370 | p->buf + p->curPos, &srcLen, | ||
371 | p->srcWasFinished, CODER_FINISH_ANY, | ||
372 | &status); | ||
373 | p->curPos += srcLen; | ||
374 | if (*size != 0 || srcLen == 0 || res != SZ_OK) | ||
375 | return res; | ||
376 | } | ||
377 | } | ||
378 | } | ||
379 | |||
380 | static void SeqInFilter_Construct(CSeqInFilter *p) | ||
381 | { | ||
382 | p->buf = NULL; | ||
383 | p->StateCoder.p = NULL; | ||
384 | p->p.Read = SeqInFilter_Read; | ||
385 | } | ||
386 | |||
387 | static void SeqInFilter_Free(CSeqInFilter *p, ISzAllocPtr alloc) | ||
388 | { | ||
389 | if (p->StateCoder.p) | ||
390 | { | ||
391 | p->StateCoder.Free(p->StateCoder.p, alloc); | ||
392 | p->StateCoder.p = NULL; | ||
393 | } | ||
394 | if (p->buf) | ||
395 | { | ||
396 | ISzAlloc_Free(alloc, p->buf); | ||
397 | p->buf = NULL; | ||
398 | } | ||
399 | } | ||
400 | |||
401 | |||
402 | /* ---------- CSbEncInStream ---------- */ | ||
403 | |||
404 | #ifdef USE_SUBBLOCK | ||
405 | |||
406 | typedef struct | ||
407 | { | ||
408 | ISeqInStream vt; | ||
409 | ISeqInStream *inStream; | ||
410 | CSbEnc enc; | ||
411 | } CSbEncInStream; | ||
412 | |||
413 | static SRes SbEncInStream_Read(const ISeqInStream *pp, void *data, size_t *size) | ||
414 | { | ||
415 | CSbEncInStream *p = CONTAINER_FROM_VTBL(pp, CSbEncInStream, vt); | ||
416 | size_t sizeOriginal = *size; | ||
417 | if (sizeOriginal == 0) | ||
418 | return SZ_OK; | ||
419 | |||
420 | for (;;) | ||
421 | { | ||
422 | if (p->enc.needRead && !p->enc.readWasFinished) | ||
423 | { | ||
424 | size_t processed = p->enc.needReadSizeMax; | ||
425 | RINOK(p->inStream->Read(p->inStream, p->enc.buf + p->enc.readPos, &processed)); | ||
426 | p->enc.readPos += processed; | ||
427 | if (processed == 0) | ||
428 | { | ||
429 | p->enc.readWasFinished = True; | ||
430 | p->enc.isFinalFinished = True; | ||
431 | } | ||
432 | p->enc.needRead = False; | ||
433 | } | ||
434 | |||
435 | *size = sizeOriginal; | ||
436 | RINOK(SbEnc_Read(&p->enc, data, size)); | ||
437 | if (*size != 0 || !p->enc.needRead) | ||
438 | return SZ_OK; | ||
439 | } | ||
440 | } | ||
441 | |||
442 | void SbEncInStream_Construct(CSbEncInStream *p, ISzAllocPtr alloc) | ||
443 | { | ||
444 | SbEnc_Construct(&p->enc, alloc); | ||
445 | p->vt.Read = SbEncInStream_Read; | ||
446 | } | ||
447 | |||
448 | SRes SbEncInStream_Init(CSbEncInStream *p) | ||
449 | { | ||
450 | return SbEnc_Init(&p->enc); | ||
451 | } | ||
452 | |||
453 | void SbEncInStream_Free(CSbEncInStream *p) | ||
454 | { | ||
455 | SbEnc_Free(&p->enc); | ||
456 | } | ||
457 | |||
458 | #endif | ||
459 | |||
460 | |||
461 | |||
462 | /* ---------- CXzProps ---------- */ | ||
463 | |||
464 | |||
465 | void XzFilterProps_Init(CXzFilterProps *p) | ||
466 | { | ||
467 | p->id = 0; | ||
468 | p->delta = 0; | ||
469 | p->ip = 0; | ||
470 | p->ipDefined = False; | ||
471 | } | ||
472 | |||
473 | void XzProps_Init(CXzProps *p) | ||
474 | { | ||
475 | p->checkId = XZ_CHECK_CRC32; | ||
476 | p->blockSize = XZ_PROPS__BLOCK_SIZE__AUTO; | ||
477 | p->numBlockThreads_Reduced = -1; | ||
478 | p->numBlockThreads_Max = -1; | ||
479 | p->numTotalThreads = -1; | ||
480 | p->reduceSize = (UInt64)(Int64)-1; | ||
481 | p->forceWriteSizesInHeader = 0; | ||
482 | // p->forceWriteSizesInHeader = 1; | ||
483 | |||
484 | XzFilterProps_Init(&p->filterProps); | ||
485 | Lzma2EncProps_Init(&p->lzma2Props); | ||
486 | } | ||
487 | |||
488 | |||
489 | static void XzEncProps_Normalize_Fixed(CXzProps *p) | ||
490 | { | ||
491 | UInt64 fileSize; | ||
492 | int t1, t1n, t2, t2r, t3; | ||
493 | { | ||
494 | CLzma2EncProps tp = p->lzma2Props; | ||
495 | if (tp.numTotalThreads <= 0) | ||
496 | tp.numTotalThreads = p->numTotalThreads; | ||
497 | Lzma2EncProps_Normalize(&tp); | ||
498 | t1n = tp.numTotalThreads; | ||
499 | } | ||
500 | |||
501 | t1 = p->lzma2Props.numTotalThreads; | ||
502 | t2 = p->numBlockThreads_Max; | ||
503 | t3 = p->numTotalThreads; | ||
504 | |||
505 | if (t2 > MTCODER__THREADS_MAX) | ||
506 | t2 = MTCODER__THREADS_MAX; | ||
507 | |||
508 | if (t3 <= 0) | ||
509 | { | ||
510 | if (t2 <= 0) | ||
511 | t2 = 1; | ||
512 | t3 = t1n * t2; | ||
513 | } | ||
514 | else if (t2 <= 0) | ||
515 | { | ||
516 | t2 = t3 / t1n; | ||
517 | if (t2 == 0) | ||
518 | { | ||
519 | t1 = 1; | ||
520 | t2 = t3; | ||
521 | } | ||
522 | if (t2 > MTCODER__THREADS_MAX) | ||
523 | t2 = MTCODER__THREADS_MAX; | ||
524 | } | ||
525 | else if (t1 <= 0) | ||
526 | { | ||
527 | t1 = t3 / t2; | ||
528 | if (t1 == 0) | ||
529 | t1 = 1; | ||
530 | } | ||
531 | else | ||
532 | t3 = t1n * t2; | ||
533 | |||
534 | p->lzma2Props.numTotalThreads = t1; | ||
535 | |||
536 | t2r = t2; | ||
537 | |||
538 | fileSize = p->reduceSize; | ||
539 | |||
540 | if ((p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1)) | ||
541 | p->lzma2Props.lzmaProps.reduceSize = p->blockSize; | ||
542 | |||
543 | Lzma2EncProps_Normalize(&p->lzma2Props); | ||
544 | |||
545 | t1 = p->lzma2Props.numTotalThreads; | ||
546 | |||
547 | { | ||
548 | if (t2 > 1 && fileSize != (UInt64)(Int64)-1) | ||
549 | { | ||
550 | UInt64 numBlocks = fileSize / p->blockSize; | ||
551 | if (numBlocks * p->blockSize != fileSize) | ||
552 | numBlocks++; | ||
553 | if (numBlocks < (unsigned)t2) | ||
554 | { | ||
555 | t2r = (int)numBlocks; | ||
556 | if (t2r == 0) | ||
557 | t2r = 1; | ||
558 | t3 = t1 * t2r; | ||
559 | } | ||
560 | } | ||
561 | } | ||
562 | |||
563 | p->numBlockThreads_Max = t2; | ||
564 | p->numBlockThreads_Reduced = t2r; | ||
565 | p->numTotalThreads = t3; | ||
566 | } | ||
567 | |||
568 | |||
569 | static void XzProps_Normalize(CXzProps *p) | ||
570 | { | ||
571 | /* we normalize xzProps properties, but we normalize only some of CXzProps::lzma2Props properties. | ||
572 | Lzma2Enc_SetProps() will normalize lzma2Props later. */ | ||
573 | |||
574 | if (p->blockSize == XZ_PROPS__BLOCK_SIZE__SOLID) | ||
575 | { | ||
576 | p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; | ||
577 | p->numBlockThreads_Reduced = 1; | ||
578 | p->numBlockThreads_Max = 1; | ||
579 | if (p->lzma2Props.numTotalThreads <= 0) | ||
580 | p->lzma2Props.numTotalThreads = p->numTotalThreads; | ||
581 | return; | ||
582 | } | ||
583 | else | ||
584 | { | ||
585 | CLzma2EncProps *lzma2 = &p->lzma2Props; | ||
586 | if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) | ||
587 | { | ||
588 | // xz-auto | ||
589 | p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; | ||
590 | |||
591 | if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) | ||
592 | { | ||
593 | // if (xz-auto && lzma2-solid) - we use solid for both | ||
594 | p->blockSize = XZ_PROPS__BLOCK_SIZE__SOLID; | ||
595 | p->numBlockThreads_Reduced = 1; | ||
596 | p->numBlockThreads_Max = 1; | ||
597 | if (p->lzma2Props.numTotalThreads <= 0) | ||
598 | p->lzma2Props.numTotalThreads = p->numTotalThreads; | ||
599 | } | ||
600 | else | ||
601 | { | ||
602 | // if (xz-auto && (lzma2-auto || lzma2-fixed_) | ||
603 | // we calculate block size for lzma2 and use that block size for xz, lzma2 uses single-chunk per block | ||
604 | CLzma2EncProps tp = p->lzma2Props; | ||
605 | if (tp.numTotalThreads <= 0) | ||
606 | tp.numTotalThreads = p->numTotalThreads; | ||
607 | |||
608 | Lzma2EncProps_Normalize(&tp); | ||
609 | |||
610 | p->blockSize = tp.blockSize; // fixed or solid | ||
611 | p->numBlockThreads_Reduced = tp.numBlockThreads_Reduced; | ||
612 | p->numBlockThreads_Max = tp.numBlockThreads_Max; | ||
613 | if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) | ||
614 | lzma2->blockSize = tp.blockSize; // fixed or solid, LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID | ||
615 | if (lzma2->lzmaProps.reduceSize > tp.blockSize && tp.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) | ||
616 | lzma2->lzmaProps.reduceSize = tp.blockSize; | ||
617 | lzma2->numBlockThreads_Reduced = 1; | ||
618 | lzma2->numBlockThreads_Max = 1; | ||
619 | return; | ||
620 | } | ||
621 | } | ||
622 | else | ||
623 | { | ||
624 | // xz-fixed | ||
625 | // we can use xz::reduceSize or xz::blockSize as base for lzmaProps::reduceSize | ||
626 | |||
627 | p->lzma2Props.lzmaProps.reduceSize = p->reduceSize; | ||
628 | { | ||
629 | UInt64 r = p->reduceSize; | ||
630 | if (r > p->blockSize || r == (UInt64)(Int64)-1) | ||
631 | r = p->blockSize; | ||
632 | lzma2->lzmaProps.reduceSize = r; | ||
633 | } | ||
634 | if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO) | ||
635 | lzma2->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID; | ||
636 | else if (lzma2->blockSize > p->blockSize && lzma2->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID) | ||
637 | lzma2->blockSize = p->blockSize; | ||
638 | |||
639 | XzEncProps_Normalize_Fixed(p); | ||
640 | } | ||
641 | } | ||
642 | } | ||
643 | |||
644 | |||
645 | /* ---------- CLzma2WithFilters ---------- */ | ||
646 | |||
647 | typedef struct | ||
648 | { | ||
649 | CLzma2EncHandle lzma2; | ||
650 | CSeqInFilter filter; | ||
651 | |||
652 | #ifdef USE_SUBBLOCK | ||
653 | CSbEncInStream sb; | ||
654 | #endif | ||
655 | } CLzma2WithFilters; | ||
656 | |||
657 | |||
658 | static void Lzma2WithFilters_Construct(CLzma2WithFilters *p) | ||
659 | { | ||
660 | p->lzma2 = NULL; | ||
661 | SeqInFilter_Construct(&p->filter); | ||
662 | |||
663 | #ifdef USE_SUBBLOCK | ||
664 | SbEncInStream_Construct(&p->sb, alloc); | ||
665 | #endif | ||
666 | } | ||
667 | |||
668 | |||
669 | static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p, ISzAllocPtr alloc, ISzAllocPtr bigAlloc) | ||
670 | { | ||
671 | if (!p->lzma2) | ||
672 | { | ||
673 | p->lzma2 = Lzma2Enc_Create(alloc, bigAlloc); | ||
674 | if (!p->lzma2) | ||
675 | return SZ_ERROR_MEM; | ||
676 | } | ||
677 | return SZ_OK; | ||
678 | } | ||
679 | |||
680 | |||
681 | static void Lzma2WithFilters_Free(CLzma2WithFilters *p, ISzAllocPtr alloc) | ||
682 | { | ||
683 | #ifdef USE_SUBBLOCK | ||
684 | SbEncInStream_Free(&p->sb); | ||
685 | #endif | ||
686 | |||
687 | SeqInFilter_Free(&p->filter, alloc); | ||
688 | if (p->lzma2) | ||
689 | { | ||
690 | Lzma2Enc_Destroy(p->lzma2); | ||
691 | p->lzma2 = NULL; | ||
692 | } | ||
693 | } | ||
694 | |||
695 | |||
696 | typedef struct | ||
697 | { | ||
698 | UInt64 unpackSize; | ||
699 | UInt64 totalSize; | ||
700 | size_t headerSize; | ||
701 | } CXzEncBlockInfo; | ||
702 | |||
703 | |||
704 | static SRes Xz_CompressBlock( | ||
705 | CLzma2WithFilters *lzmaf, | ||
706 | |||
707 | ISeqOutStream *outStream, | ||
708 | Byte *outBufHeader, | ||
709 | Byte *outBufData, size_t outBufDataLimit, | ||
710 | |||
711 | ISeqInStream *inStream, | ||
712 | // UInt64 expectedSize, | ||
713 | const Byte *inBuf, // used if (!inStream) | ||
714 | size_t inBufSize, // used if (!inStream), it's block size, props->blockSize is ignored | ||
715 | |||
716 | const CXzProps *props, | ||
717 | ICompressProgress *progress, | ||
718 | int *inStreamFinished, /* only for inStream version */ | ||
719 | CXzEncBlockInfo *blockSizes, | ||
720 | ISzAllocPtr alloc, | ||
721 | ISzAllocPtr allocBig) | ||
722 | { | ||
723 | CSeqCheckInStream checkInStream; | ||
724 | CSeqSizeOutStream seqSizeOutStream; | ||
725 | CXzBlock block; | ||
726 | unsigned filterIndex = 0; | ||
727 | CXzFilter *filter = NULL; | ||
728 | const CXzFilterProps *fp = &props->filterProps; | ||
729 | if (fp->id == 0) | ||
730 | fp = NULL; | ||
731 | |||
732 | *inStreamFinished = False; | ||
733 | |||
734 | RINOK(Lzma2WithFilters_Create(lzmaf, alloc, allocBig)); | ||
735 | |||
736 | RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, &props->lzma2Props)); | ||
737 | |||
738 | XzBlock_ClearFlags(&block); | ||
739 | XzBlock_SetNumFilters(&block, 1 + (fp ? 1 : 0)); | ||
740 | |||
741 | if (fp) | ||
742 | { | ||
743 | filter = &block.filters[filterIndex++]; | ||
744 | filter->id = fp->id; | ||
745 | filter->propsSize = 0; | ||
746 | |||
747 | if (fp->id == XZ_ID_Delta) | ||
748 | { | ||
749 | filter->props[0] = (Byte)(fp->delta - 1); | ||
750 | filter->propsSize = 1; | ||
751 | } | ||
752 | else if (fp->ipDefined) | ||
753 | { | ||
754 | Byte *ptr = filter->props; | ||
755 | SetUi32(ptr, fp->ip); | ||
756 | filter->propsSize = 4; | ||
757 | } | ||
758 | } | ||
759 | |||
760 | { | ||
761 | CXzFilter *f = &block.filters[filterIndex++]; | ||
762 | f->id = XZ_ID_LZMA2; | ||
763 | f->propsSize = 1; | ||
764 | f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2); | ||
765 | } | ||
766 | |||
767 | seqSizeOutStream.vt.Write = SeqSizeOutStream_Write; | ||
768 | seqSizeOutStream.realStream = outStream; | ||
769 | seqSizeOutStream.outBuf = outBufData; | ||
770 | seqSizeOutStream.outBufLimit = outBufDataLimit; | ||
771 | seqSizeOutStream.processed = 0; | ||
772 | |||
773 | /* | ||
774 | if (expectedSize != (UInt64)(Int64)-1) | ||
775 | { | ||
776 | block.unpackSize = expectedSize; | ||
777 | if (props->blockSize != (UInt64)(Int64)-1) | ||
778 | if (expectedSize > props->blockSize) | ||
779 | block.unpackSize = props->blockSize; | ||
780 | XzBlock_SetHasUnpackSize(&block); | ||
781 | } | ||
782 | */ | ||
783 | |||
784 | if (outStream) | ||
785 | { | ||
786 | RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt)); | ||
787 | } | ||
788 | |||
789 | checkInStream.vt.Read = SeqCheckInStream_Read; | ||
790 | SeqCheckInStream_Init(&checkInStream, props->checkId); | ||
791 | |||
792 | checkInStream.realStream = inStream; | ||
793 | checkInStream.data = inBuf; | ||
794 | checkInStream.limit = props->blockSize; | ||
795 | if (!inStream) | ||
796 | checkInStream.limit = inBufSize; | ||
797 | |||
798 | if (fp) | ||
799 | { | ||
800 | #ifdef USE_SUBBLOCK | ||
801 | if (fp->id == XZ_ID_Subblock) | ||
802 | { | ||
803 | lzmaf->sb.inStream = &checkInStream.vt; | ||
804 | RINOK(SbEncInStream_Init(&lzmaf->sb)); | ||
805 | } | ||
806 | else | ||
807 | #endif | ||
808 | { | ||
809 | lzmaf->filter.realStream = &checkInStream.vt; | ||
810 | RINOK(SeqInFilter_Init(&lzmaf->filter, filter, alloc)); | ||
811 | } | ||
812 | } | ||
813 | |||
814 | { | ||
815 | SRes res; | ||
816 | Byte *outBuf = NULL; | ||
817 | size_t outSize = 0; | ||
818 | BoolInt useStream = (fp || inStream); | ||
819 | // useStream = True; | ||
820 | |||
821 | if (!useStream) | ||
822 | { | ||
823 | XzCheck_Update(&checkInStream.check, inBuf, inBufSize); | ||
824 | checkInStream.processed = inBufSize; | ||
825 | } | ||
826 | |||
827 | if (!outStream) | ||
828 | { | ||
829 | outBuf = seqSizeOutStream.outBuf; // + (size_t)seqSizeOutStream.processed; | ||
830 | outSize = seqSizeOutStream.outBufLimit; // - (size_t)seqSizeOutStream.processed; | ||
831 | } | ||
832 | |||
833 | res = Lzma2Enc_Encode2(lzmaf->lzma2, | ||
834 | outBuf ? NULL : &seqSizeOutStream.vt, | ||
835 | outBuf, | ||
836 | outBuf ? &outSize : NULL, | ||
837 | |||
838 | useStream ? | ||
839 | (fp ? | ||
840 | ( | ||
841 | #ifdef USE_SUBBLOCK | ||
842 | (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.vt: | ||
843 | #endif | ||
844 | &lzmaf->filter.p) : | ||
845 | &checkInStream.vt) : NULL, | ||
846 | |||
847 | useStream ? NULL : inBuf, | ||
848 | useStream ? 0 : inBufSize, | ||
849 | |||
850 | progress); | ||
851 | |||
852 | if (outBuf) | ||
853 | seqSizeOutStream.processed += outSize; | ||
854 | |||
855 | RINOK(res); | ||
856 | blockSizes->unpackSize = checkInStream.processed; | ||
857 | } | ||
858 | { | ||
859 | Byte buf[4 + 64]; | ||
860 | unsigned padSize = XZ_GET_PAD_SIZE(seqSizeOutStream.processed); | ||
861 | UInt64 packSize = seqSizeOutStream.processed; | ||
862 | |||
863 | buf[0] = 0; | ||
864 | buf[1] = 0; | ||
865 | buf[2] = 0; | ||
866 | buf[3] = 0; | ||
867 | |||
868 | SeqCheckInStream_GetDigest(&checkInStream, buf + 4); | ||
869 | RINOK(WriteBytes(&seqSizeOutStream.vt, buf + (4 - padSize), padSize + XzFlags_GetCheckSize((CXzStreamFlags)props->checkId))); | ||
870 | |||
871 | blockSizes->totalSize = seqSizeOutStream.processed - padSize; | ||
872 | |||
873 | if (!outStream) | ||
874 | { | ||
875 | seqSizeOutStream.outBuf = outBufHeader; | ||
876 | seqSizeOutStream.outBufLimit = XZ_BLOCK_HEADER_SIZE_MAX; | ||
877 | seqSizeOutStream.processed = 0; | ||
878 | |||
879 | block.unpackSize = blockSizes->unpackSize; | ||
880 | XzBlock_SetHasUnpackSize(&block); | ||
881 | |||
882 | block.packSize = packSize; | ||
883 | XzBlock_SetHasPackSize(&block); | ||
884 | |||
885 | RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt)); | ||
886 | |||
887 | blockSizes->headerSize = (size_t)seqSizeOutStream.processed; | ||
888 | blockSizes->totalSize += seqSizeOutStream.processed; | ||
889 | } | ||
890 | } | ||
891 | |||
892 | if (inStream) | ||
893 | *inStreamFinished = checkInStream.realStreamFinished; | ||
894 | else | ||
895 | { | ||
896 | *inStreamFinished = False; | ||
897 | if (checkInStream.processed != inBufSize) | ||
898 | return SZ_ERROR_FAIL; | ||
899 | } | ||
900 | |||
901 | return SZ_OK; | ||
902 | } | ||
903 | |||
904 | |||
905 | |||
906 | typedef struct | ||
907 | { | ||
908 | ICompressProgress vt; | ||
909 | ICompressProgress *progress; | ||
910 | UInt64 inOffset; | ||
911 | UInt64 outOffset; | ||
912 | } CCompressProgress_XzEncOffset; | ||
913 | |||
914 | |||
915 | static SRes CompressProgress_XzEncOffset_Progress(const ICompressProgress *pp, UInt64 inSize, UInt64 outSize) | ||
916 | { | ||
917 | const CCompressProgress_XzEncOffset *p = CONTAINER_FROM_VTBL(pp, CCompressProgress_XzEncOffset, vt); | ||
918 | inSize += p->inOffset; | ||
919 | outSize += p->outOffset; | ||
920 | return ICompressProgress_Progress(p->progress, inSize, outSize); | ||
921 | } | ||
922 | |||
923 | |||
924 | |||
925 | |||
926 | typedef struct | ||
927 | { | ||
928 | ISzAllocPtr alloc; | ||
929 | ISzAllocPtr allocBig; | ||
930 | |||
931 | CXzProps xzProps; | ||
932 | UInt64 expectedDataSize; | ||
933 | |||
934 | CXzEncIndex xzIndex; | ||
935 | |||
936 | CLzma2WithFilters lzmaf_Items[MTCODER__THREADS_MAX]; | ||
937 | |||
938 | size_t outBufSize; /* size of allocated outBufs[i] */ | ||
939 | Byte *outBufs[MTCODER__BLOCKS_MAX]; | ||
940 | |||
941 | #ifndef _7ZIP_ST | ||
942 | unsigned checkType; | ||
943 | ISeqOutStream *outStream; | ||
944 | BoolInt mtCoder_WasConstructed; | ||
945 | CMtCoder mtCoder; | ||
946 | CXzEncBlockInfo EncBlocks[MTCODER__BLOCKS_MAX]; | ||
947 | #endif | ||
948 | |||
949 | } CXzEnc; | ||
950 | |||
951 | |||
952 | static void XzEnc_Construct(CXzEnc *p) | ||
953 | { | ||
954 | unsigned i; | ||
955 | |||
956 | XzEncIndex_Construct(&p->xzIndex); | ||
957 | |||
958 | for (i = 0; i < MTCODER__THREADS_MAX; i++) | ||
959 | Lzma2WithFilters_Construct(&p->lzmaf_Items[i]); | ||
960 | |||
961 | #ifndef _7ZIP_ST | ||
962 | p->mtCoder_WasConstructed = False; | ||
963 | { | ||
964 | for (i = 0; i < MTCODER__BLOCKS_MAX; i++) | ||
965 | p->outBufs[i] = NULL; | ||
966 | p->outBufSize = 0; | ||
967 | } | ||
968 | #endif | ||
969 | } | ||
970 | |||
971 | |||
972 | static void XzEnc_FreeOutBufs(CXzEnc *p) | ||
973 | { | ||
974 | unsigned i; | ||
975 | for (i = 0; i < MTCODER__BLOCKS_MAX; i++) | ||
976 | if (p->outBufs[i]) | ||
977 | { | ||
978 | ISzAlloc_Free(p->alloc, p->outBufs[i]); | ||
979 | p->outBufs[i] = NULL; | ||
980 | } | ||
981 | p->outBufSize = 0; | ||
982 | } | ||
983 | |||
984 | |||
985 | static void XzEnc_Free(CXzEnc *p, ISzAllocPtr alloc) | ||
986 | { | ||
987 | unsigned i; | ||
988 | |||
989 | XzEncIndex_Free(&p->xzIndex, alloc); | ||
990 | |||
991 | for (i = 0; i < MTCODER__THREADS_MAX; i++) | ||
992 | Lzma2WithFilters_Free(&p->lzmaf_Items[i], alloc); | ||
993 | |||
994 | #ifndef _7ZIP_ST | ||
995 | if (p->mtCoder_WasConstructed) | ||
996 | { | ||
997 | MtCoder_Destruct(&p->mtCoder); | ||
998 | p->mtCoder_WasConstructed = False; | ||
999 | } | ||
1000 | XzEnc_FreeOutBufs(p); | ||
1001 | #endif | ||
1002 | } | ||
1003 | |||
1004 | |||
1005 | CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig) | ||
1006 | { | ||
1007 | CXzEnc *p = (CXzEnc *)ISzAlloc_Alloc(alloc, sizeof(CXzEnc)); | ||
1008 | if (!p) | ||
1009 | return NULL; | ||
1010 | XzEnc_Construct(p); | ||
1011 | XzProps_Init(&p->xzProps); | ||
1012 | XzProps_Normalize(&p->xzProps); | ||
1013 | p->expectedDataSize = (UInt64)(Int64)-1; | ||
1014 | p->alloc = alloc; | ||
1015 | p->allocBig = allocBig; | ||
1016 | return p; | ||
1017 | } | ||
1018 | |||
1019 | |||
1020 | void XzEnc_Destroy(CXzEncHandle pp) | ||
1021 | { | ||
1022 | CXzEnc *p = (CXzEnc *)pp; | ||
1023 | XzEnc_Free(p, p->alloc); | ||
1024 | ISzAlloc_Free(p->alloc, p); | ||
1025 | } | ||
1026 | |||
1027 | |||
1028 | SRes XzEnc_SetProps(CXzEncHandle pp, const CXzProps *props) | ||
1029 | { | ||
1030 | CXzEnc *p = (CXzEnc *)pp; | ||
1031 | p->xzProps = *props; | ||
1032 | XzProps_Normalize(&p->xzProps); | ||
1033 | return SZ_OK; | ||
1034 | } | ||
1035 | |||
1036 | |||
1037 | void XzEnc_SetDataSize(CXzEncHandle pp, UInt64 expectedDataSiize) | ||
1038 | { | ||
1039 | CXzEnc *p = (CXzEnc *)pp; | ||
1040 | p->expectedDataSize = expectedDataSiize; | ||
1041 | } | ||
1042 | |||
1043 | |||
1044 | |||
1045 | |||
1046 | #ifndef _7ZIP_ST | ||
1047 | |||
1048 | static SRes XzEnc_MtCallback_Code(void *pp, unsigned coderIndex, unsigned outBufIndex, | ||
1049 | const Byte *src, size_t srcSize, int finished) | ||
1050 | { | ||
1051 | CXzEnc *me = (CXzEnc *)pp; | ||
1052 | SRes res; | ||
1053 | CMtProgressThunk progressThunk; | ||
1054 | |||
1055 | Byte *dest = me->outBufs[outBufIndex]; | ||
1056 | |||
1057 | UNUSED_VAR(finished) | ||
1058 | |||
1059 | { | ||
1060 | CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex]; | ||
1061 | bInfo->totalSize = 0; | ||
1062 | bInfo->unpackSize = 0; | ||
1063 | bInfo->headerSize = 0; | ||
1064 | } | ||
1065 | |||
1066 | if (!dest) | ||
1067 | { | ||
1068 | dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize); | ||
1069 | if (!dest) | ||
1070 | return SZ_ERROR_MEM; | ||
1071 | me->outBufs[outBufIndex] = dest; | ||
1072 | } | ||
1073 | |||
1074 | MtProgressThunk_CreateVTable(&progressThunk); | ||
1075 | progressThunk.mtProgress = &me->mtCoder.mtProgress; | ||
1076 | MtProgressThunk_Init(&progressThunk); | ||
1077 | |||
1078 | { | ||
1079 | CXzEncBlockInfo blockSizes; | ||
1080 | int inStreamFinished; | ||
1081 | |||
1082 | res = Xz_CompressBlock( | ||
1083 | &me->lzmaf_Items[coderIndex], | ||
1084 | |||
1085 | NULL, | ||
1086 | dest, | ||
1087 | dest + XZ_BLOCK_HEADER_SIZE_MAX, me->outBufSize - XZ_BLOCK_HEADER_SIZE_MAX, | ||
1088 | |||
1089 | NULL, | ||
1090 | // srcSize, // expectedSize | ||
1091 | src, srcSize, | ||
1092 | |||
1093 | &me->xzProps, | ||
1094 | &progressThunk.vt, | ||
1095 | &inStreamFinished, | ||
1096 | &blockSizes, | ||
1097 | me->alloc, | ||
1098 | me->allocBig); | ||
1099 | |||
1100 | if (res == SZ_OK) | ||
1101 | me->EncBlocks[outBufIndex] = blockSizes; | ||
1102 | |||
1103 | return res; | ||
1104 | } | ||
1105 | } | ||
1106 | |||
1107 | |||
1108 | static SRes XzEnc_MtCallback_Write(void *pp, unsigned outBufIndex) | ||
1109 | { | ||
1110 | CXzEnc *me = (CXzEnc *)pp; | ||
1111 | |||
1112 | const CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex]; | ||
1113 | const Byte *data = me->outBufs[outBufIndex]; | ||
1114 | |||
1115 | RINOK(WriteBytes(me->outStream, data, bInfo->headerSize)); | ||
1116 | |||
1117 | { | ||
1118 | UInt64 totalPackFull = bInfo->totalSize + XZ_GET_PAD_SIZE(bInfo->totalSize); | ||
1119 | RINOK(WriteBytes(me->outStream, data + XZ_BLOCK_HEADER_SIZE_MAX, (size_t)totalPackFull - bInfo->headerSize)); | ||
1120 | } | ||
1121 | |||
1122 | return XzEncIndex_AddIndexRecord(&me->xzIndex, bInfo->unpackSize, bInfo->totalSize, me->alloc); | ||
1123 | } | ||
1124 | |||
1125 | #endif | ||
1126 | |||
1127 | |||
1128 | |||
1129 | SRes XzEnc_Encode(CXzEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress) | ||
1130 | { | ||
1131 | CXzEnc *p = (CXzEnc *)pp; | ||
1132 | |||
1133 | const CXzProps *props = &p->xzProps; | ||
1134 | |||
1135 | XzEncIndex_Init(&p->xzIndex); | ||
1136 | { | ||
1137 | UInt64 numBlocks = 1; | ||
1138 | UInt64 blockSize = props->blockSize; | ||
1139 | |||
1140 | if (blockSize != XZ_PROPS__BLOCK_SIZE__SOLID | ||
1141 | && props->reduceSize != (UInt64)(Int64)-1) | ||
1142 | { | ||
1143 | numBlocks = props->reduceSize / blockSize; | ||
1144 | if (numBlocks * blockSize != props->reduceSize) | ||
1145 | numBlocks++; | ||
1146 | } | ||
1147 | else | ||
1148 | blockSize = (UInt64)1 << 62; | ||
1149 | |||
1150 | RINOK(XzEncIndex_PreAlloc(&p->xzIndex, numBlocks, blockSize, XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(blockSize), p->alloc)); | ||
1151 | } | ||
1152 | |||
1153 | RINOK(Xz_WriteHeader((CXzStreamFlags)props->checkId, outStream)); | ||
1154 | |||
1155 | |||
1156 | #ifndef _7ZIP_ST | ||
1157 | if (props->numBlockThreads_Reduced > 1) | ||
1158 | { | ||
1159 | IMtCoderCallback2 vt; | ||
1160 | |||
1161 | if (!p->mtCoder_WasConstructed) | ||
1162 | { | ||
1163 | p->mtCoder_WasConstructed = True; | ||
1164 | MtCoder_Construct(&p->mtCoder); | ||
1165 | } | ||
1166 | |||
1167 | vt.Code = XzEnc_MtCallback_Code; | ||
1168 | vt.Write = XzEnc_MtCallback_Write; | ||
1169 | |||
1170 | p->checkType = props->checkId; | ||
1171 | p->xzProps = *props; | ||
1172 | |||
1173 | p->outStream = outStream; | ||
1174 | |||
1175 | p->mtCoder.allocBig = p->allocBig; | ||
1176 | p->mtCoder.progress = progress; | ||
1177 | p->mtCoder.inStream = inStream; | ||
1178 | p->mtCoder.inData = NULL; | ||
1179 | p->mtCoder.inDataSize = 0; | ||
1180 | p->mtCoder.mtCallback = &vt; | ||
1181 | p->mtCoder.mtCallbackObject = p; | ||
1182 | |||
1183 | if ( props->blockSize == XZ_PROPS__BLOCK_SIZE__SOLID | ||
1184 | || props->blockSize == XZ_PROPS__BLOCK_SIZE__AUTO) | ||
1185 | return SZ_ERROR_FAIL; | ||
1186 | |||
1187 | p->mtCoder.blockSize = (size_t)props->blockSize; | ||
1188 | if (p->mtCoder.blockSize != props->blockSize) | ||
1189 | return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */ | ||
1190 | |||
1191 | { | ||
1192 | size_t destBlockSize = XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(p->mtCoder.blockSize); | ||
1193 | if (destBlockSize < p->mtCoder.blockSize) | ||
1194 | return SZ_ERROR_PARAM; | ||
1195 | if (p->outBufSize != destBlockSize) | ||
1196 | XzEnc_FreeOutBufs(p); | ||
1197 | p->outBufSize = destBlockSize; | ||
1198 | } | ||
1199 | |||
1200 | p->mtCoder.numThreadsMax = (unsigned)props->numBlockThreads_Max; | ||
1201 | p->mtCoder.expectedDataSize = p->expectedDataSize; | ||
1202 | |||
1203 | RINOK(MtCoder_Code(&p->mtCoder)); | ||
1204 | } | ||
1205 | else | ||
1206 | #endif | ||
1207 | { | ||
1208 | int writeStartSizes; | ||
1209 | CCompressProgress_XzEncOffset progress2; | ||
1210 | Byte *bufData = NULL; | ||
1211 | size_t bufSize = 0; | ||
1212 | |||
1213 | progress2.vt.Progress = CompressProgress_XzEncOffset_Progress; | ||
1214 | progress2.inOffset = 0; | ||
1215 | progress2.outOffset = 0; | ||
1216 | progress2.progress = progress; | ||
1217 | |||
1218 | writeStartSizes = 0; | ||
1219 | |||
1220 | if (props->blockSize != XZ_PROPS__BLOCK_SIZE__SOLID) | ||
1221 | { | ||
1222 | writeStartSizes = (props->forceWriteSizesInHeader > 0); | ||
1223 | |||
1224 | if (writeStartSizes) | ||
1225 | { | ||
1226 | size_t t2; | ||
1227 | size_t t = (size_t)props->blockSize; | ||
1228 | if (t != props->blockSize) | ||
1229 | return SZ_ERROR_PARAM; | ||
1230 | t = XZ_GET_MAX_BLOCK_PACK_SIZE(t); | ||
1231 | if (t < props->blockSize) | ||
1232 | return SZ_ERROR_PARAM; | ||
1233 | t2 = XZ_BLOCK_HEADER_SIZE_MAX + t; | ||
1234 | if (!p->outBufs[0] || t2 != p->outBufSize) | ||
1235 | { | ||
1236 | XzEnc_FreeOutBufs(p); | ||
1237 | p->outBufs[0] = (Byte *)ISzAlloc_Alloc(p->alloc, t2); | ||
1238 | if (!p->outBufs[0]) | ||
1239 | return SZ_ERROR_MEM; | ||
1240 | p->outBufSize = t2; | ||
1241 | } | ||
1242 | bufData = p->outBufs[0] + XZ_BLOCK_HEADER_SIZE_MAX; | ||
1243 | bufSize = t; | ||
1244 | } | ||
1245 | } | ||
1246 | |||
1247 | for (;;) | ||
1248 | { | ||
1249 | CXzEncBlockInfo blockSizes; | ||
1250 | int inStreamFinished; | ||
1251 | |||
1252 | /* | ||
1253 | UInt64 rem = (UInt64)(Int64)-1; | ||
1254 | if (props->reduceSize != (UInt64)(Int64)-1 | ||
1255 | && props->reduceSize >= progress2.inOffset) | ||
1256 | rem = props->reduceSize - progress2.inOffset; | ||
1257 | */ | ||
1258 | |||
1259 | blockSizes.headerSize = 0; // for GCC | ||
1260 | |||
1261 | RINOK(Xz_CompressBlock( | ||
1262 | &p->lzmaf_Items[0], | ||
1263 | |||
1264 | writeStartSizes ? NULL : outStream, | ||
1265 | writeStartSizes ? p->outBufs[0] : NULL, | ||
1266 | bufData, bufSize, | ||
1267 | |||
1268 | inStream, | ||
1269 | // rem, | ||
1270 | NULL, 0, | ||
1271 | |||
1272 | props, | ||
1273 | progress ? &progress2.vt : NULL, | ||
1274 | &inStreamFinished, | ||
1275 | &blockSizes, | ||
1276 | p->alloc, | ||
1277 | p->allocBig)); | ||
1278 | |||
1279 | { | ||
1280 | UInt64 totalPackFull = blockSizes.totalSize + XZ_GET_PAD_SIZE(blockSizes.totalSize); | ||
1281 | |||
1282 | if (writeStartSizes) | ||
1283 | { | ||
1284 | RINOK(WriteBytes(outStream, p->outBufs[0], blockSizes.headerSize)); | ||
1285 | RINOK(WriteBytes(outStream, bufData, (size_t)totalPackFull - blockSizes.headerSize)); | ||
1286 | } | ||
1287 | |||
1288 | RINOK(XzEncIndex_AddIndexRecord(&p->xzIndex, blockSizes.unpackSize, blockSizes.totalSize, p->alloc)); | ||
1289 | |||
1290 | progress2.inOffset += blockSizes.unpackSize; | ||
1291 | progress2.outOffset += totalPackFull; | ||
1292 | } | ||
1293 | |||
1294 | if (inStreamFinished) | ||
1295 | break; | ||
1296 | } | ||
1297 | } | ||
1298 | |||
1299 | return XzEncIndex_WriteFooter(&p->xzIndex, (CXzStreamFlags)props->checkId, outStream); | ||
1300 | } | ||
1301 | |||
1302 | |||
1303 | #include "Alloc.h" | ||
1304 | |||
1305 | SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream, | ||
1306 | const CXzProps *props, ICompressProgress *progress) | ||
1307 | { | ||
1308 | SRes res; | ||
1309 | CXzEncHandle xz = XzEnc_Create(&g_Alloc, &g_BigAlloc); | ||
1310 | if (!xz) | ||
1311 | return SZ_ERROR_MEM; | ||
1312 | res = XzEnc_SetProps(xz, props); | ||
1313 | if (res == SZ_OK) | ||
1314 | res = XzEnc_Encode(xz, outStream, inStream, progress); | ||
1315 | XzEnc_Destroy(xz); | ||
1316 | return res; | ||
1317 | } | ||
1318 | |||
1319 | |||
1320 | SRes Xz_EncodeEmpty(ISeqOutStream *outStream) | ||
1321 | { | ||
1322 | SRes res; | ||
1323 | CXzEncIndex xzIndex; | ||
1324 | XzEncIndex_Construct(&xzIndex); | ||
1325 | res = Xz_WriteHeader((CXzStreamFlags)0, outStream); | ||
1326 | if (res == SZ_OK) | ||
1327 | res = XzEncIndex_WriteFooter(&xzIndex, (CXzStreamFlags)0, outStream); | ||
1328 | XzEncIndex_Free(&xzIndex, NULL); // g_Alloc | ||
1329 | return res; | ||
1330 | } | ||