GZip and Deflate in IIS

Windows specific forum
User avatar
RichAlgeni
Addict
Addict
Posts: 914
Joined: Wed Sep 22, 2010 1:50 am
Location: Bradenton, FL

GZip and Deflate in IIS

Post by RichAlgeni »

Many thanks to JHPJHP for his beautiful code! I have adapted it for my needs. This is a dll wrapper I created to use inside other dll's for Microsoft Internet Information Server (IIS). Since it lives inside a server process, the compressed data just overwrites the source data.

zlib_wrapper_64.pb

Code: Select all

EnableExplicit

#Z_NO_FLUSH                =  0
#Z_PARTIAL_FLUSH           =  1
#Z_SYNC_FLUSH              =  2
#Z_FULL_FLUSH              =  3
#Z_FINISH                  =  4
#Z_BLOCK                   =  5
#Z_TREES                   =  6
                             
#Z_OK                      =  0
#Z_STREAM_END              =  1
#Z_NEED_DICT               =  2
#Z_ERRNO                   = -1
#Z_STREAM_ERROR            = -2
#Z_DATA_ERROR              = -3
#Z_MEM_ERROR               = -4
#Z_BUF_ERROR               = -5
#Z_VERSION_ERROR           = -6

#Z_DEFAULT_COMPRESSION     = -1
#Z_NO_COMPRESSION          =  0
#Z_BEST_SPEED              =  1
#Z_BEST_COMPRESSION        =  9
                              
#Z_DEFAULT_STRATEGY        =  0
#Z_FILTERED                =  1
#Z_HUFFMAN_ONLY            =  2
#Z_RLE                     =  3
#Z_FIXED                   =  4
                              
#Z_BINARY                  =  0
#Z_TEXT                    =  1
#Z_ASCII                   =  1
#Z_UNKNOWN                 =  2
                              
#Z_NULL                    =  0
#Z_DEFLATED                =  8
                              
#MAX_MEM_LEVEL             =  9
#MAX_WBITS                 = 15
#GZIP_ENCODING             = 16
                              
#OS_FAT                    =  0
#OS_AMIGA                  =  1
#OS_VMS                    =  2
#OS_UNIX                   =  3
#OS_VM_CMS                 =  4
#OS_ATARI_TOS              =  5
#OS_HPFS                   =  6
#OS_MACINTOSH              =  7
#OS_Z_SYSTEM               =  8
#OS_CP_M                   =  9
#OS_TOPS_20                = 10
#OS_NTFS                   = 11
#OS_QDOS                   = 12
#OS_ACORN_RISCOS           = 13
                              
#ZLIB_VERSION              = "1.2.8"
#CHUNK_SIZE                = 1024 * 256

Structure Z_STREAM Align #PB_Structure_AlignC
    *next_in
    avail_in.l
    total_in.l
    *next_out
    avail_out.l
    total_out.l
    *msg
    *state
    *zalloc
    *zfree
    *opaque
    data_type.l
    adler.l
    reserved.l
EndStructure

Structure GZ_HEADER Align #PB_Structure_AlignC
    text.l
    time.l
    xflags.l
    os.l
    *extra
    extra_len.l
    extra_max.l
    *name
    name_max.l
    *comment
    comm_max.l
    hcrc.l
    done.l
EndStructure

ImportC "zlib_64.lib"
    compress2(*destinBuffer, *destinSize, *sourceBuffer, sourceSize.i, compressLevel.i)
    deflate(*stream, flush)
    deflateBound(*stream, sourceLen)
    deflateEnd(*stream)
    deflateInit2_(*stream, level, method, windowBits, memLevel, strategy, version.p-ascii, strm_size)
    deflateSetHeader(*stream, *head)
EndImport

ProcedureDLL.i AttachProcess(instance.i)
EndProcedure

ProcedureDLL.i DetachProcess(instance.i)
EndProcedure

ProcedureDLL.i AttachThread(instance.i)
EndProcedure

ProcedureDLL.i DetachThread(instance.i)
EndProcedure

; **********************************************************************************
; dll procedure to pack a memory area into a new memory area using ZLib
; **********************************************************************************

ProcedureDLL.i PackMemoryZlib(*sourceBuffer, sourceSize, compressLevel = 9)

; *sourceBuffer  = pointer to the source buffer
;  sourceSize    = size of the source buffer
;  compressLevel = compression level

; NOTE: #Z_DATA_ERROR means the file cannot be compressed
; NOTE: CompressLevel must be between 0 (lowest) and 9 (highest)
; NOTE: The compressed file will be written on top of the source file

	Protected result.i
    Protected compressErr.i
    Protected destinSize.i   = sourceSize * 1.4
	Protected destinBuffer.s = Space(destinSize)

    If *sourceBuffer <= 0
        ProcedureReturn #Z_MEM_ERROR
    EndIf

    If sourceSize <= 0
        ProcedureReturn #Z_MEM_ERROR - 10
    EndIf

    If compressLevel < 0 Or compressLevel > 9
        ProcedureReturn #Z_MEM_ERROR - 100
    EndIf

; now compress the data, and see what we get in return

    result = compress2(@destinBuffer, @destinSize, *sourceBuffer, sourceSize, compressLevel)

    Select result
    Case #Z_OK
        If destinSize >= sourceSize
            result = #Z_DATA_ERROR
        Else
			CopyMemory(@destinBuffer, *sourceBuffer, destinSize)
            result = destinSize
        EndIf
    Case -3; Z_DATA_ERROR
        result = #Z_BUF_ERROR
    Case -4, -5; Z_ERROR_MEM, Z_BUF_ERROR
        result = #Z_STREAM_ERROR
    Default; ANYTHING ELSE
        result = #Z_ERRNO
    EndSelect

    ProcedureReturn result

EndProcedure

; **********************************************************************************
; procedure to deflate the data itself
; **********************************************************************************

Procedure.i Deflate_Payload(*destinBuffer, destinSize, *sourceBuffer, sourceSize, *sourceName)

	Protected nOut.i            = 0
	Protected nSize.i           = 0
	Protected nStart.i          = 0
    Protected headerComment.s   = "Compressed in gzip format"
    Protected *output           = AllocateMemory(#CHUNK_SIZE)
    Protected *stream.Z_STREAM  = AllocateMemory(SizeOf(Z_STREAM))
    Protected *header.GZ_HEADER = AllocateMemory(SizeOf(GZ_HEADER))
    Protected windowBits.i      = (15 | #GZIP_ENCODING)

    *stream\zalloc    = #Z_NULL
    *stream\zfree     = #Z_NULL
    *stream\opaque    = #Z_NULL
    *stream\data_type = #Z_BINARY
    deflateInit2_(*stream, #Z_DEFAULT_COMPRESSION, #Z_DEFLATED, windowBits, #MAX_MEM_LEVEL, #Z_DEFAULT_STRATEGY, #ZLIB_VERSION, SizeOf(Z_STREAM))
    *header\name      = *sourceName
    *header\comment   = @headerComment
    *header\text      = #Z_NULL
    *header\time      = Date() + 60 * 60 * 4
    *header\xflags    = #Z_NULL
    *header\os        = #OS_NTFS
    *header\extra_len = #Z_NULL
    *header\extra_max = #Z_NULL
    *header\name_max  = #Z_NULL
    *header\comm_max  = #Z_NULL
    *header\hcrc      = #Z_NULL
    *header\done      = #Z_NULL

    deflateSetHeader(*stream, *header)

    *stream\next_in    = *sourceBuffer
    *stream\avail_in   = sourceSize

    Repeat
        *stream\avail_out = #CHUNK_SIZE
        *stream\next_out  = *output
        deflate(*stream, #Z_FINISH)
        nOut  = #CHUNK_SIZE - *stream\avail_out
        nSize = nSize + nOut

        If nSize = 0
            Break
        EndIf

        CopyMemory(*output, *destinBuffer + nStart, nOut)
        nStart + nOut
    Until *stream\avail_out <> 0

    deflateEnd(*stream)

    FreeMemory(*header)
    FreeMemory(*stream)
	FreeMemory(*output)

	ProcedureReturn nSize

EndProcedure

; **********************************************************************************
; dll procedure to pack a memory area into a new memory area using ZLib Gzip
; **********************************************************************************

ProcedureDLL.i PackGzipZlib(*sourceBuffer, sourceSize, *sourceName)

; *sourceBuffer  = pointer to the source buffer
;  sourceSize    = size of the source buffer

; NOTE: #Z_DATA_ERROR means the file cannot be compressed
; NOTE: The compressed file will be written on top of the source file

	Protected result.i
    Protected compressErr.i
    Protected destinSize.i   = sourceSize * 1.4
	Protected destinBuffer.s = Space(destinSize)

    If *sourceBuffer <= 0
        ProcedureReturn #Z_MEM_ERROR
    EndIf

    If sourceSize <= 0
        ProcedureReturn #Z_MEM_ERROR - 10
    EndIf

; now compress the data, and see what we get in return

    result = Deflate_Payload(@destinBuffer, destinSize, *sourceBuffer, sourceSize, *sourceName)

    If result > 0
		destinSize = result
        If destinSize >= sourceSize
            result = #Z_DATA_ERROR
        Else
			CopyMemory(@destinBuffer, *sourceBuffer, destinSize)
        EndIf
	Else
        result = #Z_ERRNO
    EndIf

    ProcedureReturn result

EndProcedure

CompilerIf #PB_Compiler_Thread = 0
    CompilerError "ZLib components must be compiled with threadsafe enabled!"
CompilerEndIf
Here is the process I used to test the compression files for validity, prior to utilizing inside my IIS dll processes.

check_compression.pb

Code: Select all

EnableExplicit

Define result.i
Define anyFile.s
Define fileName.s
Define libNumber.i
Define resultLine.s
Define sourceSize.i
Define sourceName.s
Define sourceBuffer.s
Define libraryName.s  = "zlib_wrapper_64.dll"

; open the library needed

libNumber = OpenLibrary(#PB_Any, libraryName)
If libNumber <= 0
    MessageRequester("Test", "Unable To open " + libraryName)
    End
EndIf

; create prototypes for the compression dll

Prototype compressGzip(*sourceBuffer, sourceSize.i, *sourceName)
Prototype compressDflt(*sourceBuffer, sourceSize, compressLevel.i)

; now define the global we will need to call the functions

Global compressGzip.compressGzip = GetFunction(libNumber, "PackGzipZlib")
Global compressDflt.compressDflt = GetFunction(libNumber, "PackMemoryZlib")

anyFile = OpenFileRequester("Inflate / Deflate", "", "All files (*.*)|*.*", 0)

If anyFile
    sourceSize = FileSize(anyFile)

    Select #True
    Case Bool(sourceSize < 0)
        MessageRequester("Compression Test", "There was a problem opening the file, operation cancelled.")
    Case Bool(sourceSize = 0)
        MessageRequester("Compression Test", "File is empty, operation cancelled.")
    Case Bool(sourceSize > 1024 * 1024 * 1024)
        MessageRequester("Compression Test", "File is greater than 1Gb, operation cancelled.")
    Default
        fileName = GetFilePart(anyFile)

        If ReadFile(0, anyFile, #PB_File_SharedRead | #PB_File_SharedWrite | #PB_File_NoBuffering)
            sourceBuffer = Space(sourceSize + 1)
            ReadData(0, @sourceBuffer, sourceSize)
            CloseFile(0)
        EndIf

        result     = compressGzip(@sourceBuffer, sourceSize.i, @sourceName)
        resultLine = "GZip'd size = " + Str(result) + #CRLF$

        If CreateFile(0, anyFile + ".gz", #PB_File_NoBuffering)
            WriteData(0, @sourceBuffer, result)
            CloseFile(0)
        EndIf

        result     = compressDflt(@sourceBuffer, sourceSize, 9)
        resultLine + "Deflate'd size = " + Str(result)

        If CreateFile(0, anyFile + ".df", #PB_File_NoBuffering)
            WriteData(0, @sourceBuffer, result)
            CloseFile(0)
        EndIf

        MessageRequester("Compression Test", resultLine)
    EndSelect
Else
    MessageRequester("Compression Test", "Could Not Read the file.")
EndIf

End