# Monday, December 01, 2008

VFPCompression Update
This update contains a fix that effects the Unzip routines and a new function called ZipComment(). I've also updated the sample code and documentation that is provided with this library.

The bug that was fixed pertained to 0 byte (length) files were being ignored when a zip file's contents were extracted. The Zip routines were handling the 0 byte length files correctly.

The ZipComment() function allows you to add, replace or delete the global zipfile comment for a specified zip file. The code at the bottom of this blog entry shows an example of its use and the documentation now includes this function.

Special Thank You
Special thanks goes out to Mike Sue-Ping who posted out on the Universal Thread about the bug that is fixed in this update.

What's Next
I still plan to add more functionality to this FLL (ability to create cabs and self-extracting archives, better error handling, etc.). I'm hopeful that those of you that download this library will take the time to provide me feedback and any suggestions you may have for further improving it. If you do find a bug, please comment on it here and/or contact me directly. Note the "Contact Craig Boyd" link to the right of this blog entry.

Until next time... Visual FoxPro Rocks!

VFP Compression Update:

VFPCompression FLL Download (37 KB approx.)

VFP Compression Sample Code:

****************************
*!* Example 1
****************************
*!* Zip a file quickly with or without password protection.
****************************
SET LIBRARY TO LOCFILE("vfpcompression.fll")
?ZipFileQuick("C:\MyFile1.txt")
?ZipFileQuick("C:\MyFile2.txt", "MyPassword")
SET LIBRARY TO

****************************
*!* Example 2
****************************
*!* Zip a folder quickly with or without respect
*!* for relative pathing of the files. Password
*!* protection can be included if desired.
****************************
SET LIBRARY TO LOCFILE("vfpcompression.fll")
?ZipFolderQuick("C:\MyFolder")
?ZipFolderQuick("C:\MyFolder2", .T., "MyPassword")
?ZipFolderQuick("C:\MyFolder2", .F., "MyPassword")
SET LIBRARY TO

****************************
*!* Example 3
****************************
*!* Unzip a zip file quickly with or without respect
*!* for relative pathing of the files. Password
*!* protection can be included if desired.
****************************
SET LIBRARY TO LOCFILE("vfpcompression.fll")
?UnzipQuick("C:\MyFile.zip", "C:\")
?UnzipQuick("C:\MyFolder.zip", "C:\", .T.)
?UnzipQuick("C:\MyFolder.zip", "C:\", .F., "MyPassword")
SET LIBRARY TO

****************************
*!* Example 4
****************************
*!* Create a zip file, add some files to it
*!* and then close it when done. Respect
*!* for relative pathing and Password
*!* protection can be included if desired.
****************************
SET LIBRARY TO LOCFILE("vfpcompression.fll")
?ZipOpen("MyZipFile.zip", "C:\", .F.)
?ZipFile("C:\SomeFile.txt", .F.)
?ZipFile("C:\AnotherFile.txt", .F., "MyPassword")
?ZipClose()
SET LIBRARY TO

****************************
*!* Example 5
****************************
*!* Create a zip file, add some folders to it
*!* and then close it when done. Respect
*!* for relative pathing and Password
*!* protection can be included if desired.
****************************
SET LIBRARY TO LOCFILE("vfpcompression.fll")
?ZipOpen("C:\MyZipFile.zip")
*!* ?ZipOpen("MyZipFile.zip", "C:\", .F.)
?ZipFolder("C:\MyFolder\", .F.) && trailing backslash is optional
?ZipFolder("C:\AnotherFolder", .F., "MyPassword")
?ZipClose()
SET LIBRARY TO

****************************
*!* Example 6
****************************
*!* Compress and decompress a string in memory.
*!* The amount of compression is pretty remarkable.
****************************
SET LIBRARY TO LOCFILE("vfpcompression.fll")
CLEAR
lcOriginal = REPLICATE("Visual FoxPro Rocks!",100)
?"Original Length: " + TRANSFORM(LEN(lcOriginal))
?
lcCompressed = ZipString(lcOriginal)
?"Compressed: " + lcCompressed
?"Compressed Length: " + TRANSFORM(LEN(lcCompressed))
?
?"Length Savings: " + TRANSFORM(LEN(lcOriginal) - LEN(lcCompressed)) + " bytes"
?
lcUncompressed = UnzipString(lcCompressed)
*!* ?"Uncompressed: " + lcUncompressed
?"Uncompressed Length: " + TRANSFORM(LEN(lcUncompressed))
?"Equals Original: " + IIF(lcUncompressed == lcOriginal, "YES", "NO")
IF !(lcUncompressed == lcOriginal)
    EXIT
ENDIF
SET LIBRARY TO

****************************
*!* Example 7
****************************
*!* Demonstrates the callback functionality
****************************
SET LIBRARY TO LOCFILE("vfpcompression.fll")
ZipCallback("MyCallback()") && Start Event Handling - Any Function/Procedure/Method (in scope of course)
?ZipOpen("MyZip.zip", "C:\", .F.) && create zip file
?ZipFile("C:\MyFile.txt", .F.) && compress file into zip
?ZipClose() && done zipping
?UnzipQuick("C:\MyZip.zip", "C:\") && unzip contents of Test.zip to C:\
ZipCallback("") && Stop Event Handling
SET LIBRARY TO

*****************************
FUNCTION MyCallback()
    *****************************
    *!* Variables below are created on the fly
    *!* by the FLL when the ZipCallback feature is used

    *!* Depends on the value of nZipEvent
    ?cZipObjectName && Name of Zip, File, or Folder being processed

    *!* Events that fire MyCallback
    *!* 0 = Open Zip
    *!* 1 = Start Zip/Unzip of File
    *!* 2 = Read/Write File (nZipBytes will contain value of bytes read for event)
    *!* 3 - End Zip/Unzip of File
    *!* 4 - Folder Opened
    *!* 5 - Close Zip
    ?nZipEvent

    *!* Number of Bytes read (Event 3)
    ?nZipBytes

ENDFUNC

****************************
*!* Example 8
****************************
*!* Demonstrates how to use the UnzipAFileInfo()
*!* and UnzipAFileInfoByIndex() functions.
****************************
SET LIBRARY TO LOCFILE("vfpcompression.fll")
UnzipOpen("C:\MyZip.zip")
UnzipGotoTopFile()
UnzipAFileInfo("laTestArray1")
UnzipClose()
showfileinfo(@laTestArray1)
?
UnzipOpen("C:\MyZip.zip")
UnzipAFileInfoByIndex("laTestArray2",2)
UnzipClose()
showfileinfo(@laTestArray2)
SET LIBRARY TO

FUNCTION showfileinfo(aFileInfo)
    LOCAL lnCounter
    LOCAL ARRAY aCaptions(13)
    aCaptions(1) = "File Name"
    aCaptions(2) = "Comment"
    aCaptions(3) = "Version"
    aCaptions(4) = "Version Needed"
    aCaptions(5) = "Flags"
    aCaptions(6) = "Compression Method"
    aCaptions(7) = "DateTime"
    aCaptions(8) = "CRC"
    aCaptions(9) = "Compressed Size"
    aCaptions(10) = "Uncompressed Size"
    aCaptions(11) = "Internal Attribute"
    aCaptions(12) = "External Attribute"
    aCaptions(13) = "Folder"
    FOR lnCounter = 1 TO 13
        ?aCaptions(lnCounter)
        ?aFileInfo(lnCounter)
        ?TYPE("aFileInfo(lnCounter)")
    ENDFOR
ENDFUNC

****************************
*!* Example 9
****************************
*!* Manipulate the global zipfile comment of a zip file.
****************************
SET LIBRARY TO LOCFILE("vfpcompression.fll")
ZipComment("C:\MyZip1.zip", "Hello") && add or replace a global comment to a zip file
ZipComment("C:\MyZip2.zip", "") && delete a global comment from a zip file
SET LIBRARY TO

VFP Compression Documentation:

Function ZipString()

Signature: ZipString(cString[, nLevel])

Parameters:

cString - The character string you wish to compress

nLevel - The compression level to use which is 1 through 9 (1 is the fastest, while 9 is the best compression). The default value for this parameter is 6.

Return Value:

Character Data - the compressed version of cString.

Remarks:

This function is particularly useful in a client-server application given that strings of data (such as memo fields, character fields, and xml) can be compressed before sending them across the network and then extracted at the other end (using UnzipString).


Function ZipFileQuick()

Signature: ZipFileQuick(cFileName[, cPassword])

Parameters:

cFileName - The fully qualified file name (full path) of the file you wish to have compressed.

cPassword - The password you wish to protect the zipped file with.

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

The zip file that this function creates will have the same file name as cFileName, with the extension as ".zip".


Function ZipFolderQuick()

Signature: ZipFolderQuick(cFolderName[, lIgnorePaths[, cPassword]])

Parameters:

cFolderName - The full path to the folder you wish to have zipped.

cPassword - The password you wish to protect the zipped files with.

lIgnorePath - If you wish to ignore the relative path of the file into the zip file that is being created you would pass .T. for this parameter. The default value for this parameter is .F. which means that the relative path will be respected.

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

The zipfile that this function creates will have the same file name as cFolderName, with the extension as ".zip".


Function ZipOpen()

Signature: ZipOpen(cZipFileName[,cFolderName[,lAppend]])

Parameters:

cZipFileName - The file name or full path of the zip file you wish to create.

cFolderName - The full path of the folder in which you want cZipFileName created.

lAppend - If the zip file you are compressing to exists you can choose to append to it by passing .T. to this parameter. Defaults to .F..

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

ZipOpen() is used in conjunction with the matching ZipClose(). The usual series of function calls would consist of creating/opening the zip file using ZipOpen, zipping files and/or folders using ZipFile/ZipFileRelative/ZipFolder, and then closing the zip file using ZipClose.


Function ZipClose()

Signature: ZipClose()

Parameters: None

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

ZipClose() must be called after issuing a ZipOpen(). The usual series of function calls would consist of creating/opening the zip file using ZipOpen, zipping files and/or folders using ZipFile/ZipFileRelative/ZipFolder, and then closing the zip file using ZipClose.


Function ZipFile()

Signature: ZipFile(cFileName[,lIgnorePath[,cPassword]])

Parameters:

cFileName - The file name or full path of the file you wish to compress.

lIgnorePath - If you wish to ignore the relative path of the file into the zip file that is being created you would pass .T. for this parameter. The default value for this parameter is .F. which means that the relative path will be respected.

cPassword - The password you wish to protect the zipped file with.

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

ZipFile() is used between calls to ZipOpen() and ZipClose(). The usual series of function calls would consist of creating/opening the zip file using ZipOpen, zipping files and/or folders using ZipFile/ZipFileRelative/ZipFolder, and then closing the zip file using ZipClose.

The cPassword is usually the same for all files within a zip, however it does not need to be the same. Different passwords can be specified for different files and you can even selectively password protect files within the zip.


Function ZipFileRelative()

Signature: ZipFileRelative(cFileName[,cRelativePath[, cPassword]])

Parameters:

cFileName - The file name or full path of the file you wish to compress.

cRelativePath - The relative path you wish to have saved in the zip for this file. This allows you to set up the structure (relative paths) in the zip different from the actual relative paths of the files you are compressing.

cPassword - The password you wish to protect the zipped file with.

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

ZipFileRelative() is used between calls to ZipOpen() and ZipClose(). The usual series of function calls would consist of creating/opening the zip file using ZipOpen, zipping files and/or folders using ZipFile/ZipFileRelative/ZipFolder, and then closing the zip file using ZipClose.

The cPassword is usually the same for all files within a zip, however it does not need to be the same. Different passwords can be specified for different files and you can even selectively password protect files within the zip.


Function ZipFolder()

Signature: ZipFolder(cFolderName[,lIgnorePaths[, cPassword]])

Parameters:

cFolderName - The full path to the folder you wish to compress.

lIgnorePaths - If you wish to ignore the relative path of the folder into the zip file that is being created you would pass .T. for this parameter. The default value for this parameter is .F. which means that paths will be respected.

cPassword - The password you wish to protect the zipped file with.

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

ZipFolder() is used between calls to ZipOpen() and ZipClose(). The usual series of function calls would consist of creating/opening the zip file using ZipOpen, zipping files and/or folders using ZipFile/ZipFileRelative/ZipFolder, and then closing the zip file using ZipClose.


Function UnzipString()

Signature: UnzipString(cString)

Parameters:

cString - The compressed string you wish to uncompress.

Return Value:

Character Data - the extracted version of cString.

Remarks:

The string to be extracted must have been compressed with the ZipString() function or other compression function that is compatible with the compress or compress2 functions in zlib.


Function UnzipQuick()

Signature: UnzipQuick(cZipFileName, [cOutputFolderName[, lIgnorePaths[, cPassword]]])

Parameters:

cZipFileName - The fully qualified file name (full path) of the zip file you wish to have extracted.

cOutputFolderName - The full path to the folder you wish to extract the contents of the zip to.

cPassword - The password to use when unzipping the file.

lIgnorePaths - If you wish to ignore the relative paths that are contained in the zip file you would pass .T. for this parameter. The default value for this parameter is .F. which means that the relative paths will be respected.

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

The file and folders in the zip file will be extracted into the same folder as the cZipFileName resides in.


Function UnzipOpen()

Signature: UnzipOpen(cZipFileName)

Parameters:

cZipFileName - The file name or full path of the zip file you wish to uncompress.

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

UnzipOpen() is used in conjunction with the matching UnzipClose(). The usual series of function calls would consist of opening the zip file using UnzipOpen, uncompressing files and/or folders using Unzip/UnzipTo/UnzipByIndex/UnzipFile, and then closing the zip file using UnzipClose.


Function UnzipClose()

Signature: UnzipClose()

Parameters: None

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

UnzipClose() must be called after issuing an UnzipOpen(). The usual series of function calls would consist of opening the zip file using UnzipOpen, uncompressing files and/or folders using Unzip/UnzipTo/UnzipByIndex/UnzipFile, and then closing the zip file using UnzipClose.


Function Unzip()

Signature: Unzip([lIgnorePaths[, cPassword]])

Parameters:

lIgnorePaths - If you wish to ignore the relative paths that are contained in the zip file you would pass .T. for this parameter. The default value for this parameter is .F. which means that the relative paths will be respected.

cPassword - The password to use when unzipping the file.

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

Unzip() is used between calls to UnzipOpen() and UnzipClose() to uncompress the entire zip file. The files and folders contained in the zip file will be extracted to the same folder as the zip file resides in unless a call to UnzipSetFolder() has been previously issued. The usual series of function calls would consist of opening the zip file using UnzipOpen, uncompressing files and/or folders using Unzip/UnzipTo/UnzipByIndex/UnzipFile, and then closing the zip file using UnzipClose.


Function UnzipTo()

Signature: UnzipTo(cOutputFolderName[, lIgnorePaths[, cPassword]])

Parameters:

cOutputFolderName - The folder into which the zip file contents should be extracted.

lIgnorePaths - If you wish to ignore the relative paths that are contained in the zip file you would pass .T. for this parameter. The default value for this parameter is .F. which means that the relative paths will be respected.

cPassword - The password to use when unzipping the file.

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

UnzipTo() is used between calls to UnzipOpen() and UnzipClose(). The functionality of this is similar to calling UnzipSetFolder() and then Unzip(). The usual series of function calls would consist of opening the zip file using UnzipOpen, uncompressing files and/or folders using Unzip/UnzipTo/UnzipByIndex/UnzipFile, and then closing the zip file using UnzipClose.


Function UnzipFile()

Signature: UnzipFile(cOutputFolderName[, lIgnorePaths[, cPassword]])

Parameters:

cOutputFolderName - The folder into which the current file (cotained in the zip) should be extracted.

lIgnorePaths - If you wish to ignore the relative path of the current file you would pass .T. for this parameter. The default value for this parameter is .F. which means that the relative path will be respected.

cPassword - The password to use when unzipping the file.

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

UnzipFile() is used between calls to UnzipOpen() and UnzipClose() to extract the currently selected file contained in the zip file. UnzipFile() is used in conjunction with the UnzipGotoTopFile, UnzipGotoNextFile, UnzipGotoFileByName, and UnzipGotoFileByIndex functions. You can think of the contents of a zip file as records in a table. In this sense UnzipGotoTopFile, UnzipGotoNextFile, UnzipGotoFileByName, and UnzipGotoFileByIndex functions are used to move the record pointer and the UnzipFile function is used to extract the file that the record pointer is currently on.

The cPassword is usually the same for all files within a zip, however it does not need to be the same. Just keep in mind that passwords can be specified for different files within a zip and when you are unzipping such an archive you will need to change the cPassword accordingly.


Function UnzipByIndex()

Signature: UnzipByIndex(nIndex[, cOutputFolderName[,lIgnorePaths, cPassword]]])

Parameters:

nIndex - The index number of the file to be extracted.

cOutputFolderName - The folder into which the zip file contents should be extracted.

lIgnorePaths - If you wish to ignore the relative path for this file that is contained in the zip file you would pass .T. for this parameter. The default value for this parameter is .F. which means that the relative path will be respected.

cPassword - The password to use when unzipping the file.

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

UnzipByIndex() is used between calls to UnzipOpen() and UnzipClose() to extract a file by the position (index) it holds in the zip file. UnzipByIndex() is used in conjunction with the UnzipFileCount function. You can think of the contents of a zip file as records in a table. In this sense UnzipFileCount would give you the record count for the table and the UnzipByIndex function be used to extract a particular file by record number.

The cPassword is usually the same for all files within a zip, however it does not need to be the same. Just keep in mind that passwords can be specified for different files within a zip and when you are unzipping such an archive you will need to change the cPassword accordingly.


Function UnzipFileCount()

Signature: UnzipFileCount()

Parameters: None

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

UnzipFileCount() is used between calls to UnzipOpen() and UnzipClose() to retrieve the number of files that are contained in the zip file. It does not actually extract anything. UnzipFileCount() is used in conjunction with the UnzipByIndex function. You can think of the contents of a zip file as records in a table. In this sense UnzipFileCount would give you the record count for the table and the UnzipByIndex function be used to extract a particular file by record number.


Function UnzipSetFolder()

Signature: UnzipSetFolder(cOutputFolderName)

Parameters:

cOutputFolderName - The folder into which the zip file contents should be extracted.

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

UnzipSetFolder() is used between calls to UnzipOpen() and UnzipClose() to set the output folder for extracted zip contents. It does not actually extract anything. The usual series of function calls would consist of opening the zip file using UnzipOpen, calling UnzipSetFolder to set the output folder, uncompressing files and/or folders using Unzip/UnzipTo/UnzipByIndex/UnzipFile, and then closing the zip file using UnzipClose.


Function UnzipGotoTopFile()

Signature: UnzipGotoTopFile([cExtension])

Parameters:

cExtension - The file extension to use as a filter for file type. All other file types will be ignored and only the first file of the type specified will be selected in the zip file.

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

UnzipGotoTopFile() is used between calls to UnzipOpen() and UnzipClose() to select a particular file in the contents of the open zip file. UnzipGotoTopFile() is used in conjunction with the UnzipFile function to extract a particular file from the zip. By using the cExtension optional parameter you can select the first record of a particular file type. You can think of the contents of a zip file as records in a table. In this sense UnzipGotoTopFile, UnzipGotoNextFile, UnzipGotoFileByName, and UnzipGotoFileByIndex functions are used to move the record pointer and the UnzipFile function is used to extract the file that the record pointer is currently on.


Function UnzipGotoNextFile()

Signature: UnzipGotoNextFile([cExtension])

Parameters:

cExtension - The file extension to use as a filter for file type. All other file types will be ignored and only the next file of the type specified will be selected in the zip file.

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

UnzipGotoNextFile() is used between calls to UnzipOpen() and UnzipClose() to select a particular file in the contents of the open zip file. UnzipGotoNextFile() is used in conjunction with the UnzipFile function to extract a particular file from the zip. By using the cExtension optional parameter you can select the next record of a particular file type. You can think of the contents of a zip file as records in a table. In this sense UnzipGotoTopFile, UnzipGotoNextFile, UnzipGotoFileByName, and UnzipGotoFileByIndex functions are used to move the record pointer and the UnzipFile function is used to extract the file that the record pointer is currently on.


Function UnzipGotoFileByName()

Signature: UnzipGotoFileByName(cFileName[, lIgnoreFilePath])

Parameters:

cFileName - The file name of the file you wish to select in the zip file contents. You can specify a relative path as well to narrow down the search.

lIgnoreFilePath - If you wish to just find a file of a particular name in the zip file you can pass .T. for this parameter and the relative path of the file will be ignored. The first matching file of the name specified in cFileName will be selected in the zip contents.

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

UnzipGotoFileByName() is used between calls to UnzipOpen() and UnzipClose() to select a particular file in the contents of the open zip file by file name and/or relative path. UnzipGotoFileByName() is used in conjunction with the UnzipFile function to extract a particular file from the open zip file. You can think of the contents of a zip file as records in a table. In this sense UnzipGotoTopFile, UnzipGotoNextFile, UnzipGotoFileByName, and UnzipGotoFileByIndex functions are used to move the record pointer and the UnzipFile function is used to extract the file that the record pointer is currently on.


Function UnzipGotoFileByIndex()

Signature: UnzipGotoFileByIndex(nIndex)

Parameters:

nIndex - The index number of the file to be selected.

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Remarks:

UnzipGotoFileByIndex() is used between calls to UnzipOpen() and UnzipClose() to select a particular file by the position it physically holds in the contents of the open zip file. UnzipGotoFileByIndex() is used in conjunction with the UnzipFile function to extract a particular file from the zip file contents. You can think of the contents of a zip file as records in a table. In this sense UnzipGotoTopFile, UnzipGotoNextFile, UnzipGotoFileByName, and UnzipGotoFileByIndex functions are used to move the record pointer and the UnzipFile function is used to extract the file that the record pointer is currently on.


Function UnzipAFileInfoByIndex()

Signature: UnzipAFileInfoByIndex(cArrayName, nIndex)

Parameters:

cArrayName - Name of the VFP array to be created with file information in it.

nIndex - The index number of the file you want to return information about.

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Creates an array with 13 rows (elements) in it. The rows contain various pieces of information regarding the file that is held in the zip file at nIndex. The following table describes the contents and data type of each row in the array:

Row Array Content Data Type
1 File Name Character
2 Comment Character
3 Version Numeric
4 Version Needed Numeric
5 Flags Numeric
6 Compression Method Numeric
7 DOS Date Datetime
8 CRC Numeric
9 Compressed Size Numeric
10 Uncompressed Size Numeric
11 Internal Attribute Numeric
12 External Attribute Numeric
13 Folder Logical

Remarks:

The array that is created will have whatever name was specified by cArrayName. Should the array already exist it will release it and recreate it. UnzipAFileInfoByIndex() is used between calls to UnzipOpen() and UnzipClose() to show information about a particular file. The file is referred to by the position it physically holds in the contents of the open zip file. You can think of the contents of a zip file as records in a table. In this sense the UnzipAFileInfoByIndex function is used to refer to and retrieve information about a particular record number in the zip file.


Function UnzipAFileInfo()

Signature: UnzipAFileInfo(cArrayName)

Parameters:

cArrayName - Name of the VFP array to be created with file information in it.

Return Value:

Logical - returns .T. if successful or .F. if the operation has failed.

Creates an array with 13 rows (elements) in it. The rows contain various pieces of information regarding the currently selected file in the zip. The following table describes the contents and data type of each row in the array:

Row Array Content Data Type
1 File Name Character
2 Comment Character
3 Version Numeric
4 Version Needed Numeric
5 Flags Numeric
6 Compression Method Numeric
7 DOS Date Datetime
8 CRC Numeric
9 Compressed Size Numeric
10 Uncompressed Size Numeric
11 Internal Attribute Numeric
12 External Attribute Numeric
13 Folder Logical

Remarks:

The array that is created will have whatever name was specified by cArrayName. Should the array already exist it will release it and recreate it. UnzipAFileInfo() is used between calls to UnzipOpen() and UnzipClose() to show information about a particular file. Use the UnzipAFileInfo function in conjunction with UnzipGotoTopFile, UnzipGotoNextFile, UnzipGotoFileByName, and UnzipGotoFileByIndex functions to return information regarding a particular file contained in the open zip file. You can think of the contents of a zip file as records in a table. In this sense the UnzipAFileInfo function is used to refer to and retrieve information about the record that the record pointer is currently on within the zip file.


Function ZipCallback()

Signature: ZipCallback(cFunction)

Parameters:

cFunction - A string denoting a function, procedure, or method that you want fired whenever a zip event occurs, such as "MyCallback()".

Return Value: None

Events:

When one of the following zip events occurs the function/procedure/method specified by the cFunction parameter will be called. cZipObjectName, nZipEvent, and nZipBytes are private variables created on-the-fly by the FLL. They will contain the values specified in the table below.

Event Description cZipObjectName (character) nZipEvent (numeric) nZipBytes (numeric)
Zip Opened Name and path of zip file 0 N/A
Zip/Unzip File Start Name and path of file being zipped/unzipped 1 N/A
Zip Read or Unzip Write Name and path of file being zipped/unzipped 2 Number of bytes currently being read or written
Zip/Unzip File End Name and path of file being zipped/unzipped 3 N/A
Zip/Unzip Folder Opened Name and path of folder being zipped/unzipped 4 N/A
Zip Closed Name and path of zip file 5 N/A

Remarks:

Event handling is started as soon as you call ZipCallback and pass it the name of a function, procedure, or object method. ZipCallback provides a way for you to hook into the internal events happening inside of the VFPCompression FLL. nZipBytes reports the number of bytes currently being read during zip (2048 bytes at a time) or written during unzip (4096 bytes at a time) of an individual file. In order to turn off event handling simply call the ZipCallback with an empty length string, such as ZipCallback("").


Function ZipComment()

Signature: ZipComment(cZipFileName, cComment)

Parameters:

cZipFileName - The file name or full path to the zip file you wish to add, replace, or delete the comment on.

cComment - A string containing the comment (maximum of 255 characters)

Return Value:

None - returns .T. if successful or .F. if the operation has failed.

Remarks:

If a comment does not exist in the zip file, the string designated in cComment will be added. However, if a comment already exists in the zip file, the existing comment will be replaced with the cComment specified. This replacement functionality allows you to also delete an existing comment in a zip file by passing an empty string to the cComment parameter.

 

Monday, December 01, 2008 2:12:25 AM (GMT Standard Time, UTC+00:00)  #    Comments [13]
Monday, December 01, 2008 5:59:23 AM (GMT Standard Time, UTC+00:00)
Mike Sue-Ping beat me to the 0-byte file detection...!!

I encountered the now extinct bug around 3am last night (a dbf with only 7-8 fields that I was zapping for a quick structure kept being ignored from the zip and/or showing a default CRC-reading; I solved the problem by appending a few blank records).

BTW, I am wondering if there are at least half a dozen Craig Boyds working out there in the VFPPromisedLand - as no single human being can turn out such functional/deep/definitive FLLs (and blog details!) at the speed these are being published. My thanks to ALL of them!
Monday, December 01, 2008 7:34:16 PM (GMT Standard Time, UTC+00:00)
I have been trying the new update...my issue appears to be with ZipFolder. If I call it like this:

ZipFolder("c:\folder")

or like this:

ZipFolder("c:\folder",.F.)

then I end up with an empty ZIP file. If I call it like this:

ZipFolder("c:\folder",.T.)

then it compresses everything in the folder...but it also ignores the paths which is not helpful for what I am trying to do.

Any ideas?
Curt Hamlin
Monday, December 01, 2008 7:55:56 PM (GMT Standard Time, UTC+00:00)
Curt,


OK, the following works...

C:\
MyFolder
MyFile1.txt
MySubFolder
MyFile2.txt

... if I run the following code:

?ZipOpen("C:\MyZipFile.zip")
?ZipFolder("C:\MyFolder\", .F.)
?ZipClose()

... however if I do a ZipOpen to another drive...

?ZipOpen("F:\MyZipFile.zip")

... then I get the behavior you are reporting. I'm fixing it now.
Monday, December 01, 2008 8:16:02 PM (GMT Standard Time, UTC+00:00)
It might be useful if there was a way to delete files from a .zip file.

This would enable developers to sychronise folders with .zip files by comparing the properties of files to be zipped with those already in a .zip file, deleting redundant files and overwriting required files with later versions.

Also noticed that populating a cursor with files to be zipped properties using Scripting.FileSystemObject, there is often a one second difference between the value returned by UnzipAFileInfoByIndex(), row 7, when the files have been zipped.
Monday, December 01, 2008 8:55:31 PM (GMT Standard Time, UTC+00:00)
In reality...zipfolder() does not do relative path...it is always the absolute path.

A file like C:\MyFolder\SubFolder\file.txt

When compressed with zipfolder ("c:\myfolder\subfolder") is stored as

MyFolder
SubFolder
file.txt

You would think that if it was relative path then file.txt relative to c:\myfolder\subfolder would be just file.txt.

Correct? or am I misreading the term relative?
Curt Hamlin
Monday, December 01, 2008 10:06:15 PM (GMT Standard Time, UTC+00:00)
I was looking at some old "PKWare" documentation. I noticed that they had the option to not store the path information, store it relative (-directories=relative), full path (-path=full), relative to current folder (-path=current), etc. The way that this library appears to work is consistently none or path=full.
Curt Hamlin
Tuesday, December 02, 2008 12:29:47 AM (GMT Standard Time, UTC+00:00)
Curt,

Really appreciate your feedback. Can you email me so I can send you a new version of the FLL that I have created. I'd like to make sure it has fixed your earlier issue (checks out on this end) and I would like to discuss the ignore paths feature to see if I can make it more intuitive and useful... in the documentation and the FLL. Thanks.
Tuesday, December 02, 2008 1:59:35 PM (GMT Standard Time, UTC+00:00)
- ZipFolderQuick()- doesn't do passwords, it returns .T. but the zip has no password set. Also, if the given folder is relative (not absolute) it creates the zip, adds the folder, but the folder is empty, also no password set in this case. The function returns .T.
- UnzipQuick() - if no password is given but the file is passworded, it extracts the file, it returns .T. but the file contents are giberish .. shouldn't return .F. and extract nothing ?!

will test further and return with feedback
Eduard
Friday, December 05, 2008 5:51:23 PM (GMT Standard Time, UTC+00:00)
I have been trying to contact SPS for sometime in regards to the use of VFP Compression DLL. Could you guys get back to me as soon as possible??

Thanks.
Saturday, December 06, 2008 1:15:52 AM (GMT Standard Time, UTC+00:00)
Hi Luis,

What can I help you with? You can contact me directly via the "Contact Craig Boyd" link that is under the Navigation section at the top right of this page.
Wednesday, December 10, 2008 6:04:17 AM (GMT Standard Time, UTC+00:00)
Hi Craig,

I've got a few small issues with UnzipQuick, which also may apply to some other functions that I haven't yet tested. The documentation for UnzipQuick indicates that only the first argument is required, and Remarks state that the unzip results go into the directory that contains the specified .ZIP file. However, my testing shows that the unzip results go into the current directory when cOutputFolderName is omitted. More generally, the remarks appear to be wrong (as well as contradicting your explanation of cOutputFolderName), since the extracted results will not go into the same folder as the cZipFileName resides in, except when cOutputFolderName explicitly specifies that directory.

A minor observation: this function actually seems to handle relative paths for cZipFileName, although the description of that argument says it should be a fully qualified path. If it really does support relative paths as well as full paths, you might as well say so. I couldn't tell if this was an oversight or you were just being cautious about exceptional cases.

One more thing, which is not just a documentation issue: the date/time created on extracted files is getting set to the same thing as the date/time last changed. This is not as useful or conventional a way of handling creation dates as is customary. In general, the creation date/time should be set to the time when this copy of the file was created, i.e. when the file was extracted, which would actually be later than the date/time last modified. By observing that convention, you would make it easier to tell the sequence in which files were added to a directory regardless of their last modification timestamps, which I often find useful. I assume that your other unzip functions also behave this way, in which case I'd suggest they too be changed to observe the more usual convention regarding creation dates.

Finally, I'd like to thank you for your splendid work. I've also used your excellent encryption/decryption functions, and I'm very interested in the many other things you've been doing. Thanks again, and please keep up the great work!

Mike
Tuesday, March 03, 2009 10:37:13 AM (GMT Standard Time, UTC+00:00)
Hi,
function ZipComment() works great :)
But how can I get a comment from zip file?
Fox has a function for getting comments from EXE, but it does not work with ZIP files.

thanks
Sinisa
Friday, October 09, 2009 2:37:18 AM (GMT Daylight Time, UTC+01:00)
Hi

If table is open then compression utility does not compress it. Any solution if we want compress open tables too?
Nadeem Iqbal
All comments require the approval of the site owner before being displayed.
Name
E-mail
(will show your gravatar icon)
Home page

Comment (Some html is allowed: a@href@title, b, blockquote@cite, em, i, strike, strong, sub, sup, u) where the @ means "attribute." For example, you can use <a href="" title=""> or <blockquote cite="Scott">.  

Enter the code shown (prevents robots):

Live Comment Preview

 

Archive

<March 2010>
SunMonTueWedThuFriSat
28123456
78910111213
14151617181920
21222324252627
28293031123
45678910