1 /* 7zIn.c -- 7z Input functions
\r
2 2010-10-29 : Igor Pavlov : Public domain */
\r
10 Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
\r
12 #define RINOM(x) { if ((x) == 0) return SZ_ERROR_MEM; }
\r
14 #define NUM_FOLDER_CODERS_MAX 32
\r
15 #define NUM_CODER_STREAMS_MAX 32
\r
17 void SzCoderInfo_Init(CSzCoderInfo *p)
\r
19 Buf_Init(&p->Props);
\r
22 void SzCoderInfo_Free(CSzCoderInfo *p, ISzAlloc *alloc)
\r
24 Buf_Free(&p->Props, alloc);
\r
25 SzCoderInfo_Init(p);
\r
28 void SzFolder_Init(CSzFolder *p)
\r
35 p->NumBindPairs = 0;
\r
36 p->NumPackStreams = 0;
\r
37 p->UnpackCRCDefined = 0;
\r
39 p->NumUnpackStreams = 0;
\r
42 void SzFolder_Free(CSzFolder *p, ISzAlloc *alloc)
\r
46 for (i = 0; i < p->NumCoders; i++)
\r
47 SzCoderInfo_Free(&p->Coders[i], alloc);
\r
48 IAlloc_Free(alloc, p->Coders);
\r
49 IAlloc_Free(alloc, p->BindPairs);
\r
50 IAlloc_Free(alloc, p->PackStreams);
\r
51 IAlloc_Free(alloc, p->UnpackSizes);
\r
55 UInt32 SzFolder_GetNumOutStreams(CSzFolder *p)
\r
59 for (i = 0; i < p->NumCoders; i++)
\r
60 result += p->Coders[i].NumOutStreams;
\r
64 int SzFolder_FindBindPairForInStream(CSzFolder *p, UInt32 inStreamIndex)
\r
67 for (i = 0; i < p->NumBindPairs; i++)
\r
68 if (p->BindPairs[i].InIndex == inStreamIndex)
\r
74 int SzFolder_FindBindPairForOutStream(CSzFolder *p, UInt32 outStreamIndex)
\r
77 for (i = 0; i < p->NumBindPairs; i++)
\r
78 if (p->BindPairs[i].OutIndex == outStreamIndex)
\r
83 UInt64 SzFolder_GetUnpackSize(CSzFolder *p)
\r
85 int i = (int)SzFolder_GetNumOutStreams(p);
\r
88 for (i--; i >= 0; i--)
\r
89 if (SzFolder_FindBindPairForOutStream(p, i) < 0)
\r
90 return p->UnpackSizes[i];
\r
95 void SzFile_Init(CSzFileItem *p)
\r
101 p->MTimeDefined = 0;
\r
104 void SzAr_Init(CSzAr *p)
\r
107 p->PackCRCsDefined = 0;
\r
111 p->NumPackStreams = 0;
\r
116 void SzAr_Free(CSzAr *p, ISzAlloc *alloc)
\r
120 for (i = 0; i < p->NumFolders; i++)
\r
121 SzFolder_Free(&p->Folders[i], alloc);
\r
123 IAlloc_Free(alloc, p->PackSizes);
\r
124 IAlloc_Free(alloc, p->PackCRCsDefined);
\r
125 IAlloc_Free(alloc, p->PackCRCs);
\r
126 IAlloc_Free(alloc, p->Folders);
\r
127 IAlloc_Free(alloc, p->Files);
\r
132 void SzArEx_Init(CSzArEx *p)
\r
135 p->FolderStartPackStreamIndex = 0;
\r
136 p->PackStreamStartPositions = 0;
\r
137 p->FolderStartFileIndex = 0;
\r
138 p->FileIndexToFolderIndexMap = 0;
\r
139 p->FileNameOffsets = 0;
\r
140 Buf_Init(&p->FileNames);
\r
143 void SzArEx_Free(CSzArEx *p, ISzAlloc *alloc)
\r
145 IAlloc_Free(alloc, p->FolderStartPackStreamIndex);
\r
146 IAlloc_Free(alloc, p->PackStreamStartPositions);
\r
147 IAlloc_Free(alloc, p->FolderStartFileIndex);
\r
148 IAlloc_Free(alloc, p->FileIndexToFolderIndexMap);
\r
150 IAlloc_Free(alloc, p->FileNameOffsets);
\r
151 Buf_Free(&p->FileNames, alloc);
\r
153 SzAr_Free(&p->db, alloc);
\r
158 UInt64 GetFolderPackStreamSize(int folderIndex, int streamIndex) const
\r
160 return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex];
\r
163 UInt64 GetFilePackSize(int fileIndex) const
\r
165 int folderIndex = FileIndexToFolderIndexMap[fileIndex];
\r
166 if (folderIndex >= 0)
\r
168 const CSzFolder &folderInfo = Folders[folderIndex];
\r
169 if (FolderStartFileIndex[folderIndex] == fileIndex)
\r
170 return GetFolderFullPackSize(folderIndex);
\r
176 #define MY_ALLOC(T, p, size, alloc) { if ((size) == 0) p = 0; else \
\r
177 if ((p = (T *)IAlloc_Alloc(alloc, (size) * sizeof(T))) == 0) return SZ_ERROR_MEM; }
\r
179 static SRes SzArEx_Fill(CSzArEx *p, ISzAlloc *alloc)
\r
181 UInt32 startPos = 0;
\r
182 UInt64 startPosSize = 0;
\r
184 UInt32 folderIndex = 0;
\r
185 UInt32 indexInFolder = 0;
\r
186 MY_ALLOC(UInt32, p->FolderStartPackStreamIndex, p->db.NumFolders, alloc);
\r
187 for (i = 0; i < p->db.NumFolders; i++)
\r
189 p->FolderStartPackStreamIndex[i] = startPos;
\r
190 startPos += p->db.Folders[i].NumPackStreams;
\r
193 MY_ALLOC(UInt64, p->PackStreamStartPositions, p->db.NumPackStreams, alloc);
\r
195 for (i = 0; i < p->db.NumPackStreams; i++)
\r
197 p->PackStreamStartPositions[i] = startPosSize;
\r
198 startPosSize += p->db.PackSizes[i];
\r
201 MY_ALLOC(UInt32, p->FolderStartFileIndex, p->db.NumFolders, alloc);
\r
202 MY_ALLOC(UInt32, p->FileIndexToFolderIndexMap, p->db.NumFiles, alloc);
\r
204 for (i = 0; i < p->db.NumFiles; i++)
\r
206 CSzFileItem *file = p->db.Files + i;
\r
207 int emptyStream = !file->HasStream;
\r
208 if (emptyStream && indexInFolder == 0)
\r
210 p->FileIndexToFolderIndexMap[i] = (UInt32)-1;
\r
213 if (indexInFolder == 0)
\r
216 v3.13 incorrectly worked with empty folders
\r
217 v4.07: Loop for skipping empty folders
\r
221 if (folderIndex >= p->db.NumFolders)
\r
222 return SZ_ERROR_ARCHIVE;
\r
223 p->FolderStartFileIndex[folderIndex] = i;
\r
224 if (p->db.Folders[folderIndex].NumUnpackStreams != 0)
\r
229 p->FileIndexToFolderIndexMap[i] = folderIndex;
\r
233 if (indexInFolder >= p->db.Folders[folderIndex].NumUnpackStreams)
\r
243 UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder)
\r
245 return p->dataPos +
\r
246 p->PackStreamStartPositions[p->FolderStartPackStreamIndex[folderIndex] + indexInFolder];
\r
249 int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize)
\r
251 UInt32 packStreamIndex = p->FolderStartPackStreamIndex[folderIndex];
\r
252 CSzFolder *folder = p->db.Folders + folderIndex;
\r
255 for (i = 0; i < folder->NumPackStreams; i++)
\r
257 UInt64 t = size + p->db.PackSizes[packStreamIndex + i];
\r
258 if (t < size) /* check it */
\r
259 return SZ_ERROR_FAIL;
\r
268 SRes SzReadTime(const CObjectVector<CBuf> &dataVector,
\r
269 CObjectVector<CSzFileItem> &files, UInt64 type)
\r
271 CBoolVector boolVector;
\r
272 RINOK(ReadBoolVector2(files.Size(), boolVector))
\r
274 CStreamSwitch streamSwitch;
\r
275 RINOK(streamSwitch.Set(this, &dataVector));
\r
277 for (int i = 0; i < files.Size(); i++)
\r
279 CSzFileItem &file = files[i];
\r
280 CArchiveFileTime fileTime;
\r
281 bool defined = boolVector[i];
\r
285 RINOK(SzReadUInt32(low));
\r
286 RINOK(SzReadUInt32(high));
\r
287 fileTime.dwLowDateTime = low;
\r
288 fileTime.dwHighDateTime = high;
\r
292 case k7zIdCTime: file.IsCTimeDefined = defined; if (defined) file.CTime = fileTime; break;
\r
293 case k7zIdATime: file.IsATimeDefined = defined; if (defined) file.ATime = fileTime; break;
\r
294 case k7zIdMTime: file.IsMTimeDefined = defined; if (defined) file.MTime = fileTime; break;
\r
301 static int TestSignatureCandidate(Byte *testBytes)
\r
304 for (i = 0; i < k7zSignatureSize; i++)
\r
305 if (testBytes[i] != k7zSignature[i])
\r
310 typedef struct _CSzState
\r
316 static SRes SzReadByte(CSzData *sd, Byte *b)
\r
319 return SZ_ERROR_ARCHIVE;
\r
325 static SRes SzReadBytes(CSzData *sd, Byte *data, size_t size)
\r
328 for (i = 0; i < size; i++)
\r
330 RINOK(SzReadByte(sd, data + i));
\r
335 static SRes SzReadUInt32(CSzData *sd, UInt32 *value)
\r
339 for (i = 0; i < 4; i++)
\r
342 RINOK(SzReadByte(sd, &b));
\r
343 *value |= ((UInt32)(b) << (8 * i));
\r
348 static SRes SzReadNumber(CSzData *sd, UInt64 *value)
\r
353 RINOK(SzReadByte(sd, &firstByte));
\r
355 for (i = 0; i < 8; i++)
\r
358 if ((firstByte & mask) == 0)
\r
360 UInt64 highPart = firstByte & (mask - 1);
\r
361 *value += (highPart << (8 * i));
\r
364 RINOK(SzReadByte(sd, &b));
\r
365 *value |= ((UInt64)b << (8 * i));
\r
371 static SRes SzReadNumber32(CSzData *sd, UInt32 *value)
\r
374 RINOK(SzReadNumber(sd, &value64));
\r
375 if (value64 >= 0x80000000)
\r
376 return SZ_ERROR_UNSUPPORTED;
\r
377 if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 2)))
\r
378 return SZ_ERROR_UNSUPPORTED;
\r
379 *value = (UInt32)value64;
\r
383 static SRes SzReadID(CSzData *sd, UInt64 *value)
\r
385 return SzReadNumber(sd, value);
\r
388 static SRes SzSkeepDataSize(CSzData *sd, UInt64 size)
\r
390 if (size > sd->Size)
\r
391 return SZ_ERROR_ARCHIVE;
\r
392 sd->Size -= (size_t)size;
\r
393 sd->Data += (size_t)size;
\r
397 static SRes SzSkeepData(CSzData *sd)
\r
400 RINOK(SzReadNumber(sd, &size));
\r
401 return SzSkeepDataSize(sd, size);
\r
404 static SRes SzReadArchiveProperties(CSzData *sd)
\r
409 RINOK(SzReadID(sd, &type));
\r
410 if (type == k7zIdEnd)
\r
417 static SRes SzWaitAttribute(CSzData *sd, UInt64 attribute)
\r
422 RINOK(SzReadID(sd, &type));
\r
423 if (type == attribute)
\r
425 if (type == k7zIdEnd)
\r
426 return SZ_ERROR_ARCHIVE;
\r
427 RINOK(SzSkeepData(sd));
\r
431 static SRes SzReadBoolVector(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc)
\r
436 MY_ALLOC(Byte, *v, numItems, alloc);
\r
437 for (i = 0; i < numItems; i++)
\r
441 RINOK(SzReadByte(sd, &b));
\r
444 (*v)[i] = (Byte)(((b & mask) != 0) ? 1 : 0);
\r
450 static SRes SzReadBoolVector2(CSzData *sd, size_t numItems, Byte **v, ISzAlloc *alloc)
\r
452 Byte allAreDefined;
\r
454 RINOK(SzReadByte(sd, &allAreDefined));
\r
455 if (allAreDefined == 0)
\r
456 return SzReadBoolVector(sd, numItems, v, alloc);
\r
457 MY_ALLOC(Byte, *v, numItems, alloc);
\r
458 for (i = 0; i < numItems; i++)
\r
463 static SRes SzReadHashDigests(
\r
466 Byte **digestsDefined,
\r
471 RINOK(SzReadBoolVector2(sd, numItems, digestsDefined, alloc));
\r
472 MY_ALLOC(UInt32, *digests, numItems, alloc);
\r
473 for (i = 0; i < numItems; i++)
\r
474 if ((*digestsDefined)[i])
\r
476 RINOK(SzReadUInt32(sd, (*digests) + i));
\r
481 static SRes SzReadPackInfo(
\r
483 UInt64 *dataOffset,
\r
484 UInt32 *numPackStreams,
\r
485 UInt64 **packSizes,
\r
486 Byte **packCRCsDefined,
\r
491 RINOK(SzReadNumber(sd, dataOffset));
\r
492 RINOK(SzReadNumber32(sd, numPackStreams));
\r
494 RINOK(SzWaitAttribute(sd, k7zIdSize));
\r
496 MY_ALLOC(UInt64, *packSizes, (size_t)*numPackStreams, alloc);
\r
498 for (i = 0; i < *numPackStreams; i++)
\r
500 RINOK(SzReadNumber(sd, (*packSizes) + i));
\r
506 RINOK(SzReadID(sd, &type));
\r
507 if (type == k7zIdEnd)
\r
509 if (type == k7zIdCRC)
\r
511 RINOK(SzReadHashDigests(sd, (size_t)*numPackStreams, packCRCsDefined, packCRCs, alloc));
\r
514 RINOK(SzSkeepData(sd));
\r
516 if (*packCRCsDefined == 0)
\r
518 MY_ALLOC(Byte, *packCRCsDefined, (size_t)*numPackStreams, alloc);
\r
519 MY_ALLOC(UInt32, *packCRCs, (size_t)*numPackStreams, alloc);
\r
520 for (i = 0; i < *numPackStreams; i++)
\r
522 (*packCRCsDefined)[i] = 0;
\r
523 (*packCRCs)[i] = 0;
\r
529 static SRes SzReadSwitch(CSzData *sd)
\r
532 RINOK(SzReadByte(sd, &external));
\r
533 return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED;
\r
536 static SRes SzGetNextFolderItem(CSzData *sd, CSzFolder *folder, ISzAlloc *alloc)
\r
538 UInt32 numCoders, numBindPairs, numPackStreams, i;
\r
539 UInt32 numInStreams = 0, numOutStreams = 0;
\r
541 RINOK(SzReadNumber32(sd, &numCoders));
\r
542 if (numCoders > NUM_FOLDER_CODERS_MAX)
\r
543 return SZ_ERROR_UNSUPPORTED;
\r
544 folder->NumCoders = numCoders;
\r
546 MY_ALLOC(CSzCoderInfo, folder->Coders, (size_t)numCoders, alloc);
\r
548 for (i = 0; i < numCoders; i++)
\r
549 SzCoderInfo_Init(folder->Coders + i);
\r
551 for (i = 0; i < numCoders; i++)
\r
554 CSzCoderInfo *coder = folder->Coders + i;
\r
556 unsigned idSize, j;
\r
558 RINOK(SzReadByte(sd, &mainByte));
\r
559 idSize = (unsigned)(mainByte & 0xF);
\r
560 RINOK(SzReadBytes(sd, longID, idSize));
\r
561 if (idSize > sizeof(coder->MethodID))
\r
562 return SZ_ERROR_UNSUPPORTED;
\r
563 coder->MethodID = 0;
\r
564 for (j = 0; j < idSize; j++)
\r
565 coder->MethodID |= (UInt64)longID[idSize - 1 - j] << (8 * j);
\r
567 if ((mainByte & 0x10) != 0)
\r
569 RINOK(SzReadNumber32(sd, &coder->NumInStreams));
\r
570 RINOK(SzReadNumber32(sd, &coder->NumOutStreams));
\r
571 if (coder->NumInStreams > NUM_CODER_STREAMS_MAX ||
\r
572 coder->NumOutStreams > NUM_CODER_STREAMS_MAX)
\r
573 return SZ_ERROR_UNSUPPORTED;
\r
577 coder->NumInStreams = 1;
\r
578 coder->NumOutStreams = 1;
\r
580 if ((mainByte & 0x20) != 0)
\r
582 UInt64 propertiesSize = 0;
\r
583 RINOK(SzReadNumber(sd, &propertiesSize));
\r
584 if (!Buf_Create(&coder->Props, (size_t)propertiesSize, alloc))
\r
585 return SZ_ERROR_MEM;
\r
586 RINOK(SzReadBytes(sd, coder->Props.data, (size_t)propertiesSize));
\r
589 while ((mainByte & 0x80) != 0)
\r
591 RINOK(SzReadByte(sd, &mainByte));
\r
592 RINOK(SzSkeepDataSize(sd, (mainByte & 0xF)));
\r
593 if ((mainByte & 0x10) != 0)
\r
596 RINOK(SzReadNumber32(sd, &n));
\r
597 RINOK(SzReadNumber32(sd, &n));
\r
599 if ((mainByte & 0x20) != 0)
\r
601 UInt64 propertiesSize = 0;
\r
602 RINOK(SzReadNumber(sd, &propertiesSize));
\r
603 RINOK(SzSkeepDataSize(sd, propertiesSize));
\r
606 numInStreams += coder->NumInStreams;
\r
607 numOutStreams += coder->NumOutStreams;
\r
610 if (numOutStreams == 0)
\r
611 return SZ_ERROR_UNSUPPORTED;
\r
613 folder->NumBindPairs = numBindPairs = numOutStreams - 1;
\r
614 MY_ALLOC(CSzBindPair, folder->BindPairs, (size_t)numBindPairs, alloc);
\r
616 for (i = 0; i < numBindPairs; i++)
\r
618 CSzBindPair *bp = folder->BindPairs + i;
\r
619 RINOK(SzReadNumber32(sd, &bp->InIndex));
\r
620 RINOK(SzReadNumber32(sd, &bp->OutIndex));
\r
623 if (numInStreams < numBindPairs)
\r
624 return SZ_ERROR_UNSUPPORTED;
\r
626 folder->NumPackStreams = numPackStreams = numInStreams - numBindPairs;
\r
627 MY_ALLOC(UInt32, folder->PackStreams, (size_t)numPackStreams, alloc);
\r
629 if (numPackStreams == 1)
\r
631 for (i = 0; i < numInStreams ; i++)
\r
632 if (SzFolder_FindBindPairForInStream(folder, i) < 0)
\r
634 if (i == numInStreams)
\r
635 return SZ_ERROR_UNSUPPORTED;
\r
636 folder->PackStreams[0] = i;
\r
639 for (i = 0; i < numPackStreams; i++)
\r
641 RINOK(SzReadNumber32(sd, folder->PackStreams + i));
\r
646 static SRes SzReadUnpackInfo(
\r
648 UInt32 *numFolders,
\r
649 CSzFolder **folders, /* for alloc */
\r
651 ISzAlloc *allocTemp)
\r
654 RINOK(SzWaitAttribute(sd, k7zIdFolder));
\r
655 RINOK(SzReadNumber32(sd, numFolders));
\r
657 RINOK(SzReadSwitch(sd));
\r
659 MY_ALLOC(CSzFolder, *folders, (size_t)*numFolders, alloc);
\r
661 for (i = 0; i < *numFolders; i++)
\r
662 SzFolder_Init((*folders) + i);
\r
664 for (i = 0; i < *numFolders; i++)
\r
666 RINOK(SzGetNextFolderItem(sd, (*folders) + i, alloc));
\r
670 RINOK(SzWaitAttribute(sd, k7zIdCodersUnpackSize));
\r
672 for (i = 0; i < *numFolders; i++)
\r
675 CSzFolder *folder = (*folders) + i;
\r
676 UInt32 numOutStreams = SzFolder_GetNumOutStreams(folder);
\r
678 MY_ALLOC(UInt64, folder->UnpackSizes, (size_t)numOutStreams, alloc);
\r
680 for (j = 0; j < numOutStreams; j++)
\r
682 RINOK(SzReadNumber(sd, folder->UnpackSizes + j));
\r
689 RINOK(SzReadID(sd, &type));
\r
690 if (type == k7zIdEnd)
\r
692 if (type == k7zIdCRC)
\r
695 Byte *crcsDefined = 0;
\r
697 res = SzReadHashDigests(sd, *numFolders, &crcsDefined, &crcs, allocTemp);
\r
700 for (i = 0; i < *numFolders; i++)
\r
702 CSzFolder *folder = (*folders) + i;
\r
703 folder->UnpackCRCDefined = crcsDefined[i];
\r
704 folder->UnpackCRC = crcs[i];
\r
707 IAlloc_Free(allocTemp, crcs);
\r
708 IAlloc_Free(allocTemp, crcsDefined);
\r
712 RINOK(SzSkeepData(sd));
\r
716 static SRes SzReadSubStreamsInfo(
\r
719 CSzFolder *folders,
\r
720 UInt32 *numUnpackStreams,
\r
721 UInt64 **unpackSizes,
\r
722 Byte **digestsDefined,
\r
724 ISzAlloc *allocTemp)
\r
729 UInt32 numDigests = 0;
\r
731 for (i = 0; i < numFolders; i++)
\r
732 folders[i].NumUnpackStreams = 1;
\r
733 *numUnpackStreams = numFolders;
\r
737 RINOK(SzReadID(sd, &type));
\r
738 if (type == k7zIdNumUnpackStream)
\r
740 *numUnpackStreams = 0;
\r
741 for (i = 0; i < numFolders; i++)
\r
744 RINOK(SzReadNumber32(sd, &numStreams));
\r
745 folders[i].NumUnpackStreams = numStreams;
\r
746 *numUnpackStreams += numStreams;
\r
750 if (type == k7zIdCRC || type == k7zIdSize)
\r
752 if (type == k7zIdEnd)
\r
754 RINOK(SzSkeepData(sd));
\r
757 if (*numUnpackStreams == 0)
\r
760 *digestsDefined = 0;
\r
765 *unpackSizes = (UInt64 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt64));
\r
766 RINOM(*unpackSizes);
\r
767 *digestsDefined = (Byte *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(Byte));
\r
768 RINOM(*digestsDefined);
\r
769 *digests = (UInt32 *)IAlloc_Alloc(allocTemp, (size_t)*numUnpackStreams * sizeof(UInt32));
\r
773 for (i = 0; i < numFolders; i++)
\r
776 v3.13 incorrectly worked with empty folders
\r
777 v4.07: we check that folder is empty
\r
781 UInt32 numSubstreams = folders[i].NumUnpackStreams;
\r
782 if (numSubstreams == 0)
\r
784 if (type == k7zIdSize)
\r
785 for (j = 1; j < numSubstreams; j++)
\r
788 RINOK(SzReadNumber(sd, &size));
\r
789 (*unpackSizes)[si++] = size;
\r
792 (*unpackSizes)[si++] = SzFolder_GetUnpackSize(folders + i) - sum;
\r
794 if (type == k7zIdSize)
\r
796 RINOK(SzReadID(sd, &type));
\r
799 for (i = 0; i < *numUnpackStreams; i++)
\r
801 (*digestsDefined)[i] = 0;
\r
806 for (i = 0; i < numFolders; i++)
\r
808 UInt32 numSubstreams = folders[i].NumUnpackStreams;
\r
809 if (numSubstreams != 1 || !folders[i].UnpackCRCDefined)
\r
810 numDigests += numSubstreams;
\r
817 if (type == k7zIdCRC)
\r
819 int digestIndex = 0;
\r
820 Byte *digestsDefined2 = 0;
\r
821 UInt32 *digests2 = 0;
\r
822 SRes res = SzReadHashDigests(sd, numDigests, &digestsDefined2, &digests2, allocTemp);
\r
825 for (i = 0; i < numFolders; i++)
\r
827 CSzFolder *folder = folders + i;
\r
828 UInt32 numSubstreams = folder->NumUnpackStreams;
\r
829 if (numSubstreams == 1 && folder->UnpackCRCDefined)
\r
831 (*digestsDefined)[si] = 1;
\r
832 (*digests)[si] = folder->UnpackCRC;
\r
838 for (j = 0; j < numSubstreams; j++, digestIndex++)
\r
840 (*digestsDefined)[si] = digestsDefined2[digestIndex];
\r
841 (*digests)[si] = digests2[digestIndex];
\r
847 IAlloc_Free(allocTemp, digestsDefined2);
\r
848 IAlloc_Free(allocTemp, digests2);
\r
851 else if (type == k7zIdEnd)
\r
855 RINOK(SzSkeepData(sd));
\r
857 RINOK(SzReadID(sd, &type));
\r
862 static SRes SzReadStreamsInfo(
\r
864 UInt64 *dataOffset,
\r
866 UInt32 *numUnpackStreams,
\r
867 UInt64 **unpackSizes, /* allocTemp */
\r
868 Byte **digestsDefined, /* allocTemp */
\r
869 UInt32 **digests, /* allocTemp */
\r
871 ISzAlloc *allocTemp)
\r
876 RINOK(SzReadID(sd, &type));
\r
877 if ((UInt64)(int)type != type)
\r
878 return SZ_ERROR_UNSUPPORTED;
\r
883 case k7zIdPackInfo:
\r
885 RINOK(SzReadPackInfo(sd, dataOffset, &p->NumPackStreams,
\r
886 &p->PackSizes, &p->PackCRCsDefined, &p->PackCRCs, alloc));
\r
889 case k7zIdUnpackInfo:
\r
891 RINOK(SzReadUnpackInfo(sd, &p->NumFolders, &p->Folders, alloc, allocTemp));
\r
894 case k7zIdSubStreamsInfo:
\r
896 RINOK(SzReadSubStreamsInfo(sd, p->NumFolders, p->Folders,
\r
897 numUnpackStreams, unpackSizes, digestsDefined, digests, allocTemp));
\r
901 return SZ_ERROR_UNSUPPORTED;
\r
906 size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest)
\r
908 size_t len = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];
\r
912 const Byte *src = p->FileNames.data + (p->FileNameOffsets[fileIndex] * 2);
\r
913 for (i = 0; i < len; i++)
\r
914 dest[i] = GetUi16(src + i * 2);
\r
919 static SRes SzReadFileNames(const Byte *p, size_t size, UInt32 numFiles, size_t *sizes)
\r
923 for (i = 0; i < numFiles; i++)
\r
929 return SZ_ERROR_ARCHIVE;
\r
930 if (p[pos * 2] == 0 && p[pos * 2 + 1] == 0)
\r
937 return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
\r
940 static SRes SzReadHeader2(
\r
941 CSzArEx *p, /* allocMain */
\r
943 UInt64 **unpackSizes, /* allocTemp */
\r
944 Byte **digestsDefined, /* allocTemp */
\r
945 UInt32 **digests, /* allocTemp */
\r
946 Byte **emptyStreamVector, /* allocTemp */
\r
947 Byte **emptyFileVector, /* allocTemp */
\r
948 Byte **lwtVector, /* allocTemp */
\r
949 ISzAlloc *allocMain,
\r
950 ISzAlloc *allocTemp)
\r
953 UInt32 numUnpackStreams = 0;
\r
954 UInt32 numFiles = 0;
\r
955 CSzFileItem *files = 0;
\r
956 UInt32 numEmptyStreams = 0;
\r
959 RINOK(SzReadID(sd, &type));
\r
961 if (type == k7zIdArchiveProperties)
\r
963 RINOK(SzReadArchiveProperties(sd));
\r
964 RINOK(SzReadID(sd, &type));
\r
968 if (type == k7zIdMainStreamsInfo)
\r
970 RINOK(SzReadStreamsInfo(sd,
\r
976 digests, allocMain, allocTemp));
\r
977 p->dataPos += p->startPosAfterHeader;
\r
978 RINOK(SzReadID(sd, &type));
\r
981 if (type == k7zIdEnd)
\r
983 if (type != k7zIdFilesInfo)
\r
984 return SZ_ERROR_ARCHIVE;
\r
986 RINOK(SzReadNumber32(sd, &numFiles));
\r
987 p->db.NumFiles = numFiles;
\r
989 MY_ALLOC(CSzFileItem, files, (size_t)numFiles, allocMain);
\r
991 p->db.Files = files;
\r
992 for (i = 0; i < numFiles; i++)
\r
993 SzFile_Init(files + i);
\r
999 RINOK(SzReadID(sd, &type));
\r
1000 if (type == k7zIdEnd)
\r
1002 RINOK(SzReadNumber(sd, &size));
\r
1003 if (size > sd->Size)
\r
1004 return SZ_ERROR_ARCHIVE;
\r
1005 if ((UInt64)(int)type != type)
\r
1007 RINOK(SzSkeepDataSize(sd, size));
\r
1015 RINOK(SzReadSwitch(sd));
\r
1016 namesSize = (size_t)size - 1;
\r
1017 if ((namesSize & 1) != 0)
\r
1018 return SZ_ERROR_ARCHIVE;
\r
1019 if (!Buf_Create(&p->FileNames, namesSize, allocMain))
\r
1020 return SZ_ERROR_MEM;
\r
1021 MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain);
\r
1022 memcpy(p->FileNames.data, sd->Data, namesSize);
\r
1023 RINOK(SzReadFileNames(sd->Data, namesSize >> 1, numFiles, p->FileNameOffsets))
\r
1024 RINOK(SzSkeepDataSize(sd, namesSize));
\r
1027 case k7zIdEmptyStream:
\r
1029 RINOK(SzReadBoolVector(sd, numFiles, emptyStreamVector, allocTemp));
\r
1030 numEmptyStreams = 0;
\r
1031 for (i = 0; i < numFiles; i++)
\r
1032 if ((*emptyStreamVector)[i])
\r
1033 numEmptyStreams++;
\r
1036 case k7zIdEmptyFile:
\r
1038 RINOK(SzReadBoolVector(sd, numEmptyStreams, emptyFileVector, allocTemp));
\r
1041 case k7zIdWinAttributes:
\r
1043 RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp));
\r
1044 RINOK(SzReadSwitch(sd));
\r
1045 for (i = 0; i < numFiles; i++)
\r
1047 CSzFileItem *f = &files[i];
\r
1048 Byte defined = (*lwtVector)[i];
\r
1049 f->AttribDefined = defined;
\r
1053 RINOK(SzReadUInt32(sd, &f->Attrib));
\r
1056 IAlloc_Free(allocTemp, *lwtVector);
\r
1057 *lwtVector = NULL;
\r
1062 RINOK(SzReadBoolVector2(sd, numFiles, lwtVector, allocTemp));
\r
1063 RINOK(SzReadSwitch(sd));
\r
1064 for (i = 0; i < numFiles; i++)
\r
1066 CSzFileItem *f = &files[i];
\r
1067 Byte defined = (*lwtVector)[i];
\r
1068 f->MTimeDefined = defined;
\r
1069 f->MTime.Low = f->MTime.High = 0;
\r
1072 RINOK(SzReadUInt32(sd, &f->MTime.Low));
\r
1073 RINOK(SzReadUInt32(sd, &f->MTime.High));
\r
1076 IAlloc_Free(allocTemp, *lwtVector);
\r
1077 *lwtVector = NULL;
\r
1082 RINOK(SzSkeepDataSize(sd, size));
\r
1088 UInt32 emptyFileIndex = 0;
\r
1089 UInt32 sizeIndex = 0;
\r
1090 for (i = 0; i < numFiles; i++)
\r
1092 CSzFileItem *file = files + i;
\r
1094 if (*emptyStreamVector == 0)
\r
1095 file->HasStream = 1;
\r
1097 file->HasStream = (Byte)((*emptyStreamVector)[i] ? 0 : 1);
\r
1098 if (file->HasStream)
\r
1101 file->Size = (*unpackSizes)[sizeIndex];
\r
1102 file->Crc = (*digests)[sizeIndex];
\r
1103 file->CrcDefined = (Byte)(*digestsDefined)[sizeIndex];
\r
1108 if (*emptyFileVector == 0)
\r
1111 file->IsDir = (Byte)((*emptyFileVector)[emptyFileIndex] ? 0 : 1);
\r
1115 file->CrcDefined = 0;
\r
1119 return SzArEx_Fill(p, allocMain);
\r
1122 static SRes SzReadHeader(
\r
1125 ISzAlloc *allocMain,
\r
1126 ISzAlloc *allocTemp)
\r
1128 UInt64 *unpackSizes = 0;
\r
1129 Byte *digestsDefined = 0;
\r
1130 UInt32 *digests = 0;
\r
1131 Byte *emptyStreamVector = 0;
\r
1132 Byte *emptyFileVector = 0;
\r
1133 Byte *lwtVector = 0;
\r
1134 SRes res = SzReadHeader2(p, sd,
\r
1135 &unpackSizes, &digestsDefined, &digests,
\r
1136 &emptyStreamVector, &emptyFileVector, &lwtVector,
\r
1137 allocMain, allocTemp);
\r
1138 IAlloc_Free(allocTemp, unpackSizes);
\r
1139 IAlloc_Free(allocTemp, digestsDefined);
\r
1140 IAlloc_Free(allocTemp, digests);
\r
1141 IAlloc_Free(allocTemp, emptyStreamVector);
\r
1142 IAlloc_Free(allocTemp, emptyFileVector);
\r
1143 IAlloc_Free(allocTemp, lwtVector);
\r
1147 static SRes SzReadAndDecodePackedStreams2(
\r
1148 ILookInStream *inStream,
\r
1151 UInt64 baseOffset,
\r
1153 UInt64 **unpackSizes,
\r
1154 Byte **digestsDefined,
\r
1156 ISzAlloc *allocTemp)
\r
1159 UInt32 numUnpackStreams = 0;
\r
1160 UInt64 dataStartPos;
\r
1161 CSzFolder *folder;
\r
1162 UInt64 unpackSize;
\r
1165 RINOK(SzReadStreamsInfo(sd, &dataStartPos, p,
\r
1166 &numUnpackStreams, unpackSizes, digestsDefined, digests,
\r
1167 allocTemp, allocTemp));
\r
1169 dataStartPos += baseOffset;
\r
1170 if (p->NumFolders != 1)
\r
1171 return SZ_ERROR_ARCHIVE;
\r
1173 folder = p->Folders;
\r
1174 unpackSize = SzFolder_GetUnpackSize(folder);
\r
1176 RINOK(LookInStream_SeekTo(inStream, dataStartPos));
\r
1178 if (!Buf_Create(outBuffer, (size_t)unpackSize, allocTemp))
\r
1179 return SZ_ERROR_MEM;
\r
1181 res = SzFolder_Decode(folder, p->PackSizes,
\r
1182 inStream, dataStartPos,
\r
1183 outBuffer->data, (size_t)unpackSize, allocTemp);
\r
1185 if (folder->UnpackCRCDefined)
\r
1186 if (CrcCalc(outBuffer->data, (size_t)unpackSize) != folder->UnpackCRC)
\r
1187 return SZ_ERROR_CRC;
\r
1191 static SRes SzReadAndDecodePackedStreams(
\r
1192 ILookInStream *inStream,
\r
1195 UInt64 baseOffset,
\r
1196 ISzAlloc *allocTemp)
\r
1199 UInt64 *unpackSizes = 0;
\r
1200 Byte *digestsDefined = 0;
\r
1201 UInt32 *digests = 0;
\r
1204 res = SzReadAndDecodePackedStreams2(inStream, sd, outBuffer, baseOffset,
\r
1205 &p, &unpackSizes, &digestsDefined, &digests,
\r
1207 SzAr_Free(&p, allocTemp);
\r
1208 IAlloc_Free(allocTemp, unpackSizes);
\r
1209 IAlloc_Free(allocTemp, digestsDefined);
\r
1210 IAlloc_Free(allocTemp, digests);
\r
1214 static SRes SzArEx_Open2(
\r
1216 ILookInStream *inStream,
\r
1217 ISzAlloc *allocMain,
\r
1218 ISzAlloc *allocTemp)
\r
1220 Byte header[k7zStartHeaderSize];
\r
1221 Int64 startArcPos;
\r
1222 UInt64 nextHeaderOffset, nextHeaderSize;
\r
1223 size_t nextHeaderSizeT;
\r
1224 UInt32 nextHeaderCRC;
\r
1229 RINOK(inStream->Seek(inStream, &startArcPos, SZ_SEEK_CUR));
\r
1231 RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE));
\r
1233 if (!TestSignatureCandidate(header))
\r
1234 return SZ_ERROR_NO_ARCHIVE;
\r
1235 if (header[6] != k7zMajorVersion)
\r
1236 return SZ_ERROR_UNSUPPORTED;
\r
1238 nextHeaderOffset = GetUi64(header + 12);
\r
1239 nextHeaderSize = GetUi64(header + 20);
\r
1240 nextHeaderCRC = GetUi32(header + 28);
\r
1242 p->startPosAfterHeader = startArcPos + k7zStartHeaderSize;
\r
1244 if (CrcCalc(header + 12, 20) != GetUi32(header + 8))
\r
1245 return SZ_ERROR_CRC;
\r
1247 nextHeaderSizeT = (size_t)nextHeaderSize;
\r
1248 if (nextHeaderSizeT != nextHeaderSize)
\r
1249 return SZ_ERROR_MEM;
\r
1250 if (nextHeaderSizeT == 0)
\r
1252 if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize ||
\r
1253 nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize)
\r
1254 return SZ_ERROR_NO_ARCHIVE;
\r
1258 RINOK(inStream->Seek(inStream, &pos, SZ_SEEK_END));
\r
1259 if ((UInt64)pos < startArcPos + nextHeaderOffset ||
\r
1260 (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset ||
\r
1261 (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize)
\r
1262 return SZ_ERROR_INPUT_EOF;
\r
1265 RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset));
\r
1267 if (!Buf_Create(&buffer, nextHeaderSizeT, allocTemp))
\r
1268 return SZ_ERROR_MEM;
\r
1270 res = LookInStream_Read(inStream, buffer.data, nextHeaderSizeT);
\r
1273 res = SZ_ERROR_ARCHIVE;
\r
1274 if (CrcCalc(buffer.data, nextHeaderSizeT) == nextHeaderCRC)
\r
1278 sd.Data = buffer.data;
\r
1279 sd.Size = buffer.size;
\r
1280 res = SzReadID(&sd, &type);
\r
1283 if (type == k7zIdEncodedHeader)
\r
1286 Buf_Init(&outBuffer);
\r
1287 res = SzReadAndDecodePackedStreams(inStream, &sd, &outBuffer, p->startPosAfterHeader, allocTemp);
\r
1289 Buf_Free(&outBuffer, allocTemp);
\r
1292 Buf_Free(&buffer, allocTemp);
\r
1293 buffer.data = outBuffer.data;
\r
1294 buffer.size = outBuffer.size;
\r
1295 sd.Data = buffer.data;
\r
1296 sd.Size = buffer.size;
\r
1297 res = SzReadID(&sd, &type);
\r
1303 if (type == k7zIdHeader)
\r
1304 res = SzReadHeader(p, &sd, allocMain, allocTemp);
\r
1306 res = SZ_ERROR_UNSUPPORTED;
\r
1310 Buf_Free(&buffer, allocTemp);
\r
1314 SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream, ISzAlloc *allocMain, ISzAlloc *allocTemp)
\r
1316 SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp);
\r
1318 SzArEx_Free(p, allocMain);
\r
1322 SRes SzArEx_Extract(
\r
1324 ILookInStream *inStream,
\r
1326 UInt32 *blockIndex,
\r
1328 size_t *outBufferSize,
\r
1330 size_t *outSizeProcessed,
\r
1331 ISzAlloc *allocMain,
\r
1332 ISzAlloc *allocTemp)
\r
1334 UInt32 folderIndex = p->FileIndexToFolderIndexMap[fileIndex];
\r
1337 *outSizeProcessed = 0;
\r
1338 if (folderIndex == (UInt32)-1)
\r
1340 IAlloc_Free(allocMain, *outBuffer);
\r
1341 *blockIndex = folderIndex;
\r
1343 *outBufferSize = 0;
\r
1347 if (*outBuffer == 0 || *blockIndex != folderIndex)
\r
1349 CSzFolder *folder = p->db.Folders + folderIndex;
\r
1350 UInt64 unpackSizeSpec = SzFolder_GetUnpackSize(folder);
\r
1351 size_t unpackSize = (size_t)unpackSizeSpec;
\r
1352 UInt64 startOffset = SzArEx_GetFolderStreamPos(p, folderIndex, 0);
\r
1354 if (unpackSize != unpackSizeSpec)
\r
1355 return SZ_ERROR_MEM;
\r
1356 *blockIndex = folderIndex;
\r
1357 IAlloc_Free(allocMain, *outBuffer);
\r
1360 RINOK(LookInStream_SeekTo(inStream, startOffset));
\r
1364 *outBufferSize = unpackSize;
\r
1365 if (unpackSize != 0)
\r
1367 *outBuffer = (Byte *)IAlloc_Alloc(allocMain, unpackSize);
\r
1368 if (*outBuffer == 0)
\r
1369 res = SZ_ERROR_MEM;
\r
1373 res = SzFolder_Decode(folder,
\r
1374 p->db.PackSizes + p->FolderStartPackStreamIndex[folderIndex],
\r
1375 inStream, startOffset,
\r
1376 *outBuffer, unpackSize, allocTemp);
\r
1379 if (folder->UnpackCRCDefined)
\r
1381 if (CrcCalc(*outBuffer, unpackSize) != folder->UnpackCRC)
\r
1382 res = SZ_ERROR_CRC;
\r
1391 CSzFileItem *fileItem = p->db.Files + fileIndex;
\r
1393 for (i = p->FolderStartFileIndex[folderIndex]; i < fileIndex; i++)
\r
1394 *offset += (UInt32)p->db.Files[i].Size;
\r
1395 *outSizeProcessed = (size_t)fileItem->Size;
\r
1396 if (*offset + *outSizeProcessed > *outBufferSize)
\r
1397 return SZ_ERROR_FAIL;
\r
1398 if (fileItem->CrcDefined && CrcCalc(*outBuffer + *offset, *outSizeProcessed) != fileItem->Crc)
\r
1399 res = SZ_ERROR_CRC;
\r