질문에서 winrar등에서 만들어진 zip파일에서 안되는 것을 보고 패치를 했습니다.
FPC의 packages의 paszlib의 zipper.pp의 내용을 고친 것입니다.
(수정) 파일명으로 할당하는 부분에 대한 추가적인 코드 추가.
Index: packages/paszlib/src/zipper.pp
===================================================================
--- packages/paszlib/src/zipper.pp (revision 29277)
+++ packages/paszlib/src/zipper.pp (working copy)
@@ -32,6 +32,8 @@
LOCAL_FILE_HEADER_SIGNATURE = $04034B50;
CENTRAL_FILE_HEADER_SIGNATURE = $02014B50;
ZIP64_HEADER_ID = $0001;
+ // infozip unicode path
+ INFOZIP_UNICODE_PATH_ID = $7075;
Type
Local_File_Header_Type = Packed Record //1 per zipped file
@@ -757,6 +759,17 @@
Result := Result or UNIX_FILE;
end;
+function CRC32Str(const s:string):DWord;
+var
+ i:Integer;
+begin
+ Result:=$FFFFFFFF;
+ if Length(S)>0 then
+ for i:=1 to Length(s) do
+ Result:=Crc_32_Tab[Byte(Result XOR LongInt(s[i]))] XOR ((Result SHR 8) AND $00FFFFFF);
+ Result:=not Result;
+end;
+
{ ---------------------------------------------------------------------
TDeCompressor
---------------------------------------------------------------------}
@@ -2031,6 +2044,9 @@
D : TDateTime;
ExtraFieldHdr: Extensible_Data_Field_Header_Type;
SavePos: int64; //could be qword but limited by stream
+ // Infozip unicode path
+ Infozip_Unicode_Path_Ver:Byte;
+ Infozip_Unicode_Path_CRC32:DWord;
Begin
FZipStream.Seek(Item.HdrPos,soBeginning);
FZipStream.ReadBuffer(LocalHdr,SizeOf(LocalHdr));
@@ -2048,7 +2064,7 @@
if Extra_Field_Length>0 then
begin
SavePos := FZipStream.Position;
- if (LocalHdr.Extra_Field_Length>=SizeOf(ExtraFieldHdr)+SizeOf(LocalZip64Fld)) then
+ if (LocalHdr.Extra_Field_Length>=SizeOf(ExtraFieldHdr)) then
while FZipStream.Position=20701}
+ if DefaultSystemCodePage<>CP_UTF8 then
+ Item.ArchiveFileName:=Utf8ToAnsi(S)
+ else
+ Item.ArchiveFileName:=S;
+ if DefaultRTLFileSystemCodePage<>CP_UTF8 then
+ Item.DiskFileName:=Utf8ToAnsi(S)
+ else
+ Item.DiskFileName:=S;
+ {$ELSE}
+ Item.ArchiveFileName:=Utf8ToAnsi(S);
+ Item.DiskFileName:=Utf8ToAnsi(S);
+ {$ENDIF}
+ end else
+ FZipStream.Seek(ExtraFieldHdr.Data_Size-5,soFromCurrent);
+ end else
+ FZipStream.Seek(ExtraFieldHdr.Data_Size-1,soFromCurrent);
+ end else
+ FZipStream.Seek(ExtraFieldHdr.Data_Size,soFromCurrent);
end;
// Move past extra fields
FZipStream.Seek(SavePos+Extra_Field_Length,soFromBeginning);
@@ -2229,6 +2276,9 @@
NewNode : TFullZipFileEntry;
D : TDateTime;
S : String;
+ // infozip unicode path
+ Infozip_unicode_path_ver : byte; // always 1
+ Infozip_unicode_path_crc32 : DWord;
Begin
FindEndHeaders(EndHdr, EndHdrPos,
EndZip64Hdr, EndZip64HdrPos);
@@ -2319,6 +2369,31 @@
NewNode.HdrPos := Zip64Field.Relative_Hdr_Offset;
end;
end
+ // infozip unicode path extra field
+ else if ExtraFieldHeader.Header_ID = INFOZIP_UNICODE_PATH_ID then
+ begin
+ FZipStream.ReadBuffer(Infozip_unicode_path_ver,1);
+ if Infozip_unicode_path_ver=1 then begin
+ FZipStream.ReadBuffer(Infozip_unicode_path_crc32,sizeof(Infozip_unicode_path_crc32));
+ {$IFDEF FPC_BIG_ENDIAN}
+ Infozip_unicode_path_crc32:=SwapEndian(Infozip_unicode_path_crc32);
+ {$ENDIF}
+ if CRC32Str(S)=Infozip_unicode_path_crc32 then begin
+ SetLength(S,ExtraFieldHeader.Data_Size-5);
+ FZipStream.ReadBuffer(S[1],Length(S));
+ {$if FPC_FULLVERSION>=20701}
+ if DefaultSystemCodePage<>CP_UTF8 then
+ NewNode.ArchiveFileName:=Utf8ToAnsi(S)
+ else
+ NewNode.ArchiveFileName:=S;
+ {$ELSE}
+ NewNode.ArchiveFileName:=Utf8ToAnsi(S);
+ {$ENDIF}
+ end else
+ FZipStream.Seek(ExtraFieldHeader.Data_Size-5,soFromCurrent);
+ end else
+ FZipStream.Seek(ExtraFieldHeader.Data_Size-1,soFromCurrent);
+ end
else
begin
// Read past non-Zip64 extra field
참고하시기를~
|