#include-once

; ===============================================================================================================
;
; Description:      ZIP Functions
; Author:           wraithdu
; Date:             2013-05-28
; Credits:          PsaltyDS for the original idea on which this UDF is based.
;					torels for the basic framework on which this UDF is based.
;
; NOTES:
;   This UDF attempts to register a COM error handler if one does not exist.  This is done to prevent
;   any fatal COM errors.  If you have implemented your own COM error handler, this WILL NOT replace it.
;
;   The Shell object does not have a delete method, so some workarounds have been implemented.  The
;   options are either an interactive method (as in right-click -> Delete) or a slower method (slow for
;   large files).  The interactive method is the main function, while the slow method is in the internal
;   function section near the bottom.
;
;   When adding a file item to a ZIP archive, if the file exists and the overwrite flag is set, the slower
;   internal delete method is used.  This is the only way to make this step non-interactive.  It will be
;   slow for large files.
;
;   WINDOWS XP NOTE: This internal delete method does not work in Windows XP, it will fail with an error.
;
;        As a result, adding files directly to a subdirectory will not work. So please don't try it. As a
;        workaround, create the directory structure that holds your files in a temporary location, and add the
;        root directory to the root of the zip file.
;
;        For example, to add 'file.ext' to the path 'some\sub\path', first create 'some\sub\path\file.ext'
;        in a temporary location, then add the entire 'some' directory to the root of your zip file.
;
;   The zipfldr library does not allow overwriting or merging of folders in a ZIP archive.  That means
;   if you try to add a folder and a folder with that name already exists, it will simply fail.  Period.
;   As such, I've disabled that functionality.
;
;   I've also removed the AddFolderContents function. There are too many pitfalls with that scenario, not
;   the least of which being the above restriction.
;
; ===============================================================================================================

;;; Start COM error Handler
;=====
; if a COM error handler does not already exist, assign one
If Not ObjEvent("AutoIt.Error") Then
	; MUST assign this to a variable
	Global Const $_Zip_COMErrorHandler = ObjEvent("AutoIt.Error", "_Zip_COMErrorFunc")
EndIf

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_AddItem
; Description....:	Add a file or folder to a ZIP archive
; Syntax.........:	_Zip_AddItem($sZipFile, $sItem[, $sDestDir = ""[, $iFlag = 21]])
; Parameters.....:	$sZipFile   - Full path to ZIP file
;					$sItem      - Full path to item to add
;					$sDestDir   - [Optional] Destination subdirectory in which to place the item
;								+ Directory must be formatted similarly: "some\sub\dir"
;					$iFlag      - [Optional] File copy flags (Default = 1+4+16)
;								|   1 - Overwrite destination file if it exists
;								|   4 - No progress box
;								|   8 - Rename the file if a file of the same name already exists
;								|  16 - Respond "Yes to All" for any dialog that is displayed
;								|  64 - Preserve undo information, if possible
;								| 256 - Display a progress dialog box but do not show the file names
;								| 512 - Do not confirm the creation of a new directory if the operation requires one to be created
;								|1024 - Do not display a user interface if an error occurs
;								|2048 - Version 4.71. Do not copy the security attributes of the file
;								|4096 - Only operate in the local directory, don't operate recursively into subdirectories
;								|8192 - Version 5.0. Do not copy connected files as a group, only copy the specified files
;
; Return values..:	Success     - 1
;					Failure     - 0 and sets @error
;								| 1 - zipfldr.dll does not exist
;								| 2 - Library not installed
;								| 3 - Destination ZIP file not a full path
;								| 4 - Item to add not a full path
;								| 5 - Item to add does not exist
;								| 6 - Destination subdirectory cannot be a full path
;								| 7 - Destination ZIP file or sub path does not exist
;								| 8 - Destination item exists and is a folder (see Remarks)
;								| 9 - Destination item exists and overwrite flag not set
;								|10 - Destination item exists and failed to overwrite
;								|11 - Failed to create internal directory structure
;
; Author.........:	wraithdu
; Modified.......:
; Remarks........:	Destination folders CANNOT be overwritten or merged.  They must be manually deleted first.
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _Zip_AddItem($sZipFile, $sItem, $sDestDir = "", $iFlag = 21)
	If Not _Zip_DllChk() Then Return SetError(@error, 0, 0)
	If Not _IsFullPath($sZipFile) Then Return SetError(3, 0, 0)
	If Not _IsFullPath($sItem) Then Return SetError(4, 0, 0)
	If Not FileExists($sItem) Then Return SetError(5, 0, 0)
	If _IsFullPath($sDestDir) Then Return SetError(6, 0, 0)
	; clean paths
	$sItem = _Zip_PathStripSlash($sItem)
	$sDestDir = _Zip_PathStripSlash($sDestDir)
	Local $sNameOnly = _Zip_PathNameOnly($sItem)
	; process overwrite flag
	Local $iOverwrite = 0
	If BitAND($iFlag, 1) Then
		$iOverwrite = 1
		$iFlag -= 1
	EndIf
	; check for overwrite, if target exists...
	Local $sTest = $sNameOnly
	If $sDestDir <> "" Then $sTest = $sDestDir & "\" & $sNameOnly
	Local $itemExists = _Zip_ItemExists($sZipFile, $sTest)
	If @error Then Return SetError(7, 0, 0)
	If $itemExists Then
		If @extended Then
			; get out, cannot overwrite folders... AT ALL
			Return SetError(8, 0, 0)
		Else
			If $iOverwrite Then
				_Zip_InternalDelete($sZipFile, $sTest)
				If @error Then Return SetError(10, 0, 0)
			Else
				Return SetError(9, 0, 0)
			EndIf
		EndIf
	EndIf
	Local $sTempFile = ""
	If $sDestDir <> "" Then
		$sTempFile = _Zip_AddPath($sZipFile, $sDestDir)
		If @error Then Return SetError(11, 0, 0)
	EndIf
	Local $oNS = _Zip_GetNameSpace($sZipFile, $sDestDir)
	; copy the item(s)
	$oNS.CopyHere($sItem, $iFlag)
	Do
		Sleep(250)
	Until IsObj($oNS.ParseName($sNameOnly))
	If $sTempFile <> "" Then
		_Zip_InternalDelete($sZipFile, $sDestDir & "\" & $sTempFile)
		If @error Then Return SetError(12, 0, 0)
	EndIf
	Return 1
EndFunc   ;==>_Zip_AddItem

Func _Zip_COMErrorFunc()
EndFunc   ;==>_Zip_COMErrorFunc

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_Count
; Description....:	Count items in the root of a ZIP archive (not recursive)
; Syntax.........:	_Zip_Count($sZipFile)
; Parameters.....:	$sZipFile   - Full path to ZIP file
;
; Return values..:	Success     - Item count
;					Failure     - 0 and sets @error
;								| 1 - zipfldr.dll does not exist
;								| 2 - Library not installed
;								| 3 - Not a full path
;								| 4 - ZIP file does not exist
; Author.........:	wraithdu, torels
; Modified.......:
; Remarks........:
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _Zip_Count($sZipFile)
	If Not _Zip_DllChk() Then Return SetError(@error, 0, 0)
	If Not _IsFullPath($sZipFile) Then Return SetError(3, 0, 0)
	Local $oNS = _Zip_GetNameSpace($sZipFile)
	If Not IsObj($oNS) Then Return SetError(4, 0, 0)
	Return $oNS.Items().Count
EndFunc   ;==>_Zip_Count

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_CountAll
; Description....:	Recursively count items contained in a ZIP archive
; Syntax.........:	_Zip_CountAll($sZipFile)
; Parameters.....:	$sZipFile       - Full path to ZIP file
;					$sSub           - [Internal]
;					$iFileCount     - [Internal]
;					$iFolderCount   - [Internal]
;
; Return values..:	Success         - Array with file and folder count
;									[0] - File count
;									[1] - Folder count
;					Failure         - 0 and sets @error
;									| 1 - zipfldr.dll does not exist
;									| 2 - Library not installed
;									| 3 - Not a full path
;									| 4 - ZIP file does not exist
; Author.........:	wraithdu
; Modified.......:
; Remarks........:
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _Zip_CountAll($sZipFile, $sSub = "", $iFileCount = 0, $iFolderCount = 0)
	If Not _Zip_DllChk() Then Return SetError(@error, 0, 0)
	If Not _IsFullPath($sZipFile) Then Return SetError(3, 0, 0)
	Local $oNS = _Zip_GetNameSpace($sZipFile, $sSub)
	If Not IsObj($oNS) Then Return SetError(4, 0, 0)
	Local $oItems = $oNS.Items(), $aCount, $sSub2
	For $oItem In $oItems
		; reset subdir so recursion doesn't break
		$sSub2 = $sSub
		If $oItem.IsFolder Then
			; folder, recurse
			$iFolderCount += 1
			If $sSub2 = "" Then
				$sSub2 = $oItem.Name
			Else
				$sSub2 &= "\" & $oItem.Name
			EndIf
			$aCount = _Zip_CountAll($sZipFile, $sSub2, $iFileCount, $iFolderCount)
			$iFileCount = $aCount[0]
			$iFolderCount = $aCount[1]
		Else
			$iFileCount += 1
		EndIf
	Next
	Dim $aCount[2] = [$iFileCount, $iFolderCount]
	Return $aCount
EndFunc   ;==>_Zip_CountAll

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_Create
; Description....:	Create empty ZIP archive
; Syntax.........:	_Zip_Create($sFileName[, $iOverwrite = 0])
; Parameters.....:	$sFileName  - Name of new ZIP file
;					$iOverwrite - [Optional] Overwrite flag (Default = 0)
;								| 0 - Do not overwrite the file if it exists
;								| 1 - Overwrite the file if it exists
;
; Return values..:	Success     - Name of the new file
;					Failure     - 0 and sets @error
;								| 1 - A file with that name already exists and $iOverwrite flag is not set
;								| 2 - Failed to create new file
; Author.........:	wraithdu, torels
; Modified.......:
; Remarks........:
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _Zip_Create($sFileName, $iOverwrite = 0)
	If FileExists($sFileName) And Not $iOverwrite Then Return SetError(1, 0, 0)
	Local $hFp = FileOpen($sFileName, 2 + 8 + 16)
	If $hFp = -1 Then Return SetError(2, 0, 0)
	FileWrite($hFp, Binary("0x504B0506000000000000000000000000000000000000"))
	FileClose($hFp)
	Return $sFileName
EndFunc   ;==>_Zip_Create

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_DeleteItem
; Description....:	Delete a file or folder from a ZIP archive
; Syntax.........:	_Zip_DeleteItem($sZipFile, $sFileName)
; Parameters.....:	$sZipFile   - Full path to the ZIP file
;					$sFileName  - Name of the item in the ZIP file
;
; Return values..:	Success     - 1
;					Failure     - 0 and sets @error
;								| 1 - zipfldr.dll does not exist
;								| 2 - Library not installed
;								| 3 - Not a full path
;								| 4 - ZIP file or sub path does not exist
;								| 5 - Item not found in ZIP file
;								| 6 - Failed to get list of verbs
;								| 7 - Failed to delete item
;								| 8 - User cancelled delete operation or operation failed
; Author.........:	wraithdu
; Modified.......:
; Remarks........:	$sFileName may be a path to an item from the root of the ZIP archive.
;					For example, some ZIP file 'test.zip' has a subpath 'some\dir\file.ext'.  Do not include a leading or trailing '\'.
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _Zip_DeleteItem($sZipFile, $sFileName)
	If Not _Zip_DllChk() Then Return SetError(@error, 0, 0)
	If Not _IsFullPath($sZipFile) Then Return SetError(3, 0, 0)
	; parse filename
	Local $sPath = ""
	$sFileName = _Zip_PathStripSlash($sFileName)
	If StringInStr($sFileName, "\") Then
		; subdirectory, parse out path and filename
		$sPath = _Zip_PathPathOnly($sFileName)
		$sFileName = _Zip_PathNameOnly($sFileName)
	EndIf
	Local $oNS = _Zip_GetNameSpace($sZipFile, $sPath)
	If Not IsObj($oNS) Then Return SetError(4, 0, 0)
	Local $oFolderItem = $oNS.ParseName($sFileName)
	If Not IsObj($oFolderItem) Then Return SetError(5, 0, 0)
	Local $oVerbs = $oFolderItem.Verbs()
	If Not IsObj($oVerbs) Then Return SetError(6, 0, 0)
	For $oVerb In $oVerbs
		If StringReplace($oVerb.Name, "&", "") = "delete" Then
			$oVerb.DoIt()
			If IsObj($oNS.ParseName($sFileName)) Then
				Return SetError(8, 0, 0)
			Else
				Return 1
			EndIf
		EndIf
	Next
	Return SetError(7, 0, 0)
EndFunc   ;==>_Zip_DeleteItem

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_ItemExists
; Description....:	Determines if an item exists in a ZIP file
; Syntax.........:	_Zip_ItemExists($sZipFile, $sItem)
; Parameters.....:	$sZipFile   - Full path to ZIP file
;					$sItem      - Name of item
;
; Return values..:	Success     - 1
;								@extended is set to 1 if the item is a folder, 0 if a file
;					Failure     - 0 and sets @error
;								| 1 - zipfldr.dll does not exist
;								| 2 - Library not installed
;								| 3 - Not a full path
;								| 4 - ZIP file or sub path does not exist
; Author.........:	wraithdu
; Modified.......:
; Remarks........:	$sItem may be a path to an item from the root of the ZIP archive.
;					For example, some ZIP file 'test.zip' has a subpath 'some\dir\file.ext'.  Do not include a leading or trailing '\'.
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _Zip_ItemExists($sZipFile, $sItem)
	If Not _Zip_DllChk() Then Return SetError(@error, 0, 0)
	If Not _IsFullPath($sZipFile) Then Return SetError(3, 0, 0)
	Local $sPath = ""
	$sItem = _Zip_PathStripSlash($sItem)
	If StringInStr($sItem, "\") Then
		; subfolder
		$sPath = _Zip_PathPathOnly($sItem)
		$sItem = _Zip_PathNameOnly($sItem)
	EndIf
	Local $oNS = _Zip_GetNameSpace($sZipFile, $sPath)
	If Not IsObj($oNS) Then Return SetError(4, 0, 0)
	Local $oItem = $oNS.ParseName($sItem)
	; @extended holds whether item is a file (0) or folder (1)
	If IsObj($oItem) Then Return SetExtended(Number($oItem.IsFolder), 1)
	Return 0
EndFunc   ;==>_Zip_ItemExists

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_List
; Description....:	List items in the root of a ZIP archive (not recursive)
; Syntax.........:	_Zip_List($sZipFile)
; Parameters.....:	$sZipFile   - Full path to ZIP file
;
; Return values..:	Success     - Array of items
;					Failure     - 0 and sets @error
;								| 1 - zipfldr.dll does not exist
;								| 2 - Library not installed
;								| 3 - Not a full path
;								| 4 - ZIP file does not exist
; Author.........:	wraithdu, torels
; Modified.......:
; Remarks........:	Item count is returned in array[0].
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _Zip_List($sZipFile)
	If Not _Zip_DllChk() Then Return SetError(@error, 0, 0)
	If Not _IsFullPath($sZipFile) Then Return SetError(3, 0, 0)
	Local $oNS = _Zip_GetNameSpace($sZipFile)
	If Not IsObj($oNS) Then Return SetError(4, 0, 0)
	Local $aArray[1] = [0]
	Local $oList = $oNS.Items()
	For $oItem In $oList
		$aArray[0] += 1
		ReDim $aArray[$aArray[0] + 1]
		$aArray[$aArray[0]] = $oItem.Name
	Next
	Return $aArray
EndFunc   ;==>_Zip_List

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_ListAll
; Description....:	List all files inside a ZIP archive
; Syntax.........:	_Zip_ListAll($sZipFile[, $iFullPath = 1])
; Parameters.....:	$sZipFile   - Full path to ZIP file
;					$iFullPath  - [Optional] Path flag (Default = 1)
;								| 0 - Return file names only
;								| 1 - Return full paths of files from the archive root
;
; Return values..:	Success     - Array of file names / paths
;					Failure     - 0 and sets @error
;								| 1 - zipfldr.dll does not exist
;								| 2 - Library not installed
;								| 3 - Not a full path
;								| 4 - ZIP file does not exist
; Author.........:	wraithdu
; Modified.......:
; Remarks........:	File count is returned in array[0], does not list folders.
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _Zip_ListAll($sZipFile, $iFullPath = 1)
	If Not _Zip_DllChk() Then Return SetError(@error, 0, 0)
	If Not _IsFullPath($sZipFile) Then Return SetError(3, 0, 0)
	Local $aArray[1] = [0]
	_Zip_ListAll_Internal($sZipFile, "", $aArray, $iFullPath)
	If @error Then
		Return SetError(@error, 0, 0)
	Else
		Return $aArray
	EndIf
EndFunc   ;==>_Zip_ListAll

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_Search
; Description....:	Search for files in a ZIP archive
; Syntax.........:	_Zip_Search($sZipFile, $sSearchString)
; Parameters.....:	$sZipFile       - Full path to ZIP file
;					$sSearchString  - Substring to search
;
; Return values..:	Success         - Array of matching file paths from the root of the archive
;					Failure         - 0 and sets @error
;									| 1 - zipfldr.dll does not exist
;									| 2 - Library not installed
;									| 3 - Not a full path
;									| 4 - ZIP file does not exist
;									| 5 - No matching files found
; Author.........:	wraithdu
; Modified.......:
; Remarks........:	Found file count is returned in array[0].
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _Zip_Search($sZipFile, $sSearchString)
	Local $aList = _Zip_ListAll($sZipFile)
	If @error Then Return SetError(@error, 0, 0)
	Local $aArray[1] = [0], $sName
	For $i = 1 To $aList[0]
		$sName = $aList[$i]
		If StringInStr($sName, "\") Then
			; subdirectory, isolate file name
			$sName = _Zip_PathNameOnly($sName)
		EndIf
		If StringInStr($sName, $sSearchString) Then
			$aArray[0] += 1
			ReDim $aArray[$aArray[0] + 1]
			$aArray[$aArray[0]] = $aList[$i]
		EndIf
	Next
	If $aArray[0] = 0 Then
		; no files found
		Return SetError(5, 0, 0)
	Else
		Return $aArray
	EndIf
EndFunc   ;==>_Zip_Search

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_SearchInFile
; Description....:	Search file contents of files in a ZIP archive
; Syntax.........:	_Zip_SearchInFile($sZipFile, $sSearchString)
; Parameters.....:	$sZipFile       - Full path to ZIP file
;					$sSearchString  - Substring to search
;
; Return values..:	Success         - Array of matching file paths from the root of the archive
;					Failure         - 0 and sets @error
;									| 1 - zipfldr.dll does not exist
;									| 2 - Library not installed
;									| 3 - Not a full path
;									| 4 - ZIP file does not exist
;									| 5 - Failed to create temporary directory
;									| 6 - Failed to extract ZIP file to temporary directory
;									| 7 - No matching files found
; Author.........:	wraithdu
; Modified.......:
; Remarks........:	Found file count is returned in array[0].
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _Zip_SearchInFile($sZipFile, $sSearchString)
	Local $aList = _Zip_ListAll($sZipFile)
	If @error Then Return SetError(@error, 0, 0)
	Local $sTempDir = _Zip_CreateTempDir()
	If @error Then Return SetError(5, 0, 0)
	_Zip_UnzipAll($sZipFile, $sTempDir) ; flag = 20 -> no dialog, yes to all
	If @error Then
		DirRemove($sTempDir, 1)
		Return SetError(6, 0, 0)
	EndIf
	Local $aArray[1] = [0], $sData
	For $i = 1 To $aList[0]
		$sData = FileRead($sTempDir & "\" & $aList[$i])
		If StringInStr($sData, $sSearchString) Then
			$aArray[0] += 1
			ReDim $aArray[$aArray[0] + 1]
			$aArray[$aArray[0]] = $aList[$i]
		EndIf
	Next
	DirRemove($sTempDir, 1)
	If $aArray[0] = 0 Then
		; no files found
		Return SetError(7, 0, 0)
	Else
		Return $aArray
	EndIf
EndFunc   ;==>_Zip_SearchInFile

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_Unzip
; Description....:	Extract a single item from a ZIP archive
; Syntax.........:	_Zip_Unzip($sZipFile, $sFileName, $sDestPath[, $iFlag = 21])
; Parameters.....:	$sZipFile   - Full path to ZIP file
;					$sFileName  - Name of the item in the ZIP file
;					$sDestPath  - Full path to the destination
;					$iFlag      - [Optional] File copy flags (Default = 1+4+16)
;								|   1 - Overwrite destination file if it exists
;								|   4 - No progress box
;								|   8 - Rename the file if a file of the same name already exists
;								|  16 - Respond "Yes to All" for any dialog that is displayed
;								|  64 - Preserve undo information, if possible
;								| 256 - Display a progress dialog box but do not show the file names
;								| 512 - Do not confirm the creation of a new directory if the operation requires one to be created
;								|1024 - Do not display a user interface if an error occurs
;								|2048 - Version 4.71. Do not copy the security attributes of the file
;								|4096 - Only operate in the local directory, don't operate recursively into subdirectories
;								|8192 - Version 5.0. Do not copy connected files as a group, only copy the specified files
;
; Return values..:	Success     - 1
;					Failure     - 0 and sets @error
;								| 1 - zipfldr.dll does not exist
;								| 2 - Library not installed
;								| 3 - Not a full path
;								| 4 - ZIP file or sub path does not exist
;								| 5 - Item not found in ZIP file
;								| 6 - Failed to create destination (if necessary)
;								| 7 - Failed to open destination
;								| 8 - Failed to delete destination file / folder for overwriting
;								| 9 - Destination exists and overwrite flag not set
;								|10 - Failed to extract file
; Author.........:	wraithdu, torels
; Modified.......:
; Remarks........:	$sFileName may be a path to an item from the root of the ZIP archive.
;					For example, some ZIP file 'test.zip' has a subpath 'some\dir\file.ext'.  Do not include a leading or trailing '\'.
;					If the overwrite flag is not set and the destination file / folder exists, overwriting is controlled
;					by the remaining file copy flags ($iFlag) and/or user interaction.
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _Zip_Unzip($sZipFile, $sFileName, $sDestPath, $iFlag = 21)
	If Not _Zip_DllChk() Then Return SetError(@error, 0, 0)
	If Not _IsFullPath($sZipFile) Or Not _IsFullPath($sDestPath) Then Return SetError(3, 0, 0)
	; get temp directory created by Windows
	Local $sTempDir = _Zip_TempDirName($sZipFile)
	; parse filename
	Local $sPath = ""
	$sFileName = _Zip_PathStripSlash($sFileName)
	If StringInStr($sFileName, "\") Then
		; subdirectory, parse out path and filename
		$sPath = _Zip_PathPathOnly($sFileName)
		$sFileName = _Zip_PathNameOnly($sFileName)
	EndIf
	Local $oNS = _Zip_GetNameSpace($sZipFile, $sPath)
	If Not IsObj($oNS) Then Return SetError(4, 0, 0)
	Local $oFolderItem = $oNS.ParseName($sFileName)
	If Not IsObj($oFolderItem) Then Return SetError(5, 0, 0)
	$sDestPath = _Zip_PathStripSlash($sDestPath)
	If Not FileExists($sDestPath) Then
		DirCreate($sDestPath)
		If @error Then Return SetError(6, 0, 0)
	EndIf
	Local $oNS2 = _Zip_GetNameSpace($sDestPath)
	If Not IsObj($oNS2) Then Return SetError(7, 0, 0)
	; process overwrite flag
	Local $iOverwrite = 0
	If BitAND($iFlag, 1) Then
		$iOverwrite = 1
		$iFlag -= 1
	EndIf
	Local $sDestFullPath = $sDestPath & "\" & $sFileName
	If FileExists($sDestFullPath) Then
		; destination file exists
		If $iOverwrite Then
			If StringInStr(FileGetAttrib($sDestFullPath), "D") Then
				; folder
				If Not DirRemove($sDestFullPath, 1) Then Return SetError(8, 0, 0)
			Else
				If Not FileDelete($sDestFullPath) Then Return SetError(8, 0, 0)
			EndIf
		Else
			Return SetError(9, 0, 0)
		EndIf
	EndIf
	$oNS2.CopyHere($oFolderItem, $iFlag)
	; remove temp dir created by Windows
	DirRemove($sTempDir, 1)
	If FileExists($sDestFullPath) Then
		; success
		Return 1
	Else
		; failure
		Return SetError(10, 0, 0)
	EndIf
EndFunc   ;==>_Zip_Unzip

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_UnzipAll
; Description....:	Extract all files contained in a ZIP archive
; Syntax.........:	_Zip_UnzipAll($sZipFile, $sDestPath[, $iFlag = 20])
; Parameters.....:	$sZipFile   - Full path to ZIP file
;					$sDestPath  - Full path to the destination
;					$iFlag      - [Optional] File copy flags (Default = 4+16)
;								|   4 - No progress box
;								|   8 - Rename the file if a file of the same name already exists
;								|  16 - Respond "Yes to All" for any dialog that is displayed
;								|  64 - Preserve undo information, if possible
;								| 256 - Display a progress dialog box but do not show the file names
;								| 512 - Do not confirm the creation of a new directory if the operation requires one to be created
;								|1024 - Do not display a user interface if an error occurs
;								|2048 - Version 4.71. Do not copy the security attributes of the file
;								|4096 - Only operate in the local directory, don't operate recursively into subdirectories
;								|8192 - Version 5.0. Do not copy connected files as a group, only copy the specified files
;
; Return values..:	Success     - 1
;					Failure     - 0 and sets @error
;								| 1 - zipfldr.dll does not exist
;								| 2 - Library not installed
;								| 3 - Not a full path
;								| 4 - ZIP file does not exist
;								| 5 - Failed to create destination (if necessary)
;								| 6 - Failed to open destination
;								| 7 - Failed to extract file(s)
; Author.........:	wraithdu, torels
; Modified.......:
; Remarks........:	Overwriting of destination files is controlled solely by the file copy flags (ie $iFlag = 1 is NOT valid).
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _Zip_UnzipAll($sZipFile, $sDestPath, $iFlag = 20)
	If Not _Zip_DllChk() Then Return SetError(@error, 0, 0)
	If Not _IsFullPath($sZipFile) Or Not _IsFullPath($sDestPath) Then Return SetError(3, 0, 0)
	; get temp dir created by Windows
	Local $sTempDir = _Zip_TempDirName($sZipFile)
	Local $oNS = _Zip_GetNameSpace($sZipFile)
	If Not IsObj($oNS) Then Return SetError(4, 0, 0)
	$sDestPath = _Zip_PathStripSlash($sDestPath)
	If Not FileExists($sDestPath) Then
		DirCreate($sDestPath)
		If @error Then Return SetError(5, 0, 0)
	EndIf
	Local $oNS2 = _Zip_GetNameSpace($sDestPath)
	If Not IsObj($oNS2) Then Return SetError(6, 0, 0)
	$oNS2.CopyHere($oNS.Items(), $iFlag)
	; remove temp dir created by WIndows
	DirRemove($sTempDir, 1)
	If FileExists($sDestPath & "\" & $oNS.Items().Item($oNS.Items().Count - 1).Name) Then
		; success... most likely
		; checks for existence of last item from source in destination
		Return 1
	Else
		; failure
		Return SetError(7, 0, 0)
	EndIf
EndFunc   ;==>_Zip_UnzipAll

#region INTERNAL FUNCTIONS
; #FUNCTION# ====================================================================================================
; Name...........:	_IsFullPath
; Description....:	Determines if a given path is a fully qualified path (well, roughly...)
; Syntax.........:	_IsFullPath($sPath)
; Parameters.....:	$sPath  - Path to check
;
; Return values..:	Success - True
;					Failure - False
; Author.........:	torels
; Modified.......:
; Remarks........:
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _IsFullPath($sPath)
	If StringInStr($sPath, ":\") Then
		Return True
	Else
		Return False
	EndIf
EndFunc   ;==>_IsFullPath

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_AddPath
; Description....:	INTERNAL FUNCTION
; Author.........:	wraithdu
; ===============================================================================================================
Func _Zip_AddPath($sZipFile, $sPath)
	If Not _Zip_DllChk() Then Return SetError(@error, 0, 0)
	If Not _IsFullPath($sZipFile) Then Return SetError(3, 0, 0)
	Local $oNS = _Zip_GetNameSpace($sZipFile)
	If Not IsObj($oNS) Then Return SetError(4, 0, 0)
	; check and create directory structure
	$sPath = _Zip_PathStripSlash($sPath)
	Local $sNewPath = "", $sFileName = ""
	If $sPath <> "" Then
		Local $aDir = StringSplit($sPath, "\"), $oTest
		For $i = 1 To $aDir[0]
			; check if item already exists
			$oTest = $oNS.ParseName($aDir[$i])
			If IsObj($oTest) Then
				; check if folder
				If Not $oTest.IsFolder Then Return SetError(5, 0, 0)
				; get next namespace level
				$oNS = $oTest.GetFolder
			Else
				; create temp dir
				Local $sTempDir = _Zip_CreateTempDir()
				If @error Then Return SetError(6, 0, 0)
				Local $oTemp = _Zip_GetNameSpace($sTempDir)
				; create the directory structure
				For $i = $i To $aDir[0]
					$sNewPath &= $aDir[$i] & "\"
				Next
				DirCreate($sTempDir & "\" & $sNewPath)
				$sFileName = _Zip_CreateTempName()
				$sNewPath &= $sFileName
				FileClose(FileOpen($sTempDir & "\" & $sNewPath, 2 + 8))
				$oNS.CopyHere($oTemp.Items())
				; wait for file
				Do
					Sleep(250)
				Until _Zip_ItemExists($sZipFile, $sNewPath)
				DirRemove($sTempDir, 1)
				ExitLoop
			EndIf
		Next
	EndIf
	Return $sFileName
EndFunc   ;==>_Zip_AddPath

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_CreateTempDir
; Description....:	INTERNAL FUNCTION
; Author.........:	wraithdu
; ===============================================================================================================
Func _Zip_CreateTempDir()
	Local $s_TempName
	Do
		$s_TempName = ""
		While StringLen($s_TempName) < 7
			$s_TempName &= Chr(Random(97, 122, 1))
		WEnd
		$s_TempName = @TempDir & "\~" & $s_TempName & ".tmp"
	Until Not FileExists($s_TempName)
	If Not DirCreate($s_TempName) Then Return SetError(1, 0, 0)
	Return $s_TempName
EndFunc   ;==>_Zip_CreateTempDir

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_CreateTempName
; Description....:	INTERNAL FUNCTION
; Author.........:	wraithdu
; ===============================================================================================================
Func _Zip_CreateTempName()
	Local $GUID = DllStructCreate("dword Data1;word Data2;word Data3;byte Data4[8]")
	DllCall("ole32.dll", "int", "CoCreateGuid", "ptr", DllStructGetPtr($GUID))
	Local $ret = DllCall("ole32.dll", "int", "StringFromGUID2", "ptr", DllStructGetPtr($GUID), "wstr", "", "int", 40)
	If @error Then Return SetError(1, 0, "")
	Return StringRegExpReplace($ret[2], "[}{-]", "")
EndFunc   ;==>_Zip_CreateTempName

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_DllChk
; Description....:	Checks if the zipfldr library is installed
; Syntax.........:	_Zip_DllChk()
; Parameters.....:	None.
; Return values..:	Success - 1
;					Failure - 0 and sets @error
;							| 1 - zipfldr.dll not found
;							| 2 - Library not installed
; Author.........:	wraithdu, torels
; Modified.......:
; Remarks........:
; Related........:
; Link...........:
; Example........:
; ===============================================================================================================
Func _Zip_DllChk()
	If Not FileExists(@SystemDir & "\zipfldr.dll") Then Return SetError(1, 0, 0)
	If Not RegRead("HKEY_CLASSES_ROOT\CLSID\{E88DCCE0-B7B3-11d1-A9F0-00AA0060FA31}", "") Then Return SetError(2, 0, 0)
	Return 1
EndFunc   ;==>_Zip_DllChk

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_GetNameSpace
; Description....:	INTERNAL FUNCTION
; Author.........:	wraithdu
; ===============================================================================================================
Func _Zip_GetNameSpace($sZipFile, $sPath = "")
	If Not _Zip_DllChk() Then Return SetError(@error, 0, 0)
	If Not _IsFullPath($sZipFile) Then Return SetError(3, 0, 0)
	Local $oApp = ObjCreate("Shell.Application")
	Local $oNS = $oApp.NameSpace($sZipFile)
	If Not IsObj($oNS) Then Return SetError(4, 0, 0)
	If $sPath <> "" Then
		; subfolder
		Local $aPath = StringSplit($sPath, "\")
		Local $oItem
		For $i = 1 To $aPath[0]
			$oItem = $oNS.ParseName($aPath[$i])
			If Not IsObj($oItem) Then Return SetError(5, 0, 0)
			$oNS = $oItem.GetFolder
			If Not IsObj($oNS) Then Return SetError(6, 0, 0)
		Next
	EndIf
	Return $oNS
EndFunc   ;==>_Zip_GetNameSpace

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_InternalDelete
; Description....:	INTERNAL FUNCTION
; Author.........:	wraithdu
; ===============================================================================================================
Func _Zip_InternalDelete($sZipFile, $sFileName)
	If Not _Zip_DllChk() Then Return SetError(@error, 0, 0)
	If Not _IsFullPath($sZipFile) Then Return SetError(3, 0, 0)
	; parse filename
	Local $sPath = ""
	$sFileName = _Zip_PathStripSlash($sFileName)
	If StringInStr($sFileName, "\") Then
		; subdirectory, parse out path and filename
		$sPath = _Zip_PathPathOnly($sFileName)
		$sFileName = _Zip_PathNameOnly($sFileName)
	EndIf
	Local $oNS = _Zip_GetNameSpace($sZipFile, $sPath)
	If Not IsObj($oNS) Then Return SetError(4, 0, 0)
	Local $oFolderItem = $oNS.ParseName($sFileName)
	If Not IsObj($oFolderItem) Then Return SetError(5, 0, 0)
	; ## Ugh, this was ultimately a bad solution
	; move file to a temp directory and remove the directory
	Local $sTempDir = _Zip_CreateTempDir()
	If @error Then Return SetError(6, 0, 0)
	Local $oApp = ObjCreate("Shell.Application")
	$oApp.NameSpace($sTempDir).MoveHere($oFolderItem, 20)
	DirRemove($sTempDir, 1)
	$oFolderItem = $oNS.ParseName($sFileName)
	If IsObj($oFolderItem) Then
		; failure
		Return SetError(7, 0, 0)
	Else
		Return 1
	EndIf
EndFunc   ;==>_Zip_InternalDelete

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_ListAll_Internal
; Description....:	INTERNAL FUNCTION
; Author.........:	wraithdu
; ===============================================================================================================
Func _Zip_ListAll_Internal($sZipFile, $sSub, ByRef $aArray, $iFullPath, $sPrefix = "")
	Local $oNS = _Zip_GetNameSpace($sZipFile, $sSub)
	If Not IsObj($oNS) Then Return SetError(4, 0, 0)
	Local $oList = $oNS.Items(), $sSub2
	For $oItem In $oList
		; reset subdir so recursion doesn't break
		$sSub2 = $sSub
		If $oItem.IsFolder Then
			If $sSub2 = "" Then
				$sSub2 = $oItem.Name
			Else
				$sSub2 &= "\" & $oItem.Name
			EndIf
			; folder, recurse
			If $iFullPath Then
				; build path from root of zip
				_Zip_ListAll_Internal($sZipFile, $sSub2, $aArray, $iFullPath, $sSub2 & "\")
				If @error Then Return SetError(4)
			Else
				; just filenames
				_Zip_ListAll_Internal($sZipFile, $sSub2, $aArray, $iFullPath, "")
				If @error Then Return SetError(4)
			EndIf
		Else
			$aArray[0] += 1
			ReDim $aArray[$aArray[0] + 1]
			$aArray[$aArray[0]] = $sPrefix & $oItem.Name
		EndIf
	Next
EndFunc   ;==>_Zip_ListAll_Internal

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_PathNameOnly
; Description....:	INTERNAL FUNCTION
; Author.........:	wraithdu
; ===============================================================================================================
Func _Zip_PathNameOnly($sPath)
	Return StringRegExpReplace($sPath, ".*\\", "")
EndFunc   ;==>_Zip_PathNameOnly

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_PathPathOnly
; Description....:	INTERNAL FUNCTION
; Author.........:	wraithdu
; ===============================================================================================================
Func _Zip_PathPathOnly($sPath)
	Return StringRegExpReplace($sPath, "^(.*)\\.*?$", "${1}")
EndFunc   ;==>_Zip_PathPathOnly

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_PathStripSlash
; Description....:	INTERNAL FUNCTION
; Author.........:	wraithdu
; ===============================================================================================================
Func _Zip_PathStripSlash($sString)
	Return StringRegExpReplace($sString, "(^\\+|\\+$)", "")
EndFunc   ;==>_Zip_PathStripSlash

; #FUNCTION# ====================================================================================================
; Name...........:	_Zip_TempDirName
; Description....:	INTERNAL FUNCTION
; Author.........:	wraithdu, trancexxx
; ===============================================================================================================
Func _Zip_TempDirName($sZipFile)
	Local $i = 0, $sTemp, $sName = _Zip_PathNameOnly($sZipFile)
	Do
		$i += 1
		$sTemp = @TempDir & "\Temporary Directory " & $i & " for " & $sName
	Until Not FileExists($sTemp) ; this folder will be created during extraction
	Return $sTemp
EndFunc   ;==>_Zip_TempDirName
#endregion INTERNAL FUNCTIONS