I had to take a swing at a single-procedure solution.
Takes a *gzip buffer and returns an unpacked buffer. Uses PB's UseZipPacker() but nothing else.
Does this work for you?
Code: Select all
Procedure.i UngzipToBuffer(*gzip, gzipBytes.i = #PB_Default) ; #PB_Default --> get gzipBytes from MemorySize(*gzip)
Protected *Buffer = #Null
If (*gzip)
UseZipPacker()
If (gzipBytes = #PB_Default)
gzipBytes = MemorySize(*gzip)
EndIf
If (gzipBytes > 0)
Protected CompressedBytes.i, UncompressedBytes.i, BufferSize.i, UnpackedBytes.i, TempWord.w
If ((PeekA(*gzip + 0) = $1F) And (PeekA(*gzip + 1) = $8B)) ; magic number
If (PeekA(*gzip + 2) = $08) ; DEFLATE compression method
If (PeekA(*gzip + 3) = $00) ; no header flags supported (yet)
UncompressedBytes = PeekL(*gzip + gzipBytes - 4)
If (UncompressedBytes > 0)
CompressedBytes = gzipBytes - (10 + 8)
If (CompressedBytes > 0)
BufferSize = UncompressedBytes + 16
*Buffer = AllocateMemory(BufferSize, #PB_Memory_NoClear)
If (*Buffer)
PokeU(*Buffer + UncompressedBytes - 1, $7F7F)
TempWord = PeekW(*gzip + 8)
PokeA(*gzip + 8, $78) ; zlib magic number
PokeA(*gzip + 9, $9C) ; assume "Default Compression"
UnpackedBytes = UncompressMemory(*gzip + (10 - 2), 2 + CompressedBytes + 4, *Buffer, BufferSize)
PokeW(*gzip + 8, TempWord)
If (UnpackedBytes = -1)
If ((PeekA(*Buffer + UncompressedBytes - 1) <> $7F) And (PeekA(*Buffer + UncompressedBytes) = $7F))
UnpackedBytes = UncompressedBytes
EndIf
EndIf
If (UnpackedBytes = UncompressedBytes)
*Buffer = ReAllocateMemory(*Buffer, UnpackedBytes)
Else
FreeMemory(*Buffer)
*Buffer = #Null
EndIf
EndIf
EndIf
EndIf
EndIf
EndIf
EndIf
EndIf
EndIf
ProcedureReturn (*Buffer)
EndProcedure
And a second helper procedure to un-gzip to file:
Code: Select all
Procedure.i UngzipToFile(*gzip, File.s, gzipBytes.i = #PB_Default) ; #PB_Default --> get gzipBytes from MemorySize(*gzip)
Protected Result.i = #False
If (File)
Protected *Buffer = UngzipToBuffer(*gzip, gzipBytes)
If (*Buffer)
Protected FN.i = CreateFile(#PB_Any, File)
If (FN)
Protected BufferSize.i = MemorySize(*Buffer)
If (WriteData(FN, *Buffer, BufferSize) = BufferSize)
Result = #True
EndIf
CloseFile(FN)
EndIf
FreeMemory(*Buffer)
EndIf
EndIf
ProcedureReturn (Result)
EndProcedure
Note, it does everything in-memory rather than iterating chunks of data, so I would not recommend using this for huge/gigabytes of data!