File: n_zlib.sru
Size: 61237
Date: Thu, 14 Jul 2022 19:38:04 +0200
$PBExportHeader$n_zlib.sru
forward
global type n_zlib from nonvisualobject
end type
type tm_zip from structure within n_zlib
end type
type zip_fileinfo from structure within n_zlib
end type
type filetime from structure within n_zlib
end type
type win32_find_data from structure within n_zlib
end type
type systemtime from structure within n_zlib
end type
type shfileinfo from structure within n_zlib
end type
type unz_fileinfo from structure within n_zlib
end type
end forward

type tm_zip from structure
   unsignedlong      tm_sec
   unsignedlong      tm_min
   unsignedlong      tm_hour
   unsignedlong      tm_mday
   unsignedlong      tm_mon
   unsignedlong      tm_year
end type

type zip_fileinfo from structure
   tm_zip      tmz_date
   unsignedlong      dosdate
   unsignedlong      internal_fa
   unsignedlong      external_fa
end type

type filetime from structure
   unsignedlong      dwlowdatetime
   unsignedlong      dwhighdatetime
end type

type win32_find_data from structure
   unsignedlong      dwfileattributes
   filetime    ftcreationtime
   filetime    ftlastaccesstime
   filetime    ftlastwritetime
   unsignedlong      nfilesizehigh
   unsignedlong      nfilesizelow
   unsignedlong      dwreserved0
   unsignedlong      dwreserved1
   character      cfilename[260]
   character      calternatefilename[14]
   unsignedlong      dwfiletype
   unsignedlong      dwcreatortype
   unsignedinteger      wfinderflags
end type

type systemtime from structure
   unsignedinteger      wyear
   unsignedinteger      wmonth
   unsignedinteger      wdayofweek
   unsignedinteger      wday
   unsignedinteger      whour
   unsignedinteger      wminute
   unsignedinteger      wsecond
   unsignedinteger      wmilliseconds
end type

type shfileinfo from structure
   longptr     hicon
   unsignedlong      iicon
   unsignedlong      dwattributes
   character      szdisplayname[260]
   character      sztypename[80]
end type

type unz_fileinfo from structure
   unsignedlong      version
   unsignedlong      version_needed
   unsignedlong      flag
   unsignedlong      compression_method
   unsignedlong      dosdate
   unsignedlong      crc
   unsignedlong      compressed_size
   unsignedlong      uncompressed_size
   unsignedlong      size_filename
   unsignedlong      size_file_extra
   unsignedlong      size_file_comment
   unsignedlong      disk_num_start
   unsignedlong      internal_fa
   unsignedlong      external_fa
   tm_zip      tmu_date
end type

global type n_zlib from nonvisualobject autoinstantiate
end type

type prototypes
// zlib functions

Function long compress ( &
   Ref blob dest, &
   Ref ulong destLen, &
   Ref blob source, &
   ulong sourceLen &
   ) Library "zlibwapi.dll"

Function long compress2 ( &
   Ref blob dest, &
   Ref ulong destLen, &
   Ref blob source, &
   ulong sourceLen, &
   long level &
   ) Library "zlibwapi.dll"

Function ulong crc32 ( &
   ulong crc, &
   Ref blob buf, &
   ulong len &
   ) Library "zlibwapi.dll"

Function long gzclose ( &
   longptr gzFile &
   ) Library "zlibwapi.dll"

Function longptr gzopen ( &
   string path, &
   string mode &
   ) Library "zlibwapi.dll" Alias For "gzopen;Ansi"

Function long gzread ( &
   longptr gzFile, &
   Ref blob data, &
   ulong dataLen &
   ) Library "zlibwapi.dll"

Function long gzwrite ( &
   longptr gzFile, &
   Ref blob buffer, &
   ulong uSizeBuf &
   ) Library "zlibwapi.dll"

Function long uncompress ( &
   Ref blob dest, &
   Ref ulong destLen, &
   Ref blob source, &
   ulong sourceLen &
   ) Library "zlibwapi.dll"

Function long unzClose ( &
   longptr unzFile &
   ) Library "zlibwapi.dll"

Function long unzCloseCurrentFile ( &
   longptr unzFile &
   ) Library "zlibwapi.dll"

Function long unzGetCurrentFileInfo ( &
   longptr unzFile, &
   Ref unz_fileinfo file_info, &
   Ref string szFileName, &
   ulong filenamesize, &
   Ref ulong extrafield, &
   ulong extrasize, &
   Ref string comment, &
   ulong cmtsize &
   ) Library "zlibwapi.dll" Alias For "unzGetCurrentFileInfo;Ansi"

Function long unzGetGlobalComment ( &
   longptr unzFile, &
   Ref string szComment, &
   ulong uSizeBuf &
   ) Library "zlibwapi.dll" Alias For "unzGetGlobalComment;Ansi"

Function long unzGoToFirstFile ( &
   longptr unzFile &
   ) Library "zlibwapi.dll"

Function long unzGoToNextFile ( &
   longptr unzFile &
   ) Library "zlibwapi.dll"

Function long unzLocateFile ( &
   longptr unzFile, &
   string szFileName, &
   long iCase &
   ) Library "zlibwapi.dll" Alias For "unzLocateFile;Ansi"

Function longptr unzOpen ( &
   string filename &
   ) Library "zlibwapi.dll" Alias For "unzOpen;Ansi"

Function long unzOpenCurrentFile ( &
   longptr unzFile &
   ) Library "zlibwapi.dll"

Function long unzOpenCurrentFilePassword ( &
   longptr unzFile, &
   Ref string password &
   ) Library "zlibwapi.dll" Alias For "unzOpenCurrentFilePassword;Ansi"

Function long unzReadCurrentFile ( &
   longptr unzFile, &
   Ref blob data, &
   ulong dataLen &
   ) Library "zlibwapi.dll"

Function long zipClose ( &
   longptr file, &
   Ref string global_comment &
   ) Library "zlibwapi.dll" Alias For "zipClose;Ansi"

Function long zipCloseFileInZip ( &
   longptr file &
   ) Library "zlibwapi.dll"

Function longptr zipOpen ( &
   Ref string pathname, &
   long append &
   ) Library "zlibwapi.dll" Alias For "zipOpen;Ansi"

Function long zipOpenNewFileInZip ( &
   longptr file, &
   Ref string filename, &
   Ref zip_fileinfo zipfi, &
   Ref long extrafield_local, &
   longptr size_extrafield_local, &
   Ref long extrafield_global, &
   longptr size_extrafield_global, &
   Ref string comment, &
   long method, &
   long level &
   ) Library "zlibwapi.dll" Alias For "zipOpenNewFileInZip;Ansi"

Function long zipOpenNewFileInZip3 ( &
   longptr file, &
   Ref string filename, &
   Ref zip_fileinfo zipfi, &
   Ref long extrafield_local, &
   longptr size_extrafield_local, &
   Ref long extrafield_global, &
   longptr size_extrafield_global, &
   Ref string comment, &
   long method, &
   long level, &
   long raw, &
   long windowBits, &
   long memLevel, &
   long strategy, &
   Ref string password, &
   ulong crcForCrypting &
   ) Library "zlibwapi.dll" Alias For "zipOpenNewFileInZip3;Ansi"

Function long zipWriteInFileInZip ( &
   longptr zipFile, &
   Ref blob buffer, &
   long uSizeBuf &
   ) Library "zlibwapi.dll"

Function string zlibVersion ( &
   ) Library "zlibwapi.dll" Alias For "zlibVersion;Ansi"

// Win API functions

Function ulong GetLastError( &
   ) Library "kernel32.dll"

Function ulong FormatMessage( &
   ulong dwFlags, &
   longptr lpSource, &
   ulong dwMessageId, &
   ulong dwLanguageId, &
   Ref string lpBuffer, &
   ulong nSize, &
   ulong Arguments &
   ) Library "kernel32.dll" Alias For "FormatMessageW"

Function boolean CloseHandle ( &
   longptr hObject &
   ) Library "kernel32.dll"
   
Function longptr CreateFile ( &
   string lpFileName, &
   ulong dwDesiredAccess, &
   ulong dwShareMode, &
   longptr lpSecurityAttributes, &
   ulong dwCreationDisposition, &
   ulong dwFlagsAndAttributes, &
   long hTemplateFile &
   ) Library "kernel32.dll" Alias For "CreateFileW"

Function boolean FileTimeToLocalFileTime ( &
   Ref filetime lpFileTime, &
   Ref filetime lpLocalFileTime &
   ) Library "kernel32.dll"

Function boolean FileTimeToSystemTime ( &
   Ref filetime lpFileTime, &
   Ref systemtime lpSystemTime &
   ) Library "kernel32.dll"

Function boolean FindClose ( &
   longptr handle &
   ) Library "kernel32.dll"

Function longptr FindFirstFile ( &
   Ref string filename, &
   Ref win32_find_data findfiledata &
   ) Library "kernel32.dll" Alias For "FindFirstFileW"

Function longptr FindMimeFromData ( &
   longptr pBC, &
   string pwzUrl, &
   blob pBuffer, &
   ulong cbSize, &
   longptr pwzMimeProposed, &
   ulong dwMimeFlags, &
   Ref longptr ppwzMimeOut, &
   ulong dwReserved &
   ) Library "urlmon.dll"

Function boolean FindNextFile ( &
   longptr handle, &
   Ref win32_find_data findfiledata &
   ) Library "kernel32.dll" Alias For "FindNextFileW"

Function boolean ReadFile ( &
   longptr hFile, &
   Ref blob lpBuffer, &
   ulong nNumberOfBytesToRead, &
   Ref ulong lpNumberOfBytesRead, &
   ulong lpOverlapped &
   ) Library "kernel32.dll"

Function ulong SHGetFileInfo ( &
   string pszPath, &
   ulong dwFileAttributes, &
   Ref SHFILEINFO psfi, &
   ulong cbFileInfo, &
   ulong uFlags &
   ) Library "shell32.dll" Alias For "SHGetFileInfoW"

end prototypes

type variables
String is_password

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

// compression levels
Constant Long Z_NO_COMPRESSION      = 0
Constant Long Z_BEST_SPEED          = 1
Constant Long Z_BEST_COMPRESSION    = 9
Constant Long Z_DEFAULT_COMPRESSION = -1

// compression strategy
Constant Long Z_FILTERED         = 1
Constant Long Z_HUFFMAN_ONLY     = 2
Constant Long Z_RLE              = 3
Constant Long Z_FIXED            = 4
Constant Long Z_DEFAULT_STRATEGY = 0

// Possible values of the data_type field
Constant Long Z_BINARY  = 0
Constant Long Z_TEXT    = 1
Constant Long Z_ASCII   = Z_TEXT
Constant Long Z_UNKNOWN = 2

// The deflate compression method (the only one supported in this version)
Constant Long Z_DEFLATED = 8

// Unzip constants
Constant Long UNZ_OK                   = 0
Constant Long UNZ_END_OF_LIST_OF_FILE  = -100
Constant Long UNZ_ERRNO                = Z_ERRNO
Constant Long UNZ_EOF                  = 0
Constant Long UNZ_PARAMERROR           = -102
Constant Long UNZ_BADZIPFILE           = -103
Constant Long UNZ_INTERNALERROR        = -104
Constant Long UNZ_CRCERROR             = -105

// Zip constants
Constant Long ZIP_OK             = 0
Constant Long ZIP_ERRNO          = Z_ERRNO
Constant Long ZIP_PARAMERROR     = -102
Constant Long ZIP_INTERNALERROR  = -104

// zipOpen
Constant Long APPEND_STATUS_CREATE        = 0
Constant Long APPEND_STATUS_CREATEAFTER   = 1
Constant Long APPEND_STATUS_ADDINZIP      = 2

// Utility constants
Constant Long DEF_MEM_LEVEL = 8
Constant Long MAX_WBITS = 15

// Constants for CreateFile API function
Constant Long  INVALID_HANDLE_VALUE = -1
Constant ULong GENERIC_READ      = 2147483648
Constant ULong GENERIC_WRITE     = 1073741824
Constant ULong FILE_SHARE_READ   = 1
Constant ULong FILE_SHARE_WRITE  = 2
Constant ULong CREATE_NEW        = 1
Constant ULong CREATE_ALWAYS     = 2
Constant ULong OPEN_EXISTING     = 3
Constant ULong OPEN_ALWAYS       = 4
Constant ULong TRUNCATE_EXISTING = 5

end variables

forward prototypes
public function longptr of_zipopen (string as_pathname, long al_append)
public function longptr of_zipopen (string as_pathname)
public function long of_zipclose (longptr al_zipfile, string as_comment)
public function long of_zipclosefileinzip (longptr al_zipfile)
public function string of_replaceall (string as_oldstring, string as_findstr, string as_replace)
public function long of_zipopennewfileinzip (longptr al_zipfile, string as_filename, string as_nameinzip, string as_comment, string as_password)
public function unsignedlong of_internal_fa (string as_filename)
public function string of_findmimefromdata (string as_filename, ref blob ablob_data)
public function long of_zipwriteinfileinzip (longptr al_zipfile, ref blob ablob_data)
public function long of_importfile (longptr al_zipfile, string as_filename, string as_nameinzip, string as_comment, string as_password)
public function long of_importfile (longptr al_zipfile, string as_filename, string as_nameinzip)
public function long of_zipopennewfileinzip (longptr al_zipfile, string as_filename, string as_nameinzip)
public function unsignedlong of_getfilecrc (string as_filename)
public function unsignedlong of_readfile (string as_filename, ref blob abl_filedata)
public function string of_zlibversion ()
public function string of_directory (string as_filename, boolean ab_subdir)
public function longptr of_unzopen (string as_filename)
public function long of_unzclose (longptr al_zipfile)
public function string of_unzgetglobalcomment (longptr al_zipfile)
public function long of_unzgotofirstfile (longptr al_zipfile)
public function long of_unzgotonextfile (longptr al_zipfile)
public function string of_getfiledescription (string as_filename)
public function boolean of_checkbit (unsignedlong aul_number, integer ai_bit)
public function long of_unzgetcurrentfileinfo (longptr al_zipfile, ref string as_fullname, ref string as_name, ref string as_path, ref string as_cmts, ref unsignedlong aul_usize, ref unsignedlong aul_csize, ref datetime adt_datetime, ref boolean ab_password, ref boolean ab_readonly, ref boolean ab_hidden, ref boolean ab_system, ref boolean ab_subdir, ref boolean ab_archive)
public subroutine of_setpassword (string as_password)
public function boolean of_extractblob (longptr al_zipfile, string as_filename, ref blob ablb_filedata)
public function boolean of_extractfile (longptr al_zipfile, string as_filename, string as_nameinzip)
public function boolean of_currentfilehaspassword (longptr al_zipfile)
public function boolean of_compress (blob ablob_source, ref blob ablob_dest)
public function boolean of_compress (string as_source, ref blob ablob_dest)
public function boolean of_uncompress (blob ablob_src, unsignedlong aul_destlen, ref blob ablob_dest)
public function boolean of_uncompress (blob ablob_src, unsignedlong aul_destlen, ref string as_dest)
public function long of_gzclose (longptr al_gzfile)
public function longptr of_gzopen (string as_path, string as_mode)
public function long of_gzread (longptr al_gzfile, ref blob ablob_data, unsignedlong aul_destlen)
public function long of_gzwrite (longptr al_gzfile, ref blob ablob_data)
public function boolean of_compress2 (blob ablob_source, ref blob ablob_dest, long al_level)
public function boolean of_compress2 (string as_source, ref blob ablob_dest, long al_level)
public function string of_getlasterror ()
public function long of_importblob (longptr al_zipfile, string as_filename, blob ablob_data)
public function long of_importfolder (longptr al_zipfile, string as_folder)
public function long of_importfolder (longptr al_zipfile, string as_folder, string as_subfolder)
end prototypes

public function longptr of_zipopen (string as_pathname, long al_append);// -----------------------------------------------------------------------------
// SCRIPT:     of_zipOpen
//
// PURPOSE:    This function opens a zip archive file.
//
// ARGUMENTS:  as_pathname - Full path filename of the zip archive file.
//             al_append   - One of these values:
//                APPEND_STATUS_CREATE
//                APPEND_STATUS_CREATEAFTER
//                APPEND_STATUS_ADDINZIP
//
// RETURN:     0 = Error, >0 = zipFile Handle
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial coding
// -----------------------------------------------------------------------------

Return zipOpen(as_pathname, al_append)

end function

public function longptr of_zipopen (string as_pathname);// -----------------------------------------------------------------------------
// SCRIPT:     of_zipOpen
//
// PURPOSE:    This function opens a zip archive file.
//
// ARGUMENTS:  as_pathname - Full path filename of the zip archive file.
//
// RETURN:     0 = Error, >0 = zipFile Handle
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial coding
// -----------------------------------------------------------------------------

Long ll_append

If FileExists(as_pathname) Then
   ll_append = APPEND_STATUS_ADDINZIP
Else
   ll_append = APPEND_STATUS_CREATE
End If

Return zipOpen(as_pathname, ll_append)

end function

public function long of_zipclose (longptr al_zipfile, string as_comment);// -----------------------------------------------------------------------------
// SCRIPT:     of_zipClose
//
// PURPOSE:    This function closes the zip archive file.
//
// ARGUMENTS:  al_zipfile  - Handle to open zip archive file.
//             as_comment  - Global comment for the zip archive file.
//
// RETURN:     0 = Success
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial coding
// -----------------------------------------------------------------------------

Return zipClose(al_zipfile, as_comment)

end function

public function long of_zipclosefileinzip (longptr al_zipfile);// -----------------------------------------------------------------------------
// SCRIPT:     of_zipCloseFileInZip
//
// PURPOSE:    This function closes a file being added to a zip archive file.
//
// ARGUMENTS:  al_zipfile  - Handle returned by of_zipOpen.
//
// RETURN:     0 = Success
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial coding
// -----------------------------------------------------------------------------

Return zipCloseFileInZip(al_zipfile)

end function

public function string of_replaceall (string as_oldstring, string as_findstr, string as_replace);// -----------------------------------------------------------------------------
// SCRIPT:     of_ReplaceAll
//
// PURPOSE:    This function replaces all occurrences of a string in another.
//
// ARGUMENTS:  as_oldstring   - The string to update
//             as_findstr     - The string to look for
//             as_replace     - The string to replace with
//
// RETURN:     The updated string
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial coding
// -----------------------------------------------------------------------------

Long ll_findstr, ll_replace, ll_pos
String ls_newstring

// get length of strings
ll_findstr = Len(as_findstr)
ll_replace = Len(as_replace)

// find first occurrence
ls_newstring = as_oldstring
ll_pos = Pos(ls_newstring, as_findstr)

Do While ll_pos > 0
   // replace old with new
   ls_newstring = Replace(ls_newstring, ll_pos, ll_findstr, as_replace)
   // find next occurrence
   ll_pos = Pos(ls_newstring, as_findstr, (ll_pos + ll_replace))
Loop

Return ls_newstring

end function

public function long of_zipopennewfileinzip (longptr al_zipfile, string as_filename, string as_nameinzip, string as_comment, string as_password);// -----------------------------------------------------------------------------
// SCRIPT:     of_zipOpenNewFileInZip
//
// PURPOSE:    This function opens a new file in the zip archive file.
//
// ARGUMENTS:  al_zipfile     - Handle to open zip archive file.
//             as_filename    - Full path name of file being added.
//             as_nameinzip   - Name of file within the zip file.
//             as_comment     - Comment for the file.
//             as_password    - Password for the file.
//
// RETURN:     0 = Success
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial coding
// -----------------------------------------------------------------------------

zip_fileinfo lstr_zipfi
WIN32_FIND_DATA lstr_fd
FILETIME lstr_ft
SYSTEMTIME lstr_st

Long ll_rc, ll_handle, ll_ExtraLocal, ll_ExtraGlobal
String ls_filename
ULong lul_crc

// Get the file information
ll_handle = FindFirstFile(as_filename, lstr_fd)
If ll_Handle <= 0 Then Return -1
FindClose(ll_handle)

// .zip standard is to use forward slash
ls_filename = of_ReplaceAll(as_nameinzip, "\", "/")

// Value of 1 indicates text file, 0 indicates binary
lstr_zipfi.internal_fa = of_Internal_FA(as_filename)

// get file attributes (Read-Only, Hidden, System, Archive)
lstr_zipfi.external_fa = lstr_fd.dwfileattributes

// convert create datetime to usable format
FileTimeToLocalFileTime(lstr_fd.ftLastWriteTime, lstr_ft)
FileTimeToSystemTime(lstr_ft, lstr_st)

// copy datetime to structure
lstr_zipfi.tmz_date.tm_mon  = lstr_st.wMonth - 1
lstr_zipfi.tmz_date.tm_mday = lstr_st.wDay
lstr_zipfi.tmz_date.tm_year = lstr_st.wYear
lstr_zipfi.tmz_date.tm_hour = lstr_st.wHour
lstr_zipfi.tmz_date.tm_min  = lstr_st.wMinute
lstr_zipfi.tmz_date.tm_sec  = lstr_st.wSecond

If as_password = "" Then
   ll_rc = zipOpenNewFileInZip(al_zipfile, ls_filename, &
                  lstr_zipfi, ll_ExtraLocal, 0, ll_ExtraGlobal, 0, &
                  as_comment, Z_DEFLATED, Z_DEFAULT_COMPRESSION)
Else
   lul_crc = of_GetFileCRC(as_filename)
   ll_rc = zipOpenNewFileInZip3(al_zipfile, ls_filename, &
                  lstr_zipfi, ll_ExtraLocal, 0, ll_ExtraGlobal, 0, &
                  as_comment, Z_DEFLATED, Z_DEFAULT_COMPRESSION, &
                  0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, &
                  as_password, lul_crc)
End If

Return ll_rc

end function

public function unsignedlong of_internal_fa (string as_filename);// -----------------------------------------------------------------------------
// SCRIPT:     of_Internal_FA
//
// PURPOSE:    This function will determine if the file is likely to be a
//             text file or a binary file.  This is used for the internal_fa
//             property when adding a file to a .zip archive.  It is only
//             for documentation, it doesn't need to be accurate.
//
// ARGUMENTS:  as_filename - The name of the file
//
// RETURN:     2=unknown, 1=text, 0=binary
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial coding
// -----------------------------------------------------------------------------

Longptr ll_file
ULong lul_bytes
String ls_mime
Blob lblob_filedata
Boolean lb_result

// open file for read
ll_file = CreateFile(as_filename, GENERIC_READ, &
               FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0)
If ll_file = INVALID_HANDLE_VALUE Then
   Return 2
End If

// allocate buffer space
lblob_filedata = Blob(Space(256), EncodingAnsi!)

// read first 256 bytes of the file
lb_result = ReadFile(ll_file, lblob_filedata, &
                     256, lul_bytes, 0)

// close the file
CloseHandle(ll_file)

// get the MIME Type
ls_mime = of_FindMimeFromData(as_filename, lblob_filedata)
If Lower(Left(ls_mime, 4)) = "text" Then
   Return 1
End If

Return 0

end function

public function string of_findmimefromdata (string as_filename, ref blob ablob_data);// -----------------------------------------------------------------------------
// SCRIPT:     of_FindMimeFromData
//
// PURPOSE:    This function is determines the file MIME type.
//
// ARGUMENTS:  as_filename - The name of the file
//             ablob_data  - Contents of the file
//
// RETURN:     MIME Type, Null=Failure
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial coding
// -----------------------------------------------------------------------------

Constant Long NOERROR = 0
Constant Long NULL = 0
Constant ULong FMFD_DEFAULT = 0
String ls_mimetype
LongPtr ll_ptr
Long ll_rtn

ll_rtn = FindMimeFromData(NULL, as_filename, ablob_data, &
            Len(ablob_data), NULL, FMFD_DEFAULT, ll_ptr, 0)

If ll_rtn = NOERROR Then
   ls_mimetype = String(ll_ptr, "address")
Else
   SetNull(ls_mimetype)
End If

Return ls_mimetype

end function

public function long of_zipwriteinfileinzip (longptr al_zipfile, ref blob ablob_data);// -----------------------------------------------------------------------------
// SCRIPT:     of_zipWriteInFileInZip
//
// PURPOSE:    This function will write a new file to the zip archive file.
//
// ARGUMENTS:  al_zipfile  -  Handle to open zip archive file.
//
// RETURN:     0 = Success
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial coding
// -----------------------------------------------------------------------------

Long ll_sizebuf

ll_sizebuf = Len(ablob_data)

Return zipWriteInFileInZip(al_zipfile, ablob_data, ll_sizebuf)

end function

public function long of_importfile (longptr al_zipfile, string as_filename, string as_nameinzip, string as_comment, string as_password);// -----------------------------------------------------------------------------
// SCRIPT:     of_ImportFile
//
// PURPOSE:    This function will add a new file to the zip archive file.
//
// ARGUMENTS:  al_zipfile     - Handle of currently open zip archive.
//             as_filename    - Name of file being added to archive.
//             as_nameinzip   - Name of the file within the zip file.
//             as_comment     - Comment for the file.
//             as_password    - Password for the file.
//
// RETURN:     0=Success
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Blob lbl_FileData
Long ll_rc

If of_ReadFile(as_filename, lbl_FileData) > 0 Then
   ll_rc = of_zipOpenNewFileInZip(al_zipFile, as_filename, &
                     as_nameinzip, as_comment, as_password)
   If ll_rc = 0 Then
      ll_rc = of_zipWriteInFileInZip(al_zipFile, lbl_FileData)
      ll_rc = of_zipCloseFileInZip(al_zipFile)
   End If
Else
   ll_rc = -1
End If

Return ll_rc

end function

public function long of_importfile (longptr al_zipfile, string as_filename, string as_nameinzip);// -----------------------------------------------------------------------------
// SCRIPT:     of_ImportFile
//
// PURPOSE:    This function will add a new file to the zip archive file.
//
// ARGUMENTS:  al_zipfile     - Handle of currently open zip archive.
//             as_filename    - Name of file being added to archive.
//             as_nameinzip   - Name of the file within the zip file.
//
// RETURN:     0=Success
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Return of_ImportFile(al_zipfile, as_filename, as_nameinzip, "", is_password)

end function

public function long of_zipopennewfileinzip (longptr al_zipfile, string as_filename, string as_nameinzip);// -----------------------------------------------------------------------------
// SCRIPT:     of_zipOpenNewFileInZip
//
// PURPOSE:    This function opens a new file in the zip archive file.
//
// ARGUMENTS:  al_zipfile     - Handle to open zip archive file.
//             as_filename    - Full path name of file being added.
//             as_nameinzip   - Name of file within the zip file.
//
// RETURN:     0 = Success
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial coding
// -----------------------------------------------------------------------------

Return of_zipOpenNewFileInZip(al_zipfile, as_filename, as_nameinzip, "", "")

end function

public function unsignedlong of_getfilecrc (string as_filename);// -----------------------------------------------------------------------------
// SCRIPT:     of_GetFileCRC
//
// PURPOSE:    This function calculates a files CRC32 value.
//
// ARGUMENTS:  as_filename - The name of the file
//
// RETURN:     CRC32 value, Zero=Failure
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

ULong lul_crc, lul_length
Blob lblob_buffer

lul_length = FileLength(as_filename)

If of_ReadFile(as_filename, lblob_buffer) > 0 Then
   lul_crc = crc32(lul_crc, lblob_buffer, lul_length);
Else
   lul_crc = 0
End If

Return lul_crc

end function

public function unsignedlong of_readfile (string as_filename, ref blob abl_filedata);// -----------------------------------------------------------------------------
// SCRIPT:     of_ReadFile
//
// PURPOSE:    This function reads a file into a blob.
//
// ARGUMENTS:  as_filename    - Name of the file
//             abl_filedata   - Contents of the file (byref)
//
// RETURN:     Length of the file or 0 for errors.
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Re-wrote to use Windows API functions
// -----------------------------------------------------------------------------

Blob lbl_buffer
Longptr ll_hFile
ULong lul_bytes, lul_length

// get file length
lul_length = FileLength(as_filename)

// allocate buffer space
lbl_buffer = Blob(Space((lul_length / 2) + 1))

// open file for read
ll_hFile = CreateFile(as_filename, GENERIC_READ, &
               FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0)
If ll_hFile = INVALID_HANDLE_VALUE Then
   Return 0
End If

// read the entire file contents in one shot
If ReadFile(ll_hFile, lbl_buffer, lul_length, lul_bytes, 0) Then
   abl_filedata = BlobMid(lbl_buffer, 1, lul_length)
Else
   lul_length = 0
End If

// close the file
CloseHandle(ll_hFile)

Return lul_length

end function

public function string of_zlibversion ();// -----------------------------------------------------------------------------
// SCRIPT:     of_ZlibVersion
//
// PURPOSE:    This function returns the version of Zlib.
//
// RETURN:     Version string
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

String ls_version

ls_version = Space(20)

ls_version = zlibVersion()

Return ls_version

end function

public function string of_directory (string as_filename, boolean ab_subdir);// -----------------------------------------------------------------------------
// SCRIPT:     of_Directory
//
// PURPOSE:    This function returns directory information about the
//             current file in the zip archive file.
//
// ARGUMENTS:  as_filename - The name of the file
//             ab_subdir   - Whether subdirectory entries should be returned
//
// RETURN:     Datawindow import string
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

DateTime ldt_datetime
Long ll_rc
Longptr ll_zipfile
ULong lul_usize, lul_csize
String ls_dwdata, ls_rowdata, ls_fullname
String ls_name, ls_path, ls_cmts, ls_attrib
Boolean lb_password, lb_readonly, lb_hidden
Boolean lb_system, lb_subdir, lb_archive

// open the zip archive
ll_zipfile = of_unzOpen(as_filename)

If ll_zipfile > 0 Then
   // walk thru each file in the zip archive
   ll_rc = of_unzGoToFirstFile(ll_zipfile)
   DO WHILE ll_rc = 0
      // get information about the file
      of_unzGetCurrentFileInfo(ll_zipfile, ls_fullname, ls_name, ls_path, &
               ls_cmts, lul_usize, lul_csize, ldt_datetime, lb_password, &
               lb_readonly, lb_hidden, lb_system, lb_subdir, lb_archive)
      // skip subdirectories if not needed
      If lb_subdir And Not ab_subdir Then
         ll_rc = of_unzGoToNextFile(ll_zipfile)
         Continue
      End If
      // build datawindow import string
      ls_rowdata  = Trim(ls_name) + "~t"
      If lb_subdir Then
         ls_rowdata += "Folder~t"
      Else
         ls_rowdata += of_GetFileDescription(ls_name) + "~t"
      End If
      ls_rowdata += String(ldt_datetime) + "~t"
      ls_rowdata += String(lul_usize) + "~t"
      If lul_usize = 0 Then
         ls_rowdata += "0~t"
      Else
         ls_rowdata += String(lul_csize / lul_usize) + "~t"
      End If
      ls_rowdata += String(lul_csize) + "~t"
      ls_attrib = ""
      If lb_readonly Then
         ls_attrib += "R"
      End If
      If lb_hidden Then
         ls_attrib += "H"
      End If
      If lb_system Then
         ls_attrib += "S"
      End If
      If lb_archive Then
         ls_attrib += "A"
      End If
      ls_rowdata += ls_attrib + "~t"
      If lb_password Then
         ls_rowdata += "Y~t"
      Else
         ls_rowdata += "N~t"
      End If
      ls_rowdata += ls_path + "~t"
      ls_rowdata += ls_fullname + "~t"
      ls_rowdata += ls_cmts + "~t"
      
      // add this row to the overall string
      If Len(ls_dwdata) = 0 Then
         ls_dwdata = ls_rowdata
      Else
         ls_dwdata = ls_dwdata + "~r~n" + ls_rowdata
      End If
      ll_rc = of_unzGoToNextFile(ll_zipfile)
   LOOP
   // close the zip archive
   of_unzClose(ll_zipfile)
End If

Return ls_dwdata

end function

public function longptr of_unzopen (string as_filename);// -----------------------------------------------------------------------------
// SCRIPT:     of_unzOpen
//
// PURPOSE:    This function will open the zip archive file for unzipping.
//
// ARGUMENTS:  as_filename - The name of the file
//
// RETURN:     Handle to open zip archive file
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Return unzOpen(as_filename)

end function

public function long of_unzclose (longptr al_zipfile);// -----------------------------------------------------------------------------
// SCRIPT:     of_unzClose
//
// PURPOSE:    This function will close the zip archive file.
//
// ARGUMENTS:  al_zipfile  - Handle to open zip archive file
//
// RETURN:     Zero=Success
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Return unzClose(al_zipfile)

end function

public function string of_unzgetglobalcomment (longptr al_zipfile);// -----------------------------------------------------------------------------
// SCRIPT:     of_unzGetGlobalComment
//
// PURPOSE:    This function returns the global comment for the file.
//
// ARGUMENTS:  al_zipfile  - Handle to open zip archive file
//
// RETURN:     The comment string
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

String ls_comment
Ulong lul_sizebuf
Long ll_rc

lul_sizebuf = 500
ls_comment = Space(lul_sizebuf)

ll_rc = unzGetGlobalComment(al_zipfile, ls_comment, lul_sizebuf)

Return ls_comment

end function

public function long of_unzgotofirstfile (longptr al_zipfile);// -----------------------------------------------------------------------------
// SCRIPT:     of_unzGotoFirstFile
//
// PURPOSE:    This function makes the first file in the zip archive
//             the current file.
//
// ARGUMENTS:  al_zipfile  - Handle to open zip archive file
//
// RETURN:     Zero=Success
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Return unzGoToFirstFile(al_zipfile)

end function

public function long of_unzgotonextfile (longptr al_zipfile);// -----------------------------------------------------------------------------
// SCRIPT:     of_unzGotoNextFile
//
// PURPOSE:    This function makes the next file in the zip archive
//             the current file.
//
// ARGUMENTS:  al_zipfile  - Handle to open zip archive file
//
// RETURN:     Zero=Success
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Return unzGoToNextFile(al_zipfile)

end function

public function string of_getfiledescription (string as_filename);// -----------------------------------------------------------------------------
// SCRIPT:     of_GetFileDescription
//
// PURPOSE:    This function returns the file description used by Win Explorer.
//
// ARGUMENTS:  as_filename - The name of the file
//
// RETURN:     Description
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Constant ULong SHGFI_ICON = 256 
Constant ULong SHGFI_DISPLAYNAME = 512
Constant ULong SHGFI_TYPENAME = 1024
Constant ULong SHGFI_USEFILEATTRIBUTES = 16

Environment le_env
SHFILEINFO lstr_SFI
String ls_typename
ULong lul_SizeOf, lul_return

GetEnvironment(le_env)
If le_env.ProcessBitness = 32 Then
   lul_SizeOf = 692
Else
   lul_SizeOf = 696
End If

lul_return = SHGetFileInfo(as_filename, 0, lstr_SFI, &
               lul_SizeOf, SHGFI_TYPENAME + SHGFI_USEFILEATTRIBUTES)
If lul_return = 1 Then
   ls_typename = String(lstr_SFI.szTypeName)
End If

Return ls_typename

end function

public function boolean of_checkbit (unsignedlong aul_number, integer ai_bit);// -----------------------------------------------------------------------------
// SCRIPT:     of_Checkbit
//
// PURPOSE:    This function determines if a certain bit is on or off within
//             the number.
//
// ARGUMENTS:  aul_number  - Number to check bits
//             ai_bit      - Bit number ( starting at 1 )
//
// RETURN:     True = On, False = Off
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial Coding
// -----------------------------------------------------------------------------

If Int(Mod(aul_number / (2 ^(ai_bit - 1)), 2)) > 0 Then
   Return True
End If

Return False

end function

public function long of_unzgetcurrentfileinfo (longptr al_zipfile, ref string as_fullname, ref string as_name, ref string as_path, ref string as_cmts, ref unsignedlong aul_usize, ref unsignedlong aul_csize, ref datetime adt_datetime, ref boolean ab_password, ref boolean ab_readonly, ref boolean ab_hidden, ref boolean ab_system, ref boolean ab_subdir, ref boolean ab_archive);// -----------------------------------------------------------------------------
// SCRIPT:     of_unzGetCurrentFileInfo
//
// PURPOSE:    This function returns directory information about the
//             current file in the zip archive file.
//
// ARGUMENTS:  al_zipfile  - Handle to open zip archive file
//
// RETURN:     Zero=Success
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

unz_fileinfo lstr_info
Long ll_rc, ll_pos
String ls_temp
ULong lul_fname, lul_extraptr, lul_extra, lul_cmts
Date ld_date
Time lt_time

// initialize buffers
lul_fname = 260
as_fullname = Space(lul_fname)
lul_cmts  = 520
as_cmts   = Space(lul_cmts)

// get file info
ll_rc = unzGetCurrentFileInfo(al_zipfile, lstr_info, as_fullname, &
               lul_fname, lul_extraptr, lul_extra, as_cmts, lul_cmts)
If ll_rc <> UNZ_OK Then
   Return ll_rc
End If

// extract filename/filepath from full path
ls_temp = "\" + this.of_ReplaceAll(as_fullname, "/", "\")
If Right(ls_temp, 1) = "\" Then
   ls_temp = Left(ls_temp, Len(ls_temp) - 1)
End If
ll_pos = LastPos(ls_temp, "\")
as_name = Mid(ls_temp, ll_pos + 1)
as_path = Mid(Left(ls_temp, ll_pos), 2)

// file size
aul_usize = lstr_info.uncompressed_size
aul_csize = lstr_info.compressed_size

// build datetime
ld_date = Date(lstr_info.tmu_date.tm_year, &
               lstr_info.tmu_date.tm_mon + 1, &
               lstr_info.tmu_date.tm_mday)
lt_time = Time(lstr_info.tmu_date.tm_hour, &
               lstr_info.tmu_date.tm_min, &
               lstr_info.tmu_date.tm_sec)
adt_datetime = DateTime(ld_date, lt_time)

// has a password?
ab_password = of_CheckBit(lstr_info.flag, 1)

// file attributes
ab_readonly = of_CheckBit(lstr_info.external_fa, 1)
ab_hidden   = of_CheckBit(lstr_info.external_fa, 2)
ab_system   = of_CheckBit(lstr_info.external_fa, 3)
ab_subdir   = of_CheckBit(lstr_info.external_fa, 5)
ab_archive  = of_CheckBit(lstr_info.external_fa, 6)

Return ll_rc

end function

public subroutine of_setpassword (string as_password);// -----------------------------------------------------------------------------
// SCRIPT:     of_SetPassword
//
// PURPOSE:    This function sets the password.
//
// ARGUMENTS:  as_password - Password to save
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 03/26/2008  RolandS     Initial creation
// -----------------------------------------------------------------------------

is_password = as_password

end subroutine

public function boolean of_extractblob (longptr al_zipfile, string as_filename, ref blob ablb_filedata);return true

end function

public function boolean of_extractfile (longptr al_zipfile, string as_filename, string as_nameinzip);// -----------------------------------------------------------------------------
// SCRIPT:     of_ExtractFile
//
// PURPOSE:    This function will extract a file from the zip archive and
//             save it to disk.  The zip archive must have already been
//             opened using the using the of_unzOpen function.
//
// ARGUMENTS:  al_zipfile     - Handle of currently open zip archive
//             as_filename    - Name of file being extracted from archive
//             as_nameinzip   - Name of the file within the zip file
//
// RETURN:     True=Success, False=Error
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Integer li_fnum
Long ll_rc
Blob lblob_data
ULong lul_datalen

// locate the file within the archive
If Len(as_filename) > 0 Then
   ll_rc = unzLocateFile(al_zipfile, as_nameinzip, 2) // 2=Case Insensitive
   If ll_rc < 0 Then
      Return False
   End If
End If

// if file has password and none given, display error
If of_CurrentFileHasPassword(al_zipfile) Then
   If is_password = "" Then
      Return False
   End If
End If

// open the current file
If is_password = "" Then
   ll_rc = unzOpenCurrentFile(al_zipfile)
   If ll_rc < 0 Then
      Return False
   End If
Else
   ll_rc = unzOpenCurrentFilePassword(al_zipfile, is_password)
   If ll_rc < 0 Then
      Return False
   End If
End If

// allocate buffer space
lul_datalen = 8192
lblob_data = Blob(Space(lul_datalen))

// open file
li_fnum = FileOpen(as_filename, StreamMode!, Write!, LockReadWrite!, Replace!)
If li_fnum > 0 Then
   // read file 8k bytes at a time until done
   ll_rc = unzReadCurrentFile(al_zipfile, lblob_data, lul_datalen)
   If ll_rc < 0 Then
      FileClose(li_fnum)
      Return False
   End If
   DO WHILE ll_rc > 0
      // write data to file
      ll_rc = FileWrite(li_fnum, BlobMid(lblob_data, 1, ll_rc))
      // read next 8k bytes
      ll_rc = unzReadCurrentFile(al_zipfile, lblob_data, lul_datalen)
   LOOP
   // close file
   FileClose(li_fnum)
Else
   Return False
End If

// close the current file
ll_rc = unzCloseCurrentFile(al_zipfile)

Return True

end function

public function boolean of_currentfilehaspassword (longptr al_zipfile);// -----------------------------------------------------------------------------
// SCRIPT:     of_CurrentFileHasPassword
//
// PURPOSE:    This function determines if the current file has a password.
//
// ARGUMENTS:  al_zipfile  - Handle to open zip archive file
//
// RETURN:     True=password, False=no password
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

unz_fileinfo lstr_info
Long ll_rc
String ls_fullname, ls_cmts
ULong lul_fname, lul_extraptr, lul_extra, lul_cmts

// initialize buffers
lul_fname = 260
ls_fullname = Space(lul_fname)
lul_cmts  = 520
ls_cmts   = Space(lul_cmts)

// get file info
ll_rc = unzGetCurrentFileInfo(al_zipfile, lstr_info, ls_fullname, &
               lul_fname, lul_extraptr, lul_extra, ls_cmts, lul_cmts)

// check for password
Return of_CheckBit(lstr_info.flag, 1)

end function

public function boolean of_compress (blob ablob_source, ref blob ablob_dest);// -----------------------------------------------------------------------------
// SCRIPT:     of_Compress
//
// PURPOSE:    This function will compress the passed blob.
//
// ARGUMENTS:  ablob_source   -  Input blob variable
//             ablob_dest     -  Output blob variable
//
// RETURN:     True=Success, False=Failure
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Long ll_rc
ULong lul_srclen, lul_destlen
Blob lblob_dest

// allocate buffer space
lul_srclen  = Len(ablob_source)
lul_destlen = (lul_srclen * 1.01) + 12  // zlib needs a little extra room
lblob_dest = Blob(Space(lul_destlen))

// compress the blob
ll_rc = compress(lblob_dest, lul_destlen, ablob_source, lul_srclen)
If ll_rc = Z_OK Then
   ablob_dest = BlobMid(lblob_dest, 1, lul_destlen)
Else
   SetNull(ablob_dest)
   Return False
End If

Return True

end function

public function boolean of_compress (string as_source, ref blob ablob_dest);// -----------------------------------------------------------------------------
// SCRIPT:     of_Compress
//
// PURPOSE:    This function will compress the passed string.
//
// ARGUMENTS:  as_source   -  Input string variable
//             ablob_dest  -  Output blob variable
//
// RETURN:     True=Success, False=Failure
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Blob lblob_src

// convert string to blob
lblob_src  = Blob(as_source)

Return of_Compress(lblob_src, ablob_dest)

end function

public function boolean of_uncompress (blob ablob_src, unsignedlong aul_destlen, ref blob ablob_dest);// -----------------------------------------------------------------------------
// SCRIPT:     of_Uncompress
//
// PURPOSE:    This function will uncompress the passed blob to a blob.
//
// ARGUMENTS:  ablob_source   -  Input blob variable
//             aul_destlen    -  Original length of the input
//             ablob_dest     -  Output blob variable
//
// RETURN:     True=Success, False=Failure
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Long ll_rc
ULong lul_destlen, lul_srclen
Blob lblob_dest

// allocate buffer space
lblob_dest = Blob(Space(aul_destlen))
lul_destlen = Len(lblob_dest)
lul_srclen  = Len(ablob_src)

// uncompress the blob
ll_rc = uncompress(lblob_dest, lul_destlen, ablob_src, lul_srclen)
If ll_rc = Z_OK Then
   ablob_dest = BlobMid(lblob_dest, 1, aul_destlen)
Else
   SetNull(ablob_dest)
   Return False
End If

Return True

end function

public function boolean of_uncompress (blob ablob_src, unsignedlong aul_destlen, ref string as_dest);// -----------------------------------------------------------------------------
// SCRIPT:     of_Uncompress
//
// PURPOSE:    This function will uncompress the passed blob to a blob.
//
// ARGUMENTS:  ablob_source   -  Input blob variable
//             aul_destlen    -  Original length of the input
//             ablob_dest     -  Output blob variable
//
// RETURN:     True=Success, False=Failure
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Blob lblob_dest

// allocate buffer space
lblob_dest = Blob(Space(aul_destlen))

If of_Uncompress(ablob_src, Len(lblob_dest), lblob_dest) Then
   as_dest = String(lblob_dest)
   Return True
Else
   as_dest = ""
End If

Return False

end function

public function long of_gzclose (longptr al_gzfile);// -----------------------------------------------------------------------------
// SCRIPT:     of_gzClose
//
// PURPOSE:    This function will close the gzip archive file.
//
// ARGUMENTS:  aul_unzfile - Handle to open gzip archive file
//
// RETURN:     Zero=Success
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Return gzclose(al_gzfile)

end function

public function longptr of_gzopen (string as_path, string as_mode);// -----------------------------------------------------------------------------
// SCRIPT:     of_gzOpen
//
// PURPOSE:    This function will open the gzipped file.
//
// ARGUMENTS:  as_filename - The name of the file
//             as_mode     - The mode for opening the file:
//                            rb (=read binary) / wb (=write binary)
//
// RETURN:     Handle to open gzip archive file
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Return gzopen(as_path, as_mode)

end function

public function long of_gzread (longptr al_gzfile, ref blob ablob_data, unsignedlong aul_destlen);// -----------------------------------------------------------------------------
// SCRIPT:     of_gzRead
//
// PURPOSE:    This function uncompresses the current file in the gzip archive
//             file and places it in a blob variable.
//
// ARGUMENTS:  al_gzfile      -  Handle to open gzip archive file.
//             ablob_data     -  Blob to contain file (output).
//             aul_destlen    -  The buffer size for uncompressed data
//
// RETURN:     the size of read data
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Blob lblob_data
Long ll_rc, ll_total
ULong lul_next, lul_datalen

// allocate buffer space
lul_datalen = 8192
lblob_data = Blob(Space(lul_datalen))
ablob_data = Blob(Space(aul_destlen))
lul_next = 1

// read file 8k bytes at a time until done
ll_rc = gzread(al_gzfile, lblob_data, lul_datalen)
DO WHILE ll_rc > 0
   ll_total += ll_rc
   // concatenate to output blob
   lul_next = BlobEdit(ablob_data, lul_next, BlobMid(lblob_data, 1, ll_rc))
   // read next 8k bytes
   ll_rc = gzRead(al_gzfile, lblob_data, lul_datalen)
LOOP
ll_total += ll_rc

Return ll_total

end function

public function long of_gzwrite (longptr al_gzfile, ref blob ablob_data);// -----------------------------------------------------------------------------
// SCRIPT:     of_gzWrite
//
// PURPOSE:    This function will write into a gzip file
//
// ARGUMENTS:  al_zipfile  -  Handle to open gzip archive file.
//             ablob_data  -  the data to write
//
// RETURN:     Zero=Success
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Integer ll_rc
Long ll_sizebuf

ll_sizebuf = Len(ablob_data)

ll_rc = gzwrite(al_gzfile, ablob_data, ll_sizebuf)

Return ll_rc

end function

public function boolean of_compress2 (blob ablob_source, ref blob ablob_dest, long al_level);// -----------------------------------------------------------------------------
// SCRIPT:     of_Compress2
//
// PURPOSE:    This function will compress the passed blob using the
//             requested compression level.
//
// ARGUMENTS:  ablob_source   -  Input blob variable
//             ablob_dest     -  Output blob variable
//             al_level       -  Compression level
//                                  Z_NO_COMPRESSION
//                                  Z_BEST_SPEED
//                                  Z_BEST_COMPRESSION
//                                  Z_DEFAULT_COMPRESSION
//
// RETURN:     True=Success, False=Failure
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Long ll_rc
ULong lul_srclen, lul_destlen
Blob lblob_dest

// allocate buffer space
lul_srclen  = Len(ablob_source)
lul_destlen = (lul_srclen * 1.01) + 12  // zlib needs a little extra room
lblob_dest = Blob(Space(lul_destlen))

// compress the blob
ll_rc = compress2(lblob_dest, lul_destlen, ablob_source, lul_srclen, al_level)
If ll_rc = Z_OK Then
   ablob_dest = BlobMid(lblob_dest, 1, lul_destlen)
Else
   SetNull(ablob_dest)
   Return False
End If

Return True

end function

public function boolean of_compress2 (string as_source, ref blob ablob_dest, long al_level);// -----------------------------------------------------------------------------
// SCRIPT:     of_Compress2
//
// PURPOSE:    This function will compress the passed string using the
//             requested compression level.
//
// ARGUMENTS:  ablob_source   -  Input blob variable
//             ablob_dest     -  Output blob variable
//             al_level       -  Compression level
//                                  Z_NO_COMPRESSION
//                                  Z_BEST_SPEED
//                                  Z_BEST_COMPRESSION
//                                  Z_DEFAULT_COMPRESSION
//
// RETURN:     True=Success, False=Failure
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Blob lblob_src

// convert string to blob
lblob_src  = Blob(as_source)

Return of_Compress2(lblob_src, ablob_dest, al_level)

end function

public function string of_getlasterror ();// -----------------------------------------------------------------------------
// SCRIPT:     of_GetLastError
//
// PURPOSE:    This function returns the last Windows API error.
//
// RETURN:     Error message text
//
// DATE        CHANGED BY  DESCRIPTION OF CHANGE / REASON
// ----------  ----------  -----------------------------------------------------
// 06/23/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Constant ULong FORMAT_MESSAGE_FROM_SYSTEM = 4096
Constant ULong LANG_NEUTRAL = 0
String ls_buffer, ls_errmsg
ULong lul_error

lul_error = GetLastError()

ls_buffer = Space(255)

FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, &
      lul_error, LANG_NEUTRAL, ls_buffer, 255, 0)

ls_errmsg = "Error# " + String(lul_error) + "~r~n~r~n" + ls_buffer

Return ls_errmsg

end function

public function long of_importblob (longptr al_zipfile, string as_filename, blob ablob_data);// -----------------------------------------------------------------------------
// SCRIPT:     of_ImportBlob
//
// PURPOSE:    This function will add a new blob to the zip archive file.
//
// ARGUMENTS:  al_zipfile  - Handle of currently open zip archive
//             as_filename - Name of file being added to archive
//             ablob_data  - Blob data to be imported
//
// RETURN:     0=Success
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

zip_fileinfo lstr_zipfi
String ls_comment
Long ll_rc, ll_ExtraLocal, ll_ExtraGlobal
ULong lul_crc

lstr_zipfi.tmz_date.tm_mon  = Month(Today()) - 1
lstr_zipfi.tmz_date.tm_mday = Day(Today())
lstr_zipfi.tmz_date.tm_year = Year(Today())
lstr_zipfi.tmz_date.tm_hour = Hour(Now())
lstr_zipfi.tmz_date.tm_min  = Minute(Now())
lstr_zipfi.tmz_date.tm_sec  = Second(Now())

If is_password = "" Then
   ll_rc = zipOpenNewFileInZip(al_zipfile, as_filename, &
                  lstr_zipfi, ll_ExtraLocal, 0, ll_ExtraGlobal, 0, &
                  ls_comment, Z_DEFLATED, Z_DEFAULT_COMPRESSION)
Else
   lul_crc = of_GetFileCRC(as_filename)
   ll_rc = zipOpenNewFileInZip3(al_zipfile, as_filename, &
                  lstr_zipfi, ll_ExtraLocal, 0, ll_ExtraGlobal, 0, &
                  ls_comment, Z_DEFLATED, Z_DEFAULT_COMPRESSION, &
                  0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, &
                  is_password, lul_crc)
End If

If ll_rc = 0 Then
   ll_rc = this.of_zipWriteInFileInZip(al_zipFile, ablob_data)
   ll_rc = this.of_zipCloseFileInZip(al_zipFile)
End If

Return ll_rc

end function

public function long of_importfolder (longptr al_zipfile, string as_folder);// -----------------------------------------------------------------------------
// SCRIPT:     of_ImportFolder
//
// PURPOSE:    This function will add all the files within a folder
//             to the zip archive file.
//
// ARGUMENTS:  al_zipfile  - Handle of currently open zip archive
//             as_folder   - Name of folder being added to archive
//
// RETURN:     0=Success
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

Return of_ImportFolder(al_zipfile, as_folder, "")

end function

public function long of_importfolder (longptr al_zipfile, string as_folder, string as_subfolder);// -----------------------------------------------------------------------------
// SCRIPT:     of_ImportFolder
//
// PURPOSE:    This function will add all the files within a folder
//             to the zip archive file.
//
// ARGUMENTS:  al_zipfile     - Handle of currently open zip archive
//             as_folder      - Name of folder being added to archive
//             as_subfolder   - Subfolder name when called recursively
//
// RETURN:     0=Success
//
// DATE        PROG/ID     DESCRIPTION OF CHANGE / REASON
// ----------  --------    -----------------------------------------------------
// 04/16/2022  RolandS     Initial creation
// -----------------------------------------------------------------------------

win32_find_data lstr_fd
Long ll_Handle
Boolean lb_found, lb_subdir
String ls_filespec, ls_nameinzip, ls_filename

// append filename pattern
If as_subfolder = "" Then
   ls_filespec = as_folder + "\*.*"
Else
   ls_filespec = as_folder + "\" + as_subfolder + "\*.*"
End If

// find first file
ll_Handle = FindFirstFile(ls_filespec, lstr_fd)
If ll_Handle < 1 Then Return -1

// loop through each file
Do
   ls_nameinzip = String(lstr_fd.cFilename)
   If ls_nameinzip = "." Or ls_nameinzip = ".." Then
   Else
      If as_subfolder <> "" Then
         ls_nameinzip = as_subfolder + "\" + ls_nameinzip
      End If
      lb_subdir = of_checkbit(lstr_fd.dwFileAttributes, 5)
      If lb_subdir Then
         // recursively call self to process subfolder
         of_ImportFolder(al_zipfile, as_folder, ls_nameinzip)
      Else
         // add file to the zipfile
         ls_filename = as_folder + "\" + ls_nameinzip
         of_ImportFile(al_zipFile, ls_filename, ls_nameinzip)
      End If
   End If
   // find next file
   lb_Found = FindNextFile(ll_Handle, lstr_fd)
Loop Until Not lb_Found

// close find handle
FindClose(ll_Handle)

Return 0

end function

on n_zlib.create
call super::create
TriggerEvent( this, "constructor" )
end on

on n_zlib.destroy
TriggerEvent( this, "destructor" )
call super::destroy
end on