1/* 7zDec.c -- Decoding from 7z folder 22014-06-16 : Igor Pavlov : Public domain */ 3 4#include "Precomp.h" 5 6#include <string.h> 7 8/* #define _7ZIP_PPMD_SUPPPORT */ 9 10#include "7z.h" 11 12#include "Bcj2.h" 13#include "Bra.h" 14#include "CpuArch.h" 15#include "LzmaDec.h" 16#include "Lzma2Dec.h" 17#ifdef _7ZIP_PPMD_SUPPPORT 18#include "Ppmd7.h" 19#endif 20 21#define k_Copy 0 22#define k_LZMA2 0x21 23#define k_LZMA 0x30101 24#define k_BCJ 0x03030103 25#define k_PPC 0x03030205 26#define k_ARM 0x03030501 27#define k_ARMT 0x03030701 28#define k_SPARC 0x03030805 29#define k_BCJ2 0x0303011B 30 31#ifdef _7ZIP_PPMD_SUPPPORT 32 33#define k_PPMD 0x30401 34 35typedef struct 36{ 37 IByteIn p; 38 const Byte *cur; 39 const Byte *end; 40 const Byte *begin; 41 UInt64 processed; 42 Bool extra; 43 SRes res; 44 ILookInStream *inStream; 45} CByteInToLook; 46 47static Byte ReadByte(void *pp) 48{ 49 CByteInToLook *p = (CByteInToLook *)pp; 50 if (p->cur != p->end) 51 return *p->cur++; 52 if (p->res == SZ_OK) 53 { 54 size_t size = p->cur - p->begin; 55 p->processed += size; 56 p->res = p->inStream->Skip(p->inStream, size); 57 size = (1 << 25); 58 p->res = p->inStream->Look(p->inStream, (const void **)&p->begin, &size); 59 p->cur = p->begin; 60 p->end = p->begin + size; 61 if (size != 0) 62 return *p->cur++;; 63 } 64 p->extra = True; 65 return 0; 66} 67 68static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, 69 Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) 70{ 71 CPpmd7 ppmd; 72 CByteInToLook s; 73 SRes res = SZ_OK; 74 75 s.p.Read = ReadByte; 76 s.inStream = inStream; 77 s.begin = s.end = s.cur = NULL; 78 s.extra = False; 79 s.res = SZ_OK; 80 s.processed = 0; 81 82 if (propsSize != 5) 83 return SZ_ERROR_UNSUPPORTED; 84 85 { 86 unsigned order = props[0]; 87 UInt32 memSize = GetUi32(props + 1); 88 if (order < PPMD7_MIN_ORDER || 89 order > PPMD7_MAX_ORDER || 90 memSize < PPMD7_MIN_MEM_SIZE || 91 memSize > PPMD7_MAX_MEM_SIZE) 92 return SZ_ERROR_UNSUPPORTED; 93 Ppmd7_Construct(&ppmd); 94 if (!Ppmd7_Alloc(&ppmd, memSize, allocMain)) 95 return SZ_ERROR_MEM; 96 Ppmd7_Init(&ppmd, order); 97 } 98 { 99 CPpmd7z_RangeDec rc; 100 Ppmd7z_RangeDec_CreateVTable(&rc); 101 rc.Stream = &s.p; 102 if (!Ppmd7z_RangeDec_Init(&rc)) 103 res = SZ_ERROR_DATA; 104 else if (s.extra) 105 res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); 106 else 107 { 108 SizeT i; 109 for (i = 0; i < outSize; i++) 110 { 111 int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.p); 112 if (s.extra || sym < 0) 113 break; 114 outBuffer[i] = (Byte)sym; 115 } 116 if (i != outSize) 117 res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA); 118 else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc)) 119 res = SZ_ERROR_DATA; 120 } 121 } 122 Ppmd7_Free(&ppmd, allocMain); 123 return res; 124} 125 126#endif 127 128 129static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, 130 Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) 131{ 132 CLzmaDec state; 133 SRes res = SZ_OK; 134 135 LzmaDec_Construct(&state); 136 RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain)); 137 state.dic = outBuffer; 138 state.dicBufSize = outSize; 139 LzmaDec_Init(&state); 140 141 for (;;) 142 { 143 Byte *inBuf = NULL; 144 size_t lookahead = (1 << 18); 145 if (lookahead > inSize) 146 lookahead = (size_t)inSize; 147 res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead); 148 if (res != SZ_OK) 149 break; 150 151 { 152 SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos; 153 ELzmaStatus status; 154 res = LzmaDec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status); 155 lookahead -= inProcessed; 156 inSize -= inProcessed; 157 if (res != SZ_OK) 158 break; 159 if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == state.dicPos)) 160 { 161 if (state.dicBufSize != outSize || lookahead != 0 || 162 (status != LZMA_STATUS_FINISHED_WITH_MARK && 163 status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)) 164 res = SZ_ERROR_DATA; 165 break; 166 } 167 res = inStream->Skip((void *)inStream, inProcessed); 168 if (res != SZ_OK) 169 break; 170 } 171 } 172 173 LzmaDec_FreeProbs(&state, allocMain); 174 return res; 175} 176 177static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream, 178 Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain) 179{ 180 CLzma2Dec state; 181 SRes res = SZ_OK; 182 183 Lzma2Dec_Construct(&state); 184 if (propsSize != 1) 185 return SZ_ERROR_DATA; 186 RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain)); 187 state.decoder.dic = outBuffer; 188 state.decoder.dicBufSize = outSize; 189 Lzma2Dec_Init(&state); 190 191 for (;;) 192 { 193 Byte *inBuf = NULL; 194 size_t lookahead = (1 << 18); 195 if (lookahead > inSize) 196 lookahead = (size_t)inSize; 197 res = inStream->Look((void *)inStream, (const void **)&inBuf, &lookahead); 198 if (res != SZ_OK) 199 break; 200 201 { 202 SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos; 203 ELzmaStatus status; 204 res = Lzma2Dec_DecodeToDic(&state, outSize, inBuf, &inProcessed, LZMA_FINISH_END, &status); 205 lookahead -= inProcessed; 206 inSize -= inProcessed; 207 if (res != SZ_OK) 208 break; 209 if (state.decoder.dicPos == state.decoder.dicBufSize || (inProcessed == 0 && dicPos == state.decoder.dicPos)) 210 { 211 if (state.decoder.dicBufSize != outSize || lookahead != 0 || 212 (status != LZMA_STATUS_FINISHED_WITH_MARK)) 213 res = SZ_ERROR_DATA; 214 break; 215 } 216 res = inStream->Skip((void *)inStream, inProcessed); 217 if (res != SZ_OK) 218 break; 219 } 220 } 221 222 Lzma2Dec_FreeProbs(&state, allocMain); 223 return res; 224} 225 226static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer) 227{ 228 while (inSize > 0) 229 { 230 void *inBuf; 231 size_t curSize = (1 << 18); 232 if (curSize > inSize) 233 curSize = (size_t)inSize; 234 RINOK(inStream->Look((void *)inStream, (const void **)&inBuf, &curSize)); 235 if (curSize == 0) 236 return SZ_ERROR_INPUT_EOF; 237 memcpy(outBuffer, inBuf, curSize); 238 outBuffer += curSize; 239 inSize -= curSize; 240 RINOK(inStream->Skip((void *)inStream, curSize)); 241 } 242 return SZ_OK; 243} 244 245static Bool IS_MAIN_METHOD(UInt32 m) 246{ 247 switch (m) 248 { 249 case k_Copy: 250 case k_LZMA: 251 case k_LZMA2: 252 #ifdef _7ZIP_PPMD_SUPPPORT 253 case k_PPMD: 254 #endif 255 return True; 256 } 257 return False; 258} 259 260static Bool IS_SUPPORTED_CODER(const CSzCoderInfo *c) 261{ 262 return 263 c->NumInStreams == 1 && 264 c->NumOutStreams == 1 && 265 /* c->MethodID <= (UInt32)0xFFFFFFFF && */ 266 IS_MAIN_METHOD((UInt32)c->MethodID); 267} 268 269#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumInStreams == 4 && (c)->NumOutStreams == 1) 270 271static SRes CheckSupportedFolder(const CSzFolder *f) 272{ 273 if (f->NumCoders < 1 || f->NumCoders > 4) 274 return SZ_ERROR_UNSUPPORTED; 275 if (!IS_SUPPORTED_CODER(&f->Coders[0])) 276 return SZ_ERROR_UNSUPPORTED; 277 if (f->NumCoders == 1) 278 { 279 if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBindPairs != 0) 280 return SZ_ERROR_UNSUPPORTED; 281 return SZ_OK; 282 } 283 if (f->NumCoders == 2) 284 { 285 const CSzCoderInfo *c = &f->Coders[1]; 286 if ( 287 /* c->MethodID > (UInt32)0xFFFFFFFF || */ 288 c->NumInStreams != 1 || 289 c->NumOutStreams != 1 || 290 f->NumPackStreams != 1 || 291 f->PackStreams[0] != 0 || 292 f->NumBindPairs != 1 || 293 f->BindPairs[0].InIndex != 1 || 294 f->BindPairs[0].OutIndex != 0) 295 return SZ_ERROR_UNSUPPORTED; 296 switch ((UInt32)c->MethodID) 297 { 298 case k_BCJ: 299 case k_ARM: 300 break; 301 default: 302 return SZ_ERROR_UNSUPPORTED; 303 } 304 return SZ_OK; 305 } 306 if (f->NumCoders == 4) 307 { 308 if (!IS_SUPPORTED_CODER(&f->Coders[1]) || 309 !IS_SUPPORTED_CODER(&f->Coders[2]) || 310 !IS_BCJ2(&f->Coders[3])) 311 return SZ_ERROR_UNSUPPORTED; 312 if (f->NumPackStreams != 4 || 313 f->PackStreams[0] != 2 || 314 f->PackStreams[1] != 6 || 315 f->PackStreams[2] != 1 || 316 f->PackStreams[3] != 0 || 317 f->NumBindPairs != 3 || 318 f->BindPairs[0].InIndex != 5 || f->BindPairs[0].OutIndex != 0 || 319 f->BindPairs[1].InIndex != 4 || f->BindPairs[1].OutIndex != 1 || 320 f->BindPairs[2].InIndex != 3 || f->BindPairs[2].OutIndex != 2) 321 return SZ_ERROR_UNSUPPORTED; 322 return SZ_OK; 323 } 324 return SZ_ERROR_UNSUPPORTED; 325} 326 327#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break; 328 329static SRes SzFolder_Decode2(const CSzFolder *folder, 330 const Byte *propsData, 331 const UInt64 *unpackSizes, 332 const UInt64 *packPositions, 333 ILookInStream *inStream, UInt64 startPos, 334 Byte *outBuffer, SizeT outSize, ISzAlloc *allocMain, 335 Byte *tempBuf[]) 336{ 337 UInt32 ci; 338 SizeT tempSizes[3] = { 0, 0, 0}; 339 SizeT tempSize3 = 0; 340 Byte *tempBuf3 = 0; 341 342 RINOK(CheckSupportedFolder(folder)); 343 344 for (ci = 0; ci < folder->NumCoders; ci++) 345 { 346 const CSzCoderInfo *coder = &folder->Coders[ci]; 347 348 if (IS_MAIN_METHOD((UInt32)coder->MethodID)) 349 { 350 UInt32 si = 0; 351 UInt64 offset; 352 UInt64 inSize; 353 Byte *outBufCur = outBuffer; 354 SizeT outSizeCur = outSize; 355 if (folder->NumCoders == 4) 356 { 357 UInt32 indices[] = { 3, 2, 0 }; 358 UInt64 unpackSize = unpackSizes[ci]; 359 si = indices[ci]; 360 if (ci < 2) 361 { 362 Byte *temp; 363 outSizeCur = (SizeT)unpackSize; 364 if (outSizeCur != unpackSize) 365 return SZ_ERROR_MEM; 366 temp = (Byte *)IAlloc_Alloc(allocMain, outSizeCur); 367 if (temp == 0 && outSizeCur != 0) 368 return SZ_ERROR_MEM; 369 outBufCur = tempBuf[1 - ci] = temp; 370 tempSizes[1 - ci] = outSizeCur; 371 } 372 else if (ci == 2) 373 { 374 if (unpackSize > outSize) /* check it */ 375 return SZ_ERROR_PARAM; 376 tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize); 377 tempSize3 = outSizeCur = (SizeT)unpackSize; 378 } 379 else 380 return SZ_ERROR_UNSUPPORTED; 381 } 382 offset = packPositions[si]; 383 inSize = packPositions[si + 1] - offset; 384 RINOK(LookInStream_SeekTo(inStream, startPos + offset)); 385 386 if (coder->MethodID == k_Copy) 387 { 388 if (inSize != outSizeCur) /* check it */ 389 return SZ_ERROR_DATA; 390 RINOK(SzDecodeCopy(inSize, inStream, outBufCur)); 391 } 392 else if (coder->MethodID == k_LZMA) 393 { 394 RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); 395 } 396 else if (coder->MethodID == k_LZMA2) 397 { 398 RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); 399 } 400 else 401 { 402 #ifdef _7ZIP_PPMD_SUPPPORT 403 RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain)); 404 #else 405 return SZ_ERROR_UNSUPPORTED; 406 #endif 407 } 408 } 409 else if (coder->MethodID == k_BCJ2) 410 { 411 UInt64 offset = packPositions[1]; 412 UInt64 s3Size = packPositions[2] - offset; 413 SRes res; 414 if (ci != 3) 415 return SZ_ERROR_UNSUPPORTED; 416 RINOK(LookInStream_SeekTo(inStream, startPos + offset)); 417 tempSizes[2] = (SizeT)s3Size; 418 if (tempSizes[2] != s3Size) 419 return SZ_ERROR_MEM; 420 tempBuf[2] = (Byte *)IAlloc_Alloc(allocMain, tempSizes[2]); 421 if (tempBuf[2] == 0 && tempSizes[2] != 0) 422 return SZ_ERROR_MEM; 423 res = SzDecodeCopy(s3Size, inStream, tempBuf[2]); 424 RINOK(res) 425 426 res = Bcj2_Decode( 427 tempBuf3, tempSize3, 428 tempBuf[0], tempSizes[0], 429 tempBuf[1], tempSizes[1], 430 tempBuf[2], tempSizes[2], 431 outBuffer, outSize); 432 RINOK(res) 433 } 434 else 435 { 436 if (ci != 1) 437 return SZ_ERROR_UNSUPPORTED; 438 switch (coder->MethodID) 439 { 440 case k_BCJ: 441 { 442 UInt32 state; 443 x86_Convert_Init(state); 444 x86_Convert(outBuffer, outSize, 0, &state, 0); 445 break; 446 } 447 CASE_BRA_CONV(ARM) 448 default: 449 return SZ_ERROR_UNSUPPORTED; 450 } 451 } 452 } 453 return SZ_OK; 454} 455 456SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex, 457 ILookInStream *inStream, UInt64 startPos, 458 Byte *outBuffer, size_t outSize, 459 ISzAlloc *allocMain) 460{ 461 SRes res; 462 CSzFolder folder; 463 CSzData sd; 464 CSzData sdSizes; 465 466 const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex]; 467 sd.Data = data; 468 sd.Size = p->FoCodersOffsets[folderIndex + 1] - p->FoCodersOffsets[folderIndex]; 469 470 sdSizes.Data = p->UnpackSizesData + p->FoSizesOffsets[folderIndex]; 471 sdSizes.Size = 472 p->FoSizesOffsets[folderIndex + 1] - 473 p->FoSizesOffsets[folderIndex]; 474 475 res = SzGetNextFolderItem(&folder, &sd, &sdSizes); 476 477 if (res != SZ_OK) 478 return res; 479 480 if (sd.Size != 0 || outSize != folder.CodersUnpackSizes[folder.MainOutStream]) 481 return SZ_ERROR_FAIL; 482 { 483 int i; 484 Byte *tempBuf[3] = { 0, 0, 0}; 485 res = SzFolder_Decode2(&folder, data, folder.CodersUnpackSizes, 486 p->PackPositions + p->FoStartPackStreamIndex[folderIndex], 487 inStream, startPos, 488 outBuffer, (SizeT)outSize, allocMain, tempBuf); 489 for (i = 0; i < 3; i++) 490 IAlloc_Free(allocMain, tempBuf[i]); 491 return res; 492 } 493} 494