Zipping/Unzipping a Folder Using RevZip
The revZIP external is great if you need a cross-platform means of creating ZIP archives. Unfortunately there is no built in handler that will ZIP an entire folder for you. This lesson contains handlers that will ZIP up a folder and decompress a ZIP archive to a folder. All of the supporting handlers are included as well.
You are responsible for calling revZipOpenArchive() before and revZipCloseArchive() after calling any of the handlers in this atricle.
Code For Zipping/Unzipping Folders
-- Leave pFolderPath empty. It is used recursively command zipAddFolderToArchive pZipArchivePath, pRootFolderPath, pIncludeRootFolderInArchiveItemNames, pFilesToExclude, pExtensionsThatArentCompressed, pFolderPath local theArchiveItemName,theCharNo,theError,theFile local theFiles,theFolder,theFolders put pIncludeRootFolderInArchiveItemNames is true into pIncludeRootFolderInArchiveItemNames set the wholematches to true replace comma with cr in pExtensionsThatArentCompressed if pFolderPath is empty then put pRootFolderPath into pFolderPath if pIncludeRootFolderInArchiveItemNames then # we want folder to be reflected in archive item name set the itemdel to slash delete item -1 of pRootFolderPath end if end if put fileFilesInFolder(pFolderPath, true, true) into theFiles filter theFiles without "*/.DS_Store" set the itemdel to "." repeat for each line theFile in theFiles if theFile is among the lines of pFilesToExclude then next repeat put theFile into theArchiveItemName put offset(pRootFolderPath, theArchiveItemName) into theCharNo if theCharNo is 0 then return "file is not in expected folder" # strip root folder up to slash (zip item names shouldn't start with a slash) delete char 1 to (the number of chars of pRootFolderPath + 1) of theArchiveItemName if item -1 of theArchiveItemName is among the lines of pExtensionsThatArentCompressed then revZipAddUncompressedItemWithFile pZipArchivePath, theArchiveItemName, theFile else revZipAddItemWithFile pZipArchivePath, theArchiveItemName, theFile end if if the result is not empty then put the result into theError exit REPEAT end if end REPEAT if theError is empty then put fileFoldersInFolder(pFolderPath, true, true) into theFolders repeat for each line theFolder in theFolders zipAddFolderToArchive pZipArchivePath, pRootFolderPath, pIncludeRootFolderInArchiveItemNames, pFilesToExclude, pExtensionsThatArentCompressed, theFolder put the result into theError if theError is not empty then exit REPEAT end if end REPEAT end if return theError end zipAddFolderToArchive command zipDecompressArchiveToFolder pZipArchivePath, pOutputFolder, pItemsToExclude, pCallbackHandler local theError if the last char of pOutputFolder is slash then delete the last char of pOutputFolder set the wholematches to true put the filetype into theFileType set the filetype to empty put revZipEnumerateItems(pZipArchivePath) into theArchiveItems put the number of lines of theArchiveItems into theItemCount repeat for each line theArchiveItem in theArchiveItems add 1 to i if theArchiveItem is among the lines of pItemsToExclude then next repeat put pOutputFolder & slash & theArchiveItem into theFilePath put fileExtractDirectory(theFilePath) into theDirectoryPath if theDirectoryPath is not pOutputFolder then fileCreateAllFoldersInPath theDirectoryPath, pOutputFolder put the result into theError end if if theError is empty then if pCallbackHandler is not empty then put _CardOf(the long id of the target) into theCard put "send" && quote & pCallbackHandler && "i, theItemCount" & quote && "to theCard" into theDo do theDo end if revZipExtractItemToFile pZipArchivePath, theArchiveItem, theFilePath put the result into theError end if if theError is not empty then exit REPEAT end REPEAT set the filetype to theFileType return theError end zipDecompressArchiveToFolder function fileFilesInFolder pFolder, pFullPath, pIncludeHidden local theDefault,theFile,theFiles,theFullFiles if there is not a folder pFolder then return empty if last char of pFolder is not slash then put slash after pFolder put the defaultfolder into theDefault set the defaultfolder to pFolder put the files into theFiles set the defaultfolder to theDefault if pIncludeHidden is not true then filter theFiles without ".*" else filter theFiles without "..*" end if if pFullPath then repeat for each line theFile in theFiles put pFolder & theFile & cr after theFullFiles end REPEAT delete last char of theFullFiles return theFullFiles else return theFiles end if end fileFilesInFolder function fileFoldersInFolder pFolder, pFullPath, pIncludeHidden local theDefault,theFolders,theFullFolders,theFolder if there is not a folder pFolder then return empty if last char of pFolder is not slash then put slash after pFolder put the defaultfolder into theDefault set the defaultfolder to pFolder put the folders into theFolders set the defaultfolder to theDefault if pIncludeHidden is not true then filter theFolders without ".*" else filter theFolders without "..*" end if if pFullPath then repeat for each line theFolder in theFolders put pFolder & theFolder &cr after theFullFolders end REPEAT delete last char of theFullFolders return theFullFolders else return theFolders end if end fileFoldersInFolder function fileExtractDirectory pFilePath set the itemdelimiter to slash return item 1 to -2 of pFilePath end fileExtractDirectory ## Used for removing multiple slashes from folder paths private command _stripDoubleSlash @pVariable local theCharNo,thePrefix ## Don't wipe out UNC prefixes if char 1 to 2 of pVariable is "//" then put "//" into thePrefix delete char 1 to 2 of pVariable end if repeat forever put offset("//", pVariable) into theCharNo if theCharNo > 0 then replace "//" with slash in pVariable else exit repeat end if end repeat if thePrefix is not empty then put thePrefix before pVariable end if return empty end _stripDoubleSlash private function _escapeForShell pStr local theChar,theSpecialChars if the platform contains "MacOS" then put "\" & space & quote & "'`<>!;()?#$^&*=|" into theSpecialChars repeat for each char theChar in theSpecialChars replace theChar with ("\" & theChar) in pStr end REPEAT else replace "/" with "\" in pStr put quote & pStr & quote into pStr end if return pStr end _escapeForShell private function _executableBitFromType pType switch pType case "execute" put 7 into pType break case "write" put 6 into pType break case "read" put 5 into pType break default put 0 into pType end switch return pType end _executableBitFromType private function _CardOf pControl local theCharNo put the long id of pControl into pControl ## force the long id if word 1 of pControl is "stack" then put empty into pControl -- has no card else if word 1 of pControl is not "card" then put offset(" of card ", pControl) into theCharNo if theCharNo > 0 then delete char 1 to (theCharNo + 3) of pControl else put empty into pControl end if end if end if return pControl end _CardOf command fileCreateAllFoldersInPath pPath, pRootPath, pPerms local theCheck,theError,thePathSegment ## Watch for double slashes /Folder/To//Something// ## You will not enter a never ending loop if you aren't careful. _stripDoubleSlash pPath _stripDoubleSlash pRootPath ## Get rid of trailing slashes ## We can safely ignore UNC paths starting with "//" ## Neither pPath or pRootPath with values of just "//" would be valid repeat until the last char of pPath is not slash delete the last char of pPath end repeat if the number of chars of pRootPath > 1 and the last char of pRootPath is slash then repeat forever delete the last char of pRootPath if the last char of pRootPath is not slash or the number of chars of pRootPath is 1 then exit repeat end if end repeat end if ## Permissions if pPerms is not "shared" then put "user" into pPerms set the itemdelimiter to slash if pPath is empty or the number of items of pPath is 1 then put "cannot create folder (invalid path)" into theError end if ## VALIDATE pRootPath if theError is empty then if pRootPath is empty then put item 1 to 2 of pPath into pRootPath ## "/NODE" end if if theError is empty then if last char of pRootPath is not slash then put slash after pRootPath ## Makes it easier to deal with "/" path if there is not a folder pRootPath then put "root path does not exist" into theError end if end if end if ## VALIDATE ANCESTORY OF PATH if theError is empty then put char 1 to -2 of pRootPath into theCheck ## -2 gets rid of trailing slash if char 1 to (number of chars of theCheck) of pPath is not theCheck then put "path is not a child of root path" into theError end if end if ## CREATE FOLDERS if theError is empty then if number of items of pPath > number of items of pRootPath then put pRootPath & item (number of items of pRootPath + 1) of pPath into thePathSegment if there is not a folder thePathSegment then create folder thePathSegment if the result is not empty then put "error creating folder (" & the result & ")" into theError else if pPerms is "shared" then fileSetPermissions thePathSegment, "execute", "execute", "execute" if the result is not empty then put format("error setting permissions for folder \"%s\" (%s)", thePathSegment, line 1 of the result) into theError end if end if end if end if if theError is empty then fileCreateAllFoldersInPath pPath, thePathSegment, pPerms put the result into theError end if end if end if return theError end fileCreateAllFoldersInPath on fileSetPermissions pFile, pOwner, pGroup, pAll local theError,theResult put _escapeForShell(pFile) into pFile switch the platform case "Win32" /* Displays or changes file attributes. ATTRIB [+R | -R] [+A | -A] [+S | -S] [+H | -H] [[drive:][path]filename] [/S] [/D] + Sets an attribute. - Clears an attribute. R Read-only file attribute. A Archive file attribute. S system file attribute. H Hidden file attribute. /S Processes files in all directories in the specified path. /D Processes folders as well */ switch pOwner case "read" put "+r" into pOwner break case "write" put "-r" into pOwner break end switch put shell (format ("attrib %s %s", pOwner, pFile) ) into theResult break case "MacOS" put _executableBitFromType(pOwner) into pOwner put _executableBitFromType(pGroup) into pGroup put _executableBitFromType(pAll) into pAll put shell(format("chmod %u%u%u %s ", pOwner, pGroup, pAll, pFile)) into theResult break end SWITCH if the result is not empty then put line 1 of theResult into theError end if return theError end fileSetPermissions