Results 1 to 1 of 1

Thread: modZlib.bas

  1. #1

    Thread Starter
    Frenzied Member
    Join Date
    Oct 2008
    Posts
    1,181

    modZlib.bas

    This is my module file for using zlibwapi.dll in VB6. To use this code, simply copy the text in the code box at the bottom of this post, and paste it into an empty module in VB6. Note that you must have the DLL file in question in either the windows\system32 folder (windows\syswow64 on x64 Windows), or in the folder where your VB6 project files are for the project you are working on (the same folder where your EXE file will be compiled to). Normally Zlib's only easy to use compression/decompression functions are compress, compress2, and uncompress. Unfortunately those functions expect the compressed data to exist within the a Zlib container (has a 2 byte header, and a 4 byte footer that is an Adler32 checksum of the uncompressed data). However, a number of various file formats expect raw "deflate" data to be in use (I believe that the Zip file format is one), without any Zlib container surrounding the compressed data. Deflate is the name of the algorithm that Zlib uses. Now Zlib does have functions for directly accessing raw deflate streams, but they are VERY difficult to use, and require initializing special structures associated with the streams, requiring a massive amount of overhead in any program implementing it. Zlib also has builtin functions for working with GZip files directly, but what if you want to handle an in-memory copy of a GZip container? Well once again, you can use the stream commands for that (and again use a HUGE amount of overhead in writing what could otherwise be a very simple program).

    That's where my module comes in. It completely gets around the need for stream handling, by ultimately always using the compress2, uncompress, compressBound, and crc32 Zlib methods, and then handling the container formats as needed directly in VB6 code (and also using the Windows API CopyMemory method where needed). It contains methods for handling not only Zlib containers, but also raw deflate streams, and GZip containers. And it does it all using memory. The methods for the raw deflate streams work by calling the Zlib functions, and then adding or removing the Zlib container from the compressed data as needed. Of course, when it recreates the Zlib container, it doesn't have access to the uncompressed data until it decompresses it, so there's no way for it to recreate the Adler32 checksum, and without the correct checksum the Zlib decompressor returns an error, even though it does correctly decompress the data. As a result, error checking for decompression of a raw deflate stream is impossible, and therefore the Inflate method (Inflate is what they call decompressing Deflated data), is a "sub" rather than a "function", as it can't return any usable error, as otherwise it would always be signalling that it failed. I recommend that if you use raw deflate streams, that you use some other error checking method outside of the compression functions, such as storing a checksum or CRC separately (either in the header of your file, or in a separate file that your program will also load in addition to the file containing compressed data). My GZip compress and decompress functions call my Inflate and Deflate methods, and add or remove the GZip container from the data as needed. GZip uses CRC32 rather than a checksum, and since it can check for errors, the decompress method for GZip once again is a function. I have verified that my GZip compress function generates a valid GZip container, by saving it to a file and then opening it in the program 7Zip. My Zlib functions are included just to simplify the use of Zlib, as no special preprocessing or postprocessing of container formats is required here. These simplify handling of Zlib containers, by using byte arrays, rather than arbitrary data, so you don't need to know the size of the data that's being fed to it. These functions internally automatically determine the size of the input data by using the UBound VB6 function on the arrays. The only thing you will need to know is upon decompressing a Zlib stream or a raw Deflate stream, you will will need to know the original uncompressed size. This can be determined easily by your own use of the UBound function in your own code, and then this info can be saved into whatever structure or file format you use to pass information to and from this program. Only difference is with a GZip container, which already stores the original uncompressed size as part of the container (it's a 4byte Long value, which is the last 4 bytes of the 8byte footer at the end of the container, according to the official specs for GZip).

    All my functions use the Boolean type for the return value, and output True for success, and False for failure. All input and output data are byte arrays. All byte arrays are to be 1D arrays, with the first index at 0 (zero). My GZip functions also handle a stored filename. For compressing, supplying a filename is optional. For decompressing, even if you don't have a filename stored, since it is passed byref, a filename variable MUST be supplied, even if it's only acting as a dummy/filler variable if you have no intent to use that info. All other optional fields that may be present in a GZip container are ignored by my decompression function, and are simply skipped if they are present. If the header indicates they exist they do get processed to find their length, but only for the purpose of skipping them to get to the deflate stream, as no info stored in them is returned by my GZip decompress function. Likewise , the only optional field that can be saved by my GZip compress function is the filename field.

    Code:
    Private Declare Function crc32 Lib "zlibwapi.dll" (ByVal OldCRC As Long, ByRef Data As Any, ByVal DataLen As Long) As Long
    Private Declare Function compress2 Lib "zlibwapi.dll" (ByRef Dest As Byte, ByRef DestLen As Long, ByRef Src As Byte, ByVal SrcLen As Long, ByVal CompLevel As Long) As Long
    Private Declare Function uncompress Lib "zlibwapi.dll" (ByRef Dest As Byte, ByRef DestLen As Long, ByRef Src As Byte, ByVal SrcLen As Long) As Long
    Private Declare Function compressBound Lib "zlibwapi.dll" (ByVal SrcLen As Long) As Long
    Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
    
    
    
    Public Function ZlibCompress(ByRef Dest() As Byte, ByRef Src() As Byte, Optional ByVal CompLevel As Long = 9) As Boolean
    Dim SrcLen As Long
    Dim DestLen As Long
    Dim ErrorNum As Long
    
    SrcLen = UBound(Src) + 1
    DestLen = compressBound(SrcLen)
    ReDim Dest(DestLen - 1)
    ErrorNum = compress2(Dest(0), DestLen, Src(0), SrcLen, CompLevel)
    If ErrorNum Then Exit Function
    ReDim Preserve Dest(DestLen - 1)
    ZlibCompress = True
    End Function
    
    
    
    Public Function ZlibDecompress(ByRef Dest() As Byte, ByRef Src() As Byte, ByVal UncompLen As Long) As Boolean
    Dim SrcLen As Long
    Dim DestLen As Long
    Dim ErrorNum As Long
    
    SrcLen = UBound(Src) + 1
    DestLen = UncompLen
    ReDim Dest(DestLen - 1)
    ErrorNum = uncompress(Dest(0), DestLen, Src(0), SrcLen)
    If ErrorNum Then Exit Function
    ReDim Preserve Dest(DestLen - 1)
    ZlibDecompress = True
    End Function
    
    
    
    Public Function Deflate(ByRef Dest() As Byte, ByRef Src() As Byte, Optional ByVal CompLevel As Long = 9) As Boolean
    Dim ZlibCompData() As Byte
    Dim Success As Boolean
    
    Success = ZlibCompress(ZlibCompData, Src, CompLevel)
    If Success = False Then Exit Function
    ReDim Dest(UBound(ZlibCompData) - 6)
    CopyMemory Dest(0), ZlibCompData(2), UBound(Dest) + 1
    Deflate = True
    End Function
    
    
    
    Public Sub Inflate(ByRef Dest() As Byte, ByRef Src() As Byte, ByVal UncompLen As Long)
    Dim ZlibCompData() As Byte
    Dim CheckSumInput As Long
    Dim n As Long
        
    ReDim ZlibCompData(UBound(Src) + 6)
    ZlibCompData(0) = &H78
    ZlibCompData(1) = &H80
    CheckSumInput = &H7880&
    For n = 0 To 31
        If (CheckSumInput Or n) Mod 31 = 0 Then
            ZlibCompData(1) = ZlibCompData(1) Or n
            Exit For
        End If
    Next n
    CopyMemory ZlibCompData(2), Src(0), UBound(ZlibCompData) + 1
    ZlibDecompress Dest(), ZlibCompData(), UncompLen
    End Sub
    
    
    
    Public Function GzipCompress(ByRef Dest() As Byte, ByRef Src() As Byte, Optional ByVal CompLevel As Long = 9, Optional ByVal FileName As String) As Boolean
    Const HeaderLen As Long = 10
    Const FooterLen As Long = 8
    Dim DeflatedData() As Byte
    Dim DeflateLen As Long
    Dim FNameBytes() As Byte
    Dim FNameLen As Long
    Dim CRC As Long
    Dim UncompLen As Long
    Dim Success As Boolean
    
    Success = Deflate(DeflatedData, Src, CompLevel)
    If Success = False Then Exit Function
    DeflateLen = UBound(DeflatedData) + 1
    FNameBytes() = StrConv(FileName, vbFromUnicode)
    FNameLen = Len(FileName)
    If FNameLen > 0 Then
        FNameLen = FNameLen + 1
        ReDim Preserve FNameBytes(FNameLen - 1)
    End If
    UncompLen = UBound(Src) + 1
    CRC = crc32(0, Src(0), UncompLen)
    
    ReDim Dest(HeaderLen + FNameLen + DeflateLen + FooterLen - 1)
    Dest(0) = 31
    Dest(1) = 139
    Dest(2) = 8
    
    If FNameLen Then
        Dest(3) = 8
        CopyMemory Dest(HeaderLen), FNameBytes(0), FNameLen
    End If
    
    If CompLevel < 5 Then Dest(8) = 4 Else Dest(8) = 2
    Dest(9) = 0
    
    CopyMemory Dest(HeaderLen + FNameLen), DeflatedData(0), DeflateLen
    CopyMemory Dest(HeaderLen + FNameLen + DeflateLen), CRC, 4
    CopyMemory Dest(HeaderLen + FNameLen + DeflateLen + 4), UncompLen, 4
    
    GzipCompress = True
    End Function
    
    
    
    Public Function GzipDecompress(ByRef Dest() As Byte, ByRef Src() As Byte, ByRef FileName As String) As Boolean
    Const HeaderLen As Long = 10
    Const ID1 As Byte = 31
    Const ID2 As Byte = 139
    Const CM As Byte = 8
    Const FooterLen As Long = 8
    Dim DataPtr As Long
    Dim SrcLen As Long
    Dim FLG As Byte
    Dim XLEN As Integer
    Dim DeflatedData() As Byte
    Dim DeflateLen As Long
    Dim TempStr As String
    Dim FNameLen As Long
    Dim FCommentLen As Long
    Dim LenBeforeData As Long
    Dim UncompLen As Long
    Dim CRC As Long
    Dim CRC2 As Long
    
    SrcLen = UBound(Src) + 1
    LenBeforeData = HeaderLen
    
    If Src(0) <> ID1 Then Exit Function
    If Src(1) <> ID2 Then Exit Function
    If Src(2) <> CM Then Exit Function
    FLG = Src(3)
    If FLG And 2 Then LenBeforeData = LenBeforeData + 2
    If FLG And 4 Then
        CopyMemory XLEN, Src(HeaderLen), 2
        LenBeforeData = LenBeforeData + 2 + XLEN
        DataPtr = HeaderLen + 2 + XLEN
    Else
        DataPtr = HeaderLen
    End If
    
    If (FLG And 8) Or (FLG And 16) Then
        Do Until Src(DataPtr) = 0
            TempStr = TempStr & Chr$(Src(DataPtr))
            DataPtr = DataPtr + 1
        Loop
        If FLG And 8 Then
            FNameLen = Len(TempStr) + 1
            FileName = Left$(TempStr, FNameLen - 1)
            LenBeforeData = LenBeforeData + FNameLen
            If FLG And 16 Then
                DataPtr = DataPtr + 1
                TempStr = ""
                Do Until Src(DataPtr) = 0
                    TempStr = TempStr & Chr$(Src(DataPtr))
                    DataPtr = DataPtr + 1
                Loop
                FCommentLen = Len(TempStr) + 1
                LenBeforeData = LenBeforeData + FCommentLen
            End If
        Else
            FCommentLen = Len(TempStr) + 1
            LenBeforeData = LenBeforeData + FCommentLen
        End If
    End If
    
    DeflateLen = SrcLen - LenBeforeData - 8
    ReDim DeflatedData(DeflateLen - 1)
    
    CopyMemory CRC, Src(LenBeforeData + DeflateLen), 4
    CopyMemory UncompLen, Src(LenBeforeData + DeflateLen + 4), 4
    CopyMemory DeflatedData(0), Src(LenBeforeData), DeflateLen
    ReDim Dest(UncompLen - 1)
    Inflate Dest(), DeflatedData(), UncompLen
    CRC2 = crc32(0, Dest(0), UncompLen)
    If CRC2 <> CRC Then Exit Function
    
    GzipDecompress = True
    End Function
    Last edited by Ben321; Jun 11th, 2015 at 02:09 AM. Reason: cleaned up the code a little

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width