wqweto / ZipArchive

A single-class pure VB6 library for zip with ASM speed
MIT License
52 stars 22 forks source link

Extract File From Resource File #30

Closed cyberzilla closed 11 months ago

cyberzilla commented 11 months ago

I have tried extracting the test.zip file using the file path, and it succeeded in extracting all the files with all their contents,

With New cZipArchive
    .OpenArchive Text1.Text 'test.zip
    .Extract App.Path & "\test", Password:="test123"
End With

but when I put the test.zip file into the resource file, and tried to extract it, only one file was extracted, how do I solve this?

Dim bytResourceData() As Byte
    bytResourceData = LoadResData(404, "CUSTOM")

With New cZipArchive
    .OpenArchive bytResourceData
    .Extract App.Path & "\test", Password:="test123"
End With

Thanks @wqweto

wqweto commented 11 months ago

Just tested this w/ an encrypted archive and the sample code works here.

One thing that might trip you up is if App.Path & "\test" folder does not exists but there is a filename test in the zip archive then it will only extract this test file into App.Path folder which might be unexpected. This feature is introduced in the latest release so to be able to easily extract single file from the zip archive.

cyberzilla commented 11 months ago

I have tested the extraction directly from the IDE, and it works. However, when I compile it into an .exe, only one file is extracted. I have tried using Msgbox UBound(bytResourceData) to debug the issue, and it appears that there is a difference of 2 bytes between the IDE and the executable

cyberzilla commented 11 months ago

Apologies, maybe this is off-topic, but it seems that this case is similar to what's discussed here

wqweto commented 11 months ago

Yes, zero padding on binary resources (to DWORD boudary) would be a problem because zip format stores its Central Directory at the end of the file but the sample code still works here w/ zero padding too because when Central Directory is missing (not found in this case) cZipArchive class tries to locate each file entry in the archive by scanning data from the start i.e. without reading Central Directory.

It all depends on the original compressor the zip archive is created with to populate each entry's Local Header correctly so that fallback strategy to work when needed -- 7-zip produces zip archives which work ok w/ fallback strategy.

cyberzilla commented 11 months ago

I have successfully solved the problem. First, I converted the result of the zip file into a base64 string. Then, I embedded that string into a resource file and extracted it again. Although the base64 encoding increased the file size, it wasn't an issue, and this method worked successfully

Dim baZip() As Byte
Dim sOutput As String
With New cZipArchive
    .AddFromFolder txtPath.Text & "\*.*", Recursive:=True, IncludeEmptyFolders:=True, Password:=txtPass.Text
    .CompressArchive baZip
    .DeflateBase64 baZip, sOutput, 6
End With
CreateTextFile txtPath.Text & "\deflateencodeb64.txt", sOutput

Then i embed deflateencodeb64.txt to resource file with id "B64",

Extract code like below:

Dim baOutput() as byte
With New cZipArchive
If .InflateBase64(StrConv(LoadResData("B64", "CUSTOM"), vbUnicode), baOutput) Then
    .OpenArchive baOutput
    .Extract txtPath.Text, Password:=txtPass.Text
End If
End With

This method is excellent, and I will use it to create a custom setup file that requires several files. Combining these files into a zip file is definitely better than embedding each file individually into the resource file Thanks @wqweto

wqweto commented 11 months ago

Btw, you can extract individual files with something like

    .Extract txtPath.Text, Filter:="MyFile.txt", Password:=txtPass.Text
cyberzilla commented 11 months ago

Instead of using loadResData, I have found a very useful user control to attach binary data from here, and combined it with cZipArchive. The result is exactly as expected.