Commit 5afb94de authored by Ryan Measel's avatar Ryan Measel

Functionality to zip files from memory

The purpose of this change is to add functionality for zipping files
from memory rather than files. This removes the necessity to write a
generated file to disk before being able to archive, thus saving lots of
disk i/o.

The struct `ArchiveFile` represents the same data that is loaded from a
file.

The new method `zipData` allows an array of `ArchiveFiles` to be passed
rather than file URLs and are zipped accordingly. Other functionality
remains identical.
parent be01e413
...@@ -48,6 +48,20 @@ public enum ZipCompression: Int { ...@@ -48,6 +48,20 @@ public enum ZipCompression: Int {
} }
} }
/// Data in memory that will be archived as a file.
public struct ArchiveFile {
var filename:String
var data:NSData
var modifiedTime:Date?
public init(filename:String, data:NSData, modifiedTime:Date?) {
self.filename = filename
self.data = data
self.modifiedTime = modifiedTime
}
}
/// Zip class /// Zip class
public class Zip { public class Zip {
...@@ -364,6 +378,102 @@ public class Zip { ...@@ -364,6 +378,102 @@ public class Zip {
progressTracker.completedUnitCount = Int64(totalSize) progressTracker.completedUnitCount = Int64(totalSize)
} }
/**
Zip data in memory.
- parameter archiveFiles:Array of Archive Files.
- parameter zipFilePath: Destination NSURL, should lead to a .zip filepath.
- parameter password: Password string. Optional.
- parameter compression: Compression strategy
- 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 zipData(archiveFiles:[ArchiveFile], zipFilePath:URL, password: String?, compression: ZipCompression = .DefaultCompression, progress: ((_ progress: Double) -> ())?) throws {
let destinationPath = zipFilePath.path
// Progress handler set up
var currentPosition: Int = 0
var totalSize: Int = 0
for archiveFile in archiveFiles {
totalSize += archiveFile.data.length
}
let progressTracker = Progress(totalUnitCount: Int64(totalSize))
progressTracker.isCancellable = false
progressTracker.isPausable = false
progressTracker.kind = ProgressKind.file
// Begin Zipping
let zip = zipOpen(destinationPath, APPEND_STATUS_CREATE)
for archiveFile in archiveFiles {
// Skip empty data
if archiveFile.data.length == 0 {
continue
}
// Setup the zip file info
var zipInfo = zip_fileinfo(tmz_date: tm_zip(tm_sec: 0, tm_min: 0, tm_hour: 0, tm_mday: 0, tm_mon: 0, tm_year: 0),
dosDate: 0,
internal_fa: 0,
external_fa: 0)
if let modifiedTime = archiveFile.modifiedTime {
let calendar = Calendar.current
zipInfo.tmz_date.tm_sec = UInt32(calendar.component(.second, from: modifiedTime))
zipInfo.tmz_date.tm_min = UInt32(calendar.component(.minute, from: modifiedTime))
zipInfo.tmz_date.tm_hour = UInt32(calendar.component(.hour, from: modifiedTime))
zipInfo.tmz_date.tm_mday = UInt32(calendar.component(.day, from: modifiedTime))
zipInfo.tmz_date.tm_mon = UInt32(calendar.component(.month, from: modifiedTime))
zipInfo.tmz_date.tm_year = UInt32(calendar.component(.year, from: modifiedTime))
}
// Write the data as a file to zip
zipOpenNewFileInZip3(zip,
archiveFile.filename,
&zipInfo,
nil,
0,
nil,
0,
nil,
Z_DEFLATED,
compression.minizipCompression,
0,
-MAX_WBITS,
DEF_MEM_LEVEL,
Z_DEFAULT_STRATEGY,
password,
0)
zipWriteInFileInZip(zip, archiveFile.data.bytes, UInt32(archiveFile.data.length))
zipCloseFileInZip(zip)
// Update progress handler
currentPosition += archiveFile.data.length
if let progressHandler = progress{
progressHandler((Double(currentPosition/totalSize)))
}
progressTracker.completedUnitCount = Int64(currentPosition)
}
zipClose(zip, nil)
// Completed. Update progress handler.
if let progressHandler = progress{
progressHandler(1.0)
}
progressTracker.completedUnitCount = Int64(totalSize)
}
/** /**
Check if file extension is invalid. Check if file extension is invalid.
......
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