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