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