Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

zlib


  • Please log in to reply
18 replies to this topic
shajul
  • Members
  • 571 posts
  • Last active: Aug 01 2015 03:45 PM
  • Joined: 15 Sep 2006
Wrapper for zlib1.dll available from <!-- m -->http://www.zlib.net<!-- m --> (100K), inspired by this ask for help question.

zlib is designed to be a free, general-purpose, legally unencumbered -- that is, not covered by any patents -- lossless data-compression library for use on virtually any computer hardware and operating system. The zlib data format is itself portable across platforms.
zlib was written by Jean-loup Gailly (compression) and Mark Adler (decompression). Jean-loup is also the primary author/maintainer of gzip(1), the author of the comp.compression FAQ list and the former maintainer of Info-ZIP's Zip; Mark is also the author of gzip's and UnZip's main decompression routines and was the original author of Zip. Not surprisingly, the compression algorithm used in zlib is essentially the same as that in gzip and Zip, namely, the `deflate' method that originated in PKWARE's PKZIP 2.x.


Requirements: AHK_L Unicode (Ansi will require minor modifications)

I have wrapped only the Utility and GZip compress/decompress functions.

Functions:
zlib_Compress(Byref Compressed, Byref Data, DataLen, level = -1) {
nSize := DllCall("zlib1\compressBound", "UInt", DataLen, "Cdecl")
VarSetCapacity(Compressed,nSize)
ErrorLevel := DllCall("zlib1\compress2", "ptr", &Compressed, "UIntP", nSize, "ptr", &Data, "UInt", DataLen, "Int"
               , level    ;level 0 (no compression), 1 (best speed) - 9 (best compression)
               , "Cdecl") ;0 means Z_OK
return ErrorLevel ? 0 : nSize
} ;http://www.autohotkey.com/forum/viewtopic.php?t=68170

zlib_Decompress(Byref Decompressed, Byref CompressedData, DataLen, OriginalSize = -1) {
OriginalSize := (OriginalSize > 0) ? OriginalSize : DataLen*10 ;should be large enough for most cases
VarSetCapacity(Decompressed,OriginalSize)
ErrorLevel := DllCall("zlib1\uncompress", "Ptr", &Decompressed, "UIntP", OriginalSize, "Ptr", &CompressedData, "UInt", DataLen)
return ErrorLevel ? 0 : OriginalSize
} ;http://www.autohotkey.com/forum/viewtopic.php?t=68170

gz_compress(infilename, outfilename)
{
VarSetCapacity(sOutFileName, 260)
DllCall("WideCharToMultiByte", "Uint", 0, "Uint", 0, "str", outfilename, "int", -1, "str", sOutFileName, "int", 260, "Uint", 0, "Uint", 0)
infile := FileOpen(infilename, "r"), outfile := DllCall("zlib1\gzopen", "Str" , sOutFileName , "Str", "wb", "Cdecl")
if (!infile || !outfile) 
   return 0
nBufferLen := 8192 ; can be increased if gzbuffer function is called beforehand
VarSetCapacity(inbuffer,nBufferLen)
while ((num_read := infile.RawRead(inbuffer, nBufferLen)) > 0) 
   DllCall("zlib1\gzwrite", "UPtr", outfile, "UPtr", &inbuffer, "UInt", num_read, "Cdecl")
infile.Close()
DllCall("zlib1\gzclose", "UPtr", outfile, "Cdecl")
return 1
} ;http://www.autohotkey.com/forum/viewtopic.php?t=68170

gz_decompress(infilename, outfilename)
{
VarSetCapacity(sInFileName, 260)
DllCall("WideCharToMultiByte", "Uint", 0, "Uint", 0, "str", infilename, "int", -1, "str", sInFileName, "int", 260, "Uint", 0, "Uint", 0)
infile := DllCall("zlib1\gzopen", "Str" , sInFileName , "Str", "rb", "Cdecl"), outfile := FileOpen(outfilename, "w")
if (!infile || !outfile) 
   return 0
VarSetCapacity(buffer,8192) ;can be increased after calling gzbuffer beforehand
num_read = 0
while ((num_read := DllCall("zlib1\gzread", "UPtr", infile, "UPtr", &buffer, "UInt", 8192, "Cdecl")) > 0)
   outfile.RawWrite(buffer, num_read)
DllCall("zlib1\gzclose", "UPtr", infile, "Cdecl")
infile.Close()
return 1
} ;http://www.autohotkey.com/forum/viewtopic.php?t=68170

/*
Return codes for the compression/decompression functions. Negative values are errors, positive values are used for special but normal events.
#define Z_OK            0
#define Z_STREAM_END    1
#define Z_NEED_DICT     2
#define Z_ERRNO        (-1)
#define Z_STREAM_ERROR (-2)
#define Z_DATA_ERROR   (-3)
#define Z_MEM_ERROR    (-4)
#define Z_BUF_ERROR    (-5)
#define Z_VERSION_ERROR (-6)

Compression levels.
#define Z_NO_COMPRESSION         0
#define Z_BEST_SPEED             1
#define Z_BEST_COMPRESSION       9
#define Z_DEFAULT_COMPRESSION  (-1)
*/

Example:
; DATA COMPRESSION
infile := FileOpen(A_ScriptFullPath, "r") 
len := infile.length
infile.RawRead(MyData,len)
if (r := zlib_Compress(CompressedData , MyData, len))
 MsgBox % "Data compressed " . round((r/len)*100) . "%"
else MsgBox Error Errorlevel %Errorlevel%
infile.Close()

; DATA DECOMPRESSION
if (t := zlib_Decompress(Inflated,CompressedData,r,len))
 MsgBox % StrGet(&Inflated,len,"")
else MsgBox Error Errorlevel %Errorlevel%

;COMPRESS TO GZIP FILE
gz_compress(A_AhkPath,A_ScriptDir . "\test.gz")
;DECOMPRESS GZIP FILE
gz_decompress(A_ScriptDir . "\test.gz", A_ScriptDir . "\extracted.exe")




zlib_Compress(Byref Compressed, Byref Data, DataLen, level = -1) {
nSize := DllCall("zlib1\compressBound", "UInt", DataLen, "Cdecl")
VarSetCapacity(Compressed,nSize)
ErrorLevel := DllCall("zlib1\compress2", "ptr", &Compressed, "UIntP", nSize, "ptr", &Data, "UInt", DataLen, "Int"
               , level    ;level 0 (no compression), 1 (best speed) - 9 (best compression)
               , "Cdecl") ;0 means Z_OK
return ErrorLevel ? 0 : nSize
} ;http://www.autohotkey.com/forum/viewtopic.php?t=68170

zlib_Decompress(Byref Decompressed, Byref CompressedData, DataLen, OriginalSize = -1) {
OriginalSize := (OriginalSize > 0) ? OriginalSize : DataLen*10 ;should be large enough for most cases
VarSetCapacity(Decompressed,OriginalSize)
ErrorLevel := DllCall("zlib1\uncompress", "Ptr", &Decompressed, "UIntP", OriginalSize, "Ptr", &CompressedData, "UInt", DataLen)
return ErrorLevel ? 0 : OriginalSize
} ;http://www.autohotkey.com/forum/viewtopic.php?t=68170

gz_compress(infilename, outfilename)
{
VarSetCapacity(sOutFileName, 260)
DllCall("WideCharToMultiByte", "Uint", 0, "Uint", 0, "str", outfilename, "int", -1, "str", sOutFileName, "int", 260, "Uint", 0, "Uint", 0)
infile := FileOpen(infilename, "r"), outfile := DllCall("zlib1\gzopen", "Str" , sOutFileName , "Str", "wb", "Cdecl")
if (!infile || !outfile) 
   return 0
nBufferLen := 8192 ; can be increased if gzbuffer function is called beforehand
VarSetCapacity(inbuffer,nBufferLen)
while ((num_read := infile.RawRead(inbuffer, nBufferLen)) > 0) 
   DllCall("zlib1\gzwrite", "UPtr", outfile, "UPtr", &inbuffer, "UInt", num_read, "Cdecl")
infile.Close()
DllCall("zlib1\gzclose", "UPtr", outfile, "Cdecl")
return 1
} ;http://www.autohotkey.com/forum/viewtopic.php?t=68170

gz_decompress(infilename, outfilename)
{
VarSetCapacity(sInFileName, 260)
DllCall("WideCharToMultiByte", "Uint", 0, "Uint", 0, "str", infilename, "int", -1, "str", sInFileName, "int", 260, "Uint", 0, "Uint", 0)
infile := DllCall("zlib1\gzopen", "Str" , sInFileName , "Str", "rb", "Cdecl"), outfile := FileOpen(outfilename, "w")
if (!infile || !outfile) 
   return 0
VarSetCapacity(buffer,8192) ;can be increased after calling gzbuffer beforehand
num_read = 0
while ((num_read := DllCall("zlib1\gzread", "UPtr", infile, "UPtr", &buffer, "UInt", 8192, "Cdecl")) > 0)
   outfile.RawWrite(buffer, num_read)
DllCall("zlib1\gzclose", "UPtr", infile, "Cdecl")
infile.Close()
return 1
} ;http://www.autohotkey.com/forum/viewtopic.php?t=68170

/*
Return codes for the compression/decompression functions. Negative values are errors, positive values are used for special but normal events.
#define Z_OK            0
#define Z_STREAM_END    1
#define Z_NEED_DICT     2
#define Z_ERRNO        (-1)
#define Z_STREAM_ERROR (-2)
#define Z_DATA_ERROR   (-3)
#define Z_MEM_ERROR    (-4)
#define Z_BUF_ERROR    (-5)
#define Z_VERSION_ERROR (-6)

Compression levels.
#define Z_NO_COMPRESSION         0
#define Z_BEST_SPEED             1
#define Z_BEST_COMPRESSION       9
#define Z_DEFAULT_COMPRESSION  (-1)
*/

Reference: <!-- m -->http://www.zlib.net/manual.html<!-- m -->
If i've seen further it is by standing on the shoulders of giants

my site | ~shajul | WYSIWYG BBCode Editor

David Andersen
  • Members
  • 140 posts
  • Last active: Jun 28 2011 04:54 PM
  • Joined: 15 Jul 2005
Hi,

Thank you for creating sharing. I am trying to test this on Autohotkey (not Autohotkey_L). I am, however, not getting any sensible results out of the following code:
zlib_Compress(Byref Compressed, Byref Data, DataLen, level = -1) {
nSize := DllCall("zlib1\compressBound", "UInt", DataLen, "Cdecl")
VarSetCapacity(Compressed,nSize)
ErrorLevel := DllCall("zlib1\compress2", "ptr", &Compressed, "UIntP", nSize, "ptr", &Data, "UInt", DataLen, "Int"
               , level    ;level 0 (no compression), 1 (best speed) - 9 (best compression)
               , "Cdecl") ;0 means Z_OK

return ErrorLevel ? 0 : nSize
} ;http://www.autohotkey.com/forum/viewtopic.php?t=68170

egg := "Eggers"
output := ""
error := zlib_Compress(output, egg, 100, 9) 
msgbox, -%output%- -%error%-

The output is:
-- -113-

I just have nothing to work with, as the output is simply empty, but there is no error. zlib1.dll is placed in the same directory.

shajul
  • Members
  • 571 posts
  • Last active: Aug 01 2015 03:45 PM
  • Joined: 15 Sep 2006

I am trying to test this on Autohotkey (not Autohotkey_L)


The "Ptr" type is not supported in Autohotkey basic, use "UInt" instead in the DllCall

Also note that the output is binary data. You cannot show binary data with MsgBox (as it is not a string).
You can save it to a file or a variable, and read it from file or variable and decompress the data. File standard library may be useful to you.

If you just want to deal with files, use any of my other archiving functions on this forum.
If i've seen further it is by standing on the shoulders of giants

my site | ~shajul | WYSIWYG BBCode Editor

David Andersen
  • Members
  • 140 posts
  • Last active: Jun 28 2011 04:54 PM
  • Joined: 15 Jul 2005
Hi shajul,

Thank you for your fast reply. I am too stupid to make it work with UInt, just replacing the Ptr with UInt did not do the trick. Since the output is binary data, I am also not sure whether this would be the right way to achieve what I want, which is to compress text and store it into a text file. I have found some code, which seems to be able to convert binary data into text data, but then the whole purpose might be lost, as it then might become longer than it was in the first place. What I want to store is XML data, which should have nice compression rates.

shajul
  • Members
  • 571 posts
  • Last active: Aug 01 2015 03:45 PM
  • Joined: 15 Sep 2006
If you want to compress xml files, then you can use 7zip library, which is the best compression and relatively good speed.

If you want to store data, you may use this library, but it'll be best if saved in a binary data file.
If i've seen further it is by standing on the shoulders of giants

my site | ~shajul | WYSIWYG BBCode Editor

Sam.
  • Members
  • 107 posts
  • Last active: Jul 15 2017 04:06 PM
  • Joined: 14 Nov 2008
Thank you very much for these functions shajul :) . The zlib_Compress, zlib_Compress2, and zlib_Decompress functions were no problem to convert to AHK Basic (non-unicode), and I have been using them over the past year. Because I am completely unfamiliar with AHK_L syntax or the differences between using Unicode strings, I am having trouble converting your gz_compress and gz_decompress to AHK Basic w/ Ansi. Would you (or anyone else who is more familiar with porting AHK_L to AHK Basic) mind doing it for me?

Thank you very much,
-Sam.

  • Guests
  • Last active:
  • Joined: --
this conversion is not required
DllCall("WideCharToMultiByte", "Uint", 0, "Uint", 0, "str", outfilename, "int", -1, "str", sOutFileName, "int", 260, "Uint", 0, "Uint", 0)
also some changes to the types in dllcall and you should be good!

Sam.
  • Members
  • 107 posts
  • Last active: Jul 15 2017 04:06 PM
  • Joined: 14 Nov 2008

this conversion is not required

DllCall("WideCharToMultiByte", "Uint", 0, "Uint", 0, "str", outfilename, "int", -1, "str", sOutFileName, "int", 260, "Uint", 0, "Uint", 0)
also some changes to the types in dllcall and you should be good!

I don't recognize the "." syntax in:
infile.RawRead(inbuffer, nBufferLen)
outfile.RawWrite(buffer, num_read)
I think it was added in AHK_L. I think these could be replaced by Laszlo's BinRead() and BinWrite() functions, but I think if you use them you no longer need to open and close the handle to the file with:
infile := FileOpen(infilename, "r")
infile.Close()
but then you no longer have infile to compare here:
if (!infile || !outfile)
   return 0
But I haven't been able to get them to work. So... My confusion is apparent :( .

Guest
  • Guests
  • Last active:
  • Joined: --
Anyone here? :|

Would need a guide on how to use the decompression function for a file.
To get the decompressed content.

Sam.
  • Members
  • 107 posts
  • Last active: Jul 15 2017 04:06 PM
  • Joined: 14 Nov 2008

Would need a guide on how to use the decompression function for a file.
To get the decompressed content.

The trick is when you compress a file, you need to save the original file size somewhere because the uncompress function call will need it later. A relatively common way of handling this (and the way I do it) is to store the uncompressed file size as part of the file format of the new compressed file. Specifically a 12 byte header starting with a 4 char array (the first 3 characters of the file's extension and "C" indicating it is has been compressed). Next a 4 char array indicating the version of the file format (this one is "V1 " - note there are 2 spaces after the "V1"). Next is a 4 byte (dword) that is the length of the uncompressed data. This header is followed by the zlib compressed data. An example of the usage of this file format structure can be found here.

These are the function I have written (for AHK Basic) to zlib (de)compress files:
zlib_Compress_File(Input0, Output0){
	If (Input0 = Output0)
		Return "Output and Input can not be the same."
	SplitPath, Input0, , , InExt
	StringLeft, InExt, InExt, 3
	StringUpper, InExt, InExt
	BinRead(Input0,version,8,0)
	If (InExt "CV1  " = version){
		FileCopy, %Input0%, %Output0%, 1
		Return "Input file is already compressed.  The file will just be copied to Output."
		}
	Header := InExt "CV1  "
	BinRead(Input0,MyData,0,0)
	FileGetSize, len, %Input0%
	HSize := Endian("4",len,"Hex")
	nSize := DllCall("zlib1\compressBound", "UInt", len, "Cdecl") ;required to get dest size
	VarSetCapacity(dest,nSize)
	IfExist, %Output0%
		FileDelete, %Output0%
	ErrorLevel := DllCall("zlib1\compress", "UInt", &dest, "UInt*", nSize, "UInt", &MyData, "UInt", len, "Cdecl") ;, "Int", 9
	BinWrite(Output0,Header,0,0)
	HexWrite(Output0,HSize,0,8)
	BinWrite(Output0,dest,nSize,12)
	Return ErrorLevel
	}

zlib_Decompress_File(Input0, Output0){
	If (Input0 = Output0)
		Return "Output and Input can not be the same."
	SplitPath, Input0, , , InExt
	SplitPath, Output0, , OutDir, , OutNameNoExt
	StringLeft, InExt, InExt, 3
	StringUpper, InExt, InExt
	BinRead(Input0,version,8,0)
	If ("CV1  " = SubStr(version, 4, 5))
		Output0 := OutDir "\" OutNameNoExt "." SubStr(version, 1, 3)
	Else
		{
		FileCopy, %Input0%, %Output0%, 1
		Return "Input file is not compressed.  The file will just be copied to Output."
		}
	HexRead(Input0,HSize,4,8)
	   OriginalSize := Endian("4",Hsize,"Dec")
	DataLen := BinRead(Input0,CompressedData,0,12)
	VarSetCapacity(Decompressed,OriginalSize)
	IfExist, %Output0%
	   FileDelete, %Output0%
	ErrorLevel := DllCall("zlib1\uncompress", "UInt", &Decompressed, "UInt*", OriginalSize, "UInt", &CompressedData, "UInt", DataLen, "Cdecl")
	BinWrite(Output0,Decompressed,OriginalSize,0)
	Return ErrorLevel
	}
In addition to zlib1.dll, these function also have the following dependencies:
/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; HexWrite ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|  - Open Hex file
|  - (Over)Write n bytes (n = 0: all)
|  - From offset (offset < 0: counted from end)
|  - Close file
|  data -> file[offset + 0..n-1], rest of file unchanged
|  Return #bytes actually written
*/ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

HexWrite(file, data, n=0, offset=0)
{
   ; Open file for WRITE (0x40..), OPEN_ALWAYS (4): creates only if it does not exists
   h := DllCall("CreateFile","str",file,"Uint",0x40000000,"Uint",0,"UInt",0,"UInt",4,"Uint",0,"UInt",0)
   IfEqual h,-1, SetEnv, ErrorLevel, -1
   IfNotEqual ErrorLevel,0,Return,0 ; couldn't create the file

   m = 0                            ; seek to offset
   IfLess offset,0, SetEnv,m,2
   r := DllCall("SetFilePointerEx","Uint",h,"Int64",offset,"UInt *",p,"Int",m)
   IfEqual r,0, SetEnv, ErrorLevel, -3
   IfNotEqual ErrorLevel,0, {
      t = %ErrorLevel%              ; save ErrorLevel to be returned
      DllCall("CloseHandle", "Uint", h)
      ErrorLevel = %t%              ; return seek error
      Return 0
   }

   TotalWritten = 0
   m := Ceil(StrLen(data)/2)
   If (n <= 0 or n > m)
       n := m
   Loop %n%
   {
      StringLeft c, data, 2         ; extract next byte
      StringTrimLeft data, data, 2  ; remove  used byte
      c = 0x%c%                     ; make it number
      result := DllCall("WriteFile","UInt",h,"UChar *",c,"UInt",1,"UInt *",Written,"UInt",0)
      TotalWritten += Written       ; count written
      if (!result or Written < 1 or ErrorLevel)
         break
   }

   IfNotEqual ErrorLevel,0, SetEnv,t,%ErrorLevel%

   h := DllCall("CloseHandle", "Uint", h)
   IfEqual h,-1, SetEnv, ErrorLevel, -2
   IfNotEqual t,,SetEnv, ErrorLevel, %t%

   Return TotalWritten
}

/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; HexRead ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|  - Open Hex file
|  - Read n bytes (n = 0: all)
|  - From offset (offset < 0: counted from end)
|  - Close file
|  data (replaced) <- file[offset + 0..n-1]
|  Return #bytes actually read
*/ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

HexRead(file, ByRef data, n=0, offset=0)
{
   h := DllCall("CreateFile","Str",file,"Uint",0x80000000,"Uint",3,"UInt",0,"UInt",3,"Uint",0,"UInt",0)
   IfEqual h,-1, SetEnv, ErrorLevel, -1
   IfNotEqual ErrorLevel,0,Return,0 ; couldn't open the file

   m = 0                            ; seek to offset
   IfLess offset,0, SetEnv,m,2
   r := DllCall("SetFilePointerEx","Uint",h,"Int64",offset,"UInt *",p,"Int",m)
   IfEqual r,0, SetEnv, ErrorLevel, -3
   IfNotEqual ErrorLevel,0, {
      t = %ErrorLevel%              ; save ErrorLevel to be returned
      DllCall("CloseHandle", "Uint", h)
      ErrorLevel = %t%              ; return seek error
      Return 0
   }

   TotalRead = 0
   data =
   IfEqual n,0, SetEnv n,0xffffffff ; almost infinite

   format = %A_FormatInteger%       ; save original integer format
   SetFormat Integer, Hex           ; for converting bytes to hex

   Loop %n%
   {
      result := DllCall("ReadFile","UInt",h,"UChar *",c,"UInt",1,"UInt *",Read,"UInt",0)
      if (!result or Read < 1 or ErrorLevel)
         break
      TotalRead += Read             ; count read
      c += 0                        ; convert to hex
      StringTrimLeft c, c, 2        ; remove 0x
      c = 0%c%                      ; pad left with 0
      StringRight c, c, 2           ; always 2 digits
      data = %data%%c%              ; append 2 hex digits
   }

   IfNotEqual ErrorLevel,0, SetEnv,t,%ErrorLevel%

   h := DllCall("CloseHandle", "Uint", h)
   IfEqual h,-1, SetEnv, ErrorLevel, -2
   IfNotEqual t,,SetEnv, ErrorLevel, %t%

   SetFormat Integer, %format%      ; restore original format
   Totalread += 0                   ; convert to original format
   Return TotalRead
}

/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BinWrite ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|  - Open binary file
|  - (Over)Write n bytes (n = 0: all)
|  - From offset (offset < 0: counted from end)
|  - Close file
|  (Binary)data -> file[offset + 0..n-1], rest of file unchanged
|  Return #bytes actually written
*/ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

BinWrite(file, ByRef data, n=0, offset=0)
{
   ; Open file for WRITE (0x40..), OPEN_ALWAYS (4): creates only if it does not exists
   h := DllCall("CreateFile","str",file,"Uint",0x40000000,"Uint",0,"UInt",0,"UInt",4,"Uint",0,"UInt",0)
   IfEqual h,-1, SetEnv, ErrorLevel, -1
   IfNotEqual ErrorLevel,0,Return,0 ; couldn't create the file

   m = 0                            ; seek to offset
   IfLess offset,0, SetEnv,m,2
   r := DllCall("SetFilePointerEx","Uint",h,"Int64",offset,"UInt *",p,"Int",m)
   IfEqual r,0, SetEnv, ErrorLevel, -3
   IfNotEqual ErrorLevel,0, {
      t = %ErrorLevel%              ; save ErrorLevel to be returned
      DllCall("CloseHandle", "Uint", h)
      ErrorLevel = %t%              ; return seek error
      Return 0
   }

   m := VarSetCapacity(data)        ; get the capacity ( >= used length )
   If (n < 1 or n > m)
       n := m
   result := DllCall("WriteFile","UInt",h,"Str",data,"UInt",n,"UInt *",Written,"UInt",0)
   if (!result or Written < n)
       ErrorLevel = -3
   IfNotEqual ErrorLevel,0, SetEnv,t,%ErrorLevel%

   h := DllCall("CloseHandle", "Uint", h)
   IfEqual h,-1, SetEnv, ErrorLevel, -2
   IfNotEqual t,,SetEnv, ErrorLevel, %t%-%ErrorLevel%

   Return Written
}

/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; BinRead ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|  - Open binary file
|  - Read n bytes (n = 0: file size)
|  - From offset (offset < 0: counted from end)
|  - Close file
|  (Binary)data (replaced) <- file[offset + 0..n-1]
|  Return #bytes actually read
*/ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

BinRead(file, ByRef data, n=0, offset=0)
{
   h := DllCall("CreateFile","Str",file,"Uint",0x80000000,"Uint",3,"UInt",0,"UInt",3,"Uint",0,"UInt",0)
   IfEqual h,-1, SetEnv, ErrorLevel, -1
   IfNotEqual ErrorLevel,0,Return,0 ; couldn't open the file

   m = 0                            ; seek to offset
   IfLess offset,0, SetEnv,m,2
   r := DllCall("SetFilePointerEx","Uint",h,"Int64",offset,"UInt *",p,"Int",m)
   IfEqual r,0, SetEnv, ErrorLevel, -3
   IfNotEqual ErrorLevel,0, {
      t = %ErrorLevel%              ; save ErrorLevel to be returned
      DllCall("CloseHandle", "Uint", h)
      ErrorLevel = %t%              ; return seek error
      Return 0
   }

   m := DllCall("GetFileSize","UInt",h,"Int64 *",r)
   If (n < 1 or n > m)
       n := m
   Granted := VarSetCapacity(data, n, 0)
   IfLess Granted,%n%, {
      ErrorLevel = Mem=%Granted%
      Return 0
   }

   result := DllCall("ReadFile","UInt",h,"Str",data,"UInt",n,"UInt *",Read,"UInt",0)

   if (!result or Read < n)
       t = -3
   IfNotEqual ErrorLevel,0, SetEnv,t,%ErrorLevel%

   h := DllCall("CloseHandle", "Uint", h)
   IfEqual h,-1, SetEnv, ErrorLevel, -2
   IfNotEqual t,,SetEnv, ErrorLevel, %t%-%ErrorLevel%

   Return Read
}

/* ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; Endian ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|  - converts an integer from big-endian hex <-> little-endian decimal
|  - Parameter one is the size:  "1"=byte, "2"=word, or "4"=dword
|  - Parameter two is the hex or decimal integer to convert
|  - Parameter three is the style:  "Dec"=convert a big-endian hex integer to a little-endian decimal integer.  "Hex"=convert a little-endian decimal integer into a big-endian hex integer.
|  -              "Dec_S"=convert a big-endian signed hex integer to a little-endian decimal integer.  "Hex_S"=convert a little-endian decimal integer into a big-endian signed hex integer.
*/ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

Endian(Esize, Evalue, Estyle)
   {
   IfEqual, Estyle, Dec   ;going to a traditional decimal style number in proper order
      {
      IfNotInString, Evalue, 0x
         Evalue = 0x%Evalue%
      IfEqual, Esize, 1
         Evalue := DllCall( "ntdll\RtlUshortByteSwap", UShort, Evalue "00", UShort ) + 0
      Else IfEqual, Esize, 2
         Evalue := DllCall( "ntdll\RtlUshortByteSwap", UShort, Evalue, UShort ) + 0
      Else IfEqual, Esize, 4
         Evalue := DllCall( "ntdll\RtlUlongByteSwap", UInt,Evalue, UInt ) + 0
      }
   Else IfEqual, Estyle, Hex    ;going to a hexadecimal in inverted order
      {
      SetFormat, IntegerFast, hex
      IfEqual, Esize, 1
         {
         VarSetCapacity(Var,4,0)         ; Variable to hold integer
         NumPut(Evalue,Var,0,"Int")   ; Input as 'Signed Integer'
         EValue := NumGet(Var,0,"UChar")   ; Retrieve it as 'Unsigned Character'
         StringReplace, Evalue, Evalue, 0x
         Evalue := SubStr("00" . Evalue, -1)
         }
      Else IfEqual, Esize, 2
         {
         Evalue := DllCall( "ntdll\RtlUshortByteSwap", Int, Evalue, UShort ) + 0
         StringReplace, Evalue, Evalue, 0x
         Evalue := SubStr("0000" . Evalue, -3)
         }
      Else IfEqual, Esize, 4
         {
         Evalue := DllCall( "ntdll\RtlUlongByteSwap", Int, Evalue, UInt ) + 0
         StringReplace, Evalue, Evalue, 0x
         Evalue := SubStr("00000000" . Evalue, -7)
         }
      }
   Else IfEqual, Estyle, Dec_S   ;going to a traditional SIGNED decimal style number in proper order
      {
      IfNotInString, Evalue, 0x
         Evalue = 0x%Evalue%
      IfEqual, Esize, 1
         Evalue := DllCall( "ntdll\RtlUshortByteSwap", Short, Evalue "00", Short ) + 0
      Else IfEqual, Esize, 2
         Evalue := DllCall( "ntdll\RtlUshortByteSwap", Short, Evalue, Short ) + 0
      Else IfEqual, Esize, 4
         Evalue := DllCall( "ntdll\RtlUlongByteSwap", Int, Evalue, Int ) + 0
      }
   Else IfEqual, Estyle, Hex_S    ;going to a SIGNED hexadecimal in inverted order
      {
      SetFormat, IntegerFast, hex
      IfEqual, Esize, 1
         {
         VarSetCapacity(Var,4,0)         ; Variable to hold integer
         NumPut(Evalue,Var,0,"Int")   ; Input as 'Signed Integer'
         EValue := NumGet(Var,0,"Char")   ; Retrieve it as 'Signed Character'
         StringReplace, Evalue, Evalue, 0x
         Evalue := SubStr("00" . Evalue, -1)
         }
      Else IfEqual, Esize, 2
         {
         Evalue := DllCall( "ntdll\RtlUshortByteSwap", Int, Evalue, Short ) + 0
         StringReplace, Evalue, Evalue, 0x
         Evalue := SubStr("0000" . Evalue, -3)
         }
      Else IfEqual, Esize, 4
         {
         Evalue := DllCall( "ntdll\RtlUlongByteSwap", Int, Evalue, Int ) + 0
         StringReplace, Evalue, Evalue, 0x
         Evalue := SubStr("00000000" . Evalue, -7)
         }
      }
   SetFormat, IntegerFast, D
   Return Evalue
   }


Guest
  • Guests
  • Last active:
  • Joined: --
Thanks for the help but where does the script know which file i want to decompress?
I can't find that in there.

The goal is to create a little 'tool' which will be in my program which automatically decompresses a file (the content isn't always the same), to get the infos so I can work on with that.

Should the path be Input0 or where?
Once again sorry for this noobness but I am starting to study the DDL stuffs :|

Sam.
  • Members
  • 107 posts
  • Last active: Jul 15 2017 04:06 PM
  • Joined: 14 Nov 2008

Thanks for the help but where does the script know which file i want to decompress?
I can't find that in there.

I should really start adding a whole lot more comments to my scripts, but oh well... Yes, Input0 and Output0 in the function calls are replaced with your input and output files. For example, if zlib1.dll is in the same directory as your script, you would compress and then decompress it using the following function calls:

zlib_Compress_File(A_ScriptDir "\zlib1.dll", A_ScriptDir "\Compressed.dll")

zlib_Decompress_File(A_ScriptDir "\Compressed.dll", A_ScriptDir "\Deompressed.dll")
Does that make sense?

Guest
  • Guests
  • Last active:
  • Joined: --
So based on your example, it should look like this since I want to decompress the test.w3g file with the zlib.ddl
zlib_Decompress_File(A_ScriptDir "\test.w3g", A_ScriptDir "\Deompressed.dll")
{
   If (Output0 = Input0) ; replacing these causes an error so I guess these are the taken variables from above?
      Return "Output and Input can not be the same."
   SplitPath, Input0, , , InExt
   SplitPath, Output0, , OutDir, , OutNameNoExt
   StringLeft, InExt, InExt, 3
   StringUpper, InExt, InExt
   BinRead(Input0,version,8,0)
   If ("CV1  " = SubStr(version, 4, 5))
      Output0 := OutDir "\" OutNameNoExt "." SubStr(version, 1, 3)
   Else
      {
      FileCopy, %Input0%, %Output0%, 1
      Return "Input file is not compressed.  The file will just be copied to Output."
      }
   HexRead(Input0,HSize,4,8)
      OriginalSize := Endian("4",Hsize,"Dec")
   DataLen := BinRead(Input0,CompressedData,0,12)
   VarSetCapacity(Decompressed,OriginalSize)
   IfExist, %Output0%
      FileDelete, %Output0%
   ErrorLevel := DllCall("zlib1\uncompress", "UInt", &Decompressed, "UInt*", OriginalSize, "UInt", &CompressedData, "UInt", DataLen, "Cdecl")
   BinWrite(Output0,Decompressed,OriginalSize,0)
   Return ErrorLevel
   }

Getting error: Error at line 1. Illegal parameter name.


Sorry if I am getting on your nerves :shock:

Sam.
  • Members
  • 107 posts
  • Last active: Jul 15 2017 04:06 PM
  • Joined: 14 Nov 2008

So based on your example, it should look like this since I want to decompress the test.w3g file with the zlib.ddl

Getting error: Error at line 1. Illegal parameter name.

Sorry if I am getting on your nerves :shock:

I don't mind :) . I recommend studying the AHK documentation on Functions.
; The following is the "function call".  Is is the actual command that sends your specified input and output files to the function (below) that actually performs the operations on them.
zlib_Decompress_File(A_ScriptDir "\test.w3g", A_ScriptDir "\Deompressed.dll")

; The following is the actual "function" that is called by the above command.  Don't change Input0 or Output0 to anything else.
zlib_Decompress_File(Input0, Output0){
   If (Input0 = Output0)
      Return "Output and Input can not be the same."
   SplitPath, Input0, , , InExt
   SplitPath, Output0, , OutDir, , OutNameNoExt
   StringLeft, InExt, InExt, 3
   StringUpper, InExt, InExt
   BinRead(Input0,version,8,0)
   If ("CV1  " = SubStr(version, 4, 5))
      Output0 := OutDir "\" OutNameNoExt "." SubStr(version, 1, 3)
   Else
      {
      FileCopy, %Input0%, %Output0%, 1
      Return "Input file is not compressed.  The file will just be copied to Output."
      }
   HexRead(Input0,HSize,4,8)
      OriginalSize := Endian("4",Hsize,"Dec")
   DataLen := BinRead(Input0,CompressedData,0,12)
   VarSetCapacity(Decompressed,OriginalSize)
   IfExist, %Output0%
      FileDelete, %Output0%
   ErrorLevel := DllCall("zlib1\uncompress", "UInt", &Decompressed, "UInt*", OriginalSize, "UInt", &CompressedData, "UInt", DataLen, "Cdecl")
   BinWrite(Output0,Decompressed,OriginalSize,0)
   Return ErrorLevel
   }
Note that this decompression function will ONLY work on files that have been compressed using the file format specifications that I outlined before (the one that my compression function uses). If you are trying to decompress raw zlib-compressed data (without the file header) with this function, it won't work.

Guest
  • Guests
  • Last active:
  • Joined: --
Error: Call to nonexistent function.
Specifically: BinRead(Input0,version,8,0)
:|