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
Click to copy
Trevix
Did you forget a "revZipOpenArchive"?
Also: the line:
put format("error setting permissions for folder \"%s\" (%s)", thePathSegment, line 1 of the result) into theError formats with funny colours in the script editor.
Trevor DeVore
@Trevix - Yes I did. I've added a note about calling that before using the handles in this article. As for the script editor coloring, you would need to report that to LiveCode. The syntax is correct.