unit SevenZip; interface uses KOL; const //Property IDs kEnd = $00; kHeader = $01; kArchiveProperties = $02; kAdditionalStreamsInfo = $03; kMainStreamsInfo = $04; kFilesInfo = $05; kPackInfo = $06; kUnPackInfo = $07; kSubStreamsInfo = $08; kSize = $09; kCRC = $0A; kFolder = $0B; kCodersUnPackSize = $0C; kNumUnPackStream = $0D; kEmptyStream = $0E; kEmptyFile = $0F; kAnti = $10; kName = $11; kCreationTime = $12; kLastAccessTime = $13; kLastWriteTime = $14; kWinAttributes = $15; kComment = $16; kEncodedHeader = $17; const kSignature: array [0..5] of Char = ('7', 'z', #$BC, #$AF, #$27, #$1C); type //7z format headers REAL_UINT64 = Int64; TArchiveVersion = packed record Major: Byte; // now = 0 Minor: Byte; // now = 2 end; TStartHeader = packed record NextHeaderOffset: REAL_UINT64; NextHeaderSize: REAL_UINT64; NextHeaderCRC: Cardinal; end; TSignatureHeader = packed record ArchiveVersion: TArchiveVersion; StartHeaderCRC: Cardinal; StartHeader: TStartHeader; end; PUInt32 = ^UInt32; UInt32 = Cardinal; PUInt64 = ^UInt64; UInt64 = Int64; CFileSize = UInt64; PCFileSize = PUInt64; CMethodID= UInt64; CSzByteBuffer = packed record Capacity: Cardinal; Items: PByte; end; PCCoderInfo = ^CCoderInfo; CCoderInfo = packed record NumInStreams: UInt32; NumOutStreams: UInt32; MethodID: CMethodID; Properties: CSzByteBuffer; end; PCBindPair = ^CBindPair; CBindPair = packed record InIndex: UInt32; OutIndex: UInt32; end; PCFolder = ^CFolder; CFolder = packed record NumCoders: UInt32; Coders: PCCoderInfo; NumBindPairs: UInt32; BindPairs: PCBindPair; NumPackStreams: UInt32; PackStreams: UInt32; UnPackSizes: PCFileSize; UnPackCRCDefined: Integer ; UnPackCRC: UInt32; NumUnPackStreams: UInt32; end; CArchiveFileTime = packed record Low:UInt32; High:UInt32; end; PCFileItem = ^CFileItem; CFileItem = packed record LastWriteTime: CArchiveFileTime; { CFileSize StartPos; UInt32 Attributes; } Size: CFileSize; FileCRC: UInt32; Name: PChar; IsFileCRCDefined: Byte; HasStream: Byte; IsDirectory: Byte; IsAnti: Byte; IsLastWriteTimeDefined: Byte; { int AreAttributesDefined; int IsLastWriteTimeDefined; int IsStartPosDefined; } end; CArchiveDatabase = packed record NumPackStreams: UInt32; PackSizes: PCFileSize; PackCRCsDefined: PByte; PackCRCs: PUInt32; NumFolders: PUInt32; Folders: PCFolder; NumFiles:UInt32; Files: PCFileItem; end; CInArchiveInfo = packed record StartPositionAfterHeader: CFileSize; DataStartPosition: CFileSize; end; PCArchiveDatabaseEx= ^CArchiveDatabaseEx; CArchiveDatabaseEx = packed record Database: CArchiveDatabase; ArchiveInfo: CInArchiveInfo; FolderStartPackStreamIndex: PUInt32; PackStreamStartPositions: PCFileSize; FolderStartFileIndex: PUInt32; FileIndexToFolderIndexMap: PUInt32; end; CSzData = packed record Data: PByte; Size: UInt32; end; type SZ_RESULT = Integer; const k7zMajorVersion = 0; k7zStartHeaderSize = $20; function SzArchiveOpen2: SZ_RESULT; implementation function SzArchiveOpen2: SZ_RESULT; var db: CArchiveDatabaseEx; InStream: PStream; signature: array [0..5] of Char; version: Byte; crcFromArchive: UInt32; nextHeaderOffset: UInt64; nextHeaderSize: UInt64; nextHeaderCRC: UInt32; crc: UInt32; pos: CFileSize; buffer: CSzByteBuffer; sd: CSzData; _type: UInt64; begin crc:= 0; pos:= 0; InStream:= NewReadFileStream('D:\Work\Main\MDVReader\CE\_Books\_Books.7z'); if InStream.Read(signature, 6) <> 6 then Exit; if signature <> kSignature then Exit; { db.Clear(); db.ArchiveInfo.StartPosition = _arhiveBeginStreamPosition; } if InStream.Read(version, 1) <> 1 then Exit; if version <> k7zMajorVersion then Exit; if InStream.Read(version, 1) <> 1 then Exit; if InStream.Read(crcFromArchive, SizeOf(UInt32)) <> SizeOf(UInt32) then Exit; //RINOK(SafeReadDirectUInt32(inStream, &crcFromArchive, &crc)); // crc:= CRC_INIT_VAL; if InStream.Read(nextHeaderOffset, SizeOf(UInt64)) <> SizeOf(UInt64) then Exit; //RINOK(SafeReadDirectUInt64(inStream, &nextHeaderOffset, &crc)); if InStream.Read(nextHeaderSize, SizeOf(UInt64)) <> SizeOf(UInt64) then Exit; //RINOK(SafeReadDirectUInt64(inStream, &nextHeaderSize, &crc)); if InStream.Read(nextHeaderCRC, SizeOf(UInt32)) <> SizeOf(UInt32) then Exit; //RINOK(SafeReadDirectUInt32(inStream, &nextHeaderCRC, &crc)); pos:= k7zStartHeaderSize; db.ArchiveInfo.StartPositionAfterHeader:= pos; //if (CRC_GET_DIGEST(crc) != crcFromArchive) return SZE_ARCHIVE_ERROR; if nextHeaderSize = 0 then begin Result:= 0; Exit; end; InStream.Seek(pos + nextHeaderOffset, spBegin); buffer.Capacity:= nextHeaderSize; buffer.Items:= GetMemory(nextHeaderSize); if InStream.Read(buffer.Items, nextHeaderSize) <> nextHeaderSize then Exit; //Result:= SafeReadDirect(inStream, buffer.Items, (size_t)nextHeaderSize); (* // if (CrcCalc(buffer.Items, (UInt32)nextHeaderSize) == nextHeaderCRC) then begin while true do begin sd.Data:= buffer.Items; sd.Size:= buffer.Capacity; Result:= SzReadID(&sd, &type); if (res != SZ_OK) break; if (type == k7zIdHeader) { res = SzReadHeader(&sd, db, allocMain, allocTemp); break; } if (type != k7zIdEncodedHeader) { res = SZE_ARCHIVE_ERROR; break; } { CSzByteBuffer outBuffer; res = SzReadAndDecodePackedStreams(inStream, &sd, &outBuffer, db->ArchiveInfo.StartPositionAfterHeader, allocTemp); if (res != SZ_OK) { SzByteBufferFree(&outBuffer, allocTemp->Free); break; } SzByteBufferFree(&buffer, allocTemp->Free); buffer.Items = outBuffer.Items; buffer.Capacity = outBuffer.Capacity; } end; // end; SzByteBufferFree(&buffer, allocTemp->Free); return res; *) end; (* 7z Format description (2.30 Beta 25) ----------------------------------- This file contains description of 7z archive format. 7z archive can contain files compressed with any method. See "Methods.txt" for description for defined compressing methods. Format structure Overview ------------------------- Some fields can be optional. Archive structure ~~~~~~~~~~~~~~~~~ SignatureHeader [PackedStreams] [PackedStreamsForHeaders] [ Header or { Packed Header HeaderInfo } ] Header structure ~~~~~~~~~~~~~~~~ { ArchiveProperties AdditionalStreams { PackInfo { PackPos NumPackStreams Sizes[NumPackStreams] CRCs[NumPackStreams] } CodersInfo { NumFolders Folders[NumFolders] { NumCoders CodersInfo[NumCoders] { ID NumInStreams; NumOutStreams; PropertiesSize Properties[PropertiesSize] } NumBindPairs BindPairsInfo[NumBindPairs] { InIndex; OutIndex; } PackedIndices } UnPackSize[Folders][Folders.NumOutstreams] CRCs[NumFolders] } SubStreamsInfo { NumUnPackStreamsInFolders[NumFolders]; UnPackSizes[] CRCs[] } } MainStreamsInfo { (Same as in AdditionalStreams) } FilesInfo { NumFiles Properties[] { ID Size Data } } } HeaderInfo structure ~~~~~~~~~~~~~~~~~~~~ { (Same as in AdditionalStreams) } Notes about Notation and encoding --------------------------------- 7z uses little endian encoding. 7z archive format has optional headers that are marked as [] Header [] REAL_UINT64 means real UINT64. UINT64 means real UINT64 encoded with the following scheme: Size of encoding sequence depends from first byte: First_Byte Extra_Bytes Value (binary) 0xxxxxxx : ( xxxxxxx ) 10xxxxxx BYTE y[1] : ( xxxxxx << (8 * 1)) + y 110xxxxx BYTE y[2] : ( xxxxx << (8 * 2)) + y ... 1111110x BYTE y[6] : ( x << (8 * 6)) + y 11111110 BYTE y[7] : y 11111111 BYTE y[8] : y ........................... ArchiveProperties ~~~~~~~~~~~~~~~~~ BYTE NID::kArchiveProperties (0x02) while(true) { BYTE PropertyType; if (aType == 0) break; UINT64 PropertySize; BYTE PropertyData[PropertySize]; } Digests (NumStreams) ~~~~~~~~~~~~~~~~~~~~~ BYTE AllAreDefined if (AllAreDefined == 0) { for(NumStreams) BIT Defined } UINT32 CRCs[NumDefined] PackInfo ~~~~~~~~~~~~ BYTE NID::kPackInfo (0x06) UINT64 PackPos UINT64 NumPackStreams [] BYTE NID::kSize (0x09) UINT64 PackSizes[NumPackStreams] [] [] BYTE NID::kCRC (0x0A) PackStreamDigests[NumPackStreams] [] BYTE NID::kEnd Folder ~~~~~~ UINT64 NumCoders; for (NumCoders) { BYTE { 0:3 DecompressionMethod.IDSize 4: 0 - IsSimple 1 - Is not simple 5: 0 - No Attributes 1 - There Are Attributes 7: 0 - Last Method in Alternative_Method_List 1 - There are more alternative methods } BYTE DecompressionMethod.ID[DecompressionMethod.IDSize] if (!IsSimple) { UINT64 NumInStreams; UINT64 NumOutStreams; } if (DecompressionMethod[0] != 0) { UINT64 PropertiesSize BYTE Properties[PropertiesSize] } } NumBindPairs = NumOutStreamsTotal - 1; for (NumBindPairs) { UINT64 InIndex; UINT64 OutIndex; } NumPackedStreams = NumInStreamsTotal - NumBindPairs; if (NumPackedStreams > 1) for(NumPackedStreams) { UINT64 Index; }; Coders Info ~~~~~~~~~~~ BYTE NID::kUnPackInfo (0x07) BYTE NID::kFolder (0x0B) UINT64 NumFolders BYTE External switch(External) { case 0: Folders[NumFolders] case 1: UINT64 DataStreamIndex } BYTE ID::kCodersUnPackSize (0x0C) for(Folders) for(Folder.NumOutStreams) UINT64 UnPackSize; [] BYTE NID::kCRC (0x0A) UnPackDigests[NumFolders] [] BYTE NID::kEnd SubStreams Info ~~~~~~~~~~~~~~ BYTE NID::kSubStreamsInfo; (0x08) [] BYTE NID::kNumUnPackStream; (0x0D) UINT64 NumUnPackStreamsInFolders[NumFolders]; [] [] BYTE NID::kSize (0x09) UINT64 UnPackSizes[] [] [] BYTE NID::kCRC (0x0A) Digests[Number of streams with unknown CRC] [] BYTE NID::kEnd Streams Info ~~~~~~~~~~~~ [] PackInfo [] [] CodersInfo [] [] SubStreamsInfo [] BYTE NID::kEnd FilesInfo ~~~~~~~~~ BYTE NID::kFilesInfo; (0x05) UINT64 NumFiles while(true) { BYTE PropertyType; if (aType == 0) break; UINT64 Size; switch(PropertyType) { kEmptyStream: (0x0E) for(NumFiles) BIT IsEmptyStream kEmptyFile: (0x0F) for(EmptyStreams) BIT IsEmptyFile kAnti: (0x10) for(EmptyStreams) BIT IsAntiFile case kCreationTime: (0x12) case kLastAccessTime: (0x13) case kLastWriteTime: (0x14) BYTE AllAreDefined if (AllAreDefined == 0) { for(NumFiles) BIT TimeDefined } BYTE External; if(External != 0) UINT64 DataIndex [] for(Definded Items) UINT32 Time [] kNames: (0x11) BYTE External; if(External != 0) UINT64 DataIndex [] for(Files) { wchar_t Names[NameSize]; wchar_t 0; } [] kAttributes: (0x15) BYTE AllAreDefined if (AllAreDefined == 0) { for(NumFiles) BIT AttributesAreDefined } BYTE External; if(External != 0) UINT64 DataIndex [] for(Definded Attributes) UINT32 Attributes [] } } Header ~~~~~~ BYTE NID::kHeader (0x01) [] ArchiveProperties [] [] BYTE NID::kAdditionalStreamsInfo; (0x03) StreamsInfo [] [] BYTE NID::kMainStreamsInfo; (0x04) StreamsInfo [] [] FilesInfo [] BYTE NID::kEnd HeaderInfo ~~~~~~~~~~ [] BYTE NID::kEncodedHeader; (0x17) StreamsInfo for Encoded Header [] --- End of document *) end.