OLD | NEW |
(Empty) | |
| 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 *inSt
ream, |
| 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_IsF
inishedOK(&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 *inSt
ream, |
| 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_FINIS
H_END, &status); |
| 153 lookahead -= inProcessed; |
| 154 inSize -= inProcessed; |
| 155 if (res != SZ_OK) |
| 156 break; |
| 157 if (state.dicPos == state.dicBufSize || (inProcessed == 0 && dicPos == sta
te.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 *inS
tream, |
| 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_FINI
SH_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)->Nu
mOutStreams == 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, alloc
Main)); |
| 398 } |
| 399 else if (coder->MethodID == k_LZMA2) |
| 400 { |
| 401 RINOK(SzDecodeLzma2(coder, inSize, inStream, outBufCur, outSizeCur, allo
cMain)); |
| 402 } |
| 403 else |
| 404 { |
| 405 #ifdef _7ZIP_PPMD_SUPPPORT |
| 406 RINOK(SzDecodePpmd(coder, inSize, inStream, outBufCur, outSizeCur, alloc
Main)); |
| 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 } |
OLD | NEW |