Commit 167daeaa authored by Jake's avatar Jake

Merge remote-tracking branch 'marmelroy/master'

parents c898c506 2a3e908d
......@@ -72,5 +72,5 @@ github "marmelroy/Zip"
### Setting up with [CocoaPods](http://cocoapods.org/?q=Zip)
```ruby
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 @@
Pod::Spec.new do |s|
s.name = "Zip"
s.version = "0.3.4"
s.version = "0.4.1"
s.summary = "Zip and unzip files in Swift."
# 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 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>0.3.4</string>
<string>0.4.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>4</string>
<string>6</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
......
......@@ -11,7 +11,7 @@ import Foundation
extension Zip {
//MARK: Quick Unzip
/**
Quick unzip a file. Unzips to a new folder inside the app's documents folder with the zip file's name.
......@@ -33,6 +33,8 @@ extension Zip {
- 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.
*/
public class func quickUnzipFile(path: NSURL, progress: ((progress: Double) -> ())?) throws -> NSURL {
......@@ -50,30 +52,34 @@ extension Zip {
//MARK: Quick Zip
/**
Quick zip files.
- parameter paths: Array of NSURL filepaths.
- parameter fileName: File name for the resulting zip file.
- throws: Error if zipping fails.
- returns: NSURL of the destination folder.
*/
Quick zip files.
- parameter paths: Array of NSURL filepaths.
- parameter fileName: File name for the resulting zip file.
- throws: Error if zipping fails.
- notes: Supports implicit progress composition
- returns: NSURL of the destination folder.
*/
public class func quickZipFiles(paths: [NSURL], fileName: String) throws -> NSURL {
return try quickZipFiles(paths, fileName: fileName, progress: nil)
}
/**
Quick zip files.
- parameter paths: Array of NSURL filepaths.
- parameter fileName: File name for the resulting zip file.
- parameter progress: A progress closure called after unzipping each file in the archive. Double value betweem 0 and 1.
- throws: Error if zipping fails.
- returns: NSURL of the destination folder.
*/
/**
Quick zip files.
- parameter paths: Array of NSURL filepaths.
- parameter fileName: File name for the resulting zip file.
- parameter progress: A progress closure called after unzipping each file in the archive. Double value betweem 0 and 1.
- throws: Error if zipping fails.
- notes: Supports implicit progress composition
- returns: NSURL of the destination folder.
*/
public class func quickZipFiles(paths: [NSURL], fileName: String, progress: ((progress: Double) -> ())?) throws -> NSURL {
let fileManager = NSFileManager.defaultManager()
let documentsUrl = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as NSURL
......@@ -82,5 +88,5 @@ extension Zip {
return destinationUrl
}
}
\ No newline at end of file
......@@ -17,7 +17,7 @@ public enum ZipError: ErrorType {
case UnzipFail
/// Zip fail
case ZipFail
/// User readable description
public var description: String {
switch self {
......@@ -31,6 +31,11 @@ public enum ZipError: ErrorType {
/// Zip class
public class Zip {
/**
Set of vaild file extensions
*/
internal static var customFileExtensions: Set<String> = []
// MARK: Lifecycle
/**
......@@ -42,7 +47,7 @@ public class Zip {
}
// MARK: Unzip
/**
Unzip file
......@@ -51,20 +56,22 @@ public class Zip {
- parameter overwrite: Overwrite bool.
- parameter password: Optional password if file is protected.
- 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.
- notes: Supports implicit progress composition
*/
public class func unzipFile(zipFilePath: NSURL, destination: NSURL, overwrite: Bool, password: String?, progress: ((progress: Double) -> ())?) throws {
// File manager
let fileManager = NSFileManager.defaultManager()
// Check whether a zip file exists at path.
guard let path = zipFilePath.path where destination.path != nil else {
throw ZipError.FileNotFound
}
if fileManager.fileExistsAtPath(path) == false || zipFilePath.pathExtension != "zip" {
if fileManager.fileExistsAtPath(path) == false || fileExtensionIsInvalid(zipFilePath.pathExtension) {
throw ZipError.FileNotFound
}
......@@ -81,9 +88,17 @@ public class Zip {
if let attributeFileSize = fileAttributes[NSFileSize] as? Double {
totalSize += attributeFileSize
}
let progressTracker = NSProgress(totalUnitCount: Int64(totalSize))
progressTracker.cancellable = false
progressTracker.pausable = false
progressTracker.kind = NSProgressKindFile
// Begin unzipping
let zip = unzOpen64(path)
defer {
unzClose(zip)
}
if unzGoToFirstFile(zip) != UNZ_OK {
throw ZipError.UnzipFail
}
......@@ -165,27 +180,33 @@ public class Zip {
progressHandler(progress: (currentPosition/totalSize))
}
progressTracker.completedUnitCount = Int64(currentPosition)
} while (ret == UNZ_OK && ret != UNZ_END_OF_LIST_OF_FILE)
// Completed. Update progress handler.
if let progressHandler = progress{
progressHandler(progress: 1.0)
}
progressTracker.completedUnitCount = Int64(totalSize)
}
// MARK: Zip
/**
Zip files.
- parameter paths: Array of NSURL filepaths.
- parameter zipFilePath: Destination NSURL, should lead to a .zip filepath.
- parameter password: Password string. Optional.
- parameter progress: A progress closure called after unzipping each file in the archive. Double value betweem 0 and 1.
- throws: Error if zipping fails.
*/
Zip files.
- parameter paths: Array of NSURL filepaths.
- parameter zipFilePath: Destination NSURL, should lead to a .zip filepath.
- parameter password: Password string. Optional.
- parameter progress: A progress closure called after unzipping each file in the archive. Double value betweem 0 and 1.
- throws: Error if zipping fails.
- notes: Supports implicit progress composition
*/
public class func zipFiles(paths: [NSURL], zipFilePath: NSURL, password: String?, progress: ((progress: Double) -> ())?) throws {
// File manager
......@@ -218,6 +239,11 @@ public class Zip {
catch {}
}
let progressTracker = NSProgress(totalUnitCount: Int64(totalSize))
progressTracker.cancellable = false
progressTracker.pausable = false
progressTracker.kind = NSProgressKindFile
// Begin Zipping
let zip = zipOpen(destinationPath, APPEND_STATUS_CREATE)
for path in processedPaths {
......@@ -268,6 +294,8 @@ public class Zip {
progressHandler(progress: (currentPosition/totalSize))
}
progressTracker.completedUnitCount = Int64(currentPosition)
zipCloseFileInZip(zip)
free(buffer)
fclose(input)
......@@ -279,8 +307,54 @@ public class Zip {
if let progressHandler = progress{
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)
}
}
\ No newline at end of file
/**
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 @@
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>0.3.4</string>
<string>0.4.1</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>4</string>
<string>6</string>
</dict>
</plist>
......@@ -43,7 +43,7 @@ class ZipTests: XCTestCase {
XCTAssert(true)
}
}
func testQuickUnzipNonZipPath() {
do {
let filePath = NSBundle(forClass: ZipTests.self).URLForResource("3crBXeO", withExtension: "gif")!
......@@ -84,9 +84,11 @@ class ZipTests: XCTestCase {
do {
let filePath = NSBundle(forClass: ZipTests.self).URLForResource("bb8", withExtension: "zip")!
let documentsFolder = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0] as NSURL
try Zip.unzipFile(filePath, destination: documentsFolder, overwrite: true, password: "password", progress: { (progress) -> () in
print(progress)
})
let fileManager = NSFileManager.defaultManager()
XCTAssertTrue(fileManager.fileExistsAtPath(documentsFolder.path!))
}
......@@ -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() {
do {
let imageURL1 = NSBundle(forClass: ZipTests.self).URLForResource("3crBXeO", withExtension: "gif")!
......@@ -129,7 +173,7 @@ class ZipTests: XCTestCase {
XCTFail()
}
}
func testZip() {
do {
......@@ -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() {
do {
let bookURL = NSBundle(forClass: ZipTests.self).URLForResource("bb8", withExtension: "zip")!
......@@ -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
-scheme Sample \
-sdk "$SDK" \
-destination "$PLATFORM" \
build test
build
done
trap - EXIT
exit 0
......
......@@ -2,4 +2,6 @@ source 'https://github.com/CocoaPods/Specs.git'
platform :ios, "9.0"
use_frameworks!
target Sample do
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