Commit 167daeaa authored by Jake's avatar Jake

Merge remote-tracking branch 'marmelroy/master'

parents c898c506 2a3e908d
...@@ -72,5 +72,5 @@ github "marmelroy/Zip" ...@@ -72,5 +72,5 @@ github "marmelroy/Zip"
### Setting up with [CocoaPods](http://cocoapods.org/?q=Zip) ### Setting up with [CocoaPods](http://cocoapods.org/?q=Zip)
```ruby ```ruby
source 'https://github.com/CocoaPods/Specs.git' source 'https://github.com/CocoaPods/Specs.git'
pod 'Zip', '~> 0.3' pod 'Zip', '~> 0.4'
``` ```
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.4.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>6</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
Pod::Spec.new do |s| Pod::Spec.new do |s|
s.name = "Zip" s.name = "Zip"
s.version = "0.3.4" s.version = "0.4.1"
s.summary = "Zip and unzip files in Swift." s.summary = "Zip and unzip files in Swift."
# This description is used to generate tags and improve search results. # This description is used to generate tags and improve search results.
......
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0730"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "3425458C1CE525B200336074"
BuildableName = "Zip.framework"
BlueprintName = "Zip tvOS"
ReferencedContainer = "container:Zip.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "3425458C1CE525B200336074"
BuildableName = "Zip.framework"
BlueprintName = "Zip tvOS"
ReferencedContainer = "container:Zip.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "3425458C1CE525B200336074"
BuildableName = "Zip.framework"
BlueprintName = "Zip tvOS"
ReferencedContainer = "container:Zip.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.4.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>6</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
...@@ -15,11 +15,11 @@ ...@@ -15,11 +15,11 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>FMWK</string> <string>FMWK</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.3.4</string> <string>0.4.1</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>4</string> <string>6</string>
<key>NSPrincipalClass</key> <key>NSPrincipalClass</key>
<string></string> <string></string>
</dict> </dict>
......
...@@ -33,6 +33,8 @@ extension Zip { ...@@ -33,6 +33,8 @@ extension Zip {
- throws: Error if unzipping fails or if file is not found. Can be printed with a description variable. - throws: Error if unzipping fails or if file is not found. Can be printed with a description variable.
- notes: Supports implicit progress composition
- returns: NSURL of the destination folder. - returns: NSURL of the destination folder.
*/ */
public class func quickUnzipFile(path: NSURL, progress: ((progress: Double) -> ())?) throws -> NSURL { public class func quickUnzipFile(path: NSURL, progress: ((progress: Double) -> ())?) throws -> NSURL {
...@@ -57,6 +59,8 @@ extension Zip { ...@@ -57,6 +59,8 @@ extension Zip {
- throws: Error if zipping fails. - throws: Error if zipping fails.
- notes: Supports implicit progress composition
- returns: NSURL of the destination folder. - returns: NSURL of the destination folder.
*/ */
public class func quickZipFiles(paths: [NSURL], fileName: String) throws -> NSURL { public class func quickZipFiles(paths: [NSURL], fileName: String) throws -> NSURL {
...@@ -72,6 +76,8 @@ extension Zip { ...@@ -72,6 +76,8 @@ extension Zip {
- throws: Error if zipping fails. - throws: Error if zipping fails.
- notes: Supports implicit progress composition
- returns: NSURL of the destination folder. - returns: NSURL of the destination folder.
*/ */
public class func quickZipFiles(paths: [NSURL], fileName: String, progress: ((progress: Double) -> ())?) throws -> NSURL { public class func quickZipFiles(paths: [NSURL], fileName: String, progress: ((progress: Double) -> ())?) throws -> NSURL {
......
...@@ -31,6 +31,11 @@ public enum ZipError: ErrorType { ...@@ -31,6 +31,11 @@ public enum ZipError: ErrorType {
/// Zip class /// Zip class
public class Zip { public class Zip {
/**
Set of vaild file extensions
*/
internal static var customFileExtensions: Set<String> = []
// MARK: Lifecycle // MARK: Lifecycle
/** /**
...@@ -53,6 +58,8 @@ public class Zip { ...@@ -53,6 +58,8 @@ public class Zip {
- parameter progress: A progress closure called after unzipping each file in the archive. Double value betweem 0 and 1. - parameter progress: A progress closure called after unzipping each file in the archive. Double value betweem 0 and 1.
- throws: Error if unzipping fails or if fail is not found. Can be printed with a description variable. - throws: Error if unzipping fails or if fail is not found. Can be printed with a description variable.
- notes: Supports implicit progress composition
*/ */
public class func unzipFile(zipFilePath: NSURL, destination: NSURL, overwrite: Bool, password: String?, progress: ((progress: Double) -> ())?) throws { public class func unzipFile(zipFilePath: NSURL, destination: NSURL, overwrite: Bool, password: String?, progress: ((progress: Double) -> ())?) throws {
...@@ -64,7 +71,7 @@ public class Zip { ...@@ -64,7 +71,7 @@ public class Zip {
guard let path = zipFilePath.path where destination.path != nil else { guard let path = zipFilePath.path where destination.path != nil else {
throw ZipError.FileNotFound throw ZipError.FileNotFound
} }
if fileManager.fileExistsAtPath(path) == false || zipFilePath.pathExtension != "zip" { if fileManager.fileExistsAtPath(path) == false || fileExtensionIsInvalid(zipFilePath.pathExtension) {
throw ZipError.FileNotFound throw ZipError.FileNotFound
} }
...@@ -82,8 +89,16 @@ public class Zip { ...@@ -82,8 +89,16 @@ public class Zip {
totalSize += attributeFileSize totalSize += attributeFileSize
} }
let progressTracker = NSProgress(totalUnitCount: Int64(totalSize))
progressTracker.cancellable = false
progressTracker.pausable = false
progressTracker.kind = NSProgressKindFile
// Begin unzipping // Begin unzipping
let zip = unzOpen64(path) let zip = unzOpen64(path)
defer {
unzClose(zip)
}
if unzGoToFirstFile(zip) != UNZ_OK { if unzGoToFirstFile(zip) != UNZ_OK {
throw ZipError.UnzipFail throw ZipError.UnzipFail
} }
...@@ -165,6 +180,8 @@ public class Zip { ...@@ -165,6 +180,8 @@ public class Zip {
progressHandler(progress: (currentPosition/totalSize)) progressHandler(progress: (currentPosition/totalSize))
} }
progressTracker.completedUnitCount = Int64(currentPosition)
} while (ret == UNZ_OK && ret != UNZ_END_OF_LIST_OF_FILE) } while (ret == UNZ_OK && ret != UNZ_END_OF_LIST_OF_FILE)
// Completed. Update progress handler. // Completed. Update progress handler.
...@@ -172,6 +189,8 @@ public class Zip { ...@@ -172,6 +189,8 @@ public class Zip {
progressHandler(progress: 1.0) progressHandler(progress: 1.0)
} }
progressTracker.completedUnitCount = Int64(totalSize)
} }
// MARK: Zip // MARK: Zip
...@@ -185,6 +204,8 @@ public class Zip { ...@@ -185,6 +204,8 @@ public class Zip {
- parameter progress: A progress closure called after unzipping each file in the archive. Double value betweem 0 and 1. - parameter progress: A progress closure called after unzipping each file in the archive. Double value betweem 0 and 1.
- throws: Error if zipping fails. - throws: Error if zipping fails.
- notes: Supports implicit progress composition
*/ */
public class func zipFiles(paths: [NSURL], zipFilePath: NSURL, password: String?, progress: ((progress: Double) -> ())?) throws { public class func zipFiles(paths: [NSURL], zipFilePath: NSURL, password: String?, progress: ((progress: Double) -> ())?) throws {
...@@ -218,6 +239,11 @@ public class Zip { ...@@ -218,6 +239,11 @@ public class Zip {
catch {} catch {}
} }
let progressTracker = NSProgress(totalUnitCount: Int64(totalSize))
progressTracker.cancellable = false
progressTracker.pausable = false
progressTracker.kind = NSProgressKindFile
// Begin Zipping // Begin Zipping
let zip = zipOpen(destinationPath, APPEND_STATUS_CREATE) let zip = zipOpen(destinationPath, APPEND_STATUS_CREATE)
for path in processedPaths { for path in processedPaths {
...@@ -268,6 +294,8 @@ public class Zip { ...@@ -268,6 +294,8 @@ public class Zip {
progressHandler(progress: (currentPosition/totalSize)) progressHandler(progress: (currentPosition/totalSize))
} }
progressTracker.completedUnitCount = Int64(currentPosition)
zipCloseFileInZip(zip) zipCloseFileInZip(zip)
free(buffer) free(buffer)
fclose(input) fclose(input)
...@@ -279,8 +307,54 @@ public class Zip { ...@@ -279,8 +307,54 @@ public class Zip {
if let progressHandler = progress{ if let progressHandler = progress{
progressHandler(progress: 1.0) progressHandler(progress: 1.0)
} }
progressTracker.completedUnitCount = Int64(totalSize)
}
/**
Check if file extension is invalid.
- parameter fileExtension: A file extension.
- returns: false if the extension is a valid file extension, otherwise true.
*/
internal class func fileExtensionIsInvalid(fileExtension: String?) -> Bool {
guard let fileExtension = fileExtension else { return true }
return !isValidFileExtension(fileExtension)
}
/**
Add a file extension to the set of custom file extensions
- parameter fileExtension: A file extension.
*/
public class func addCustomFileExtension(fileExtension: String) {
customFileExtensions.insert(fileExtension)
}
/**
Remove a file extension from the set of custom file extensions
- parameter fileExtension: A file extension.
*/
public class func removeCustomFileExtension(fileExtension: String) {
customFileExtensions.remove(fileExtension)
} }
/**
Check if a specific file extension is valid
- parameter fileExtension: A file extension.
- returns: true if the extension valid, otherwise false.
*/
public class func isValidFileExtension(fileExtension: String) -> Bool {
let validFileExtensions: Set<String> = customFileExtensions.union(["zip", "cbz"])
return validFileExtensions.contains(fileExtension)
}
} }
...@@ -15,10 +15,10 @@ ...@@ -15,10 +15,10 @@
<key>CFBundlePackageType</key> <key>CFBundlePackageType</key>
<string>BNDL</string> <string>BNDL</string>
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.3.4</string> <string>0.4.1</string>
<key>CFBundleSignature</key> <key>CFBundleSignature</key>
<string>????</string> <string>????</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>4</string> <string>6</string>
</dict> </dict>
</plist> </plist>
...@@ -84,9 +84,11 @@ class ZipTests: XCTestCase { ...@@ -84,9 +84,11 @@ class ZipTests: XCTestCase {
do { do {
let filePath = NSBundle(forClass: ZipTests.self).URLForResource("bb8", withExtension: "zip")! let filePath = NSBundle(forClass: ZipTests.self).URLForResource("bb8", withExtension: "zip")!
let documentsFolder = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as NSURL let documentsFolder = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as NSURL
try Zip.unzipFile(filePath, destination: documentsFolder, overwrite: true, password: "password", progress: { (progress) -> () in try Zip.unzipFile(filePath, destination: documentsFolder, overwrite: true, password: "password", progress: { (progress) -> () in
print(progress) print(progress)
}) })
let fileManager = NSFileManager.defaultManager() let fileManager = NSFileManager.defaultManager()
XCTAssertTrue(fileManager.fileExistsAtPath(documentsFolder.path!)) XCTAssertTrue(fileManager.fileExistsAtPath(documentsFolder.path!))
} }
...@@ -95,6 +97,48 @@ class ZipTests: XCTestCase { ...@@ -95,6 +97,48 @@ class ZipTests: XCTestCase {
} }
} }
func testImplicitProgressUnzip() {
do {
let progress = NSProgress()
progress.totalUnitCount = 1
let filePath = NSBundle(forClass: ZipTests.self).URLForResource("bb8", withExtension: "zip")!
let documentsFolder = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as NSURL
progress.becomeCurrentWithPendingUnitCount(1)
try Zip.unzipFile(filePath, destination: documentsFolder, overwrite: true, password: "password", progress: nil)
progress.resignCurrent()
XCTAssertTrue(progress.totalUnitCount == progress.completedUnitCount)
}
catch {
XCTFail()
}
}
func testImplicitProgressZip() {
do {
let progress = NSProgress()
progress.totalUnitCount = 1
let imageURL1 = NSBundle(forClass: ZipTests.self).URLForResource("3crBXeO", withExtension: "gif")!
let imageURL2 = NSBundle(forClass: ZipTests.self).URLForResource("kYkLkPf", withExtension: "gif")!
let documentsFolder = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as NSURL
let zipFilePath = documentsFolder.URLByAppendingPathComponent("archive.zip")
progress.becomeCurrentWithPendingUnitCount(1)
try Zip.zipFiles([imageURL1, imageURL2], zipFilePath: zipFilePath, password: nil, progress: nil)
progress.resignCurrent()
XCTAssertTrue(progress.totalUnitCount == progress.completedUnitCount)
}
catch {
XCTFail()
}
}
func testQuickZip() { func testQuickZip() {
do { do {
let imageURL1 = NSBundle(forClass: ZipTests.self).URLForResource("3crBXeO", withExtension: "gif")! let imageURL1 = NSBundle(forClass: ZipTests.self).URLForResource("3crBXeO", withExtension: "gif")!
...@@ -148,6 +192,32 @@ class ZipTests: XCTestCase { ...@@ -148,6 +192,32 @@ class ZipTests: XCTestCase {
} }
} }
func testZipUnzipPassword() {
do {
let imageURL1 = NSBundle(forClass: ZipTests.self).URLForResource("3crBXeO", withExtension: "gif")!
let imageURL2 = NSBundle(forClass: ZipTests.self).URLForResource("kYkLkPf", withExtension: "gif")!
let documentsFolder = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as NSURL
let zipFilePath = documentsFolder.URLByAppendingPathComponent("archive.zip")
try Zip.zipFiles([imageURL1, imageURL2], zipFilePath: zipFilePath, password: "password", progress: { (progress) -> () in
print(progress)
})
let fileManager = NSFileManager.defaultManager()
XCTAssertTrue(fileManager.fileExistsAtPath(zipFilePath.path!))
guard let fileExtension = zipFilePath.pathExtension, let fileName = zipFilePath.lastPathComponent else {
throw ZipError.UnzipFail
}
let directoryName = fileName.stringByReplacingOccurrencesOfString(".\(fileExtension)", withString: "")
let documentsUrl = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as NSURL
let destinationUrl = documentsUrl.URLByAppendingPathComponent(directoryName, isDirectory: true)
try Zip.unzipFile(zipFilePath, destination: destinationUrl, overwrite: true, password: "password", progress: nil)
XCTAssertTrue(fileManager.fileExistsAtPath(destinationUrl.path!))
}
catch {
XCTFail()
}
}
func testQuickUnzipSubDir() { func testQuickUnzipSubDir() {
do { do {
let bookURL = NSBundle(forClass: ZipTests.self).URLForResource("bb8", withExtension: "zip")! let bookURL = NSBundle(forClass: ZipTests.self).URLForResource("bb8", withExtension: "zip")!
...@@ -165,5 +235,44 @@ class ZipTests: XCTestCase { ...@@ -165,5 +235,44 @@ class ZipTests: XCTestCase {
} }
} }
func testFileExtensionIsNotInvalidForValidUrl() {
let fileUrl = NSURL(string: "file.cbz")
let result = Zip.fileExtensionIsInvalid(fileUrl?.pathExtension)
XCTAssertFalse(result)
}
func testFileExtensionIsInvalidForInvalidUrl() {
let fileUrl = NSURL(string: "file.xyz")
let result = Zip.fileExtensionIsInvalid(fileUrl?.pathExtension)
XCTAssertTrue(result)
}
func testAddedCustomFileExtensionIsValid() {
let fileExtension = "cstm"
Zip.addCustomFileExtension(fileExtension)
let result = Zip.isValidFileExtension(fileExtension)
XCTAssertTrue(result)
Zip.removeCustomFileExtension(fileExtension)
}
func testRemovedCustomFileExtensionIsInvalid() {
let fileExtension = "cstm"
Zip.addCustomFileExtension(fileExtension)
Zip.removeCustomFileExtension(fileExtension)
let result = Zip.isValidFileExtension(fileExtension)
XCTAssertFalse(result)
}
func testDefaultFileExtensionsIsValid() {
XCTAssertTrue(Zip.isValidFileExtension("zip"))
XCTAssertTrue(Zip.isValidFileExtension("cbz"))
}
func testDefaultFileExtensionsIsNotRemoved() {
Zip.removeCustomFileExtension("zip")
Zip.removeCustomFileExtension("cbz")
XCTAssertTrue(Zip.isValidFileExtension("zip"))
XCTAssertTrue(Zip.isValidFileExtension("cbz"))
}
} }
...@@ -40,7 +40,7 @@ if [ "$MODE" = "examples" ]; then ...@@ -40,7 +40,7 @@ if [ "$MODE" = "examples" ]; then
-scheme Sample \ -scheme Sample \
-sdk "$SDK" \ -sdk "$SDK" \
-destination "$PLATFORM" \ -destination "$PLATFORM" \
build test build
done done
trap - EXIT trap - EXIT
exit 0 exit 0
......
...@@ -2,4 +2,6 @@ source 'https://github.com/CocoaPods/Specs.git' ...@@ -2,4 +2,6 @@ source 'https://github.com/CocoaPods/Specs.git'
platform :ios, "9.0" platform :ios, "9.0"
use_frameworks! use_frameworks!
target Sample do
pod 'Zip', :git => 'https://github.com/marmelroy/Zip.git', :submodules => true pod 'Zip', :git => 'https://github.com/marmelroy/Zip.git', :submodules => true
end
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment