1 /* Lzma2Enc.c -- LZMA2 Encoder 2 2010-09-24 : Igor Pavlov : Public domain */ 3 4 /* #include <stdio.h> */ 5 #include <string.h> 6 7 /* #define _7ZIP_ST */ 8 9 #include "Lzma2Enc.h" 10 11 #ifndef _7ZIP_ST 12 #include "MtCoder.h" 13 #else 14 #define NUM_MT_CODER_THREADS_MAX 1 15 #endif 16 17 #define LZMA2_CONTROL_LZMA (1 << 7) 18 #define LZMA2_CONTROL_COPY_NO_RESET 2 19 #define LZMA2_CONTROL_COPY_RESET_DIC 1 20 #define LZMA2_CONTROL_EOF 0 21 22 #define LZMA2_LCLP_MAX 4 23 24 #define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)) 25 26 #define LZMA2_PACK_SIZE_MAX (1 << 16) 27 #define LZMA2_COPY_CHUNK_SIZE LZMA2_PACK_SIZE_MAX 28 #define LZMA2_UNPACK_SIZE_MAX (1 << 21) 29 #define LZMA2_KEEP_WINDOW_SIZE LZMA2_UNPACK_SIZE_MAX 30 31 #define LZMA2_CHUNK_SIZE_COMPRESSED_MAX ((1 << 16) + 16) 32 33 34 #define PRF(x) /* x */ 35 36 /* ---------- CLzma2EncInt ---------- */ 37 38 typedef struct 39 { 40 CLzmaEncHandle enc; 41 UInt64 srcPos; 42 Byte props; 43 Bool needInitState; 44 Bool needInitProp; 45 } CLzma2EncInt; 46 47 static SRes Lzma2EncInt_Init(CLzma2EncInt *p, const CLzma2EncProps *props) 48 { 49 Byte propsEncoded[LZMA_PROPS_SIZE]; 50 SizeT propsSize = LZMA_PROPS_SIZE; 51 RINOK(LzmaEnc_SetProps(p->enc, &props->lzmaProps)); 52 RINOK(LzmaEnc_WriteProperties(p->enc, propsEncoded, &propsSize)); 53 p->srcPos = 0; 54 p->props = propsEncoded[0]; 55 p->needInitState = True; 56 p->needInitProp = True; 57 return SZ_OK; 58 } 59 60 SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize, 61 ISzAlloc *alloc, ISzAlloc *allocBig); 62 SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen, 63 UInt32 keepWindowSize, ISzAlloc *alloc, ISzAlloc *allocBig); 64 SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, Bool reInit, 65 Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize); 66 const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp); 67 void LzmaEnc_Finish(CLzmaEncHandle pp); 68 void LzmaEnc_SaveState(CLzmaEncHandle pp); 69 void LzmaEnc_RestoreState(CLzmaEncHandle pp); 70 71 72 static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf, 73 size_t *packSizeRes, ISeqOutStream *outStream) 74 { 75 size_t packSizeLimit = *packSizeRes; 76 size_t packSize = packSizeLimit; 77 UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX; 78 unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0); 79 Bool useCopyBlock; 80 SRes res; 81 82 *packSizeRes = 0; 83 if (packSize < lzHeaderSize) 84 return SZ_ERROR_OUTPUT_EOF; 85 packSize -= lzHeaderSize; 86 87 LzmaEnc_SaveState(p->enc); 88 res = LzmaEnc_CodeOneMemBlock(p->enc, p->needInitState, 89 outBuf + lzHeaderSize, &packSize, LZMA2_PACK_SIZE_MAX, &unpackSize); 90 91 PRF(printf("\npackSize = %7d unpackSize = %7d ", packSize, unpackSize)); 92 93 if (unpackSize == 0) 94 return res; 95 96 if (res == SZ_OK) 97 useCopyBlock = (packSize + 2 >= unpackSize || packSize > (1 << 16)); 98 else 99 { 100 if (res != SZ_ERROR_OUTPUT_EOF) 101 return res; 102 res = SZ_OK; 103 useCopyBlock = True; 104 } 105 106 if (useCopyBlock) 107 { 108 size_t destPos = 0; 109 PRF(printf("################# COPY ")); 110 while (unpackSize > 0) 111 { 112 UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE; 113 if (packSizeLimit - destPos < u + 3) 114 return SZ_ERROR_OUTPUT_EOF; 115 outBuf[destPos++] = (Byte)(p->srcPos == 0 ? LZMA2_CONTROL_COPY_RESET_DIC : LZMA2_CONTROL_COPY_NO_RESET); 116 outBuf[destPos++] = (Byte)((u - 1) >> 8); 117 outBuf[destPos++] = (Byte)(u - 1); 118 memcpy(outBuf + destPos, LzmaEnc_GetCurBuf(p->enc) - unpackSize, u); 119 unpackSize -= u; 120 destPos += u; 121 p->srcPos += u; 122 if (outStream) 123 { 124 *packSizeRes += destPos; 125 if (outStream->Write(outStream, outBuf, destPos) != destPos) 126 return SZ_ERROR_WRITE; 127 destPos = 0; 128 } 129 else 130 *packSizeRes = destPos; 131 /* needInitState = True; */ 132 } 133 LzmaEnc_RestoreState(p->enc); 134 return SZ_OK; 135 } 136 { 137 size_t destPos = 0; 138 UInt32 u = unpackSize - 1; 139 UInt32 pm = (UInt32)(packSize - 1); 140 unsigned mode = (p->srcPos == 0) ? 3 : (p->needInitState ? (p->needInitProp ? 2 : 1) : 0); 141 142 PRF(printf(" ")); 143 144 outBuf[destPos++] = (Byte)(LZMA2_CONTROL_LZMA | (mode << 5) | ((u >> 16) & 0x1F)); 145 outBuf[destPos++] = (Byte)(u >> 8); 146 outBuf[destPos++] = (Byte)u; 147 outBuf[destPos++] = (Byte)(pm >> 8); 148 outBuf[destPos++] = (Byte)pm; 149 150 if (p->needInitProp) 151 outBuf[destPos++] = p->props; 152 153 p->needInitProp = False; 154 p->needInitState = False; 155 destPos += packSize; 156 p->srcPos += unpackSize; 157 158 if (outStream) 159 if (outStream->Write(outStream, outBuf, destPos) != destPos) 160 return SZ_ERROR_WRITE; 161 *packSizeRes = destPos; 162 return SZ_OK; 163 } 164 } 165 166 /* ---------- Lzma2 Props ---------- */ 167 168 void Lzma2EncProps_Init(CLzma2EncProps *p) 169 { 170 LzmaEncProps_Init(&p->lzmaProps); 171 p->numTotalThreads = -1; 172 p->numBlockThreads = -1; 173 p->blockSize = 0; 174 } 175 176 void Lzma2EncProps_Normalize(CLzma2EncProps *p) 177 { 178 int t1, t1n, t2, t3; 179 { 180 CLzmaEncProps lzmaProps = p->lzmaProps; 181 LzmaEncProps_Normalize(&lzmaProps); 182 t1n = lzmaProps.numThreads; 183 } 184 185 t1 = p->lzmaProps.numThreads; 186 t2 = p->numBlockThreads; 187 t3 = p->numTotalThreads; 188 189 if (t2 > NUM_MT_CODER_THREADS_MAX) 190 t2 = NUM_MT_CODER_THREADS_MAX; 191 192 if (t3 <= 0) 193 { 194 if (t2 <= 0) 195 t2 = 1; 196 t3 = t1n * t2; 197 } 198 else if (t2 <= 0) 199 { 200 t2 = t3 / t1n; 201 if (t2 == 0) 202 { 203 t1 = 1; 204 t2 = t3; 205 } 206 if (t2 > NUM_MT_CODER_THREADS_MAX) 207 t2 = NUM_MT_CODER_THREADS_MAX; 208 } 209 else if (t1 <= 0) 210 { 211 t1 = t3 / t2; 212 if (t1 == 0) 213 t1 = 1; 214 } 215 else 216 t3 = t1n * t2; 217 218 p->lzmaProps.numThreads = t1; 219 p->numBlockThreads = t2; 220 p->numTotalThreads = t3; 221 LzmaEncProps_Normalize(&p->lzmaProps); 222 223 if (p->blockSize == 0) 224 { 225 UInt32 dictSize = p->lzmaProps.dictSize; 226 UInt64 blockSize = (UInt64)dictSize << 2; 227 const UInt32 kMinSize = (UInt32)1 << 20; 228 const UInt32 kMaxSize = (UInt32)1 << 28; 229 if (blockSize < kMinSize) blockSize = kMinSize; 230 if (blockSize > kMaxSize) blockSize = kMaxSize; 231 if (blockSize < dictSize) blockSize = dictSize; 232 p->blockSize = (size_t)blockSize; 233 } 234 } 235 236 static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize) 237 { 238 return (p && p->Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK; 239 } 240 241 /* ---------- Lzma2 ---------- */ 242 243 typedef struct 244 { 245 Byte propEncoded; 246 CLzma2EncProps props; 247 248 Byte *outBuf; 249 250 ISzAlloc *alloc; 251 ISzAlloc *allocBig; 252 253 CLzma2EncInt coders[NUM_MT_CODER_THREADS_MAX]; 254 255 #ifndef _7ZIP_ST 256 CMtCoder mtCoder; 257 #endif 258 259 } CLzma2Enc; 260 261 262 /* ---------- Lzma2EncThread ---------- */ 263 264 static SRes Lzma2Enc_EncodeMt1(CLzma2EncInt *p, CLzma2Enc *mainEncoder, 265 ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress) 266 { 267 UInt64 packTotal = 0; 268 SRes res = SZ_OK; 269 270 if (mainEncoder->outBuf == 0) 271 { 272 mainEncoder->outBuf = (Byte *)IAlloc_Alloc(mainEncoder->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX); 273 if (mainEncoder->outBuf == 0) 274 return SZ_ERROR_MEM; 275 } 276 RINOK(Lzma2EncInt_Init(p, &mainEncoder->props)); 277 RINOK(LzmaEnc_PrepareForLzma2(p->enc, inStream, LZMA2_KEEP_WINDOW_SIZE, 278 mainEncoder->alloc, mainEncoder->allocBig)); 279 for (;;) 280 { 281 size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX; 282 res = Lzma2EncInt_EncodeSubblock(p, mainEncoder->outBuf, &packSize, outStream); 283 if (res != SZ_OK) 284 break; 285 packTotal += packSize; 286 res = Progress(progress, p->srcPos, packTotal); 287 if (res != SZ_OK) 288 break; 289 if (packSize == 0) 290 break; 291 } 292 LzmaEnc_Finish(p->enc); 293 if (res == SZ_OK) 294 { 295 Byte b = 0; 296 if (outStream->Write(outStream, &b, 1) != 1) 297 return SZ_ERROR_WRITE; 298 } 299 return res; 300 } 301 302 #ifndef _7ZIP_ST 303 304 typedef struct 305 { 306 IMtCoderCallback funcTable; 307 CLzma2Enc *lzma2Enc; 308 } CMtCallbackImp; 309 310 static SRes MtCallbackImp_Code(void *pp, unsigned index, Byte *dest, size_t *destSize, 311 const Byte *src, size_t srcSize, int finished) 312 { 313 CMtCallbackImp *imp = (CMtCallbackImp *)pp; 314 CLzma2Enc *mainEncoder = imp->lzma2Enc; 315 CLzma2EncInt *p = &mainEncoder->coders[index]; 316 317 SRes res = SZ_OK; 318 { 319 size_t destLim = *destSize; 320 *destSize = 0; 321 322 if (srcSize != 0) 323 { 324 RINOK(Lzma2EncInt_Init(p, &mainEncoder->props)); 325 326 RINOK(LzmaEnc_MemPrepare(p->enc, src, srcSize, LZMA2_KEEP_WINDOW_SIZE, 327 mainEncoder->alloc, mainEncoder->allocBig)); 328 329 while (p->srcPos < srcSize) 330 { 331 size_t packSize = destLim - *destSize; 332 res = Lzma2EncInt_EncodeSubblock(p, dest + *destSize, &packSize, NULL); 333 if (res != SZ_OK) 334 break; 335 *destSize += packSize; 336 337 if (packSize == 0) 338 { 339 res = SZ_ERROR_FAIL; 340 break; 341 } 342 343 if (MtProgress_Set(&mainEncoder->mtCoder.mtProgress, index, p->srcPos, *destSize) != SZ_OK) 344 { 345 res = SZ_ERROR_PROGRESS; 346 break; 347 } 348 } 349 LzmaEnc_Finish(p->enc); 350 if (res != SZ_OK) 351 return res; 352 } 353 if (finished) 354 { 355 if (*destSize == destLim) 356 return SZ_ERROR_OUTPUT_EOF; 357 dest[(*destSize)++] = 0; 358 } 359 } 360 return res; 361 } 362 363 #endif 364 365 /* ---------- Lzma2Enc ---------- */ 366 367 CLzma2EncHandle Lzma2Enc_Create(ISzAlloc *alloc, ISzAlloc *allocBig) 368 { 369 CLzma2Enc *p = (CLzma2Enc *)alloc->Alloc(alloc, sizeof(CLzma2Enc)); 370 if (p == 0) 371 return NULL; 372 Lzma2EncProps_Init(&p->props); 373 Lzma2EncProps_Normalize(&p->props); 374 p->outBuf = 0; 375 p->alloc = alloc; 376 p->allocBig = allocBig; 377 { 378 unsigned i; 379 for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) 380 p->coders[i].enc = 0; 381 } 382 #ifndef _7ZIP_ST 383 MtCoder_Construct(&p->mtCoder); 384 #endif 385 386 return p; 387 } 388 389 void Lzma2Enc_Destroy(CLzma2EncHandle pp) 390 { 391 CLzma2Enc *p = (CLzma2Enc *)pp; 392 unsigned i; 393 for (i = 0; i < NUM_MT_CODER_THREADS_MAX; i++) 394 { 395 CLzma2EncInt *t = &p->coders[i]; 396 if (t->enc) 397 { 398 LzmaEnc_Destroy(t->enc, p->alloc, p->allocBig); 399 t->enc = 0; 400 } 401 } 402 403 #ifndef _7ZIP_ST 404 MtCoder_Destruct(&p->mtCoder); 405 #endif 406 407 IAlloc_Free(p->alloc, p->outBuf); 408 IAlloc_Free(p->alloc, pp); 409 } 410 411 SRes Lzma2Enc_SetProps(CLzma2EncHandle pp, const CLzma2EncProps *props) 412 { 413 CLzma2Enc *p = (CLzma2Enc *)pp; 414 CLzmaEncProps lzmaProps = props->lzmaProps; 415 LzmaEncProps_Normalize(&lzmaProps); 416 if (lzmaProps.lc + lzmaProps.lp > LZMA2_LCLP_MAX) 417 return SZ_ERROR_PARAM; 418 p->props = *props; 419 Lzma2EncProps_Normalize(&p->props); 420 return SZ_OK; 421 } 422 423 Byte Lzma2Enc_WriteProperties(CLzma2EncHandle pp) 424 { 425 CLzma2Enc *p = (CLzma2Enc *)pp; 426 unsigned i; 427 UInt32 dicSize = LzmaEncProps_GetDictSize(&p->props.lzmaProps); 428 for (i = 0; i < 40; i++) 429 if (dicSize <= LZMA2_DIC_SIZE_FROM_PROP(i)) 430 break; 431 return (Byte)i; 432 } 433 434 SRes Lzma2Enc_Encode(CLzma2EncHandle pp, 435 ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress) 436 { 437 CLzma2Enc *p = (CLzma2Enc *)pp; 438 int i; 439 440 for (i = 0; i < p->props.numBlockThreads; i++) 441 { 442 CLzma2EncInt *t = &p->coders[i]; 443 if (t->enc == NULL) 444 { 445 t->enc = LzmaEnc_Create(p->alloc); 446 if (t->enc == NULL) 447 return SZ_ERROR_MEM; 448 } 449 } 450 451 #ifndef _7ZIP_ST 452 if (p->props.numBlockThreads <= 1) 453 #endif 454 return Lzma2Enc_EncodeMt1(&p->coders[0], p, outStream, inStream, progress); 455 456 #ifndef _7ZIP_ST 457 458 { 459 CMtCallbackImp mtCallback; 460 461 mtCallback.funcTable.Code = MtCallbackImp_Code; 462 mtCallback.lzma2Enc = p; 463 464 p->mtCoder.progress = progress; 465 p->mtCoder.inStream = inStream; 466 p->mtCoder.outStream = outStream; 467 p->mtCoder.alloc = p->alloc; 468 p->mtCoder.mtCallback = &mtCallback.funcTable; 469 470 p->mtCoder.blockSize = p->props.blockSize; 471 p->mtCoder.destBlockSize = p->props.blockSize + (p->props.blockSize >> 10) + 16; 472 p->mtCoder.numThreads = p->props.numBlockThreads; 473 474 return MtCoder_Code(&p->mtCoder); 475 } 476 #endif 477 } 478