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 #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 = (unsigned)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 size_t destPos = *outBufSize; 636 if (destPos >= outLim) 637 return SZ_ERROR_OUTPUT_EOF; 638 outBuf[destPos] = 0; 639 *outBufSize = destPos + 1; 640 } 641 else 642 { 643 Byte b = 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 = 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 return Lzma2Enc_EncodeMt1(p, 798 &p->coders[0], 799 outStream, outBuf, outBufSize, 800 inStream, inData, inDataSize, 801 True, /* finished */ 802 progress); 803 } 804