Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 23 additions & 5 deletions Zip/Zip.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,16 @@ public enum ZipError: Error {
case unzipFail
/// Zip fail
case zipFail

/// Operation Cancelled
case operationCancelled

/// User readable description
public var description: String {
switch self {
case .fileNotFound: return NSLocalizedString("File not found.", comment: "")
case .unzipFail: return NSLocalizedString("Failed to unzip file.", comment: "")
case .zipFail: return NSLocalizedString("Failed to zip file.", comment: "")
case .operationCancelled: return NSLocalizedString("Operation cancelled", comment: "")
}
}
}
Expand All @@ -50,12 +53,16 @@ public enum ZipCompression: Int {

/// Zip class
public class Zip {

/**
Set of vaild file extensions
*/
internal static var customFileExtensions: Set<String> = []

/**
Cancellation block. This is set once the progress tracker is has been created
*/
public static var cancelCurrentOperation: (()->Void) = { }

// MARK: Lifecycle

/**
Expand Down Expand Up @@ -113,6 +120,8 @@ public class Zip {
progressTracker.isPausable = false
progressTracker.kind = ProgressKind.file

cancelCurrentOperation = { progressTracker.cancel() }

// Begin unzipping
let zip = unzOpen64(path)
defer {
Expand Down Expand Up @@ -234,16 +243,19 @@ public class Zip {
}

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) && !progressTracker.isCancelled

guard !progressTracker.isCancelled else {
throw ZipError.operationCancelled
}

// Completed. Update progress handler.
if let progressHandler = progress{
progressHandler(1.0)
}

progressTracker.completedUnitCount = Int64(totalSize)

}

// MARK: Zip
Expand Down Expand Up @@ -297,6 +309,8 @@ public class Zip {
progressTracker.isPausable = false
progressTracker.kind = ProgressKind.file

cancelCurrentOperation = { progressTracker.cancel() }

// Begin Zipping
let zip = zipOpen(destinationPath, APPEND_STATUS_CREATE)
for path in processedPaths {
Expand Down Expand Up @@ -338,6 +352,10 @@ public class Zip {
}
var length: Int = 0
while (feof(input) == 0) {
guard !progressTracker.isCancelled else {
throw ZipError.operationCancelled
}

length = fread(buffer, 1, chunkSize, input)
zipWriteInFileInZip(zip, buffer, UInt32(length))
}
Expand Down
65 changes: 65 additions & 0 deletions ZipTests/ZipTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -315,4 +315,69 @@ class ZipTests: XCTestCase {
XCTAssertTrue(Zip.isValidFileExtension("cbz"))
}

func testCancelDuringZipCancels() {
var currentProgress: Double = 0

let expect = expectation(description: "Zip operation should throw .OperationCancelled")

do {
let progress = Progress()
progress.totalUnitCount = 1

let imageURL1 = Bundle(for: ZipTests.self).url(forResource: "3crBXeO", withExtension: "gif")!
let imageURL2 = Bundle(for: ZipTests.self).url(forResource: "kYkLkPf", withExtension: "gif")!
let documentsFolder = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as NSURL
let zipFilePath = documentsFolder.appendingPathComponent("archive.zip")!

try Zip.zipFiles(paths: [imageURL1, imageURL2], zipFilePath: zipFilePath, password: nil) { progress in
currentProgress = progress

if progress > 0 {
Zip.cancelCurrentOperation()
}
}

}
catch {
XCTAssertEqual(error as? ZipError, .operationCancelled)
XCTAssertLessThan(currentProgress, 1, "Progress should be less than 1 when cancelling the current operation")
expect.fulfill()
}

waitForExpectations(timeout: 5) { error in
XCTAssertNil(error)
}
}

func testCancelDuringUnzipCancels() {
var currentProgress: Double = 0
let expect = expectation(description: "Unzip operation should throw .OperationCancelled")

do {
let progress = Progress()
progress.totalUnitCount = 1

let bookURL = Bundle(for: ZipTests.self).url(forResource: "bb8", withExtension: "zip")!
let documentsFolder = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] as NSURL
let zipFilePath = documentsFolder.appendingPathComponent("contents")!

try Zip.unzipFile(bookURL, destination: zipFilePath, overwrite: true, password: nil, progress: { progress in
currentProgress = progress

if progress > 0 {
Zip.cancelCurrentOperation()
}
}) { _ in }
}
catch {
XCTAssertEqual(error as? ZipError, .operationCancelled)
XCTAssertLessThan(currentProgress, 1, "Progress should be less than 1 when cancelling the current operation")
expect.fulfill()
}

waitForExpectations(timeout: 5) { error in
XCTAssertNil(error)
}
}

}