7 #define RINOM(x) { if((x) == 0) return SZE_OUTOFMEMORY; }
9 void SzArDbExInit(CArchiveDatabaseEx
*db
)
11 SzArchiveDatabaseInit(&db
->Database
);
12 db
->FolderStartPackStreamIndex
= 0;
13 db
->PackStreamStartPositions
= 0;
14 db
->FolderStartFileIndex
= 0;
15 db
->FileIndexToFolderIndexMap
= 0;
18 void SzArDbExFree(CArchiveDatabaseEx
*db
, void (*freeFunc
)(void *))
20 freeFunc(db
->FolderStartPackStreamIndex
);
21 freeFunc(db
->PackStreamStartPositions
);
22 freeFunc(db
->FolderStartFileIndex
);
23 freeFunc(db
->FileIndexToFolderIndexMap
);
24 SzArchiveDatabaseFree(&db
->Database
, freeFunc
);
29 CFileSize GetFolderPackStreamSize(int folderIndex, int streamIndex) const
31 return PackSizes[FolderStartPackStreamIndex[folderIndex] + streamIndex];
34 CFileSize GetFilePackSize(int fileIndex) const
36 int folderIndex = FileIndexToFolderIndexMap[fileIndex];
39 const CFolder &folderInfo = Folders[folderIndex];
40 if (FolderStartFileIndex[folderIndex] == fileIndex)
41 return GetFolderFullPackSize(folderIndex);
48 SZ_RESULT
MySzInAlloc(void **p
, size_t size
, void * (*allocFunc
)(size_t size
))
60 SZ_RESULT
SzArDbExFill(CArchiveDatabaseEx
*db
, void * (*allocFunc
)(size_t size
))
63 CFileSize startPosSize
= 0;
65 UInt32 folderIndex
= 0;
66 UInt32 indexInFolder
= 0;
67 RINOK(MySzInAlloc((void **)&db
->FolderStartPackStreamIndex
, db
->Database
.NumFolders
* sizeof(UInt32
), allocFunc
));
68 for(i
= 0; i
< db
->Database
.NumFolders
; i
++)
70 db
->FolderStartPackStreamIndex
[i
] = startPos
;
71 startPos
+= db
->Database
.Folders
[i
].NumPackStreams
;
74 RINOK(MySzInAlloc((void **)&db
->PackStreamStartPositions
, db
->Database
.NumPackStreams
* sizeof(CFileSize
), allocFunc
));
76 for(i
= 0; i
< db
->Database
.NumPackStreams
; i
++)
78 db
->PackStreamStartPositions
[i
] = startPosSize
;
79 startPosSize
+= db
->Database
.PackSizes
[i
];
82 RINOK(MySzInAlloc((void **)&db
->FolderStartFileIndex
, db
->Database
.NumFolders
* sizeof(UInt32
), allocFunc
));
83 RINOK(MySzInAlloc((void **)&db
->FileIndexToFolderIndexMap
, db
->Database
.NumFiles
* sizeof(UInt32
), allocFunc
));
85 for (i
= 0; i
< db
->Database
.NumFiles
; i
++)
87 CFileItem
*file
= db
->Database
.Files
+ i
;
88 int emptyStream
= !file
->HasStream
;
89 if (emptyStream
&& indexInFolder
== 0)
91 db
->FileIndexToFolderIndexMap
[i
] = (UInt32
)-1;
94 if (indexInFolder
== 0)
97 v3.13 incorrectly worked with empty folders
98 v4.07: Loop for skipping empty folders
102 if (folderIndex
>= db
->Database
.NumFolders
)
103 return SZE_ARCHIVE_ERROR
;
104 db
->FolderStartFileIndex
[folderIndex
] = i
;
105 if (db
->Database
.Folders
[folderIndex
].NumUnPackStreams
!= 0)
110 db
->FileIndexToFolderIndexMap
[i
] = folderIndex
;
114 if (indexInFolder
>= db
->Database
.Folders
[folderIndex
].NumUnPackStreams
)
124 CFileSize
SzArDbGetFolderStreamPos(CArchiveDatabaseEx
*db
, UInt32 folderIndex
, UInt32 indexInFolder
)
126 return db
->ArchiveInfo
.DataStartPosition
+
127 db
->PackStreamStartPositions
[db
->FolderStartPackStreamIndex
[folderIndex
] + indexInFolder
];
130 CFileSize
SzArDbGetFolderFullPackSize(CArchiveDatabaseEx
*db
, UInt32 folderIndex
)
132 UInt32 packStreamIndex
= db
->FolderStartPackStreamIndex
[folderIndex
];
133 CFolder
*folder
= db
->Database
.Folders
+ folderIndex
;
136 for (i
= 0; i
< folder
->NumPackStreams
; i
++)
137 size
+= db
->Database
.PackSizes
[packStreamIndex
+ i
];
143 SZ_RESULT SzReadTime(const CObjectVector<CSzByteBuffer> &dataVector,
144 CObjectVector<CFileItem> &files, UInt64 type)
146 CBoolVector boolVector;
147 RINOK(ReadBoolVector2(files.Size(), boolVector))
149 CStreamSwitch streamSwitch;
150 RINOK(streamSwitch.Set(this, &dataVector));
152 for(int i = 0; i < files.Size(); i++)
154 CFileItem &file = files[i];
155 CArchiveFileTime fileTime;
156 bool defined = boolVector[i];
160 RINOK(SzReadUInt32(low));
161 RINOK(SzReadUInt32(high));
162 fileTime.dwLowDateTime = low;
163 fileTime.dwHighDateTime = high;
167 case k7zIdCreationTime:
168 file.IsCreationTimeDefined = defined;
170 file.CreationTime = fileTime;
172 case k7zIdLastWriteTime:
173 file.IsLastWriteTimeDefined = defined;
175 file.LastWriteTime = fileTime;
177 case k7zIdLastAccessTime:
178 file.IsLastAccessTimeDefined = defined;
180 file.LastAccessTime = fileTime;
188 SZ_RESULT
SafeReadDirect(ISzInStream
*inStream
, Byte
*data
, size_t size
)
194 size_t processedSize
;
195 RINOK(inStream
->Read(inStream
, (void **)&inBuffer
, size
, &processedSize
));
196 if (processedSize
== 0 || processedSize
> size
)
198 size
-= processedSize
;
201 *data
++ = *inBuffer
++;
203 while (--processedSize
!= 0);
206 size_t processedSize
;
207 RINOK(inStream
->Read(inStream
, data
, size
, &processedSize
));
208 if (processedSize
!= size
)
214 SZ_RESULT
SafeReadDirectByte(ISzInStream
*inStream
, Byte
*data
)
216 return SafeReadDirect(inStream
, data
, 1);
219 SZ_RESULT
SafeReadDirectUInt32(ISzInStream
*inStream
, UInt32
*value
)
223 for (i
= 0; i
< 4; i
++)
226 RINOK(SafeReadDirectByte(inStream
, &b
));
227 *value
|= ((UInt32
)b
<< (8 * i
));
232 SZ_RESULT
SafeReadDirectUInt64(ISzInStream
*inStream
, UInt64
*value
)
236 for (i
= 0; i
< 8; i
++)
239 RINOK(SafeReadDirectByte(inStream
, &b
));
240 *value
|= ((UInt32
)b
<< (8 * i
));
245 int TestSignatureCandidate(Byte
*testBytes
)
248 for (i
= 0; i
< k7zSignatureSize
; i
++)
249 if (testBytes
[i
] != k7zSignature
[i
])
254 typedef struct _CSzState
260 SZ_RESULT
SzReadByte(CSzData
*sd
, Byte
*b
)
263 return SZE_ARCHIVE_ERROR
;
269 SZ_RESULT
SzReadBytes(CSzData
*sd
, Byte
*data
, size_t size
)
272 for (i
= 0; i
< size
; i
++)
274 RINOK(SzReadByte(sd
, data
+ i
));
279 SZ_RESULT
SzReadUInt32(CSzData
*sd
, UInt32
*value
)
283 for (i
= 0; i
< 4; i
++)
286 RINOK(SzReadByte(sd
, &b
));
287 *value
|= ((UInt32
)(b
) << (8 * i
));
292 SZ_RESULT
SzReadNumber(CSzData
*sd
, UInt64
*value
)
297 RINOK(SzReadByte(sd
, &firstByte
));
299 for (i
= 0; i
< 8; i
++)
302 if ((firstByte
& mask
) == 0)
304 UInt64 highPart
= firstByte
& (mask
- 1);
305 *value
+= (highPart
<< (8 * i
));
308 RINOK(SzReadByte(sd
, &b
));
309 *value
|= ((UInt64
)b
<< (8 * i
));
315 SZ_RESULT
SzReadSize(CSzData
*sd
, CFileSize
*value
)
318 RINOK(SzReadNumber(sd
, &value64
));
319 *value
= (CFileSize
)value64
;
323 SZ_RESULT
SzReadNumber32(CSzData
*sd
, UInt32
*value
)
326 RINOK(SzReadNumber(sd
, &value64
));
327 if (value64
>= 0x80000000)
329 if (value64
>= ((UInt64
)(1) << ((sizeof(size_t) - 1) * 8 + 2)))
331 *value
= (UInt32
)value64
;
335 SZ_RESULT
SzReadID(CSzData
*sd
, UInt64
*value
)
337 return SzReadNumber(sd
, value
);
340 SZ_RESULT
SzSkeepDataSize(CSzData
*sd
, UInt64 size
)
343 return SZE_ARCHIVE_ERROR
;
344 sd
->Size
-= (size_t)size
;
345 sd
->Data
+= (size_t)size
;
349 SZ_RESULT
SzSkeepData(CSzData
*sd
)
352 RINOK(SzReadNumber(sd
, &size
));
353 return SzSkeepDataSize(sd
, size
);
356 SZ_RESULT
SzReadArchiveProperties(CSzData
*sd
)
361 RINOK(SzReadID(sd
, &type
));
362 if (type
== k7zIdEnd
)
369 SZ_RESULT
SzWaitAttribute(CSzData
*sd
, UInt64 attribute
)
374 RINOK(SzReadID(sd
, &type
));
375 if (type
== attribute
)
377 if (type
== k7zIdEnd
)
378 return SZE_ARCHIVE_ERROR
;
379 RINOK(SzSkeepData(sd
));
383 SZ_RESULT
SzReadBoolVector(CSzData
*sd
, size_t numItems
, Byte
**v
, void * (*allocFunc
)(size_t size
))
388 RINOK(MySzInAlloc((void **)v
, numItems
* sizeof(Byte
), allocFunc
));
389 for(i
= 0; i
< numItems
; i
++)
393 RINOK(SzReadByte(sd
, &b
));
396 (*v
)[i
] = (Byte
)(((b
& mask
) != 0) ? 1 : 0);
402 SZ_RESULT
SzReadBoolVector2(CSzData
*sd
, size_t numItems
, Byte
**v
, void * (*allocFunc
)(size_t size
))
406 RINOK(SzReadByte(sd
, &allAreDefined
));
407 if (allAreDefined
== 0)
408 return SzReadBoolVector(sd
, numItems
, v
, allocFunc
);
409 RINOK(MySzInAlloc((void **)v
, numItems
* sizeof(Byte
), allocFunc
));
410 for(i
= 0; i
< numItems
; i
++)
415 SZ_RESULT
SzReadHashDigests(
418 Byte
**digestsDefined
,
420 void * (*allocFunc
)(size_t size
))
423 RINOK(SzReadBoolVector2(sd
, numItems
, digestsDefined
, allocFunc
));
424 RINOK(MySzInAlloc((void **)digests
, numItems
* sizeof(UInt32
), allocFunc
));
425 for(i
= 0; i
< numItems
; i
++)
426 if ((*digestsDefined
)[i
])
428 RINOK(SzReadUInt32(sd
, (*digests
) + i
));
433 SZ_RESULT
SzReadPackInfo(
435 CFileSize
*dataOffset
,
436 UInt32
*numPackStreams
,
437 CFileSize
**packSizes
,
438 Byte
**packCRCsDefined
,
440 void * (*allocFunc
)(size_t size
))
443 RINOK(SzReadSize(sd
, dataOffset
));
444 RINOK(SzReadNumber32(sd
, numPackStreams
));
446 RINOK(SzWaitAttribute(sd
, k7zIdSize
));
448 RINOK(MySzInAlloc((void **)packSizes
, (size_t)*numPackStreams
* sizeof(CFileSize
), allocFunc
));
450 for(i
= 0; i
< *numPackStreams
; i
++)
452 RINOK(SzReadSize(sd
, (*packSizes
) + i
));
458 RINOK(SzReadID(sd
, &type
));
459 if (type
== k7zIdEnd
)
461 if (type
== k7zIdCRC
)
463 RINOK(SzReadHashDigests(sd
, (size_t)*numPackStreams
, packCRCsDefined
, packCRCs
, allocFunc
));
466 RINOK(SzSkeepData(sd
));
468 if (*packCRCsDefined
== 0)
470 RINOK(MySzInAlloc((void **)packCRCsDefined
, (size_t)*numPackStreams
* sizeof(Byte
), allocFunc
));
471 RINOK(MySzInAlloc((void **)packCRCs
, (size_t)*numPackStreams
* sizeof(UInt32
), allocFunc
));
472 for(i
= 0; i
< *numPackStreams
; i
++)
474 (*packCRCsDefined
)[i
] = 0;
481 SZ_RESULT
SzReadSwitch(CSzData
*sd
)
484 RINOK(SzReadByte(sd
, &external
));
485 return (external
== 0) ? SZ_OK
: SZE_ARCHIVE_ERROR
;
488 SZ_RESULT
SzGetNextFolderItem(CSzData
*sd
, CFolder
*folder
, void * (*allocFunc
)(size_t size
))
492 UInt32 numPackedStreams
;
494 UInt32 numInStreams
= 0;
495 UInt32 numOutStreams
= 0;
496 RINOK(SzReadNumber32(sd
, &numCoders
));
497 folder
->NumCoders
= numCoders
;
499 RINOK(MySzInAlloc((void **)&folder
->Coders
, (size_t)numCoders
* sizeof(CCoderInfo
), allocFunc
));
501 for (i
= 0; i
< numCoders
; i
++)
502 SzCoderInfoInit(folder
->Coders
+ i
);
504 for (i
= 0; i
< numCoders
; i
++)
507 CCoderInfo
*coder
= folder
->Coders
+ i
;
509 RINOK(SzReadByte(sd
, &mainByte
));
510 coder
->MethodID
.IDSize
= (Byte
)(mainByte
& 0xF);
511 RINOK(SzReadBytes(sd
, coder
->MethodID
.ID
, coder
->MethodID
.IDSize
));
512 if ((mainByte
& 0x10) != 0)
514 RINOK(SzReadNumber32(sd
, &coder
->NumInStreams
));
515 RINOK(SzReadNumber32(sd
, &coder
->NumOutStreams
));
519 coder
->NumInStreams
= 1;
520 coder
->NumOutStreams
= 1;
522 if ((mainByte
& 0x20) != 0)
524 UInt64 propertiesSize
= 0;
525 RINOK(SzReadNumber(sd
, &propertiesSize
));
526 if (!SzByteBufferCreate(&coder
->Properties
, (size_t)propertiesSize
, allocFunc
))
527 return SZE_OUTOFMEMORY
;
528 RINOK(SzReadBytes(sd
, coder
->Properties
.Items
, (size_t)propertiesSize
));
531 while ((mainByte
& 0x80) != 0)
533 RINOK(SzReadByte(sd
, &mainByte
));
534 RINOK(SzSkeepDataSize(sd
, (mainByte
& 0xF)));
535 if ((mainByte
& 0x10) != 0)
538 RINOK(SzReadNumber32(sd
, &n
));
539 RINOK(SzReadNumber32(sd
, &n
));
541 if ((mainByte
& 0x20) != 0)
543 UInt64 propertiesSize
= 0;
544 RINOK(SzReadNumber(sd
, &propertiesSize
));
545 RINOK(SzSkeepDataSize(sd
, propertiesSize
));
548 numInStreams
+= (UInt32
)coder
->NumInStreams
;
549 numOutStreams
+= (UInt32
)coder
->NumOutStreams
;
552 numBindPairs
= numOutStreams
- 1;
553 folder
->NumBindPairs
= numBindPairs
;
556 RINOK(MySzInAlloc((void **)&folder
->BindPairs
, (size_t)numBindPairs
* sizeof(CBindPair
), allocFunc
));
558 for (i
= 0; i
< numBindPairs
; i
++)
560 CBindPair
*bindPair
= folder
->BindPairs
+ i
;;
561 RINOK(SzReadNumber32(sd
, &bindPair
->InIndex
));
562 RINOK(SzReadNumber32(sd
, &bindPair
->OutIndex
));
565 numPackedStreams
= numInStreams
- (UInt32
)numBindPairs
;
567 folder
->NumPackStreams
= numPackedStreams
;
568 RINOK(MySzInAlloc((void **)&folder
->PackStreams
, (size_t)numPackedStreams
* sizeof(UInt32
), allocFunc
));
570 if (numPackedStreams
== 1)
574 for (j
= 0; j
< numInStreams
; j
++)
575 if (SzFolderFindBindPairForInStream(folder
, j
) < 0)
577 folder
->PackStreams
[pi
++] = j
;
582 for(i
= 0; i
< numPackedStreams
; i
++)
584 RINOK(SzReadNumber32(sd
, folder
->PackStreams
+ i
));
589 SZ_RESULT
SzReadUnPackInfo(
592 CFolder
**folders
, /* for allocFunc */
593 void * (*allocFunc
)(size_t size
),
597 RINOK(SzWaitAttribute(sd
, k7zIdFolder
));
598 RINOK(SzReadNumber32(sd
, numFolders
));
600 RINOK(SzReadSwitch(sd
));
603 RINOK(MySzInAlloc((void **)folders
, (size_t)*numFolders
* sizeof(CFolder
), allocFunc
));
605 for(i
= 0; i
< *numFolders
; i
++)
606 SzFolderInit((*folders
) + i
);
608 for(i
= 0; i
< *numFolders
; i
++)
610 RINOK(SzGetNextFolderItem(sd
, (*folders
) + i
, allocFunc
));
614 RINOK(SzWaitAttribute(sd
, k7zIdCodersUnPackSize
));
616 for(i
= 0; i
< *numFolders
; i
++)
619 CFolder
*folder
= (*folders
) + i
;
620 UInt32 numOutStreams
= SzFolderGetNumOutStreams(folder
);
622 RINOK(MySzInAlloc((void **)&folder
->UnPackSizes
, (size_t)numOutStreams
* sizeof(CFileSize
), allocFunc
));
624 for(j
= 0; j
< numOutStreams
; j
++)
626 RINOK(SzReadSize(sd
, folder
->UnPackSizes
+ j
));
633 RINOK(SzReadID(sd
, &type
));
634 if (type
== k7zIdEnd
)
636 if (type
== k7zIdCRC
)
639 Byte
*crcsDefined
= 0;
641 res
= SzReadHashDigests(sd
, *numFolders
, &crcsDefined
, &crcs
, allocTemp
->Alloc
);
644 for(i
= 0; i
< *numFolders
; i
++)
646 CFolder
*folder
= (*folders
) + i
;
647 folder
->UnPackCRCDefined
= crcsDefined
[i
];
648 folder
->UnPackCRC
= crcs
[i
];
651 allocTemp
->Free(crcs
);
652 allocTemp
->Free(crcsDefined
);
656 RINOK(SzSkeepData(sd
));
660 SZ_RESULT
SzReadSubStreamsInfo(
664 UInt32
*numUnPackStreams
,
665 CFileSize
**unPackSizes
,
666 Byte
**digestsDefined
,
673 UInt32 numDigests
= 0;
675 for(i
= 0; i
< numFolders
; i
++)
676 folders
[i
].NumUnPackStreams
= 1;
677 *numUnPackStreams
= numFolders
;
681 RINOK(SzReadID(sd
, &type
));
682 if (type
== k7zIdNumUnPackStream
)
684 *numUnPackStreams
= 0;
685 for(i
= 0; i
< numFolders
; i
++)
688 RINOK(SzReadNumber32(sd
, &numStreams
));
689 folders
[i
].NumUnPackStreams
= numStreams
;
690 *numUnPackStreams
+= numStreams
;
694 if (type
== k7zIdCRC
|| type
== k7zIdSize
)
696 if (type
== k7zIdEnd
)
698 RINOK(SzSkeepData(sd
));
701 if (*numUnPackStreams
== 0)
709 *unPackSizes
= (CFileSize
*)allocTemp
->Alloc((size_t)*numUnPackStreams
* sizeof(CFileSize
));
711 *digestsDefined
= (Byte
*)allocTemp
->Alloc((size_t)*numUnPackStreams
* sizeof(Byte
));
712 RINOM(*digestsDefined
);
713 *digests
= (UInt32
*)allocTemp
->Alloc((size_t)*numUnPackStreams
* sizeof(UInt32
));
717 for(i
= 0; i
< numFolders
; i
++)
720 v3.13 incorrectly worked with empty folders
721 v4.07: we check that folder is empty
725 UInt32 numSubstreams
= folders
[i
].NumUnPackStreams
;
726 if (numSubstreams
== 0)
728 if (type
== k7zIdSize
)
729 for (j
= 1; j
< numSubstreams
; j
++)
732 RINOK(SzReadSize(sd
, &size
));
733 (*unPackSizes
)[si
++] = size
;
736 (*unPackSizes
)[si
++] = SzFolderGetUnPackSize(folders
+ i
) - sum
;
738 if (type
== k7zIdSize
)
740 RINOK(SzReadID(sd
, &type
));
743 for(i
= 0; i
< *numUnPackStreams
; i
++)
745 (*digestsDefined
)[i
] = 0;
750 for(i
= 0; i
< numFolders
; i
++)
752 UInt32 numSubstreams
= folders
[i
].NumUnPackStreams
;
753 if (numSubstreams
!= 1 || !folders
[i
].UnPackCRCDefined
)
754 numDigests
+= numSubstreams
;
761 if (type
== k7zIdCRC
)
764 Byte
*digestsDefined2
= 0;
765 UInt32
*digests2
= 0;
766 SZ_RESULT res
= SzReadHashDigests(sd
, numDigests
, &digestsDefined2
, &digests2
, allocTemp
->Alloc
);
769 for (i
= 0; i
< numFolders
; i
++)
771 CFolder
*folder
= folders
+ i
;
772 UInt32 numSubstreams
= folder
->NumUnPackStreams
;
773 if (numSubstreams
== 1 && folder
->UnPackCRCDefined
)
775 (*digestsDefined
)[si
] = 1;
776 (*digests
)[si
] = folder
->UnPackCRC
;
782 for (j
= 0; j
< numSubstreams
; j
++, digestIndex
++)
784 (*digestsDefined
)[si
] = digestsDefined2
[digestIndex
];
785 (*digests
)[si
] = digests2
[digestIndex
];
791 allocTemp
->Free(digestsDefined2
);
792 allocTemp
->Free(digests2
);
795 else if (type
== k7zIdEnd
)
799 RINOK(SzSkeepData(sd
));
801 RINOK(SzReadID(sd
, &type
));
806 SZ_RESULT
SzReadStreamsInfo(
808 CFileSize
*dataOffset
,
809 CArchiveDatabase
*db
,
810 UInt32
*numUnPackStreams
,
811 CFileSize
**unPackSizes
, /* allocTemp */
812 Byte
**digestsDefined
, /* allocTemp */
813 UInt32
**digests
, /* allocTemp */
814 void * (*allocFunc
)(size_t size
),
820 RINOK(SzReadID(sd
, &type
));
821 if ((UInt64
)(int)type
!= type
)
829 RINOK(SzReadPackInfo(sd
, dataOffset
, &db
->NumPackStreams
,
830 &db
->PackSizes
, &db
->PackCRCsDefined
, &db
->PackCRCs
, allocFunc
));
833 case k7zIdUnPackInfo
:
835 RINOK(SzReadUnPackInfo(sd
, &db
->NumFolders
, &db
->Folders
, allocFunc
, allocTemp
));
838 case k7zIdSubStreamsInfo
:
840 RINOK(SzReadSubStreamsInfo(sd
, db
->NumFolders
, db
->Folders
,
841 numUnPackStreams
, unPackSizes
, digestsDefined
, digests
, allocTemp
));
850 Byte kUtf8Limits
[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
852 SZ_RESULT
SzReadFileNames(CSzData
*sd
, UInt32 numFiles
, CFileItem
*files
,
853 void * (*allocFunc
)(size_t size
))
856 for(i
= 0; i
< numFiles
; i
++)
860 CFileItem
*file
= files
+ i
;
861 while(pos
+ 2 <= sd
->Size
)
864 UInt32 value
= (UInt32
)(sd
->Data
[pos
] | (((UInt32
)sd
->Data
[pos
+ 1]) << 8));
871 if (value
>= 0xD800 && value
< 0xE000)
875 return SZE_ARCHIVE_ERROR
;
876 if (pos
+ 2 > sd
->Size
)
877 return SZE_ARCHIVE_ERROR
;
878 c2
= (UInt32
)(sd
->Data
[pos
] | (((UInt32
)sd
->Data
[pos
+ 1]) << 8));
880 if (c2
< 0xDC00 || c2
>= 0xE000)
881 return SZE_ARCHIVE_ERROR
;
882 value
= ((value
- 0xD800) << 10) | (c2
- 0xDC00);
884 for (numAdds
= 1; numAdds
< 5; numAdds
++)
885 if (value
< (((UInt32
)1) << (numAdds
* 5 + 6)))
890 RINOK(MySzInAlloc((void **)&file
->Name
, (size_t)len
* sizeof(char), allocFunc
));
896 UInt32 value
= (UInt32
)(sd
->Data
[0] | (((UInt32
)sd
->Data
[1]) << 8));
897 SzSkeepDataSize(sd
, 2);
900 file
->Name
[len
++] = (char)value
;
905 if (value
>= 0xD800 && value
< 0xE000)
907 UInt32 c2
= (UInt32
)(sd
->Data
[0] | (((UInt32
)sd
->Data
[1]) << 8));
908 SzSkeepDataSize(sd
, 2);
909 value
= ((value
- 0xD800) << 10) | (c2
- 0xDC00);
911 for (numAdds
= 1; numAdds
< 5; numAdds
++)
912 if (value
< (((UInt32
)1) << (numAdds
* 5 + 6)))
914 file
->Name
[len
++] = (char)(kUtf8Limits
[numAdds
- 1] + (value
>> (6 * numAdds
)));
918 file
->Name
[len
++] = (char)(0x80 + ((value
>> (6 * numAdds
)) & 0x3F));
928 SZ_RESULT
SzReadHeader2(
930 CArchiveDatabaseEx
*db
, /* allocMain */
931 CFileSize
**unPackSizes
, /* allocTemp */
932 Byte
**digestsDefined
, /* allocTemp */
933 UInt32
**digests
, /* allocTemp */
934 Byte
**emptyStreamVector
, /* allocTemp */
935 Byte
**emptyFileVector
, /* allocTemp */
940 UInt32 numUnPackStreams
= 0;
942 CFileItem
*files
= 0;
943 UInt32 numEmptyStreams
= 0;
946 RINOK(SzReadID(sd
, &type
));
948 if (type
== k7zIdArchiveProperties
)
950 RINOK(SzReadArchiveProperties(sd
));
951 RINOK(SzReadID(sd
, &type
));
955 if (type
== k7zIdMainStreamsInfo
)
957 RINOK(SzReadStreamsInfo(sd
,
958 &db
->ArchiveInfo
.DataStartPosition
,
963 digests
, allocMain
->Alloc
, allocTemp
));
964 db
->ArchiveInfo
.DataStartPosition
+= db
->ArchiveInfo
.StartPositionAfterHeader
;
965 RINOK(SzReadID(sd
, &type
));
968 if (type
== k7zIdEnd
)
970 if (type
!= k7zIdFilesInfo
)
971 return SZE_ARCHIVE_ERROR
;
973 RINOK(SzReadNumber32(sd
, &numFiles
));
974 db
->Database
.NumFiles
= numFiles
;
976 RINOK(MySzInAlloc((void **)&files
, (size_t)numFiles
* sizeof(CFileItem
), allocMain
->Alloc
));
978 db
->Database
.Files
= files
;
979 for(i
= 0; i
< numFiles
; i
++)
980 SzFileInit(files
+ i
);
986 RINOK(SzReadID(sd
, &type
));
987 if (type
== k7zIdEnd
)
989 RINOK(SzReadNumber(sd
, &size
));
991 if ((UInt64
)(int)type
!= type
)
993 RINOK(SzSkeepDataSize(sd
, size
));
1000 RINOK(SzReadSwitch(sd
));
1001 RINOK(SzReadFileNames(sd
, numFiles
, files
, allocMain
->Alloc
))
1004 case k7zIdEmptyStream
:
1006 RINOK(SzReadBoolVector(sd
, numFiles
, emptyStreamVector
, allocTemp
->Alloc
));
1007 numEmptyStreams
= 0;
1008 for (i
= 0; i
< numFiles
; i
++)
1009 if ((*emptyStreamVector
)[i
])
1013 case k7zIdEmptyFile
:
1015 RINOK(SzReadBoolVector(sd
, numEmptyStreams
, emptyFileVector
, allocTemp
->Alloc
));
1020 RINOK(SzSkeepDataSize(sd
, size
));
1026 UInt32 emptyFileIndex
= 0;
1027 UInt32 sizeIndex
= 0;
1028 for(i
= 0; i
< numFiles
; i
++)
1030 CFileItem
*file
= files
+ i
;
1032 if (*emptyStreamVector
== 0)
1033 file
->HasStream
= 1;
1035 file
->HasStream
= (Byte
)((*emptyStreamVector
)[i
] ? 0 : 1);
1038 file
->IsDirectory
= 0;
1039 file
->Size
= (*unPackSizes
)[sizeIndex
];
1040 file
->FileCRC
= (*digests
)[sizeIndex
];
1041 file
->IsFileCRCDefined
= (Byte
)(*digestsDefined
)[sizeIndex
];
1046 if (*emptyFileVector
== 0)
1047 file
->IsDirectory
= 1;
1049 file
->IsDirectory
= (Byte
)((*emptyFileVector
)[emptyFileIndex
] ? 0 : 1);
1052 file
->IsFileCRCDefined
= 0;
1056 return SzArDbExFill(db
, allocMain
->Alloc
);
1059 SZ_RESULT
SzReadHeader(
1061 CArchiveDatabaseEx
*db
,
1062 ISzAlloc
*allocMain
,
1063 ISzAlloc
*allocTemp
)
1065 CFileSize
*unPackSizes
= 0;
1066 Byte
*digestsDefined
= 0;
1067 UInt32
*digests
= 0;
1068 Byte
*emptyStreamVector
= 0;
1069 Byte
*emptyFileVector
= 0;
1070 SZ_RESULT res
= SzReadHeader2(sd
, db
,
1071 &unPackSizes
, &digestsDefined
, &digests
,
1072 &emptyStreamVector
, &emptyFileVector
,
1073 allocMain
, allocTemp
);
1074 allocTemp
->Free(unPackSizes
);
1075 allocTemp
->Free(digestsDefined
);
1076 allocTemp
->Free(digests
);
1077 allocTemp
->Free(emptyStreamVector
);
1078 allocTemp
->Free(emptyFileVector
);
1082 SZ_RESULT
SzReadAndDecodePackedStreams2(
1083 ISzInStream
*inStream
,
1085 CSzByteBuffer
*outBuffer
,
1086 CFileSize baseOffset
,
1087 CArchiveDatabase
*db
,
1088 CFileSize
**unPackSizes
,
1089 Byte
**digestsDefined
,
1094 ISzAlloc
*allocTemp
)
1097 UInt32 numUnPackStreams
= 0;
1098 CFileSize dataStartPos
;
1101 CFileSize packSize
= 0;
1104 CFileSize unPackSize
;
1108 RINOK(SzReadStreamsInfo(sd
, &dataStartPos
, db
,
1109 &numUnPackStreams
, unPackSizes
, digestsDefined
, digests
,
1110 allocTemp
->Alloc
, allocTemp
));
1112 dataStartPos
+= baseOffset
;
1113 if (db
->NumFolders
!= 1)
1114 return SZE_ARCHIVE_ERROR
;
1116 folder
= db
->Folders
;
1117 unPackSize
= SzFolderGetUnPackSize(folder
);
1119 RINOK(inStream
->Seek(inStream
, dataStartPos
));
1122 for (i
= 0; i
< db
->NumPackStreams
; i
++)
1123 packSize
+= db
->PackSizes
[i
];
1125 RINOK(MySzInAlloc((void **)inBuffer
, (size_t)packSize
, allocTemp
->Alloc
));
1127 RINOK(SafeReadDirect(inStream
, *inBuffer
, (size_t)packSize
));
1130 if (!SzByteBufferCreate(outBuffer
, (size_t)unPackSize
, allocTemp
->Alloc
))
1131 return SZE_OUTOFMEMORY
;
1133 res
= SzDecode(db
->PackSizes
, folder
,
1139 outBuffer
->Items
, (size_t)unPackSize
,
1140 &outRealSize
, allocTemp
);
1142 if (outRealSize
!= (UInt32
)unPackSize
)
1144 if (folder
->UnPackCRCDefined
)
1145 if (!CrcVerifyDigest(folder
->UnPackCRC
, outBuffer
->Items
, (size_t)unPackSize
))
1150 SZ_RESULT
SzReadAndDecodePackedStreams(
1151 ISzInStream
*inStream
,
1153 CSzByteBuffer
*outBuffer
,
1154 CFileSize baseOffset
,
1155 ISzAlloc
*allocTemp
)
1157 CArchiveDatabase db
;
1158 CFileSize
*unPackSizes
= 0;
1159 Byte
*digestsDefined
= 0;
1160 UInt32
*digests
= 0;
1165 SzArchiveDatabaseInit(&db
);
1166 res
= SzReadAndDecodePackedStreams2(inStream
, sd
, outBuffer
, baseOffset
,
1167 &db
, &unPackSizes
, &digestsDefined
, &digests
,
1172 SzArchiveDatabaseFree(&db
, allocTemp
->Free
);
1173 allocTemp
->Free(unPackSizes
);
1174 allocTemp
->Free(digestsDefined
);
1175 allocTemp
->Free(digests
);
1177 allocTemp
->Free(inBuffer
);
1182 SZ_RESULT
SzArchiveOpen2(
1183 ISzInStream
*inStream
,
1184 CArchiveDatabaseEx
*db
,
1185 ISzAlloc
*allocMain
,
1186 ISzAlloc
*allocTemp
)
1188 Byte signature
[k7zSignatureSize
];
1190 UInt32 crcFromArchive
;
1191 UInt64 nextHeaderOffset
;
1192 UInt64 nextHeaderSize
;
1193 UInt32 nextHeaderCRC
;
1196 CSzByteBuffer buffer
;
1200 RINOK(SafeReadDirect(inStream
, signature
, k7zSignatureSize
));
1202 if (!TestSignatureCandidate(signature
))
1203 return SZE_ARCHIVE_ERROR
;
1207 db.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition;
1209 RINOK(SafeReadDirectByte(inStream
, &version
));
1210 if (version
!= k7zMajorVersion
)
1211 return SZE_ARCHIVE_ERROR
;
1212 RINOK(SafeReadDirectByte(inStream
, &version
));
1214 RINOK(SafeReadDirectUInt32(inStream
, &crcFromArchive
));
1217 RINOK(SafeReadDirectUInt64(inStream
, &nextHeaderOffset
));
1218 CrcUpdateUInt64(&crc
, nextHeaderOffset
);
1219 RINOK(SafeReadDirectUInt64(inStream
, &nextHeaderSize
));
1220 CrcUpdateUInt64(&crc
, nextHeaderSize
);
1221 RINOK(SafeReadDirectUInt32(inStream
, &nextHeaderCRC
));
1222 CrcUpdateUInt32(&crc
, nextHeaderCRC
);
1224 pos
= k7zStartHeaderSize
;
1225 db
->ArchiveInfo
.StartPositionAfterHeader
= pos
;
1227 if (CrcGetDigest(&crc
) != crcFromArchive
)
1228 return SZE_ARCHIVE_ERROR
;
1230 if (nextHeaderSize
== 0)
1233 RINOK(inStream
->Seek(inStream
, (CFileSize
)(pos
+ nextHeaderOffset
)));
1235 if (!SzByteBufferCreate(&buffer
, (size_t)nextHeaderSize
, allocTemp
->Alloc
))
1236 return SZE_OUTOFMEMORY
;
1238 res
= SafeReadDirect(inStream
, buffer
.Items
, (size_t)nextHeaderSize
);
1241 if (CrcVerifyDigest(nextHeaderCRC
, buffer
.Items
, (UInt32
)nextHeaderSize
))
1246 sd
.Data
= buffer
.Items
;
1247 sd
.Size
= buffer
.Capacity
;
1248 res
= SzReadID(&sd
, &type
);
1251 if (type
== k7zIdHeader
)
1253 res
= SzReadHeader(&sd
, db
, allocMain
, allocTemp
);
1256 if (type
!= k7zIdEncodedHeader
)
1258 res
= SZE_ARCHIVE_ERROR
;
1262 CSzByteBuffer outBuffer
;
1263 res
= SzReadAndDecodePackedStreams(inStream
, &sd
, &outBuffer
,
1264 db
->ArchiveInfo
.StartPositionAfterHeader
,
1268 SzByteBufferFree(&outBuffer
, allocTemp
->Free
);
1271 SzByteBufferFree(&buffer
, allocTemp
->Free
);
1272 buffer
.Items
= outBuffer
.Items
;
1273 buffer
.Capacity
= outBuffer
.Capacity
;
1278 SzByteBufferFree(&buffer
, allocTemp
->Free
);
1282 SZ_RESULT
SzArchiveOpen(
1283 ISzInStream
*inStream
,
1284 CArchiveDatabaseEx
*db
,
1285 ISzAlloc
*allocMain
,
1286 ISzAlloc
*allocTemp
)
1288 SZ_RESULT res
= SzArchiveOpen2(inStream
, db
, allocMain
, allocTemp
);
1290 SzArDbExFree(db
, allocMain
->Free
);