Switch zip implementation

This commit is contained in:
Ali 2021-01-25 18:39:31 +05:00
parent b61e28ae44
commit f29cfa3f24
47 changed files with 14408 additions and 2280 deletions

View File

@ -15,7 +15,7 @@ swift_library(
"//submodules/SyncCore:SyncCore",
"//submodules/TelegramCore:TelegramCore",
"//submodules/AppBundle:AppBundle",
"//third-party/ZIPFoundation:ZIPFoundation",
"//third-party/ZipArchive:ZipArchive",
"//submodules/AccountContext:AccountContext",
"//submodules/PresentationDataUtils:PresentationDataUtils",
"//submodules/RadialStatusNode:RadialStatusNode",

View File

@ -11,7 +11,7 @@ import PresentationDataUtils
import RadialStatusNode
import AnimatedStickerNode
import AppBundle
import ZIPFoundation
import ZipArchive
import MimeTypes
import ConfettiEffect
import TelegramUniversalVideoContent
@ -398,10 +398,10 @@ public final class ChatImportActivityScreen: ViewController {
private var presentationData: PresentationData
fileprivate let cancel: () -> Void
fileprivate var peerId: PeerId
private let archive: Archive
private let archivePath: String
private let mainEntry: TempBoxFile
private let mainEntrySize: Int
private let otherEntries: [(Entry, String, ChatHistoryImport.MediaType, Promise<TempBoxFile?>)]
private let otherEntries: [(SSZipEntry, String, ChatHistoryImport.MediaType, Promise<TempBoxFile?>)]
private let totalBytes: Int
private var pendingEntries: [String: (Int, Float)] = [:]
@ -415,27 +415,27 @@ public final class ChatImportActivityScreen: ViewController {
}
}
public init(context: AccountContext, cancel: @escaping () -> Void, peerId: PeerId, archive: Archive, mainEntry: TempBoxFile, otherEntries: [(Entry, String, ChatHistoryImport.MediaType)]) {
public init(context: AccountContext, cancel: @escaping () -> Void, peerId: PeerId, archivePath: String, mainEntry: TempBoxFile, otherEntries: [(SSZipEntry, String, ChatHistoryImport.MediaType)]) {
self.context = context
self.cancel = cancel
self.peerId = peerId
self.archive = archive
self.archivePath = archivePath
self.mainEntry = mainEntry
self.otherEntries = otherEntries.map { entry -> (Entry, String, ChatHistoryImport.MediaType, Promise<TempBoxFile?>) in
self.otherEntries = otherEntries.map { entry -> (SSZipEntry, String, ChatHistoryImport.MediaType, Promise<TempBoxFile?>) in
let signal = Signal<TempBoxFile?, NoError> { subscriber in
let tempFile = TempBox.shared.tempFile(fileName: entry.1)
do {
let _ = try archive.extract(entry.0, to: URL(fileURLWithPath: tempFile.path))
if SSZipArchive.extractFileFromArchive(atPath: archivePath, filePath: entry.0.path, toPath: tempFile.path) {
subscriber.putNext(tempFile)
subscriber.putCompletion()
} catch {
} else {
subscriber.putNext(nil)
subscriber.putCompletion()
}
return EmptyDisposable
}
|> runOn(Queue.concurrentDefaultQueue())
let promise = Promise<TempBoxFile?>()
promise.set(signal)
return (entry.0, entry.1, entry.2, promise)
@ -448,12 +448,12 @@ public final class ChatImportActivityScreen: ViewController {
}
for (entry, fileName, _) in otherEntries {
self.pendingEntries[fileName] = (entry.uncompressedSize, 0.0)
self.pendingEntries[fileName] = (Int(entry.uncompressedSize), 0.0)
}
var totalBytes: Int = self.mainEntrySize
for entry in self.otherEntries {
totalBytes += entry.0.uncompressedSize
totalBytes += Int(entry.0.uncompressedSize)
}
self.totalBytes = totalBytes
@ -512,7 +512,6 @@ public final class ChatImportActivityScreen: ViewController {
self.controllerNode.updateState(state: .progress(0.0), animated: true)
let context = self.context
let archive = self.archive
let mainEntry = self.mainEntry
let otherEntries = self.otherEntries
@ -550,6 +549,7 @@ public final class ChatImportActivityScreen: ViewController {
for (_, fileName, mediaType, fileData) in otherEntries {
let unpackedFile: Signal<TempBoxFile, ImportError> = fileData.get()
|> take(1)
|> deliverOnMainQueue
|> castError(ImportError.self)
|> mapToSignal { file -> Signal<TempBoxFile, ImportError> in
if let file = file {

View File

@ -213,7 +213,7 @@ swift_library(
"//submodules/AnimatedNavigationStripeNode:AnimatedNavigationStripeNode",
"//submodules/AudioBlob:AudioBlob",
"//Telegram:GeneratedSources",
"//third-party/ZIPFoundation:ZIPFoundation",
"//third-party/ZipArchive:ZipArchive",
"//submodules/ChatImportUI:ChatImportUI",
"//submodules/ChatHistoryImportTasks:ChatHistoryImportTasks",
"//submodules/DatePickerNode:DatePickerNode",

View File

@ -21,7 +21,7 @@ import MobileCoreServices
import OverlayStatusController
import PresentationDataUtils
import ChatImportUI
import ZIPFoundation
import ZipArchive
import ActivityIndicator
private let inForeground = ValuePromise<Bool>(false, ignoreRepeated: true)
@ -392,7 +392,7 @@ public class ShareRootControllerImpl {
if attachment.hasItemConformingToTypeIdentifier(kUTTypeFileURL as String) {
attachment.loadItem(forTypeIdentifier: kUTTypeFileURL as String, completionHandler: { result, error in
Queue.mainQueue().async {
guard let url = result as? URL else {
guard let url = result as? URL, url.isFileURL else {
beginShare()
return
}
@ -405,7 +405,10 @@ public class ShareRootControllerImpl {
beginShare()
return
}
guard let archive = Archive(url: url, accessMode: .read) else {
let archivePath = url.path
guard let entries = SSZipArchive.getEntriesForFile(atPath: archivePath) else {
beginShare()
return
}
@ -417,8 +420,8 @@ public class ShareRootControllerImpl {
]
var maybeMainFileName: String?
mainFileLoop: for entry in archive {
let entryFileName = entry.path(using: .utf8).replacingOccurrences(of: "/", with: "_").replacingOccurrences(of: "..", with: "_")
mainFileLoop: for entry in entries {
let entryFileName = entry.path.replacingOccurrences(of: "/", with: "_").replacingOccurrences(of: "..", with: "_")
let fullRange = NSRange(entryFileName.startIndex ..< entryFileName.endIndex, in: entryFileName)
for expression in mainFileNames {
if expression.firstMatch(in: entryFileName, options: [], range: fullRange) != nil {
@ -438,19 +441,20 @@ public class ShareRootControllerImpl {
let stickerRegex = try! NSRegularExpression(pattern: "[\\d]+-STICKER-.*?\\.webp")
let voiceRegex = try! NSRegularExpression(pattern: "[\\d]+-AUDIO-.*?\\.opus")
var otherEntries: [(Entry, String, ChatHistoryImport.MediaType)] = []
var otherEntries: [(SSZipEntry, String, ChatHistoryImport.MediaType)] = []
var mainFile: TempBoxFile?
do {
for entry in archive {
let entryPath = entry.path(using: .utf8).replacingOccurrences(of: "/", with: "_").replacingOccurrences(of: "..", with: "_")
for entry in entries {
let entryPath = entry.path.replacingOccurrences(of: "/", with: "_").replacingOccurrences(of: "..", with: "_")
if entryPath.isEmpty {
continue
}
let tempFile = TempBox.shared.tempFile(fileName: entryPath)
if entryPath == mainFileName {
let _ = try archive.extract(entry, to: URL(fileURLWithPath: tempFile.path))
mainFile = tempFile
if SSZipArchive.extractFileFromArchive(atPath: archivePath, filePath: entry.path, toPath: tempFile.path) {
mainFile = tempFile
}
} else {
let entryFileName = (entryPath as NSString).lastPathComponent
if !entryFileName.isEmpty {
@ -557,7 +561,7 @@ public class ShareRootControllerImpl {
navigationController.view.endEditing(true)
navigationController.pushViewController(ChatImportActivityScreen(context: context, cancel: {
self?.getExtensionContext()?.completeRequest(returningItems: nil, completionHandler: nil)
}, peerId: peerId, archive: archive, mainEntry: mainFile, otherEntries: otherEntries))
}, peerId: peerId, archivePath: archivePath, mainEntry: mainFile, otherEntries: otherEntries))
}
attemptSelectionImpl = { peer in
@ -671,7 +675,7 @@ public class ShareRootControllerImpl {
navigationController.view.endEditing(true)
navigationController.pushViewController(ChatImportActivityScreen(context: context, cancel: {
self?.getExtensionContext()?.completeRequest(returningItems: nil, completionHandler: nil)
}, peerId: peerId, archive: archive, mainEntry: mainFile, otherEntries: otherEntries))
}, peerId: peerId, archivePath: archivePath, mainEntry: mainFile, otherEntries: otherEntries))
}
attemptSelectionImpl = { [weak controller] peer in
@ -733,7 +737,7 @@ public class ShareRootControllerImpl {
navigationController.view.endEditing(true)
navigationController.pushViewController(ChatImportActivityScreen(context: context, cancel: {
self?.getExtensionContext()?.completeRequest(returningItems: nil, completionHandler: nil)
}, peerId: peerId, archive: archive, mainEntry: mainFile, otherEntries: otherEntries))
}, peerId: peerId, archivePath: archivePath, mainEntry: mainFile, otherEntries: otherEntries))
}
attemptSelectionImpl = { [weak controller] peer in

View File

@ -1,12 +0,0 @@
load("@build_bazel_rules_swift//swift:swift.bzl", "swift_library")
swift_library(
name = "ZIPFoundation",
module_name = "ZIPFoundation",
srcs = glob([
"Sources/**/*.swift",
]),
visibility = [
"//visibility:public",
],
)

View File

@ -1,178 +0,0 @@
//
// Archive+MemoryFile.swift
// ZIPFoundation
//
// Copyright © 2017-2020 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
//
import Foundation
#if swift(>=5.0)
extension Archive {
/// Returns a `Data` object containing a representation of the receiver.
public var data: Data? { return memoryFile?.data }
static func configureMemoryBacking(for data: Data, mode: AccessMode)
-> (UnsafeMutablePointer<FILE>, MemoryFile)? {
let posixMode: String
switch mode {
case .read: posixMode = "rb"
case .create: posixMode = "wb+"
case .update: posixMode = "rb+"
}
let memoryFile = MemoryFile(data: data)
guard let archiveFile = memoryFile.open(mode: posixMode) else { return nil }
if mode == .create {
let endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord(numberOfDisk: 0, numberOfDiskStart: 0,
totalNumberOfEntriesOnDisk: 0,
totalNumberOfEntriesInCentralDirectory: 0,
sizeOfCentralDirectory: 0,
offsetToStartOfCentralDirectory: 0,
zipFileCommentLength: 0,
zipFileCommentData: Data())
_ = endOfCentralDirectoryRecord.data.withUnsafeBytes { (buffer: UnsafeRawBufferPointer) in
fwrite(buffer.baseAddress, buffer.count, 1, archiveFile) // Errors handled during read
}
}
return (archiveFile, memoryFile)
}
}
class MemoryFile {
private(set) var data: Data
private var offset = 0
init(data: Data = Data()) {
self.data = data
}
func open(mode: String) -> UnsafeMutablePointer<FILE>? {
let cookie = Unmanaged.passRetained(self)
let writable = mode.count > 0 && (mode.first! != "r" || mode.last! == "+")
let append = mode.count > 0 && mode.first! == "a"
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
let result = writable
? funopen(cookie.toOpaque(), readStub, writeStub, seekStub, closeStub)
: funopen(cookie.toOpaque(), readStub, nil, seekStub, closeStub)
#else
let stubs = cookie_io_functions_t(read: readStub, write: writeStub, seek: seekStub, close: closeStub)
let result = fopencookie(cookie.toOpaque(), mode, stubs)
#endif
if append {
fseek(result, 0, SEEK_END)
}
return result
}
}
private extension MemoryFile {
func readData(buffer: UnsafeMutableRawBufferPointer) -> Int {
let size = min(buffer.count, data.count-offset)
let start = data.startIndex
data.copyBytes(to: buffer.bindMemory(to: UInt8.self), from: start+offset..<start+offset+size)
offset += size
return size
}
func writeData(buffer: UnsafeRawBufferPointer) -> Int {
let start = data.startIndex
if offset < data.count && offset+buffer.count > data.count {
data.removeSubrange(start+offset..<start+data.count)
} else if offset > data.count {
data.append(Data(count: offset-data.count))
}
if offset == data.count {
data.append(buffer.bindMemory(to: UInt8.self))
} else {
let start = data.startIndex // May have changed in earlier mutation
data.replaceSubrange(start+offset..<start+offset+buffer.count, with: buffer.bindMemory(to: UInt8.self))
}
offset += buffer.count
return buffer.count
}
func seek(offset: Int, whence: Int32) -> Int {
var result = -1
if whence == SEEK_SET {
result = offset
} else if whence == SEEK_CUR {
result = self.offset + offset
} else if whence == SEEK_END {
result = data.count + offset
}
self.offset = result
return self.offset
}
}
private func fileFromCookie(cookie: UnsafeRawPointer) -> MemoryFile {
return Unmanaged<MemoryFile>.fromOpaque(cookie).takeUnretainedValue()
}
private func closeStub(_ cookie: UnsafeMutableRawPointer?) -> Int32 {
if let cookie = cookie {
Unmanaged<MemoryFile>.fromOpaque(cookie).release()
}
return 0
}
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
private func readStub(_ cookie: UnsafeMutableRawPointer?,
_ bytePtr: UnsafeMutablePointer<Int8>?,
_ count: Int32) -> Int32 {
guard let cookie = cookie, let bytePtr = bytePtr else { return 0 }
return Int32(fileFromCookie(cookie: cookie).readData(
buffer: UnsafeMutableRawBufferPointer(start: bytePtr, count: Int(count))))
}
private func writeStub(_ cookie: UnsafeMutableRawPointer?,
_ bytePtr: UnsafePointer<Int8>?,
_ count: Int32) -> Int32 {
guard let cookie = cookie, let bytePtr = bytePtr else { return 0 }
return Int32(fileFromCookie(cookie: cookie).writeData(
buffer: UnsafeRawBufferPointer(start: bytePtr, count: Int(count))))
}
private func seekStub(_ cookie: UnsafeMutableRawPointer?,
_ offset: fpos_t,
_ whence: Int32) -> fpos_t {
guard let cookie = cookie else { return 0 }
return fpos_t(fileFromCookie(cookie: cookie).seek(offset: Int(offset), whence: whence))
}
#else
private func readStub(_ cookie: UnsafeMutableRawPointer?,
_ bytePtr: UnsafeMutablePointer<Int8>?,
_ count: Int) -> Int {
guard let cookie = cookie, let bytePtr = bytePtr else { return 0 }
return fileFromCookie(cookie: cookie).readData(
buffer: UnsafeMutableRawBufferPointer(start: bytePtr, count: count))
}
private func writeStub(_ cookie: UnsafeMutableRawPointer?,
_ bytePtr: UnsafePointer<Int8>?,
_ count: Int) -> Int {
guard let cookie = cookie, let bytePtr = bytePtr else { return 0 }
return fileFromCookie(cookie: cookie).writeData(
buffer: UnsafeRawBufferPointer(start: bytePtr, count: count))
}
private func seekStub(_ cookie: UnsafeMutableRawPointer?,
_ offset: UnsafeMutablePointer<Int>?,
_ whence: Int32) -> Int32 {
guard let cookie = cookie, let offset = offset else { return 0 }
let result = fileFromCookie(cookie: cookie).seek(offset: Int(offset.pointee), whence: whence)
if result >= 0 {
offset.pointee = result
return 0
} else {
return -1
}
}
#endif
#endif

View File

@ -1,133 +0,0 @@
//
// Archive+Reading.swift
// ZIPFoundation
//
// Copyright © 2017-2020 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
//
import Foundation
extension Archive {
/// Read a ZIP `Entry` from the receiver and write it to `url`.
///
/// - Parameters:
/// - entry: The ZIP `Entry` to read.
/// - url: The destination file URL.
/// - bufferSize: The maximum size of the read buffer and the decompression buffer (if needed).
/// - skipCRC32: Optional flag to skip calculation of the CRC32 checksum to improve performance.
/// - progress: A progress object that can be used to track or cancel the extract operation.
/// - Returns: The checksum of the processed content or 0 if the `skipCRC32` flag was set to `true`.
/// - Throws: An error if the destination file cannot be written or the entry contains malformed content.
public func extract(_ entry: Entry, to url: URL, bufferSize: UInt32 = defaultReadChunkSize, skipCRC32: Bool = false,
progress: Progress? = nil) throws -> CRC32 {
let fileManager = FileManager()
var checksum = CRC32(0)
switch entry.type {
case .file:
guard !fileManager.itemExists(at: url) else {
throw CocoaError(.fileWriteFileExists, userInfo: [NSFilePathErrorKey: url.path])
}
try fileManager.createParentDirectoryStructure(for: url)
let destinationRepresentation = fileManager.fileSystemRepresentation(withPath: url.path)
guard let destinationFile: UnsafeMutablePointer<FILE> = fopen(destinationRepresentation, "wb+") else {
throw CocoaError(.fileNoSuchFile)
}
defer { fclose(destinationFile) }
let consumer = { _ = try Data.write(chunk: $0, to: destinationFile) }
checksum = try self.extract(entry, bufferSize: bufferSize, skipCRC32: skipCRC32,
progress: progress, consumer: consumer)
case .directory:
let consumer = { (_: Data) in
try fileManager.createDirectory(at: url, withIntermediateDirectories: true, attributes: nil)
}
checksum = try self.extract(entry, bufferSize: bufferSize, skipCRC32: skipCRC32,
progress: progress, consumer: consumer)
case .symlink:
guard !fileManager.itemExists(at: url) else {
throw CocoaError(.fileWriteFileExists, userInfo: [NSFilePathErrorKey: url.path])
}
let consumer = { (data: Data) in
guard let linkPath = String(data: data, encoding: .utf8) else { throw ArchiveError.invalidEntryPath }
try fileManager.createParentDirectoryStructure(for: url)
try fileManager.createSymbolicLink(atPath: url.path, withDestinationPath: linkPath)
}
checksum = try self.extract(entry, bufferSize: bufferSize, skipCRC32: skipCRC32,
progress: progress, consumer: consumer)
}
let attributes = FileManager.attributes(from: entry)
try fileManager.setAttributes(attributes, ofItemAtPath: url.path)
return checksum
}
/// Read a ZIP `Entry` from the receiver and forward its contents to a `Consumer` closure.
///
/// - Parameters:
/// - entry: The ZIP `Entry` to read.
/// - bufferSize: The maximum size of the read buffer and the decompression buffer (if needed).
/// - skipCRC32: Optional flag to skip calculation of the CRC32 checksum to improve performance.
/// - progress: A progress object that can be used to track or cancel the extract operation.
/// - consumer: A closure that consumes contents of `Entry` as `Data` chunks.
/// - Returns: The checksum of the processed content or 0 if the `skipCRC32` flag was set to `true`..
/// - Throws: An error if the destination file cannot be written or the entry contains malformed content.
public func extract(_ entry: Entry, bufferSize: UInt32 = defaultReadChunkSize, skipCRC32: Bool = false,
progress: Progress? = nil, consumer: Consumer) throws -> CRC32 {
var checksum = CRC32(0)
let localFileHeader = entry.localFileHeader
fseek(self.archiveFile, entry.dataOffset, SEEK_SET)
progress?.totalUnitCount = self.totalUnitCountForReading(entry)
switch entry.type {
case .file:
guard let compressionMethod = CompressionMethod(rawValue: localFileHeader.compressionMethod) else {
throw ArchiveError.invalidCompressionMethod
}
switch compressionMethod {
case .none: checksum = try self.readUncompressed(entry: entry, bufferSize: bufferSize,
skipCRC32: skipCRC32, progress: progress, with: consumer)
case .deflate: checksum = try self.readCompressed(entry: entry, bufferSize: bufferSize,
skipCRC32: skipCRC32, progress: progress, with: consumer)
}
case .directory:
try consumer(Data())
progress?.completedUnitCount = self.totalUnitCountForReading(entry)
case .symlink:
let localFileHeader = entry.localFileHeader
let size = Int(localFileHeader.compressedSize)
let data = try Data.readChunk(of: size, from: self.archiveFile)
checksum = data.crc32(checksum: 0)
try consumer(data)
progress?.completedUnitCount = self.totalUnitCountForReading(entry)
}
return checksum
}
// MARK: - Helpers
private func readUncompressed(entry: Entry, bufferSize: UInt32, skipCRC32: Bool,
progress: Progress? = nil, with consumer: Consumer) throws -> CRC32 {
let size = Int(entry.centralDirectoryStructure.uncompressedSize)
return try Data.consumePart(of: size, chunkSize: Int(bufferSize), skipCRC32: skipCRC32,
provider: { (_, chunkSize) -> Data in
return try Data.readChunk(of: Int(chunkSize), from: self.archiveFile)
}, consumer: { (data) in
if progress?.isCancelled == true { throw ArchiveError.cancelledOperation }
try consumer(data)
progress?.completedUnitCount += Int64(data.count)
})
}
private func readCompressed(entry: Entry, bufferSize: UInt32, skipCRC32: Bool,
progress: Progress? = nil, with consumer: Consumer) throws -> CRC32 {
let size = Int(entry.centralDirectoryStructure.compressedSize)
return try Data.decompress(size: size, bufferSize: Int(bufferSize), skipCRC32: skipCRC32,
provider: { (_, chunkSize) -> Data in
return try Data.readChunk(of: chunkSize, from: self.archiveFile)
}, consumer: { (data) in
if progress?.isCancelled == true { throw ArchiveError.cancelledOperation }
try consumer(data)
progress?.completedUnitCount += Int64(data.count)
})
}
}

View File

@ -1,354 +0,0 @@
//
// Archive+Writing.swift
// ZIPFoundation
//
// Copyright © 2017-2020 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
//
import Foundation
extension Archive {
private enum ModifyOperation: Int {
case remove = -1
case add = 1
}
/// Write files, directories or symlinks to the receiver.
///
/// - Parameters:
/// - path: The path that is used to identify an `Entry` within the `Archive` file.
/// - baseURL: The base URL of the `Entry` to add.
/// The `baseURL` combined with `path` must form a fully qualified file URL.
/// - compressionMethod: Indicates the `CompressionMethod` that should be applied to `Entry`.
/// By default, no compression will be applied.
/// - bufferSize: The maximum size of the write buffer and the compression buffer (if needed).
/// - progress: A progress object that can be used to track or cancel the add operation.
/// - Throws: An error if the source file cannot be read or the receiver is not writable.
public func addEntry(with path: String, relativeTo baseURL: URL, compressionMethod: CompressionMethod = .none,
bufferSize: UInt32 = defaultWriteChunkSize, progress: Progress? = nil) throws {
let fileManager = FileManager()
let entryURL = baseURL.appendingPathComponent(path)
guard fileManager.itemExists(at: entryURL) else {
throw CocoaError(.fileReadNoSuchFile, userInfo: [NSFilePathErrorKey: entryURL.path])
}
let type = try FileManager.typeForItem(at: entryURL)
// symlinks do not need to be readable
guard type == .symlink || fileManager.isReadableFile(atPath: entryURL.path) else {
throw CocoaError(.fileReadNoPermission, userInfo: [NSFilePathErrorKey: url.path])
}
let modDate = try FileManager.fileModificationDateTimeForItem(at: entryURL)
let uncompressedSize = type == .directory ? 0 : try FileManager.fileSizeForItem(at: entryURL)
let permissions = try FileManager.permissionsForItem(at: entryURL)
var provider: Provider
switch type {
case .file:
let entryFileSystemRepresentation = fileManager.fileSystemRepresentation(withPath: entryURL.path)
guard let entryFile: UnsafeMutablePointer<FILE> = fopen(entryFileSystemRepresentation, "rb") else {
throw CocoaError(.fileNoSuchFile)
}
defer { fclose(entryFile) }
provider = { _, _ in return try Data.readChunk(of: Int(bufferSize), from: entryFile) }
try self.addEntry(with: path, type: type, uncompressedSize: uncompressedSize,
modificationDate: modDate, permissions: permissions,
compressionMethod: compressionMethod, bufferSize: bufferSize,
progress: progress, provider: provider)
case .directory:
provider = { _, _ in return Data() }
try self.addEntry(with: path.hasSuffix("/") ? path : path + "/",
type: type, uncompressedSize: uncompressedSize,
modificationDate: modDate, permissions: permissions,
compressionMethod: compressionMethod, bufferSize: bufferSize,
progress: progress, provider: provider)
case .symlink:
provider = { _, _ -> Data in
let linkDestination = try fileManager.destinationOfSymbolicLink(atPath: entryURL.path)
let linkFileSystemRepresentation = fileManager.fileSystemRepresentation(withPath: linkDestination)
let linkLength = Int(strlen(linkFileSystemRepresentation))
let linkBuffer = UnsafeBufferPointer(start: linkFileSystemRepresentation, count: linkLength)
return Data(buffer: linkBuffer)
}
try self.addEntry(with: path, type: type, uncompressedSize: uncompressedSize,
modificationDate: modDate, permissions: permissions,
compressionMethod: compressionMethod, bufferSize: bufferSize,
progress: progress, provider: provider)
}
}
/// Write files, directories or symlinks to the receiver.
///
/// - Parameters:
/// - path: The path that is used to identify an `Entry` within the `Archive` file.
/// - type: Indicates the `Entry.EntryType` of the added content.
/// - uncompressedSize: The uncompressed size of the data that is going to be added with `provider`.
/// - modificationDate: A `Date` describing the file modification date of the `Entry`.
/// Default is the current `Date`.
/// - permissions: POSIX file permissions for the `Entry`.
/// Default is `0`o`644` for files and symlinks and `0`o`755` for directories.
/// - compressionMethod: Indicates the `CompressionMethod` that should be applied to `Entry`.
/// By default, no compression will be applied.
/// - bufferSize: The maximum size of the write buffer and the compression buffer (if needed).
/// - progress: A progress object that can be used to track or cancel the add operation.
/// - provider: A closure that accepts a position and a chunk size. Returns a `Data` chunk.
/// - Throws: An error if the source data is invalid or the receiver is not writable.
public func addEntry(with path: String, type: Entry.EntryType, uncompressedSize: UInt32,
modificationDate: Date = Date(), permissions: UInt16? = nil,
compressionMethod: CompressionMethod = .none, bufferSize: UInt32 = defaultWriteChunkSize,
progress: Progress? = nil, provider: Provider) throws {
guard self.accessMode != .read else { throw ArchiveError.unwritableArchive }
// Directories and symlinks cannot be compressed
let compressionMethod = type == .file ? compressionMethod : .none
progress?.totalUnitCount = type == .directory ? defaultDirectoryUnitCount : Int64(uncompressedSize)
var endOfCentralDirRecord = self.endOfCentralDirectoryRecord
var startOfCD = Int(endOfCentralDirRecord.offsetToStartOfCentralDirectory)
fseek(self.archiveFile, startOfCD, SEEK_SET)
let existingCentralDirData = try Data.readChunk(of: Int(endOfCentralDirRecord.sizeOfCentralDirectory),
from: self.archiveFile)
fseek(self.archiveFile, startOfCD, SEEK_SET)
let localFileHeaderStart = ftell(self.archiveFile)
let modDateTime = modificationDate.fileModificationDateTime
defer { fflush(self.archiveFile) }
do {
var localFileHeader = try self.writeLocalFileHeader(path: path, compressionMethod: compressionMethod,
size: (uncompressedSize, 0), checksum: 0,
modificationDateTime: modDateTime)
let (written, checksum) = try self.writeEntry(localFileHeader: localFileHeader, type: type,
compressionMethod: compressionMethod, bufferSize: bufferSize,
progress: progress, provider: provider)
startOfCD = ftell(self.archiveFile)
fseek(self.archiveFile, localFileHeaderStart, SEEK_SET)
// Write the local file header a second time. Now with compressedSize (if applicable) and a valid checksum.
localFileHeader = try self.writeLocalFileHeader(path: path, compressionMethod: compressionMethod,
size: (uncompressedSize, written),
checksum: checksum, modificationDateTime: modDateTime)
fseek(self.archiveFile, startOfCD, SEEK_SET)
_ = try Data.write(chunk: existingCentralDirData, to: self.archiveFile)
let permissions = permissions ?? (type == .directory ? defaultDirectoryPermissions :defaultFilePermissions)
let externalAttributes = FileManager.externalFileAttributesForEntry(of: type, permissions: permissions)
let offset = UInt32(localFileHeaderStart)
let centralDir = try self.writeCentralDirectoryStructure(localFileHeader: localFileHeader,
relativeOffset: offset,
externalFileAttributes: externalAttributes)
if startOfCD > UINT32_MAX { throw ArchiveError.invalidStartOfCentralDirectoryOffset }
endOfCentralDirRecord = try self.writeEndOfCentralDirectory(centralDirectoryStructure: centralDir,
startOfCentralDirectory: UInt32(startOfCD),
operation: .add)
self.endOfCentralDirectoryRecord = endOfCentralDirRecord
} catch ArchiveError.cancelledOperation {
try rollback(localFileHeaderStart, existingCentralDirData, endOfCentralDirRecord)
throw ArchiveError.cancelledOperation
}
}
/// Remove a ZIP `Entry` from the receiver.
///
/// - Parameters:
/// - entry: The `Entry` to remove.
/// - bufferSize: The maximum size for the read and write buffers used during removal.
/// - progress: A progress object that can be used to track or cancel the remove operation.
/// - Throws: An error if the `Entry` is malformed or the receiver is not writable.
public func remove(_ entry: Entry, bufferSize: UInt32 = defaultReadChunkSize, progress: Progress? = nil) throws {
let manager = FileManager()
let tempDir = self.uniqueTemporaryDirectoryURL()
defer { try? manager.removeItem(at: tempDir) }
let uniqueString = ProcessInfo.processInfo.globallyUniqueString
let tempArchiveURL = tempDir.appendingPathComponent(uniqueString)
do { try manager.createParentDirectoryStructure(for: tempArchiveURL) } catch {
throw ArchiveError.unwritableArchive }
guard let tempArchive = Archive(url: tempArchiveURL, accessMode: .create) else {
throw ArchiveError.unwritableArchive
}
progress?.totalUnitCount = self.totalUnitCountForRemoving(entry)
var centralDirectoryData = Data()
var offset = 0
for currentEntry in self {
let centralDirectoryStructure = currentEntry.centralDirectoryStructure
if currentEntry != entry {
let entryStart = Int(currentEntry.centralDirectoryStructure.relativeOffsetOfLocalHeader)
fseek(self.archiveFile, entryStart, SEEK_SET)
let provider: Provider = { (_, chunkSize) -> Data in
return try Data.readChunk(of: Int(chunkSize), from: self.archiveFile)
}
let consumer: Consumer = {
if progress?.isCancelled == true { throw ArchiveError.cancelledOperation }
_ = try Data.write(chunk: $0, to: tempArchive.archiveFile)
progress?.completedUnitCount += Int64($0.count)
}
_ = try Data.consumePart(of: Int(currentEntry.localSize), chunkSize: Int(bufferSize),
provider: provider, consumer: consumer)
let centralDir = CentralDirectoryStructure(centralDirectoryStructure: centralDirectoryStructure,
offset: UInt32(offset))
centralDirectoryData.append(centralDir.data)
} else { offset = currentEntry.localSize }
}
let startOfCentralDirectory = ftell(tempArchive.archiveFile)
_ = try Data.write(chunk: centralDirectoryData, to: tempArchive.archiveFile)
tempArchive.endOfCentralDirectoryRecord = self.endOfCentralDirectoryRecord
let endOfCentralDirectoryRecord = try
tempArchive.writeEndOfCentralDirectory(centralDirectoryStructure: entry.centralDirectoryStructure,
startOfCentralDirectory: UInt32(startOfCentralDirectory),
operation: .remove)
tempArchive.endOfCentralDirectoryRecord = endOfCentralDirectoryRecord
self.endOfCentralDirectoryRecord = endOfCentralDirectoryRecord
fflush(tempArchive.archiveFile)
try self.replaceCurrentArchiveWithArchive(at: tempArchive.url)
}
// MARK: - Helpers
func uniqueTemporaryDirectoryURL() -> URL {
#if swift(>=5.0) || os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
if let tempDir = try? FileManager().url(for: .itemReplacementDirectory, in: .userDomainMask,
appropriateFor: self.url, create: true) {
return tempDir
}
#endif
return URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(
ProcessInfo.processInfo.globallyUniqueString)
}
func replaceCurrentArchiveWithArchive(at URL: URL) throws {
fclose(self.archiveFile)
let fileManager = FileManager()
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
do {
_ = try fileManager.replaceItemAt(self.url, withItemAt: URL)
} catch {
_ = try fileManager.removeItem(at: self.url)
_ = try fileManager.moveItem(at: URL, to: self.url)
}
#else
_ = try fileManager.removeItem(at: self.url)
_ = try fileManager.moveItem(at: URL, to: self.url)
#endif
let fileSystemRepresentation = fileManager.fileSystemRepresentation(withPath: self.url.path)
self.archiveFile = fopen(fileSystemRepresentation, "rb+")
}
private func writeLocalFileHeader(path: String, compressionMethod: CompressionMethod,
size: (uncompressed: UInt32, compressed: UInt32),
checksum: CRC32,
modificationDateTime: (UInt16, UInt16)) throws -> LocalFileHeader {
// We always set Bit 11 in generalPurposeBitFlag, which indicates an UTF-8 encoded path.
guard let fileNameData = path.data(using: .utf8) else { throw ArchiveError.invalidEntryPath }
let localFileHeader = LocalFileHeader(versionNeededToExtract: UInt16(20), generalPurposeBitFlag: UInt16(2048),
compressionMethod: compressionMethod.rawValue,
lastModFileTime: modificationDateTime.1,
lastModFileDate: modificationDateTime.0, crc32: checksum,
compressedSize: size.compressed, uncompressedSize: size.uncompressed,
fileNameLength: UInt16(fileNameData.count), extraFieldLength: UInt16(0),
fileNameData: fileNameData, extraFieldData: Data())
_ = try Data.write(chunk: localFileHeader.data, to: self.archiveFile)
return localFileHeader
}
private func writeEntry(localFileHeader: LocalFileHeader, type: Entry.EntryType,
compressionMethod: CompressionMethod, bufferSize: UInt32, progress: Progress? = nil,
provider: Provider) throws -> (sizeWritten: UInt32, crc32: CRC32) {
var checksum = CRC32(0)
var sizeWritten = UInt32(0)
switch type {
case .file:
switch compressionMethod {
case .none:
(sizeWritten, checksum) = try self.writeUncompressed(size: localFileHeader.uncompressedSize,
bufferSize: bufferSize,
progress: progress, provider: provider)
case .deflate:
(sizeWritten, checksum) = try self.writeCompressed(size: localFileHeader.uncompressedSize,
bufferSize: bufferSize,
progress: progress, provider: provider)
}
case .directory:
_ = try provider(0, 0)
if let progress = progress { progress.completedUnitCount = progress.totalUnitCount }
case .symlink:
(sizeWritten, checksum) = try self.writeSymbolicLink(size: localFileHeader.uncompressedSize,
provider: provider)
if let progress = progress { progress.completedUnitCount = progress.totalUnitCount }
}
return (sizeWritten, checksum)
}
private func writeUncompressed(size: UInt32, bufferSize: UInt32, progress: Progress? = nil,
provider: Provider) throws -> (sizeWritten: UInt32, checksum: CRC32) {
var position = 0
var sizeWritten = 0
var checksum = CRC32(0)
while position < size {
if progress?.isCancelled == true { throw ArchiveError.cancelledOperation }
let readSize = (Int(size) - position) >= bufferSize ? Int(bufferSize) : (Int(size) - position)
let entryChunk = try provider(Int(position), Int(readSize))
checksum = entryChunk.crc32(checksum: checksum)
sizeWritten += try Data.write(chunk: entryChunk, to: self.archiveFile)
position += Int(bufferSize)
progress?.completedUnitCount = Int64(sizeWritten)
}
return (UInt32(sizeWritten), checksum)
}
private func writeCompressed(size: UInt32, bufferSize: UInt32, progress: Progress? = nil,
provider: Provider) throws -> (sizeWritten: UInt32, checksum: CRC32) {
var sizeWritten = 0
let consumer: Consumer = { data in sizeWritten += try Data.write(chunk: data, to: self.archiveFile) }
let checksum = try Data.compress(size: Int(size), bufferSize: Int(bufferSize),
provider: { (position, size) -> Data in
if progress?.isCancelled == true { throw ArchiveError.cancelledOperation }
let data = try provider(position, size)
progress?.completedUnitCount += Int64(data.count)
return data
}, consumer: consumer)
return(UInt32(sizeWritten), checksum)
}
private func writeSymbolicLink(size: UInt32, provider: Provider) throws -> (sizeWritten: UInt32, checksum: CRC32) {
let linkData = try provider(0, Int(size))
let checksum = linkData.crc32(checksum: 0)
let sizeWritten = try Data.write(chunk: linkData, to: self.archiveFile)
return (UInt32(sizeWritten), checksum)
}
private func writeCentralDirectoryStructure(localFileHeader: LocalFileHeader, relativeOffset: UInt32,
externalFileAttributes: UInt32) throws -> CentralDirectoryStructure {
let centralDirectory = CentralDirectoryStructure(localFileHeader: localFileHeader,
fileAttributes: externalFileAttributes,
relativeOffset: relativeOffset)
_ = try Data.write(chunk: centralDirectory.data, to: self.archiveFile)
return centralDirectory
}
private func writeEndOfCentralDirectory(centralDirectoryStructure: CentralDirectoryStructure,
startOfCentralDirectory: UInt32,
operation: ModifyOperation) throws -> EndOfCentralDirectoryRecord {
var record = self.endOfCentralDirectoryRecord
let countChange = operation.rawValue
var dataLength = Int(centralDirectoryStructure.extraFieldLength)
dataLength += Int(centralDirectoryStructure.fileNameLength)
dataLength += Int(centralDirectoryStructure.fileCommentLength)
let centralDirectoryDataLengthChange = operation.rawValue * (dataLength + CentralDirectoryStructure.size)
var updatedSizeOfCentralDirectory = Int(record.sizeOfCentralDirectory)
updatedSizeOfCentralDirectory += centralDirectoryDataLengthChange
let numberOfEntriesOnDisk = UInt16(Int(record.totalNumberOfEntriesOnDisk) + countChange)
let numberOfEntriesInCentralDirectory = UInt16(Int(record.totalNumberOfEntriesInCentralDirectory) + countChange)
record = EndOfCentralDirectoryRecord(record: record, numberOfEntriesOnDisk: numberOfEntriesOnDisk,
numberOfEntriesInCentralDirectory: numberOfEntriesInCentralDirectory,
updatedSizeOfCentralDirectory: UInt32(updatedSizeOfCentralDirectory),
startOfCentralDirectory: startOfCentralDirectory)
_ = try Data.write(chunk: record.data, to: self.archiveFile)
return record
}
private func rollback(_ localFileHeaderStart: Int,
_ existingCentralDirectoryData: Data,
_ endOfCentralDirRecord: EndOfCentralDirectoryRecord) throws {
fflush(self.archiveFile)
ftruncate(fileno(self.archiveFile), off_t(localFileHeaderStart))
fseek(self.archiveFile, localFileHeaderStart, SEEK_SET)
_ = try Data.write(chunk: existingCentralDirectoryData, to: self.archiveFile)
_ = try Data.write(chunk: endOfCentralDirRecord.data, to: self.archiveFile)
}
}

View File

@ -1,398 +0,0 @@
//
// Archive.swift
// ZIPFoundation
//
// Copyright © 2017-2020 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
//
import Foundation
/// The default chunk size when reading entry data from an archive.
public let defaultReadChunkSize = UInt32(16*1024)
/// The default chunk size when writing entry data to an archive.
public let defaultWriteChunkSize = defaultReadChunkSize
/// The default permissions for newly added entries.
public let defaultFilePermissions = UInt16(0o644)
public let defaultDirectoryPermissions = UInt16(0o755)
let defaultPOSIXBufferSize = defaultReadChunkSize
let defaultDirectoryUnitCount = Int64(1)
let minDirectoryEndOffset = 22
let maxDirectoryEndOffset = 66000
let endOfCentralDirectoryStructSignature = 0x06054b50
let localFileHeaderStructSignature = 0x04034b50
let dataDescriptorStructSignature = 0x08074b50
let centralDirectoryStructSignature = 0x02014b50
/// The compression method of an `Entry` in a ZIP `Archive`.
public enum CompressionMethod: UInt16 {
/// Indicates that an `Entry` has no compression applied to its contents.
case none = 0
/// Indicates that contents of an `Entry` have been compressed with a zlib compatible Deflate algorithm.
case deflate = 8
}
/// A sequence of uncompressed or compressed ZIP entries.
///
/// You use an `Archive` to create, read or update ZIP files.
/// To read an existing ZIP file, you have to pass in an existing file `URL` and `AccessMode.read`:
///
/// var archiveURL = URL(fileURLWithPath: "/path/file.zip")
/// var archive = Archive(url: archiveURL, accessMode: .read)
///
/// An `Archive` is a sequence of entries. You can
/// iterate over an archive using a `for`-`in` loop to get access to individual `Entry` objects:
///
/// for entry in archive {
/// print(entry.path)
/// }
///
/// Each `Entry` in an `Archive` is represented by its `path`. You can
/// use `path` to retrieve the corresponding `Entry` from an `Archive` via subscripting:
///
/// let entry = archive['/path/file.txt']
///
/// To create a new `Archive`, pass in a non-existing file URL and `AccessMode.create`. To modify an
/// existing `Archive` use `AccessMode.update`:
///
/// var archiveURL = URL(fileURLWithPath: "/path/file.zip")
/// var archive = Archive(url: archiveURL, accessMode: .update)
/// try archive?.addEntry("test.txt", relativeTo: baseURL, compressionMethod: .deflate)
public final class Archive: Sequence {
typealias LocalFileHeader = Entry.LocalFileHeader
typealias DataDescriptor = Entry.DataDescriptor
typealias CentralDirectoryStructure = Entry.CentralDirectoryStructure
/// An error that occurs during reading, creating or updating a ZIP file.
public enum ArchiveError: Error {
/// Thrown when an archive file is either damaged or inaccessible.
case unreadableArchive
/// Thrown when an archive is either opened with AccessMode.read or the destination file is unwritable.
case unwritableArchive
/// Thrown when the path of an `Entry` cannot be stored in an archive.
case invalidEntryPath
/// Thrown when an `Entry` can't be stored in the archive with the proposed compression method.
case invalidCompressionMethod
/// Thrown when the start of the central directory exceeds `UINT32_MAX`
case invalidStartOfCentralDirectoryOffset
/// Thrown when an archive does not contain the required End of Central Directory Record.
case missingEndOfCentralDirectoryRecord
/// Thrown when an extract, add or remove operation was canceled.
case cancelledOperation
}
/// The access mode for an `Archive`.
public enum AccessMode: UInt {
/// Indicates that a newly instantiated `Archive` should create its backing file.
case create
/// Indicates that a newly instantiated `Archive` should read from an existing backing file.
case read
/// Indicates that a newly instantiated `Archive` should update an existing backing file.
case update
}
struct EndOfCentralDirectoryRecord: DataSerializable {
let endOfCentralDirectorySignature = UInt32(endOfCentralDirectoryStructSignature)
let numberOfDisk: UInt16
let numberOfDiskStart: UInt16
let totalNumberOfEntriesOnDisk: UInt16
let totalNumberOfEntriesInCentralDirectory: UInt16
let sizeOfCentralDirectory: UInt32
let offsetToStartOfCentralDirectory: UInt32
let zipFileCommentLength: UInt16
let zipFileCommentData: Data
static let size = 22
}
private var preferredEncoding: String.Encoding?
/// URL of an Archive's backing file.
public let url: URL
/// Access mode for an archive file.
public let accessMode: AccessMode
var archiveFile: UnsafeMutablePointer<FILE>
var endOfCentralDirectoryRecord: EndOfCentralDirectoryRecord
/// Initializes a new ZIP `Archive`.
///
/// You can use this initalizer to create new archive files or to read and update existing ones.
/// The `mode` parameter indicates the intended usage of the archive: `.read`, `.create` or `.update`.
/// - Parameters:
/// - url: File URL to the receivers backing file.
/// - mode: Access mode of the receiver.
/// - preferredEncoding: Encoding for entry paths. Overrides the encoding specified in the archive.
/// This encoding is only used when _decoding_ paths from the receiver.
/// Paths of entries added with `addEntry` are always UTF-8 encoded.
/// - Returns: An archive initialized with a backing file at the passed in file URL and the given access mode
/// or `nil` if the following criteria are not met:
/// - Note:
/// - The file URL _must_ point to an existing file for `AccessMode.read`.
/// - The file URL _must_ point to a non-existing file for `AccessMode.create`.
/// - The file URL _must_ point to an existing file for `AccessMode.update`.
public init?(url: URL, accessMode mode: AccessMode, preferredEncoding: String.Encoding? = nil) {
self.url = url
self.accessMode = mode
self.preferredEncoding = preferredEncoding
guard let (archiveFile, endOfCentralDirectoryRecord) = Archive.configureFileBacking(for: url, mode: mode) else {
return nil
}
self.archiveFile = archiveFile
self.endOfCentralDirectoryRecord = endOfCentralDirectoryRecord
setvbuf(self.archiveFile, nil, _IOFBF, Int(defaultPOSIXBufferSize))
}
#if swift(>=5.0)
var memoryFile: MemoryFile?
/// Initializes a new in-memory ZIP `Archive`.
///
/// You can use this initalizer to create new in-memory archive files or to read and update existing ones.
///
/// - Parameters:
/// - data: `Data` object used as backing for in-memory archives.
/// - mode: Access mode of the receiver.
/// - preferredEncoding: Encoding for entry paths. Overrides the encoding specified in the archive.
/// This encoding is only used when _decoding_ paths from the receiver.
/// Paths of entries added with `addEntry` are always UTF-8 encoded.
/// - Returns: An in-memory archive initialized with passed in backing data.
/// - Note:
/// - The backing `data` _must_ contain a valid ZIP archive for `AccessMode.read` and `AccessMode.update`.
/// - The backing `data` _must_ be empty (or omitted) for `AccessMode.create`.
public init?(data: Data = Data(), accessMode mode: AccessMode, preferredEncoding: String.Encoding? = nil) {
guard let url = URL(string: "memory:"),
let (archiveFile, memoryFile) = Archive.configureMemoryBacking(for: data, mode: mode) else {
return nil
}
self.url = url
self.accessMode = mode
self.preferredEncoding = preferredEncoding
self.archiveFile = archiveFile
self.memoryFile = memoryFile
guard let endOfCentralDirectoryRecord = Archive.scanForEndOfCentralDirectoryRecord(in: archiveFile)
else {
fclose(self.archiveFile)
return nil
}
self.endOfCentralDirectoryRecord = endOfCentralDirectoryRecord
}
#endif
deinit {
fclose(self.archiveFile)
}
public func makeIterator() -> AnyIterator<Entry> {
let endOfCentralDirectoryRecord = self.endOfCentralDirectoryRecord
var directoryIndex = Int(endOfCentralDirectoryRecord.offsetToStartOfCentralDirectory)
var index = 0
return AnyIterator {
guard index < Int(endOfCentralDirectoryRecord.totalNumberOfEntriesInCentralDirectory) else { return nil }
guard let centralDirStruct: CentralDirectoryStructure = Data.readStruct(from: self.archiveFile,
at: directoryIndex) else {
return nil
}
let offset = Int(centralDirStruct.relativeOffsetOfLocalHeader)
guard let localFileHeader: LocalFileHeader = Data.readStruct(from: self.archiveFile,
at: offset) else { return nil }
var dataDescriptor: DataDescriptor?
if centralDirStruct.usesDataDescriptor {
let additionalSize = Int(localFileHeader.fileNameLength) + Int(localFileHeader.extraFieldLength)
let isCompressed = centralDirStruct.compressionMethod != CompressionMethod.none.rawValue
let dataSize = isCompressed ? centralDirStruct.compressedSize : centralDirStruct.uncompressedSize
let descriptorPosition = offset + LocalFileHeader.size + additionalSize + Int(dataSize)
dataDescriptor = Data.readStruct(from: self.archiveFile, at: descriptorPosition)
}
defer {
directoryIndex += CentralDirectoryStructure.size
directoryIndex += Int(centralDirStruct.fileNameLength)
directoryIndex += Int(centralDirStruct.extraFieldLength)
directoryIndex += Int(centralDirStruct.fileCommentLength)
index += 1
}
return Entry(centralDirectoryStructure: centralDirStruct,
localFileHeader: localFileHeader, dataDescriptor: dataDescriptor)
}
}
/// Retrieve the ZIP `Entry` with the given `path` from the receiver.
///
/// - Note: The ZIP file format specification does not enforce unique paths for entries.
/// Therefore an archive can contain multiple entries with the same path. This method
/// always returns the first `Entry` with the given `path`.
///
/// - Parameter path: A relative file path identifiying the corresponding `Entry`.
/// - Returns: An `Entry` with the given `path`. Otherwise, `nil`.
public subscript(path: String) -> Entry? {
if let encoding = preferredEncoding {
return self.first { $0.path(using: encoding) == path }
}
return self.first { $0.path == path }
}
// MARK: - Helpers
private static func configureFileBacking(for url: URL, mode: AccessMode)
-> (UnsafeMutablePointer<FILE>, EndOfCentralDirectoryRecord)? {
let fileManager = FileManager()
switch mode {
case .read:
let fileSystemRepresentation = fileManager.fileSystemRepresentation(withPath: url.path)
guard let archiveFile = fopen(fileSystemRepresentation, "rb"),
let endOfCentralDirectoryRecord = Archive.scanForEndOfCentralDirectoryRecord(in: archiveFile) else {
return nil
}
return (archiveFile, endOfCentralDirectoryRecord)
case .create:
let endOfCentralDirectoryRecord = EndOfCentralDirectoryRecord(numberOfDisk: 0, numberOfDiskStart: 0,
totalNumberOfEntriesOnDisk: 0,
totalNumberOfEntriesInCentralDirectory: 0,
sizeOfCentralDirectory: 0,
offsetToStartOfCentralDirectory: 0,
zipFileCommentLength: 0,
zipFileCommentData: Data())
do {
try endOfCentralDirectoryRecord.data.write(to: url, options: .withoutOverwriting)
} catch { return nil }
fallthrough
case .update:
let fileSystemRepresentation = fileManager.fileSystemRepresentation(withPath: url.path)
guard let archiveFile = fopen(fileSystemRepresentation, "rb+"),
let endOfCentralDirectoryRecord = Archive.scanForEndOfCentralDirectoryRecord(in: archiveFile) else {
return nil
}
fseek(archiveFile, 0, SEEK_SET)
return (archiveFile, endOfCentralDirectoryRecord)
}
}
private static func scanForEndOfCentralDirectoryRecord(in file: UnsafeMutablePointer<FILE>)
-> EndOfCentralDirectoryRecord? {
var directoryEnd = 0
var index = minDirectoryEndOffset
fseek(file, 0, SEEK_END)
let archiveLength = ftell(file)
while directoryEnd == 0 && index < maxDirectoryEndOffset && index <= archiveLength {
fseek(file, archiveLength - index, SEEK_SET)
var potentialDirectoryEndTag: UInt32 = UInt32()
fread(&potentialDirectoryEndTag, 1, MemoryLayout<UInt32>.size, file)
if potentialDirectoryEndTag == UInt32(endOfCentralDirectoryStructSignature) {
directoryEnd = archiveLength - index
return Data.readStruct(from: file, at: directoryEnd)
}
index += 1
}
return nil
}
}
extension Archive {
/// The number of the work units that have to be performed when
/// removing `entry` from the receiver.
///
/// - Parameter entry: The entry that will be removed.
/// - Returns: The number of the work units.
public func totalUnitCountForRemoving(_ entry: Entry) -> Int64 {
return Int64(self.endOfCentralDirectoryRecord.offsetToStartOfCentralDirectory
- UInt32(entry.localSize))
}
func makeProgressForRemoving(_ entry: Entry) -> Progress {
return Progress(totalUnitCount: self.totalUnitCountForRemoving(entry))
}
/// The number of the work units that have to be performed when
/// reading `entry` from the receiver.
///
/// - Parameter entry: The entry that will be read.
/// - Returns: The number of the work units.
public func totalUnitCountForReading(_ entry: Entry) -> Int64 {
switch entry.type {
case .file, .symlink:
return Int64(entry.uncompressedSize)
case .directory:
return defaultDirectoryUnitCount
}
}
func makeProgressForReading(_ entry: Entry) -> Progress {
return Progress(totalUnitCount: self.totalUnitCountForReading(entry))
}
/// The number of the work units that have to be performed when
/// adding the file at `url` to the receiver.
/// - Parameter entry: The entry that will be removed.
/// - Returns: The number of the work units.
public func totalUnitCountForAddingItem(at url: URL) -> Int64 {
var count = Int64(0)
do {
let type = try FileManager.typeForItem(at: url)
switch type {
case .file, .symlink:
count = Int64(try FileManager.fileSizeForItem(at: url))
case .directory:
count = defaultDirectoryUnitCount
}
} catch { count = -1 }
return count
}
func makeProgressForAddingItem(at url: URL) -> Progress {
return Progress(totalUnitCount: self.totalUnitCountForAddingItem(at: url))
}
}
extension Archive.EndOfCentralDirectoryRecord {
var data: Data {
var endOfCDSignature = self.endOfCentralDirectorySignature
var numberOfDisk = self.numberOfDisk
var numberOfDiskStart = self.numberOfDiskStart
var totalNumberOfEntriesOnDisk = self.totalNumberOfEntriesOnDisk
var totalNumberOfEntriesInCD = self.totalNumberOfEntriesInCentralDirectory
var sizeOfCentralDirectory = self.sizeOfCentralDirectory
var offsetToStartOfCD = self.offsetToStartOfCentralDirectory
var zipFileCommentLength = self.zipFileCommentLength
var data = Data()
withUnsafePointer(to: &endOfCDSignature, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &numberOfDisk, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &numberOfDiskStart, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &totalNumberOfEntriesOnDisk, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &totalNumberOfEntriesInCD, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &sizeOfCentralDirectory, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &offsetToStartOfCD, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &zipFileCommentLength, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
data.append(self.zipFileCommentData)
return data
}
init?(data: Data, additionalDataProvider provider: (Int) throws -> Data) {
guard data.count == Archive.EndOfCentralDirectoryRecord.size else { return nil }
guard data.scanValue(start: 0) == endOfCentralDirectorySignature else { return nil }
self.numberOfDisk = data.scanValue(start: 4)
self.numberOfDiskStart = data.scanValue(start: 6)
self.totalNumberOfEntriesOnDisk = data.scanValue(start: 8)
self.totalNumberOfEntriesInCentralDirectory = data.scanValue(start: 10)
self.sizeOfCentralDirectory = data.scanValue(start: 12)
self.offsetToStartOfCentralDirectory = data.scanValue(start: 16)
self.zipFileCommentLength = data.scanValue(start: 20)
guard let commentData = try? provider(Int(self.zipFileCommentLength)) else { return nil }
guard commentData.count == Int(self.zipFileCommentLength) else { return nil }
self.zipFileCommentData = commentData
}
init(record: Archive.EndOfCentralDirectoryRecord,
numberOfEntriesOnDisk: UInt16,
numberOfEntriesInCentralDirectory: UInt16,
updatedSizeOfCentralDirectory: UInt32,
startOfCentralDirectory: UInt32) {
numberOfDisk = record.numberOfDisk
numberOfDiskStart = record.numberOfDiskStart
totalNumberOfEntriesOnDisk = numberOfEntriesOnDisk
totalNumberOfEntriesInCentralDirectory = numberOfEntriesInCentralDirectory
sizeOfCentralDirectory = updatedSizeOfCentralDirectory
offsetToStartOfCentralDirectory = startOfCentralDirectory
zipFileCommentLength = record.zipFileCommentLength
zipFileCommentData = record.zipFileCommentData
}
}

View File

@ -1,349 +0,0 @@
//
// Data+Compression.swift
// ZIPFoundation
//
// Copyright © 2017-2020 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
//
import Foundation
/// An unsigned 32-Bit Integer representing a checksum.
public typealias CRC32 = UInt32
/// A custom handler that consumes a `Data` object containing partial entry data.
/// - Parameters:
/// - data: A chunk of `Data` to consume.
/// - Throws: Can throw to indicate errors during data consumption.
public typealias Consumer = (_ data: Data) throws -> Void
/// A custom handler that receives a position and a size that can be used to provide data from an arbitrary source.
/// - Parameters:
/// - position: The current read position.
/// - size: The size of the chunk to provide.
/// - Returns: A chunk of `Data`.
/// - Throws: Can throw to indicate errors in the data source.
public typealias Provider = (_ position: Int, _ size: Int) throws -> Data
/// The lookup table used to calculate `CRC32` checksums.
public let crcTable: [UInt32] = [
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
0x2d02ef8d]
extension Data {
enum CompressionError: Error {
case invalidStream
case corruptedData
}
/// Calculate the `CRC32` checksum of the receiver.
///
/// - Parameter checksum: The starting seed.
/// - Returns: The checksum calcualted from the bytes of the receiver and the starting seed.
public func crc32(checksum: CRC32) -> CRC32 {
// The typecast is necessary on 32-bit platforms because of
// https://bugs.swift.org/browse/SR-1774
let mask = 0xffffffff as UInt32
let bufferSize = self.count/MemoryLayout<UInt8>.size
var result = checksum ^ mask
#if swift(>=5.0)
crcTable.withUnsafeBufferPointer { crcTablePointer in
self.withUnsafeBytes { bufferPointer in
let bytePointer = bufferPointer.bindMemory(to: UInt8.self)
for bufferIndex in 0..<bufferSize {
let byte = bytePointer[bufferIndex]
let index = Int((result ^ UInt32(byte)) & 0xff)
result = (result >> 8) ^ crcTablePointer[index]
}
}
}
#else
self.withUnsafeBytes { (bytes) in
let bins = stride(from: 0, to: bufferSize, by: 256)
for bin in bins {
for binIndex in 0..<256 {
let byteIndex = bin + binIndex
guard byteIndex < bufferSize else { break }
let byte = bytes[byteIndex]
let index = Int((result ^ UInt32(byte)) & 0xff)
result = (result >> 8) ^ crcTable[index]
}
}
}
#endif
return result ^ mask
}
/// Compress the output of `provider` and pass it to `consumer`.
/// - Parameters:
/// - size: The uncompressed size of the data to be compressed.
/// - bufferSize: The maximum size of the compression buffer.
/// - provider: A closure that accepts a position and a chunk size. Returns a `Data` chunk.
/// - consumer: A closure that processes the result of the compress operation.
/// - Returns: The checksum of the processed content.
public static func compress(size: Int, bufferSize: Int, provider: Provider, consumer: Consumer) throws -> CRC32 {
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
return try self.process(operation: COMPRESSION_STREAM_ENCODE, size: size, bufferSize: bufferSize,
provider: provider, consumer: consumer)
#else
return try self.encode(size: size, bufferSize: bufferSize, provider: provider, consumer: consumer)
#endif
}
/// Decompress the output of `provider` and pass it to `consumer`.
/// - Parameters:
/// - size: The compressed size of the data to be decompressed.
/// - bufferSize: The maximum size of the decompression buffer.
/// - skipCRC32: Optional flag to skip calculation of the CRC32 checksum to improve performance.
/// - provider: A closure that accepts a position and a chunk size. Returns a `Data` chunk.
/// - consumer: A closure that processes the result of the decompress operation.
/// - Returns: The checksum of the processed content.
public static func decompress(size: Int, bufferSize: Int, skipCRC32: Bool,
provider: Provider, consumer: Consumer) throws -> CRC32 {
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
return try self.process(operation: COMPRESSION_STREAM_DECODE, size: size, bufferSize: bufferSize,
skipCRC32: skipCRC32, provider: provider, consumer: consumer)
#else
return try self.decode(bufferSize: bufferSize, skipCRC32: skipCRC32, provider: provider, consumer: consumer)
#endif
}
}
// MARK: - Apple Platforms
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
import Compression
extension Data {
static func process(operation: compression_stream_operation, size: Int, bufferSize: Int, skipCRC32: Bool = false,
provider: Provider, consumer: Consumer) throws -> CRC32 {
var crc32 = CRC32(0)
let destPointer = UnsafeMutablePointer<UInt8>.allocate(capacity: bufferSize)
defer { destPointer.deallocate() }
let streamPointer = UnsafeMutablePointer<compression_stream>.allocate(capacity: 1)
defer { streamPointer.deallocate() }
var stream = streamPointer.pointee
var status = compression_stream_init(&stream, operation, COMPRESSION_ZLIB)
guard status != COMPRESSION_STATUS_ERROR else { throw CompressionError.invalidStream }
defer { compression_stream_destroy(&stream) }
stream.src_size = 0
stream.dst_ptr = destPointer
stream.dst_size = bufferSize
var position = 0
var sourceData: Data?
repeat {
if stream.src_size == 0 {
do {
sourceData = try provider(position, Swift.min((size - position), bufferSize))
if let sourceData = sourceData {
position += sourceData.count
stream.src_size = sourceData.count
}
} catch { throw error }
}
if let sourceData = sourceData {
sourceData.withUnsafeBytes { (rawBufferPointer) in
if let baseAddress = rawBufferPointer.baseAddress {
let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
stream.src_ptr = pointer.advanced(by: sourceData.count - stream.src_size)
let flags = sourceData.count < bufferSize ? Int32(COMPRESSION_STREAM_FINALIZE.rawValue) : 0
status = compression_stream_process(&stream, flags)
}
}
if operation == COMPRESSION_STREAM_ENCODE && !skipCRC32 { crc32 = sourceData.crc32(checksum: crc32) }
}
switch status {
case COMPRESSION_STATUS_OK, COMPRESSION_STATUS_END:
let outputData = Data(bytesNoCopy: destPointer, count: bufferSize - stream.dst_size, deallocator: .none)
try consumer(outputData)
if operation == COMPRESSION_STREAM_DECODE && !skipCRC32 { crc32 = outputData.crc32(checksum: crc32) }
stream.dst_ptr = destPointer
stream.dst_size = bufferSize
default: throw CompressionError.corruptedData
}
} while status == COMPRESSION_STATUS_OK
return crc32
}
}
// MARK: - Linux
#else
import CZlib
extension Data {
static func encode(size: Int, bufferSize: Int, provider: Provider, consumer: Consumer) throws -> CRC32 {
var stream = z_stream()
let streamSize = Int32(MemoryLayout<z_stream>.size)
var result = deflateInit2_(&stream, Z_DEFAULT_COMPRESSION,
Z_DEFLATED, -MAX_WBITS, 9, Z_DEFAULT_STRATEGY, ZLIB_VERSION, streamSize)
defer { deflateEnd(&stream) }
guard result == Z_OK else { throw CompressionError.invalidStream }
var flush = Z_NO_FLUSH
var position = 0
var zipCRC32 = CRC32(0)
repeat {
let readSize = Swift.min((size - position), bufferSize)
var inputChunk = try provider(position, readSize)
zipCRC32 = inputChunk.crc32(checksum: zipCRC32)
stream.avail_in = UInt32(inputChunk.count)
try inputChunk.withUnsafeMutableBytes { (rawBufferPointer) in
if let baseAddress = rawBufferPointer.baseAddress {
let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
stream.next_in = pointer
flush = position + bufferSize >= size ? Z_FINISH : Z_NO_FLUSH
} else if rawBufferPointer.count > 0 {
throw CompressionError.corruptedData
} else {
stream.next_in = nil
flush = Z_FINISH
}
var outputChunk = Data(count: bufferSize)
repeat {
stream.avail_out = UInt32(bufferSize)
try outputChunk.withUnsafeMutableBytes { (rawBufferPointer) in
guard let baseAddress = rawBufferPointer.baseAddress, rawBufferPointer.count > 0 else {
throw CompressionError.corruptedData
}
let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
stream.next_out = pointer
result = deflate(&stream, flush)
}
guard result >= Z_OK else { throw CompressionError.corruptedData }
outputChunk.count = bufferSize - Int(stream.avail_out)
try consumer(outputChunk)
} while stream.avail_out == 0
}
position += readSize
} while flush != Z_FINISH
return zipCRC32
}
static func decode(bufferSize: Int, skipCRC32: Bool, provider: Provider, consumer: Consumer) throws -> CRC32 {
var stream = z_stream()
let streamSize = Int32(MemoryLayout<z_stream>.size)
var result = inflateInit2_(&stream, -MAX_WBITS, ZLIB_VERSION, streamSize)
defer { inflateEnd(&stream) }
guard result == Z_OK else { throw CompressionError.invalidStream }
var unzipCRC32 = CRC32(0)
var position = 0
repeat {
stream.avail_in = UInt32(bufferSize)
var chunk = try provider(position, bufferSize)
position += chunk.count
try chunk.withUnsafeMutableBytes { (rawBufferPointer) in
if let baseAddress = rawBufferPointer.baseAddress, rawBufferPointer.count > 0 {
let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
stream.next_in = pointer
repeat {
var outputData = Data(count: bufferSize)
stream.avail_out = UInt32(bufferSize)
try outputData.withUnsafeMutableBytes { (rawBufferPointer) in
if let baseAddress = rawBufferPointer.baseAddress, rawBufferPointer.count > 0 {
let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
stream.next_out = pointer
} else {
throw CompressionError.corruptedData
}
result = inflate(&stream, Z_NO_FLUSH)
guard result != Z_NEED_DICT &&
result != Z_DATA_ERROR &&
result != Z_MEM_ERROR else {
throw CompressionError.corruptedData
}
}
let remainingLength = UInt32(bufferSize) - stream.avail_out
outputData.count = Int(remainingLength)
try consumer(outputData)
if !skipCRC32 { unzipCRC32 = outputData.crc32(checksum: unzipCRC32) }
} while stream.avail_out == 0
}
}
} while result != Z_STREAM_END
return unzipCRC32
}
}
#endif
#if !swift(>=5.0)
// Since Swift 5.0, `Data.withUnsafeBytes()` passes an `UnsafeRawBufferPointer` instead of an `UnsafePointer<UInt8>`
// into `body`.
// We provide a compatible method for targets that use Swift 4.x so that we can use the new version
// across all language versions.
internal extension Data {
func withUnsafeBytes<T>(_ body: (UnsafeRawBufferPointer) throws -> T) rethrows -> T {
let count = self.count
return try withUnsafeBytes { (pointer: UnsafePointer<UInt8>) throws -> T in
try body(UnsafeRawBufferPointer(start: pointer, count: count))
}
}
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
#else
mutating func withUnsafeMutableBytes<T>(_ body: (UnsafeMutableRawBufferPointer) throws -> T) rethrows -> T {
let count = self.count
guard count > 0 else {
return try body(UnsafeMutableRawBufferPointer(start: nil, count: count))
}
return try withUnsafeMutableBytes { (pointer: UnsafeMutablePointer<UInt8>) throws -> T in
try body(UnsafeMutableRawBufferPointer(start: pointer, count: count))
}
}
#endif
}
#endif

View File

@ -1,103 +0,0 @@
//
// Data+Serialization.swift
// ZIPFoundation
//
// Copyright © 2017-2020 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
//
import Foundation
protocol DataSerializable {
static var size: Int { get }
init?(data: Data, additionalDataProvider: (Int) throws -> Data)
var data: Data { get }
}
extension Data {
enum DataError: Error {
case unreadableFile
case unwritableFile
}
func scanValue<T>(start: Int) -> T {
let subdata = self.subdata(in: start..<start+MemoryLayout<T>.size)
#if swift(>=5.0)
return subdata.withUnsafeBytes { $0.load(as: T.self) }
#else
return subdata.withUnsafeBytes { $0.pointee }
#endif
}
static func readStruct<T>(from file: UnsafeMutablePointer<FILE>, at offset: Int) -> T? where T: DataSerializable {
fseek(file, offset, SEEK_SET)
guard let data = try? self.readChunk(of: T.size, from: file) else {
return nil
}
let structure = T(data: data, additionalDataProvider: { (additionalDataSize) -> Data in
return try self.readChunk(of: additionalDataSize, from: file)
})
return structure
}
static func consumePart(of size: Int, chunkSize: Int, skipCRC32: Bool = false,
provider: Provider, consumer: Consumer) throws -> CRC32 {
var checksum = CRC32(0)
guard size > 0 else {
try consumer(Data())
return checksum
}
let readInOneChunk = (size < chunkSize)
var chunkSize = readInOneChunk ? size : chunkSize
var bytesRead = 0
while bytesRead < size {
let remainingSize = size - bytesRead
chunkSize = remainingSize < chunkSize ? remainingSize : chunkSize
let data = try provider(bytesRead, chunkSize)
try consumer(data)
if !skipCRC32 {
checksum = data.crc32(checksum: checksum)
}
bytesRead += chunkSize
}
return checksum
}
static func readChunk(of size: Int, from file: UnsafeMutablePointer<FILE>) throws -> Data {
let alignment = MemoryLayout<UInt>.alignment
#if swift(>=4.1)
let bytes = UnsafeMutableRawPointer.allocate(byteCount: size, alignment: alignment)
#else
let bytes = UnsafeMutableRawPointer.allocate(bytes: size, alignedTo: alignment)
#endif
let bytesRead = fread(bytes, 1, size, file)
let error = ferror(file)
if error > 0 {
throw DataError.unreadableFile
}
#if swift(>=4.1)
return Data(bytesNoCopy: bytes, count: bytesRead, deallocator: .custom({ buf, _ in buf.deallocate() }))
#else
let deallocator = Deallocator.custom({ buf, _ in buf.deallocate(bytes: size, alignedTo: 1) })
return Data(bytesNoCopy: bytes, count: bytesRead, deallocator: deallocator)
#endif
}
static func write(chunk: Data, to file: UnsafeMutablePointer<FILE>) throws -> Int {
var sizeWritten = 0
chunk.withUnsafeBytes { (rawBufferPointer) in
if let baseAddress = rawBufferPointer.baseAddress, rawBufferPointer.count > 0 {
let pointer = baseAddress.assumingMemoryBound(to: UInt8.self)
sizeWritten = fwrite(pointer, 1, chunk.count, file)
}
}
let error = ferror(file)
if error > 0 {
throw DataError.unwritableFile
}
return sizeWritten
}
}

View File

@ -1,400 +0,0 @@
//
// Entry.swift
// ZIPFoundation
//
// Copyright © 2017-2020 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
//
import Foundation
import CoreFoundation
/// A value that represents a file, a directory or a symbolic link within a ZIP `Archive`.
///
/// You can retrieve instances of `Entry` from an `Archive` via subscripting or iteration.
/// Entries are identified by their `path`.
public struct Entry: Equatable {
/// The type of an `Entry` in a ZIP `Archive`.
public enum EntryType: Int {
/// Indicates a regular file.
case file
/// Indicates a directory.
case directory
/// Indicates a symbolic link.
case symlink
init(mode: mode_t) {
switch mode & S_IFMT {
case S_IFDIR:
self = .directory
case S_IFLNK:
self = .symlink
default:
self = .file
}
}
}
enum OSType: UInt {
case msdos = 0
case unix = 3
case osx = 19
case unused = 20
}
struct LocalFileHeader: DataSerializable {
let localFileHeaderSignature = UInt32(localFileHeaderStructSignature)
let versionNeededToExtract: UInt16
let generalPurposeBitFlag: UInt16
let compressionMethod: UInt16
let lastModFileTime: UInt16
let lastModFileDate: UInt16
let crc32: UInt32
let compressedSize: UInt32
let uncompressedSize: UInt32
let fileNameLength: UInt16
let extraFieldLength: UInt16
static let size = 30
let fileNameData: Data
let extraFieldData: Data
}
struct DataDescriptor: DataSerializable {
let data: Data
let dataDescriptorSignature = UInt32(dataDescriptorStructSignature)
let crc32: UInt32
let compressedSize: UInt32
let uncompressedSize: UInt32
static let size = 16
}
struct CentralDirectoryStructure: DataSerializable {
let centralDirectorySignature = UInt32(centralDirectoryStructSignature)
let versionMadeBy: UInt16
let versionNeededToExtract: UInt16
let generalPurposeBitFlag: UInt16
let compressionMethod: UInt16
let lastModFileTime: UInt16
let lastModFileDate: UInt16
let crc32: UInt32
let compressedSize: UInt32
let uncompressedSize: UInt32
let fileNameLength: UInt16
let extraFieldLength: UInt16
let fileCommentLength: UInt16
let diskNumberStart: UInt16
let internalFileAttributes: UInt16
let externalFileAttributes: UInt32
let relativeOffsetOfLocalHeader: UInt32
static let size = 46
let fileNameData: Data
let extraFieldData: Data
let fileCommentData: Data
var usesDataDescriptor: Bool { return (self.generalPurposeBitFlag & (1 << 3 )) != 0 }
var usesUTF8PathEncoding: Bool { return (self.generalPurposeBitFlag & (1 << 11 )) != 0 }
var isEncrypted: Bool { return (self.generalPurposeBitFlag & (1 << 0)) != 0 }
var isZIP64: Bool { return self.versionNeededToExtract >= 45 }
}
/// Returns the `path` of the receiver within a ZIP `Archive` using a given encoding.
///
/// - Parameters:
/// - encoding: `String.Encoding`
public func path(using encoding: String.Encoding) -> String {
return String(data: self.centralDirectoryStructure.fileNameData, encoding: encoding) ?? ""
}
/// The `path` of the receiver within a ZIP `Archive`.
public var path: String {
let dosLatinUS = 0x400
let dosLatinUSEncoding = CFStringEncoding(dosLatinUS)
let dosLatinUSStringEncoding = CFStringConvertEncodingToNSStringEncoding(dosLatinUSEncoding)
let codepage437 = String.Encoding(rawValue: dosLatinUSStringEncoding)
let encoding = self.centralDirectoryStructure.usesUTF8PathEncoding ? .utf8 : codepage437
return self.path(using: encoding)
}
/// The file attributes of the receiver as key/value pairs.
///
/// Contains the modification date and file permissions.
public var fileAttributes: [FileAttributeKey: Any] {
return FileManager.attributes(from: self)
}
/// The `CRC32` checksum of the receiver.
///
/// - Note: Always returns `0` for entries of type `EntryType.directory`.
public var checksum: CRC32 {
var checksum = self.centralDirectoryStructure.crc32
if self.centralDirectoryStructure.usesDataDescriptor {
guard let dataDescriptor = self.dataDescriptor else { return 0 }
checksum = dataDescriptor.crc32
}
return checksum
}
/// The `EntryType` of the receiver.
public var type: EntryType {
// OS Type is stored in the upper byte of versionMadeBy
let osTypeRaw = self.centralDirectoryStructure.versionMadeBy >> 8
let osType = OSType(rawValue: UInt(osTypeRaw)) ?? .unused
var isDirectory = self.path.hasSuffix("/")
switch osType {
case .unix, .osx:
let mode = mode_t(self.centralDirectoryStructure.externalFileAttributes >> 16) & S_IFMT
switch mode {
case S_IFREG:
return .file
case S_IFDIR:
return .directory
case S_IFLNK:
return .symlink
default:
return isDirectory ? .directory : .file
}
case .msdos:
isDirectory = isDirectory || ((centralDirectoryStructure.externalFileAttributes >> 4) == 0x01)
fallthrough // For all other OSes we can only guess based on the directory suffix char
default: return isDirectory ? .directory : .file
}
}
/// The size of the receiver's compressed data.
public var compressedSize: Int {
return Int(dataDescriptor?.compressedSize ?? localFileHeader.compressedSize)
}
/// The size of the receiver's uncompressed data.
public var uncompressedSize: Int {
return Int(dataDescriptor?.uncompressedSize ?? localFileHeader.uncompressedSize)
}
/// The combined size of the local header, the data and the optional data descriptor.
var localSize: Int {
let localFileHeader = self.localFileHeader
var extraDataLength = Int(localFileHeader.fileNameLength)
extraDataLength += Int(localFileHeader.extraFieldLength)
var size = LocalFileHeader.size + extraDataLength
let isCompressed = localFileHeader.compressionMethod != CompressionMethod.none.rawValue
size += isCompressed ? self.compressedSize : self.uncompressedSize
size += self.dataDescriptor != nil ? DataDescriptor.size : 0
return size
}
var dataOffset: Int {
var dataOffset = Int(self.centralDirectoryStructure.relativeOffsetOfLocalHeader)
dataOffset += LocalFileHeader.size
dataOffset += Int(self.localFileHeader.fileNameLength)
dataOffset += Int(self.localFileHeader.extraFieldLength)
return dataOffset
}
let centralDirectoryStructure: CentralDirectoryStructure
let localFileHeader: LocalFileHeader
let dataDescriptor: DataDescriptor?
public static func == (lhs: Entry, rhs: Entry) -> Bool {
return lhs.path == rhs.path
&& lhs.localFileHeader.crc32 == rhs.localFileHeader.crc32
&& lhs.centralDirectoryStructure.relativeOffsetOfLocalHeader
== rhs.centralDirectoryStructure.relativeOffsetOfLocalHeader
}
init?(centralDirectoryStructure: CentralDirectoryStructure,
localFileHeader: LocalFileHeader,
dataDescriptor: DataDescriptor?) {
// We currently don't support ZIP64 or encrypted archives
guard !centralDirectoryStructure.isZIP64 else { return nil }
guard !centralDirectoryStructure.isEncrypted else { return nil }
self.centralDirectoryStructure = centralDirectoryStructure
self.localFileHeader = localFileHeader
self.dataDescriptor = dataDescriptor
}
}
extension Entry.LocalFileHeader {
var data: Data {
var localFileHeaderSignature = self.localFileHeaderSignature
var versionNeededToExtract = self.versionNeededToExtract
var generalPurposeBitFlag = self.generalPurposeBitFlag
var compressionMethod = self.compressionMethod
var lastModFileTime = self.lastModFileTime
var lastModFileDate = self.lastModFileDate
var crc32 = self.crc32
var compressedSize = self.compressedSize
var uncompressedSize = self.uncompressedSize
var fileNameLength = self.fileNameLength
var extraFieldLength = self.extraFieldLength
var data = Data()
withUnsafePointer(to: &localFileHeaderSignature, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &versionNeededToExtract, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &generalPurposeBitFlag, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &compressionMethod, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &lastModFileTime, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &lastModFileDate, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &crc32, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &compressedSize, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &uncompressedSize, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &fileNameLength, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &extraFieldLength, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
data.append(self.fileNameData)
data.append(self.extraFieldData)
return data
}
init?(data: Data, additionalDataProvider provider: (Int) throws -> Data) {
guard data.count == Entry.LocalFileHeader.size else { return nil }
guard data.scanValue(start: 0) == localFileHeaderSignature else { return nil }
self.versionNeededToExtract = data.scanValue(start: 4)
self.generalPurposeBitFlag = data.scanValue(start: 6)
self.compressionMethod = data.scanValue(start: 8)
self.lastModFileTime = data.scanValue(start: 10)
self.lastModFileDate = data.scanValue(start: 12)
self.crc32 = data.scanValue(start: 14)
self.compressedSize = data.scanValue(start: 18)
self.uncompressedSize = data.scanValue(start: 22)
self.fileNameLength = data.scanValue(start: 26)
self.extraFieldLength = data.scanValue(start: 28)
let additionalDataLength = Int(self.fileNameLength) + Int(self.extraFieldLength)
guard let additionalData = try? provider(additionalDataLength) else { return nil }
guard additionalData.count == additionalDataLength else { return nil }
var subRangeStart = 0
var subRangeEnd = Int(self.fileNameLength)
self.fileNameData = additionalData.subdata(in: subRangeStart..<subRangeEnd)
subRangeStart += Int(self.fileNameLength)
subRangeEnd = subRangeStart + Int(self.extraFieldLength)
self.extraFieldData = additionalData.subdata(in: subRangeStart..<subRangeEnd)
}
}
extension Entry.CentralDirectoryStructure {
var data: Data {
var centralDirectorySignature = self.centralDirectorySignature
var versionMadeBy = self.versionMadeBy
var versionNeededToExtract = self.versionNeededToExtract
var generalPurposeBitFlag = self.generalPurposeBitFlag
var compressionMethod = self.compressionMethod
var lastModFileTime = self.lastModFileTime
var lastModFileDate = self.lastModFileDate
var crc32 = self.crc32
var compressedSize = self.compressedSize
var uncompressedSize = self.uncompressedSize
var fileNameLength = self.fileNameLength
var extraFieldLength = self.extraFieldLength
var fileCommentLength = self.fileCommentLength
var diskNumberStart = self.diskNumberStart
var internalFileAttributes = self.internalFileAttributes
var externalFileAttributes = self.externalFileAttributes
var relativeOffsetOfLocalHeader = self.relativeOffsetOfLocalHeader
var data = Data()
withUnsafePointer(to: &centralDirectorySignature, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &versionMadeBy, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &versionNeededToExtract, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &generalPurposeBitFlag, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &compressionMethod, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &lastModFileTime, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &lastModFileDate, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &crc32, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &compressedSize, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &uncompressedSize, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &fileNameLength, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &extraFieldLength, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &fileCommentLength, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &diskNumberStart, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &internalFileAttributes, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &externalFileAttributes, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
withUnsafePointer(to: &relativeOffsetOfLocalHeader, { data.append(UnsafeBufferPointer(start: $0, count: 1))})
data.append(self.fileNameData)
data.append(self.extraFieldData)
data.append(self.fileCommentData)
return data
}
init?(data: Data, additionalDataProvider provider: (Int) throws -> Data) {
guard data.count == Entry.CentralDirectoryStructure.size else { return nil }
guard data.scanValue(start: 0) == centralDirectorySignature else { return nil }
self.versionMadeBy = data.scanValue(start: 4)
self.versionNeededToExtract = data.scanValue(start: 6)
self.generalPurposeBitFlag = data.scanValue(start: 8)
self.compressionMethod = data.scanValue(start: 10)
self.lastModFileTime = data.scanValue(start: 12)
self.lastModFileDate = data.scanValue(start: 14)
self.crc32 = data.scanValue(start: 16)
self.compressedSize = data.scanValue(start: 20)
self.uncompressedSize = data.scanValue(start: 24)
self.fileNameLength = data.scanValue(start: 28)
self.extraFieldLength = data.scanValue(start: 30)
self.fileCommentLength = data.scanValue(start: 32)
self.diskNumberStart = data.scanValue(start: 34)
self.internalFileAttributes = data.scanValue(start: 36)
self.externalFileAttributes = data.scanValue(start: 38)
self.relativeOffsetOfLocalHeader = data.scanValue(start: 42)
let additionalDataLength = Int(self.fileNameLength) + Int(self.extraFieldLength) + Int(self.fileCommentLength)
guard let additionalData = try? provider(additionalDataLength) else { return nil }
guard additionalData.count == additionalDataLength else { return nil }
var subRangeStart = 0
var subRangeEnd = Int(self.fileNameLength)
self.fileNameData = additionalData.subdata(in: subRangeStart..<subRangeEnd)
subRangeStart += Int(self.fileNameLength)
subRangeEnd = subRangeStart + Int(self.extraFieldLength)
self.extraFieldData = additionalData.subdata(in: subRangeStart..<subRangeEnd)
subRangeStart += Int(self.extraFieldLength)
subRangeEnd = subRangeStart + Int(self.fileCommentLength)
self.fileCommentData = additionalData.subdata(in: subRangeStart..<subRangeEnd)
}
init(localFileHeader: Entry.LocalFileHeader, fileAttributes: UInt32, relativeOffset: UInt32) {
versionMadeBy = UInt16(789)
versionNeededToExtract = localFileHeader.versionNeededToExtract
generalPurposeBitFlag = localFileHeader.generalPurposeBitFlag
compressionMethod = localFileHeader.compressionMethod
lastModFileTime = localFileHeader.lastModFileTime
lastModFileDate = localFileHeader.lastModFileDate
crc32 = localFileHeader.crc32
compressedSize = localFileHeader.compressedSize
uncompressedSize = localFileHeader.uncompressedSize
fileNameLength = localFileHeader.fileNameLength
extraFieldLength = UInt16(0)
fileCommentLength = UInt16(0)
diskNumberStart = UInt16(0)
internalFileAttributes = UInt16(0)
externalFileAttributes = fileAttributes
relativeOffsetOfLocalHeader = relativeOffset
fileNameData = localFileHeader.fileNameData
extraFieldData = Data()
fileCommentData = Data()
}
init(centralDirectoryStructure: Entry.CentralDirectoryStructure, offset: UInt32) {
let relativeOffset = centralDirectoryStructure.relativeOffsetOfLocalHeader - offset
relativeOffsetOfLocalHeader = relativeOffset
versionMadeBy = centralDirectoryStructure.versionMadeBy
versionNeededToExtract = centralDirectoryStructure.versionNeededToExtract
generalPurposeBitFlag = centralDirectoryStructure.generalPurposeBitFlag
compressionMethod = centralDirectoryStructure.compressionMethod
lastModFileTime = centralDirectoryStructure.lastModFileTime
lastModFileDate = centralDirectoryStructure.lastModFileDate
crc32 = centralDirectoryStructure.crc32
compressedSize = centralDirectoryStructure.compressedSize
uncompressedSize = centralDirectoryStructure.uncompressedSize
fileNameLength = centralDirectoryStructure.fileNameLength
extraFieldLength = centralDirectoryStructure.extraFieldLength
fileCommentLength = centralDirectoryStructure.fileCommentLength
diskNumberStart = centralDirectoryStructure.diskNumberStart
internalFileAttributes = centralDirectoryStructure.internalFileAttributes
externalFileAttributes = centralDirectoryStructure.externalFileAttributes
fileNameData = centralDirectoryStructure.fileNameData
extraFieldData = centralDirectoryStructure.extraFieldData
fileCommentData = centralDirectoryStructure.fileCommentData
}
}
extension Entry.DataDescriptor {
init?(data: Data, additionalDataProvider provider: (Int) throws -> Data) {
guard data.count == Entry.DataDescriptor.size else { return nil }
let signature: UInt32 = data.scanValue(start: 0)
// The DataDescriptor signature is not mandatory so we have to re-arrange the input data if it is missing.
var readOffset = 0
if signature == self.dataDescriptorSignature { readOffset = 4 }
self.crc32 = data.scanValue(start: readOffset + 0)
self.compressedSize = data.scanValue(start: readOffset + 4)
self.uncompressedSize = data.scanValue(start: readOffset + 8)
// Our add(_ entry:) methods always maintain compressed & uncompressed
// sizes and so we don't need a data descriptor for newly added entries.
// Data descriptors of already existing entries are manually preserved
// when copying those entries to the tempArchive during remove(_ entry:).
self.data = Data()
}
}

View File

@ -1,326 +0,0 @@
//
// FileManager+ZIP.swift
// ZIPFoundation
//
// Copyright © 2017-2020 Thomas Zoechling, https://www.peakstep.com and the ZIP Foundation project authors.
// Released under the MIT License.
//
// See https://github.com/weichsel/ZIPFoundation/blob/master/LICENSE for license information.
//
import Foundation
extension FileManager {
typealias CentralDirectoryStructure = Entry.CentralDirectoryStructure
/// Zips the file or direcory contents at the specified source URL to the destination URL.
///
/// If the item at the source URL is a directory, the directory itself will be
/// represented within the ZIP `Archive`. Calling this method with a directory URL
/// `file:///path/directory/` will create an archive with a `directory/` entry at the root level.
/// You can override this behavior by passing `false` for `shouldKeepParent`. In that case, the contents
/// of the source directory will be placed at the root of the archive.
/// - Parameters:
/// - sourceURL: The file URL pointing to an existing file or directory.
/// - destinationURL: The file URL that identifies the destination of the zip operation.
/// - shouldKeepParent: Indicates that the directory name of a source item should be used as root element
/// within the archive. Default is `true`.
/// - compressionMethod: Indicates the `CompressionMethod` that should be applied.
/// By default, `zipItem` will create uncompressed archives.
/// - progress: A progress object that can be used to track or cancel the zip operation.
/// - Throws: Throws an error if the source item does not exist or the destination URL is not writable.
public func zipItem(at sourceURL: URL, to destinationURL: URL,
shouldKeepParent: Bool = true, compressionMethod: CompressionMethod = .none,
progress: Progress? = nil) throws {
let fileManager = FileManager()
guard fileManager.itemExists(at: sourceURL) else {
throw CocoaError(.fileReadNoSuchFile, userInfo: [NSFilePathErrorKey: sourceURL.path])
}
guard !fileManager.itemExists(at: destinationURL) else {
throw CocoaError(.fileWriteFileExists, userInfo: [NSFilePathErrorKey: destinationURL.path])
}
guard let archive = Archive(url: destinationURL, accessMode: .create) else {
throw Archive.ArchiveError.unwritableArchive
}
let isDirectory = try FileManager.typeForItem(at: sourceURL) == .directory
if isDirectory {
let subPaths = try self.subpathsOfDirectory(atPath: sourceURL.path)
var totalUnitCount = Int64(0)
if let progress = progress {
totalUnitCount = subPaths.reduce(Int64(0), {
let itemURL = sourceURL.appendingPathComponent($1)
let itemSize = archive.totalUnitCountForAddingItem(at: itemURL)
return $0 + itemSize
})
progress.totalUnitCount = totalUnitCount
}
// If the caller wants to keep the parent directory, we use the lastPathComponent of the source URL
// as common base for all entries (similar to macOS' Archive Utility.app)
let directoryPrefix = sourceURL.lastPathComponent
for entryPath in subPaths {
let finalEntryPath = shouldKeepParent ? directoryPrefix + "/" + entryPath : entryPath
let finalBaseURL = shouldKeepParent ? sourceURL.deletingLastPathComponent() : sourceURL
if let progress = progress {
let itemURL = sourceURL.appendingPathComponent(entryPath)
let entryProgress = archive.makeProgressForAddingItem(at: itemURL)
progress.addChild(entryProgress, withPendingUnitCount: entryProgress.totalUnitCount)
try archive.addEntry(with: finalEntryPath, relativeTo: finalBaseURL,
compressionMethod: compressionMethod, progress: entryProgress)
} else {
try archive.addEntry(with: finalEntryPath, relativeTo: finalBaseURL,
compressionMethod: compressionMethod)
}
}
} else {
progress?.totalUnitCount = archive.totalUnitCountForAddingItem(at: sourceURL)
let baseURL = sourceURL.deletingLastPathComponent()
try archive.addEntry(with: sourceURL.lastPathComponent, relativeTo: baseURL,
compressionMethod: compressionMethod, progress: progress)
}
}
/// Unzips the contents at the specified source URL to the destination URL.
///
/// - Parameters:
/// - sourceURL: The file URL pointing to an existing ZIP file.
/// - destinationURL: The file URL that identifies the destination directory of the unzip operation.
/// - skipCRC32: Optional flag to skip calculation of the CRC32 checksum to improve performance.
/// - progress: A progress object that can be used to track or cancel the unzip operation.
/// - preferredEncoding: Encoding for entry paths. Overrides the encoding specified in the archive.
/// - Throws: Throws an error if the source item does not exist or the destination URL is not writable.
public func unzipItem(at sourceURL: URL, to destinationURL: URL, skipCRC32: Bool = false,
progress: Progress? = nil, preferredEncoding: String.Encoding? = nil) throws {
let fileManager = FileManager()
guard fileManager.itemExists(at: sourceURL) else {
throw CocoaError(.fileReadNoSuchFile, userInfo: [NSFilePathErrorKey: sourceURL.path])
}
guard let archive = Archive(url: sourceURL, accessMode: .read, preferredEncoding: preferredEncoding) else {
throw Archive.ArchiveError.unreadableArchive
}
// Defer extraction of symlinks until all files & directories have been created.
// This is necessary because we can't create links to files that haven't been created yet.
let sortedEntries = archive.sorted { (left, right) -> Bool in
switch (left.type, right.type) {
case (.directory, .file): return true
case (.directory, .symlink): return true
case (.file, .symlink): return true
default: return false
}
}
var totalUnitCount = Int64(0)
if let progress = progress {
totalUnitCount = sortedEntries.reduce(0, { $0 + archive.totalUnitCountForReading($1) })
progress.totalUnitCount = totalUnitCount
}
for entry in sortedEntries {
let path = preferredEncoding == nil ? entry.path : entry.path(using: preferredEncoding!)
let destinationEntryURL = destinationURL.appendingPathComponent(path)
guard destinationEntryURL.isContained(in: destinationURL) else {
throw CocoaError(.fileReadInvalidFileName,
userInfo: [NSFilePathErrorKey: destinationEntryURL.path])
}
if let progress = progress {
let entryProgress = archive.makeProgressForReading(entry)
progress.addChild(entryProgress, withPendingUnitCount: entryProgress.totalUnitCount)
_ = try archive.extract(entry, to: destinationEntryURL, skipCRC32: skipCRC32, progress: entryProgress)
} else {
_ = try archive.extract(entry, to: destinationEntryURL, skipCRC32: skipCRC32)
}
}
}
// MARK: - Helpers
func itemExists(at url: URL) -> Bool {
// Use `URL.checkResourceIsReachable()` instead of `FileManager.fileExists()` here
// because we don't want implicit symlink resolution.
// As per documentation, `FileManager.fileExists()` traverses symlinks and therefore a broken symlink
// would throw a `.fileReadNoSuchFile` false positive error.
// For ZIP files it may be intended to archive "broken" symlinks because they might be
// resolvable again when extracting the archive to a different destination.
return (try? url.checkResourceIsReachable()) == true
}
func createParentDirectoryStructure(for url: URL) throws {
let parentDirectoryURL = url.deletingLastPathComponent()
try self.createDirectory(at: parentDirectoryURL, withIntermediateDirectories: true, attributes: nil)
}
class func attributes(from entry: Entry) -> [FileAttributeKey: Any] {
let centralDirectoryStructure = entry.centralDirectoryStructure
let entryType = entry.type
let fileTime = centralDirectoryStructure.lastModFileTime
let fileDate = centralDirectoryStructure.lastModFileDate
let defaultPermissions = entryType == .directory ? defaultDirectoryPermissions : defaultFilePermissions
var attributes = [.posixPermissions: defaultPermissions] as [FileAttributeKey: Any]
// Certain keys are not yet supported in swift-corelibs
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
attributes[.modificationDate] = Date(dateTime: (fileDate, fileTime))
#endif
let versionMadeBy = centralDirectoryStructure.versionMadeBy
guard let osType = Entry.OSType(rawValue: UInt(versionMadeBy >> 8)) else { return attributes }
let externalFileAttributes = centralDirectoryStructure.externalFileAttributes
let permissions = self.permissions(for: externalFileAttributes, osType: osType, entryType: entryType)
attributes[.posixPermissions] = NSNumber(value: permissions)
return attributes
}
class func permissions(for externalFileAttributes: UInt32, osType: Entry.OSType,
entryType: Entry.EntryType) -> UInt16 {
switch osType {
case .unix, .osx:
let permissions = mode_t(externalFileAttributes >> 16) & (~S_IFMT)
let defaultPermissions = entryType == .directory ? defaultDirectoryPermissions : defaultFilePermissions
return permissions == 0 ? defaultPermissions : UInt16(permissions)
default:
return entryType == .directory ? defaultDirectoryPermissions : defaultFilePermissions
}
}
class func externalFileAttributesForEntry(of type: Entry.EntryType, permissions: UInt16) -> UInt32 {
var typeInt: UInt16
switch type {
case .file:
typeInt = UInt16(S_IFREG)
case .directory:
typeInt = UInt16(S_IFDIR)
case .symlink:
typeInt = UInt16(S_IFLNK)
}
var externalFileAttributes = UInt32(typeInt|UInt16(permissions))
externalFileAttributes = (externalFileAttributes << 16)
return externalFileAttributes
}
class func permissionsForItem(at URL: URL) throws -> UInt16 {
let fileManager = FileManager()
let entryFileSystemRepresentation = fileManager.fileSystemRepresentation(withPath: URL.path)
var fileStat = stat()
lstat(entryFileSystemRepresentation, &fileStat)
let permissions = fileStat.st_mode
return UInt16(permissions)
}
class func fileModificationDateTimeForItem(at url: URL) throws -> Date {
let fileManager = FileManager()
guard fileManager.itemExists(at: url) else {
throw CocoaError(.fileReadNoSuchFile, userInfo: [NSFilePathErrorKey: url.path])
}
let entryFileSystemRepresentation = fileManager.fileSystemRepresentation(withPath: url.path)
var fileStat = stat()
lstat(entryFileSystemRepresentation, &fileStat)
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
let modTimeSpec = fileStat.st_mtimespec
#else
let modTimeSpec = fileStat.st_mtim
#endif
let timeStamp = TimeInterval(modTimeSpec.tv_sec) + TimeInterval(modTimeSpec.tv_nsec)/1000000000.0
let modDate = Date(timeIntervalSince1970: timeStamp)
return modDate
}
class func fileSizeForItem(at url: URL) throws -> UInt32 {
let fileManager = FileManager()
guard fileManager.itemExists(at: url) else {
throw CocoaError(.fileReadNoSuchFile, userInfo: [NSFilePathErrorKey: url.path])
}
let entryFileSystemRepresentation = fileManager.fileSystemRepresentation(withPath: url.path)
var fileStat = stat()
lstat(entryFileSystemRepresentation, &fileStat)
return UInt32(fileStat.st_size)
}
class func typeForItem(at url: URL) throws -> Entry.EntryType {
let fileManager = FileManager()
guard url.isFileURL, fileManager.itemExists(at: url) else {
throw CocoaError(.fileReadNoSuchFile, userInfo: [NSFilePathErrorKey: url.path])
}
let entryFileSystemRepresentation = fileManager.fileSystemRepresentation(withPath: url.path)
var fileStat = stat()
lstat(entryFileSystemRepresentation, &fileStat)
return Entry.EntryType(mode: fileStat.st_mode)
}
}
extension Date {
init(dateTime: (UInt16, UInt16)) {
var msdosDateTime = Int(dateTime.0)
msdosDateTime <<= 16
msdosDateTime |= Int(dateTime.1)
var unixTime = tm()
unixTime.tm_sec = Int32((msdosDateTime&31)*2)
unixTime.tm_min = Int32((msdosDateTime>>5)&63)
unixTime.tm_hour = Int32((Int(dateTime.1)>>11)&31)
unixTime.tm_mday = Int32((msdosDateTime>>16)&31)
unixTime.tm_mon = Int32((msdosDateTime>>21)&15)
unixTime.tm_mon -= 1 // UNIX time struct month entries are zero based.
unixTime.tm_year = Int32(1980+(msdosDateTime>>25))
unixTime.tm_year -= 1900 // UNIX time structs count in "years since 1900".
let time = timegm(&unixTime)
self = Date(timeIntervalSince1970: TimeInterval(time))
}
var fileModificationDateTime: (UInt16, UInt16) {
return (self.fileModificationDate, self.fileModificationTime)
}
var fileModificationDate: UInt16 {
var time = time_t(self.timeIntervalSince1970)
guard let unixTime = gmtime(&time) else {
return 0
}
var year = unixTime.pointee.tm_year + 1900 // UNIX time structs count in "years since 1900".
// ZIP uses the MSDOS date format which has a valid range of 1980 - 2099.
year = year >= 1980 ? year : 1980
year = year <= 2099 ? year : 2099
let month = unixTime.pointee.tm_mon + 1 // UNIX time struct month entries are zero based.
let day = unixTime.pointee.tm_mday
return (UInt16)(day + ((month) * 32) + ((year - 1980) * 512))
}
var fileModificationTime: UInt16 {
var time = time_t(self.timeIntervalSince1970)
guard let unixTime = gmtime(&time) else {
return 0
}
let hour = unixTime.pointee.tm_hour
let minute = unixTime.pointee.tm_min
let second = unixTime.pointee.tm_sec
return (UInt16)((second/2) + (minute * 32) + (hour * 2048))
}
}
#if swift(>=4.2)
#else
#if os(macOS) || os(iOS) || os(watchOS) || os(tvOS)
#else
// The swift-corelibs-foundation version of NSError.swift was missing a convenience method to create
// error objects from error codes. (https://github.com/apple/swift-corelibs-foundation/pull/1420)
// We have to provide an implementation for non-Darwin platforms using Swift versions < 4.2.
public extension CocoaError {
public static func error(_ code: CocoaError.Code, userInfo: [AnyHashable: Any]? = nil, url: URL? = nil) -> Error {
var info: [String: Any] = userInfo as? [String: Any] ?? [:]
if let url = url {
info[NSURLErrorKey] = url
}
return NSError(domain: NSCocoaErrorDomain, code: code.rawValue, userInfo: info)
}
}
#endif
#endif
public extension URL {
func isContained(in parentDirectoryURL: URL) -> Bool {
// Ensure this URL is contained in the passed in URL
let parentDirectoryURL = URL(fileURLWithPath: parentDirectoryURL.path, isDirectory: true).standardized
return self.standardized.absoluteString.hasPrefix(parentDirectoryURL.absoluteString)
}
}

30
third-party/ZipArchive/BUILD vendored Normal file
View File

@ -0,0 +1,30 @@
objc_library(
name = "ZipArchive",
enable_modules = True,
module_name = "ZipArchive",
srcs = glob([
"Sources/*.m",
"Sources/minizip/*.h",
"Sources/minizip/*.c",
]),
hdrs = glob([
"PublicHeaders/**/*.h",
]),
includes = [
"PublicHeaders",
],
copts = [
"-DHAVE_ZLIB",
"-DHAVE_INTTYPES_H",
"-DHAVE_PKCRYPT",
"-DHAVE_STDINT_H",
"-DHAVE_WZAES",
],
sdk_frameworks = [
"Foundation",
],
visibility = [
"//visibility:public",
],
)

View File

@ -0,0 +1,70 @@
#ifndef SSZipCommon
#define SSZipCommon
#include <stdint.h>
// typedefs moved from mz_compat.h to here for public access
/* unz_global_info structure contain global data about the ZIPfile
These data comes from the end of central dir */
typedef struct unz_global_info64_s
{
uint64_t number_entry; /* total number of entries in the central dir on this disk */
uint32_t number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP */
uint16_t size_comment; /* size of the global comment of the zipfile */
} unz_global_info64;
typedef struct unz_global_info_s
{
uint32_t number_entry; /* total number of entries in the central dir on this disk */
uint32_t number_disk_with_CD; /* number the the disk with central dir, used for spanning ZIP */
uint16_t size_comment; /* size of the global comment of the zipfile */
} unz_global_info;
/* unz_file_info contain information about a file in the zipfile */
/* https://pkware.cachefly.net/webdocs/casestudies/APPNOTE.TXT */
typedef struct unz_file_info64_s
{
uint16_t version; /* version made by 2 bytes */
uint16_t version_needed; /* version needed to extract 2 bytes */
uint16_t flag; /* general purpose bit flag 2 bytes */
uint16_t compression_method; /* compression method 2 bytes */
uint32_t dos_date; /* last mod file date in Dos fmt 4 bytes */
uint32_t crc; /* crc-32 4 bytes */
uint64_t compressed_size; /* compressed size 8 bytes */
uint64_t uncompressed_size; /* uncompressed size 8 bytes */
uint16_t size_filename; /* filename length 2 bytes */
uint16_t size_file_extra; /* extra field length 2 bytes */
uint16_t size_file_comment; /* file comment length 2 bytes */
uint32_t disk_num_start; /* disk number start 4 bytes */
uint16_t internal_fa; /* internal file attributes 2 bytes */
uint32_t external_fa; /* external file attributes 4 bytes */
uint64_t disk_offset;
uint16_t size_file_extra_internal;
} unz_file_info64;
typedef struct unz_file_info_s
{
uint16_t version; /* version made by 2 bytes */
uint16_t version_needed; /* version needed to extract 2 bytes */
uint16_t flag; /* general purpose bit flag 2 bytes */
uint16_t compression_method; /* compression method 2 bytes */
uint32_t dos_date; /* last mod file date in Dos fmt 4 bytes */
uint32_t crc; /* crc-32 4 bytes */
uint32_t compressed_size; /* compressed size 4 bytes */
uint32_t uncompressed_size; /* uncompressed size 4 bytes */
uint16_t size_filename; /* filename length 2 bytes */
uint16_t size_file_extra; /* extra field length 2 bytes */
uint16_t size_file_comment; /* file comment length 2 bytes */
uint16_t disk_num_start; /* disk number start 2 bytes */
uint16_t internal_fa; /* internal file attributes 2 bytes */
uint32_t external_fa; /* external file attributes 4 bytes */
uint64_t disk_offset;
} unz_file_info;
#endif

View File

@ -0,0 +1,167 @@
//
// SSZipArchive.h
// SSZipArchive
//
// Created by Sam Soffes on 7/21/10.
// Copyright (c) Sam Soffes 2010-2015. All rights reserved.
//
#ifndef _SSZIPARCHIVE_H
#define _SSZIPARCHIVE_H
#import <Foundation/Foundation.h>
#if COCOAPODS
#import <SSZipArchive/SSZipCommon.h>
#else
#import <ZipArchive/SSZipCommon.h>
#endif
NS_ASSUME_NONNULL_BEGIN
extern NSString *const SSZipArchiveErrorDomain;
typedef NS_ENUM(NSInteger, SSZipArchiveErrorCode) {
SSZipArchiveErrorCodeFailedOpenZipFile = -1,
SSZipArchiveErrorCodeFailedOpenFileInZip = -2,
SSZipArchiveErrorCodeFileInfoNotLoadable = -3,
SSZipArchiveErrorCodeFileContentNotReadable = -4,
SSZipArchiveErrorCodeFailedToWriteFile = -5,
SSZipArchiveErrorCodeInvalidArguments = -6,
};
@protocol SSZipArchiveDelegate;
@interface SSZipEntry : NSObject
@property (nonatomic, strong, readonly) NSString *path;
@property (nonatomic, readonly) NSUInteger uncompressedSize;
- (instancetype)initWithPath:(NSString *)path uncompressedSize:(NSUInteger)uncompressedSize;
@end
@interface SSZipArchive : NSObject
+ (NSArray<SSZipEntry *> * _Nullable)getEntriesForFileAtPath:(NSString *)path;
+ (BOOL)extractFileFromArchiveAtPath:(NSString *)path filePath:(NSString *)filePath toPath:(NSString *)toPath;
// Password check
+ (BOOL)isFilePasswordProtectedAtPath:(NSString *)path;
+ (BOOL)isPasswordValidForArchiveAtPath:(NSString *)path password:(NSString *)pw error:(NSError * _Nullable * _Nullable)error NS_SWIFT_NOTHROW;
// Total payload size
+ (NSNumber *)payloadSizeForArchiveAtPath:(NSString *)path error:(NSError **)error;
// Unzip
+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination;
+ (BOOL)unzipFileAtPath:(NSString *)path toDestination:(NSString *)destination delegate:(nullable id<SSZipArchiveDelegate>)delegate;
+ (BOOL)unzipFileAtPath:(NSString *)path
toDestination:(NSString *)destination
overwrite:(BOOL)overwrite
password:(nullable NSString *)password
error:(NSError * *)error;
+ (BOOL)unzipFileAtPath:(NSString *)path
toDestination:(NSString *)destination
overwrite:(BOOL)overwrite
password:(nullable NSString *)password
error:(NSError * *)error
delegate:(nullable id<SSZipArchiveDelegate>)delegate NS_REFINED_FOR_SWIFT;
+ (BOOL)unzipFileAtPath:(NSString *)path
toDestination:(NSString *)destination
preserveAttributes:(BOOL)preserveAttributes
overwrite:(BOOL)overwrite
password:(nullable NSString *)password
error:(NSError * *)error
delegate:(nullable id<SSZipArchiveDelegate>)delegate;
+ (BOOL)unzipFileAtPath:(NSString *)path
toDestination:(NSString *)destination
progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler
completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler;
+ (BOOL)unzipFileAtPath:(NSString *)path
toDestination:(NSString *)destination
overwrite:(BOOL)overwrite
password:(nullable NSString *)password
progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler
completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler;
+ (BOOL)unzipFileAtPath:(NSString *)path
toDestination:(NSString *)destination
preserveAttributes:(BOOL)preserveAttributes
overwrite:(BOOL)overwrite
nestedZipLevel:(NSInteger)nestedZipLevel
password:(nullable NSString *)password
error:(NSError **)error
delegate:(nullable id<SSZipArchiveDelegate>)delegate
progressHandler:(void (^_Nullable)(NSString *entry, unz_file_info zipInfo, long entryNumber, long total))progressHandler
completionHandler:(void (^_Nullable)(NSString *path, BOOL succeeded, NSError * _Nullable error))completionHandler;
// Zip
// default compression level is Z_DEFAULT_COMPRESSION (from "zlib.h")
// keepParentDirectory: if YES, then unzipping will give `directoryName/fileName`. If NO, then unzipping will just give `fileName`. Default is NO.
// without password
+ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray<NSString *> *)paths;
+ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath;
+ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirectory;
// with optional password, default encryption is AES
// don't use AES if you need compatibility with native macOS unzip and Archive Utility
+ (BOOL)createZipFileAtPath:(NSString *)path withFilesAtPaths:(NSArray<NSString *> *)paths withPassword:(nullable NSString *)password;
+ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath withPassword:(nullable NSString *)password;
+ (BOOL)createZipFileAtPath:(NSString *)path withContentsOfDirectory:(NSString *)directoryPath keepParentDirectory:(BOOL)keepParentDirectory withPassword:(nullable NSString *)password;
+ (BOOL)createZipFileAtPath:(NSString *)path
withContentsOfDirectory:(NSString *)directoryPath
keepParentDirectory:(BOOL)keepParentDirectory
withPassword:(nullable NSString *)password
andProgressHandler:(void(^ _Nullable)(NSUInteger entryNumber, NSUInteger total))progressHandler;
+ (BOOL)createZipFileAtPath:(NSString *)path
withContentsOfDirectory:(NSString *)directoryPath
keepParentDirectory:(BOOL)keepParentDirectory
compressionLevel:(int)compressionLevel
password:(nullable NSString *)password
AES:(BOOL)aes
progressHandler:(void(^ _Nullable)(NSUInteger entryNumber, NSUInteger total))progressHandler;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithPath:(NSString *)path NS_DESIGNATED_INITIALIZER;
- (BOOL)open;
/// write empty folder
- (BOOL)writeFolderAtPath:(NSString *)path withFolderName:(NSString *)folderName withPassword:(nullable NSString *)password;
/// write file
- (BOOL)writeFile:(NSString *)path withPassword:(nullable NSString *)password;
- (BOOL)writeFileAtPath:(NSString *)path withFileName:(nullable NSString *)fileName withPassword:(nullable NSString *)password;
- (BOOL)writeFileAtPath:(NSString *)path withFileName:(nullable NSString *)fileName compressionLevel:(int)compressionLevel password:(nullable NSString *)password AES:(BOOL)aes;
/// write data
- (BOOL)writeData:(NSData *)data filename:(nullable NSString *)filename withPassword:(nullable NSString *)password;
- (BOOL)writeData:(NSData *)data filename:(nullable NSString *)filename compressionLevel:(int)compressionLevel password:(nullable NSString *)password AES:(BOOL)aes;
- (BOOL)close;
@end
@protocol SSZipArchiveDelegate <NSObject>
@optional
- (void)zipArchiveWillUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo;
- (void)zipArchiveDidUnzipArchiveAtPath:(NSString *)path zipInfo:(unz_global_info)zipInfo unzippedPath:(NSString *)unzippedPath;
- (BOOL)zipArchiveShouldUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo;
- (void)zipArchiveWillUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo;
- (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath fileInfo:(unz_file_info)fileInfo;
- (void)zipArchiveDidUnzipFileAtIndex:(NSInteger)fileIndex totalFiles:(NSInteger)totalFiles archivePath:(NSString *)archivePath unzippedFilePath:(NSString *)unzippedFilePath;
- (void)zipArchiveProgressEvent:(unsigned long long)loaded total:(unsigned long long)total;
@end
NS_ASSUME_NONNULL_END
#endif /* _SSZIPARCHIVE_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,17 @@
Condition of use and distribution are the same as zlib:
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgement in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

View File

@ -0,0 +1,252 @@
/* mz.h -- Errors codes, zip flags and magic
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#ifndef MZ_H
#define MZ_H
/***************************************************************************/
/* MZ_VERSION */
#define MZ_VERSION ("2.9.2")
/* MZ_ERROR */
#define MZ_OK (0) /* zlib */
#define MZ_STREAM_ERROR (-1) /* zlib */
#define MZ_DATA_ERROR (-3) /* zlib */
#define MZ_MEM_ERROR (-4) /* zlib */
#define MZ_BUF_ERROR (-5) /* zlib */
#define MZ_VERSION_ERROR (-6) /* zlib */
#define MZ_END_OF_LIST (-100)
#define MZ_END_OF_STREAM (-101)
#define MZ_PARAM_ERROR (-102)
#define MZ_FORMAT_ERROR (-103)
#define MZ_INTERNAL_ERROR (-104)
#define MZ_CRC_ERROR (-105)
#define MZ_CRYPT_ERROR (-106)
#define MZ_EXIST_ERROR (-107)
#define MZ_PASSWORD_ERROR (-108)
#define MZ_SUPPORT_ERROR (-109)
#define MZ_HASH_ERROR (-110)
#define MZ_OPEN_ERROR (-111)
#define MZ_CLOSE_ERROR (-112)
#define MZ_SEEK_ERROR (-113)
#define MZ_TELL_ERROR (-114)
#define MZ_READ_ERROR (-115)
#define MZ_WRITE_ERROR (-116)
#define MZ_SIGN_ERROR (-117)
#define MZ_SYMLINK_ERROR (-118)
/* MZ_OPEN */
#define MZ_OPEN_MODE_READ (0x01)
#define MZ_OPEN_MODE_WRITE (0x02)
#define MZ_OPEN_MODE_READWRITE (MZ_OPEN_MODE_READ | MZ_OPEN_MODE_WRITE)
#define MZ_OPEN_MODE_APPEND (0x04)
#define MZ_OPEN_MODE_CREATE (0x08)
#define MZ_OPEN_MODE_EXISTING (0x10)
/* MZ_SEEK */
#define MZ_SEEK_SET (0)
#define MZ_SEEK_CUR (1)
#define MZ_SEEK_END (2)
/* MZ_COMPRESS */
#define MZ_COMPRESS_METHOD_STORE (0)
#define MZ_COMPRESS_METHOD_DEFLATE (8)
#define MZ_COMPRESS_METHOD_BZIP2 (12)
#define MZ_COMPRESS_METHOD_LZMA (14)
#define MZ_COMPRESS_METHOD_AES (99)
#define MZ_COMPRESS_LEVEL_DEFAULT (-1)
#define MZ_COMPRESS_LEVEL_FAST (2)
#define MZ_COMPRESS_LEVEL_NORMAL (6)
#define MZ_COMPRESS_LEVEL_BEST (9)
/* MZ_ZIP_FLAG */
#define MZ_ZIP_FLAG_ENCRYPTED (1 << 0)
#define MZ_ZIP_FLAG_LZMA_EOS_MARKER (1 << 1)
#define MZ_ZIP_FLAG_DEFLATE_MAX (1 << 1)
#define MZ_ZIP_FLAG_DEFLATE_NORMAL (0)
#define MZ_ZIP_FLAG_DEFLATE_FAST (1 << 2)
#define MZ_ZIP_FLAG_DEFLATE_SUPER_FAST (MZ_ZIP_FLAG_DEFLATE_FAST | \
MZ_ZIP_FLAG_DEFLATE_MAX)
#define MZ_ZIP_FLAG_DATA_DESCRIPTOR (1 << 3)
#define MZ_ZIP_FLAG_UTF8 (1 << 11)
#define MZ_ZIP_FLAG_MASK_LOCAL_INFO (1 << 13)
/* MZ_ZIP_EXTENSION */
#define MZ_ZIP_EXTENSION_ZIP64 (0x0001)
#define MZ_ZIP_EXTENSION_NTFS (0x000a)
#define MZ_ZIP_EXTENSION_AES (0x9901)
#define MZ_ZIP_EXTENSION_UNIX1 (0x000d)
#define MZ_ZIP_EXTENSION_SIGN (0x10c5)
#define MZ_ZIP_EXTENSION_HASH (0x1a51)
#define MZ_ZIP_EXTENSION_CDCD (0xcdcd)
/* MZ_ZIP64 */
#define MZ_ZIP64_AUTO (0)
#define MZ_ZIP64_FORCE (1)
#define MZ_ZIP64_DISABLE (2)
/* MZ_HOST_SYSTEM */
#define MZ_HOST_SYSTEM(VERSION_MADEBY) ((uint8_t)(VERSION_MADEBY >> 8))
#define MZ_HOST_SYSTEM_MSDOS (0)
#define MZ_HOST_SYSTEM_UNIX (3)
#define MZ_HOST_SYSTEM_WINDOWS_NTFS (10)
#define MZ_HOST_SYSTEM_RISCOS (13)
#define MZ_HOST_SYSTEM_OSX_DARWIN (19)
/* MZ_PKCRYPT */
#define MZ_PKCRYPT_HEADER_SIZE (12)
/* MZ_AES */
#define MZ_AES_VERSION (1)
#define MZ_AES_ENCRYPTION_MODE_128 (0x01)
#define MZ_AES_ENCRYPTION_MODE_192 (0x02)
#define MZ_AES_ENCRYPTION_MODE_256 (0x03)
#define MZ_AES_KEY_LENGTH(MODE) (8 * (MODE & 3) + 8)
#define MZ_AES_KEY_LENGTH_MAX (32)
#define MZ_AES_BLOCK_SIZE (16)
#define MZ_AES_HEADER_SIZE(MODE) ((4 * (MODE & 3) + 4) + 2)
#define MZ_AES_FOOTER_SIZE (10)
/* MZ_HASH */
#define MZ_HASH_MD5 (10)
#define MZ_HASH_MD5_SIZE (16)
#define MZ_HASH_SHA1 (20)
#define MZ_HASH_SHA1_SIZE (20)
#define MZ_HASH_SHA256 (23)
#define MZ_HASH_SHA256_SIZE (32)
#define MZ_HASH_MAX_SIZE (256)
/* MZ_ENCODING */
#define MZ_ENCODING_CODEPAGE_437 (437)
#define MZ_ENCODING_CODEPAGE_932 (932)
#define MZ_ENCODING_CODEPAGE_936 (936)
#define MZ_ENCODING_CODEPAGE_950 (950)
#define MZ_ENCODING_UTF8 (65001)
/* MZ_UTILITY */
#define MZ_UNUSED(SYMBOL) ((void)SYMBOL)
#ifndef MZ_CUSTOM_ALLOC
#define MZ_ALLOC(SIZE) (malloc(SIZE))
#endif
#ifndef MZ_CUSTOM_FREE
#define MZ_FREE(PTR) (free(PTR))
#endif
#if defined(_WINDOWS) && defined(MZ_EXPORTS)
#define MZ_EXPORT __declspec(dllexport)
#else
#define MZ_EXPORT
#endif
/***************************************************************************/
#include <stdlib.h> /* size_t, NULL, malloc */
#include <time.h> /* time_t, time() */
#include <string.h> /* memset, strncpy, strlen */
#include <limits.h>
#ifdef HAVE_STDINT_H
# include <stdint.h>
#endif
#ifndef __INT8_TYPE__
typedef signed char int8_t;
#endif
#ifndef __INT16_TYPE__
typedef short int16_t;
#endif
#ifndef __INT32_TYPE__
typedef int int32_t;
#endif
#ifndef __INT64_TYPE__
typedef long long int64_t;
#endif
#ifndef __UINT8_TYPE__
typedef unsigned char uint8_t;
#endif
#ifndef __UINT16_TYPE__
typedef unsigned short uint16_t;
#endif
#ifndef __UINT32_TYPE__
typedef unsigned int uint32_t;
#endif
#ifndef __UINT64_TYPE__
typedef unsigned long long uint64_t;
#endif
#ifdef HAVE_INTTYPES_H
# include <inttypes.h>
#endif
#ifndef PRId8
# define PRId8 "hhd"
#endif
#ifndef PRId16
# define PRId16 "hd"
#endif
#ifndef PRId32
# define PRId32 "d"
#endif
#ifndef PRIu32
# define PRIu32 "u"
#endif
#ifndef PRIx32
# define PRIx32 "x"
#endif
#if ULONG_MAX == 4294967295UL
# ifndef PRId64
# define PRId64 "lld"
# endif
# ifndef PRIu64
# define PRIu64 "llu"
# endif
# ifndef PRIx64
# define PRIx64 "llx"
# endif
#else
# ifndef PRId64
# define PRId64 "ld"
# endif
# ifndef PRIu64
# define PRIu64 "lu"
# endif
# ifndef PRIx64
# define PRIx64 "lx"
# endif
#endif
#ifndef INT16_MAX
# define INT16_MAX 32767
#endif
#ifndef INT32_MAX
# define INT32_MAX 2147483647L
#endif
#ifndef INT64_MAX
# define INT64_MAX 9223372036854775807LL
#endif
#ifndef UINT16_MAX
# define UINT16_MAX 65535U
#endif
#ifndef UINT32_MAX
# define UINT32_MAX 4294967295UL
#endif
#ifndef UINT64_MAX
# define UINT64_MAX 18446744073709551615ULL
#endif
/***************************************************************************/
#endif

View File

@ -0,0 +1,991 @@
/* mz_compat.c -- Backwards compatible interface for older versions
Version 2.8.9, July 4, 2019
part of the MiniZip project
Copyright (C) 2010-2019 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
Copyright (C) 1998-2010 Gilles Vollant
https://www.winimage.com/zLibDll/minizip.html
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#include "mz.h"
#include "mz_os.h"
#include "mz_strm.h"
#include "mz_strm_mem.h"
#include "mz_strm_os.h"
#include "mz_strm_zlib.h"
#include "mz_zip.h"
#include <stdio.h> /* SEEK */
#include "mz_compat.h"
/***************************************************************************/
typedef struct mz_compat_s {
void *stream;
void *handle;
uint64_t entry_index;
int64_t entry_pos;
int64_t total_out;
} mz_compat;
/***************************************************************************/
static int32_t zipConvertAppendToStreamMode(int append)
{
int32_t mode = MZ_OPEN_MODE_WRITE;
switch (append)
{
case APPEND_STATUS_CREATE:
mode |= MZ_OPEN_MODE_CREATE;
break;
case APPEND_STATUS_CREATEAFTER:
mode |= MZ_OPEN_MODE_CREATE | MZ_OPEN_MODE_APPEND;
break;
case APPEND_STATUS_ADDINZIP:
mode |= MZ_OPEN_MODE_READ | MZ_OPEN_MODE_APPEND;
break;
}
return mode;
}
zipFile zipOpen(const char *path, int append)
{
zlib_filefunc64_def pzlib = mz_stream_os_get_interface();
return zipOpen2(path, append, NULL, &pzlib);
}
zipFile zipOpen64(const void *path, int append)
{
zlib_filefunc64_def pzlib = mz_stream_os_get_interface();
return zipOpen2(path, append, NULL, &pzlib);
}
zipFile zipOpen2(const char *path, int append, const char **globalcomment,
zlib_filefunc_def *pzlib_filefunc_def)
{
return zipOpen2_64(path, append, globalcomment, pzlib_filefunc_def);
}
zipFile zipOpen2_64(const void *path, int append, const char **globalcomment,
zlib_filefunc64_def *pzlib_filefunc_def)
{
zipFile zip = NULL;
int32_t mode = zipConvertAppendToStreamMode(append);
void *stream = NULL;
if (pzlib_filefunc_def)
{
if (mz_stream_create(&stream, (mz_stream_vtbl *)*pzlib_filefunc_def) == NULL)
return NULL;
}
else
{
if (mz_stream_os_create(&stream) == NULL)
return NULL;
}
if (mz_stream_open(stream, path, mode) != MZ_OK)
{
mz_stream_delete(&stream);
return NULL;
}
zip = zipOpen_MZ(stream, append, globalcomment);
if (zip == NULL)
{
mz_stream_delete(&stream);
return NULL;
}
return zip;
}
zipFile zipOpen_MZ(void *stream, int append, const char **globalcomment)
{
mz_compat *compat = NULL;
int32_t err = MZ_OK;
int32_t mode = zipConvertAppendToStreamMode(append);
void *handle = NULL;
mz_zip_create(&handle);
err = mz_zip_open(handle, stream, mode);
if (err != MZ_OK)
{
mz_zip_delete(&handle);
return NULL;
}
if (globalcomment != NULL)
mz_zip_get_comment(handle, globalcomment);
compat = (mz_compat *)MZ_ALLOC(sizeof(mz_compat));
if (compat != NULL)
{
compat->handle = handle;
compat->stream = stream;
}
else
{
mz_zip_delete(&handle);
}
return (zipFile)compat;
}
int zipOpenNewFileInZip5(zipFile file, const char *filename, const zip_fileinfo *zipfi,
const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
uint16_t size_extrafield_global, const char *comment, uint16_t compression_method, int level,
int raw, int windowBits, int memLevel, int strategy, const char *password,
signed char aes, uint16_t version_madeby, uint16_t flag_base, int zip64)
{
mz_compat *compat = (mz_compat *)file;
mz_zip_file file_info;
uint64_t dos_date = 0;
MZ_UNUSED(strategy);
MZ_UNUSED(memLevel);
MZ_UNUSED(windowBits);
MZ_UNUSED(size_extrafield_local);
MZ_UNUSED(extrafield_local);
if (compat == NULL)
return ZIP_PARAMERROR;
memset(&file_info, 0, sizeof(file_info));
if (zipfi != NULL)
{
if (zipfi->mz_dos_date != 0)
dos_date = zipfi->mz_dos_date;
else
dos_date = mz_zip_tm_to_dosdate(&zipfi->tmz_date);
file_info.modified_date = mz_zip_dosdate_to_time_t(dos_date);
file_info.external_fa = zipfi->external_fa;
file_info.internal_fa = zipfi->internal_fa;
}
if (filename == NULL)
filename = "-";
file_info.compression_method = compression_method;
file_info.filename = filename;
/* file_info.extrafield_local = extrafield_local; */
/* file_info.extrafield_local_size = size_extrafield_local; */
file_info.extrafield = extrafield_global;
file_info.extrafield_size = size_extrafield_global;
file_info.version_madeby = version_madeby;
file_info.comment = comment;
file_info.flag = flag_base;
if (zip64)
file_info.zip64 = MZ_ZIP64_FORCE;
else
file_info.zip64 = MZ_ZIP64_DISABLE;
#ifdef HAVE_WZAES
if ((aes && password != NULL) || (raw && (file_info.flag & MZ_ZIP_FLAG_ENCRYPTED)))
file_info.aes_version = MZ_AES_VERSION;
#endif
return mz_zip_entry_write_open(compat->handle, &file_info, (int16_t)level, (uint8_t)raw, password);
}
int zipWriteInFileInZip(zipFile file, const void *buf, uint32_t len)
{
mz_compat *compat = (mz_compat *)file;
int32_t written = 0;
if (compat == NULL || len >= INT32_MAX)
return ZIP_PARAMERROR;
written = mz_zip_entry_write(compat->handle, buf, (int32_t)len);
if ((written < 0) || ((uint32_t)written != len))
return ZIP_ERRNO;
return ZIP_OK;
}
int zipCloseFileInZipRaw(zipFile file, uint32_t uncompressed_size, uint32_t crc32)
{
return zipCloseFileInZipRaw64(file, uncompressed_size, crc32);
}
int zipCloseFileInZipRaw64(zipFile file, int64_t uncompressed_size, uint32_t crc32)
{
mz_compat *compat = (mz_compat *)file;
if (compat == NULL)
return ZIP_PARAMERROR;
return mz_zip_entry_close_raw(compat->handle, uncompressed_size, crc32);
}
int zipCloseFileInZip(zipFile file)
{
return zipCloseFileInZip64(file);
}
int zipCloseFileInZip64(zipFile file)
{
mz_compat *compat = (mz_compat *)file;
if (compat == NULL)
return ZIP_PARAMERROR;
return mz_zip_entry_close(compat->handle);
}
int zipClose(zipFile file, const char *global_comment)
{
return zipClose_64(file, global_comment);
}
int zipClose_64(zipFile file, const char *global_comment)
{
return zipClose2_64(file, global_comment, MZ_VERSION_MADEBY);
}
int zipClose2_64(zipFile file, const char *global_comment, uint16_t version_madeby)
{
mz_compat *compat = (mz_compat *)file;
int32_t err = MZ_OK;
if (compat->handle != NULL)
err = zipClose2_MZ(file, global_comment, version_madeby);
if (compat->stream != NULL)
{
mz_stream_close(compat->stream);
mz_stream_delete(&compat->stream);
}
MZ_FREE(compat);
return err;
}
/* Only closes the zip handle, does not close the stream */
int zipClose_MZ(zipFile file, const char *global_comment)
{
return zipClose2_MZ(file, global_comment, MZ_VERSION_MADEBY);
}
/* Only closes the zip handle, does not close the stream */
int zipClose2_MZ(zipFile file, const char *global_comment, uint16_t version_madeby)
{
mz_compat *compat = (mz_compat *)file;
int32_t err = MZ_OK;
if (compat == NULL)
return ZIP_PARAMERROR;
if (compat->handle == NULL)
return err;
if (global_comment != NULL)
mz_zip_set_comment(compat->handle, global_comment);
mz_zip_set_version_madeby(compat->handle, version_madeby);
err = mz_zip_close(compat->handle);
mz_zip_delete(&compat->handle);
return err;
}
void* zipGetStream(zipFile file)
{
mz_compat *compat = (mz_compat *)file;
if (compat == NULL)
return NULL;
return (void *)compat->stream;
}
/***************************************************************************/
unzFile unzOpen(const char *path)
{
return unzOpen64(path);
}
unzFile unzOpen64(const void *path)
{
zlib_filefunc64_def pzlib = mz_stream_os_get_interface();
return unzOpen2(path, &pzlib);
}
unzFile unzOpen2(const char *path, zlib_filefunc_def *pzlib_filefunc_def)
{
return unzOpen2_64(path, pzlib_filefunc_def);
}
unzFile unzOpen2_64(const void *path, zlib_filefunc64_def *pzlib_filefunc_def)
{
unzFile unz = NULL;
void *stream = NULL;
if (pzlib_filefunc_def)
{
if (mz_stream_create(&stream, (mz_stream_vtbl *)*pzlib_filefunc_def) == NULL)
return NULL;
}
else
{
if (mz_stream_os_create(&stream) == NULL)
return NULL;
}
if (mz_stream_open(stream, path, MZ_OPEN_MODE_READ) != MZ_OK)
{
mz_stream_delete(&stream);
return NULL;
}
unz = unzOpen_MZ(stream);
if (unz == NULL)
{
mz_stream_delete(&stream);
return NULL;
}
return unz;
}
unzFile unzOpen_MZ(void *stream)
{
mz_compat *compat = NULL;
int32_t err = MZ_OK;
void *handle = NULL;
mz_zip_create(&handle);
err = mz_zip_open(handle, stream, MZ_OPEN_MODE_READ);
if (err != MZ_OK)
{
mz_zip_delete(&handle);
return NULL;
}
compat = (mz_compat *)MZ_ALLOC(sizeof(mz_compat));
if (compat != NULL)
{
compat->handle = handle;
compat->stream = stream;
mz_zip_goto_first_entry(compat->handle);
}
else
{
mz_zip_delete(&handle);
}
return (unzFile)compat;
}
int unzClose(unzFile file)
{
mz_compat *compat = (mz_compat *)file;
int32_t err = MZ_OK;
if (compat == NULL)
return UNZ_PARAMERROR;
if (compat->handle != NULL)
err = unzClose_MZ(file);
if (compat->stream != NULL)
{
mz_stream_close(compat->stream);
mz_stream_delete(&compat->stream);
}
MZ_FREE(compat);
return err;
}
/* Only closes the zip handle, does not close the stream */
int unzClose_MZ(unzFile file)
{
mz_compat *compat = (mz_compat *)file;
int32_t err = MZ_OK;
if (compat == NULL)
return UNZ_PARAMERROR;
err = mz_zip_close(compat->handle);
mz_zip_delete(&compat->handle);
return err;
}
int unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32)
{
mz_compat *compat = (mz_compat *)file;
unz_global_info64 global_info64;
int32_t err = MZ_OK;
memset(pglobal_info32, 0, sizeof(unz_global_info));
if (compat == NULL)
return UNZ_PARAMERROR;
err = unzGetGlobalInfo64(file, &global_info64);
if (err == MZ_OK)
{
pglobal_info32->number_entry = (uint32_t)global_info64.number_entry;
pglobal_info32->size_comment = global_info64.size_comment;
pglobal_info32->number_disk_with_CD = global_info64.number_disk_with_CD;
}
return err;
}
int unzGetGlobalInfo64(unzFile file, unz_global_info64 *pglobal_info)
{
mz_compat *compat = (mz_compat *)file;
const char *comment_ptr = NULL;
int32_t err = MZ_OK;
memset(pglobal_info, 0, sizeof(unz_global_info64));
if (compat == NULL)
return UNZ_PARAMERROR;
err = mz_zip_get_comment(compat->handle, &comment_ptr);
if (err == MZ_OK)
pglobal_info->size_comment = (uint16_t)strlen(comment_ptr);
if ((err == MZ_OK) || (err == MZ_EXIST_ERROR))
err = mz_zip_get_number_entry(compat->handle, &pglobal_info->number_entry);
if (err == MZ_OK)
err = mz_zip_get_disk_number_with_cd(compat->handle, &pglobal_info->number_disk_with_CD);
return err;
}
int unzGetGlobalComment(unzFile file, char *comment, uint16_t comment_size)
{
mz_compat *compat = (mz_compat *)file;
const char *comment_ptr = NULL;
int32_t err = MZ_OK;
if (comment == NULL || comment_size == 0)
return UNZ_PARAMERROR;
err = mz_zip_get_comment(compat->handle, &comment_ptr);
if (err == MZ_OK)
{
strncpy(comment, comment_ptr, comment_size - 1);
comment[comment_size - 1] = 0;
}
return err;
}
int unzOpenCurrentFile3(unzFile file, int *method, int *level, int raw, const char *password)
{
mz_compat *compat = (mz_compat *)file;
mz_zip_file *file_info = NULL;
int32_t err = MZ_OK;
void *stream = NULL;
if (compat == NULL)
return UNZ_PARAMERROR;
if (method != NULL)
*method = 0;
if (level != NULL)
*level = 0;
compat->total_out = 0;
err = mz_zip_entry_read_open(compat->handle, (uint8_t)raw, password);
if (err == MZ_OK)
err = mz_zip_entry_get_info(compat->handle, &file_info);
if (err == MZ_OK)
{
if (method != NULL)
{
*method = file_info->compression_method;
}
if (level != NULL)
{
*level = 6;
switch (file_info->flag & 0x06)
{
case MZ_ZIP_FLAG_DEFLATE_SUPER_FAST:
*level = 1;
break;
case MZ_ZIP_FLAG_DEFLATE_FAST:
*level = 2;
break;
case MZ_ZIP_FLAG_DEFLATE_MAX:
*level = 9;
break;
}
}
}
if (err == MZ_OK)
err = mz_zip_get_stream(compat->handle, &stream);
if (err == MZ_OK)
compat->entry_pos = mz_stream_tell(stream);
return err;
}
int unzOpenCurrentFile(unzFile file)
{
return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);
}
int unzOpenCurrentFilePassword(unzFile file, const char *password)
{
return unzOpenCurrentFile3(file, NULL, NULL, 0, password);
}
int unzOpenCurrentFile2(unzFile file, int *method, int *level, int raw)
{
return unzOpenCurrentFile3(file, method, level, raw, NULL);
}
int unzReadCurrentFile(unzFile file, void *buf, uint32_t len)
{
mz_compat *compat = (mz_compat *)file;
int32_t err = MZ_OK;
if (compat == NULL || len >= INT32_MAX)
return UNZ_PARAMERROR;
err = mz_zip_entry_read(compat->handle, buf, (int32_t)len);
if (err > 0)
compat->total_out += (uint32_t)err;
return err;
}
int unzCloseCurrentFile(unzFile file)
{
mz_compat *compat = (mz_compat *)file;
int32_t err = MZ_OK;
if (compat == NULL)
return UNZ_PARAMERROR;
err = mz_zip_entry_close(compat->handle);
return err;
}
int unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *filename,
uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size)
{
mz_compat *compat = (mz_compat *)file;
mz_zip_file *file_info = NULL;
uint16_t bytes_to_copy = 0;
int32_t err = MZ_OK;
if (compat == NULL)
return UNZ_PARAMERROR;
err = mz_zip_entry_get_info(compat->handle, &file_info);
if ((err == MZ_OK) && (pfile_info != NULL))
{
pfile_info->version = file_info->version_madeby;
pfile_info->version_needed = file_info->version_needed;
pfile_info->flag = file_info->flag;
pfile_info->compression_method = file_info->compression_method;
pfile_info->mz_dos_date = mz_zip_time_t_to_dos_date(file_info->modified_date);
//mz_zip_time_t_to_tm(file_info->modified_date, &pfile_info->tmu_date);
//pfile_info->tmu_date.tm_year += 1900;
pfile_info->crc = file_info->crc;
pfile_info->size_filename = file_info->filename_size;
pfile_info->size_file_extra = file_info->extrafield_size;
pfile_info->size_file_comment = file_info->comment_size;
pfile_info->disk_num_start = (uint16_t)file_info->disk_number;
pfile_info->internal_fa = file_info->internal_fa;
pfile_info->external_fa = file_info->external_fa;
pfile_info->compressed_size = (uint32_t)file_info->compressed_size;
pfile_info->uncompressed_size = (uint32_t)file_info->uncompressed_size;
if (filename_size > 0 && filename != NULL && file_info->filename != NULL)
{
bytes_to_copy = filename_size;
if (bytes_to_copy > file_info->filename_size)
bytes_to_copy = file_info->filename_size;
memcpy(filename, file_info->filename, bytes_to_copy);
if (bytes_to_copy < filename_size)
filename[bytes_to_copy] = 0;
}
if (extrafield_size > 0 && extrafield != NULL)
{
bytes_to_copy = extrafield_size;
if (bytes_to_copy > file_info->extrafield_size)
bytes_to_copy = file_info->extrafield_size;
memcpy(extrafield, file_info->extrafield, bytes_to_copy);
}
if (comment_size > 0 && comment != NULL && file_info->comment != NULL)
{
bytes_to_copy = comment_size;
if (bytes_to_copy > file_info->comment_size)
bytes_to_copy = file_info->comment_size;
memcpy(comment, file_info->comment, bytes_to_copy);
if (bytes_to_copy < comment_size)
comment[bytes_to_copy] = 0;
}
}
return err;
}
int unzGetCurrentFileInfo64(unzFile file, unz_file_info64 * pfile_info, char *filename,
uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment, uint16_t comment_size)
{
mz_compat *compat = (mz_compat *)file;
mz_zip_file *file_info = NULL;
uint16_t bytes_to_copy = 0;
int32_t err = MZ_OK;
if (compat == NULL)
return UNZ_PARAMERROR;
err = mz_zip_entry_get_info(compat->handle, &file_info);
if ((err == MZ_OK) && (pfile_info != NULL))
{
pfile_info->version = file_info->version_madeby;
pfile_info->version_needed = file_info->version_needed;
pfile_info->flag = file_info->flag;
pfile_info->compression_method = file_info->compression_method;
pfile_info->mz_dos_date = mz_zip_time_t_to_dos_date(file_info->modified_date);
//mz_zip_time_t_to_tm(file_info->modified_date, &pfile_info->tmu_date);
//pfile_info->tmu_date.tm_year += 1900;
pfile_info->crc = file_info->crc;
pfile_info->size_filename = file_info->filename_size;
pfile_info->size_file_extra = file_info->extrafield_size;
pfile_info->size_file_comment = file_info->comment_size;
pfile_info->disk_num_start = file_info->disk_number;
pfile_info->internal_fa = file_info->internal_fa;
pfile_info->external_fa = file_info->external_fa;
pfile_info->compressed_size = (uint64_t)file_info->compressed_size;
pfile_info->uncompressed_size = (uint64_t)file_info->uncompressed_size;
if (filename_size > 0 && filename != NULL && file_info->filename != NULL)
{
bytes_to_copy = filename_size;
if (bytes_to_copy > file_info->filename_size)
bytes_to_copy = file_info->filename_size;
memcpy(filename, file_info->filename, bytes_to_copy);
if (bytes_to_copy < filename_size)
filename[bytes_to_copy] = 0;
}
if (extrafield_size > 0 && extrafield != NULL)
{
bytes_to_copy = extrafield_size;
if (bytes_to_copy > file_info->extrafield_size)
bytes_to_copy = file_info->extrafield_size;
memcpy(extrafield, file_info->extrafield, bytes_to_copy);
}
if (comment_size > 0 && comment != NULL && file_info->comment != NULL)
{
bytes_to_copy = comment_size;
if (bytes_to_copy > file_info->comment_size)
bytes_to_copy = file_info->comment_size;
memcpy(comment, file_info->comment, bytes_to_copy);
if (bytes_to_copy < comment_size)
comment[bytes_to_copy] = 0;
}
}
return err;
}
int unzGoToFirstFile(unzFile file)
{
mz_compat *compat = (mz_compat *)file;
if (compat == NULL)
return UNZ_PARAMERROR;
compat->entry_index = 0;
return mz_zip_goto_first_entry(compat->handle);
}
int unzGoToNextFile(unzFile file)
{
mz_compat *compat = (mz_compat *)file;
int32_t err = MZ_OK;
if (compat == NULL)
return UNZ_PARAMERROR;
err = mz_zip_goto_next_entry(compat->handle);
if (err != MZ_END_OF_LIST)
compat->entry_index += 1;
return err;
}
int unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func)
{
mz_compat *compat = (mz_compat *)file;
mz_zip_file *file_info = NULL;
uint64_t preserve_index = 0;
int32_t err = MZ_OK;
int32_t result = 0;
if (compat == NULL)
return UNZ_PARAMERROR;
preserve_index = compat->entry_index;
err = mz_zip_goto_first_entry(compat->handle);
while (err == MZ_OK)
{
err = mz_zip_entry_get_info(compat->handle, &file_info);
if (err != MZ_OK)
break;
if (filename_compare_func != NULL)
result = filename_compare_func(file, filename, file_info->filename);
else
result = strcmp(filename, file_info->filename);
if (result == 0)
return MZ_OK;
err = mz_zip_goto_next_entry(compat->handle);
}
compat->entry_index = preserve_index;
return err;
}
/***************************************************************************/
int unzGetFilePos(unzFile file, unz_file_pos *file_pos)
{
mz_compat *compat = (mz_compat *)file;
int32_t offset = 0;
if (compat == NULL || file_pos == NULL)
return UNZ_PARAMERROR;
offset = unzGetOffset(file);
if (offset < 0)
return offset;
file_pos->pos_in_zip_directory = (uint32_t)offset;
file_pos->num_of_file = (uint32_t)compat->entry_index;
return MZ_OK;
}
int unzGoToFilePos(unzFile file, unz_file_pos *file_pos)
{
mz_compat *compat = (mz_compat *)file;
unz64_file_pos file_pos64;
if (compat == NULL || file_pos == NULL)
return UNZ_PARAMERROR;
file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory;
file_pos64.num_of_file = file_pos->num_of_file;
return unzGoToFilePos64(file, &file_pos64);
}
int unzGetFilePos64(unzFile file, unz64_file_pos *file_pos)
{
mz_compat *compat = (mz_compat *)file;
int64_t offset = 0;
if (compat == NULL || file_pos == NULL)
return UNZ_PARAMERROR;
offset = unzGetOffset64(file);
if (offset < 0)
return (int)offset;
file_pos->pos_in_zip_directory = offset;
file_pos->num_of_file = compat->entry_index;
return UNZ_OK;
}
int unzGoToFilePos64(unzFile file, const unz64_file_pos *file_pos)
{
mz_compat *compat = (mz_compat *)file;
int32_t err = MZ_OK;
if (compat == NULL || file_pos == NULL)
return UNZ_PARAMERROR;
err = mz_zip_goto_entry(compat->handle, file_pos->pos_in_zip_directory);
if (err == MZ_OK)
compat->entry_index = file_pos->num_of_file;
return err;
}
int32_t unzGetOffset(unzFile file)
{
return (int32_t)unzGetOffset64(file);
}
int64_t unzGetOffset64(unzFile file)
{
mz_compat *compat = (mz_compat *)file;
if (compat == NULL)
return UNZ_PARAMERROR;
return mz_zip_get_entry(compat->handle);
}
int unzSetOffset(unzFile file, uint32_t pos)
{
return unzSetOffset64(file, pos);
}
int unzSetOffset64(unzFile file, int64_t pos)
{
mz_compat *compat = (mz_compat *)file;
if (compat == NULL)
return UNZ_PARAMERROR;
return (int)mz_zip_goto_entry(compat->handle, pos);
}
int unzGetLocalExtrafield(unzFile file, void *buf, unsigned int len)
{
mz_compat *compat = (mz_compat *)file;
mz_zip_file *file_info = NULL;
int32_t err = MZ_OK;
int32_t bytes_to_copy = 0;
if (compat == NULL || buf == NULL || len >= INT32_MAX)
return UNZ_PARAMERROR;
err = mz_zip_entry_get_local_info(compat->handle, &file_info);
if (err != MZ_OK)
return err;
bytes_to_copy = (int32_t)len;
if (bytes_to_copy > file_info->extrafield_size)
bytes_to_copy = file_info->extrafield_size;
memcpy(buf, file_info->extrafield, bytes_to_copy);
return MZ_OK;
}
int64_t unztell(unzFile file)
{
mz_compat *compat = (mz_compat *)file;
if (compat == NULL)
return UNZ_PARAMERROR;
return (int64_t)compat->total_out;
}
int32_t unzTell(unzFile file)
{
mz_compat *compat = (mz_compat *)file;
if (compat == NULL)
return UNZ_PARAMERROR;
return (int32_t)compat->total_out;
}
int64_t unzTell64(unzFile file)
{
mz_compat *compat = (mz_compat *)file;
if (compat == NULL)
return UNZ_PARAMERROR;
return (int64_t)compat->total_out;
}
int unzSeek(unzFile file, int32_t offset, int origin)
{
return unzSeek64(file, offset, origin);
}
int unzSeek64(unzFile file, int64_t offset, int origin)
{
mz_compat *compat = (mz_compat *)file;
mz_zip_file *file_info = NULL;
int64_t position = 0;
int32_t err = MZ_OK;
void *stream = NULL;
if (compat == NULL)
return UNZ_PARAMERROR;
err = mz_zip_entry_get_info(compat->handle, &file_info);
if (err != MZ_OK)
return err;
if (file_info->compression_method != MZ_COMPRESS_METHOD_STORE)
return UNZ_ERRNO;
if (origin == SEEK_SET)
position = offset;
else if (origin == SEEK_CUR)
position = compat->total_out + offset;
else if (origin == SEEK_END)
position = (int64_t)file_info->compressed_size + offset;
else
return UNZ_PARAMERROR;
if (position > (int64_t)file_info->compressed_size)
return UNZ_PARAMERROR;
err = mz_zip_get_stream(compat->handle, &stream);
if (err == MZ_OK)
err = mz_stream_seek(stream, compat->entry_pos + position, MZ_SEEK_SET);
if (err == MZ_OK)
compat->total_out = position;
return err;
}
int unzEndOfFile(unzFile file)
{
mz_compat *compat = (mz_compat *)file;
mz_zip_file *file_info = NULL;
int32_t err = MZ_OK;
if (compat == NULL)
return UNZ_PARAMERROR;
err = mz_zip_entry_get_info(compat->handle, &file_info);
if (err != MZ_OK)
return err;
if (compat->total_out == (int64_t)file_info->uncompressed_size)
return 1;
return 0;
}
void* unzGetStream(unzFile file)
{
mz_compat *compat = (mz_compat *)file;
if (compat == NULL)
return NULL;
return (void *)compat->stream;
}
/***************************************************************************/
void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def)
{
if (pzlib_filefunc_def != NULL)
*pzlib_filefunc_def = mz_stream_os_get_interface();
}
void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def)
{
if (pzlib_filefunc_def != NULL)
*pzlib_filefunc_def = mz_stream_os_get_interface();
}
void fill_win32_filefunc(zlib_filefunc_def *pzlib_filefunc_def)
{
if (pzlib_filefunc_def != NULL)
*pzlib_filefunc_def = mz_stream_os_get_interface();
}
void fill_win32_filefunc64(zlib_filefunc64_def *pzlib_filefunc_def)
{
if (pzlib_filefunc_def != NULL)
*pzlib_filefunc_def = mz_stream_os_get_interface();
}
void fill_win32_filefunc64A(zlib_filefunc64_def *pzlib_filefunc_def)
{
if (pzlib_filefunc_def != NULL)
*pzlib_filefunc_def = mz_stream_os_get_interface();
}
void fill_win32_filefunc64W(zlib_filefunc64_def *pzlib_filefunc_def)
{
/* NOTE: You should no longer pass in widechar string to open function */
if (pzlib_filefunc_def != NULL)
*pzlib_filefunc_def = mz_stream_os_get_interface();
}
void fill_memory_filefunc(zlib_filefunc_def *pzlib_filefunc_def)
{
if (pzlib_filefunc_def != NULL)
*pzlib_filefunc_def = mz_stream_mem_get_interface();
}

View File

@ -0,0 +1,250 @@
/* mz_compat.h -- Backwards compatible interface for older versions
Version 2.8.6, April 8, 2019
part of the MiniZip project
Copyright (C) 2010-2019 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
Copyright (C) 1998-2010 Gilles Vollant
https://www.winimage.com/zLibDll/minizip.html
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#ifndef MZ_COMPAT_H
#define MZ_COMPAT_H
#include "mz.h"
#include <ZipArchive/SSZipCommon.h>
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
#if defined(HAVE_ZLIB) && defined(MAX_MEM_LEVEL)
#ifndef DEF_MEM_LEVEL
# if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
# else
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
# endif
#endif
#endif
#ifndef MAX_WBITS
#define MAX_WBITS 15
#endif
#ifndef DEF_MEM_LEVEL
#define DEF_MEM_LEVEL 8
#endif
#ifndef ZEXPORT
# define ZEXPORT MZ_EXPORT
#endif
/***************************************************************************/
#if defined(STRICTZIP) || defined(STRICTZIPUNZIP)
/* like the STRICT of WIN32, we define a pointer that cannot be converted
from (void*) without cast */
typedef struct TagzipFile__ { int unused; } zip_file__;
typedef zip_file__ *zipFile;
#else
typedef void *zipFile;
#endif
/***************************************************************************/
typedef void *zlib_filefunc_def;
typedef void *zlib_filefunc64_def;
typedef const char *zipcharpc;
typedef struct tm tm_unz;
typedef struct tm tm_zip;
typedef uint64_t ZPOS64_T;
/***************************************************************************/
// ZipArchive 2.x uses dos_date
#define MZ_COMPAT_VERSION 120
#if MZ_COMPAT_VERSION <= 110
#define mz_dos_date dosDate
#else
#define mz_dos_date dos_date
#endif
typedef struct
{
uint32_t mz_dos_date;
struct tm tmz_date;
uint16_t internal_fa; /* internal file attributes 2 bytes */
uint32_t external_fa; /* external file attributes 4 bytes */
} zip_fileinfo;
/***************************************************************************/
#define ZIP_OK (0)
#define ZIP_EOF (0)
#define ZIP_ERRNO (-1)
#define ZIP_PARAMERROR (-102)
#define ZIP_BADZIPFILE (-103)
#define ZIP_INTERNALERROR (-104)
#define Z_BZIP2ED (12)
#define APPEND_STATUS_CREATE (0)
#define APPEND_STATUS_CREATEAFTER (1)
#define APPEND_STATUS_ADDINZIP (2)
/***************************************************************************/
/* Writing a zip file */
ZEXPORT zipFile zipOpen(const char *path, int append);
ZEXPORT zipFile zipOpen64(const void *path, int append);
ZEXPORT zipFile zipOpen2(const char *path, int append, const char **globalcomment,
zlib_filefunc_def *pzlib_filefunc_def);
ZEXPORT zipFile zipOpen2_64(const void *path, int append, const char **globalcomment,
zlib_filefunc64_def *pzlib_filefunc_def);
zipFile zipOpen_MZ(void *stream, int append, const char **globalcomment);
ZEXPORT int zipOpenNewFileInZip5(zipFile file, const char *filename, const zip_fileinfo *zipfi,
const void *extrafield_local, uint16_t size_extrafield_local, const void *extrafield_global,
uint16_t size_extrafield_global, const char *comment, uint16_t compression_method, int level,
int raw, int windowBits, int memLevel, int strategy, const char *password,
signed char aes, uint16_t version_madeby, uint16_t flag_base, int zip64);
ZEXPORT int zipWriteInFileInZip(zipFile file, const void *buf, uint32_t len);
ZEXPORT int zipCloseFileInZipRaw(zipFile file, uint32_t uncompressed_size, uint32_t crc32);
ZEXPORT int zipCloseFileInZipRaw64(zipFile file, int64_t uncompressed_size, uint32_t crc32);
ZEXPORT int zipCloseFileInZip(zipFile file);
ZEXPORT int zipCloseFileInZip64(zipFile file);
ZEXPORT int zipClose(zipFile file, const char *global_comment);
ZEXPORT int zipClose_64(zipFile file, const char *global_comment);
ZEXPORT int zipClose2_64(zipFile file, const char *global_comment, uint16_t version_madeby);
int zipClose_MZ(zipFile file, const char *global_comment);
int zipClose2_MZ(zipFile file, const char *global_comment, uint16_t version_madeby);
ZEXPORT void* zipGetStream(zipFile file);
/***************************************************************************/
#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
/* like the STRICT of WIN32, we define a pointer that cannot be converted
from (void*) without cast */
typedef struct TagunzFile__ { int unused; } unz_file__;
typedef unz_file__ *unzFile;
#else
typedef void *unzFile;
#endif
/***************************************************************************/
#define UNZ_OK (0)
#define UNZ_END_OF_LIST_OF_FILE (-100)
#define UNZ_ERRNO (-1)
#define UNZ_EOF (0)
#define UNZ_PARAMERROR (-102)
#define UNZ_BADZIPFILE (-103)
#define UNZ_INTERNALERROR (-104)
#define UNZ_CRCERROR (-105)
#define UNZ_BADPASSWORD (-106)
/***************************************************************************/
typedef int (*unzFileNameComparer)(unzFile file, const char *filename1, const char *filename2);
typedef int (*unzIteratorFunction)(unzFile file);
typedef int (*unzIteratorFunction2)(unzFile file, unz_file_info64 *pfile_info, char *filename,
uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment,
uint16_t comment_size);
/***************************************************************************/
/* Reading a zip file */
ZEXPORT unzFile unzOpen(const char *path);
ZEXPORT unzFile unzOpen64(const void *path);
ZEXPORT unzFile unzOpen2(const char *path, zlib_filefunc_def *pzlib_filefunc_def);
ZEXPORT unzFile unzOpen2_64(const void *path, zlib_filefunc64_def *pzlib_filefunc_def);
unzFile unzOpen_MZ(void *stream);
ZEXPORT int unzClose(unzFile file);
int unzClose_MZ(unzFile file);
ZEXPORT int unzGetGlobalInfo(unzFile file, unz_global_info* pglobal_info32);
ZEXPORT int unzGetGlobalInfo64(unzFile file, unz_global_info64 *pglobal_info);
ZEXPORT int unzGetGlobalComment(unzFile file, char *comment, uint16_t comment_size);
ZEXPORT int unzOpenCurrentFile(unzFile file);
ZEXPORT int unzOpenCurrentFilePassword(unzFile file, const char *password);
ZEXPORT int unzOpenCurrentFile2(unzFile file, int *method, int *level, int raw);
ZEXPORT int unzOpenCurrentFile3(unzFile file, int *method, int *level, int raw, const char *password);
ZEXPORT int unzReadCurrentFile(unzFile file, void *buf, uint32_t len);
ZEXPORT int unzCloseCurrentFile(unzFile file);
ZEXPORT int unzGetCurrentFileInfo(unzFile file, unz_file_info *pfile_info, char *filename,
uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment,
uint16_t comment_size);
ZEXPORT int unzGetCurrentFileInfo64(unzFile file, unz_file_info64 * pfile_info, char *filename,
uint16_t filename_size, void *extrafield, uint16_t extrafield_size, char *comment,
uint16_t comment_size);
ZEXPORT int unzGoToFirstFile(unzFile file);
ZEXPORT int unzGoToNextFile(unzFile file);
ZEXPORT int unzLocateFile(unzFile file, const char *filename, unzFileNameComparer filename_compare_func);
ZEXPORT int unzGetLocalExtrafield(unzFile file, void *buf, unsigned int len);
/***************************************************************************/
/* Raw access to zip file */
typedef struct unz_file_pos_s
{
uint32_t pos_in_zip_directory; /* offset in zip file directory */
uint32_t num_of_file; /* # of file */
} unz_file_pos;
ZEXPORT int unzGetFilePos(unzFile file, unz_file_pos *file_pos);
ZEXPORT int unzGoToFilePos(unzFile file, unz_file_pos *file_pos);
typedef struct unz64_file_pos_s
{
int64_t pos_in_zip_directory; /* offset in zip file directory */
uint64_t num_of_file; /* # of file */
} unz64_file_pos;
ZEXPORT int unzGetFilePos64(unzFile file, unz64_file_pos *file_pos);
ZEXPORT int unzGoToFilePos64(unzFile file, const unz64_file_pos *file_pos);
ZEXPORT int64_t unzGetOffset64(unzFile file);
ZEXPORT int32_t unzGetOffset(unzFile file);
ZEXPORT int unzSetOffset64(unzFile file, int64_t pos);
ZEXPORT int unzSetOffset(unzFile file, uint32_t pos);
ZEXPORT int64_t unztell(unzFile file);
ZEXPORT int32_t unzTell(unzFile file);
ZEXPORT int64_t unzTell64(unzFile file);
ZEXPORT int unzSeek(unzFile file, int32_t offset, int origin);
ZEXPORT int unzSeek64(unzFile file, int64_t offset, int origin);
ZEXPORT int unzEndOfFile(unzFile file);
ZEXPORT void* unzGetStream(unzFile file);
/***************************************************************************/
ZEXPORT void fill_fopen_filefunc(zlib_filefunc_def *pzlib_filefunc_def);
ZEXPORT void fill_fopen64_filefunc(zlib_filefunc64_def *pzlib_filefunc_def);
ZEXPORT void fill_win32_filefunc(zlib_filefunc_def *pzlib_filefunc_def);
ZEXPORT void fill_win32_filefunc64(zlib_filefunc64_def *pzlib_filefunc_def);
ZEXPORT void fill_win32_filefunc64A(zlib_filefunc64_def *pzlib_filefunc_def);
ZEXPORT void fill_win32_filefunc64W(zlib_filefunc64_def *pzlib_filefunc_def);
ZEXPORT void fill_memory_filefunc(zlib_filefunc_def *pzlib_filefunc_def);
/***************************************************************************/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,195 @@
/* mz_crypt.c -- Crypto/hash functions
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#include "mz.h"
#include "mz_crypt.h"
#if defined(HAVE_ZLIB)
# include "zlib.h"
# if defined(ZLIBNG_VERNUM) && !defined(ZLIB_COMPAT)
# include "zlib-ng.h"
# endif
#elif defined(HAVE_LZMA)
# include "lzma.h"
#endif
/***************************************************************************/
/* Define z_crc_t in zlib 1.2.5 and less or if using zlib-ng */
#if defined(HAVE_ZLIB) && defined(ZLIBNG_VERNUM)
# if defined(ZLIB_COMPAT)
# define ZLIB_PREFIX(x) x
# else
# define ZLIB_PREFIX(x) zng_ ## x
# endif
typedef uint32_t z_crc_t;
#elif defined(HAVE_ZLIB)
# define ZLIB_PREFIX(x) x
# if (ZLIB_VERNUM < 0x1270)
typedef unsigned long z_crc_t;
# endif
#endif
/***************************************************************************/
uint32_t mz_crypt_crc32_update(uint32_t value, const uint8_t *buf, int32_t size)
{
#if defined(HAVE_ZLIB)
return (uint32_t)ZLIB_PREFIX(crc32)((z_crc_t)value, buf, (uInt)size);
#elif defined(HAVE_LZMA)
return (uint32_t)lzma_crc32(buf, (size_t)size, (uint32_t)value);
#else
static uint32_t crc32_table[256] = {
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
};
value = ~value;
while (size > 0)
{
value = (value >> 8) ^ crc32_table[(value ^ *buf) & 0xFF];
buf += 1;
size -= 1;
}
return ~value;
#endif
}
#ifndef MZ_ZIP_NO_ENCRYPTION
int32_t mz_crypt_pbkdf2(uint8_t *password, int32_t password_length, uint8_t *salt,
int32_t salt_length, int32_t iteration_count, uint8_t *key, int32_t key_length)
{
void *hmac1 = NULL;
void *hmac2 = NULL;
void *hmac3 = NULL;
int32_t err = MZ_OK;
uint16_t i = 0;
uint16_t j = 0;
uint16_t k = 0;
uint16_t block_count = 0;
uint8_t uu[MZ_HASH_SHA1_SIZE];
uint8_t ux[MZ_HASH_SHA1_SIZE];
if (password == NULL || salt == NULL || key == NULL)
return MZ_PARAM_ERROR;
memset(key, 0, key_length);
mz_crypt_hmac_create(&hmac1);
mz_crypt_hmac_create(&hmac2);
mz_crypt_hmac_create(&hmac3);
mz_crypt_hmac_set_algorithm(hmac1, MZ_HASH_SHA1);
mz_crypt_hmac_set_algorithm(hmac2, MZ_HASH_SHA1);
mz_crypt_hmac_set_algorithm(hmac3, MZ_HASH_SHA1);
err = mz_crypt_hmac_init(hmac1, password, password_length);
if (err == MZ_OK)
err = mz_crypt_hmac_init(hmac2, password, password_length);
if (err == MZ_OK)
err = mz_crypt_hmac_update(hmac2, salt, salt_length);
block_count = 1 + ((uint16_t)key_length - 1) / MZ_HASH_SHA1_SIZE;
for (i = 0; (err == MZ_OK) && (i < block_count); i += 1)
{
memset(ux, 0, sizeof(ux));
err = mz_crypt_hmac_copy(hmac2, hmac3);
if (err != MZ_OK)
break;
uu[0] = (uint8_t)((i + 1) >> 24);
uu[1] = (uint8_t)((i + 1) >> 16);
uu[2] = (uint8_t)((i + 1) >> 8);
uu[3] = (uint8_t)(i + 1);
for (j = 0, k = 4; j < iteration_count; j += 1)
{
err = mz_crypt_hmac_update(hmac3, uu, k);
if (err == MZ_OK)
err = mz_crypt_hmac_end(hmac3, uu, sizeof(uu));
if (err != MZ_OK)
break;
for(k = 0; k < MZ_HASH_SHA1_SIZE; k += 1)
ux[k] ^= uu[k];
err = mz_crypt_hmac_copy(hmac1, hmac3);
if (err != MZ_OK)
break;
}
if (err != MZ_OK)
break;
j = 0;
k = i * MZ_HASH_SHA1_SIZE;
while (j < MZ_HASH_SHA1_SIZE && k < key_length)
key[k++] = ux[j++];
}
/* hmac3 uses the same provider as hmac2, so it must be deleted
before the context is destroyed. */
mz_crypt_hmac_delete(&hmac3);
mz_crypt_hmac_delete(&hmac1);
mz_crypt_hmac_delete(&hmac2);
return err;
}
#endif
/***************************************************************************/

View File

@ -0,0 +1,66 @@
/* mz_crypt.h -- Crypto/hash functions
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#ifndef MZ_CRYPT_H
#define MZ_CRYPT_H
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
uint32_t mz_crypt_crc32_update(uint32_t value, const uint8_t *buf, int32_t size);
int32_t mz_crypt_pbkdf2(uint8_t *password, int32_t password_length, uint8_t *salt,
int32_t salt_length, int32_t iteration_count, uint8_t *key, int32_t key_length);
/***************************************************************************/
int32_t mz_crypt_rand(uint8_t *buf, int32_t size);
void mz_crypt_sha_reset(void *handle);
int32_t mz_crypt_sha_begin(void *handle);
int32_t mz_crypt_sha_update(void *handle, const void *buf, int32_t size);
int32_t mz_crypt_sha_end(void *handle, uint8_t *digest, int32_t digest_size);
void mz_crypt_sha_set_algorithm(void *handle, uint16_t algorithm);
void* mz_crypt_sha_create(void **handle);
void mz_crypt_sha_delete(void **handle);
void mz_crypt_aes_reset(void *handle);
int32_t mz_crypt_aes_encrypt(void *handle, uint8_t *buf, int32_t size);
int32_t mz_crypt_aes_decrypt(void *handle, uint8_t *buf, int32_t size);
int32_t mz_crypt_aes_set_encrypt_key(void *handle, const void *key, int32_t key_length);
int32_t mz_crypt_aes_set_decrypt_key(void *handle, const void *key, int32_t key_length);
void mz_crypt_aes_set_mode(void *handle, int32_t mode);
void* mz_crypt_aes_create(void **handle);
void mz_crypt_aes_delete(void **handle);
void mz_crypt_hmac_reset(void *handle);
int32_t mz_crypt_hmac_init(void *handle, const void *key, int32_t key_length);
int32_t mz_crypt_hmac_update(void *handle, const void *buf, int32_t size);
int32_t mz_crypt_hmac_end(void *handle, uint8_t *digest, int32_t digest_size);
int32_t mz_crypt_hmac_copy(void *src_handle, void *target_handle);
void mz_crypt_hmac_set_algorithm(void *handle, uint16_t algorithm);
void* mz_crypt_hmac_create(void **handle);
void mz_crypt_hmac_delete(void **handle);
int32_t mz_crypt_sign(uint8_t *message, int32_t message_size, uint8_t *cert_data, int32_t cert_data_size,
const char *cert_pwd, uint8_t **signature, int32_t *signature_size);
int32_t mz_crypt_sign_verify(uint8_t *message, int32_t message_size, uint8_t *signature, int32_t signature_size);
/***************************************************************************/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,532 @@
/* mz_crypt_apple.c -- Crypto/hash functions for Apple
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#include "mz.h"
#include <CoreFoundation/CoreFoundation.h>
#include <CommonCrypto/CommonCryptor.h>
#include <CommonCrypto/CommonDigest.h>
#include <CommonCrypto/CommonHMAC.h>
#include <Security/Security.h>
#include <Security/SecPolicy.h>
/***************************************************************************/
int32_t mz_crypt_rand(uint8_t *buf, int32_t size)
{
if (SecRandomCopyBytes(kSecRandomDefault, size, buf) != errSecSuccess)
return 0;
return size;
}
/***************************************************************************/
typedef struct mz_crypt_sha_s {
CC_SHA1_CTX ctx1;
CC_SHA256_CTX ctx256;
int32_t error;
int32_t initialized;
uint16_t algorithm;
} mz_crypt_sha;
/***************************************************************************/
void mz_crypt_sha_reset(void *handle)
{
mz_crypt_sha *sha = (mz_crypt_sha *)handle;
sha->error = 0;
sha->initialized = 0;
}
int32_t mz_crypt_sha_begin(void *handle)
{
mz_crypt_sha *sha = (mz_crypt_sha *)handle;
if (sha == NULL)
return MZ_PARAM_ERROR;
mz_crypt_sha_reset(handle);
if (sha->algorithm == MZ_HASH_SHA1)
sha->error = CC_SHA1_Init(&sha->ctx1);
else if (sha->algorithm == MZ_HASH_SHA256)
sha->error = CC_SHA256_Init(&sha->ctx256);
else
return MZ_PARAM_ERROR;
if (!sha->error)
return MZ_HASH_ERROR;
sha->initialized = 1;
return MZ_OK;
}
int32_t mz_crypt_sha_update(void *handle, const void *buf, int32_t size)
{
mz_crypt_sha *sha = (mz_crypt_sha *)handle;
if (sha == NULL || buf == NULL || !sha->initialized)
return MZ_PARAM_ERROR;
if (sha->algorithm == MZ_HASH_SHA1)
sha->error = CC_SHA1_Update(&sha->ctx1, buf, size);
else
sha->error = CC_SHA256_Update(&sha->ctx256, buf, size);
if (!sha->error)
return MZ_HASH_ERROR;
return size;
}
int32_t mz_crypt_sha_end(void *handle, uint8_t *digest, int32_t digest_size)
{
mz_crypt_sha *sha = (mz_crypt_sha *)handle;
if (sha == NULL || digest == NULL || !sha->initialized)
return MZ_PARAM_ERROR;
if (sha->algorithm == MZ_HASH_SHA1)
{
if (digest_size < MZ_HASH_SHA1_SIZE)
return MZ_BUF_ERROR;
sha->error = CC_SHA1_Final(digest, &sha->ctx1);
}
else
{
if (digest_size < MZ_HASH_SHA256_SIZE)
return MZ_BUF_ERROR;
sha->error = CC_SHA256_Final(digest, &sha->ctx256);
}
if (!sha->error)
return MZ_HASH_ERROR;
return MZ_OK;
}
void mz_crypt_sha_set_algorithm(void *handle, uint16_t algorithm)
{
mz_crypt_sha *sha = (mz_crypt_sha *)handle;
sha->algorithm = algorithm;
}
void *mz_crypt_sha_create(void **handle)
{
mz_crypt_sha *sha = NULL;
sha = (mz_crypt_sha *)MZ_ALLOC(sizeof(mz_crypt_sha));
if (sha != NULL)
{
memset(sha, 0, sizeof(mz_crypt_sha));
sha->algorithm = MZ_HASH_SHA256;
}
if (handle != NULL)
*handle = sha;
return sha;
}
void mz_crypt_sha_delete(void **handle)
{
mz_crypt_sha *sha = NULL;
if (handle == NULL)
return;
sha = (mz_crypt_sha *)*handle;
if (sha != NULL)
{
mz_crypt_sha_reset(*handle);
MZ_FREE(sha);
}
*handle = NULL;
}
/***************************************************************************/
typedef struct mz_crypt_aes_s {
CCCryptorRef crypt;
int32_t mode;
int32_t error;
} mz_crypt_aes;
/***************************************************************************/
void mz_crypt_aes_reset(void *handle)
{
mz_crypt_aes *aes = (mz_crypt_aes *)handle;
if (aes->crypt != NULL)
CCCryptorRelease(aes->crypt);
aes->crypt = NULL;
}
int32_t mz_crypt_aes_encrypt(void *handle, uint8_t *buf, int32_t size)
{
mz_crypt_aes *aes = (mz_crypt_aes *)handle;
size_t data_moved = 0;
if (aes == NULL || buf == NULL)
return MZ_PARAM_ERROR;
if (size != MZ_AES_BLOCK_SIZE)
return MZ_PARAM_ERROR;
aes->error = CCCryptorUpdate(aes->crypt, buf, size, buf, size, &data_moved);
if (aes->error != kCCSuccess)
return MZ_HASH_ERROR;
return size;
}
int32_t mz_crypt_aes_decrypt(void *handle, uint8_t *buf, int32_t size)
{
mz_crypt_aes *aes = (mz_crypt_aes *)handle;
size_t data_moved = 0;
if (aes == NULL || buf == NULL)
return MZ_PARAM_ERROR;
if (size != MZ_AES_BLOCK_SIZE)
return MZ_PARAM_ERROR;
aes->error = CCCryptorUpdate(aes->crypt, buf, size, buf, size, &data_moved);
if (aes->error != kCCSuccess)
return MZ_HASH_ERROR;
return size;
}
int32_t mz_crypt_aes_set_encrypt_key(void *handle, const void *key, int32_t key_length)
{
mz_crypt_aes *aes = (mz_crypt_aes *)handle;
if (aes == NULL || key == NULL || key_length == 0)
return MZ_PARAM_ERROR;
mz_crypt_aes_reset(handle);
aes->error = CCCryptorCreate(kCCEncrypt, kCCAlgorithmAES, kCCOptionECBMode,
key, key_length, NULL, &aes->crypt);
if (aes->error != kCCSuccess)
return MZ_HASH_ERROR;
return MZ_OK;
}
int32_t mz_crypt_aes_set_decrypt_key(void *handle, const void *key, int32_t key_length)
{
mz_crypt_aes *aes = (mz_crypt_aes *)handle;
if (aes == NULL || key == NULL || key_length == 0)
return MZ_PARAM_ERROR;
mz_crypt_aes_reset(handle);
aes->error = CCCryptorCreate(kCCDecrypt, kCCAlgorithmAES, kCCOptionECBMode,
key, key_length, NULL, &aes->crypt);
if (aes->error != kCCSuccess)
return MZ_HASH_ERROR;
return MZ_OK;
}
void mz_crypt_aes_set_mode(void *handle, int32_t mode)
{
mz_crypt_aes *aes = (mz_crypt_aes *)handle;
aes->mode = mode;
}
void *mz_crypt_aes_create(void **handle)
{
mz_crypt_aes *aes = NULL;
aes = (mz_crypt_aes *)MZ_ALLOC(sizeof(mz_crypt_aes));
if (aes != NULL)
memset(aes, 0, sizeof(mz_crypt_aes));
if (handle != NULL)
*handle = aes;
return aes;
}
void mz_crypt_aes_delete(void **handle)
{
mz_crypt_aes *aes = NULL;
if (handle == NULL)
return;
aes = (mz_crypt_aes *)*handle;
if (aes != NULL)
{
mz_crypt_aes_reset(*handle);
MZ_FREE(aes);
}
*handle = NULL;
}
/***************************************************************************/
typedef struct mz_crypt_hmac_s {
CCHmacContext ctx;
int32_t initialized;
int32_t error;
uint16_t algorithm;
} mz_crypt_hmac;
/***************************************************************************/
static void mz_crypt_hmac_free(void *handle)
{
mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
memset(&hmac->ctx, 0, sizeof(hmac->ctx));
}
void mz_crypt_hmac_reset(void *handle)
{
mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
mz_crypt_hmac_free(handle);
hmac->error = 0;
}
int32_t mz_crypt_hmac_init(void *handle, const void *key, int32_t key_length)
{
mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
CCHmacAlgorithm algorithm = 0;
if (hmac == NULL || key == NULL)
return MZ_PARAM_ERROR;
mz_crypt_hmac_reset(handle);
if (hmac->algorithm == MZ_HASH_SHA1)
algorithm = kCCHmacAlgSHA1;
else if (hmac->algorithm == MZ_HASH_SHA256)
algorithm = kCCHmacAlgSHA256;
else
return MZ_PARAM_ERROR;
CCHmacInit(&hmac->ctx, algorithm, key, key_length);
return MZ_OK;
}
int32_t mz_crypt_hmac_update(void *handle, const void *buf, int32_t size)
{
mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
if (hmac == NULL || buf == NULL)
return MZ_PARAM_ERROR;
CCHmacUpdate(&hmac->ctx, buf, size);
return MZ_OK;
}
int32_t mz_crypt_hmac_end(void *handle, uint8_t *digest, int32_t digest_size)
{
mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
if (hmac == NULL || digest == NULL)
return MZ_PARAM_ERROR;
if (hmac->algorithm == MZ_HASH_SHA1)
{
if (digest_size < MZ_HASH_SHA1_SIZE)
return MZ_BUF_ERROR;
CCHmacFinal(&hmac->ctx, digest);
}
else
{
if (digest_size < MZ_HASH_SHA256_SIZE)
return MZ_BUF_ERROR;
CCHmacFinal(&hmac->ctx, digest);
}
return MZ_OK;
}
void mz_crypt_hmac_set_algorithm(void *handle, uint16_t algorithm)
{
mz_crypt_hmac *hmac = (mz_crypt_hmac *)handle;
hmac->algorithm = algorithm;
}
int32_t mz_crypt_hmac_copy(void *src_handle, void *target_handle)
{
mz_crypt_hmac *source = (mz_crypt_hmac *)src_handle;
mz_crypt_hmac *target = (mz_crypt_hmac *)target_handle;
if (source == NULL || target == NULL)
return MZ_PARAM_ERROR;
memcpy(&target->ctx, &source->ctx, sizeof(CCHmacContext));
return MZ_OK;
}
void *mz_crypt_hmac_create(void **handle)
{
mz_crypt_hmac *hmac = NULL;
hmac = (mz_crypt_hmac *)MZ_ALLOC(sizeof(mz_crypt_hmac));
if (hmac != NULL)
{
memset(hmac, 0, sizeof(mz_crypt_hmac));
hmac->algorithm = MZ_HASH_SHA256;
}
if (handle != NULL)
*handle = hmac;
return hmac;
}
void mz_crypt_hmac_delete(void **handle)
{
mz_crypt_hmac *hmac = NULL;
if (handle == NULL)
return;
hmac = (mz_crypt_hmac *)*handle;
if (hmac != NULL)
{
mz_crypt_hmac_free(*handle);
MZ_FREE(hmac);
}
*handle = NULL;
}
/***************************************************************************/
#if defined(MZ_ZIP_SIGNING)
int32_t mz_crypt_sign(uint8_t *message, int32_t message_size, uint8_t *cert_data, int32_t cert_data_size,
const char *cert_pwd, uint8_t **signature, int32_t *signature_size)
{
CFStringRef password_ref = NULL;
CFDictionaryRef options_dict = NULL;
CFDictionaryRef identity_trust = NULL;
CFDataRef signature_out = NULL;
CFDataRef pkcs12_data = NULL;
CFArrayRef items = 0;
SecIdentityRef identity = NULL;
SecTrustRef trust = NULL;
OSStatus status = noErr;
const void *options_key[2] = { kSecImportExportPassphrase, kSecReturnRef };
const void *options_values[2] = { 0, kCFBooleanTrue };
int32_t err = MZ_SIGN_ERROR;
if (message == NULL || cert_data == NULL || signature == NULL || signature_size == NULL)
return MZ_PARAM_ERROR;
*signature = NULL;
*signature_size = 0;
password_ref = CFStringCreateWithCString(0, cert_pwd, kCFStringEncodingUTF8);
options_values[0] = password_ref;
options_dict = CFDictionaryCreate(0, options_key, options_values, 2, 0, 0);
if (options_dict)
pkcs12_data = CFDataCreate(0, cert_data, cert_data_size);
if (pkcs12_data)
status = SecPKCS12Import(pkcs12_data, options_dict, &items);
if (status == noErr)
identity_trust = CFArrayGetValueAtIndex(items, 0);
if (identity_trust)
identity = (SecIdentityRef)CFDictionaryGetValue(identity_trust, kSecImportItemIdentity);
if (identity)
trust = (SecTrustRef)CFDictionaryGetValue(identity_trust, kSecImportItemTrust);
if (trust)
{
status = CMSEncodeContent(identity, NULL, NULL, FALSE, 0, message, message_size, &signature_out);
if (status == errSecSuccess)
{
*signature_size = CFDataGetLength(signature_out);
*signature = (uint8_t *)MZ_ALLOC(*signature_size);
memcpy(*signature, CFDataGetBytePtr(signature_out), *signature_size);
err = MZ_OK;
}
}
if (signature_out)
CFRelease(signature_out);
if (items)
CFRelease(items);
if (pkcs12_data)
CFRelease(pkcs12_data);
if (options_dict)
CFRelease(options_dict);
if (password_ref)
CFRelease(password_ref);
return err;
}
int32_t mz_crypt_sign_verify(uint8_t *message, int32_t message_size, uint8_t *signature, int32_t signature_size)
{
CMSDecoderRef decoder = NULL;
CMSSignerStatus signer_status = 0;
CFDataRef message_out = NULL;
SecPolicyRef trust_policy = NULL;
OSStatus status = noErr;
OSStatus verify_status = noErr;
size_t signer_count = 0;
size_t i = 0;
int32_t err = MZ_SIGN_ERROR;
if (message == NULL || signature == NULL)
return MZ_PARAM_ERROR;
status = CMSDecoderCreate(&decoder);
if (status == errSecSuccess)
status = CMSDecoderUpdateMessage(decoder, signature, signature_size);
if (status == errSecSuccess)
status = CMSDecoderFinalizeMessage(decoder);
if (status == errSecSuccess)
trust_policy = SecPolicyCreateBasicX509();
if (status == errSecSuccess && trust_policy)
{
CMSDecoderGetNumSigners(decoder, &signer_count);
if (signer_count > 0)
err = MZ_OK;
for (i = 0; i < signer_count; i += 1)
{
status = CMSDecoderCopySignerStatus(decoder, i, trust_policy, TRUE, &signer_status, NULL, &verify_status);
if (status != errSecSuccess || verify_status != 0 || signer_status != kCMSSignerValid)
{
err = MZ_SIGN_ERROR;
break;
}
}
}
if (err == MZ_OK)
{
status = CMSDecoderCopyContent(decoder, &message_out);
if ((status != errSecSuccess) ||
(CFDataGetLength(message_out) != message_size) ||
(memcmp(message, CFDataGetBytePtr(message_out), message_size) != 0))
err = MZ_SIGN_ERROR;
}
if (trust_policy)
CFRelease(trust_policy);
if (decoder)
CFRelease(decoder);
return err;
}
#endif

View File

@ -0,0 +1,401 @@
/* mz_os.c -- System functions
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
Copyright (C) 1998-2010 Gilles Vollant
https://www.winimage.com/zLibDll/minizip.html
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#include "mz.h"
#include "mz_crypt.h"
#include "mz_os.h"
#include "mz_strm.h"
#include "mz_strm_os.h"
#include <ctype.h> /* tolower */
/***************************************************************************/
int32_t mz_path_combine(char *path, const char *join, int32_t max_path)
{
int32_t path_len = 0;
if (path == NULL || join == NULL || max_path == 0)
return MZ_PARAM_ERROR;
path_len = (int32_t)strlen(path);
if (path_len == 0)
{
strncpy(path, join, max_path - 1);
path[max_path - 1] = 0;
}
else
{
mz_path_append_slash(path, max_path, MZ_PATH_SLASH_PLATFORM);
strncat(path, join, max_path - path_len);
}
return MZ_OK;
}
int32_t mz_path_append_slash(char *path, int32_t max_path, char slash)
{
int32_t path_len = (int32_t)strlen(path);
if ((path_len + 2) >= max_path)
return MZ_BUF_ERROR;
if (path[path_len - 1] != '\\' && path[path_len - 1] != '/')
{
path[path_len] = slash;
path[path_len + 1] = 0;
}
return MZ_OK;
}
int32_t mz_path_remove_slash(char *path)
{
int32_t path_len = (int32_t)strlen(path);
while (path_len > 0)
{
if (path[path_len - 1] == '\\' || path[path_len - 1] == '/')
path[path_len - 1] = 0;
else
break;
path_len -= 1;
}
return MZ_OK;
}
int32_t mz_path_has_slash(const char *path)
{
int32_t path_len = (int32_t)strlen(path);
if (path[path_len - 1] != '\\' && path[path_len - 1] != '/')
return MZ_EXIST_ERROR;
return MZ_OK;
}
int32_t mz_path_convert_slashes(char *path, char slash)
{
int32_t i = 0;
for (i = 0; i < (int32_t)strlen(path); i += 1)
{
if (path[i] == '\\' || path[i] == '/')
path[i] = slash;
}
return MZ_OK;
}
int32_t mz_path_compare_wc(const char *path, const char *wildcard, uint8_t ignore_case)
{
while (*path != 0)
{
switch (*wildcard)
{
case '*':
if (*(wildcard + 1) == 0)
return MZ_OK;
while (*path != 0)
{
if (mz_path_compare_wc(path, (wildcard + 1), ignore_case) == MZ_OK)
return MZ_OK;
path += 1;
}
return MZ_EXIST_ERROR;
default:
/* Ignore differences in path slashes on platforms */
if ((*path == '\\' && *wildcard == '/') || (*path == '/' && *wildcard == '\\'))
break;
if (ignore_case)
{
if (tolower(*path) != tolower(*wildcard))
return MZ_EXIST_ERROR;
}
else
{
if (*path != *wildcard)
return MZ_EXIST_ERROR;
}
break;
}
path += 1;
wildcard += 1;
}
if ((*wildcard != 0) && (*wildcard != '*'))
return MZ_EXIST_ERROR;
return MZ_OK;
}
int32_t mz_path_resolve(const char *path, char *output, int32_t max_output)
{
const char *source = path;
const char *check = output;
char *target = output;
if (max_output <= 0)
return MZ_PARAM_ERROR;
while (*source != 0 && max_output > 1)
{
check = source;
if ((*check == '\\') || (*check == '/'))
check += 1;
if ((source == path) || (target == output) || (check != source))
{
/* Skip double paths */
if ((*check == '\\') || (*check == '/'))
{
source += 1;
continue;
}
if ((*check != 0) && (*check == '.'))
{
check += 1;
/* Remove . if at end of string and not at the beginning */
if ((*check == 0) && (source != path && target != output))
{
/* Copy last slash */
*target = *source;
target += 1;
max_output -= 1;
source += (check - source);
continue;
}
/* Remove . if not at end of string */
else if ((*check == '\\') || (*check == '/'))
{
source += (check - source);
/* Skip slash if at beginning of string */
if (target == output && *source != 0)
source += 1;
continue;
}
/* Go to parent directory .. */
else if (*check == '.')
{
check += 1;
if ((*check == 0) || (*check == '\\' || *check == '/'))
{
source += (check - source);
/* Search backwards for previous slash */
if (target != output)
{
target -= 1;
do
{
if ((*target == '\\') || (*target == '/'))
break;
target -= 1;
max_output += 1;
}
while (target > output);
}
if ((target == output) && (*source != 0))
source += 1;
if ((*target == '\\' || *target == '/') && (*source == 0))
target += 1;
*target = 0;
continue;
}
}
}
}
*target = *source;
source += 1;
target += 1;
max_output -= 1;
}
*target = 0;
if (*path == 0)
return MZ_INTERNAL_ERROR;
return MZ_OK;
}
int32_t mz_path_remove_filename(char *path)
{
char *path_ptr = NULL;
if (path == NULL)
return MZ_PARAM_ERROR;
path_ptr = path + strlen(path) - 1;
while (path_ptr > path)
{
if ((*path_ptr == '/') || (*path_ptr == '\\'))
{
*path_ptr = 0;
break;
}
path_ptr -= 1;
}
if (path_ptr == path)
*path_ptr = 0;
return MZ_OK;
}
int32_t mz_path_remove_extension(char *path)
{
char *path_ptr = NULL;
if (path == NULL)
return MZ_PARAM_ERROR;
path_ptr = path + strlen(path) - 1;
while (path_ptr > path)
{
if ((*path_ptr == '/') || (*path_ptr == '\\'))
break;
if (*path_ptr == '.')
{
*path_ptr = 0;
break;
}
path_ptr -= 1;
}
if (path_ptr == path)
*path_ptr = 0;
return MZ_OK;
}
int32_t mz_path_get_filename(const char *path, const char **filename)
{
const char *match = NULL;
if (path == NULL || filename == NULL)
return MZ_PARAM_ERROR;
*filename = NULL;
for (match = path; *match != 0; match += 1)
{
if ((*match == '\\') || (*match == '/'))
*filename = match + 1;
}
if (*filename == NULL)
return MZ_EXIST_ERROR;
return MZ_OK;
}
int32_t mz_dir_make(const char *path)
{
int32_t err = MZ_OK;
int16_t len = 0;
char *current_dir = NULL;
char *match = NULL;
char hold = 0;
len = (int16_t)strlen(path);
if (len <= 0)
return 0;
current_dir = (char *)MZ_ALLOC((uint16_t)len + 1);
if (current_dir == NULL)
return MZ_MEM_ERROR;
strcpy(current_dir, path);
mz_path_remove_slash(current_dir);
err = mz_os_make_dir(current_dir);
if (err != MZ_OK)
{
match = current_dir + 1;
while (1)
{
while (*match != 0 && *match != '\\' && *match != '/')
match += 1;
hold = *match;
*match = 0;
err = mz_os_make_dir(current_dir);
if (err != MZ_OK)
break;
if (hold == 0)
break;
*match = hold;
match += 1;
}
}
MZ_FREE(current_dir);
return err;
}
int32_t mz_file_get_crc(const char *path, uint32_t *result_crc)
{
void *stream = NULL;
uint32_t crc32 = 0;
int32_t read = 0;
int32_t err = MZ_OK;
uint8_t buf[16384];
mz_stream_os_create(&stream);
err = mz_stream_os_open(stream, path, MZ_OPEN_MODE_READ);
if (err == MZ_OK)
{
do
{
read = mz_stream_os_read(stream, buf, sizeof(buf));
if (read < 0)
{
err = read;
break;
}
crc32 = mz_crypt_crc32_update(crc32, buf, read);
}
while ((err == MZ_OK) && (read > 0));
mz_stream_os_close(stream);
}
*result_crc = crc32;
mz_stream_os_delete(&stream);
return err;
}
/***************************************************************************/

View File

@ -0,0 +1,176 @@
/* mz_os.h -- System functions
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#ifndef MZ_OS_H
#define MZ_OS_H
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
#if defined(__APPLE__)
# define MZ_VERSION_MADEBY_HOST_SYSTEM (MZ_HOST_SYSTEM_OSX_DARWIN)
#elif defined(__riscos__)
# define MZ_VERSION_MADEBY_HOST_SYSTEM (MZ_HOST_SYSTEM_RISCOS)
#elif defined(__unix__)
# define MZ_VERSION_MADEBY_HOST_SYSTEM (MZ_HOST_SYSTEM_UNIX)
#elif defined(_WIN32)
# define MZ_VERSION_MADEBY_HOST_SYSTEM (MZ_HOST_SYSTEM_WINDOWS_NTFS)
#endif
#if defined(HAVE_LZMA)
# define MZ_VERSION_MADEBY_ZIP_VERSION (63)
#elif defined(HAVE_WZAES)
# define MZ_VERSION_MADEBY_ZIP_VERSION (51)
#elif defined(HAVE_BZIP2)
# define MZ_VERSION_MADEBY_ZIP_VERSION (46)
#else
# define MZ_VERSION_MADEBY_ZIP_VERSION (45)
#endif
#define MZ_VERSION_MADEBY ((MZ_VERSION_MADEBY_HOST_SYSTEM << 8) | \
(MZ_VERSION_MADEBY_ZIP_VERSION))
#define MZ_PATH_SLASH_UNIX ('/')
#if defined(_WIN32)
# define MZ_PATH_SLASH_PLATFORM ('\\')
#else
# define MZ_PATH_SLASH_PLATFORM (MZ_PATH_SLASH_UNIX)
#endif
/***************************************************************************/
#if defined(_WIN32)
struct dirent {
char d_name[256];
};
typedef void* DIR;
#else
#include <dirent.h>
#endif
/***************************************************************************/
/* Shared functions */
int32_t mz_path_combine(char *path, const char *join, int32_t max_path);
/* Combines two paths */
int32_t mz_path_append_slash(char *path, int32_t max_path, char slash);
/* Appends a path slash on to the end of the path */
int32_t mz_path_remove_slash(char *path);
/* Removes a path slash from the end of the path */
int32_t mz_path_has_slash(const char *path);
/* Returns whether or not the path ends with slash */
int32_t mz_path_convert_slashes(char *path, char slash);
/* Converts the slashes in a path */
int32_t mz_path_compare_wc(const char *path, const char *wildcard, uint8_t ignore_case);
/* Compare two paths with wildcard */
int32_t mz_path_resolve(const char *path, char *target, int32_t max_target);
/* Resolves path */
int32_t mz_path_remove_filename(char *path);
/* Remove the filename from a path */
int32_t mz_path_remove_extension(char *path);
/* Remove the extension from a path */
int32_t mz_path_get_filename(const char *path, const char **filename);
/* Get the filename from a path */
int32_t mz_dir_make(const char *path);
/* Creates a directory recursively */
int32_t mz_file_get_crc(const char *path, uint32_t *result_crc);
/* Gets the crc32 hash of a file */
/***************************************************************************/
/* Platform specific functions */
wchar_t *mz_os_unicode_string_create(const char *string, int32_t encoding);
/* Create unicode string from a utf8 string */
void mz_os_unicode_string_delete(wchar_t **string);
/* Delete a unicode string that was created */
uint8_t *mz_os_utf8_string_create(const char *string, int32_t encoding);
/* Create a utf8 string from a string with another encoding */
void mz_os_utf8_string_delete(uint8_t **string);
/* Delete a utf8 string that was created */
int32_t mz_os_rand(uint8_t *buf, int32_t size);
/* Random number generator (not cryptographically secure) */
int32_t mz_os_rename(const char *source_path, const char *target_path);
/* Rename a file */
int32_t mz_os_unlink(const char *path);
/* Delete an existing file */
int32_t mz_os_file_exists(const char *path);
/* Check to see if a file exists */
int64_t mz_os_get_file_size(const char *path);
/* Gets the length of a file */
int32_t mz_os_get_file_date(const char *path, time_t *modified_date, time_t *accessed_date, time_t *creation_date);
/* Gets a file's modified, access, and creation dates if supported */
int32_t mz_os_set_file_date(const char *path, time_t modified_date, time_t accessed_date, time_t creation_date);
/* Sets a file's modified, access, and creation dates if supported */
int32_t mz_os_get_file_attribs(const char *path, uint32_t *attributes);
/* Gets a file's attributes */
int32_t mz_os_set_file_attribs(const char *path, uint32_t attributes);
/* Sets a file's attributes */
int32_t mz_os_make_dir(const char *path);
/* Recursively creates a directory */
DIR* mz_os_open_dir(const char *path);
/* Opens a directory for listing */
struct
dirent* mz_os_read_dir(DIR *dir);
/* Reads a directory listing entry */
int32_t mz_os_close_dir(DIR *dir);
/* Closes a directory that has been opened for listing */
int32_t mz_os_is_dir(const char *path);
/* Checks to see if path is a directory */
int32_t mz_os_is_symlink(const char *path);
/* Checks to see if path is a symbolic link */
int32_t mz_os_make_symlink(const char *path, const char *target_path);
/* Creates a symbolic link pointing to a target */
int32_t mz_os_read_symlink(const char *path, char *target_path, int32_t max_target_path);
/* Gets the target path for a symbolic link */
uint64_t mz_os_ms_time(void);
/* Gets the time in milliseconds */
/***************************************************************************/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,329 @@
/* mz_os_posix.c -- System functions for posix
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#include "mz.h"
#include "mz_strm.h"
#include "mz_os.h"
#include <stdio.h> /* rename */
#include <errno.h>
#include <iconv.h>
#include <sys/types.h>
#include <sys/stat.h>
#if defined(__APPLE__) || defined(__unix__) || defined(__riscos__)
# include <utime.h>
# include <unistd.h>
#endif
#if defined(__APPLE__)
# include <mach/clock.h>
# include <mach/mach.h>
#endif
/***************************************************************************/
uint8_t *mz_os_utf8_string_create(const char *string, int32_t encoding)
{
iconv_t cd;
const char *from_encoding = NULL;
size_t result = 0;
size_t string_length = 0;
size_t string_utf8_size = 0;
uint8_t *string_utf8 = NULL;
uint8_t *string_utf8_ptr = NULL;
if (string == NULL)
return NULL;
if (encoding == MZ_ENCODING_CODEPAGE_437)
from_encoding = "CP437";
else if (encoding == MZ_ENCODING_CODEPAGE_932)
from_encoding = "CP932";
else if (encoding == MZ_ENCODING_CODEPAGE_936)
from_encoding = "CP936";
else if (encoding == MZ_ENCODING_CODEPAGE_950)
from_encoding = "CP950";
else if (encoding == MZ_ENCODING_UTF8)
from_encoding = "UTF-8";
else
return NULL;
cd = iconv_open("UTF-8", from_encoding);
if (cd == (iconv_t)-1)
return NULL;
string_length = strlen(string);
string_utf8_size = string_length * 2;
string_utf8 = (uint8_t *)MZ_ALLOC((int32_t)(string_utf8_size + 1));
string_utf8_ptr = string_utf8;
if (string_utf8)
{
memset(string_utf8, 0, string_utf8_size + 1);
result = iconv(cd, (char **)&string, &string_length,
(char **)&string_utf8_ptr, &string_utf8_size);
}
iconv_close(cd);
if (result == (size_t)-1)
{
MZ_FREE(string_utf8);
string_utf8 = NULL;
}
return string_utf8;
}
void mz_os_utf8_string_delete(uint8_t **string)
{
if (string != NULL)
{
MZ_FREE(*string);
*string = NULL;
}
}
/***************************************************************************/
int32_t mz_os_rand(uint8_t *buf, int32_t size)
{
static unsigned calls = 0;
int32_t i = 0;
/* Ensure different random header each time */
if (++calls == 1)
{
#define PI_SEED 3141592654UL
srand((unsigned)(time(NULL) ^ PI_SEED));
}
while (i < size)
buf[i++] = (rand() >> 7) & 0xff;
return size;
}
int32_t mz_os_rename(const char *source_path, const char *target_path)
{
if (rename(source_path, target_path) == -1)
return MZ_EXIST_ERROR;
return MZ_OK;
}
int32_t mz_os_unlink(const char *path)
{
if (unlink(path) == -1)
return MZ_EXIST_ERROR;
return MZ_OK;
}
int32_t mz_os_file_exists(const char *path)
{
struct stat path_stat;
memset(&path_stat, 0, sizeof(path_stat));
if (stat(path, &path_stat) == 0)
return MZ_OK;
return MZ_EXIST_ERROR;
}
int64_t mz_os_get_file_size(const char *path)
{
struct stat path_stat;
memset(&path_stat, 0, sizeof(path_stat));
if (stat(path, &path_stat) == 0)
{
/* Stat returns size taken up by directory entry, so return 0 */
if (S_ISDIR(path_stat.st_mode))
return 0;
return path_stat.st_size;
}
return 0;
}
int32_t mz_os_get_file_date(const char *path, time_t *modified_date, time_t *accessed_date, time_t *creation_date)
{
struct stat path_stat;
char *name = NULL;
size_t len = 0;
int32_t err = MZ_INTERNAL_ERROR;
memset(&path_stat, 0, sizeof(path_stat));
if (strcmp(path, "-") != 0)
{
/* Not all systems allow stat'ing a file with / appended */
len = strlen(path);
name = (char *)malloc(len + 1);
strncpy(name, path, len + 1);
mz_path_remove_slash(name);
if (stat(name, &path_stat) == 0)
{
if (modified_date != NULL)
*modified_date = path_stat.st_mtime;
if (accessed_date != NULL)
*accessed_date = path_stat.st_atime;
/* Creation date not supported */
if (creation_date != NULL)
*creation_date = 0;
err = MZ_OK;
}
free(name);
}
return err;
}
int32_t mz_os_set_file_date(const char *path, time_t modified_date, time_t accessed_date, time_t creation_date)
{
struct utimbuf ut;
ut.actime = accessed_date;
ut.modtime = modified_date;
/* Creation date not supported */
MZ_UNUSED(creation_date);
if (utime(path, &ut) != 0)
return MZ_INTERNAL_ERROR;
return MZ_OK;
}
int32_t mz_os_get_file_attribs(const char *path, uint32_t *attributes)
{
struct stat path_stat;
int32_t err = MZ_OK;
memset(&path_stat, 0, sizeof(path_stat));
if (lstat(path, &path_stat) == -1)
err = MZ_INTERNAL_ERROR;
*attributes = path_stat.st_mode;
return err;
}
int32_t mz_os_set_file_attribs(const char *path, uint32_t attributes)
{
int32_t err = MZ_OK;
if (chmod(path, (mode_t)attributes) == -1)
err = MZ_INTERNAL_ERROR;
return err;
}
int32_t mz_os_make_dir(const char *path)
{
int32_t err = 0;
err = mkdir(path, 0755);
if (err != 0 && errno != EEXIST)
return MZ_INTERNAL_ERROR;
return MZ_OK;
}
DIR* mz_os_open_dir(const char *path)
{
return opendir(path);
}
struct dirent* mz_os_read_dir(DIR *dir)
{
if (dir == NULL)
return NULL;
return readdir(dir);
}
int32_t mz_os_close_dir(DIR *dir)
{
if (dir == NULL)
return MZ_PARAM_ERROR;
if (closedir(dir) == -1)
return MZ_INTERNAL_ERROR;
return MZ_OK;
}
int32_t mz_os_is_dir(const char *path)
{
struct stat path_stat;
memset(&path_stat, 0, sizeof(path_stat));
stat(path, &path_stat);
if (S_ISDIR(path_stat.st_mode))
return MZ_OK;
return MZ_EXIST_ERROR;
}
int32_t mz_os_is_symlink(const char *path)
{
struct stat path_stat;
memset(&path_stat, 0, sizeof(path_stat));
lstat(path, &path_stat);
if (S_ISLNK(path_stat.st_mode))
return MZ_OK;
return MZ_EXIST_ERROR;
}
int32_t mz_os_make_symlink(const char *path, const char *target_path)
{
if (symlink(target_path, path) != 0)
return MZ_INTERNAL_ERROR;
return MZ_OK;
}
int32_t mz_os_read_symlink(const char *path, char *target_path, int32_t max_target_path)
{
size_t length = 0;
length = (size_t)readlink(path, target_path, max_target_path - 1);
if (length == (size_t)-1)
return MZ_EXIST_ERROR;
target_path[length] = 0;
return MZ_OK;
}
uint64_t mz_os_ms_time(void)
{
struct timespec ts;
#if defined(__APPLE__)
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
ts.tv_sec = mts.tv_sec;
ts.tv_nsec = mts.tv_nsec;
#else
clock_gettime(CLOCK_MONOTONIC, &ts);
#endif
return ((uint64_t)ts.tv_sec * 1000) + ((uint64_t)ts.tv_nsec / 1000000);
}

View File

@ -0,0 +1,623 @@
/* mz_strm.c -- Stream interface
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#include "mz.h"
#include "mz_strm.h"
/***************************************************************************/
#define MZ_STREAM_FIND_SIZE (1024)
/***************************************************************************/
int32_t mz_stream_open(void *stream, const char *path, int32_t mode)
{
mz_stream *strm = (mz_stream *)stream;
if (strm == NULL || strm->vtbl == NULL || strm->vtbl->open == NULL)
return MZ_STREAM_ERROR;
return strm->vtbl->open(strm, path, mode);
}
int32_t mz_stream_is_open(void *stream)
{
mz_stream *strm = (mz_stream *)stream;
if (strm == NULL || strm->vtbl == NULL || strm->vtbl->is_open == NULL)
return MZ_STREAM_ERROR;
return strm->vtbl->is_open(strm);
}
int32_t mz_stream_read(void *stream, void *buf, int32_t size)
{
mz_stream *strm = (mz_stream *)stream;
if (strm == NULL || strm->vtbl == NULL || strm->vtbl->read == NULL)
return MZ_PARAM_ERROR;
if (mz_stream_is_open(stream) != MZ_OK)
return MZ_STREAM_ERROR;
return strm->vtbl->read(strm, buf, size);
}
static int32_t mz_stream_read_value(void *stream, uint64_t *value, int32_t len)
{
uint8_t buf[8];
int32_t n = 0;
int32_t i = 0;
*value = 0;
if (mz_stream_read(stream, buf, len) == len)
{
for (n = 0; n < len; n += 1, i += 8)
*value += ((uint64_t)buf[n]) << i;
}
else if (mz_stream_error(stream))
return MZ_STREAM_ERROR;
else
return MZ_END_OF_STREAM;
return MZ_OK;
}
int32_t mz_stream_read_uint8(void *stream, uint8_t *value)
{
int32_t err = MZ_OK;
uint64_t value64 = 0;
*value = 0;
err = mz_stream_read_value(stream, &value64, sizeof(uint8_t));
if (err == MZ_OK)
*value = (uint8_t)value64;
return err;
}
int32_t mz_stream_read_uint16(void *stream, uint16_t *value)
{
int32_t err = MZ_OK;
uint64_t value64 = 0;
*value = 0;
err = mz_stream_read_value(stream, &value64, sizeof(uint16_t));
if (err == MZ_OK)
*value = (uint16_t)value64;
return err;
}
int32_t mz_stream_read_uint32(void *stream, uint32_t *value)
{
int32_t err = MZ_OK;
uint64_t value64 = 0;
*value = 0;
err = mz_stream_read_value(stream, &value64, sizeof(uint32_t));
if (err == MZ_OK)
*value = (uint32_t)value64;
return err;
}
int32_t mz_stream_read_int64(void *stream, int64_t *value)
{
return mz_stream_read_value(stream, (uint64_t *)value, sizeof(uint64_t));
}
int32_t mz_stream_read_uint64(void *stream, uint64_t *value)
{
return mz_stream_read_value(stream, value, sizeof(uint64_t));
}
int32_t mz_stream_write(void *stream, const void *buf, int32_t size)
{
mz_stream *strm = (mz_stream *)stream;
if (size == 0)
return size;
if (strm == NULL || strm->vtbl == NULL || strm->vtbl->write == NULL)
return MZ_PARAM_ERROR;
if (mz_stream_is_open(stream) != MZ_OK)
return MZ_STREAM_ERROR;
return strm->vtbl->write(strm, buf, size);
}
static int32_t mz_stream_write_value(void *stream, uint64_t value, int32_t len)
{
uint8_t buf[8];
int32_t n = 0;
for (n = 0; n < len; n += 1)
{
buf[n] = (uint8_t)(value & 0xff);
value >>= 8;
}
if (value != 0)
{
/* Data overflow - hack for ZIP64 (X Roche) */
for (n = 0; n < len; n += 1)
buf[n] = 0xff;
}
if (mz_stream_write(stream, buf, len) != len)
return MZ_STREAM_ERROR;
return MZ_OK;
}
int32_t mz_stream_write_uint8(void *stream, uint8_t value)
{
return mz_stream_write_value(stream, value, sizeof(uint8_t));
}
int32_t mz_stream_write_uint16(void *stream, uint16_t value)
{
return mz_stream_write_value(stream, value, sizeof(uint16_t));
}
int32_t mz_stream_write_uint32(void *stream, uint32_t value)
{
return mz_stream_write_value(stream, value, sizeof(uint32_t));
}
int32_t mz_stream_write_int64(void *stream, int64_t value)
{
return mz_stream_write_value(stream, (uint64_t)value, sizeof(uint64_t));
}
int32_t mz_stream_write_uint64(void *stream, uint64_t value)
{
return mz_stream_write_value(stream, value, sizeof(uint64_t));
}
int32_t mz_stream_copy(void *target, void *source, int32_t len)
{
return mz_stream_copy_stream(target, NULL, source, NULL, len);
}
int32_t mz_stream_copy_to_end(void *target, void *source)
{
return mz_stream_copy_stream_to_end(target, NULL, source, NULL);
}
int32_t mz_stream_copy_stream(void *target, mz_stream_write_cb write_cb, void *source,
mz_stream_read_cb read_cb, int32_t len)
{
uint8_t buf[16384];
int32_t bytes_to_copy = 0;
int32_t read = 0;
int32_t written = 0;
if (write_cb == NULL)
write_cb = mz_stream_write;
if (read_cb == NULL)
read_cb = mz_stream_read;
while (len > 0)
{
bytes_to_copy = len;
if (bytes_to_copy > (int32_t)sizeof(buf))
bytes_to_copy = sizeof(buf);
read = read_cb(source, buf, bytes_to_copy);
if (read <= 0)
return MZ_STREAM_ERROR;
written = write_cb(target, buf, read);
if (written != read)
return MZ_STREAM_ERROR;
len -= read;
}
return MZ_OK;
}
int32_t mz_stream_copy_stream_to_end(void *target, mz_stream_write_cb write_cb, void *source,
mz_stream_read_cb read_cb)
{
uint8_t buf[16384];
int32_t read = 0;
int32_t written = 0;
if (write_cb == NULL)
write_cb = mz_stream_write;
if (read_cb == NULL)
read_cb = mz_stream_read;
read = read_cb(source, buf, sizeof(buf));
while (read > 0)
{
written = write_cb(target, buf, read);
if (written != read)
return MZ_STREAM_ERROR;
read = read_cb(source, buf, sizeof(buf));
}
if (read < 0)
return MZ_STREAM_ERROR;
return MZ_OK;
}
int64_t mz_stream_tell(void *stream)
{
mz_stream *strm = (mz_stream *)stream;
if (strm == NULL || strm->vtbl == NULL || strm->vtbl->tell == NULL)
return MZ_PARAM_ERROR;
if (mz_stream_is_open(stream) != MZ_OK)
return MZ_STREAM_ERROR;
return strm->vtbl->tell(strm);
}
int32_t mz_stream_seek(void *stream, int64_t offset, int32_t origin)
{
mz_stream *strm = (mz_stream *)stream;
if (strm == NULL || strm->vtbl == NULL || strm->vtbl->seek == NULL)
return MZ_PARAM_ERROR;
if (mz_stream_is_open(stream) != MZ_OK)
return MZ_STREAM_ERROR;
if (origin == MZ_SEEK_SET && offset < 0)
return MZ_SEEK_ERROR;
return strm->vtbl->seek(strm, offset, origin);
}
int32_t mz_stream_find(void *stream, const void *find, int32_t find_size, int64_t max_seek, int64_t *position)
{
uint8_t buf[MZ_STREAM_FIND_SIZE];
int32_t buf_pos = 0;
int32_t read_size = sizeof(buf);
int32_t read = 0;
int64_t read_pos = 0;
int64_t start_pos = 0;
int64_t disk_pos = 0;
int32_t i = 0;
uint8_t first = 1;
int32_t err = MZ_OK;
if (stream == NULL || find == NULL || position == NULL)
return MZ_PARAM_ERROR;
if (find_size < 0 || find_size >= (int32_t)sizeof(buf))
return MZ_PARAM_ERROR;
*position = -1;
start_pos = mz_stream_tell(stream);
while (read_pos < max_seek)
{
if (read_size > (int32_t)(max_seek - read_pos - buf_pos) && (max_seek - read_pos - buf_pos) < (int64_t)sizeof(buf))
read_size = (int32_t)(max_seek - read_pos - buf_pos);
read = mz_stream_read(stream, buf + buf_pos, read_size);
if ((read <= 0) || (read + buf_pos < find_size))
break;
for (i = 0; i <= read + buf_pos - find_size; i += 1)
{
if (memcmp(&buf[i], find, find_size) != 0)
continue;
disk_pos = mz_stream_tell(stream);
/* Seek to position on disk where the data was found */
err = mz_stream_seek(stream, disk_pos - ((int64_t)read + buf_pos - i), MZ_SEEK_SET);
if (err != MZ_OK)
return MZ_EXIST_ERROR;
*position = start_pos + read_pos + i;
return MZ_OK;
}
if (first)
{
read -= find_size;
read_size -= find_size;
buf_pos = find_size;
first = 0;
}
memmove(buf, buf + read, find_size);
read_pos += read;
}
return MZ_EXIST_ERROR;
}
int32_t mz_stream_find_reverse(void *stream, const void *find, int32_t find_size, int64_t max_seek, int64_t *position)
{
uint8_t buf[MZ_STREAM_FIND_SIZE];
int32_t buf_pos = 0;
int32_t read_size = MZ_STREAM_FIND_SIZE;
int64_t read_pos = 0;
int32_t read = 0;
int64_t start_pos = 0;
int64_t disk_pos = 0;
uint8_t first = 1;
int32_t i = 0;
int32_t err = MZ_OK;
if (stream == NULL || find == NULL || position == NULL)
return MZ_PARAM_ERROR;
if (find_size < 0 || find_size >= (int32_t)sizeof(buf))
return MZ_PARAM_ERROR;
*position = -1;
start_pos = mz_stream_tell(stream);
while (read_pos < max_seek)
{
if (read_size > (int32_t)(max_seek - read_pos) && (max_seek - read_pos) < (int64_t)sizeof(buf))
read_size = (int32_t)(max_seek - read_pos);
if (mz_stream_seek(stream, start_pos - (read_pos + read_size), MZ_SEEK_SET) != MZ_OK)
break;
read = mz_stream_read(stream, buf, read_size);
if ((read <= 0) || (read + buf_pos < find_size))
break;
if (read + buf_pos < MZ_STREAM_FIND_SIZE)
memmove(buf + MZ_STREAM_FIND_SIZE - (read + buf_pos), buf, read);
for (i = find_size; i <= (read + buf_pos); i += 1)
{
if (memcmp(&buf[MZ_STREAM_FIND_SIZE - i], find, find_size) != 0)
continue;
disk_pos = mz_stream_tell(stream);
/* Seek to position on disk where the data was found */
err = mz_stream_seek(stream, disk_pos + buf_pos - i, MZ_SEEK_SET);
if (err != MZ_OK)
return MZ_EXIST_ERROR;
*position = start_pos - (read_pos - buf_pos + i);
return MZ_OK;
}
if (first)
{
read -= find_size;
read_size -= find_size;
buf_pos = find_size;
first = 0;
}
if (read == 0)
break;
memmove(buf + read_size, buf, find_size);
read_pos += read;
}
return MZ_EXIST_ERROR;
}
int32_t mz_stream_close(void *stream)
{
mz_stream *strm = (mz_stream *)stream;
if (strm == NULL || strm->vtbl == NULL || strm->vtbl->close == NULL)
return MZ_PARAM_ERROR;
if (mz_stream_is_open(stream) != MZ_OK)
return MZ_STREAM_ERROR;
return strm->vtbl->close(strm);
}
int32_t mz_stream_error(void *stream)
{
mz_stream *strm = (mz_stream *)stream;
if (strm == NULL || strm->vtbl == NULL || strm->vtbl->error == NULL)
return MZ_PARAM_ERROR;
return strm->vtbl->error(strm);
}
int32_t mz_stream_set_base(void *stream, void *base)
{
mz_stream *strm = (mz_stream *)stream;
strm->base = (mz_stream *)base;
return MZ_OK;
}
void* mz_stream_get_interface(void *stream)
{
mz_stream *strm = (mz_stream *)stream;
if (strm == NULL || strm->vtbl == NULL)
return NULL;
return (void *)strm->vtbl;
}
int32_t mz_stream_get_prop_int64(void *stream, int32_t prop, int64_t *value)
{
mz_stream *strm = (mz_stream *)stream;
if (strm == NULL || strm->vtbl == NULL || strm->vtbl->get_prop_int64 == NULL)
return MZ_PARAM_ERROR;
return strm->vtbl->get_prop_int64(stream, prop, value);
}
int32_t mz_stream_set_prop_int64(void *stream, int32_t prop, int64_t value)
{
mz_stream *strm = (mz_stream *)stream;
if (strm == NULL || strm->vtbl == NULL || strm->vtbl->set_prop_int64 == NULL)
return MZ_PARAM_ERROR;
return strm->vtbl->set_prop_int64(stream, prop, value);
}
void *mz_stream_create(void **stream, mz_stream_vtbl *vtbl)
{
if (stream == NULL)
return NULL;
if (vtbl == NULL || vtbl->create == NULL)
return NULL;
return vtbl->create(stream);
}
void mz_stream_delete(void **stream)
{
mz_stream *strm = NULL;
if (stream == NULL)
return;
strm = (mz_stream *)*stream;
if (strm != NULL && strm->vtbl != NULL && strm->vtbl->destroy != NULL)
strm->vtbl->destroy(stream);
*stream = NULL;
}
/***************************************************************************/
typedef struct mz_stream_raw_s {
mz_stream stream;
int64_t total_in;
int64_t total_out;
int64_t max_total_in;
} mz_stream_raw;
/***************************************************************************/
int32_t mz_stream_raw_open(void *stream, const char *path, int32_t mode)
{
MZ_UNUSED(stream);
MZ_UNUSED(path);
MZ_UNUSED(mode);
return MZ_OK;
}
int32_t mz_stream_raw_is_open(void *stream)
{
mz_stream_raw *raw = (mz_stream_raw *)stream;
return mz_stream_is_open(raw->stream.base);
}
int32_t mz_stream_raw_read(void *stream, void *buf, int32_t size)
{
mz_stream_raw *raw = (mz_stream_raw *)stream;
int32_t bytes_to_read = size;
int32_t read = 0;
if (raw->max_total_in > 0)
{
if ((int64_t)bytes_to_read > (raw->max_total_in - raw->total_in))
bytes_to_read = (int32_t)(raw->max_total_in - raw->total_in);
}
read = mz_stream_read(raw->stream.base, buf, bytes_to_read);
if (read > 0)
{
raw->total_in += read;
raw->total_out += read;
}
return read;
}
int32_t mz_stream_raw_write(void *stream, const void *buf, int32_t size)
{
mz_stream_raw *raw = (mz_stream_raw *)stream;
int32_t written = 0;
written = mz_stream_write(raw->stream.base, buf, size);
if (written > 0)
{
raw->total_out += written;
raw->total_in += written;
}
return written;
}
int64_t mz_stream_raw_tell(void *stream)
{
mz_stream_raw *raw = (mz_stream_raw *)stream;
return mz_stream_tell(raw->stream.base);
}
int32_t mz_stream_raw_seek(void *stream, int64_t offset, int32_t origin)
{
mz_stream_raw *raw = (mz_stream_raw *)stream;
return mz_stream_seek(raw->stream.base, offset, origin);
}
int32_t mz_stream_raw_close(void *stream)
{
MZ_UNUSED(stream);
return MZ_OK;
}
int32_t mz_stream_raw_error(void *stream)
{
mz_stream_raw *raw = (mz_stream_raw *)stream;
return mz_stream_error(raw->stream.base);
}
int32_t mz_stream_raw_get_prop_int64(void *stream, int32_t prop, int64_t *value)
{
mz_stream_raw *raw = (mz_stream_raw *)stream;
switch (prop)
{
case MZ_STREAM_PROP_TOTAL_IN:
*value = raw->total_in;
return MZ_OK;
case MZ_STREAM_PROP_TOTAL_OUT:
*value = raw->total_out;
return MZ_OK;
}
return MZ_EXIST_ERROR;
}
int32_t mz_stream_raw_set_prop_int64(void *stream, int32_t prop, int64_t value)
{
mz_stream_raw *raw = (mz_stream_raw *)stream;
switch (prop)
{
case MZ_STREAM_PROP_TOTAL_IN_MAX:
raw->max_total_in = value;
return MZ_OK;
}
return MZ_EXIST_ERROR;
}
/***************************************************************************/
static mz_stream_vtbl mz_stream_raw_vtbl = {
mz_stream_raw_open,
mz_stream_raw_is_open,
mz_stream_raw_read,
mz_stream_raw_write,
mz_stream_raw_tell,
mz_stream_raw_seek,
mz_stream_raw_close,
mz_stream_raw_error,
mz_stream_raw_create,
mz_stream_raw_delete,
mz_stream_raw_get_prop_int64,
mz_stream_raw_set_prop_int64
};
/***************************************************************************/
void *mz_stream_raw_create(void **stream)
{
mz_stream_raw *raw = NULL;
raw = (mz_stream_raw *)MZ_ALLOC(sizeof(mz_stream_raw));
if (raw != NULL)
{
memset(raw, 0, sizeof(mz_stream_raw));
raw->stream.vtbl = &mz_stream_raw_vtbl;
}
if (stream != NULL)
*stream = raw;
return raw;
}
void mz_stream_raw_delete(void **stream)
{
mz_stream_raw *raw = NULL;
if (stream == NULL)
return;
raw = (mz_stream_raw *)*stream;
if (raw != NULL)
MZ_FREE(raw);
*stream = NULL;
}

View File

@ -0,0 +1,134 @@
/* mz_strm.h -- Stream interface
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#ifndef MZ_STREAM_H
#define MZ_STREAM_H
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
#define MZ_STREAM_PROP_TOTAL_IN (1)
#define MZ_STREAM_PROP_TOTAL_IN_MAX (2)
#define MZ_STREAM_PROP_TOTAL_OUT (3)
#define MZ_STREAM_PROP_TOTAL_OUT_MAX (4)
#define MZ_STREAM_PROP_HEADER_SIZE (5)
#define MZ_STREAM_PROP_FOOTER_SIZE (6)
#define MZ_STREAM_PROP_DISK_SIZE (7)
#define MZ_STREAM_PROP_DISK_NUMBER (8)
#define MZ_STREAM_PROP_COMPRESS_LEVEL (9)
#define MZ_STREAM_PROP_COMPRESS_ALGORITHM (10)
#define MZ_STREAM_PROP_COMPRESS_WINDOW (11)
/***************************************************************************/
typedef int32_t (*mz_stream_open_cb) (void *stream, const char *path, int32_t mode);
typedef int32_t (*mz_stream_is_open_cb) (void *stream);
typedef int32_t (*mz_stream_read_cb) (void *stream, void *buf, int32_t size);
typedef int32_t (*mz_stream_write_cb) (void *stream, const void *buf, int32_t size);
typedef int64_t (*mz_stream_tell_cb) (void *stream);
typedef int32_t (*mz_stream_seek_cb) (void *stream, int64_t offset, int32_t origin);
typedef int32_t (*mz_stream_close_cb) (void *stream);
typedef int32_t (*mz_stream_error_cb) (void *stream);
typedef void* (*mz_stream_create_cb) (void **stream);
typedef void (*mz_stream_destroy_cb) (void **stream);
typedef int32_t (*mz_stream_get_prop_int64_cb) (void *stream, int32_t prop, int64_t *value);
typedef int32_t (*mz_stream_set_prop_int64_cb) (void *stream, int32_t prop, int64_t value);
typedef int32_t (*mz_stream_find_cb) (void *stream, const void *find, int32_t find_size,
int64_t max_seek, int64_t *position);
/***************************************************************************/
typedef struct mz_stream_vtbl_s
{
mz_stream_open_cb open;
mz_stream_is_open_cb is_open;
mz_stream_read_cb read;
mz_stream_write_cb write;
mz_stream_tell_cb tell;
mz_stream_seek_cb seek;
mz_stream_close_cb close;
mz_stream_error_cb error;
mz_stream_create_cb create;
mz_stream_destroy_cb destroy;
mz_stream_get_prop_int64_cb get_prop_int64;
mz_stream_set_prop_int64_cb set_prop_int64;
} mz_stream_vtbl;
typedef struct mz_stream_s {
mz_stream_vtbl *vtbl;
struct mz_stream_s *base;
} mz_stream;
/***************************************************************************/
int32_t mz_stream_open(void *stream, const char *path, int32_t mode);
int32_t mz_stream_is_open(void *stream);
int32_t mz_stream_read(void *stream, void *buf, int32_t size);
int32_t mz_stream_read_uint8(void *stream, uint8_t *value);
int32_t mz_stream_read_uint16(void *stream, uint16_t *value);
int32_t mz_stream_read_uint32(void *stream, uint32_t *value);
int32_t mz_stream_read_int64(void *stream, int64_t *value);
int32_t mz_stream_read_uint64(void *stream, uint64_t *value);
int32_t mz_stream_write(void *stream, const void *buf, int32_t size);
int32_t mz_stream_write_uint8(void *stream, uint8_t value);
int32_t mz_stream_write_uint16(void *stream, uint16_t value);
int32_t mz_stream_write_uint32(void *stream, uint32_t value);
int32_t mz_stream_write_int64(void *stream, int64_t value);
int32_t mz_stream_write_uint64(void *stream, uint64_t value);
int32_t mz_stream_copy(void *target, void *source, int32_t len);
int32_t mz_stream_copy_to_end(void *target, void *source);
int32_t mz_stream_copy_stream(void *target, mz_stream_write_cb write_cb, void *source, mz_stream_read_cb read_cb, int32_t len);
int32_t mz_stream_copy_stream_to_end(void *target, mz_stream_write_cb write_cb, void *source, mz_stream_read_cb read_cb);
int64_t mz_stream_tell(void *stream);
int32_t mz_stream_seek(void *stream, int64_t offset, int32_t origin);
int32_t mz_stream_find(void *stream, const void *find, int32_t find_size, int64_t max_seek, int64_t *position);
int32_t mz_stream_find_reverse(void *stream, const void *find, int32_t find_size, int64_t max_seek, int64_t *position);
int32_t mz_stream_close(void *stream);
int32_t mz_stream_error(void *stream);
int32_t mz_stream_set_base(void *stream, void *base);
void* mz_stream_get_interface(void *stream);
int32_t mz_stream_get_prop_int64(void *stream, int32_t prop, int64_t *value);
int32_t mz_stream_set_prop_int64(void *stream, int32_t prop, int64_t value);
void* mz_stream_create(void **stream, mz_stream_vtbl *vtbl);
void mz_stream_delete(void **stream);
/***************************************************************************/
int32_t mz_stream_raw_open(void *stream, const char *filename, int32_t mode);
int32_t mz_stream_raw_is_open(void *stream);
int32_t mz_stream_raw_read(void *stream, void *buf, int32_t size);
int32_t mz_stream_raw_write(void *stream, const void *buf, int32_t size);
int64_t mz_stream_raw_tell(void *stream);
int32_t mz_stream_raw_seek(void *stream, int64_t offset, int32_t origin);
int32_t mz_stream_raw_close(void *stream);
int32_t mz_stream_raw_error(void *stream);
int32_t mz_stream_raw_get_prop_int64(void *stream, int32_t prop, int64_t *value);
int32_t mz_stream_raw_set_prop_int64(void *stream, int32_t prop, int64_t value);
void* mz_stream_raw_create(void **stream);
void mz_stream_raw_delete(void **stream);
/***************************************************************************/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,416 @@
/* mz_strm_buf.c -- Stream for buffering reads/writes
Version 2.9.2, February 12, 2020
part of the MiniZip project
This version of ioapi is designed to buffer IO.
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#include "mz.h"
#include "mz_strm.h"
#include "mz_strm_buf.h"
/***************************************************************************/
static mz_stream_vtbl mz_stream_buffered_vtbl = {
mz_stream_buffered_open,
mz_stream_buffered_is_open,
mz_stream_buffered_read,
mz_stream_buffered_write,
mz_stream_buffered_tell,
mz_stream_buffered_seek,
mz_stream_buffered_close,
mz_stream_buffered_error,
mz_stream_buffered_create,
mz_stream_buffered_delete,
NULL,
NULL
};
/***************************************************************************/
typedef struct mz_stream_buffered_s {
mz_stream stream;
int32_t error;
char readbuf[INT16_MAX];
int32_t readbuf_len;
int32_t readbuf_pos;
int32_t readbuf_hits;
int32_t readbuf_misses;
char writebuf[INT16_MAX];
int32_t writebuf_len;
int32_t writebuf_pos;
int32_t writebuf_hits;
int32_t writebuf_misses;
int64_t position;
} mz_stream_buffered;
/***************************************************************************/
#if 0
# define mz_stream_buffered_print printf
#else
# define mz_stream_buffered_print(fmt,...)
#endif
/***************************************************************************/
static int32_t mz_stream_buffered_reset(void *stream)
{
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
buffered->readbuf_len = 0;
buffered->readbuf_pos = 0;
buffered->writebuf_len = 0;
buffered->writebuf_pos = 0;
buffered->position = 0;
return MZ_OK;
}
int32_t mz_stream_buffered_open(void *stream, const char *path, int32_t mode)
{
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
mz_stream_buffered_print("Buffered - Open (mode %" PRId32 ")\n", mode);
mz_stream_buffered_reset(buffered);
return mz_stream_open(buffered->stream.base, path, mode);
}
int32_t mz_stream_buffered_is_open(void *stream)
{
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
return mz_stream_is_open(buffered->stream.base);
}
static int32_t mz_stream_buffered_flush(void *stream, int32_t *written)
{
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
int32_t total_bytes_written = 0;
int32_t bytes_to_write = buffered->writebuf_len;
int32_t bytes_left_to_write = buffered->writebuf_len;
int32_t bytes_written = 0;
*written = 0;
while (bytes_left_to_write > 0)
{
bytes_written = mz_stream_write(buffered->stream.base,
buffered->writebuf + (bytes_to_write - bytes_left_to_write), bytes_left_to_write);
if (bytes_written != bytes_left_to_write)
return MZ_WRITE_ERROR;
buffered->writebuf_misses += 1;
mz_stream_buffered_print("Buffered - Write flush (%" PRId32 ":%" PRId32 " len %" PRId32 ")\n",
bytes_to_write, bytes_left_to_write, buffered->writebuf_len);
total_bytes_written += bytes_written;
bytes_left_to_write -= bytes_written;
buffered->position += bytes_written;
}
buffered->writebuf_len = 0;
buffered->writebuf_pos = 0;
*written = total_bytes_written;
return MZ_OK;
}
int32_t mz_stream_buffered_read(void *stream, void *buf, int32_t size)
{
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
int32_t buf_len = 0;
int32_t bytes_to_read = 0;
int32_t bytes_to_copy = 0;
int32_t bytes_left_to_read = size;
int32_t bytes_read = 0;
mz_stream_buffered_print("Buffered - Read (size %" PRId32 " pos %" PRId64 ")\n", size, buffered->position);
if (buffered->writebuf_len > 0)
{
mz_stream_buffered_print("Buffered - Switch from write to read, not yet supported (pos %" PRId64 ")\n",
buffered->position);
}
while (bytes_left_to_read > 0)
{
if ((buffered->readbuf_len == 0) || (buffered->readbuf_pos == buffered->readbuf_len))
{
if (buffered->readbuf_len == sizeof(buffered->readbuf))
{
buffered->readbuf_pos = 0;
buffered->readbuf_len = 0;
}
bytes_to_read = (int32_t)sizeof(buffered->readbuf) - (buffered->readbuf_len - buffered->readbuf_pos);
bytes_read = mz_stream_read(buffered->stream.base, buffered->readbuf + buffered->readbuf_pos, bytes_to_read);
if (bytes_read < 0)
return bytes_read;
buffered->readbuf_misses += 1;
buffered->readbuf_len += bytes_read;
buffered->position += bytes_read;
mz_stream_buffered_print("Buffered - Filled (read %" PRId32 "/%" PRId32 " buf %" PRId32 ":%" PRId32 " pos %" PRId64 ")\n",
bytes_read, bytes_to_read, buffered->readbuf_pos, buffered->readbuf_len, buffered->position);
if (bytes_read == 0)
break;
}
if ((buffered->readbuf_len - buffered->readbuf_pos) > 0)
{
bytes_to_copy = buffered->readbuf_len - buffered->readbuf_pos;
if (bytes_to_copy > bytes_left_to_read)
bytes_to_copy = bytes_left_to_read;
memcpy((char *)buf + buf_len, buffered->readbuf + buffered->readbuf_pos, bytes_to_copy);
buf_len += bytes_to_copy;
bytes_left_to_read -= bytes_to_copy;
buffered->readbuf_hits += 1;
buffered->readbuf_pos += bytes_to_copy;
mz_stream_buffered_print("Buffered - Emptied (copied %" PRId32 " remaining %" PRId32 " buf %" PRId32 ":%" PRId32 " pos %" PRId64 ")\n",
bytes_to_copy, bytes_left_to_read, buffered->readbuf_pos, buffered->readbuf_len, buffered->position);
}
}
return size - bytes_left_to_read;
}
int32_t mz_stream_buffered_write(void *stream, const void *buf, int32_t size)
{
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
int32_t bytes_to_write = size;
int32_t bytes_left_to_write = size;
int32_t bytes_to_copy = 0;
int32_t bytes_used = 0;
int32_t bytes_flushed = 0;
int32_t err = MZ_OK;
mz_stream_buffered_print("Buffered - Write (size %" PRId32 " len %" PRId32 " pos %" PRId64 ")\n",
size, buffered->writebuf_len, buffered->position);
if (buffered->readbuf_len > 0)
{
buffered->position -= buffered->readbuf_len;
buffered->position += buffered->readbuf_pos;
buffered->readbuf_len = 0;
buffered->readbuf_pos = 0;
mz_stream_buffered_print("Buffered - Switch from read to write (pos %" PRId64 ")\n", buffered->position);
err = mz_stream_seek(buffered->stream.base, buffered->position, MZ_SEEK_SET);
if (err != MZ_OK)
return err;
}
while (bytes_left_to_write > 0)
{
bytes_used = buffered->writebuf_len;
if (bytes_used > buffered->writebuf_pos)
bytes_used = buffered->writebuf_pos;
bytes_to_copy = (int32_t)sizeof(buffered->writebuf) - bytes_used;
if (bytes_to_copy > bytes_left_to_write)
bytes_to_copy = bytes_left_to_write;
if (bytes_to_copy == 0)
{
err = mz_stream_buffered_flush(stream, &bytes_flushed);
if (err != MZ_OK)
return err;
if (bytes_flushed == 0)
return 0;
continue;
}
memcpy(buffered->writebuf + buffered->writebuf_pos,
(const char *)buf + (bytes_to_write - bytes_left_to_write), bytes_to_copy);
mz_stream_buffered_print("Buffered - Write copy (remaining %" PRId32 " write %" PRId32 ":%" PRId32 " len %" PRId32 ")\n",
bytes_to_copy, bytes_to_write, bytes_left_to_write, buffered->writebuf_len);
bytes_left_to_write -= bytes_to_copy;
buffered->writebuf_pos += bytes_to_copy;
buffered->writebuf_hits += 1;
if (buffered->writebuf_pos > buffered->writebuf_len)
buffered->writebuf_len += buffered->writebuf_pos - buffered->writebuf_len;
}
return size - bytes_left_to_write;
}
int64_t mz_stream_buffered_tell(void *stream)
{
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
int64_t position = mz_stream_tell(buffered->stream.base);
buffered->position = position;
mz_stream_buffered_print("Buffered - Tell (pos %" PRId64 " readpos %" PRId32 " writepos %" PRId32 ")\n",
buffered->position, buffered->readbuf_pos, buffered->writebuf_pos);
if (buffered->readbuf_len > 0)
position -= ((int64_t)buffered->readbuf_len - buffered->readbuf_pos);
if (buffered->writebuf_len > 0)
position += buffered->writebuf_pos;
return position;
}
int32_t mz_stream_buffered_seek(void *stream, int64_t offset, int32_t origin)
{
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
int32_t bytes_flushed = 0;
int32_t err = MZ_OK;
mz_stream_buffered_print("Buffered - Seek (origin %" PRId32 " offset %" PRId64 " pos %" PRId64 ")\n",
origin, offset, buffered->position);
switch (origin)
{
case MZ_SEEK_SET:
if (buffered->writebuf_len > 0)
{
if ((offset >= buffered->position) && (offset <= buffered->position + buffered->writebuf_len))
{
buffered->writebuf_pos = (int32_t)(offset - buffered->position);
return MZ_OK;
}
}
if ((buffered->readbuf_len > 0) && (offset < buffered->position) &&
(offset >= buffered->position - buffered->readbuf_len))
{
buffered->readbuf_pos = (int32_t)(offset - (buffered->position - buffered->readbuf_len));
return MZ_OK;
}
err = mz_stream_buffered_flush(stream, &bytes_flushed);
if (err != MZ_OK)
return err;
buffered->position = offset;
break;
case MZ_SEEK_CUR:
if (buffered->readbuf_len > 0)
{
if (offset <= ((int64_t)buffered->readbuf_len - buffered->readbuf_pos))
{
buffered->readbuf_pos += (uint32_t)offset;
return MZ_OK;
}
offset -= ((int64_t)buffered->readbuf_len - buffered->readbuf_pos);
buffered->position += offset;
}
if (buffered->writebuf_len > 0)
{
if (offset <= ((int64_t)buffered->writebuf_len - buffered->writebuf_pos))
{
buffered->writebuf_pos += (uint32_t)offset;
return MZ_OK;
}
/* offset -= (buffered->writebuf_len - buffered->writebuf_pos); */
}
err = mz_stream_buffered_flush(stream, &bytes_flushed);
if (err != MZ_OK)
return err;
break;
case MZ_SEEK_END:
if (buffered->writebuf_len > 0)
{
buffered->writebuf_pos = buffered->writebuf_len;
return MZ_OK;
}
break;
}
buffered->readbuf_len = 0;
buffered->readbuf_pos = 0;
buffered->writebuf_len = 0;
buffered->writebuf_pos = 0;
return mz_stream_seek(buffered->stream.base, offset, origin);
}
int32_t mz_stream_buffered_close(void *stream)
{
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
int32_t bytes_flushed = 0;
mz_stream_buffered_flush(stream, &bytes_flushed);
mz_stream_buffered_print("Buffered - Close (flushed %" PRId32 ")\n", bytes_flushed);
if (buffered->readbuf_hits + buffered->readbuf_misses > 0)
{
mz_stream_buffered_print("Buffered - Read efficiency %.02f%%\n",
(buffered->readbuf_hits / ((float)buffered->readbuf_hits + buffered->readbuf_misses)) * 100);
}
if (buffered->writebuf_hits + buffered->writebuf_misses > 0)
{
mz_stream_buffered_print("Buffered - Write efficiency %.02f%%\n",
(buffered->writebuf_hits / ((float)buffered->writebuf_hits + buffered->writebuf_misses)) * 100);
}
mz_stream_buffered_reset(buffered);
return mz_stream_close(buffered->stream.base);
}
int32_t mz_stream_buffered_error(void *stream)
{
mz_stream_buffered *buffered = (mz_stream_buffered *)stream;
return mz_stream_error(buffered->stream.base);
}
void *mz_stream_buffered_create(void **stream)
{
mz_stream_buffered *buffered = NULL;
buffered = (mz_stream_buffered *)MZ_ALLOC(sizeof(mz_stream_buffered));
if (buffered != NULL)
{
memset(buffered, 0, sizeof(mz_stream_buffered));
buffered->stream.vtbl = &mz_stream_buffered_vtbl;
}
if (stream != NULL)
*stream = buffered;
return buffered;
}
void mz_stream_buffered_delete(void **stream)
{
mz_stream_buffered *buffered = NULL;
if (stream == NULL)
return;
buffered = (mz_stream_buffered *)*stream;
if (buffered != NULL)
MZ_FREE(buffered);
*stream = NULL;
}
void *mz_stream_buffered_get_interface(void)
{
return (void *)&mz_stream_buffered_vtbl;
}

View File

@ -0,0 +1,43 @@
/* mz_strm_buf.h -- Stream for buffering reads/writes
Version 2.9.2, February 12, 2020
part of the MiniZip project
This version of ioapi is designed to buffer IO.
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#ifndef MZ_STREAM_BUFFERED_H
#define MZ_STREAM_BUFFERED_H
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
int32_t mz_stream_buffered_open(void *stream, const char *path, int32_t mode);
int32_t mz_stream_buffered_is_open(void *stream);
int32_t mz_stream_buffered_read(void *stream, void *buf, int32_t size);
int32_t mz_stream_buffered_write(void *stream, const void *buf, int32_t size);
int64_t mz_stream_buffered_tell(void *stream);
int32_t mz_stream_buffered_seek(void *stream, int64_t offset, int32_t origin);
int32_t mz_stream_buffered_close(void *stream);
int32_t mz_stream_buffered_error(void *stream);
void* mz_stream_buffered_create(void **stream);
void mz_stream_buffered_delete(void **stream);
void* mz_stream_buffered_get_interface(void);
/***************************************************************************/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,303 @@
/* mz_strm_mem.c -- Stream for memory access
Version 2.9.2, February 12, 2020
part of the MiniZip project
This interface is designed to access memory rather than files.
We do use a region of memory to put data in to and take it out of.
Based on Unzip ioapi.c version 0.22, May 19th, 2003
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
Copyright (C) 2003 Justin Fletcher
Copyright (C) 1998-2003 Gilles Vollant
https://www.winimage.com/zLibDll/minizip.html
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#include "mz.h"
#include "mz_strm.h"
#include "mz_strm_mem.h"
/***************************************************************************/
static mz_stream_vtbl mz_stream_mem_vtbl = {
mz_stream_mem_open,
mz_stream_mem_is_open,
mz_stream_mem_read,
mz_stream_mem_write,
mz_stream_mem_tell,
mz_stream_mem_seek,
mz_stream_mem_close,
mz_stream_mem_error,
mz_stream_mem_create,
mz_stream_mem_delete,
NULL,
NULL
};
/***************************************************************************/
typedef struct mz_stream_mem_s {
mz_stream stream;
int32_t mode;
uint8_t *buffer; /* Memory buffer pointer */
int32_t size; /* Size of the memory buffer */
int32_t limit; /* Furthest we've written */
int32_t position; /* Current position in the memory */
int32_t grow_size; /* Size to grow when full */
} mz_stream_mem;
/***************************************************************************/
static int32_t mz_stream_mem_set_size(void *stream, int32_t size)
{
mz_stream_mem *mem = (mz_stream_mem *)stream;
int32_t new_size = size;
uint8_t *new_buf = NULL;
new_buf = (uint8_t *)MZ_ALLOC((uint32_t)new_size);
if (new_buf == NULL)
return MZ_BUF_ERROR;
if (mem->buffer)
{
memcpy(new_buf, mem->buffer, mem->size);
MZ_FREE(mem->buffer);
}
mem->buffer = new_buf;
mem->size = new_size;
return MZ_OK;
}
int32_t mz_stream_mem_open(void *stream, const char *path, int32_t mode)
{
mz_stream_mem *mem = (mz_stream_mem *)stream;
int32_t err = MZ_OK;
MZ_UNUSED(path);
mem->mode = mode;
mem->limit = 0;
mem->position = 0;
if (mem->mode & MZ_OPEN_MODE_CREATE)
err = mz_stream_mem_set_size(stream, mem->grow_size);
else
mem->limit = mem->size;
return err;
}
int32_t mz_stream_mem_is_open(void *stream)
{
mz_stream_mem *mem = (mz_stream_mem *)stream;
if (mem->buffer == NULL)
return MZ_OPEN_ERROR;
return MZ_OK;
}
int32_t mz_stream_mem_read(void *stream, void *buf, int32_t size)
{
mz_stream_mem *mem = (mz_stream_mem *)stream;
if (size > mem->size - mem->position)
size = mem->size - mem->position;
if (mem->position + size > mem->limit)
size = mem->limit - mem->position;
if (size <= 0)
return 0;
memcpy(buf, mem->buffer + mem->position, size);
mem->position += size;
return size;
}
int32_t mz_stream_mem_write(void *stream, const void *buf, int32_t size)
{
mz_stream_mem *mem = (mz_stream_mem *)stream;
int32_t new_size = 0;
int32_t err = MZ_OK;
if (size == 0)
return size;
if (size > mem->size - mem->position)
{
if (mem->mode & MZ_OPEN_MODE_CREATE)
{
new_size = mem->size;
if (size < mem->grow_size)
new_size += mem->grow_size;
else
new_size += size;
err = mz_stream_mem_set_size(stream, new_size);
if (err != MZ_OK)
return err;
}
else
{
size = mem->size - mem->position;
}
}
memcpy(mem->buffer + mem->position, buf, size);
mem->position += size;
if (mem->position > mem->limit)
mem->limit = mem->position;
return size;
}
int64_t mz_stream_mem_tell(void *stream)
{
mz_stream_mem *mem = (mz_stream_mem *)stream;
return mem->position;
}
int32_t mz_stream_mem_seek(void *stream, int64_t offset, int32_t origin)
{
mz_stream_mem *mem = (mz_stream_mem *)stream;
int64_t new_pos = 0;
int32_t err = MZ_OK;
switch (origin)
{
case MZ_SEEK_CUR:
new_pos = mem->position + offset;
break;
case MZ_SEEK_END:
new_pos = mem->limit + offset;
break;
case MZ_SEEK_SET:
new_pos = offset;
break;
default:
return MZ_SEEK_ERROR;
}
if (new_pos > mem->size)
{
if ((mem->mode & MZ_OPEN_MODE_CREATE) == 0)
return MZ_SEEK_ERROR;
err = mz_stream_mem_set_size(stream, (int32_t)new_pos);
if (err != MZ_OK)
return err;
}
else if (new_pos < 0)
{
return MZ_SEEK_ERROR;
}
mem->position = (int32_t)new_pos;
return MZ_OK;
}
int32_t mz_stream_mem_close(void *stream)
{
MZ_UNUSED(stream);
/* We never return errors */
return MZ_OK;
}
int32_t mz_stream_mem_error(void *stream)
{
MZ_UNUSED(stream);
/* We never return errors */
return MZ_OK;
}
void mz_stream_mem_set_buffer(void *stream, void *buf, int32_t size)
{
mz_stream_mem *mem = (mz_stream_mem *)stream;
mem->buffer = (uint8_t *)buf;
mem->size = size;
mem->limit = size;
}
int32_t mz_stream_mem_get_buffer(void *stream, const void **buf)
{
return mz_stream_mem_get_buffer_at(stream, 0, buf);
}
int32_t mz_stream_mem_get_buffer_at(void *stream, int64_t position, const void **buf)
{
mz_stream_mem *mem = (mz_stream_mem *)stream;
if (buf == NULL || position < 0 || mem->size < position || mem->buffer == NULL)
return MZ_SEEK_ERROR;
*buf = mem->buffer + position;
return MZ_OK;
}
int32_t mz_stream_mem_get_buffer_at_current(void *stream, const void **buf)
{
mz_stream_mem *mem = (mz_stream_mem *)stream;
return mz_stream_mem_get_buffer_at(stream, mem->position, buf);
}
void mz_stream_mem_get_buffer_length(void *stream, int32_t *length)
{
mz_stream_mem *mem = (mz_stream_mem *)stream;
*length = mem->limit;
}
void mz_stream_mem_set_buffer_limit(void *stream, int32_t limit)
{
mz_stream_mem *mem = (mz_stream_mem *)stream;
mem->limit = limit;
}
void mz_stream_mem_set_grow_size(void *stream, int32_t grow_size)
{
mz_stream_mem *mem = (mz_stream_mem *)stream;
mem->grow_size = grow_size;
}
void *mz_stream_mem_create(void **stream)
{
mz_stream_mem *mem = NULL;
mem = (mz_stream_mem *)MZ_ALLOC(sizeof(mz_stream_mem));
if (mem != NULL)
{
memset(mem, 0, sizeof(mz_stream_mem));
mem->stream.vtbl = &mz_stream_mem_vtbl;
mem->grow_size = 4096;
}
if (stream != NULL)
*stream = mem;
return mem;
}
void mz_stream_mem_delete(void **stream)
{
mz_stream_mem *mem = NULL;
if (stream == NULL)
return;
mem = (mz_stream_mem *)*stream;
if (mem != NULL)
{
if ((mem->mode & MZ_OPEN_MODE_CREATE) && (mem->buffer != NULL))
MZ_FREE(mem->buffer);
MZ_FREE(mem);
}
*stream = NULL;
}
void *mz_stream_mem_get_interface(void)
{
return (void *)&mz_stream_mem_vtbl;
}

View File

@ -0,0 +1,49 @@
/* mz_strm_mem.h -- Stream for memory access
Version 2.9.2, February 12, 2020
part of MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#ifndef MZ_STREAM_MEM_H
#define MZ_STREAM_MEM_H
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
int32_t mz_stream_mem_open(void *stream, const char *filename, int32_t mode);
int32_t mz_stream_mem_is_open(void *stream);
int32_t mz_stream_mem_read(void *stream, void *buf, int32_t size);
int32_t mz_stream_mem_write(void *stream, const void *buf, int32_t size);
int64_t mz_stream_mem_tell(void *stream);
int32_t mz_stream_mem_seek(void *stream, int64_t offset, int32_t origin);
int32_t mz_stream_mem_close(void *stream);
int32_t mz_stream_mem_error(void *stream);
void mz_stream_mem_set_buffer(void *stream, void *buf, int32_t size);
int32_t mz_stream_mem_get_buffer(void *stream, const void **buf);
int32_t mz_stream_mem_get_buffer_at(void *stream, int64_t position, const void **buf);
int32_t mz_stream_mem_get_buffer_at_current(void *stream, const void **buf);
void mz_stream_mem_get_buffer_length(void *stream, int32_t *length);
void mz_stream_mem_set_buffer_limit(void *stream, int32_t limit);
void mz_stream_mem_set_grow_size(void *stream, int32_t grow_size);
void* mz_stream_mem_create(void **stream);
void mz_stream_mem_delete(void **stream);
void* mz_stream_mem_get_interface(void);
/***************************************************************************/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,41 @@
/* mz_sstrm_os.h -- Stream for filesystem access
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#ifndef MZ_STREAM_OS_H
#define MZ_STREAM_OS_H
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
int32_t mz_stream_os_open(void *stream, const char *path, int32_t mode);
int32_t mz_stream_os_is_open(void *stream);
int32_t mz_stream_os_read(void *stream, void *buf, int32_t size);
int32_t mz_stream_os_write(void *stream, const void *buf, int32_t size);
int64_t mz_stream_os_tell(void *stream);
int32_t mz_stream_os_seek(void *stream, int64_t offset, int32_t origin);
int32_t mz_stream_os_close(void *stream);
int32_t mz_stream_os_error(void *stream);
void* mz_stream_os_create(void **stream);
void mz_stream_os_delete(void **stream);
void* mz_stream_os_get_interface(void);
/***************************************************************************/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,228 @@
/* mz_strm_posix.c -- Stream for filesystem access for posix/linux
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
Modifications for Zip64 support
Copyright (C) 2009-2010 Mathias Svensson
http://result42.com
Copyright (C) 1998-2010 Gilles Vollant
https://www.winimage.com/zLibDll/minizip.html
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#include "mz.h"
#include "mz_strm.h"
#include "mz_strm_os.h"
#include <stdio.h> /* fopen, fread.. */
#include <errno.h>
/***************************************************************************/
#define fopen64 fopen
#ifndef MZ_FILE32_API
# ifndef NO_FSEEKO
# define ftello64 ftello
# define fseeko64 fseeko
# elif defined(_MSC_VER) && (_MSC_VER >= 1400)
# define ftello64 _ftelli64
# define fseeko64 _fseeki64
# endif
#endif
#ifndef ftello64
# define ftello64 ftell
#endif
#ifndef fseeko64
# define fseeko64 fseek
#endif
/***************************************************************************/
static mz_stream_vtbl mz_stream_os_vtbl = {
mz_stream_os_open,
mz_stream_os_is_open,
mz_stream_os_read,
mz_stream_os_write,
mz_stream_os_tell,
mz_stream_os_seek,
mz_stream_os_close,
mz_stream_os_error,
mz_stream_os_create,
mz_stream_os_delete,
NULL,
NULL
};
/***************************************************************************/
typedef struct mz_stream_posix_s
{
mz_stream stream;
int32_t error;
FILE *handle;
} mz_stream_posix;
/***************************************************************************/
int32_t mz_stream_os_open(void *stream, const char *path, int32_t mode)
{
mz_stream_posix *posix = (mz_stream_posix *)stream;
const char *mode_fopen = NULL;
if (path == NULL)
return MZ_PARAM_ERROR;
if ((mode & MZ_OPEN_MODE_READWRITE) == MZ_OPEN_MODE_READ)
mode_fopen = "rb";
else if (mode & MZ_OPEN_MODE_APPEND)
mode_fopen = "r+b";
else if (mode & MZ_OPEN_MODE_CREATE)
mode_fopen = "wb";
else
return MZ_OPEN_ERROR;
posix->handle = fopen64(path, mode_fopen);
if (posix->handle == NULL)
{
posix->error = errno;
return MZ_OPEN_ERROR;
}
if (mode & MZ_OPEN_MODE_APPEND)
return mz_stream_os_seek(stream, 0, MZ_SEEK_END);
return MZ_OK;
}
int32_t mz_stream_os_is_open(void *stream)
{
mz_stream_posix *posix = (mz_stream_posix*)stream;
if (posix->handle == NULL)
return MZ_OPEN_ERROR;
return MZ_OK;
}
int32_t mz_stream_os_read(void *stream, void *buf, int32_t size)
{
mz_stream_posix *posix = (mz_stream_posix*)stream;
int32_t read = (int32_t)fread(buf, 1, (size_t)size, posix->handle);
if (read < size && ferror(posix->handle))
{
posix->error = errno;
return MZ_READ_ERROR;
}
return read;
}
int32_t mz_stream_os_write(void *stream, const void *buf, int32_t size)
{
mz_stream_posix *posix = (mz_stream_posix*)stream;
int32_t written = (int32_t)fwrite(buf, 1, (size_t)size, posix->handle);
if (written < size && ferror(posix->handle))
{
posix->error = errno;
return MZ_WRITE_ERROR;
}
return written;
}
int64_t mz_stream_os_tell(void *stream)
{
mz_stream_posix *posix = (mz_stream_posix*)stream;
int64_t position = ftello64(posix->handle);
if (position == -1)
{
posix->error = errno;
return MZ_TELL_ERROR;
}
return position;
}
int32_t mz_stream_os_seek(void *stream, int64_t offset, int32_t origin)
{
mz_stream_posix *posix = (mz_stream_posix*)stream;
int32_t fseek_origin = 0;
switch (origin)
{
case MZ_SEEK_CUR:
fseek_origin = SEEK_CUR;
break;
case MZ_SEEK_END:
fseek_origin = SEEK_END;
break;
case MZ_SEEK_SET:
fseek_origin = SEEK_SET;
break;
default:
return MZ_SEEK_ERROR;
}
if (fseeko64(posix->handle, offset, fseek_origin) != 0)
{
posix->error = errno;
return MZ_SEEK_ERROR;
}
return MZ_OK;
}
int32_t mz_stream_os_close(void *stream)
{
mz_stream_posix *posix = (mz_stream_posix*)stream;
int32_t closed = 0;
if (posix->handle != NULL)
{
closed = fclose(posix->handle);
posix->handle = NULL;
}
if (closed != 0)
{
posix->error = errno;
return MZ_CLOSE_ERROR;
}
return MZ_OK;
}
int32_t mz_stream_os_error(void *stream)
{
mz_stream_posix *posix = (mz_stream_posix*)stream;
return posix->error;
}
void *mz_stream_os_create(void **stream)
{
mz_stream_posix *posix = NULL;
posix = (mz_stream_posix *)MZ_ALLOC(sizeof(mz_stream_posix));
if (posix != NULL)
{
memset(posix, 0, sizeof(mz_stream_posix));
posix->stream.vtbl = &mz_stream_os_vtbl;
}
if (stream != NULL)
*stream = posix;
return posix;
}
void mz_stream_os_delete(void **stream)
{
mz_stream_posix *posix = NULL;
if (stream == NULL)
return;
posix = (mz_stream_posix *)*stream;
if (posix != NULL)
MZ_FREE(posix);
*stream = NULL;
}
void *mz_stream_os_get_interface(void)
{
return (void *)&mz_stream_os_vtbl;
}

View File

@ -0,0 +1,384 @@
/* mz_strm_pkcrypt.c -- Code for traditional PKWARE encryption
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
Copyright (C) 1998-2005 Gilles Vollant
Modifications for Info-ZIP crypting
https://www.winimage.com/zLibDll/minizip.html
Copyright (C) 2003 Terry Thorsen
This code is a modified version of crypting code in Info-ZIP distribution
Copyright (C) 1990-2000 Info-ZIP. All rights reserved.
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
This encryption code is a direct transcription of the algorithm from
Roger Schlafly, described by Phil Katz in the file appnote.txt. This
file (appnote.txt) is distributed with the PKZIP program (even in the
version without encryption capabilities).
*/
#include "mz.h"
#include "mz_crypt.h"
#include "mz_strm.h"
#include "mz_strm_pkcrypt.h"
/***************************************************************************/
static mz_stream_vtbl mz_stream_pkcrypt_vtbl = {
mz_stream_pkcrypt_open,
mz_stream_pkcrypt_is_open,
mz_stream_pkcrypt_read,
mz_stream_pkcrypt_write,
mz_stream_pkcrypt_tell,
mz_stream_pkcrypt_seek,
mz_stream_pkcrypt_close,
mz_stream_pkcrypt_error,
mz_stream_pkcrypt_create,
mz_stream_pkcrypt_delete,
mz_stream_pkcrypt_get_prop_int64,
mz_stream_pkcrypt_set_prop_int64
};
/***************************************************************************/
typedef struct mz_stream_pkcrypt_s {
mz_stream stream;
int32_t error;
int16_t initialized;
uint8_t buffer[UINT16_MAX];
int64_t total_in;
int64_t max_total_in;
int64_t total_out;
uint32_t keys[3]; /* keys defining the pseudo-random sequence */
uint8_t verify1;
uint8_t verify2;
const char *password;
} mz_stream_pkcrypt;
/***************************************************************************/
#define mz_stream_pkcrypt_decode(strm, c) \
(mz_stream_pkcrypt_update_keys(strm, \
c ^= mz_stream_pkcrypt_decrypt_byte(strm)))
#define mz_stream_pkcrypt_encode(strm, c, t) \
(t = mz_stream_pkcrypt_decrypt_byte(strm), \
mz_stream_pkcrypt_update_keys(strm, (uint8_t)c), (uint8_t)(t^(c)))
/***************************************************************************/
static uint8_t mz_stream_pkcrypt_decrypt_byte(void *stream)
{
mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an */
/* unpredictable manner on 16-bit systems; not a problem */
/* with any known compiler so far, though. */
temp = pkcrypt->keys[2] | 2;
return (uint8_t)(((temp * (temp ^ 1)) >> 8) & 0xff);
}
static uint8_t mz_stream_pkcrypt_update_keys(void *stream, uint8_t c)
{
mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
uint8_t buf = c;
pkcrypt->keys[0] = (uint32_t)~mz_crypt_crc32_update(~pkcrypt->keys[0], &buf, 1);
pkcrypt->keys[1] += pkcrypt->keys[0] & 0xff;
pkcrypt->keys[1] *= 134775813L;
pkcrypt->keys[1] += 1;
buf = (uint8_t)(pkcrypt->keys[1] >> 24);
pkcrypt->keys[2] = (uint32_t)~mz_crypt_crc32_update(~pkcrypt->keys[2], &buf, 1);
return (uint8_t)c;
}
static void mz_stream_pkcrypt_init_keys(void *stream, const char *password)
{
mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
pkcrypt->keys[0] = 305419896L;
pkcrypt->keys[1] = 591751049L;
pkcrypt->keys[2] = 878082192L;
while (*password != 0)
{
mz_stream_pkcrypt_update_keys(stream, (uint8_t)*password);
password += 1;
}
}
/***************************************************************************/
int32_t mz_stream_pkcrypt_open(void *stream, const char *path, int32_t mode)
{
mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
uint16_t t = 0;
int16_t i = 0;
uint8_t verify1 = 0;
uint8_t verify2 = 0;
uint8_t header[MZ_PKCRYPT_HEADER_SIZE];
const char *password = path;
pkcrypt->total_in = 0;
pkcrypt->total_out = 0;
pkcrypt->initialized = 0;
if (mz_stream_is_open(pkcrypt->stream.base) != MZ_OK)
return MZ_OPEN_ERROR;
if (password == NULL)
password = pkcrypt->password;
if (password == NULL)
return MZ_PARAM_ERROR;
mz_stream_pkcrypt_init_keys(stream, password);
if (mode & MZ_OPEN_MODE_WRITE)
{
#ifdef MZ_ZIP_NO_COMPRESSION
MZ_UNUSED(t);
MZ_UNUSED(i);
return MZ_SUPPORT_ERROR;
#else
/* First generate RAND_HEAD_LEN - 2 random bytes. */
mz_crypt_rand(header, MZ_PKCRYPT_HEADER_SIZE - 2);
/* Encrypt random header (last two bytes is high word of crc) */
for (i = 0; i < MZ_PKCRYPT_HEADER_SIZE - 2; i++)
header[i] = mz_stream_pkcrypt_encode(stream, header[i], t);
header[i++] = mz_stream_pkcrypt_encode(stream, pkcrypt->verify1, t);
header[i++] = mz_stream_pkcrypt_encode(stream, pkcrypt->verify2, t);
if (mz_stream_write(pkcrypt->stream.base, header, sizeof(header)) != sizeof(header))
return MZ_WRITE_ERROR;
pkcrypt->total_out += MZ_PKCRYPT_HEADER_SIZE;
#endif
}
else if (mode & MZ_OPEN_MODE_READ)
{
#ifdef MZ_ZIP_NO_DECOMPRESSION
MZ_UNUSED(t);
MZ_UNUSED(i);
MZ_UNUSED(verify1);
MZ_UNUSED(verify2);
return MZ_SUPPORT_ERROR;
#else
if (mz_stream_read(pkcrypt->stream.base, header, sizeof(header)) != sizeof(header))
return MZ_READ_ERROR;
for (i = 0; i < MZ_PKCRYPT_HEADER_SIZE - 2; i++)
header[i] = mz_stream_pkcrypt_decode(stream, header[i]);
verify1 = mz_stream_pkcrypt_decode(stream, header[i++]);
verify2 = mz_stream_pkcrypt_decode(stream, header[i++]);
/* Older versions used 2 byte check, newer versions use 1 byte check. */
MZ_UNUSED(verify1);
if ((verify2 != 0) && (verify2 != pkcrypt->verify2))
return MZ_PASSWORD_ERROR;
pkcrypt->total_in += MZ_PKCRYPT_HEADER_SIZE;
#endif
}
pkcrypt->initialized = 1;
return MZ_OK;
}
int32_t mz_stream_pkcrypt_is_open(void *stream)
{
mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
if (pkcrypt->initialized == 0)
return MZ_OPEN_ERROR;
return MZ_OK;
}
int32_t mz_stream_pkcrypt_read(void *stream, void *buf, int32_t size)
{
mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
uint8_t *buf_ptr = (uint8_t *)buf;
int32_t bytes_to_read = size;
int32_t read = 0;
int32_t i = 0;
if ((int64_t)bytes_to_read > (pkcrypt->max_total_in - pkcrypt->total_in))
bytes_to_read = (int32_t)(pkcrypt->max_total_in - pkcrypt->total_in);
read = mz_stream_read(pkcrypt->stream.base, buf, bytes_to_read);
for (i = 0; i < read; i++)
buf_ptr[i] = mz_stream_pkcrypt_decode(stream, buf_ptr[i]);
if (read > 0)
pkcrypt->total_in += read;
return read;
}
int32_t mz_stream_pkcrypt_write(void *stream, const void *buf, int32_t size)
{
mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
const uint8_t *buf_ptr = (const uint8_t *)buf;
int32_t bytes_to_write = sizeof(pkcrypt->buffer);
int32_t total_written = 0;
int32_t written = 0;
int32_t i = 0;
uint16_t t = 0;
if (size < 0)
return MZ_PARAM_ERROR;
do
{
if (bytes_to_write > (size - total_written))
bytes_to_write = (size - total_written);
for (i = 0; i < bytes_to_write; i += 1)
{
pkcrypt->buffer[i] = mz_stream_pkcrypt_encode(stream, *buf_ptr, t);
buf_ptr += 1;
}
written = mz_stream_write(pkcrypt->stream.base, pkcrypt->buffer, bytes_to_write);
if (written < 0)
return written;
total_written += written;
}
while (total_written < size && written > 0);
pkcrypt->total_out += total_written;
return total_written;
}
int64_t mz_stream_pkcrypt_tell(void *stream)
{
mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
return mz_stream_tell(pkcrypt->stream.base);
}
int32_t mz_stream_pkcrypt_seek(void *stream, int64_t offset, int32_t origin)
{
mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
return mz_stream_seek(pkcrypt->stream.base, offset, origin);
}
int32_t mz_stream_pkcrypt_close(void *stream)
{
mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
pkcrypt->initialized = 0;
return MZ_OK;
}
int32_t mz_stream_pkcrypt_error(void *stream)
{
mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
return pkcrypt->error;
}
void mz_stream_pkcrypt_set_password(void *stream, const char *password)
{
mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
pkcrypt->password = password;
}
void mz_stream_pkcrypt_set_verify(void *stream, uint8_t verify1, uint8_t verify2)
{
mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
pkcrypt->verify1 = verify1;
pkcrypt->verify2 = verify2;
}
void mz_stream_pkcrypt_get_verify(void *stream, uint8_t *verify1, uint8_t *verify2)
{
mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
*verify1 = pkcrypt->verify1;
*verify2 = pkcrypt->verify2;
}
int32_t mz_stream_pkcrypt_get_prop_int64(void *stream, int32_t prop, int64_t *value)
{
mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
switch (prop)
{
case MZ_STREAM_PROP_TOTAL_IN:
*value = pkcrypt->total_in;
break;
case MZ_STREAM_PROP_TOTAL_OUT:
*value = pkcrypt->total_out;
break;
case MZ_STREAM_PROP_TOTAL_IN_MAX:
*value = pkcrypt->max_total_in;
break;
case MZ_STREAM_PROP_HEADER_SIZE:
*value = MZ_PKCRYPT_HEADER_SIZE;
break;
case MZ_STREAM_PROP_FOOTER_SIZE:
*value = 0;
break;
default:
return MZ_EXIST_ERROR;
}
return MZ_OK;
}
int32_t mz_stream_pkcrypt_set_prop_int64(void *stream, int32_t prop, int64_t value)
{
mz_stream_pkcrypt *pkcrypt = (mz_stream_pkcrypt *)stream;
switch (prop)
{
case MZ_STREAM_PROP_TOTAL_IN_MAX:
pkcrypt->max_total_in = value;
break;
default:
return MZ_EXIST_ERROR;
}
return MZ_OK;
}
void *mz_stream_pkcrypt_create(void **stream)
{
mz_stream_pkcrypt *pkcrypt = NULL;
pkcrypt = (mz_stream_pkcrypt *)MZ_ALLOC(sizeof(mz_stream_pkcrypt));
if (pkcrypt != NULL)
{
memset(pkcrypt, 0, sizeof(mz_stream_pkcrypt));
pkcrypt->stream.vtbl = &mz_stream_pkcrypt_vtbl;
}
if (stream != NULL)
*stream = pkcrypt;
return pkcrypt;
}
void mz_stream_pkcrypt_delete(void **stream)
{
mz_stream_pkcrypt *pkcrypt = NULL;
if (stream == NULL)
return;
pkcrypt = (mz_stream_pkcrypt *)*stream;
if (pkcrypt != NULL)
MZ_FREE(pkcrypt);
*stream = NULL;
}
void *mz_stream_pkcrypt_get_interface(void)
{
return (void *)&mz_stream_pkcrypt_vtbl;
}

View File

@ -0,0 +1,47 @@
/* mz_strm_pkcrypt.h -- Code for traditional PKWARE encryption
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#ifndef MZ_STREAM_PKCRYPT_H
#define MZ_STREAM_PKCRYPT_H
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
int32_t mz_stream_pkcrypt_open(void *stream, const char *filename, int32_t mode);
int32_t mz_stream_pkcrypt_is_open(void *stream);
int32_t mz_stream_pkcrypt_read(void *stream, void *buf, int32_t size);
int32_t mz_stream_pkcrypt_write(void *stream, const void *buf, int32_t size);
int64_t mz_stream_pkcrypt_tell(void *stream);
int32_t mz_stream_pkcrypt_seek(void *stream, int64_t offset, int32_t origin);
int32_t mz_stream_pkcrypt_close(void *stream);
int32_t mz_stream_pkcrypt_error(void *stream);
void mz_stream_pkcrypt_set_password(void *stream, const char *password);
void mz_stream_pkcrypt_set_verify(void *stream, uint8_t verify1, uint8_t verify2);
void mz_stream_pkcrypt_get_verify(void *stream, uint8_t *verify1, uint8_t *verify2);
int32_t mz_stream_pkcrypt_get_prop_int64(void *stream, int32_t prop, int64_t *value);
int32_t mz_stream_pkcrypt_set_prop_int64(void *stream, int32_t prop, int64_t value);
void* mz_stream_pkcrypt_create(void **stream);
void mz_stream_pkcrypt_delete(void **stream);
void* mz_stream_pkcrypt_get_interface(void);
/***************************************************************************/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,489 @@
/* mz_strm_split.c -- Stream for split files
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#include "mz.h"
#include "mz_os.h"
#include "mz_strm.h"
#include "mz_strm_split.h"
#include <stdio.h> /* snprintf */
#if defined(_MSC_VER) && (_MSC_VER < 1900)
# define snprintf _snprintf
#endif
/***************************************************************************/
#define MZ_ZIP_MAGIC_DISKHEADER (0x08074b50)
/***************************************************************************/
static mz_stream_vtbl mz_stream_split_vtbl = {
mz_stream_split_open,
mz_stream_split_is_open,
mz_stream_split_read,
mz_stream_split_write,
mz_stream_split_tell,
mz_stream_split_seek,
mz_stream_split_close,
mz_stream_split_error,
mz_stream_split_create,
mz_stream_split_delete,
mz_stream_split_get_prop_int64,
mz_stream_split_set_prop_int64
};
/***************************************************************************/
typedef struct mz_stream_split_s {
mz_stream stream;
int32_t is_open;
int64_t disk_size;
int64_t total_in;
int64_t total_in_disk;
int64_t total_out;
int64_t total_out_disk;
int32_t mode;
char *path_cd;
uint32_t path_cd_size;
char *path_disk;
uint32_t path_disk_size;
int32_t number_disk;
int32_t current_disk;
int64_t current_disk_size;
int32_t reached_end;
} mz_stream_split;
/***************************************************************************/
#if 0
# define mz_stream_split_print printf
#else
# define mz_stream_split_print(fmt,...)
#endif
/***************************************************************************/
static int32_t mz_stream_split_open_disk(void *stream, int32_t number_disk)
{
mz_stream_split *split = (mz_stream_split *)stream;
uint32_t magic = 0;
int64_t position = 0;
int32_t i = 0;
int32_t err = MZ_OK;
int16_t disk_part = 0;
/* Check if we are reading or writing a disk part or the cd disk */
if (number_disk >= 0)
{
if ((split->mode & MZ_OPEN_MODE_WRITE) == 0)
disk_part = MZ_OPEN_MODE_READ;
else if (split->disk_size > 0)
disk_part = MZ_OPEN_MODE_WRITE;
}
/* Construct disk path */
if (disk_part > 0)
{
for (i = (int32_t)strlen(split->path_disk) - 1; i >= 0; i -= 1)
{
if (split->path_disk[i] != '.')
continue;
snprintf(&split->path_disk[i], split->path_disk_size - (uint32_t)i,
".z%02" PRId32, number_disk + 1);
break;
}
}
else
{
strncpy(split->path_disk, split->path_cd, split->path_disk_size - 1);
split->path_disk[split->path_disk_size - 1] = 0;
}
mz_stream_split_print("Split - Goto disk - %s (disk %" PRId32 ")\n", split->path_disk, number_disk);
/* If disk part doesn't exist during reading then return MZ_EXIST_ERROR */
if (disk_part == MZ_OPEN_MODE_READ)
err = mz_os_file_exists(split->path_disk);
if (err == MZ_OK)
err = mz_stream_open(split->stream.base, split->path_disk, split->mode);
if (err == MZ_OK)
{
split->total_in_disk = 0;
split->total_out_disk = 0;
split->current_disk = number_disk;
if (split->mode & MZ_OPEN_MODE_WRITE)
{
if ((split->current_disk == 0) && (split->disk_size > 0))
{
err = mz_stream_write_uint32(split->stream.base, MZ_ZIP_MAGIC_DISKHEADER);
split->total_out_disk += 4;
split->total_out += split->total_out_disk;
}
}
else if (split->mode & MZ_OPEN_MODE_READ)
{
if (split->current_disk == 0)
{
err = mz_stream_read_uint32(split->stream.base, &magic);
if (magic != MZ_ZIP_MAGIC_DISKHEADER)
err = MZ_FORMAT_ERROR;
}
}
}
if (err == MZ_OK)
{
/* Get the size of the current disk we are on */
position = mz_stream_tell(split->stream.base);
mz_stream_seek(split->stream.base, 0, MZ_SEEK_END);
split->current_disk_size = mz_stream_tell(split->stream.base);
mz_stream_seek(split->stream.base, position, MZ_SEEK_SET);
split->is_open = 1;
}
return err;
}
static int32_t mz_stream_split_close_disk(void *stream)
{
mz_stream_split *split = (mz_stream_split *)stream;
if (mz_stream_is_open(split->stream.base) != MZ_OK)
return MZ_OK;
mz_stream_split_print("Split - Close disk\n");
return mz_stream_close(split->stream.base);
}
static int32_t mz_stream_split_goto_disk(void *stream, int32_t number_disk)
{
mz_stream_split *split = (mz_stream_split *)stream;
int32_t err = MZ_OK;
int32_t err_is_open = MZ_OK;
err_is_open = mz_stream_is_open(split->stream.base);
if ((split->disk_size == 0) && (split->mode & MZ_OPEN_MODE_WRITE))
{
if (err_is_open != MZ_OK)
err = mz_stream_split_open_disk(stream, number_disk);
}
else if ((number_disk != split->current_disk) || (err_is_open != MZ_OK))
{
err = mz_stream_split_close_disk(stream);
if (err == MZ_OK)
{
err = mz_stream_split_open_disk(stream, number_disk);
if (err == MZ_OK)
split->number_disk = number_disk;
}
}
return err;
}
int32_t mz_stream_split_open(void *stream, const char *path, int32_t mode)
{
mz_stream_split *split = (mz_stream_split *)stream;
int32_t number_disk = 0;
split->mode = mode;
split->path_cd_size = (uint32_t)strlen(path) + 1;
split->path_cd = (char *)MZ_ALLOC(split->path_cd_size);
if (split->path_cd == NULL)
return MZ_MEM_ERROR;
strncpy(split->path_cd, path, split->path_cd_size - 1);
split->path_cd[split->path_cd_size - 1] = 0;
mz_stream_split_print("Split - Open - %s (disk %" PRId32 ")\n", split->path_cd, number_disk);
split->path_disk_size = (uint32_t)strlen(path) + 10;
split->path_disk = (char *)MZ_ALLOC(split->path_disk_size);
if (split->path_disk == NULL)
{
MZ_FREE(split->path_cd);
return MZ_MEM_ERROR;
}
strncpy(split->path_disk, path, split->path_disk_size - 1);
split->path_disk[split->path_disk_size - 1] = 0;
if ((mode & MZ_OPEN_MODE_WRITE) && ((mode & MZ_OPEN_MODE_APPEND) == 0))
{
number_disk = 0;
split->current_disk = -1;
}
else
{
number_disk = -1;
split->current_disk = 0;
}
return mz_stream_split_goto_disk(stream, number_disk);
}
int32_t mz_stream_split_is_open(void *stream)
{
mz_stream_split *split = (mz_stream_split *)stream;
if (split->is_open != 1)
return MZ_OPEN_ERROR;
return MZ_OK;
}
int32_t mz_stream_split_read(void *stream, void *buf, int32_t size)
{
mz_stream_split *split = (mz_stream_split *)stream;
int32_t bytes_left = size;
int32_t read = 0;
int32_t err = MZ_OK;
uint8_t *buf_ptr = (uint8_t *)buf;
err = mz_stream_split_goto_disk(stream, split->number_disk);
if (err != MZ_OK)
return err;
while (bytes_left > 0)
{
read = mz_stream_read(split->stream.base, buf_ptr, bytes_left);
mz_stream_split_print("Split - Read disk - %" PRId32 "\n", read);
if (read < 0)
return read;
if (read == 0)
{
if (split->current_disk < 0) /* No more disks to goto */
break;
err = mz_stream_split_goto_disk(stream, split->current_disk + 1);
if (err == MZ_EXIST_ERROR)
{
split->current_disk = -1;
break;
}
if (err != MZ_OK)
return err;
}
bytes_left -= read;
buf_ptr += read;
split->total_in += read;
split->total_in_disk += read;
}
return size - bytes_left;
}
int32_t mz_stream_split_write(void *stream, const void *buf, int32_t size)
{
mz_stream_split *split = (mz_stream_split *)stream;
int64_t position = 0;
int32_t written = 0;
int32_t bytes_left = size;
int32_t bytes_to_write = 0;
int32_t bytes_avail = 0;
int32_t number_disk = -1;
int32_t err = MZ_OK;
const uint8_t *buf_ptr = (const uint8_t *)buf;
position = mz_stream_tell(split->stream.base);
while (bytes_left > 0)
{
bytes_to_write = bytes_left;
if (split->disk_size > 0)
{
if ((split->total_out_disk == split->disk_size && split->total_out > 0) ||
(split->number_disk == -1 && split->number_disk != split->current_disk))
{
if (split->number_disk != -1)
number_disk = split->current_disk + 1;
err = mz_stream_split_goto_disk(stream, number_disk);
if (err != MZ_OK)
return err;
}
if (split->number_disk != -1)
{
bytes_avail = (int32_t)(split->disk_size - split->total_out_disk);
if (bytes_to_write > bytes_avail)
bytes_to_write = bytes_avail;
}
}
written = mz_stream_write(split->stream.base, buf_ptr, bytes_to_write);
if (written != bytes_to_write)
return MZ_WRITE_ERROR;
mz_stream_split_print("Split - Write disk - %" PRId32 "\n", written);
bytes_left -= written;
buf_ptr += written;
split->total_out += written;
split->total_out_disk += written;
if (position == split->current_disk_size)
{
split->current_disk_size += written;
position = split->current_disk_size;
}
}
return size - bytes_left;
}
int64_t mz_stream_split_tell(void *stream)
{
mz_stream_split *split = (mz_stream_split *)stream;
int32_t err = MZ_OK;
err = mz_stream_split_goto_disk(stream, split->number_disk);
if (err != MZ_OK)
return err;
return mz_stream_tell(split->stream.base);
}
int32_t mz_stream_split_seek(void *stream, int64_t offset, int32_t origin)
{
mz_stream_split *split = (mz_stream_split *)stream;
int64_t disk_left = 0;
int64_t position = 0;
int32_t err = MZ_OK;
err = mz_stream_split_goto_disk(stream, split->number_disk);
if (err != MZ_OK)
return err;
mz_stream_split_print("Split - Seek disk - %" PRId64 " (origin %" PRId32 ")\n", offset, origin);
if ((origin == MZ_SEEK_CUR) && (split->number_disk != -1))
{
position = mz_stream_tell(split->stream.base);
disk_left = split->current_disk_size - position;
while (offset > disk_left)
{
err = mz_stream_split_goto_disk(stream, split->current_disk + 1);
if (err != MZ_OK)
return err;
offset -= disk_left;
disk_left = split->current_disk_size;
}
}
return mz_stream_seek(split->stream.base, offset, origin);
}
int32_t mz_stream_split_close(void *stream)
{
mz_stream_split *split = (mz_stream_split *)stream;
int32_t err = MZ_OK;
err = mz_stream_split_close_disk(stream);
split->is_open = 0;
return err;
}
int32_t mz_stream_split_error(void *stream)
{
mz_stream_split *split = (mz_stream_split *)stream;
return mz_stream_error(split->stream.base);
}
int32_t mz_stream_split_get_prop_int64(void *stream, int32_t prop, int64_t *value)
{
mz_stream_split *split = (mz_stream_split *)stream;
switch (prop)
{
case MZ_STREAM_PROP_TOTAL_OUT:
*value = split->total_out;
break;
case MZ_STREAM_PROP_DISK_NUMBER:
*value = split->number_disk;
break;
case MZ_STREAM_PROP_DISK_SIZE:
*value = split->disk_size;
break;
default:
return MZ_EXIST_ERROR;
}
return MZ_OK;
}
int32_t mz_stream_split_set_prop_int64(void *stream, int32_t prop, int64_t value)
{
mz_stream_split *split = (mz_stream_split *)stream;
switch (prop)
{
case MZ_STREAM_PROP_DISK_NUMBER:
split->number_disk = (int32_t)value;
break;
case MZ_STREAM_PROP_DISK_SIZE:
split->disk_size = value;
break;
default:
return MZ_EXIST_ERROR;
}
return MZ_OK;
}
void *mz_stream_split_create(void **stream)
{
mz_stream_split *split = NULL;
split = (mz_stream_split *)MZ_ALLOC(sizeof(mz_stream_split));
if (split != NULL)
{
memset(split, 0, sizeof(mz_stream_split));
split->stream.vtbl = &mz_stream_split_vtbl;
}
if (stream != NULL)
*stream = split;
return split;
}
void mz_stream_split_delete(void **stream)
{
mz_stream_split *split = NULL;
if (stream == NULL)
return;
split = (mz_stream_split *)*stream;
if (split != NULL)
{
if (split->path_cd)
MZ_FREE(split->path_cd);
if (split->path_disk)
MZ_FREE(split->path_disk);
MZ_FREE(split);
}
*stream = NULL;
}
void *mz_stream_split_get_interface(void)
{
return (void *)&mz_stream_split_vtbl;
}

View File

@ -0,0 +1,44 @@
/* mz_strm_split.h -- Stream for split files
Version 2.9.2, February 12, 2020
part of MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#ifndef MZ_STREAM_SPLIT_H
#define MZ_STREAM_SPLIT_H
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
int32_t mz_stream_split_open(void *stream, const char *filename, int32_t mode);
int32_t mz_stream_split_is_open(void *stream);
int32_t mz_stream_split_read(void *stream, void *buf, int32_t size);
int32_t mz_stream_split_write(void *stream, const void *buf, int32_t size);
int64_t mz_stream_split_tell(void *stream);
int32_t mz_stream_split_seek(void *stream, int64_t offset, int32_t origin);
int32_t mz_stream_split_close(void *stream);
int32_t mz_stream_split_error(void *stream);
int32_t mz_stream_split_get_prop_int64(void *stream, int32_t prop, int64_t *value);
int32_t mz_stream_split_set_prop_int64(void *stream, int32_t prop, int64_t value);
void* mz_stream_split_create(void **stream);
void mz_stream_split_delete(void **stream);
void* mz_stream_split_get_interface(void);
/***************************************************************************/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,405 @@
/* mz_strm_wzaes.c -- Stream for WinZip AES encryption
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
Copyright (C) 1998-2010 Brian Gladman, Worcester, UK
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#include "mz.h"
#include "mz_crypt.h"
#include "mz_strm.h"
#include "mz_strm_wzaes.h"
/***************************************************************************/
#define MZ_AES_KEYING_ITERATIONS (1000)
#define MZ_AES_SALT_LENGTH(MODE) (4 * (MODE & 3) + 4)
#define MZ_AES_SALT_LENGTH_MAX (16)
#define MZ_AES_PW_LENGTH_MAX (128)
#define MZ_AES_PW_VERIFY_SIZE (2)
#define MZ_AES_AUTHCODE_SIZE (10)
/***************************************************************************/
static mz_stream_vtbl mz_stream_wzaes_vtbl = {
mz_stream_wzaes_open,
mz_stream_wzaes_is_open,
mz_stream_wzaes_read,
mz_stream_wzaes_write,
mz_stream_wzaes_tell,
mz_stream_wzaes_seek,
mz_stream_wzaes_close,
mz_stream_wzaes_error,
mz_stream_wzaes_create,
mz_stream_wzaes_delete,
mz_stream_wzaes_get_prop_int64,
mz_stream_wzaes_set_prop_int64
};
/***************************************************************************/
typedef struct mz_stream_wzaes_s {
mz_stream stream;
int32_t mode;
int32_t error;
int16_t initialized;
uint8_t buffer[UINT16_MAX];
int64_t total_in;
int64_t max_total_in;
int64_t total_out;
int16_t encryption_mode;
const char *password;
void *aes;
uint32_t crypt_pos;
uint8_t crypt_block[MZ_AES_BLOCK_SIZE];
void *hmac;
uint8_t nonce[MZ_AES_BLOCK_SIZE];
} mz_stream_wzaes;
/***************************************************************************/
int32_t mz_stream_wzaes_open(void *stream, const char *path, int32_t mode)
{
mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
uint16_t salt_length = 0;
uint16_t password_length = 0;
uint16_t key_length = 0;
uint8_t kbuf[2 * MZ_AES_KEY_LENGTH_MAX + MZ_AES_PW_VERIFY_SIZE];
uint8_t verify[MZ_AES_PW_VERIFY_SIZE];
uint8_t verify_expected[MZ_AES_PW_VERIFY_SIZE];
uint8_t salt_value[MZ_AES_SALT_LENGTH_MAX];
const char *password = path;
wzaes->total_in = 0;
wzaes->total_out = 0;
wzaes->initialized = 0;
if (mz_stream_is_open(wzaes->stream.base) != MZ_OK)
return MZ_OPEN_ERROR;
if (password == NULL)
password = wzaes->password;
if (password == NULL)
return MZ_PARAM_ERROR;
password_length = (uint16_t)strlen(password);
if (password_length > MZ_AES_PW_LENGTH_MAX)
return MZ_PARAM_ERROR;
if (wzaes->encryption_mode < 1 || wzaes->encryption_mode > 3)
return MZ_PARAM_ERROR;
salt_length = MZ_AES_SALT_LENGTH(wzaes->encryption_mode);
if (mode & MZ_OPEN_MODE_WRITE)
{
#ifdef MZ_ZIP_NO_COMPRESSION
return MZ_SUPPORT_ERROR;
#else
mz_crypt_rand(salt_value, salt_length);
#endif
}
else if (mode & MZ_OPEN_MODE_READ)
{
#ifdef MZ_ZIP_NO_DECOMPRESSION
return MZ_SUPPORT_ERROR;
#else
if (mz_stream_read(wzaes->stream.base, salt_value, salt_length) != salt_length)
return MZ_READ_ERROR;
#endif
}
key_length = MZ_AES_KEY_LENGTH(wzaes->encryption_mode);
/* Derive the encryption and authentication keys and the password verifier */
mz_crypt_pbkdf2((uint8_t *)password, password_length, salt_value, salt_length,
MZ_AES_KEYING_ITERATIONS, kbuf, 2 * key_length + MZ_AES_PW_VERIFY_SIZE);
/* Initialize the encryption nonce and buffer pos */
wzaes->crypt_pos = MZ_AES_BLOCK_SIZE;
memset(wzaes->nonce, 0, sizeof(wzaes->nonce));
/* Initialize for encryption using key 1 */
mz_crypt_aes_reset(wzaes->aes);
mz_crypt_aes_set_mode(wzaes->aes, wzaes->encryption_mode);
mz_crypt_aes_set_encrypt_key(wzaes->aes, kbuf, key_length);
/* Initialize for authentication using key 2 */
mz_crypt_hmac_reset(wzaes->hmac);
mz_crypt_hmac_set_algorithm(wzaes->hmac, MZ_HASH_SHA1);
mz_crypt_hmac_init(wzaes->hmac, kbuf + key_length, key_length);
memcpy(verify, kbuf + (2 * key_length), MZ_AES_PW_VERIFY_SIZE);
if (mode & MZ_OPEN_MODE_WRITE)
{
if (mz_stream_write(wzaes->stream.base, salt_value, salt_length) != salt_length)
return MZ_WRITE_ERROR;
wzaes->total_out += salt_length;
if (mz_stream_write(wzaes->stream.base, verify, MZ_AES_PW_VERIFY_SIZE) != MZ_AES_PW_VERIFY_SIZE)
return MZ_WRITE_ERROR;
wzaes->total_out += MZ_AES_PW_VERIFY_SIZE;
}
else if (mode & MZ_OPEN_MODE_READ)
{
wzaes->total_in += salt_length;
if (mz_stream_read(wzaes->stream.base, verify_expected, MZ_AES_PW_VERIFY_SIZE) != MZ_AES_PW_VERIFY_SIZE)
return MZ_READ_ERROR;
wzaes->total_in += MZ_AES_PW_VERIFY_SIZE;
if (memcmp(verify_expected, verify, MZ_AES_PW_VERIFY_SIZE) != 0)
return MZ_PASSWORD_ERROR;
}
wzaes->mode = mode;
wzaes->initialized = 1;
return MZ_OK;
}
int32_t mz_stream_wzaes_is_open(void *stream)
{
mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
if (wzaes->initialized == 0)
return MZ_OPEN_ERROR;
return MZ_OK;
}
static int32_t mz_stream_wzaes_ctr_encrypt(void *stream, uint8_t *buf, int32_t size)
{
mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
uint32_t pos = wzaes->crypt_pos;
uint32_t i = 0;
int32_t err = MZ_OK;
while (i < (uint32_t)size)
{
if (pos == MZ_AES_BLOCK_SIZE)
{
uint32_t j = 0;
/* Increment encryption nonce */
while (j < 8 && !++wzaes->nonce[j])
j += 1;
/* Encrypt the nonce to form next xor buffer */
memcpy(wzaes->crypt_block, wzaes->nonce, MZ_AES_BLOCK_SIZE);
mz_crypt_aes_encrypt(wzaes->aes, wzaes->crypt_block, sizeof(wzaes->crypt_block));
pos = 0;
}
buf[i++] ^= wzaes->crypt_block[pos++];
}
wzaes->crypt_pos = pos;
return err;
}
int32_t mz_stream_wzaes_read(void *stream, void *buf, int32_t size)
{
mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
int64_t max_total_in = 0;
int32_t bytes_to_read = size;
int32_t read = 0;
max_total_in = wzaes->max_total_in - MZ_AES_FOOTER_SIZE;
if ((int64_t)bytes_to_read > (max_total_in - wzaes->total_in))
bytes_to_read = (int32_t)(max_total_in - wzaes->total_in);
read = mz_stream_read(wzaes->stream.base, buf, bytes_to_read);
if (read > 0)
{
mz_crypt_hmac_update(wzaes->hmac, (uint8_t *)buf, read);
mz_stream_wzaes_ctr_encrypt(stream, (uint8_t *)buf, read);
wzaes->total_in += read;
}
return read;
}
int32_t mz_stream_wzaes_write(void *stream, const void *buf, int32_t size)
{
mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
const uint8_t *buf_ptr = (const uint8_t *)buf;
int32_t bytes_to_write = sizeof(wzaes->buffer);
int32_t total_written = 0;
int32_t written = 0;
if (size < 0)
return MZ_PARAM_ERROR;
do
{
if (bytes_to_write > (size - total_written))
bytes_to_write = (size - total_written);
memcpy(wzaes->buffer, buf_ptr, bytes_to_write);
buf_ptr += bytes_to_write;
mz_stream_wzaes_ctr_encrypt(stream, (uint8_t *)wzaes->buffer, bytes_to_write);
mz_crypt_hmac_update(wzaes->hmac, wzaes->buffer, bytes_to_write);
written = mz_stream_write(wzaes->stream.base, wzaes->buffer, bytes_to_write);
if (written < 0)
return written;
total_written += written;
}
while (total_written < size && written > 0);
wzaes->total_out += total_written;
return total_written;
}
int64_t mz_stream_wzaes_tell(void *stream)
{
mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
return mz_stream_tell(wzaes->stream.base);
}
int32_t mz_stream_wzaes_seek(void *stream, int64_t offset, int32_t origin)
{
mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
return mz_stream_seek(wzaes->stream.base, offset, origin);
}
int32_t mz_stream_wzaes_close(void *stream)
{
mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
uint8_t expected_hash[MZ_AES_AUTHCODE_SIZE];
uint8_t computed_hash[MZ_HASH_SHA1_SIZE];
mz_crypt_hmac_end(wzaes->hmac, computed_hash, sizeof(computed_hash));
if (wzaes->mode & MZ_OPEN_MODE_WRITE)
{
if (mz_stream_write(wzaes->stream.base, computed_hash, MZ_AES_AUTHCODE_SIZE) != MZ_AES_AUTHCODE_SIZE)
return MZ_WRITE_ERROR;
wzaes->total_out += MZ_AES_AUTHCODE_SIZE;
}
else if (wzaes->mode & MZ_OPEN_MODE_READ)
{
if (mz_stream_read(wzaes->stream.base, expected_hash, MZ_AES_AUTHCODE_SIZE) != MZ_AES_AUTHCODE_SIZE)
return MZ_READ_ERROR;
wzaes->total_in += MZ_AES_AUTHCODE_SIZE;
/* If entire entry was not read this will fail */
if (memcmp(computed_hash, expected_hash, MZ_AES_AUTHCODE_SIZE) != 0)
return MZ_CRC_ERROR;
}
wzaes->initialized = 0;
return MZ_OK;
}
int32_t mz_stream_wzaes_error(void *stream)
{
mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
return wzaes->error;
}
void mz_stream_wzaes_set_password(void *stream, const char *password)
{
mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
wzaes->password = password;
}
void mz_stream_wzaes_set_encryption_mode(void *stream, int16_t encryption_mode)
{
mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
wzaes->encryption_mode = encryption_mode;
}
int32_t mz_stream_wzaes_get_prop_int64(void *stream, int32_t prop, int64_t *value)
{
mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
switch (prop)
{
case MZ_STREAM_PROP_TOTAL_IN:
*value = wzaes->total_in;
break;
case MZ_STREAM_PROP_TOTAL_OUT:
*value = wzaes->total_out;
break;
case MZ_STREAM_PROP_TOTAL_IN_MAX:
*value = wzaes->max_total_in;
break;
case MZ_STREAM_PROP_HEADER_SIZE:
*value = MZ_AES_SALT_LENGTH((int64_t)wzaes->encryption_mode) + MZ_AES_PW_VERIFY_SIZE;
break;
case MZ_STREAM_PROP_FOOTER_SIZE:
*value = MZ_AES_AUTHCODE_SIZE;
break;
default:
return MZ_EXIST_ERROR;
}
return MZ_OK;
}
int32_t mz_stream_wzaes_set_prop_int64(void *stream, int32_t prop, int64_t value)
{
mz_stream_wzaes *wzaes = (mz_stream_wzaes *)stream;
switch (prop)
{
case MZ_STREAM_PROP_TOTAL_IN_MAX:
wzaes->max_total_in = value;
break;
default:
return MZ_EXIST_ERROR;
}
return MZ_OK;
}
void *mz_stream_wzaes_create(void **stream)
{
mz_stream_wzaes *wzaes = NULL;
wzaes = (mz_stream_wzaes *)MZ_ALLOC(sizeof(mz_stream_wzaes));
if (wzaes != NULL)
{
memset(wzaes, 0, sizeof(mz_stream_wzaes));
wzaes->stream.vtbl = &mz_stream_wzaes_vtbl;
wzaes->encryption_mode = MZ_AES_ENCRYPTION_MODE_256;
mz_crypt_hmac_create(&wzaes->hmac);
mz_crypt_aes_create(&wzaes->aes);
}
if (stream != NULL)
*stream = wzaes;
return wzaes;
}
void mz_stream_wzaes_delete(void **stream)
{
mz_stream_wzaes *wzaes = NULL;
if (stream == NULL)
return;
wzaes = (mz_stream_wzaes *)*stream;
if (wzaes != NULL)
{
mz_crypt_aes_delete(&wzaes->aes);
mz_crypt_hmac_delete(&wzaes->hmac);
MZ_FREE(wzaes);
}
*stream = NULL;
}
void *mz_stream_wzaes_get_interface(void)
{
return (void *)&mz_stream_wzaes_vtbl;
}

View File

@ -0,0 +1,47 @@
/* mz_strm_wzaes.h -- Stream for WinZIP AES encryption
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#ifndef MZ_STREAM_WZAES_SHA1_H
#define MZ_STREAM_WZAES_SHA1_H
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
int32_t mz_stream_wzaes_open(void *stream, const char *filename, int32_t mode);
int32_t mz_stream_wzaes_is_open(void *stream);
int32_t mz_stream_wzaes_read(void *stream, void *buf, int32_t size);
int32_t mz_stream_wzaes_write(void *stream, const void *buf, int32_t size);
int64_t mz_stream_wzaes_tell(void *stream);
int32_t mz_stream_wzaes_seek(void *stream, int64_t offset, int32_t origin);
int32_t mz_stream_wzaes_close(void *stream);
int32_t mz_stream_wzaes_error(void *stream);
void mz_stream_wzaes_set_password(void *stream, const char *password);
void mz_stream_wzaes_set_encryption_mode(void *stream, int16_t encryption_mode);
int32_t mz_stream_wzaes_get_prop_int64(void *stream, int32_t prop, int64_t *value);
int32_t mz_stream_wzaes_set_prop_int64(void *stream, int32_t prop, int64_t value);
void* mz_stream_wzaes_create(void **stream);
void mz_stream_wzaes_delete(void **stream);
void* mz_stream_wzaes_get_interface(void);
/***************************************************************************/
#ifdef __cplusplus
}
#endif
#endif

View File

@ -0,0 +1,425 @@
/* mz_strm_zlib.c -- Stream for zlib inflate/deflate
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#include "mz.h"
#include "mz_strm.h"
#include "mz_strm_zlib.h"
#include "zlib.h"
#if defined(ZLIBNG_VERNUM) && !defined(ZLIB_COMPAT)
# include "zlib-ng.h"
#endif
/***************************************************************************/
#if defined(ZLIBNG_VERNUM) && !defined(ZLIB_COMPAT)
# define ZLIB_PREFIX(x) zng_ ## x
typedef zng_stream zlib_stream;
#else
# define ZLIB_PREFIX(x) x
typedef z_stream zlib_stream;
#endif
#if !defined(DEF_MEM_LEVEL)
# if MAX_MEM_LEVEL >= 8
# define DEF_MEM_LEVEL 8
# else
# define DEF_MEM_LEVEL MAX_MEM_LEVEL
# endif
#endif
/***************************************************************************/
static mz_stream_vtbl mz_stream_zlib_vtbl = {
mz_stream_zlib_open,
mz_stream_zlib_is_open,
mz_stream_zlib_read,
mz_stream_zlib_write,
mz_stream_zlib_tell,
mz_stream_zlib_seek,
mz_stream_zlib_close,
mz_stream_zlib_error,
mz_stream_zlib_create,
mz_stream_zlib_delete,
mz_stream_zlib_get_prop_int64,
mz_stream_zlib_set_prop_int64
};
/***************************************************************************/
typedef struct mz_stream_zlib_s {
mz_stream stream;
zlib_stream zstream;
uint8_t buffer[INT16_MAX];
int32_t buffer_len;
int64_t total_in;
int64_t total_out;
int64_t max_total_in;
int8_t initialized;
int16_t level;
int32_t window_bits;
int32_t mode;
int32_t error;
} mz_stream_zlib;
/***************************************************************************/
int32_t mz_stream_zlib_open(void *stream, const char *path, int32_t mode)
{
mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
MZ_UNUSED(path);
zlib->zstream.data_type = Z_BINARY;
zlib->zstream.zalloc = Z_NULL;
zlib->zstream.zfree = Z_NULL;
zlib->zstream.opaque = Z_NULL;
zlib->zstream.total_in = 0;
zlib->zstream.total_out = 0;
zlib->total_in = 0;
zlib->total_out = 0;
if (mode & MZ_OPEN_MODE_WRITE)
{
#ifdef MZ_ZIP_NO_COMPRESSION
return MZ_SUPPORT_ERROR;
#else
zlib->zstream.next_out = zlib->buffer;
zlib->zstream.avail_out = sizeof(zlib->buffer);
zlib->error = ZLIB_PREFIX(deflateInit2)(&zlib->zstream, (int8_t)zlib->level, Z_DEFLATED,
zlib->window_bits, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
#endif
}
else if (mode & MZ_OPEN_MODE_READ)
{
#ifdef MZ_ZIP_NO_DECOMPRESSION
return MZ_SUPPORT_ERROR;
#else
zlib->zstream.next_in = zlib->buffer;
zlib->zstream.avail_in = 0;
zlib->error = ZLIB_PREFIX(inflateInit2)(&zlib->zstream, zlib->window_bits);
#endif
}
if (zlib->error != Z_OK)
return MZ_OPEN_ERROR;
zlib->initialized = 1;
zlib->mode = mode;
return MZ_OK;
}
int32_t mz_stream_zlib_is_open(void *stream)
{
mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
if (zlib->initialized != 1)
return MZ_OPEN_ERROR;
return MZ_OK;
}
int32_t mz_stream_zlib_read(void *stream, void *buf, int32_t size)
{
#ifdef MZ_ZIP_NO_DECOMPRESSION
MZ_UNUSED(stream);
MZ_UNUSED(buf);
MZ_UNUSED(size);
return MZ_SUPPORT_ERROR;
#else
mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
uint64_t total_in_before = 0;
uint64_t total_in_after = 0;
uint64_t total_out_before = 0;
uint64_t total_out_after = 0;
uint32_t total_in = 0;
uint32_t total_out = 0;
uint32_t in_bytes = 0;
uint32_t out_bytes = 0;
int32_t bytes_to_read = sizeof(zlib->buffer);
int32_t read = 0;
int32_t err = Z_OK;
zlib->zstream.next_out = (Bytef*)buf;
zlib->zstream.avail_out = (uInt)size;
do
{
if (zlib->zstream.avail_in == 0)
{
if (zlib->max_total_in > 0)
{
if ((int64_t)bytes_to_read > (zlib->max_total_in - zlib->total_in))
bytes_to_read = (int32_t)(zlib->max_total_in - zlib->total_in);
}
read = mz_stream_read(zlib->stream.base, zlib->buffer, bytes_to_read);
if (read < 0)
return read;
zlib->zstream.next_in = zlib->buffer;
zlib->zstream.avail_in = read;
}
total_in_before = zlib->zstream.avail_in;
total_out_before = zlib->zstream.total_out;
err = ZLIB_PREFIX(inflate)(&zlib->zstream, Z_SYNC_FLUSH);
if ((err >= Z_OK) && (zlib->zstream.msg != NULL))
{
zlib->error = Z_DATA_ERROR;
break;
}
total_in_after = zlib->zstream.avail_in;
total_out_after = zlib->zstream.total_out;
in_bytes = (uint32_t)(total_in_before - total_in_after);
out_bytes = (uint32_t)(total_out_after - total_out_before);
total_in += in_bytes;
total_out += out_bytes;
zlib->total_in += in_bytes;
zlib->total_out += out_bytes;
if (err == Z_STREAM_END)
break;
if (err != Z_OK)
{
zlib->error = err;
break;
}
}
while (zlib->zstream.avail_out > 0);
if (zlib->error != 0)
{
/* Zlib errors are compatible with MZ */
return zlib->error;
}
return total_out;
#endif
}
#ifndef MZ_ZIP_NO_COMPRESSION
static int32_t mz_stream_zlib_flush(void *stream)
{
mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
if (mz_stream_write(zlib->stream.base, zlib->buffer, zlib->buffer_len) != zlib->buffer_len)
return MZ_WRITE_ERROR;
return MZ_OK;
}
static int32_t mz_stream_zlib_deflate(void *stream, int flush)
{
mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
uint64_t total_out_before = 0;
uint64_t total_out_after = 0;
int32_t out_bytes = 0;
int32_t err = Z_OK;
do
{
if (zlib->zstream.avail_out == 0)
{
err = mz_stream_zlib_flush(zlib);
if (err != MZ_OK)
return err;
zlib->zstream.avail_out = sizeof(zlib->buffer);
zlib->zstream.next_out = zlib->buffer;
zlib->buffer_len = 0;
}
total_out_before = zlib->zstream.total_out;
err = ZLIB_PREFIX(deflate)(&zlib->zstream, flush);
total_out_after = zlib->zstream.total_out;
out_bytes = (uint32_t)(total_out_after - total_out_before);
zlib->buffer_len += out_bytes;
zlib->total_out += out_bytes;
if (err == Z_STREAM_END)
break;
if (err != Z_OK)
{
zlib->error = err;
return MZ_DATA_ERROR;
}
}
while ((zlib->zstream.avail_in > 0) || (flush == Z_FINISH && err == Z_OK));
return MZ_OK;
}
#endif
int32_t mz_stream_zlib_write(void *stream, const void *buf, int32_t size)
{
mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
int32_t err = size;
#ifdef MZ_ZIP_NO_COMPRESSION
MZ_UNUSED(zlib);
MZ_UNUSED(buf);
err = MZ_SUPPORT_ERROR;
#else
zlib->zstream.next_in = (Bytef*)(intptr_t)buf;
zlib->zstream.avail_in = (uInt)size;
mz_stream_zlib_deflate(stream, Z_NO_FLUSH);
zlib->total_in += size;
#endif
return err;
}
int64_t mz_stream_zlib_tell(void *stream)
{
MZ_UNUSED(stream);
return MZ_TELL_ERROR;
}
int32_t mz_stream_zlib_seek(void *stream, int64_t offset, int32_t origin)
{
MZ_UNUSED(stream);
MZ_UNUSED(offset);
MZ_UNUSED(origin);
return MZ_SEEK_ERROR;
}
int32_t mz_stream_zlib_close(void *stream)
{
mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
if (zlib->mode & MZ_OPEN_MODE_WRITE)
{
#ifdef MZ_ZIP_NO_COMPRESSION
return MZ_SUPPORT_ERROR;
#else
mz_stream_zlib_deflate(stream, Z_FINISH);
mz_stream_zlib_flush(stream);
ZLIB_PREFIX(deflateEnd)(&zlib->zstream);
#endif
}
else if (zlib->mode & MZ_OPEN_MODE_READ)
{
#ifdef MZ_ZIP_NO_DECOMPRESSION
return MZ_SUPPORT_ERROR;
#else
ZLIB_PREFIX(inflateEnd)(&zlib->zstream);
#endif
}
zlib->initialized = 0;
if (zlib->error != Z_OK)
return MZ_CLOSE_ERROR;
return MZ_OK;
}
int32_t mz_stream_zlib_error(void *stream)
{
mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
return zlib->error;
}
int32_t mz_stream_zlib_get_prop_int64(void *stream, int32_t prop, int64_t *value)
{
mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
switch (prop)
{
case MZ_STREAM_PROP_TOTAL_IN:
*value = zlib->total_in;
break;
case MZ_STREAM_PROP_TOTAL_IN_MAX:
*value = zlib->max_total_in;
break;
case MZ_STREAM_PROP_TOTAL_OUT:
*value = zlib->total_out;
break;
case MZ_STREAM_PROP_HEADER_SIZE:
*value = 0;
break;
case MZ_STREAM_PROP_COMPRESS_WINDOW:
*value = zlib->window_bits;
break;
default:
return MZ_EXIST_ERROR;
}
return MZ_OK;
}
int32_t mz_stream_zlib_set_prop_int64(void *stream, int32_t prop, int64_t value)
{
mz_stream_zlib *zlib = (mz_stream_zlib *)stream;
switch (prop)
{
case MZ_STREAM_PROP_COMPRESS_LEVEL:
zlib->level = (int16_t)value;
break;
case MZ_STREAM_PROP_TOTAL_IN_MAX:
zlib->max_total_in = value;
break;
case MZ_STREAM_PROP_COMPRESS_WINDOW:
zlib->window_bits = (int32_t)value;
break;
default:
return MZ_EXIST_ERROR;
}
return MZ_OK;
}
void *mz_stream_zlib_create(void **stream)
{
mz_stream_zlib *zlib = NULL;
zlib = (mz_stream_zlib *)MZ_ALLOC(sizeof(mz_stream_zlib));
if (zlib != NULL)
{
memset(zlib, 0, sizeof(mz_stream_zlib));
zlib->stream.vtbl = &mz_stream_zlib_vtbl;
zlib->level = Z_DEFAULT_COMPRESSION;
zlib->window_bits = -MAX_WBITS;
}
if (stream != NULL)
*stream = zlib;
return zlib;
}
void mz_stream_zlib_delete(void **stream)
{
mz_stream_zlib *zlib = NULL;
if (stream == NULL)
return;
zlib = (mz_stream_zlib *)*stream;
if (zlib != NULL)
MZ_FREE(zlib);
*stream = NULL;
}
void *mz_stream_zlib_get_interface(void)
{
return (void *)&mz_stream_zlib_vtbl;
}

View File

@ -0,0 +1,44 @@
/* mz_strm_zlib.h -- Stream for zlib inflate/deflate
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#ifndef MZ_STREAM_ZLIB_H
#define MZ_STREAM_ZLIB_H
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
int32_t mz_stream_zlib_open(void *stream, const char *filename, int32_t mode);
int32_t mz_stream_zlib_is_open(void *stream);
int32_t mz_stream_zlib_read(void *stream, void *buf, int32_t size);
int32_t mz_stream_zlib_write(void *stream, const void *buf, int32_t size);
int64_t mz_stream_zlib_tell(void *stream);
int32_t mz_stream_zlib_seek(void *stream, int64_t offset, int32_t origin);
int32_t mz_stream_zlib_close(void *stream);
int32_t mz_stream_zlib_error(void *stream);
int32_t mz_stream_zlib_get_prop_int64(void *stream, int32_t prop, int64_t *value);
int32_t mz_stream_zlib_set_prop_int64(void *stream, int32_t prop, int64_t value);
void* mz_stream_zlib_create(void **stream);
void mz_stream_zlib_delete(void **stream);
void* mz_stream_zlib_get_interface(void);
/***************************************************************************/
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,251 @@
/* mz_zip.h -- Zip manipulation
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
Copyright (C) 2009-2010 Mathias Svensson
Modifications for Zip64 support
http://result42.com
Copyright (C) 1998-2010 Gilles Vollant
https://www.winimage.com/zLibDll/minizip.html
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#ifndef MZ_ZIP_H
#define MZ_ZIP_H
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
typedef struct mz_zip_file_s
{
uint16_t version_madeby; /* version made by */
uint16_t version_needed; /* version needed to extract */
uint16_t flag; /* general purpose bit flag */
uint16_t compression_method; /* compression method */
time_t modified_date; /* last modified date in unix time */
time_t accessed_date; /* last accessed date in unix time */
time_t creation_date; /* creation date in unix time */
uint32_t crc; /* crc-32 */
int64_t compressed_size; /* compressed size */
int64_t uncompressed_size; /* uncompressed size */
uint16_t filename_size; /* filename length */
uint16_t extrafield_size; /* extra field length */
uint16_t comment_size; /* file comment length */
uint32_t disk_number; /* disk number start */
int64_t disk_offset; /* relative offset of local header */
uint16_t internal_fa; /* internal file attributes */
uint32_t external_fa; /* external file attributes */
const char *filename; /* filename utf8 null-terminated string */
const uint8_t *extrafield; /* extrafield data */
const char *comment; /* comment utf8 null-terminated string */
const char *linkname; /* sym-link filename utf8 null-terminated string */
uint16_t zip64; /* zip64 extension mode */
uint16_t aes_version; /* winzip aes extension if not 0 */
uint8_t aes_encryption_mode; /* winzip aes encryption mode */
} mz_zip_file, mz_zip_entry;
/***************************************************************************/
typedef int32_t (*mz_zip_locate_entry_cb)(void *handle, void *userdata, mz_zip_file *file_info);
/***************************************************************************/
void * mz_zip_create(void **handle);
/* Create zip instance for opening */
void mz_zip_delete(void **handle);
/* Delete zip object */
int32_t mz_zip_open(void *handle, void *stream, int32_t mode);
/* Create a zip file, no delete file in zip functionality */
int32_t mz_zip_close(void *handle);
/* Close the zip file */
int32_t mz_zip_get_comment(void *handle, const char **comment);
/* Get a pointer to the global comment */
int32_t mz_zip_set_comment(void *handle, const char *comment);
/* Set the global comment used for writing zip file */
int32_t mz_zip_get_version_madeby(void *handle, uint16_t *version_madeby);
/* Get the version made by */
int32_t mz_zip_set_version_madeby(void *handle, uint16_t version_madeby);
/* Set the version made by used for writing zip file */
int32_t mz_zip_set_recover(void *handle, uint8_t recover);
/* Set the ability to recover the central dir by reading local file headers */
int32_t mz_zip_set_data_descriptor(void *handle, uint8_t data_descriptor);
/* Set the use of data descriptor flag when writing zip entries */
int32_t mz_zip_get_stream(void *handle, void **stream);
/* Get a pointer to the stream used to open */
int32_t mz_zip_set_cd_stream(void *handle, int64_t cd_start_pos, void *cd_stream);
/* Sets the stream to use for reading the central dir */
int32_t mz_zip_get_cd_mem_stream(void *handle, void **cd_mem_stream);
/* Get a pointer to the stream used to store the central dir in memory */
int32_t mz_zip_set_number_entry(void *handle, uint64_t number_entry);
/* Sets the total number of entries */
int32_t mz_zip_get_number_entry(void *handle, uint64_t *number_entry);
/* Get the total number of entries */
int32_t mz_zip_set_disk_number_with_cd(void *handle, uint32_t disk_number_with_cd);
/* Sets the disk number containing the central directory record */
int32_t mz_zip_get_disk_number_with_cd(void *handle, uint32_t *disk_number_with_cd);
/* Get the disk number containing the central directory record */
/***************************************************************************/
int32_t mz_zip_entry_is_open(void *handle);
/* Check to see if entry is open for read/write */
int32_t mz_zip_entry_read_open(void *handle, uint8_t raw, const char *password);
/* Open for reading the current file in the zip file */
int32_t mz_zip_entry_read(void *handle, void *buf, int32_t len);
/* Read bytes from the current file in the zip file */
int32_t mz_zip_entry_read_close(void *handle, uint32_t *crc32, int64_t *compressed_size,
int64_t *uncompressed_size);
/* Close the current file for reading and get data descriptor values */
int32_t mz_zip_entry_write_open(void *handle, const mz_zip_file *file_info,
int16_t compress_level, uint8_t raw, const char *password);
/* Open for writing the current file in the zip file */
int32_t mz_zip_entry_write(void *handle, const void *buf, int32_t len);
/* Write bytes from the current file in the zip file */
int32_t mz_zip_entry_write_close(void *handle, uint32_t crc32, int64_t compressed_size,
int64_t uncompressed_size);
/* Close the current file for writing and set data descriptor values */
int32_t mz_zip_entry_close_raw(void *handle, int64_t uncompressed_size, uint32_t crc32);
/* Close the current file in the zip file where raw is compressed data */
int32_t mz_zip_entry_close(void *handle);
/* Close the current file in the zip file */
/***************************************************************************/
int32_t mz_zip_entry_is_dir(void *handle);
/* Checks to see if the entry is a directory */
int32_t mz_zip_entry_is_symlink(void *handle);
/* Checks to see if the entry is a symbolic link */
int32_t mz_zip_entry_get_info(void *handle, mz_zip_file **file_info);
/* Get info about the current file, only valid while current entry is open */
int32_t mz_zip_entry_get_local_info(void *handle, mz_zip_file **local_file_info);
/* Get local info about the current file, only valid while current entry is being read */
int32_t mz_zip_entry_set_extrafield(void *handle, const uint8_t *extrafield, uint16_t extrafield_size);
/* Sets or updates the extra field for the entry to be used before writing cd */
int64_t mz_zip_get_entry(void *handle);
/* Return offset of the current entry in the zip file */
int32_t mz_zip_goto_entry(void *handle, int64_t cd_pos);
/* Go to specified entry in the zip file */
int32_t mz_zip_goto_first_entry(void *handle);
/* Go to the first entry in the zip file */
int32_t mz_zip_goto_next_entry(void *handle);
/* Go to the next entry in the zip file or MZ_END_OF_LIST if reaching the end */
int32_t mz_zip_locate_entry(void *handle, const char *filename, uint8_t ignore_case);
/* Locate the file with the specified name in the zip file or MZ_END_LIST if not found */
int32_t mz_zip_locate_first_entry(void *handle, void *userdata, mz_zip_locate_entry_cb cb);
/* Locate the first matching entry based on a match callback */
int32_t mz_zip_locate_next_entry(void *handle, void *userdata, mz_zip_locate_entry_cb cb);
/* Locate the next matching entry based on a match callback */
/***************************************************************************/
int32_t mz_zip_attrib_is_dir(uint32_t attrib, int32_t version_madeby);
/* Checks to see if the attribute is a directory based on platform */
int32_t mz_zip_attrib_is_symlink(uint32_t attrib, int32_t version_madeby);
/* Checks to see if the attribute is a symbolic link based on platform */
int32_t mz_zip_attrib_convert(uint8_t src_sys, uint32_t src_attrib, uint8_t target_sys,
uint32_t *target_attrib);
/* Converts file attributes from one host system to another */
int32_t mz_zip_attrib_posix_to_win32(uint32_t posix_attrib, uint32_t *win32_attrib);
/* Converts posix file attributes to win32 file attributes */
int32_t mz_zip_attrib_win32_to_posix(uint32_t win32_attrib, uint32_t *posix_attrib);
/* Converts win32 file attributes to posix file attributes */
/***************************************************************************/
int32_t mz_zip_extrafield_find(void *stream, uint16_t type, uint16_t *length);
/* Seeks to extra field by its type and returns its length */
int32_t mz_zip_extrafield_contains(const uint8_t *extrafield, int32_t extrafield_size,
uint16_t type, uint16_t *length);
/* Gets whether an extrafield exists and its size */
int32_t mz_zip_extrafield_read(void *stream, uint16_t *type, uint16_t *length);
/* Reads an extrafield header from a stream */
int32_t mz_zip_extrafield_write(void *stream, uint16_t type, uint16_t length);
/* Writes an extrafield header to a stream */
/***************************************************************************/
int32_t mz_zip_dosdate_to_tm(uint64_t dos_date, struct tm *ptm);
/* Convert dos date/time format to struct tm */
time_t mz_zip_dosdate_to_time_t(uint64_t dos_date);
/* Convert dos date/time format to time_t */
int32_t mz_zip_time_t_to_tm(time_t unix_time, struct tm *ptm);
/* Convert time_t to time struct */
uint32_t mz_zip_time_t_to_dos_date(time_t unix_time);
/* Convert time_t to dos date/time format */
uint32_t mz_zip_tm_to_dosdate(const struct tm *ptm);
/* Convert struct tm to dos date/time format */
int32_t mz_zip_ntfs_to_unix_time(uint64_t ntfs_time, time_t *unix_time);
/* Convert ntfs time to unix time */
int32_t mz_zip_unix_to_ntfs_time(time_t unix_time, uint64_t *ntfs_time);
/* Convert unix time to ntfs time */
/***************************************************************************/
int32_t mz_zip_path_compare(const char *path1, const char *path2, uint8_t ignore_case);
/* Compare two paths without regard to slashes */
/***************************************************************************/
#ifdef __cplusplus
}
#endif
#endif /* _ZIP_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,283 @@
/* mz_zip_rw.h -- Zip reader/writer
Version 2.9.2, February 12, 2020
part of the MiniZip project
Copyright (C) 2010-2020 Nathan Moinvaziri
https://github.com/nmoinvaz/minizip
This program is distributed under the terms of the same license as zlib.
See the accompanying LICENSE file for the full text of the license.
*/
#ifndef MZ_ZIP_RW_H
#define MZ_ZIP_RW_H
#ifdef __cplusplus
extern "C" {
#endif
/***************************************************************************/
typedef int32_t (*mz_zip_reader_overwrite_cb)(void *handle, void *userdata, mz_zip_file *file_info, const char *path);
typedef int32_t (*mz_zip_reader_password_cb)(void *handle, void *userdata, mz_zip_file *file_info, char *password, int32_t max_password);
typedef int32_t (*mz_zip_reader_progress_cb)(void *handle, void *userdata, mz_zip_file *file_info, int64_t position);
typedef int32_t (*mz_zip_reader_entry_cb)(void *handle, void *userdata, mz_zip_file *file_info, const char *path);
/***************************************************************************/
int32_t mz_zip_reader_is_open(void *handle);
/* Checks to see if the zip file is open */
int32_t mz_zip_reader_open(void *handle, void *stream);
/* Opens zip file from stream */
int32_t mz_zip_reader_open_file(void *handle, const char *path);
/* Opens zip file from a file path */
int32_t mz_zip_reader_open_file_in_memory(void *handle, const char *path);
/* Opens zip file from a file path into memory for faster access */
int32_t mz_zip_reader_open_buffer(void *handle, uint8_t *buf, int32_t len, uint8_t copy);
/* Opens zip file from memory buffer */
int32_t mz_zip_reader_close(void *handle);
/* Closes the zip file */
/***************************************************************************/
int32_t mz_zip_reader_unzip_cd(void *handle);
/* Unzip the central directory */
/***************************************************************************/
int32_t mz_zip_reader_goto_first_entry(void *handle);
/* Goto the first entry in the zip file that matches the pattern */
int32_t mz_zip_reader_goto_next_entry(void *handle);
/* Goto the next entry in the zip file that matches the pattern */
int32_t mz_zip_reader_locate_entry(void *handle, const char *filename, uint8_t ignore_case);
/* Locates an entry by filename */
int32_t mz_zip_reader_entry_open(void *handle);
/* Opens an entry for reading */
int32_t mz_zip_reader_entry_close(void *handle);
/* Closes an entry */
int32_t mz_zip_reader_entry_read(void *handle, void *buf, int32_t len);
/* Reads and entry after being opened */
int32_t mz_zip_reader_entry_has_sign(void *handle);
/* Checks to see if the entry has a signature */
int32_t mz_zip_reader_entry_sign_verify(void *handle);
/* Verifies a signature stored with the entry */
int32_t mz_zip_reader_entry_get_hash(void *handle, uint16_t algorithm, uint8_t *digest, int32_t digest_size);
/* Gets a hash algorithm from the entry's extra field */
int32_t mz_zip_reader_entry_get_first_hash(void *handle, uint16_t *algorithm, uint16_t *digest_size);
/* Gets the most secure hash algorithm from the entry's extra field */
int32_t mz_zip_reader_entry_get_info(void *handle, mz_zip_file **file_info);
/* Gets the current entry file info */
int32_t mz_zip_reader_entry_is_dir(void *handle);
/* Gets the current entry is a directory */
int32_t mz_zip_reader_entry_save(void *handle, void *stream, mz_stream_write_cb write_cb);
/* Save the current entry to a steam */
int32_t mz_zip_reader_entry_save_process(void *handle, void *stream, mz_stream_write_cb write_cb);
/* Saves a portion of the current entry to a stream callback */
int32_t mz_zip_reader_entry_save_file(void *handle, const char *path);
/* Save the current entry to a file */
int32_t mz_zip_reader_entry_save_buffer(void *handle, void *buf, int32_t len);
/* Save the current entry to a memory buffer */
int32_t mz_zip_reader_entry_save_buffer_length(void *handle);
/* Gets the length of the buffer required to save */
/***************************************************************************/
int32_t mz_zip_reader_save_all(void *handle, const char *destination_dir);
/* Save all files into a directory */
/***************************************************************************/
void mz_zip_reader_set_pattern(void *handle, const char *pattern, uint8_t ignore_case);
/* Sets the match pattern for entries in the zip file, if null all entries are matched */
void mz_zip_reader_set_password(void *handle, const char *password);
/* Sets the password required for extraction */
void mz_zip_reader_set_raw(void *handle, uint8_t raw);
/* Sets whether or not it should save the entry raw */
int32_t mz_zip_reader_get_raw(void *handle, uint8_t *raw);
/* Gets whether or not it should save the entry raw */
int32_t mz_zip_reader_get_zip_cd(void *handle, uint8_t *zip_cd);
/* Gets whether or not the archive has a zipped central directory */
int32_t mz_zip_reader_get_comment(void *handle, const char **comment);
/* Gets the comment for the central directory */
void mz_zip_reader_set_encoding(void *handle, int32_t encoding);
/* Sets whether or not it should support a special character encoding in zip file names. */
void mz_zip_reader_set_sign_required(void *handle, uint8_t sign_required);
/* Sets whether or not it a signature is required */
void mz_zip_reader_set_overwrite_cb(void *handle, void *userdata, mz_zip_reader_overwrite_cb cb);
/* Callback for what to do when a file is being overwritten */
void mz_zip_reader_set_password_cb(void *handle, void *userdata, mz_zip_reader_password_cb cb);
/* Callback for when a password is required and hasn't been set */
void mz_zip_reader_set_progress_cb(void *handle, void *userdata, mz_zip_reader_progress_cb cb);
/* Callback for extraction progress */
void mz_zip_reader_set_progress_interval(void *handle, uint32_t milliseconds);
/* Let at least milliseconds pass between calls to progress callback */
void mz_zip_reader_set_entry_cb(void *handle, void *userdata, mz_zip_reader_entry_cb cb);
/* Callback for zip file entries */
int32_t mz_zip_reader_get_zip_handle(void *handle, void **zip_handle);
/* Gets the underlying zip instance handle */
void* mz_zip_reader_create(void **handle);
/* Create new instance of zip reader */
void mz_zip_reader_delete(void **handle);
/* Delete instance of zip reader */
/***************************************************************************/
typedef int32_t (*mz_zip_writer_overwrite_cb)(void *handle, void *userdata, const char *path);
typedef int32_t (*mz_zip_writer_password_cb)(void *handle, void *userdata, mz_zip_file *file_info, char *password, int32_t max_password);
typedef int32_t (*mz_zip_writer_progress_cb)(void *handle, void *userdata, mz_zip_file *file_info, int64_t position);
typedef int32_t (*mz_zip_writer_entry_cb)(void *handle, void *userdata, mz_zip_file *file_info);
/***************************************************************************/
int32_t mz_zip_writer_is_open(void *handle);
/* Checks to see if the zip file is open */
int32_t mz_zip_writer_open(void *handle, void *stream);
/* Opens zip file from stream */
int32_t mz_zip_writer_open_file(void *handle, const char *path, int64_t disk_size, uint8_t append);
/* Opens zip file from a file path */
int32_t mz_zip_writer_open_file_in_memory(void *handle, const char *path);
/* Opens zip file from a file path into memory for faster access */
int32_t mz_zip_writer_close(void *handle);
/* Closes the zip file */
/***************************************************************************/
int32_t mz_zip_writer_entry_open(void *handle, mz_zip_file *file_info);
/* Opens an entry in the zip file for writing */
int32_t mz_zip_writer_entry_close(void *handle);
/* Closes entry in zip file */
int32_t mz_zip_writer_entry_write(void *handle, const void *buf, int32_t len);
/* Writes data into entry for zip */
/***************************************************************************/
int32_t mz_zip_writer_add(void *handle, void *stream, mz_stream_read_cb read_cb);
/* Writes all data to the currently open entry in the zip */
int32_t mz_zip_writer_add_process(void *handle, void *stream, mz_stream_read_cb read_cb);
/* Writes a portion of data to the currently open entry in the zip */
int32_t mz_zip_writer_add_info(void *handle, void *stream, mz_stream_read_cb read_cb, mz_zip_file *file_info);
/* Adds an entry to the zip based on the info */
int32_t mz_zip_writer_add_buffer(void *handle, void *buf, int32_t len, mz_zip_file *file_info);
/* Adds an entry to the zip with a memory buffer */
int32_t mz_zip_writer_add_file(void *handle, const char *path, const char *filename_in_zip);
/* Adds an entry to the zip from a file */
int32_t mz_zip_writer_add_path(void *handle, const char *path, const char *root_path, uint8_t include_path,
uint8_t recursive);
/* Enumerates a directory or pattern and adds entries to the zip */
int32_t mz_zip_writer_copy_from_reader(void *handle, void *reader);
/* Adds an entry from a zip reader instance */
/***************************************************************************/
void mz_zip_writer_set_password(void *handle, const char *password);
/* Password to use for encrypting files in the zip */
void mz_zip_writer_set_comment(void *handle, const char *comment);
/* Comment to use for the archive */
void mz_zip_writer_set_raw(void *handle, uint8_t raw);
/* Sets whether or not we should write the entry raw */
int32_t mz_zip_writer_get_raw(void *handle, uint8_t *raw);
/* Gets whether or not we should write the entry raw */
void mz_zip_writer_set_aes(void *handle, uint8_t aes);
/* Use aes encryption when adding files in zip */
void mz_zip_writer_set_compress_method(void *handle, uint16_t compress_method);
/* Sets the compression method when adding files in zip */
void mz_zip_writer_set_compress_level(void *handle, int16_t compress_level);
/* Sets the compression level when adding files in zip */
void mz_zip_writer_set_follow_links(void *handle, uint8_t follow_links);
/* Follow symbolic links when traversing directories and files to add */
void mz_zip_writer_set_store_links(void *handle, uint8_t store_links);
/* Store symbolic links in zip file */
void mz_zip_writer_set_zip_cd(void *handle, uint8_t zip_cd);
/* Sets whether or not central directory should be zipped */
int32_t mz_zip_writer_set_certificate(void *handle, const char *cert_path, const char *cert_pwd);
/* Sets the certificate and timestamp url to use for signing when adding files in zip */
void mz_zip_writer_set_overwrite_cb(void *handle, void *userdata, mz_zip_writer_overwrite_cb cb);
/* Callback for what to do when zip file already exists */
void mz_zip_writer_set_password_cb(void *handle, void *userdata, mz_zip_writer_password_cb cb);
/* Callback for ask if a password is required for adding */
void mz_zip_writer_set_progress_cb(void *handle, void *userdata, mz_zip_writer_progress_cb cb);
/* Callback for compression progress */
void mz_zip_writer_set_progress_interval(void *handle, uint32_t milliseconds);
/* Let at least milliseconds pass between calls to progress callback */
void mz_zip_writer_set_entry_cb(void *handle, void *userdata, mz_zip_writer_entry_cb cb);
/* Callback for zip file entries */
int32_t mz_zip_writer_get_zip_handle(void *handle, void **zip_handle);
/* Gets the underlying zip handle */
void* mz_zip_writer_create(void **handle);
/* Create new instance of zip writer */
void mz_zip_writer_delete(void **handle);
/* Delete instance of zip writer */
/***************************************************************************/
#ifdef __cplusplus
}
#endif
#endif