1 /* 7zIn.c -- 7z Input functions 2 2010-10-29 : Igor Pavlov : Public domain */ 3 4 #include <string.h> 5 6 #include "7z.h" 7 #include "7zCrc.h" 8 #include "CpuArch.h" 9 10 Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C}; 11 12 #define RINOM(x) { if ((x) == 0) return SZ_ERROR_MEM; } 13 14 #define NUM_FOLDER_CODERS_MAX 32 15 #define NUM_CODER_STREAMS_MAX 32 16 17 void SzCoderInfo_Init(CSzCoderInfo *p) 18 { 19 Buf_Init(&p->Props); 20 } 21 22 void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc) 23 { 24 Buf_Free(&p->Props, alloc); 25 SzCoderInfo_Init(p); 26 } 27 28 void SzFolder_Init(CSzFolder *p) 29 { 30 p->Coders = 0; 31 p->BindPairs = 0; 32 p->PackStreams = 0; 33 p->UnpackSizes = 0; 34 p->NumCoders = 0; 35 p->NumBindPairs = 0; 36 p->NumPackStreams = 0; 37 p->UnpackCRCDefined = 0; 38 p->UnpackCRC = 0; 39 p->NumUnpackStreams = 0; 40 } 41 42 void SzFolder_Free(CSzFolder *p, ISzAlloc *alloc) 43 { 44 UInt32 i; 45 if (p->Coders) 46 for (i = 0; i < p->NumCoders; i++) 47 SzCoderInfo_Free(&p->Coders[i], alloc); 48 IAlloc_Free(alloc, p->Coders); 49 IAlloc_Free(alloc, p->BindPairs); 50 IAlloc_Free(alloc, p->PackStreams); 51 IAlloc_Free(alloc, p->UnpackSizes); 52 SzFolder_Init(p); 53 } 54 55 UInt32 SzFolder_GetNumOutStreams(CSzFolder *p) 56 { 57 UInt32 result = 0; 58 UInt32 i; 59 for (i = 0; i < p->NumCoders; i++) 60 result += p->Coders[i].NumOutStreams; 61 return result; 62 } 63 64 int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex) 65 { 66 UInt32 i; 67 for (i = 0; i < p->NumBindPairs; i++) 68 if (p->BindPairs[i].InIndex == inStreamIndex) 69 return i; 70 return -1; 71 } 72 73 74 int SzFolder_FindBindPairForOutStream(CSzFolder *p, UInt32 outStreamIndex) 75 { 76 UInt32 i; 77 for (i = 0; i < p->NumBindPairs; i++) 78 if (p->BindPairs[i].OutIndex == outStreamIndex) 79 return i; 80 return -1; 81 } 82 83 UInt64 SzFolder_GetUnpackSize(CSzFolder *p) 84 { 85 int i = (int)SzFolder_GetNumOutStreams(p); 86 if (i == 0) 87 return 0; 88 for (i--; i >= 0; i--) 89 if (SzFolder_FindBindPairForOutStream(p, i) < 0) 90 return p->UnpackSizes[i]; 91 /* throw 1; */ 92 return 0; 93 } 94 95 void SzFile_Init(CSzFileItem *p) 96 { 97 p->HasStream = 1; 98 p->IsDir = 0; 99 p->IsAnti = 0; 100 p->CrcDefined = 0; 101 p->MTimeDefined = 0; 102 } 103 104 void SzAr_Init(CSzAr *p) 105 { 106 p->PackSizes = 0; 107 p->PackCRCsDefined = 0; 108 p->PackCRCs = 0; 109 p->Folders = 0; 110 p->Files = 0; 111 p->NumPackStreams = 0; 112 p->NumFolders = 0; 113 p->NumFiles = 0; 114 } 115 116 void SzAr_Free(CSzAr *p, ISzAlloc *alloc) 117 { 118 UInt32 i; 119 if (p->Folders) 120 for (i = 0; i < p->NumFolders; i++) 121 SzFolder_Free(&p->Folders[i], alloc); 122 123 IAlloc_Free(alloc, p->PackSizes); 124 IAlloc_Free(alloc, p->PackCRCsDefined); 125 IAlloc_Free(alloc, p->PackCRCs); 126 IAlloc_Free(alloc, p->Folders); 127 IAlloc_Free(alloc, p->Files); 128 SzAr_Init(p); 129 } 130 131 132 void SzArEx_Init(CSzArEx *p) 133 { 134 SzAr_Init(&p->db); 135 p->FolderStartPackStreamIndex = 0; 136 p->PackStreamStartPositions = 0; 137 p->FolderStartFileIndex = 0; 138 p->FileIndexToFolderIndexMap = 0; 139 p->FileNameOffsets = 0; 140 Buf_Init(&p->FileNames); 141 } 142 143 void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc) 144 { 145 IAlloc_Free(alloc, p->FolderStartPackStreamIndex); 146 IAlloc_Free(alloc, p->PackStreamStartPositions); 147 IAlloc_Free(alloc, p->FolderStartFileIndex); 148 IAlloc_Free(alloc, p->FileIndexToFolderIndexMap); 149 150 IAlloc_Free(alloc, p->FileNameOffsets); 151 Buf_Free(&p->FileNames, alloc); 152 153 SzAr_Free(&p->db, alloc); 154 SzArEx_Init(p); 155 } 156 157 /* 158 UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const 159 { 160 return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex]; 161 } 162 163 UInt64 GetFilePackSize(int fileIndex) const 164 { 165 int folderIndex = FileIndexToFolderIndexMap[fileIndex]; 166 if (folderIndex >= 0) 167 { 168 const CSzFolder &folderInfo = Folders[folderIndex]; 169 if (FolderStartFileIndex[folderIndex] == fileIndex) 170 return GetFolderFullPackSize(folderIndex); 171 } 172 return 0; 173 } 174 */ 175 176 #define MY_ALLOC(T, p, size, alloc) { if ((size) == 0) p = 0; else \ 177 if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == 0) return SZ_ERROR_MEM; } 178 179 static SRes SzArEx_Fill(CSzArEx *p, ISzAlloc *alloc) 180 { 181 UInt32 startPos = 0; 182 UInt64 startPosSize = 0; 183 UInt32 i; 184 UInt32 folderIndex = 0; 185 UInt32 indexInFolder = 0; 186 MY_ALLOC(UInt32, p->FolderStartPackStreamIndex, p->db.NumFolders, alloc); 187 for (i = 0; i < p->db.NumFolders; i++) 188 { 189 p->FolderStartPackStreamIndex[i] = startPos; 190 startPos += p->db.Folders[i].NumPackStreams; 191 } 192 193 MY_ALLOC(UInt64, p->PackStreamStartPositions, p->db.NumPackStreams, alloc); 194 195 for (i = 0; i < p->db.NumPackStreams; i++) 196 { 197 p->PackStreamStartPositions[i] = startPosSize; 198 startPosSize += p->db.PackSizes[i]; 199 } 200 201 MY_ALLOC(UInt32, p->FolderStartFileIndex, p->db.NumFolders, alloc); 202 MY_ALLOC(UInt32, p->FileIndexToFolderIndexMap, p->db.NumFiles, alloc); 203 204 for (i = 0; i < p->db.NumFiles; i++) 205 { 206 CSzFileItem *file = p->db.Files + i; 207 int emptyStream = !file->HasStream; 208 if (emptyStream && indexInFolder == 0) 209 { 210 p->FileIndexToFolderIndexMap[i] = (UInt32)-1; 211 continue; 212 } 213 if (indexInFolder == 0) 214 { 215 /* 216 v3.13 incorrectly worked with empty folders 217 v4.07: Loop for skipping empty folders 218 */ 219 for (;;) 220 { 221 if (folderIndex >= p->db.NumFolders) 222 return SZ_ERROR_ARCHIVE; 223 p->FolderStartFileIndex[folderIndex] = i; 224 if (p->db.Folders[folderIndex].NumUnpackStreams != 0) 225 break; 226 folderIndex++; 227 } 228 } 229 p->FileIndexToFolderIndexMap[i] = folderIndex; 230 if (emptyStream) 231 continue; 232 indexInFolder++; 233 if (indexInFolder >= p->db.Folders[folderIndex].NumUnpackStreams) 234 { 235 folderIndex++; 236 indexInFolder = 0; 237 } 238 } 239 return SZ_OK; 240 } 241 242 243 UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder) 244 { 245 return p->dataPos + 246 p->PackStreamStartPositions[p->FolderStartPackStreamIndex[folderIndex] + indexInFolder]; 247 } 248 249 int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize) 250 { 251 UInt32 packStreamIndex = p->FolderStartPackStreamIndex[folderIndex]; 252 CSzFolder *folder = p->db.Folders + folderIndex; 253 UInt64 size = 0; 254 UInt32 i; 255 for (i = 0; i < folder->NumPackStreams; i++) 256 { 257 UInt64 t = size + p->db.PackSizes[packStreamIndex + i]; 258 if (t < size) /* check it */ 259 return SZ_ERROR_FAIL; 260 size = t; 261 } 262 *resSize = size; 263 return SZ_OK; 264 } 265 266 267 /* 268 SRes SzReadTime(const CObjectVector<CBuf> &dataVector, 269 CObjectVector<CSzFileItem> &files, UInt64 type) 270 { 271 CBoolVector boolVector; 272 RINOK(ReadBoolVector2(files.Size(), boolVector)) 273 274 CStreamSwitch streamSwitch; 275 RINOK(streamSwitch.Set(this, &dataVector)); 276 277 for (int i = 0; i < files.Size(); i++) 278 { 279 CSzFileItem &file = files[i]; 280 CArchiveFileTime fileTime; 281 bool defined = boolVector[i]; 282 if (defined) 283 { 284 UInt32 low, high; 285 RINOK(SzReadUInt32(low)); 286 RINOK(SzReadUInt32(high)); 287 fileTime.dwLowDateTime = low; 288 fileTime.dwHighDateTime = high; 289 } 290 switch(type) 291 { 292 case k7zIdCTime: file.IsCTimeDefined = defined; if (defined) file.CTime = fileTime; break; 293 case k7zIdATime: file.IsATimeDefined = defined; if (defined) file.ATime = fileTime; break; 294 case k7zIdMTime: file.IsMTimeDefined = defined; if (defined) file.MTime = fileTime; break; 295 } 296 } 297 return SZ_OK; 298 } 299 */ 300 301 static int TestSignatureCandidate(Byte *testBytes) 302 { 303 size_t i; 304 for (i = 0; i < k7zSignatureSize; i++) 305 if (testBytes[i] != k7zSignature[i]) 306 return 0; 307 return 1; 308 } 309 310 typedef struct _CSzState 311 { 312 Byte *Data; 313 size_t Size; 314 }CSzData; 315 316 static SRes SzReadByte(CSzData *sd, Byte *b) 317 { 318 if (sd->Size == 0) 319 return SZ_ERROR_ARCHIVE; 320 sd->Size--; 321 *b = *sd->Data++; 322 return SZ_OK; 323 } 324 325 static SRes SzReadBytes(CSzData *sd, Byte *data, size_t size) 326 { 327 size_t i; 328 for (i = 0; i < size; i++) 329 { 330 RINOK(SzReadByte(sd, data + i)); 331 } 332 return SZ_OK; 333 } 334 335 static SRes SzReadUInt32(CSzData *sd, UInt32 *value) 336 { 337 int i; 338 *value = 0; 339 for (i = 0; i < 4; i++) 340 { 341 Byte b; 342 RINOK(SzReadByte(sd, &b)); 343 *value |= ((UInt32)(b) << (8 * i)); 344 } 345 return SZ_OK; 346 } 347 348 static SRes SzReadNumber(CSzData *sd, UInt64 *value) 349 { 350 Byte firstByte; 351 Byte mask = 0x80; 352 int i; 353 RINOK(SzReadByte(sd, &firstByte)); 354 *value = 0; 355 for (i = 0; i < 8; i++) 356 { 357 Byte b; 358 if ((firstByte & mask) == 0) 359 { 360 UInt64 highPart = firstByte & (mask - 1); 361 *value += (highPart << (8 * i)); 362 return SZ_OK; 363 } 364 RINOK(SzReadByte(sd, &b)); 365 *value |= ((UInt64)b << (8 * i)); 366 mask >>= 1; 367 } 368 return SZ_OK; 369 } 370 371 static SRes SzReadNumber32(CSzData *sd, UInt32 *value) 372 { 373 UInt64 value64; 374 RINOK(SzReadNumber(sd, &value64)); 375 if (value64 >= 0x80000000) 376 return SZ_ERROR_UNSUPPORTED; 377 if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 2))) 378 return SZ_ERROR_UNSUPPORTED; 379 *value = (UInt32)value64; 380 return SZ_OK; 381 } 382 383 static SRes SzReadID(CSzData *sd, UInt64 *value) 384 { 385 return SzReadNumber(sd, value); 386 } 387 388 static SRes SzSkeepDataSize(CSzData *sd, UInt64 size) 389 { 390 if (size > sd->Size) 391 return SZ_ERROR_ARCHIVE; 392 sd->Size -= (size_t)size; 393 sd->Data += (size_t)size; 394 return SZ_OK; 395 } 396 397 static SRes SzSkeepData(CSzData *sd) 398 { 399 UInt64 size; 400 RINOK(SzReadNumber(sd, &size)); 401 return SzSkeepDataSize(sd, size); 402 } 403 404 static SRes SzReadArchiveProperties(CSzData *sd) 405 { 406 for (;;) 407 { 408 UInt64 type; 409 RINOK(SzReadID(sd, &type)); 410 if (type == k7zIdEnd) 411 break; 412 SzSkeepData(sd); 413 } 414 return SZ_OK; 415 } 416 417 static SRes SzWaitAttribute(CSzData *sd, UInt64 attribute) 418 { 419 for (;;) 420 { 421 UInt64 type; 422 RINOK(SzReadID(sd, &type)); 423 if (type == attribute) 424 return SZ_OK; 425 if (type == k7zIdEnd) 426 return SZ_ERROR_ARCHIVE; 427 RINOK(SzSkeepData(sd)); 428 } 429 } 430 431 static SRes SzReadBoolVector(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc) 432 { 433 Byte b = 0; 434 Byte mask = 0; 435 size_t i; 436 MY_ALLOC(Byte, *v, numItems, alloc); 437 for (i = 0; i < numItems; i++) 438 { 439 if (mask == 0) 440 { 441 RINOK(SzReadByte(sd, &b)); 442 mask = 0x80; 443 } 444 (*v)[i] = (Byte)(((b & mask) != 0) ? 1 : 0); 445 mask >>= 1; 446 } 447 return SZ_OK; 448 } 449 450 static SRes SzReadBoolVector2(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc) 451 { 452 Byte allAreDefined; 453 size_t i; 454 RINOK(SzReadByte(sd, &allAreDefined)); 455 if (allAreDefined == 0) 456 return SzReadBoolVector(sd, numItems, v, alloc); 457 MY_ALLOC(Byte, *v, numItems, alloc); 458 for (i = 0; i < numItems; i++) 459 (*v)[i] = 1; 460 return SZ_OK; 461 } 462 463 static SRes SzReadHashDigests( 464 CSzData *sd, 465 size_t numItems, 466 Byte **digestsDefined, 467 UInt32 **digests, 468 ISzAlloc *alloc) 469 { 470 size_t i; 471 RINOK(SzReadBoolVector2(sd, numItems, digestsDefined, alloc)); 472 MY_ALLOC(UInt32, *digests, numItems, alloc); 473 for (i = 0; i < numItems; i++) 474 if ((*digestsDefined)[i]) 475 { 476 RINOK(SzReadUInt32(sd, (*digests) + i)); 477 } 478 return SZ_OK; 479 } 480 481 static SRes SzReadPackInfo( 482 CSzData *sd, 483 UInt64 *dataOffset, 484 UInt32 *numPackStreams, 485 UInt64 **packSizes, 486 Byte **packCRCsDefined, 487 UInt32 **packCRCs, 488 ISzAlloc *alloc) 489 { 490 UInt32 i; 491 RINOK(SzReadNumber(sd, dataOffset)); 492 RINOK(SzReadNumber32(sd, numPackStreams)); 493 494 RINOK(SzWaitAttribute(sd, k7zIdSize)); 495 496 MY_ALLOC(UInt64, *packSizes, (size_t)*numPackStreams, alloc); 497 498 for (i = 0; i < *numPackStreams; i++) 499 { 500 RINOK(SzReadNumber(sd, (*packSizes) + i)); 501 } 502 503 for (;;) 504 { 505 UInt64 type; 506 RINOK(SzReadID(sd, &type)); 507 if (type == k7zIdEnd) 508 break; 509 if (type == k7zIdCRC) 510 { 511 RINOK(SzReadHashDigests(sd, (size_t)*numPackStreams, packCRCsDefined, packCRCs, alloc)); 512 continue; 513 } 514 RINOK(SzSkeepData(sd)); 515 } 516 if (*packCRCsDefined == 0) 517 { 518 MY_ALLOC(Byte, *packCRCsDefined, (size_t)*numPackStreams, alloc); 519 MY_ALLOC(UInt32, *packCRCs, (size_t)*numPackStreams, alloc); 520 for (i = 0; i < *numPackStreams; i++) 521 { 522 (*packCRCsDefined)[i] = 0; 523 (*packCRCs)[i] = 0; 524 } 525 } 526 return SZ_OK; 527 } 528 529 static SRes SzReadSwitch(CSzData *sd) 530 { 531 Byte external; 532 RINOK(SzReadByte(sd, &external)); 533 return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED; 534 } 535 536 static SRes SzGetNextFolderItem(CSzData *sd, CSzFolder *folder, ISzAlloc *alloc) 537 { 538 UInt32 numCoders, numBindPairs, numPackStreams, i; 539 UInt32 numInStreams = 0, numOutStreams = 0; 540 541 RINOK(SzReadNumber32(sd, &numCoders)); 542 if (numCoders > NUM_FOLDER_CODERS_MAX) 543 return SZ_ERROR_UNSUPPORTED; 544 folder->NumCoders = numCoders; 545 546 MY_ALLOC(CSzCoderInfo, folder->Coders, (size_t)numCoders, alloc); 547 548 for (i = 0; i < numCoders; i++) 549 SzCoderInfo_Init(folder->Coders + i); 550 551 for (i = 0; i < numCoders; i++) 552 { 553 Byte mainByte; 554 CSzCoderInfo *coder = folder->Coders + i; 555 { 556 unsigned idSize, j; 557 Byte longID[15]; 558 RINOK(SzReadByte(sd, &mainByte)); 559 idSize = (unsigned)(mainByte & 0xF); 560 RINOK(SzReadBytes(sd, longID, idSize)); 561 if (idSize > sizeof(coder->MethodID)) 562 return SZ_ERROR_UNSUPPORTED; 563 coder->MethodID = 0; 564 for (j = 0; j < idSize; j++) 565 coder->MethodID |= (UInt64)longID[idSize - 1 - j] << (8 * j); 566 567 if ((mainByte & 0x10) != 0) 568 { 569 RINOK(SzReadNumber32(sd, &coder->NumInStreams)); 570 RINOK(SzReadNumber32(sd, &coder->NumOutStreams)); 571 if (coder->NumInStreams > NUM_CODER_STREAMS_MAX || 572 coder->NumOutStreams > NUM_CODER_STREAMS_MAX) 573 return SZ_ERROR_UNSUPPORTED; 574 } 575 else 576 { 577 coder->NumInStreams = 1; 578 coder->NumOutStreams = 1; 579 } 580 if ((mainByte & 0x20) != 0) 581 { 582 UInt64 propertiesSize = 0; 583 RINOK(SzReadNumber(sd, &propertiesSize)); 584 if (!Buf_Create(&coder->Props, (size_t)propertiesSize, alloc)) 585 return SZ_ERROR_MEM; 586 RINOK(SzReadBytes(sd, coder->Props.data, (size_t)propertiesSize)); 587 } 588 } 589 while ((mainByte & 0x80) != 0) 590 { 591 RINOK(SzReadByte(sd, &mainByte)); 592 RINOK(SzSkeepDataSize(sd, (mainByte & 0xF))); 593 if ((mainByte & 0x10) != 0) 594 { 595 UInt32 n; 596 RINOK(SzReadNumber32(sd, &n)); 597 RINOK(SzReadNumber32(sd, &n)); 598 } 599 if ((mainByte & 0x20) != 0) 600 { 601 UInt64 propertiesSize = 0; 602 RINOK(SzReadNumber(sd, &propertiesSize)); 603 RINOK(SzSkeepDataSize(sd, propertiesSize)); 604 } 605 } 606 numInStreams += coder->NumInStreams; 607 numOutStreams += coder->NumOutStreams; 608 } 609 610 if (numOutStreams == 0) 611 return SZ_ERROR_UNSUPPORTED; 612 613 folder->NumBindPairs = numBindPairs = numOutStreams - 1; 614 MY_ALLOC(CSzBindPair, folder->BindPairs, (size_t)numBindPairs, alloc); 615 616 for (i = 0; i < numBindPairs; i++) 617 { 618 CSzBindPair *bp = folder->BindPairs + i; 619 RINOK(SzReadNumber32(sd, &bp->InIndex)); 620 RINOK(SzReadNumber32(sd, &bp->OutIndex)); 621 } 622 623 if (numInStreams < numBindPairs) 624 return SZ_ERROR_UNSUPPORTED; 625 626 folder->NumPackStreams = numPackStreams = numInStreams - numBindPairs; 627 MY_ALLOC(UInt32, folder->PackStreams, (size_t)numPackStreams, alloc); 628 629 if (numPackStreams == 1) 630 { 631 for (i = 0; i < numInStreams ; i++) 632 if (SzFolder_FindBindPairForInStream(folder, i) < 0) 633 break; 634 if (i == numInStreams) 635 return SZ_ERROR_UNSUPPORTED; 636 folder->PackStreams[0] = i; 637 } 638 else 639 for (i = 0; i < numPackStreams; i++) 640 { 641 RINOK(SzReadNumber32(sd, folder->PackStreams + i)); 642 } 643 return SZ_OK; 644 } 645 646 static SRes SzReadUnpackInfo( 647 CSzData *sd, 648 UInt32 *numFolders, 649 CSzFolder **folders, /* for alloc */ 650 ISzAlloc *alloc, 651 ISzAlloc *allocTemp) 652 { 653 UInt32 i; 654 RINOK(SzWaitAttribute(sd, k7zIdFolder)); 655 RINOK(SzReadNumber32(sd, numFolders)); 656 { 657 RINOK(SzReadSwitch(sd)); 658 659 MY_ALLOC(CSzFolder, *folders, (size_t)*numFolders, alloc); 660 661 for (i = 0; i < *numFolders; i++) 662 SzFolder_Init((*folders) + i); 663 664 for (i = 0; i < *numFolders; i++) 665 { 666 RINOK(SzGetNextFolderItem(sd, (*folders) + i, alloc)); 667 } 668 } 669 670 RINOK(SzWaitAttribute(sd, k7zIdCodersUnpackSize)); 671 672 for (i = 0; i < *numFolders; i++) 673 { 674 UInt32 j; 675 CSzFolder *folder = (*folders) + i; 676 UInt32 numOutStreams = SzFolder_GetNumOutStreams(folder); 677 678 MY_ALLOC(UInt64, folder->UnpackSizes, (size_t)numOutStreams, alloc); 679 680 for (j = 0; j < numOutStreams; j++) 681 { 682 RINOK(SzReadNumber(sd, folder->UnpackSizes + j)); 683 } 684 } 685 686 for (;;) 687 { 688 UInt64 type; 689 RINOK(SzReadID(sd, &type)); 690 if (type == k7zIdEnd) 691 return SZ_OK; 692 if (type == k7zIdCRC) 693 { 694 SRes res; 695 Byte *crcsDefined = 0; 696 UInt32 *crcs = 0; 697 res = SzReadHashDigests(sd, *numFolders, &crcsDefined, &crcs, allocTemp); 698 if (res == SZ_OK) 699 { 700 for (i = 0; i < *numFolders; i++) 701 { 702 CSzFolder *folder = (*folders) + i; 703 folder->UnpackCRCDefined = crcsDefined[i]; 704 folder->UnpackCRC = crcs[i]; 705 } 706 } 707 IAlloc_Free(allocTemp, crcs); 708 IAlloc_Free(allocTemp, crcsDefined); 709 RINOK(res); 710 continue; 711 } 712 RINOK(SzSkeepData(sd)); 713 } 714 } 715 716 static SRes SzReadSubStreamsInfo( 717 CSzData *sd, 718 UInt32 numFolders, 719 CSzFolder *folders, 720 UInt32 *numUnpackStreams, 721 UInt64 **unpackSizes, 722 Byte **digestsDefined, 723 UInt32 **digests, 724 ISzAlloc *allocTemp) 725 { 726 UInt64 type = 0; 727 UInt32 i; 728 UInt32 si = 0; 729 UInt32 numDigests = 0; 730 731 for (i = 0; i < numFolders; i++) 732 folders[i].NumUnpackStreams = 1; 733 *numUnpackStreams = numFolders; 734 735 for (;;) 736 { 737 RINOK(SzReadID(sd, &type)); 738 if (type == k7zIdNumUnpackStream) 739 { 740 *numUnpackStreams = 0; 741 for (i = 0; i < numFolders; i++) 742 { 743 UInt32 numStreams; 744 RINOK(SzReadNumber32(sd, &numStreams)); 745 folders[i].NumUnpackStreams = numStreams; 746 *numUnpackStreams += numStreams; 747 } 748 continue; 749 } 750 if (type == k7zIdCRC || type == k7zIdSize) 751 break; 752 if (type == k7zIdEnd) 753 break; 754 RINOK(SzSkeepData(sd)); 755 } 756 757 if (*numUnpackStreams == 0) 758 { 759 *unpackSizes = 0; 760 *digestsDefined = 0; 761 *digests = 0; 762 } 763 else 764 { 765 *unpackSizes = (UInt64 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt64)); 766 RINOM(*unpackSizes); 767 *digestsDefined = (Byte *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(Byte)); 768 RINOM(*digestsDefined); 769 *digests = (UInt32 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt32)); 770 RINOM(*digests); 771 } 772 773 for (i = 0; i < numFolders; i++) 774 { 775 /* 776 v3.13 incorrectly worked with empty folders 777 v4.07: we check that folder is empty 778 */ 779 UInt64 sum = 0; 780 UInt32 j; 781 UInt32 numSubstreams = folders[i].NumUnpackStreams; 782 if (numSubstreams == 0) 783 continue; 784 if (type == k7zIdSize) 785 for (j = 1; j < numSubstreams; j++) 786 { 787 UInt64 size; 788 RINOK(SzReadNumber(sd, &size)); 789 (*unpackSizes)[si++] = size; 790 sum += size; 791 } 792 (*unpackSizes)[si++] = SzFolder_GetUnpackSize(folders + i) - sum; 793 } 794 if (type == k7zIdSize) 795 { 796 RINOK(SzReadID(sd, &type)); 797 } 798 799 for (i = 0; i < *numUnpackStreams; i++) 800 { 801 (*digestsDefined)[i] = 0; 802 (*digests)[i] = 0; 803 } 804 805 806 for (i = 0; i < numFolders; i++) 807 { 808 UInt32 numSubstreams = folders[i].NumUnpackStreams; 809 if (numSubstreams != 1 || !folders[i].UnpackCRCDefined) 810 numDigests += numSubstreams; 811 } 812 813 814 si = 0; 815 for (;;) 816 { 817 if (type == k7zIdCRC) 818 { 819 int digestIndex = 0; 820 Byte *digestsDefined2 = 0; 821 UInt32 *digests2 = 0; 822 SRes res = SzReadHashDigests(sd, numDigests, &digestsDefined2, &digests2, allocTemp); 823 if (res == SZ_OK) 824 { 825 for (i = 0; i < numFolders; i++) 826 { 827 CSzFolder *folder = folders + i; 828 UInt32 numSubstreams = folder->NumUnpackStreams; 829 if (numSubstreams == 1 && folder->UnpackCRCDefined) 830 { 831 (*digestsDefined)[si] = 1; 832 (*digests)[si] = folder->UnpackCRC; 833 si++; 834 } 835 else 836 { 837 UInt32 j; 838 for (j = 0; j < numSubstreams; j++, digestIndex++) 839 { 840 (*digestsDefined)[si] = digestsDefined2[digestIndex]; 841 (*digests)[si] = digests2[digestIndex]; 842 si++; 843 } 844 } 845 } 846 } 847 IAlloc_Free(allocTemp, digestsDefined2); 848 IAlloc_Free(allocTemp, digests2); 849 RINOK(res); 850 } 851 else if (type == k7zIdEnd) 852 return SZ_OK; 853 else 854 { 855 RINOK(SzSkeepData(sd)); 856 } 857 RINOK(SzReadID(sd, &type)); 858 } 859 } 860 861 862 static SRes SzReadStreamsInfo( 863 CSzData *sd, 864 UInt64 *dataOffset, 865 CSzAr *p, 866 UInt32 *numUnpackStreams, 867 UInt64 **unpackSizes, /* allocTemp */ 868 Byte **digestsDefined, /* allocTemp */ 869 UInt32 **digests, /* allocTemp */ 870 ISzAlloc *alloc, 871 ISzAlloc *allocTemp) 872 { 873 for (;;) 874 { 875 UInt64 type; 876 RINOK(SzReadID(sd, &type)); 877 if ((UInt64)(int)type != type) 878 return SZ_ERROR_UNSUPPORTED; 879 switch((int)type) 880 { 881 case k7zIdEnd: 882 return SZ_OK; 883 case k7zIdPackInfo: 884 { 885 RINOK(SzReadPackInfo(sd, dataOffset, &p->NumPackStreams, 886 &p->PackSizes, &p->PackCRCsDefined, &p->PackCRCs, alloc)); 887 break; 888 } 889 case k7zIdUnpackInfo: 890 { 891 RINOK(SzReadUnpackInfo(sd, &p->NumFolders, &p->Folders, alloc, allocTemp)); 892 break; 893 } 894 case k7zIdSubStreamsInfo: 895 { 896 RINOK(SzReadSubStreamsInfo(sd, p->NumFolders, p->Folders, 897 numUnpackStreams, unpackSizes, digestsDefined, digests, allocTemp)); 898 break; 899 } 900 default: 901 return SZ_ERROR_UNSUPPORTED; 902 } 903 } 904 } 905 906 size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest) 907 { 908 size_t len = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex]; 909 if (dest != 0) 910 { 911 size_t i; 912 const Byte *src = p->FileNames.data + (p->FileNameOffsets[fileIndex] * 2); 913 for (i = 0; i < len; i++) 914 dest[i] = GetUi16(src + i * 2); 915 } 916 return len; 917 } 918 919 static SRes SzReadFileNames(const Byte *p, size_t size, UInt32 numFiles, size_t *sizes) 920 { 921 UInt32 i; 922 size_t pos = 0; 923 for (i = 0; i < numFiles; i++) 924 { 925 sizes[i] = pos; 926 for (;;) 927 { 928 if (pos >= size) 929 return SZ_ERROR_ARCHIVE; 930 if (p[pos * 2] == 0 && p[pos * 2 + 1] == 0) 931 break; 932 pos++; 933 } 934 pos++; 935 } 936 sizes[i] = pos; 937 return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE; 938 } 939 940 static SRes SzReadHeader2( 941 CSzArEx *p, /* allocMain */ 942 CSzData *sd, 943 UInt64 **unpackSizes, /* allocTemp */ 944 Byte **digestsDefined, /* allocTemp */ 945 UInt32 **digests, /* allocTemp */ 946 Byte **emptyStreamVector, /* allocTemp */ 947 Byte **emptyFileVector, /* allocTemp */ 948 Byte **lwtVector, /* allocTemp */ 949 ISzAlloc *allocMain, 950 ISzAlloc *allocTemp) 951 { 952 UInt64 type; 953 UInt32 numUnpackStreams = 0; 954 UInt32 numFiles = 0; 955 CSzFileItem *files = 0; 956 UInt32 numEmptyStreams = 0; 957 UInt32 i; 958 959 RINOK(SzReadID(sd, &type)); 960 961 if (type == k7zIdArchiveProperties) 962 { 963 RINOK(SzReadArchiveProperties(sd)); 964 RINOK(SzReadID(sd, &type)); 965 } 966 967 968 if (type == k7zIdMainStreamsInfo) 969 { 970 RINOK(SzReadStreamsInfo(sd, 971 &p->dataPos, 972 &p->db, 973 &numUnpackStreams, 974 unpackSizes, 975 digestsDefined, 976 digests, allocMain, allocTemp)); 977 p->dataPos += p->startPosAfterHeader; 978 RINOK(SzReadID(sd, &type)); 979 } 980 981 if (type == k7zIdEnd) 982 return SZ_OK; 983 if (type != k7zIdFilesInfo) 984 return SZ_ERROR_ARCHIVE; 985 986 RINOK(SzReadNumber32(sd, &numFiles)); 987 p->db.NumFiles = numFiles; 988 989 MY_ALLOC(CSzFileItem, files, (size_t)numFiles, allocMain); 990 991 p->db.Files = files; 992 for (i = 0; i < numFiles; i++) 993 SzFile_Init(files + i); 994 995 for (;;) 996 { 997 UInt64 type; 998 UInt64 size; 999 RINOK(SzReadID(sd, &type)); 1000 if (type == k7zIdEnd) 1001 break; 1002 RINOK(SzReadNumber(sd, &size)); 1003 if (size > sd->Size) 1004 return SZ_ERROR_ARCHIVE; 1005 if ((UInt64)(int)type != type) 1006 { 1007 RINOK(SzSkeepDataSize(sd, size)); 1008 } 1009 else 1010 switch((int)type) 1011 { 1012 case k7zIdName: 1013 { 1014 size_t namesSize; 1015 RINOK(SzReadSwitch(sd)); 1016 namesSize = (size_t)size - 1; 1017 if ((namesSize & 1) != 0) 1018 return SZ_ERROR_ARCHIVE; 1019 if (!Buf_Create(&p->FileNames, namesSize, allocMain)) 1020 return SZ_ERROR_MEM; 1021 MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain); 1022 memcpy(p->FileNames.data, sd->Data, namesSize); 1023 RINOK(SzReadFileNames(sd->Data, namesSize >> 1, numFiles, p->FileNameOffsets)) 1024 RINOK(SzSkeepDataSize(sd, namesSize)); 1025 break; 1026 } 1027 case k7zIdEmptyStream: 1028 { 1029 RINOK(SzReadBoolVector(sd, numFiles, emptyStreamVector, allocTemp)); 1030 numEmptyStreams = 0; 1031 for (i = 0; i < numFiles; i++) 1032 if ((*emptyStreamVector)[i]) 1033 numEmptyStreams++; 1034 break; 1035 } 1036 case k7zIdEmptyFile: 1037 { 1038 RINOK(SzReadBoolVector(sd, numEmptyStreams, emptyFileVector, allocTemp)); 1039 break; 1040 } 1041 case k7zIdWinAttributes: 1042 { 1043 RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp)); 1044 RINOK(SzReadSwitch(sd)); 1045 for (i = 0; i < numFiles; i++) 1046 { 1047 CSzFileItem *f = &files[i]; 1048 Byte defined = (*lwtVector)[i]; 1049 f->AttribDefined = defined; 1050 f->Attrib = 0; 1051 if (defined) 1052 { 1053 RINOK(SzReadUInt32(sd, &f->Attrib)); 1054 } 1055 } 1056 IAlloc_Free(allocTemp, *lwtVector); 1057 *lwtVector = NULL; 1058 break; 1059 } 1060 case k7zIdMTime: 1061 { 1062 RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp)); 1063 RINOK(SzReadSwitch(sd)); 1064 for (i = 0; i < numFiles; i++) 1065 { 1066 CSzFileItem *f = &files[i]; 1067 Byte defined = (*lwtVector)[i]; 1068 f->MTimeDefined = defined; 1069 f->MTime.Low = f->MTime.High = 0; 1070 if (defined) 1071 { 1072 RINOK(SzReadUInt32(sd, &f->MTime.Low)); 1073 RINOK(SzReadUInt32(sd, &f->MTime.High)); 1074 } 1075 } 1076 IAlloc_Free(allocTemp, *lwtVector); 1077 *lwtVector = NULL; 1078 break; 1079 } 1080 default: 1081 { 1082 RINOK(SzSkeepDataSize(sd, size)); 1083 } 1084 } 1085 } 1086 1087 { 1088 UInt32 emptyFileIndex = 0; 1089 UInt32 sizeIndex = 0; 1090 for (i = 0; i < numFiles; i++) 1091 { 1092 CSzFileItem *file = files + i; 1093 file->IsAnti = 0; 1094 if (*emptyStreamVector == 0) 1095 file->HasStream = 1; 1096 else 1097 file->HasStream = (Byte)((*emptyStreamVector)[i] ? 0 : 1); 1098 if (file->HasStream) 1099 { 1100 file->IsDir = 0; 1101 file->Size = (*unpackSizes)[sizeIndex]; 1102 file->Crc = (*digests)[sizeIndex]; 1103 file->CrcDefined = (Byte)(*digestsDefined)[sizeIndex]; 1104 sizeIndex++; 1105 } 1106 else 1107 { 1108 if (*emptyFileVector == 0) 1109 file->IsDir = 1; 1110 else 1111 file->IsDir = (Byte)((*emptyFileVector)[emptyFileIndex] ? 0 : 1); 1112 emptyFileIndex++; 1113 file->Size = 0; 1114 file->Crc = 0; 1115 file->CrcDefined = 0; 1116 } 1117 } 1118 } 1119 return SzArEx_Fill(p, allocMain); 1120 } 1121 1122 static SRes SzReadHeader( 1123 CSzArEx *p, 1124 CSzData *sd, 1125 ISzAlloc *allocMain, 1126 ISzAlloc *allocTemp) 1127 { 1128 UInt64 *unpackSizes = 0; 1129 Byte *digestsDefined = 0; 1130 UInt32 *digests = 0; 1131 Byte *emptyStreamVector = 0; 1132 Byte *emptyFileVector = 0; 1133 Byte *lwtVector = 0; 1134 SRes res = SzReadHeader2(p, sd, 1135 &unpackSizes, &digestsDefined, &digests, 1136 &emptyStreamVector, &emptyFileVector, &lwtVector, 1137 allocMain, allocTemp); 1138 IAlloc_Free(allocTemp, unpackSizes); 1139 IAlloc_Free(allocTemp, digestsDefined); 1140 IAlloc_Free(allocTemp, digests); 1141 IAlloc_Free(allocTemp, emptyStreamVector); 1142 IAlloc_Free(allocTemp, emptyFileVector); 1143 IAlloc_Free(allocTemp, lwtVector); 1144 return res; 1145 } 1146 1147 static SRes SzReadAndDecodePackedStreams2( 1148 ILookInStream *inStream, 1149 CSzData *sd, 1150 CBuf *outBuffer, 1151 UInt64 baseOffset, 1152 CSzAr *p, 1153 UInt64 **unpackSizes, 1154 Byte **digestsDefined, 1155 UInt32 **digests, 1156 ISzAlloc *allocTemp) 1157 { 1158 1159 UInt32 numUnpackStreams = 0; 1160 UInt64 dataStartPos; 1161 CSzFolder *folder; 1162 UInt64 unpackSize; 1163 SRes res; 1164 1165 RINOK(SzReadStreamsInfo(sd, &dataStartPos, p, 1166 &numUnpackStreams, unpackSizes, digestsDefined, digests, 1167 allocTemp, allocTemp)); 1168 1169 dataStartPos += baseOffset; 1170 if (p->NumFolders != 1) 1171 return SZ_ERROR_ARCHIVE; 1172 1173 folder = p->Folders; 1174 unpackSize = SzFolder_GetUnpackSize(folder); 1175 1176 RINOK(LookInStream_SeekTo(inStream, dataStartPos)); 1177 1178 if (!Buf_Create(outBuffer, (size_t)unpackSize, allocTemp)) 1179 return SZ_ERROR_MEM; 1180 1181 res = SzFolder_Decode(folder, p->PackSizes, 1182 inStream, dataStartPos, 1183 outBuffer->data, (size_t)unpackSize, allocTemp); 1184 RINOK(res); 1185 if (folder->UnpackCRCDefined) 1186 if (CrcCalc(outBuffer->data, (size_t)unpackSize) != folder->UnpackCRC) 1187 return SZ_ERROR_CRC; 1188 return SZ_OK; 1189 } 1190 1191 static SRes SzReadAndDecodePackedStreams( 1192 ILookInStream *inStream, 1193 CSzData *sd, 1194 CBuf *outBuffer, 1195 UInt64 baseOffset, 1196 ISzAlloc *allocTemp) 1197 { 1198 CSzAr p; 1199 UInt64 *unpackSizes = 0; 1200 Byte *digestsDefined = 0; 1201 UInt32 *digests = 0; 1202 SRes res; 1203 SzAr_Init(&p); 1204 res = SzReadAndDecodePackedStreams2(inStream, sd, outBuffer, baseOffset, 1205 &p, &unpackSizes, &digestsDefined, &digests, 1206 allocTemp); 1207 SzAr_Free(&p, allocTemp); 1208 IAlloc_Free(allocTemp, unpackSizes); 1209 IAlloc_Free(allocTemp, digestsDefined); 1210 IAlloc_Free(allocTemp, digests); 1211 return res; 1212 } 1213 1214 static SRes SzArEx_Open2( 1215 CSzArEx *p, 1216 ILookInStream *inStream, 1217 ISzAlloc *allocMain, 1218 ISzAlloc *allocTemp) 1219 { 1220 Byte header[k7zStartHeaderSize]; 1221 Int64 startArcPos; 1222 UInt64 nextHeaderOffset, nextHeaderSize; 1223 size_t nextHeaderSizeT; 1224 UInt32 nextHeaderCRC; 1225 CBuf buffer; 1226 SRes res; 1227 1228 startArcPos = 0; 1229 RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR)); 1230 1231 RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE)); 1232 1233 if (!TestSignatureCandidate(header)) 1234 return SZ_ERROR_NO_ARCHIVE; 1235 if (header[6] != k7zMajorVersion) 1236 return SZ_ERROR_UNSUPPORTED; 1237 1238 nextHeaderOffset = GetUi64(header + 12); 1239 nextHeaderSize = GetUi64(header + 20); 1240 nextHeaderCRC = GetUi32(header + 28); 1241 1242 p->startPosAfterHeader = startArcPos + k7zStartHeaderSize; 1243 1244 if (CrcCalc(header + 12, 20) != GetUi32(header + 8)) 1245 return SZ_ERROR_CRC; 1246 1247 nextHeaderSizeT = (size_t)nextHeaderSize; 1248 if (nextHeaderSizeT != nextHeaderSize) 1249 return SZ_ERROR_MEM; 1250 if (nextHeaderSizeT == 0) 1251 return SZ_OK; 1252 if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize || 1253 nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize) 1254 return SZ_ERROR_NO_ARCHIVE; 1255 1256 { 1257 Int64 pos = 0; 1258 RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END)); 1259 if ((UInt64)pos < startArcPos + nextHeaderOffset || 1260 (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset || 1261 (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize) 1262 return SZ_ERROR_INPUT_EOF; 1263 } 1264 1265 RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset)); 1266 1267 if (!Buf_Create(&buffer, nextHeaderSizeT, allocTemp)) 1268 return SZ_ERROR_MEM; 1269 1270 res = LookInStream_Read(inStream, buffer.data, nextHeaderSizeT); 1271 if (res == SZ_OK) 1272 { 1273 res = SZ_ERROR_ARCHIVE; 1274 if (CrcCalc(buffer.data, nextHeaderSizeT) == nextHeaderCRC) 1275 { 1276 CSzData sd; 1277 UInt64 type; 1278 sd.Data = buffer.data; 1279 sd.Size = buffer.size; 1280 res = SzReadID(&sd, &type); 1281 if (res == SZ_OK) 1282 { 1283 if (type == k7zIdEncodedHeader) 1284 { 1285 CBuf outBuffer; 1286 Buf_Init(&outBuffer); 1287 res = SzReadAndDecodePackedStreams(inStream, &sd, &outBuffer, p->startPosAfterHeader, allocTemp); 1288 if (res != SZ_OK) 1289 Buf_Free(&outBuffer, allocTemp); 1290 else 1291 { 1292 Buf_Free(&buffer, allocTemp); 1293 buffer.data = outBuffer.data; 1294 buffer.size = outBuffer.size; 1295 sd.Data = buffer.data; 1296 sd.Size = buffer.size; 1297 res = SzReadID(&sd, &type); 1298 } 1299 } 1300 } 1301 if (res == SZ_OK) 1302 { 1303 if (type == k7zIdHeader) 1304 res = SzReadHeader(p, &sd, allocMain, allocTemp); 1305 else 1306 res = SZ_ERROR_UNSUPPORTED; 1307 } 1308 } 1309 } 1310 Buf_Free(&buffer, allocTemp); 1311 return res; 1312 } 1313 1314 SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp) 1315 { 1316 SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp); 1317 if (res != SZ_OK) 1318 SzArEx_Free(p, allocMain); 1319 return res; 1320 } 1321 1322 SRes SzArEx_Extract( 1323 const CSzArEx *p, 1324 ILookInStream *inStream, 1325 UInt32 fileIndex, 1326 UInt32 *blockIndex, 1327 Byte **outBuffer, 1328 size_t *outBufferSize, 1329 size_t *offset, 1330 size_t *outSizeProcessed, 1331 ISzAlloc *allocMain, 1332 ISzAlloc *allocTemp) 1333 { 1334 UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex]; 1335 SRes res = SZ_OK; 1336 *offset = 0; 1337 *outSizeProcessed = 0; 1338 if (folderIndex == (UInt32)-1) 1339 { 1340 IAlloc_Free(allocMain, *outBuffer); 1341 *blockIndex = folderIndex; 1342 *outBuffer = 0; 1343 *outBufferSize = 0; 1344 return SZ_OK; 1345 } 1346 1347 if (*outBuffer == 0 || *blockIndex != folderIndex) 1348 { 1349 CSzFolder *folder = p->db.Folders + folderIndex; 1350 UInt64 unpackSizeSpec = SzFolder_GetUnpackSize(folder); 1351 size_t unpackSize = (size_t)unpackSizeSpec; 1352 UInt64 startOffset = SzArEx_GetFolderStreamPos(p, folderIndex, 0); 1353 1354 if (unpackSize != unpackSizeSpec) 1355 return SZ_ERROR_MEM; 1356 *blockIndex = folderIndex; 1357 IAlloc_Free(allocMain, *outBuffer); 1358 *outBuffer = 0; 1359 1360 RINOK(LookInStream_SeekTo(inStream, startOffset)); 1361 1362 if (res == SZ_OK) 1363 { 1364 *outBufferSize = unpackSize; 1365 if (unpackSize != 0) 1366 { 1367 *outBuffer = (Byte *)IAlloc_Alloc(allocMain, unpackSize); 1368 if (*outBuffer == 0) 1369 res = SZ_ERROR_MEM; 1370 } 1371 if (res == SZ_OK) 1372 { 1373 res = SzFolder_Decode(folder, 1374 p->db.PackSizes + p->FolderStartPackStreamIndex[folderIndex], 1375 inStream, startOffset, 1376 *outBuffer, unpackSize, allocTemp); 1377 if (res == SZ_OK) 1378 { 1379 if (folder->UnpackCRCDefined) 1380 { 1381 if (CrcCalc(*outBuffer, unpackSize) != folder->UnpackCRC) 1382 res = SZ_ERROR_CRC; 1383 } 1384 } 1385 } 1386 } 1387 } 1388 if (res == SZ_OK) 1389 { 1390 UInt32 i; 1391 CSzFileItem *fileItem = p->db.Files + fileIndex; 1392 *offset = 0; 1393 for (i = p->FolderStartFileIndex[folderIndex]; i < fileIndex; i++) 1394 *offset += (UInt32)p->db.Files[i].Size; 1395 *outSizeProcessed = (size_t)fileItem->Size; 1396 if (*offset + *outSizeProcessed > *outBufferSize) 1397 return SZ_ERROR_FAIL; 1398 if (fileItem->CrcDefined && CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->Crc) 1399 res = SZ_ERROR_CRC; 1400 } 1401 return res; 1402 } 1403