2023-02-02 12:02:14 +03:00

556 lines
17 KiB
ObjectPascal

////////////////////////////////////////////////////////////////////////////////
//
// ****************************************************************************
// * Project : FWZip - ZipAnalizer2
// * Unit Name : uZipAnalizer2
// * Purpose : Âûâîä ïàðàìåòðîâ àðõèâà ïðè ïîìîùè ïîèñêà ñèãíàòóð
// * Author : Àëåêñàíäð (Rouse_) Áàãåëü
// * Copyright : © Fangorn Wizards Lab 1998 - 2013.
// * Version : 1.0.10
// * Home Page : http://rouse.drkb.ru
// * Home Blog : http://alexander-bagel.blogspot.ru
// ****************************************************************************
// * Stable Release : http://rouse.drkb.ru/components.php#fwzip
// * Latest Source : https://github.com/AlexanderBagel/FWZip
// ****************************************************************************
//
// Èñïîëüçóåìûå èñòî÷íèêè:
// ftp://ftp.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip
// http://zlib.net/zlib-1.2.5.tar.gz
// http://www.base2ti.com/
//
unit uZipAnalizer2;
interface
uses
Windows, Messages, SysUtils, Classes, Controls, Forms,
Dialogs, StdCtrls, ComCtrls, ExtCtrls, Menus,
FWZipConsts;
type
TdlgZipAnalizer = class(TForm)
edPath: TLabeledEdit;
btnBrowse: TButton;
btnAnalize: TButton;
GroupBox: TGroupBox;
edReport: TRichEdit;
OpenDialog: TOpenDialog;
PopupMenu: TPopupMenu;
mnuSave: TMenuItem;
SaveDialog: TSaveDialog;
procedure btnBrowseClick(Sender: TObject);
procedure edPathChange(Sender: TObject);
procedure btnAnalizeClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure mnuSaveClick(Sender: TObject);
procedure PopupMenuPopup(Sender: TObject);
private
procedure Log(const Value: string);
procedure Scan(const Value: string);
function FindSing(Stream: TStream): DWORD;
procedure ShowLocalFileHeader(Stream: TStream);
procedure ShowDataDescryptor(Stream: TStream);
procedure ShowCentralFileHeader(Stream: TStream);
procedure ShowExtraFields(Stream: TStream; Size: Integer;
FileHeader: TCentralDirectoryFileHeader);
procedure ShowZip64(Stream: TStream);
procedure ShowZip64Locator(Stream: TStream);
procedure ShowEndOfCentralDir(Stream: TStream);
procedure LoadStringValue(Stream: TStream; var Value: string;
nSize: Cardinal; UTF: Boolean);
end;
var
dlgZipAnalizer: TdlgZipAnalizer;
implementation
const
Delim = '===================================================================';
{$R *.dfm}
function GPBFToStr(Value: Word): string;
procedure AddValue(const S: string);
begin
if Result = '' then
Result := S
else
Result := Result + ', ' + S;
end;
begin
if Value = 0 then
begin
Result := 'EMPTY';
Exit;
end;
if PBF_CRYPTED and Value <> 0 then
AddValue('PBF_CRYPTED');
if PBF_DESCRIPTOR and Value <> 0 then
AddValue('PBF_DESCRIPTOR');
if PBF_UTF8 and Value <> 0 then
AddValue('PBF_UTF8');
if PBF_STRONG_CRYPT and Value <> 0 then
AddValue('PBF_STRONG_CRYPT');
end;
procedure TdlgZipAnalizer.btnAnalizeClick(Sender: TObject);
begin
edReport.Lines.BeginUpdate;
try
edReport.Clear;
Log(edPath.Text);
Log(Delim);
Scan(edPath.Text);
Log('DONE');
finally
edReport.Lines.EndUpdate;
end;
end;
procedure TdlgZipAnalizer.btnBrowseClick(Sender: TObject);
begin
if OpenDialog.Execute then
begin
edPath.Text := OpenDialog.FileName;
edReport.Clear;
end;
end;
procedure TdlgZipAnalizer.edPathChange(Sender: TObject);
begin
btnAnalize.Enabled := FileExists(edPath.Text);
end;
function TdlgZipAnalizer.FindSing(Stream: TStream): DWORD;
const
KnownSigns: array [0..5] of DWORD = (
LOCAL_FILE_HEADER_SIGNATURE,
DATA_DESCRIPTOR_SIGNATURE,
CENTRAL_FILE_HEADER_SIGNATURE,
ZIP64_END_OF_CENTRAL_DIR_SIGNATURE,
ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE,
END_OF_CENTRAL_DIR_SIGNATURE
);
function CalcLen: Integer;
begin
Result := Stream.Size - Stream.Position;
if Result > 1024 then
Result := 1024;
end;
var
pBuff, pCursor: PByte;
I, A, Len: Integer;
OldPosition: Int64;
begin
Result := 0;
GetMem(pBuff, 1024);
try
Len := CalcLen;
while (Result = 0) and (Len > 4) do
begin
OldPosition := Stream.Position;
Stream.ReadBuffer(pBuff^, Len);
pCursor := pBuff;
for I := 0 to Len - 4 do
begin
for A := 0 to 5 do
if PDWORD(pCursor)^ = KnownSigns[A] then
begin
Result := KnownSigns[A];
Break;
end;
if Result = 0 then
Inc(pCursor)
else
begin
Stream.Position := OldPosition + I;
Break;
end;
end;
if Result = 0 then
begin
Len := CalcLen;
if Len > 0 then
Stream.Position := Stream.Position - 4;
end;
end;
finally
FreeMem(pBuff);
end;
end;
procedure TdlgZipAnalizer.FormCreate(Sender: TObject);
begin
edReport.PlainText := True;
end;
procedure TdlgZipAnalizer.LoadStringValue(Stream: TStream;
var Value: string; nSize: Cardinal; UTF: Boolean);
var
aString: AnsiString;
begin
if Integer(nSize) > 0 then
begin
SetLength(aString, nSize);
Stream.ReadBuffer(aString[1], nSize);
if UTF then
begin
{$IFDEF UNICODE}
Value := string(UTF8ToUnicodeString(aString))
{$ELSE}
Value := string(UTF8Decode(aString));
Value := StringReplace(Value, '?', '_', [rfReplaceAll]);
{$ENDIF}
end
else
begin
OemToAnsi(@aString[1], @aString[1]);
Value := string(aString);
end;
end;
end;
procedure TdlgZipAnalizer.Log(const Value: string);
begin
edReport.Lines.Add(Value);
end;
procedure TdlgZipAnalizer.mnuSaveClick(Sender: TObject);
begin
if SaveDialog.Execute then
edReport.Lines.SaveToFile(SaveDialog.FileName);
end;
procedure TdlgZipAnalizer.PopupMenuPopup(Sender: TObject);
begin
mnuSave.Enabled := edReport.Lines.Count > 1;
end;
procedure TdlgZipAnalizer.Scan(const Value: string);
var
F: TFileStream;
Sign: DWORD;
begin
F := TFileStream.Create(Value, fmOpenRead or fmShareDenyWrite);
try
Sign := FindSing(F);
while Sign <> 0 do
begin
case Sign of
LOCAL_FILE_HEADER_SIGNATURE: ShowLocalFileHeader(F);
DATA_DESCRIPTOR_SIGNATURE: ShowDataDescryptor(F);
CENTRAL_FILE_HEADER_SIGNATURE: ShowCentralFileHeader(F);
ZIP64_END_OF_CENTRAL_DIR_SIGNATURE: ShowZip64(F);
ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE: ShowZip64Locator(F);
END_OF_CENTRAL_DIR_SIGNATURE: ShowEndOfCentralDir(F);
end;
Sign := FindSing(F);
end;
finally
F.Free;
end;
end;
procedure TdlgZipAnalizer.ShowCentralFileHeader(Stream: TStream);
var
Data: TCentralDirectoryFileHeader;
FileName, Comment: string;
begin
Log('CENTRAL_FILE_HEADER_SIGNATURE found at offset: ' + IntToStr(Stream.Position));
Stream.ReadBuffer(Data, SizeOf(TCentralDirectoryFileHeader));
with Data do
begin
if CentralFileHeaderSignature <> CENTRAL_FILE_HEADER_SIGNATURE then
Log('INVALID SIGNATURE!!!!');
Log(Format('VersionMadeBy: %d', [VersionMadeBy]));
Log(Format('VersionNeededToExtract: %d', [VersionNeededToExtract]));
Log(Format('GeneralPurposeBitFlag: %d (%s)', [GeneralPurposeBitFlag,
GPBFToStr(GeneralPurposeBitFlag)]));
Log(Format('CompressionMethod: %d', [CompressionMethod]));
Log(Format('LastModFileTimeTime: %d', [LastModFileTimeTime]));
Log(Format('LastModFileTimeDate: %d', [LastModFileTimeDate]));
Log(Format('Crc32: %d', [Crc32]));
Log(Format('CompressedSize: %d', [CompressedSize]));
Log(Format('UncompressedSize: %d', [UncompressedSize]));
Log(Format('FilenameLength: %d', [FilenameLength]));
Log(Format('ExtraFieldLength: %d', [ExtraFieldLength]));
Log(Format('FileCommentLength: %d', [FileCommentLength]));
Log(Format('DiskNumberStart: %d', [DiskNumberStart]));
Log(Format('InternalFileAttributes: %d', [InternalFileAttributes]));
Log(Format('ExternalFileAttributes: %d', [ExternalFileAttributes]));
Log(Format('RelativeOffsetOfLocalHeader: %d', [RelativeOffsetOfLocalHeader]));
LoadStringValue(Stream, FileName, FilenameLength,
GeneralPurposeBitFlag and PBF_UTF8 <> 0);
Log('>>> FileName: ' + FileName);
Log(Delim);
ShowExtraFields(Stream, ExtraFieldLength, Data);
if FileCommentLength > 0 then
begin
LoadStringValue(Stream, Comment, FileCommentLength,
GeneralPurposeBitFlag and PBF_UTF8 <> 0);
Log('>>> FileComment: ' + Comment);
Log(Delim);
end;
end;
end;
procedure TdlgZipAnalizer.ShowDataDescryptor(Stream: TStream);
var
Data: TDataDescriptor;
begin
Log('DATA_DESCRIPTOR_SIGNATURE found at offset: ' + IntToStr(Stream.Position));
Stream.ReadBuffer(Data, SizeOf(TDataDescriptor));
with Data do
begin
if DescriptorSignature <> DATA_DESCRIPTOR_SIGNATURE then
Log('INVALID SIGNATURE!!!!');
Log(Format('Crc32: %d', [Crc32]));
Log(Format('CompressedSize: %d', [CompressedSize]));
Log(Format('UncompressedSize: %d', [UncompressedSize]));
end;
Log(Delim);
end;
procedure TdlgZipAnalizer.ShowEndOfCentralDir(Stream: TStream);
var
Data: TEndOfCentralDir;
Comment: string;
begin
Log('END_OF_CENTRAL_DIR_SIGNATURE found at offset: ' + IntToStr(Stream.Position));
Stream.ReadBuffer(Data, SizeOf(TEndOfCentralDir));
with Data do
begin
if EndOfCentralDirSignature <> END_OF_CENTRAL_DIR_SIGNATURE then
Log('INVALID SIGNATURE!!!!');
Log(Format('NumberOfThisDisk: %d', [NumberOfThisDisk]));
Log(Format('NumberOfTheDiskWithTheStart: %d', [NumberOfTheDiskWithTheStart]));
Log(Format('TotalNumberOfEntriesOnThisDisk: %d', [TotalNumberOfEntriesOnThisDisk]));
Log(Format('TotalNumberOfEntries: %d', [TotalNumberOfEntries]));
Log(Format('SizeOfTheCentralDirectory: %d', [SizeOfTheCentralDirectory]));
Log(Format('OffsetOfStartOfCentralDirectory: %d', [OffsetOfStartOfCentralDirectory]));
Log(Format('ZipfileCommentLength: %d', [ZipfileCommentLength]));
if ZipfileCommentLength > 0 then
begin
LoadStringValue(Stream, Comment, ZipfileCommentLength, False);
Log(Format('>>> Comment: %s', [Comment]));
end;
end;
Log(Delim);
end;
procedure TdlgZipAnalizer.ShowExtraFields(Stream: TStream; Size: Integer;
FileHeader: TCentralDirectoryFileHeader);
var
Buff, EOFBuff: Pointer;
BuffCount: Integer;
HeaderID, BlockSize: Word;
function GetOffset(Value: Integer): Pointer;
begin
Result := Pointer(Integer(EOFBuff) - Value);
end;
function ByteToStr(Bytes: PByte; Size: Integer): string;
const
BytesHex: array[0..15] of char =
('0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F');
var
I: integer;
begin
SetLength(Result, Size shl 1);
for I := 0 to Size - 1 do
begin
Result[I * 2 + 1] := BytesHex[Bytes^ shr 4];
Result[I * 2 + 2] := BytesHex[Bytes^ and $0F];
Inc(Bytes);
end;
end;
var
ExDataStream: TMemoryStream;
StartPos: Int64;
begin
if Size = 0 then Exit;
StartPos := Stream.Position;
Log('EXDATA found at offset: ' + IntToStr(StartPos));
Log(Delim);
GetMem(Buff, Size);
try
BuffCount := Size;
Stream.ReadBuffer(Buff^, BuffCount);
EOFBuff := Pointer(Integer(Buff) + BuffCount);
while BuffCount > 0 do
begin
HeaderID := PWord(GetOffset(BuffCount))^;
Dec(BuffCount, 2);
BlockSize := PWord(GetOffset(BuffCount))^;
Dec(BuffCount, 2);
case HeaderID of
SUPPORTED_EXDATA_ZIP64:
begin
Log('SUPPORTED_EXDATA_ZIP64 found at offset: ' +
IntToStr(StartPos + Size - BuffCount - 4));
if FileHeader.UncompressedSize = MAXDWORD then
begin
if BuffCount < 8 then Break;
Log('UncompressedSize: ' + IntToStr(PInt64(GetOffset(BuffCount))^));
Dec(BuffCount, 8);
Dec(BlockSize, 8);
end;
if FileHeader.CompressedSize = MAXDWORD then
begin
if BuffCount < 8 then Break;
Log('CompressedSize: ' + IntToStr(PInt64(GetOffset(BuffCount))^));
Dec(BuffCount, 8);
Dec(BlockSize, 8);
end;
if FileHeader.RelativeOffsetOfLocalHeader = MAXDWORD then
begin
if BuffCount < 8 then Break;
Log('RelativeOffsetOfLocalHeader: ' + IntToStr(PInt64(GetOffset(BuffCount))^));
Dec(BuffCount, 8);
Dec(BlockSize, 8);
end;
if FileHeader.DiskNumberStart = MAXWORD then
begin
if BuffCount < 4 then Break;
Log('DiskNumberStart: ' + IntToStr(PInt64(GetOffset(BuffCount))^));
Dec(BuffCount, 4);
Dec(BlockSize, 4);
end;
Dec(BuffCount, BlockSize);
Log(Delim);
end;
SUPPORTED_EXDATA_NTFSTIME:
begin
if BuffCount < 32 then Break;
if BlockSize <> 32 then
begin
Dec(BuffCount, BlockSize);
Continue;
end;
Dec(BuffCount, 4);
if PWord(GetOffset(BuffCount))^ <> 1 then
begin
Dec(BuffCount, BlockSize);
Continue;
end;
Dec(BuffCount, 2);
if PWord(GetOffset(BuffCount))^ <> SizeOf(TNTFSFileTime) then
begin
Dec(BuffCount, BlockSize);
Continue;
end;
Dec(BuffCount, 2);
Log('SUPPORTED_EXDATA_NTFSTIME found at offset: ' +
IntToStr(StartPos + Size - BuffCount - 12));
Log(Delim);
end;
else
Log(Format('UNKNOWN EXDATA TAG %d found at offset: %d',
[HeaderID, StartPos + Size - BuffCount - 8]));
ExDataStream := TMemoryStream.Create;
try
ExDataStream.WriteBuffer(GetOffset(BuffCount)^, BlockSize);
ExDataStream.Position := 0;
Log(ByteToStr(ExDataStream.Memory, ExDataStream.Size));
finally
ExDataStream.Free;
end;
Log(Delim);
end;
Dec(BuffCount, BlockSize);
end;
finally
FreeMem(Buff);
end;
end;
procedure TdlgZipAnalizer.ShowLocalFileHeader(Stream: TStream);
var
Data: TLocalFileHeader;
FileName: string;
begin
Log('LOCAL_FILE_HEADER_SIGNATURE found at offset: ' + IntToStr(Stream.Position));
Stream.ReadBuffer(Data, SizeOf(TLocalFileHeader));
with Data do
begin
if LocalFileHeaderSignature <> LOCAL_FILE_HEADER_SIGNATURE then
Log('INVALID SIGNATURE!!!!');
Log(Format('VersionNeededToExtract: %d', [VersionNeededToExtract]));
Log(Format('GeneralPurposeBitFlag: %d (%s)', [GeneralPurposeBitFlag,
GPBFToStr(GeneralPurposeBitFlag)]));
Log(Format('CompressionMethod: %d', [CompressionMethod]));
Log(Format('LastModFileTimeTime: %d', [LastModFileTimeTime]));
Log(Format('LastModFileTimeDate: %d', [LastModFileTimeDate]));
Log(Format('Crc32: %d', [Crc32]));
Log(Format('CompressedSize: %d', [CompressedSize]));
Log(Format('UncompressedSize: %d', [UncompressedSize]));
Log(Format('FilenameLength: %d', [FilenameLength]));
Log(Format('ExtraFieldLength: %d', [ExtraFieldLength]));
LoadStringValue(Stream, FileName, FilenameLength,
GeneralPurposeBitFlag and PBF_UTF8 <> 0);
Log('>>> FileName: ' + FileName);
//Stream.Position := Stream.Position + CompressedSize;
end;
Log(Delim);
end;
procedure TdlgZipAnalizer.ShowZip64(Stream: TStream);
var
Data: TZip64EOFCentralDirectoryRecord;
begin
Log('ZIP64_END_OF_CENTRAL_DIR_SIGNATURE found at offset: ' + IntToStr(Stream.Position));
Stream.ReadBuffer(Data, SizeOf(TZip64EOFCentralDirectoryRecord));
with Data do
begin
if Zip64EndOfCentralDirSignature <> ZIP64_END_OF_CENTRAL_DIR_SIGNATURE then
Log('INVALID SIGNATURE!!!!');
Log(Format('SizeOfZip64EOFCentralDirectoryRecord: %d', [SizeOfZip64EOFCentralDirectoryRecord]));
Log(Format('VersionMadeBy: %d', [VersionMadeBy]));
Log(Format('VersionNeededToExtract: %d', [VersionNeededToExtract]));
Log(Format('number of this disk: %d', [Number1]));
Log(Format('number of the disk with the start of the central directory: %d', [Number2]));
Log(Format('total number of entries in the central directory on this disk: %d', [TotalNumber1]));
Log(Format('total number of entries in the central directory: %d', [TotalNumber2]));
Log(Format('size of the central directory: %d', [Size]));
Log(Format('offset of start of central directory with respect to the starting disk number: %d', [Offset]));
end;
Log(Delim);
end;
procedure TdlgZipAnalizer.ShowZip64Locator(Stream: TStream);
var
Data: TZip64EOFCentralDirectoryLocator;
begin
Log('ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE found at offset: ' + IntToStr(Stream.Position));
Stream.ReadBuffer(Data, SizeOf(TZip64EOFCentralDirectoryLocator));
with Data do
begin
if Signature <> ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIGNATURE then
Log('INVALID SIGNATURE!!!!');
Log(Format('NumberOfTheDisk: %d', [NumberOfTheDisk]));
Log(Format('RelativeOffset: %d', [RelativeOffset]));
Log(Format('TotalNumberOfDisks: %d', [TotalNumberOfDisks]));
end;
Log(Delim);
end;
end.