ZipPacker violates zip-spec and cannot uncomp. windows zip

Got an idea for enhancing PureBasic? New command(s) you'd like to see?
nalor
Enthusiast
Enthusiast
Posts: 121
Joined: Thu Apr 02, 2009 9:48 pm

ZipPacker violates zip-spec and cannot uncomp. windows zip

Post by nalor »

Hello!
I noticed a few problems with the new pack-implementation (tested with 5.41 and 5.42beta1 x86):
  • zip files created violate the zip-specification
  • >>DataDescriptor shouldn't be used at all
  • >>CRC32 is set although DataDescriptor is present
  • >> CompressedSize in LocalFileHeader and CentralDirectoryHeader is wrong
  • AddPackFile and CompressMemory generate different results (when comparing only the data section)
  • cannot unpack zip file created with windows-zip-implementation
Because the RemovePackFile command isn't available any longer I've created my own implementation of this command (I'm going to share it when it's ready). To perform this kind of action the first thing I had to do is to parse the Zip structure and doing so I noticed that the zip files created by the new pack commands are not valid when compared to the current zip specification. https://pkware.cachefly.net/webdocs/cas ... PPNOTE.TXT

The example below creates a small textfile and add it to a zip file - to check for the problems you need to open the created zip file with a hex editor - basically you should see this:

Image

In APPNOTE :
4.3.9 Data descriptor:
4.3.9.1 This descriptor MUST exist if bit 3 of the general purpose bit flag is set (see below). It is byte aligned and immediately follows the last byte of compressed data. This descriptor SHOULD be used only when it was not possible to seek in the output .ZIP file, e.g., when the output .ZIP file was standard output or a non-seekable device.
section 4.4.4 general purpose bit flag it says 'Bit 3: If this bit is set, the fields crc-32, compressed size and uncompressed size are set to zero in the local header. The correct values are put in the data descriptor immediately following the compressed data.
4.4.7 CRC-32: (4 bytes)' : 'If bit 3 of the general purpose flag is set, this field is set to zero in the local header and the correct value is put in the data descriptor and in the central directory.
So as far as I can see the DataDescriptor shouldn't be used at all - because my harddrive is seekable and I don't think that purebasic even supports non seekable devices ;)
But in case it is used the CRC32 in the LocalFileHeader has to be set to 0 - otherwise it violates the specification.

The next problem I've noticed is that the 'CompressedSize' is set to 0x10 bytes in the DataDescriptor and in the CentralDirectoryHeader - but the CompressedData is in fact 0x30 bytes long!

The next thing I've tried is to simply compress the Inputfile used before with 'CompressMemory' and write the compressed memory to a file - and the interesting thing is, that this file now has 0x16 bytes in size - so the 'CompressMemory' compresses different than the 'AddPackFile' ? Basically I'd expected that both data sections (the one in the zip archive and the pure 'compressmemory' file) are completely identical as both use the '
UseZipPacker()' functionality.

I also noticed that when I cannot uncompress the 0x30 bytes from the zip archive with 'UncompressMemory' ( I thought I create my own AddPack and UncompressPack using Compress/UncompressMemory - but as long as they don't compress/uncompress properly this isn't possible)

And finally the last problem - when you use windows to add the input file to a zip archive the file cannot be uncompressed with purebasic - the 'UncompressPackFile' fails for no special reason. (just create a ZIP file from the input file and remove the comment in the example).

Here's an example that can be used to demonstrate the problems:

Code: Select all

EnableExplicit

UseZipPacker()

Define iFileHdl.i
Define iPackHdl.i
Define sBaseDir.s
Define sSourceFile.s
Define sDestinationFile.s
Define sZipFile.s
Define sCompFile.s
Define sWindowsZipFile.s
Define *SourceMem
Define *CompressedMem
Define iCompressedSize.i
Define iUncompressedSize.i

sBaseDir=GetTemporaryDirectory()

sSourceFile=sBaseDir+"PbZipTest-InputFile.txt"
sZipFile=sBaseDir+"PbZipTest-ZipFile.zip"
sCompFile=sBaseDir+"PbZipTest-CompressFile.dat"
; sWindowsZipFile=sBasedir+GetFilePart(sSourceFile, #PB_FileSystem_NoExtension)+".zip"
sDestinationFile=sBaseDir+"UncompressedFromWindowsZip.txt"

;- Create TestFile
iFileHdl=CreateFile(#PB_Any, sSourceFile)
If iFileHdl
	WriteStringN(iFileHdl, "0123456789")
	WriteString(iFileHdl, "0123456789")
	CloseFile(iFileHdl)
	Debug "SourceFile >"+sSourceFile+"<"
Else
	Debug "Error creating file!"
	End
EndIf


;- add Testfile to new Zipfile
iPackHdl=CreatePack(#PB_Any, sZipFile)
If iPackHdl
	If Not AddPackFile(iPackHdl, sSourceFile, GetFilePart(sSourceFile))
		Debug "Error adding file to zip file!"
		End
	EndIf
	ClosePack(iPackHdl)
	Debug "ZipFile >"+sZipFile+"<"
Else
	Debug "Error creating zip file! >"+sZipFile+"<"
	End
EndIf

;- create 'Compressed' file from SourceFile
iFileHdl=ReadFile(#PB_Any, sSourceFile)
If Not iFileHdl
	Debug "Error reading file!"
	End
EndIf

*SourceMem=AllocateMemory(Lof(iFileHdl))
*CompressedMem=AllocateMemory(Lof(iFileHdl))

If Not *SourceMem Or Not *CompressedMem
	Debug "error alloc mem!"
	End
EndIf

If Not ReadData(iFileHdl, *SourceMem, MemorySize(*SourceMem))
	Debug "Error reading file!"
	End
EndIf
CloseFile(iFileHdl)

iCompressedSize=CompressMemory(*SourceMem, MemorySize(*SourceMem), *CompressedMem, MemorySize(*CompressedMem))
If iCompressedSize<=0
	Debug "error compressing memory! >"+iCompressedSize+"<"
	End
EndIf

Debug "CompressedSize >"+iCompressedSize+"< HEX >"+RSet(Hex(iCompressedSize), 4, "0")+"<"
iFileHdl=CreateFile(#PB_Any, sCompFile)
If Not iFileHdl
	Debug "Error creating file!"
	End
EndIf

If Not WriteData(iFileHdl, *CompressedMem, iCompressedSize)
	Debug "Error writing data file!"
	End
EndIf
CloseFile(iFileHdl)
Debug "File with compressed data >"+sCompFile+"<"

;- try to uncompress 'windows' compressed zip file
If sWindowsZipFile<>""
	iPackHdl=OpenPack(#PB_Any, sWindowsZipFile)
	If iPackHdl
		iUncompressedSize=UncompressPackFile(iPackHdl, sDestinationFile, GetFilePart(sSourceFile))
		If iUncompressedSize<=0
			Debug "Error uncompressing file from windows zip file! >"+iUncompressedSize+"< >"+sWindowsZipFile+"<"
			End
		EndIf
		ClosePack(iPackHdl)
		Debug "Destination File >"+sDestinationFile+"<"
	Else
		Debug "Error opening windows zip file! >"+sWindowsZipFile+"<"
		End
	EndIf
EndIf
Fred
Administrator
Administrator
Posts: 18162
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: ZipPacker violates zip-spec and cannot uncomp. windows z

Post by Fred »

Seems to work with built-in windows 10 zip handling. Does anyone has issue with .zip ? We use libarchive which is a pretty common lib for this, so it would be strange there is something wrong in it: http://www.libarchive.org/
nalor
Enthusiast
Enthusiast
Posts: 121
Joined: Thu Apr 02, 2009 9:48 pm

Re: ZipPacker violates zip-spec and cannot uncomp. windows z

Post by nalor »

Here's the zip file that my windows 8.1 x64 created from the input file:

http://s000.tinyupload.com/index.php?fi ... 5727884465

I also tested my example with Purebasic 5.31x86:
  • no DataDescriptor used
  • CompressedSize is correct
  • can uncompress the attached Zip File from windows
So basically the library never made any troubles for me in 5.31 - but the current implementation in 5.4x is unfortunately a big step back... :(

What has been the reason the change the library?
Fred
Administrator
Administrator
Posts: 18162
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: ZipPacker violates zip-spec and cannot uncomp. windows z

Post by Fred »

We got several major issues with unicode and when archives had many files in it. The new lib also add support for tar/gz and 7z which is good.
Fred
Administrator
Administrator
Posts: 18162
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: ZipPacker violates zip-spec and cannot uncomp. windows z

Post by Fred »

There was a problem when specifying the 'packedfilename$' param in previous 5.4x version, but 5.42 beta 2 should fix it. I can extract your zip just fine here with beta 2 (just republished a fixed version, so if you downloaded before reading this post, just download it again).
nalor
Enthusiast
Enthusiast
Posts: 121
Joined: Thu Apr 02, 2009 9:48 pm

Re: ZipPacker violates zip-spec and cannot uncomp. windows z

Post by nalor »

I can confirm that the windows-zip can be extracted with 5.42Beta2.

But I still see the problems with the spec-violating zip files. I guess the reported errors come from the library itself - but libarchive 3.1.2 is now 3 years old and the next release 3.2 went yesterday into the test-cycle:
+Feb 13, 2016: libarchive 3.1.900a released
+ This is a test release in preparation for 3.2.0
So eventually those problems are solved in the new release.
Fred
Administrator
Administrator
Posts: 18162
Joined: Fri May 17, 2002 4:39 pm
Location: France
Contact:

Re: ZipPacker violates zip-spec and cannot uncomp. windows z

Post by Fred »

Moved to feature and request, as normal features works.
nalor
Enthusiast
Enthusiast
Posts: 121
Joined: Thu Apr 02, 2009 9:48 pm

Re: ZipPacker violates zip-spec and cannot uncomp. windows z

Post by nalor »

I just noticed that I missed the 'extra field length' that explains the difference between the reported compressed size and the compressed size I've detected in my files.
4.3.7 Local file header:

local file header signature 4 bytes (0x04034b50)
version needed to extract 2 bytes
general purpose bit flag 2 bytes
compression method 2 bytes
last mod file time 2 bytes
last mod file date 2 bytes
crc-32 4 bytes
compressed size 4 bytes
uncompressed size 4 bytes
file name length 2 bytes
extra field length 2 bytes

file name (variable size)
extra field (variable size)
So the reported compressed size is correct - my fault :(

(The only thing that remains is that in case the DataDescriptor is present the CompressedSize and UncompressedSize in the LocalHeader has to be 0 - but I think nobody cares about this detail at all... )
Post Reply