diff --git a/CHANGELOG.md b/CHANGELOG.md index c650053..8b23bbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ ## History +### 1.10.0 (June 3, 2017) - Nolan O'Brien + +- add convenience file-to-file compression/decompression functions in `NOZUtils.h` +- add CLI for ZipUtilities (called `noz`) + - NOTE: Zip Mode is not yet implemented +- fix NOZUnzipper file size measurement bug + ### 1.9.3 (Feb 20, 2017) - Nolan O'Brien - add checksum error code and record validation method to unzipper diff --git a/README.md b/README.md index 765eb44..ee6e83e 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ Alternatively you may use one of the following dependency managers: Add _ZipUtilities_ to your `Podfile` ```ruby -pod 'ZipUtilities', '~> 1.9.3' +pod 'ZipUtilities', '~> 1.10.0' ``` #### Carthage diff --git a/ZipUtilities.podspec b/ZipUtilities.podspec index 8f9de71..50292f1 100644 --- a/ZipUtilities.podspec +++ b/ZipUtilities.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "ZipUtilities" - s.version = "1.9.3" + s.version = "1.10.0" s.summary = "Zip Archiving, Unarchiving and Utilities in Objective-C" s.description = <<-DESC ZipUtilities, prefixed with NOZ for Nolan O'Brien ZipUtilities, is a library of zipping and unzipping utilities for iOS and Mac OS X. diff --git a/ZipUtilities.xcodeproj/project.pbxproj b/ZipUtilities.xcodeproj/project.pbxproj index ea61265..687edc1 100644 --- a/ZipUtilities.xcodeproj/project.pbxproj +++ b/ZipUtilities.xcodeproj/project.pbxproj @@ -45,10 +45,61 @@ 1C70520E1EBEA7A80071C2FF /* backward_references_hq.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C70520A1EBEA7A80071C2FF /* backward_references_hq.h */; }; 1C70520F1EBEA7A80071C2FF /* hash_longest_match64_inc.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C70520B1EBEA7A80071C2FF /* hash_longest_match64_inc.h */; }; 1C7052101EBEA7A80071C2FF /* hash_to_binary_tree_inc.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C70520C1EBEA7A80071C2FF /* hash_to_binary_tree_inc.h */; }; - 1C7052111EBEA87F0071C2FF /* backward_references_hq.c in Sources */ = {isa = PBXBuildFile; fileRef = 1C7052091EBEA7A80071C2FF /* backward_references_hq.c */; }; + 1C7052111EBEA87F0071C2FF /* backward_references_hq.c in Sources */ = {isa = PBXBuildFile; fileRef = 1C7052091EBEA7A80071C2FF /* backward_references_hq.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; 1C7052121EBEA87F0071C2FF /* backward_references_hq.c in Sources */ = {isa = PBXBuildFile; fileRef = 1C7052091EBEA7A80071C2FF /* backward_references_hq.c */; }; - 1C7052151EBEA92F0071C2FF /* dictionary_hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 1C7052131EBEA92B0071C2FF /* dictionary_hash.c */; }; + 1C7052151EBEA92F0071C2FF /* dictionary_hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 1C7052131EBEA92B0071C2FF /* dictionary_hash.c */; settings = {COMPILER_FLAGS = "-w -Xanalyzer -analyzer-disable-all-checks"; }; }; 1C7052161EBEA9300071C2FF /* dictionary_hash.c in Sources */ = {isa = PBXBuildFile; fileRef = 1C7052131EBEA92B0071C2FF /* dictionary_hash.c */; }; + 1C70521E1EBEBBF20071C2FF /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C70521D1EBEBBF20071C2FF /* main.m */; }; + 1C7052241EBEBC370071C2FF /* NSStream+NOZAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CD441BC1BBCDDA500F40FAB /* NSStream+NOZAdditions.m */; }; + 1C7052251EBEBC370071C2FF /* NOZSyncStepOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C3223811B780CC500DC0A33 /* NOZSyncStepOperation.m */; }; + 1C7052261EBEBC370071C2FF /* NOZCompressionLibrary.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CD3DA261DA2047D0007A693 /* NOZCompressionLibrary.m */; }; + 1C7052271EBEBC370071C2FF /* NOZRawCoders.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CCAC79C1B899804004AD418 /* NOZRawCoders.m */; }; + 1C7052281EBEBC370071C2FF /* NOZError.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C3223791B77BE9F00DC0A33 /* NOZError.m */; }; + 1C7052291EBEBC370071C2FF /* NOZZipEntry.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C0542321B7D7D57007CE7BA /* NOZZipEntry.m */; }; + 1C70522A1EBEBC370071C2FF /* NOZUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C6BF7991B740ACF00969629 /* NOZUtils.m */; }; + 1C70522B1EBEBC370071C2FF /* NSData+NOZAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C7634311BB6455700BBFECF /* NSData+NOZAdditions.m */; }; + 1C70522C1EBEBC370071C2FF /* NOZ_Project.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C6BF7B31B7476BB00969629 /* NOZ_Project.m */; }; + 1C70522D1EBEBC370071C2FF /* NOZUnzipper.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C05422E1B7BDDBA007CE7BA /* NOZUnzipper.m */; }; + 1C70522E1EBEBC370071C2FF /* NOZCompress.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C6BF78D1B74093B00969629 /* NOZCompress.m */; }; + 1C70522F1EBEBC370071C2FF /* NOZZipper.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C05422A1B7BDD97007CE7BA /* NOZZipper.m */; }; + 1C7052301EBEBC370071C2FF /* NOZDecompress.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C6BF7901B74095500969629 /* NOZDecompress.m */; }; + 1C7052311EBEBC370071C2FF /* NOZDeflateCoders.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CCAC79A1B8997F4004AD418 /* NOZDeflateCoders.m */; }; + 1C7052351EBEBC370071C2FF /* NOZCompression.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CCAC7961B890FAD004AD418 /* NOZCompression.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1C7052361EBEBC370071C2FF /* NOZDecoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C7634401BB6522800BBFECF /* NOZDecoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1C7052371EBEBC370071C2FF /* backward_references_hq.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C70520A1EBEA7A80071C2FF /* backward_references_hq.h */; }; + 1C7052381EBEBC370071C2FF /* NOZZipEntry.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C0542311B7D7D57007CE7BA /* NOZZipEntry.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1C7052391EBEBC370071C2FF /* NSData+NOZAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C7634301BB6455700BBFECF /* NSData+NOZAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1C70523A1EBEBC370071C2FF /* NOZCompress.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C6BF78C1B74093B00969629 /* NOZCompress.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1C70523B1EBEBC370071C2FF /* NOZDecompress.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C6BF78F1B74095500969629 /* NOZDecompress.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1C70523C1EBEBC370071C2FF /* NSStream+NOZAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CD441BB1BBCDDA500F40FAB /* NSStream+NOZAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1C70523D1EBEBC370071C2FF /* hash_to_binary_tree_inc.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C70520C1EBEA7A80071C2FF /* hash_to_binary_tree_inc.h */; }; + 1C70523E1EBEBC370071C2FF /* NOZError.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C3223781B77BE9F00DC0A33 /* NOZError.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1C70523F1EBEBC370071C2FF /* NOZ_Project.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C6BF7B21B7476BB00969629 /* NOZ_Project.h */; }; + 1C7052401EBEBC370071C2FF /* NOZCompressionLibrary.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CD3DA251DA2047D0007A693 /* NOZCompressionLibrary.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1C7052411EBEBC370071C2FF /* NOZUtils_Project.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CF2F7ED1B87ABE9005E7C77 /* NOZUtils_Project.h */; }; + 1C7052421EBEBC370071C2FF /* NOZZipper.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C0542291B7BDD97007CE7BA /* NOZZipper.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1C7052431EBEBC370071C2FF /* NOZSyncStepOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C3223801B780CC500DC0A33 /* NOZSyncStepOperation.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1C7052441EBEBC370071C2FF /* NOZEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C7634381BB64F2100BBFECF /* NOZEncoder.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1C7052451EBEBC370071C2FF /* module.modulemap in Headers */ = {isa = PBXBuildFile; fileRef = B3F87BF41CF4C08A00FBBFEF /* module.modulemap */; settings = {ATTRIBUTES = (Public, ); }; }; + 1C7052461EBEBC370071C2FF /* NOZUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C6BF7981B740ACF00969629 /* NOZUtils.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1C7052471EBEBC370071C2FF /* NOZUnzipper.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C05422D1B7BDDBA007CE7BA /* NOZUnzipper.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1C7052481EBEBC370071C2FF /* hash_longest_match64_inc.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C70520B1EBEA7A80071C2FF /* hash_longest_match64_inc.h */; }; + 1C7052491EBEBC370071C2FF /* ZipUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 4623A8321B9A828A00A56535 /* ZipUtilities.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 1C7052561EBEBD400071C2FF /* libbrotli-mac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B0455711DF8DBD600EBB706 /* libbrotli-mac.a */; }; + 1C7052571EBEBD400071C2FF /* libZipUtilities-mac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C70524D1EBEBC370071C2FF /* libZipUtilities-mac.a */; }; + 1C7052581EBEBD400071C2FF /* libzstd-mac.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8B0455691DF8DBA000EBB706 /* libzstd-mac.a */; }; + 1C70525B1EBF5FF00071C2FF /* NOZCLIDumpMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C70525A1EBF5FF00071C2FF /* NOZCLIDumpMode.m */; }; + 1C70525E1EBF635D0071C2FF /* NOZCLI.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C70525D1EBF635D0071C2FF /* NOZCLI.m */; }; + 1C70525F1EBF97110071C2FF /* NOZXAppleCompressionCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C19A2631BA4881D004E8D6C /* NOZXAppleCompressionCoder.m */; }; + 1C7052601EBF97110071C2FF /* NOZXBrotliCompressionCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B6E34C71DE36A2B004A35C7 /* NOZXBrotliCompressionCoder.m */; }; + 1C7052611EBF97110071C2FF /* NOZXZStandardCompressionCoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B3C0C6D1DDC1BA5000C7DE1 /* NOZXZStandardCompressionCoder.m */; }; + 1C7052631EBF97740071C2FF /* libcompression.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C7052621EBF97730071C2FF /* libcompression.tbd */; }; + 1C7052671EBF97940071C2FF /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C7052661EBF97940071C2FF /* libz.tbd */; }; + 1C70526A1EBFA58F0071C2FF /* NOZCLICompressMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C7052691EBFA58F0071C2FF /* NOZCLICompressMode.m */; }; + 1C70526D1EBFA5A80071C2FF /* NOZCLIDecompressMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C70526C1EBFA5A80071C2FF /* NOZCLIDecompressMode.m */; }; + 1C7052701EBFA5CA0071C2FF /* NOZCLIZipMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C70526F1EBFA5CA0071C2FF /* NOZCLIZipMode.m */; }; + 1C7052731EBFA5D60071C2FF /* NOZCLIUnzipMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C7052721EBFA5D60071C2FF /* NOZCLIUnzipMode.m */; }; + 1C7052791EC0DBA20071C2FF /* NOZCLIMethodMode.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C7052781EC0DBA20071C2FF /* NOZCLIMethodMode.m */; }; 1C7634321BB6455700BBFECF /* NSData+NOZAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C7634301BB6455700BBFECF /* NSData+NOZAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1C7634331BB6455700BBFECF /* NSData+NOZAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C7634301BB6455700BBFECF /* NSData+NOZAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; 1C7634341BB6455700BBFECF /* NSData+NOZAdditions.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C7634301BB6455700BBFECF /* NSData+NOZAdditions.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -299,6 +350,27 @@ remoteGlobalIDString = 1C6BF76F1B74086000969629; remoteInfo = ZipUtilities; }; + 1C7052501EBEBD380071C2FF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1C6BF7681B74086000969629 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 1C7052221EBEBC370071C2FF; + remoteInfo = "libZipUtilities-mac"; + }; + 1C7052521EBEBD380071C2FF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1C6BF7681B74086000969629 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8B0455681DF8DBA000EBB706; + remoteInfo = "libzstd-mac"; + }; + 1C7052541EBEBD380071C2FF /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 1C6BF7681B74086000969629 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 8B0455701DF8DBD600EBB706; + remoteInfo = "libbrotli-mac"; + }; 4623A83A1B9A828A00A56535 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 1C6BF7681B74086000969629 /* Project object */; @@ -388,6 +460,24 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 1C7052191EBEBBF20071C2FF /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; + 1C7052331EBEBC370071C2FF /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = "include/$(PRODUCT_NAME)"; + dstSubfolderSpec = 16; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 8B0455081DF8D81300EBB706 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -459,6 +549,27 @@ 1C70520B1EBEA7A80071C2FF /* hash_longest_match64_inc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hash_longest_match64_inc.h; path = Extra/brotli/enc/hash_longest_match64_inc.h; sourceTree = ""; }; 1C70520C1EBEA7A80071C2FF /* hash_to_binary_tree_inc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = hash_to_binary_tree_inc.h; path = Extra/brotli/enc/hash_to_binary_tree_inc.h; sourceTree = ""; }; 1C7052131EBEA92B0071C2FF /* dictionary_hash.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = dictionary_hash.c; path = Extra/brotli/enc/dictionary_hash.c; sourceTree = ""; }; + 1C70521B1EBEBBF20071C2FF /* noz */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = noz; sourceTree = BUILT_PRODUCTS_DIR; }; + 1C70521D1EBEBBF20071C2FF /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 1C70524D1EBEBC370071C2FF /* libZipUtilities-mac.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libZipUtilities-mac.a"; sourceTree = BUILT_PRODUCTS_DIR; }; + 1C7052591EBF5FF00071C2FF /* NOZCLIDumpMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NOZCLIDumpMode.h; sourceTree = ""; }; + 1C70525A1EBF5FF00071C2FF /* NOZCLIDumpMode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NOZCLIDumpMode.m; sourceTree = ""; }; + 1C70525C1EBF635D0071C2FF /* NOZCLI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NOZCLI.h; sourceTree = ""; }; + 1C70525D1EBF635D0071C2FF /* NOZCLI.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NOZCLI.m; sourceTree = ""; }; + 1C7052621EBF97730071C2FF /* libcompression.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libcompression.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libcompression.tbd; sourceTree = DEVELOPER_DIR; }; + 1C7052641EBF978A0071C2FF /* libdz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libdz.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libdz.tbd; sourceTree = DEVELOPER_DIR; }; + 1C7052661EBF97940071C2FF /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.12.sdk/usr/lib/libz.tbd; sourceTree = DEVELOPER_DIR; }; + 1C7052681EBFA58F0071C2FF /* NOZCLICompressMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NOZCLICompressMode.h; sourceTree = ""; }; + 1C7052691EBFA58F0071C2FF /* NOZCLICompressMode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NOZCLICompressMode.m; sourceTree = ""; }; + 1C70526B1EBFA5A80071C2FF /* NOZCLIDecompressMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NOZCLIDecompressMode.h; sourceTree = ""; }; + 1C70526C1EBFA5A80071C2FF /* NOZCLIDecompressMode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NOZCLIDecompressMode.m; sourceTree = ""; }; + 1C70526E1EBFA5CA0071C2FF /* NOZCLIZipMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NOZCLIZipMode.h; sourceTree = ""; }; + 1C70526F1EBFA5CA0071C2FF /* NOZCLIZipMode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NOZCLIZipMode.m; sourceTree = ""; }; + 1C7052711EBFA5D60071C2FF /* NOZCLIUnzipMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NOZCLIUnzipMode.h; sourceTree = ""; }; + 1C7052721EBFA5D60071C2FF /* NOZCLIUnzipMode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NOZCLIUnzipMode.m; sourceTree = ""; }; + 1C7052741EC0D8E50071C2FF /* NOZCLIModeProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NOZCLIModeProtocol.h; sourceTree = ""; }; + 1C7052771EC0DBA20071C2FF /* NOZCLIMethodMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NOZCLIMethodMode.h; sourceTree = ""; }; + 1C7052781EC0DBA20071C2FF /* NOZCLIMethodMode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NOZCLIMethodMode.m; sourceTree = ""; }; 1C7634301BB6455700BBFECF /* NSData+NOZAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+NOZAdditions.h"; sourceTree = ""; }; 1C7634311BB6455700BBFECF /* NSData+NOZAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+NOZAdditions.m"; sourceTree = ""; }; 1C7634381BB64F2100BBFECF /* NOZEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NOZEncoder.h; sourceTree = ""; }; @@ -641,6 +752,25 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 1C7052181EBEBBF20071C2FF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 1C7052671EBF97940071C2FF /* libz.tbd in Frameworks */, + 1C7052631EBF97740071C2FF /* libcompression.tbd in Frameworks */, + 1C7052561EBEBD400071C2FF /* libbrotli-mac.a in Frameworks */, + 1C7052571EBEBD400071C2FF /* libZipUtilities-mac.a in Frameworks */, + 1C7052581EBEBD400071C2FF /* libzstd-mac.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1C7052321EBEBC370071C2FF /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 4623A82A1B9A828A00A56535 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -747,6 +877,7 @@ 1C6B60D91B9CA2310068DCB0 /* ZipUtilities.podspec */, 1C667BF91BA1294F0028E5E7 /* Extra Encoders/Decoders */, 8B8D5ADE1DDD465C00037E0E /* ZipUtilitiesApp */, + 1C70521C1EBEBBF20071C2FF /* noz */, 4623A8A91B9A8AD300A56535 /* Frameworks */, 1C6BF7711B74086000969629 /* Products */, B3F87BF31CF4C08A00FBBFEF /* Support */, @@ -769,6 +900,8 @@ 8B0455381DF8D97900EBB706 /* libbrotli.a */, 8B0455691DF8DBA000EBB706 /* libzstd-mac.a */, 8B0455711DF8DBD600EBB706 /* libbrotli-mac.a */, + 1C70521B1EBEBBF20071C2FF /* noz */, + 1C70524D1EBEBC370071C2FF /* libZipUtilities-mac.a */, ); name = Products; sourceTree = ""; @@ -843,6 +976,29 @@ name = Project; sourceTree = ""; }; + 1C70521C1EBEBBF20071C2FF /* noz */ = { + isa = PBXGroup; + children = ( + 1C70521D1EBEBBF20071C2FF /* main.m */, + 1C70525C1EBF635D0071C2FF /* NOZCLI.h */, + 1C70525D1EBF635D0071C2FF /* NOZCLI.m */, + 1C7052681EBFA58F0071C2FF /* NOZCLICompressMode.h */, + 1C7052691EBFA58F0071C2FF /* NOZCLICompressMode.m */, + 1C70526B1EBFA5A80071C2FF /* NOZCLIDecompressMode.h */, + 1C70526C1EBFA5A80071C2FF /* NOZCLIDecompressMode.m */, + 1C7052591EBF5FF00071C2FF /* NOZCLIDumpMode.h */, + 1C70525A1EBF5FF00071C2FF /* NOZCLIDumpMode.m */, + 1C7052771EC0DBA20071C2FF /* NOZCLIMethodMode.h */, + 1C7052781EC0DBA20071C2FF /* NOZCLIMethodMode.m */, + 1C7052741EC0D8E50071C2FF /* NOZCLIModeProtocol.h */, + 1C7052711EBFA5D60071C2FF /* NOZCLIUnzipMode.h */, + 1C7052721EBFA5D60071C2FF /* NOZCLIUnzipMode.m */, + 1C70526E1EBFA5CA0071C2FF /* NOZCLIZipMode.h */, + 1C70526F1EBFA5CA0071C2FF /* NOZCLIZipMode.m */, + ); + path = noz; + sourceTree = ""; + }; 4613835B1B9AAA130076C8B5 /* iOS */ = { isa = PBXGroup; children = ( @@ -885,6 +1041,9 @@ 4623A8A91B9A8AD300A56535 /* Frameworks */ = { isa = PBXGroup; children = ( + 1C7052661EBF97940071C2FF /* libz.tbd */, + 1C7052641EBF978A0071C2FF /* libdz.tbd */, + 1C7052621EBF97730071C2FF /* libcompression.tbd */, 1C19A2601BA39284004E8D6C /* libcompression.tbd */, 1C19A25D1BA3925D004E8D6C /* libcompression.tbd */, 4613835B1B9AAA130076C8B5 /* iOS */, @@ -1140,6 +1299,34 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 1C7052341EBEBC370071C2FF /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 1C7052351EBEBC370071C2FF /* NOZCompression.h in Headers */, + 1C7052361EBEBC370071C2FF /* NOZDecoder.h in Headers */, + 1C7052371EBEBC370071C2FF /* backward_references_hq.h in Headers */, + 1C7052381EBEBC370071C2FF /* NOZZipEntry.h in Headers */, + 1C7052391EBEBC370071C2FF /* NSData+NOZAdditions.h in Headers */, + 1C70523A1EBEBC370071C2FF /* NOZCompress.h in Headers */, + 1C70523B1EBEBC370071C2FF /* NOZDecompress.h in Headers */, + 1C70523C1EBEBC370071C2FF /* NSStream+NOZAdditions.h in Headers */, + 1C70523D1EBEBC370071C2FF /* hash_to_binary_tree_inc.h in Headers */, + 1C70523E1EBEBC370071C2FF /* NOZError.h in Headers */, + 1C70523F1EBEBC370071C2FF /* NOZ_Project.h in Headers */, + 1C7052401EBEBC370071C2FF /* NOZCompressionLibrary.h in Headers */, + 1C7052411EBEBC370071C2FF /* NOZUtils_Project.h in Headers */, + 1C7052421EBEBC370071C2FF /* NOZZipper.h in Headers */, + 1C7052431EBEBC370071C2FF /* NOZSyncStepOperation.h in Headers */, + 1C7052441EBEBC370071C2FF /* NOZEncoder.h in Headers */, + 1C7052451EBEBC370071C2FF /* module.modulemap in Headers */, + 1C7052461EBEBC370071C2FF /* NOZUtils.h in Headers */, + 1C7052471EBEBC370071C2FF /* NOZUnzipper.h in Headers */, + 1C7052481EBEBC370071C2FF /* hash_longest_match64_inc.h in Headers */, + 1C7052491EBEBC370071C2FF /* ZipUtilities.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 4623A82B1B9A828A00A56535 /* Headers */ = { isa = PBXHeadersBuildPhase; buildActionMask = 2147483647; @@ -1254,6 +1441,44 @@ productReference = 1C6BF77B1B74086000969629 /* ZipUtilitiesTests.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + 1C70521A1EBEBBF20071C2FF /* noz */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1C70521F1EBEBBF20071C2FF /* Build configuration list for PBXNativeTarget "noz" */; + buildPhases = ( + 1C7052171EBEBBF20071C2FF /* Sources */, + 1C7052181EBEBBF20071C2FF /* Frameworks */, + 1C7052191EBEBBF20071C2FF /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + 1C7052511EBEBD380071C2FF /* PBXTargetDependency */, + 1C7052531EBEBD380071C2FF /* PBXTargetDependency */, + 1C7052551EBEBD380071C2FF /* PBXTargetDependency */, + ); + name = noz; + productName = noz; + productReference = 1C70521B1EBEBBF20071C2FF /* noz */; + productType = "com.apple.product-type.tool"; + }; + 1C7052221EBEBC370071C2FF /* libZipUtilities-mac */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1C70524A1EBEBC370071C2FF /* Build configuration list for PBXNativeTarget "libZipUtilities-mac" */; + buildPhases = ( + 1C7052231EBEBC370071C2FF /* Sources */, + 1C7052321EBEBC370071C2FF /* Frameworks */, + 1C7052331EBEBC370071C2FF /* CopyFiles */, + 1C7052341EBEBC370071C2FF /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "libZipUtilities-mac"; + productName = ZipUtilities; + productReference = 1C70524D1EBEBC370071C2FF /* libZipUtilities-mac.a */; + productType = "com.apple.product-type.library.static"; + }; 4623A82D1B9A828A00A56535 /* ZipUtilities */ = { isa = PBXNativeTarget; buildConfigurationList = 4623A8411B9A828A00A56535 /* Build configuration list for PBXNativeTarget "ZipUtilities" */; @@ -1438,6 +1663,10 @@ CreatedOnToolsVersion = 6.4; LastSwiftMigration = 0810; }; + 1C70521A1EBEBBF20071C2FF = { + CreatedOnToolsVersion = 8.3.2; + ProvisioningStyle = Automatic; + }; 4623A82D1B9A828A00A56535 = { CreatedOnToolsVersion = 6.4; DevelopmentTeam = BFWTTPG966; @@ -1486,17 +1715,19 @@ projectDirPath = ""; projectRoot = ""; targets = ( + 8B0455091DF8D81300EBB706 /* libzstd */, + 8B0455681DF8DBA000EBB706 /* libzstd-mac */, + 8B0455231DF8D97900EBB706 /* libbrotli */, + 8B0455701DF8DBD600EBB706 /* libbrotli-mac */, 1C6BF76F1B74086000969629 /* libZipUtilities */, - 1C6BF77A1B74086000969629 /* ZipUtilitiesTests */, + 1C7052221EBEBC370071C2FF /* libZipUtilities-mac */, 4623A82D1B9A828A00A56535 /* ZipUtilities */, - 4623A8371B9A828A00A56535 /* FrameworkTests */, 4623A84B1B9A82AF00A56535 /* OSXZipUtilities */, - 4623A8551B9A82AF00A56535 /* OSXFrameworkTests */, 8B8D5ADC1DDD465C00037E0E /* ZipUtilitiesApp */, - 8B0455091DF8D81300EBB706 /* libzstd */, - 8B0455231DF8D97900EBB706 /* libbrotli */, - 8B0455681DF8DBA000EBB706 /* libzstd-mac */, - 8B0455701DF8DBD600EBB706 /* libbrotli-mac */, + 1C6BF77A1B74086000969629 /* ZipUtilitiesTests */, + 4623A8371B9A828A00A56535 /* FrameworkTests */, + 4623A8551B9A82AF00A56535 /* OSXFrameworkTests */, + 1C70521A1EBEBBF20071C2FF /* noz */, ); }; /* End PBXProject section */ @@ -1634,6 +1865,45 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 1C7052171EBEBBF20071C2FF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1C7052791EC0DBA20071C2FF /* NOZCLIMethodMode.m in Sources */, + 1C70525F1EBF97110071C2FF /* NOZXAppleCompressionCoder.m in Sources */, + 1C7052601EBF97110071C2FF /* NOZXBrotliCompressionCoder.m in Sources */, + 1C70526D1EBFA5A80071C2FF /* NOZCLIDecompressMode.m in Sources */, + 1C70526A1EBFA58F0071C2FF /* NOZCLICompressMode.m in Sources */, + 1C7052611EBF97110071C2FF /* NOZXZStandardCompressionCoder.m in Sources */, + 1C70521E1EBEBBF20071C2FF /* main.m in Sources */, + 1C7052701EBFA5CA0071C2FF /* NOZCLIZipMode.m in Sources */, + 1C70525B1EBF5FF00071C2FF /* NOZCLIDumpMode.m in Sources */, + 1C7052731EBFA5D60071C2FF /* NOZCLIUnzipMode.m in Sources */, + 1C70525E1EBF635D0071C2FF /* NOZCLI.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 1C7052231EBEBC370071C2FF /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1C7052241EBEBC370071C2FF /* NSStream+NOZAdditions.m in Sources */, + 1C7052251EBEBC370071C2FF /* NOZSyncStepOperation.m in Sources */, + 1C7052261EBEBC370071C2FF /* NOZCompressionLibrary.m in Sources */, + 1C7052271EBEBC370071C2FF /* NOZRawCoders.m in Sources */, + 1C7052281EBEBC370071C2FF /* NOZError.m in Sources */, + 1C7052291EBEBC370071C2FF /* NOZZipEntry.m in Sources */, + 1C70522A1EBEBC370071C2FF /* NOZUtils.m in Sources */, + 1C70522B1EBEBC370071C2FF /* NSData+NOZAdditions.m in Sources */, + 1C70522C1EBEBC370071C2FF /* NOZ_Project.m in Sources */, + 1C70522D1EBEBC370071C2FF /* NOZUnzipper.m in Sources */, + 1C70522E1EBEBC370071C2FF /* NOZCompress.m in Sources */, + 1C70522F1EBEBC370071C2FF /* NOZZipper.m in Sources */, + 1C7052301EBEBC370071C2FF /* NOZDecompress.m in Sources */, + 1C7052311EBEBC370071C2FF /* NOZDeflateCoders.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 4623A8291B9A828A00A56535 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1829,6 +2099,21 @@ target = 1C6BF76F1B74086000969629 /* libZipUtilities */; targetProxy = 1C6BF77D1B74086000969629 /* PBXContainerItemProxy */; }; + 1C7052511EBEBD380071C2FF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 1C7052221EBEBC370071C2FF /* libZipUtilities-mac */; + targetProxy = 1C7052501EBEBD380071C2FF /* PBXContainerItemProxy */; + }; + 1C7052531EBEBD380071C2FF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 8B0455681DF8DBA000EBB706 /* libzstd-mac */; + targetProxy = 1C7052521EBEBD380071C2FF /* PBXContainerItemProxy */; + }; + 1C7052551EBEBD380071C2FF /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 8B0455701DF8DBD600EBB706 /* libbrotli-mac */; + targetProxy = 1C7052541EBEBD380071C2FF /* PBXContainerItemProxy */; + }; 4623A83B1B9A828A00A56535 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 4623A82D1B9A828A00A56535 /* ZipUtilities */; @@ -2074,6 +2359,63 @@ }; name = Release; }; + 1C7052201EBEBBF20071C2FF /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CODE_SIGN_IDENTITY = "-"; + DEBUG_INFORMATION_FORMAT = dwarf; + HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/Extra"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Debug; + }; + 1C7052211EBEBBF20071C2FF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CODE_SIGN_IDENTITY = "-"; + HEADER_SEARCH_PATHS = "$(PROJECT_DIR)/Extra"; + MACOSX_DEPLOYMENT_TARGET = 10.10; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + }; + name = Release; + }; + 1C70524B1EBEBC370071C2FF /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXECUTABLE_PREFIX = ""; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + OTHER_LDFLAGS = "-ObjC"; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = include/ZipUtilities; + SDKROOT = macosx; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 1C70524C1EBEBC370071C2FF /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + EXECUTABLE_PREFIX = ""; + IPHONEOS_DEPLOYMENT_TARGET = 6.0; + OTHER_LDFLAGS = "-ObjC"; + PRIVATE_HEADERS_FOLDER_PATH = ""; + PRODUCT_NAME = "$(TARGET_NAME)"; + PUBLIC_HEADERS_FOLDER_PATH = include/ZipUtilities; + SDKROOT = macosx; + SKIP_INSTALL = YES; + }; + name = Release; + }; 4623A8421B9A828A00A56535 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -2451,6 +2793,24 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 1C70521F1EBEBBF20071C2FF /* Build configuration list for PBXNativeTarget "noz" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1C7052201EBEBBF20071C2FF /* Debug */, + 1C7052211EBEBBF20071C2FF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1C70524A1EBEBC370071C2FF /* Build configuration list for PBXNativeTarget "libZipUtilities-mac" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1C70524B1EBEBC370071C2FF /* Debug */, + 1C70524C1EBEBC370071C2FF /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 4623A8411B9A828A00A56535 /* Build configuration list for PBXNativeTarget "ZipUtilities" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/ZipUtilities.xcodeproj/xcshareddata/xcschemes/ZipUtilitiesApp.xcscheme b/ZipUtilities.xcodeproj/xcshareddata/xcschemes/ZipUtilitiesApp.xcscheme new file mode 100644 index 0000000..4c38aa6 --- /dev/null +++ b/ZipUtilities.xcodeproj/xcshareddata/xcschemes/ZipUtilitiesApp.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ZipUtilities.xcodeproj/xcshareddata/xcschemes/libZipUtilities-mac.xcscheme b/ZipUtilities.xcodeproj/xcshareddata/xcschemes/libZipUtilities-mac.xcscheme new file mode 100644 index 0000000..bcb065d --- /dev/null +++ b/ZipUtilities.xcodeproj/xcshareddata/xcschemes/libZipUtilities-mac.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ZipUtilities.xcodeproj/xcshareddata/xcschemes/libbrotli-mac.xcscheme b/ZipUtilities.xcodeproj/xcshareddata/xcschemes/libbrotli-mac.xcscheme new file mode 100644 index 0000000..f0ecc49 --- /dev/null +++ b/ZipUtilities.xcodeproj/xcshareddata/xcschemes/libbrotli-mac.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ZipUtilities.xcodeproj/xcshareddata/xcschemes/libbrotli.xcscheme b/ZipUtilities.xcodeproj/xcshareddata/xcschemes/libbrotli.xcscheme new file mode 100644 index 0000000..b8f7e23 --- /dev/null +++ b/ZipUtilities.xcodeproj/xcshareddata/xcschemes/libbrotli.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ZipUtilities.xcodeproj/xcshareddata/xcschemes/libzstd-mac.xcscheme b/ZipUtilities.xcodeproj/xcshareddata/xcschemes/libzstd-mac.xcscheme new file mode 100644 index 0000000..0a57e58 --- /dev/null +++ b/ZipUtilities.xcodeproj/xcshareddata/xcschemes/libzstd-mac.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ZipUtilities.xcodeproj/xcshareddata/xcschemes/libzstd.xcscheme b/ZipUtilities.xcodeproj/xcshareddata/xcschemes/libzstd.xcscheme new file mode 100644 index 0000000..feadd22 --- /dev/null +++ b/ZipUtilities.xcodeproj/xcshareddata/xcschemes/libzstd.xcscheme @@ -0,0 +1,80 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ZipUtilities.xcodeproj/xcshareddata/xcschemes/noz.xcscheme b/ZipUtilities.xcodeproj/xcshareddata/xcschemes/noz.xcscheme new file mode 100644 index 0000000..1a8b745 --- /dev/null +++ b/ZipUtilities.xcodeproj/xcshareddata/xcschemes/noz.xcscheme @@ -0,0 +1,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ZipUtilities/Info.plist b/ZipUtilities/Info.plist index 8a41c11..537079c 100644 --- a/ZipUtilities/Info.plist +++ b/ZipUtilities/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.9.3 + 1.10.0 CFBundleSignature ???? CFBundleVersion diff --git a/ZipUtilities/NOZCompress.m b/ZipUtilities/NOZCompress.m index 2f6d821..90eb987 100644 --- a/ZipUtilities/NOZCompress.m +++ b/ZipUtilities/NOZCompress.m @@ -41,7 +41,7 @@ typedef NS_ENUM(NSUInteger, NOZCompressStep) static NSArray * __nonnull NOZEntriesFromDirectory(NSString * __nonnull directoryPath); -#define kCancelledError NOZError(NOZErrorCodeCompressCancelled, nil) +#define kCancelledError NOZErrorCreate(NOZErrorCodeCompressCancelled, nil) @interface NOZCompressDelegateInternal : NSObject @property (nonatomic, readonly, nonnull) NOZCompressCompletionBlock completionBlock; @@ -237,7 +237,7 @@ - (NSError *)private_prepareProgress { _totalUncompressedBytes = _request.totalSizeOfUncompressedEntries; if (!_totalUncompressedBytes) { - return NOZError(NOZErrorCodeCompressNoEntriesToCompress, nil); + return NOZErrorCreate(NOZErrorCodeCompressNoEntriesToCompress, nil); } return nil; @@ -257,14 +257,14 @@ - (NSError *)private_openFile if (error) { _zipper = nil; - return NOZError(NOZErrorCodeCompressFailedToOpenNewZipFile, @{ @"path" : _request.destinationPath ?: @"", NSUnderlyingErrorKey : error }); + return NOZErrorCreate(NOZErrorCodeCompressFailedToOpenNewZipFile, @{ @"path" : _request.destinationPath ?: @"", NSUnderlyingErrorKey : error }); } return nil; } - (NSError *)private_addEntries { - NSError *error = NOZError(NOZErrorCodeCompressNoEntriesToCompress, nil); + NSError *error = NOZErrorCreate(NOZErrorCodeCompressNoEntriesToCompress, nil); NSArray> *entries = _request.entries; // deep copy for (id entry in entries) { @autoreleasepool { @@ -289,7 +289,7 @@ - (NSError *)private_closeFile if ([_zipper closeAndReturnError:&error]) { _zipper = nil; } else { - return NOZError(NOZErrorCodeCompressFailedToFinalizeNewZipFile, @{ NSUnderlyingErrorKey : error }); return error; + return NOZErrorCreate(NOZErrorCodeCompressFailedToFinalizeNewZipFile, @{ NSUnderlyingErrorKey : error }); return error; } } return nil; @@ -301,10 +301,10 @@ - (NSError *)private_addEntry:(id)entry { // Start if (!entry.name) { - return NOZError(NOZErrorCodeCompressMissingEntryName, @{ @"entry" : entry }); + return NOZErrorCreate(NOZErrorCodeCompressMissingEntryName, @{ @"entry" : entry }); } if (!entry.canBeZipped) { - return NOZError(NOZErrorCodeCompressEntryCannotBeZipped, @{ @"entry" : entry }); + return NOZErrorCreate(NOZErrorCodeCompressEntryCannotBeZipped, @{ @"entry" : entry }); } NSError *error = nil; @@ -324,7 +324,7 @@ - (NSError *)private_addEntry:(id)entry #pragma clang diagnostic pop if (error) { - return NOZError(NOZErrorCodeCompressFailedToAppendEntryToZip, @{ @"entry" : entry, NSUnderlyingErrorKey : error }); + return NOZErrorCreate(NOZErrorCodeCompressFailedToAppendEntryToZip, @{ @"entry" : entry, NSUnderlyingErrorKey : error }); } return nil; diff --git a/ZipUtilities/NOZDecompress.m b/ZipUtilities/NOZDecompress.m index 01e07c1..3f46072 100644 --- a/ZipUtilities/NOZDecompress.m +++ b/ZipUtilities/NOZDecompress.m @@ -39,7 +39,7 @@ typedef NS_ENUM(NSUInteger, NOZDecompressStep) NOZDecompressStepClose, }; -#define kCancelledError NOZError(NOZErrorCodeDecompressCancelled, nil) +#define kCancelledError NOZErrorCreate(NOZErrorCodeDecompressCancelled, nil) @interface NOZDecompressResult () @property (nonatomic, copy) NSString *destinationDirectoryPath; @@ -246,7 +246,7 @@ - (NSError *)private_openFile NSError *error = nil; _unzipper = [[NOZUnzipper alloc] initWithZipFile:_request.sourceFilePath]; if (![_unzipper openAndReturnError:&error]) { - return NOZError(NOZErrorCodeDecompressFailedToOpenZipArchive, @{ NSUnderlyingErrorKey : error }); + return NOZErrorCreate(NOZErrorCodeDecompressFailedToOpenZipArchive, @{ NSUnderlyingErrorKey : error }); } _sanitizedDestinationDirectoryPath = _request.destinationDirectoryPath; @@ -256,7 +256,7 @@ - (NSError *)private_openFile _sanitizedDestinationDirectoryPath = [_sanitizedDestinationDirectoryPath stringByStandardizingPath]; if (![[NSFileManager defaultManager] createDirectoryAtPath:_sanitizedDestinationDirectoryPath withIntermediateDirectories:YES attributes:nil error:NULL]) { - return NOZError(NOZErrorCodeDecompressFailedToCreateDestinationDirectory, @{ @"destinationDirectoryPath" : (_request.destinationDirectoryPath ?: [NSNull null]) }); + return NOZErrorCreate(NOZErrorCodeDecompressFailedToCreateDestinationDirectory, @{ @"destinationDirectoryPath" : (_request.destinationDirectoryPath ?: [NSNull null]) }); } return nil; @@ -268,7 +268,7 @@ - (NSError *)private_readExpectedSizes NSError *error; if (![_unzipper readCentralDirectoryAndReturnError:&error]) { - return NOZError(NOZErrorCodeDecompressFailedToReadArchiveEntry, @{ NSUnderlyingErrorKey : error }); + return NOZErrorCreate(NOZErrorCodeDecompressFailedToReadArchiveEntry, @{ NSUnderlyingErrorKey : error }); } _expectedEntryCount = _unzipper.centralDirectory.recordCount; diff --git a/ZipUtilities/NOZError.h b/ZipUtilities/NOZError.h index 50916d6..ca3d3c2 100644 --- a/ZipUtilities/NOZError.h +++ b/ZipUtilities/NOZError.h @@ -176,7 +176,10 @@ NS_INLINE BOOL NOZErrorCodeIsInErrorPage(NOZErrorCode code, NOZErrorPage page) //! Is the given _code_ an Unzip Error #define NOZErrorCodeIsUnzipError(code) NOZErrorCodeIsInErrorPage(code, NOZErrorPageUnzip) -//! Convenience macro for creating an `NOZErrorDomain` `NSError` -#define NOZErrorCreate(errCode, ui) [NSError errorWithDomain:NOZErrorDomain code:(errCode) userInfo:(ui)] +//! Convenience function for creating an `NOZErrorDomain` `NSError` +FOUNDATION_EXTERN NSError *NOZErrorCreate(NOZErrorCode code, NSDictionary * __nullable ui); + +//! Get a string value for the an error code +FOUNDATION_EXTERN NSString *NOZErrorCodeToString(NOZErrorCode code); NS_ASSUME_NONNULL_END diff --git a/ZipUtilities/NOZError.m b/ZipUtilities/NOZError.m index 2944250..ad7090a 100644 --- a/ZipUtilities/NOZError.m +++ b/ZipUtilities/NOZError.m @@ -28,3 +28,71 @@ #import "NOZError.h" NSString * const NOZErrorDomain = @"NOZErrorDomain"; + +NSString *NOZErrorCodeToString(NOZErrorCode code) +{ + +#define SWITCH_CASE(caseCode) \ + case caseCode : \ + return @"" #caseCode ; + + switch (code) { + SWITCH_CASE(NOZErrorCodeCompressUnknown); + SWITCH_CASE(NOZErrorCodeCompressFailedToOpenNewZipFile); + SWITCH_CASE(NOZErrorCodeCompressNoEntriesToCompress); + SWITCH_CASE(NOZErrorCodeCompressMissingEntryName); + SWITCH_CASE(NOZErrorCodeCompressEntryCannotBeZipped); + SWITCH_CASE(NOZErrorCodeCompressFailedToAppendEntryToZip); + SWITCH_CASE(NOZErrorCodeCompressFailedToFinalizeNewZipFile); + SWITCH_CASE(NOZErrorCodeCompressCancelled); + + SWITCH_CASE(NOZErrorCodeDecompressUnknown); + SWITCH_CASE(NOZErrorCodeDecompressFailedToOpenZipArchive); + SWITCH_CASE(NOZErrorCodeDecompressFailedToCreateDestinationDirectory); + SWITCH_CASE(NOZErrorCodeDecompressFailedToReadArchiveEntry); + SWITCH_CASE(NOZErrorCodeDecompressFailedToCreateUnarchivedFile); + SWITCH_CASE(NOZErrorCodeDecompressCannotOverwriteExistingFile); + SWITCH_CASE(NOZErrorCodeDecompressCancelled); + + SWITCH_CASE(NOZErrorCodeZipUnknown); + SWITCH_CASE(NOZErrorCodeZipInvalidFilePath); + SWITCH_CASE(NOZErrorCodeZipCannotOpenExistingZip); + SWITCH_CASE(NOZErrorCodeZipCannotCreateZip); + SWITCH_CASE(NOZErrorCodeZipFailedToCloseCurrentEntry); + SWITCH_CASE(NOZErrorCodeZipFailedToWriteZip); + SWITCH_CASE(NOZErrorCodeZipCannotOpenNewEntry); + SWITCH_CASE(NOZErrorCodeZipDoesNotSupportZip64); + SWITCH_CASE(NOZErrorCodeZipDoesNotSupportCompressionMethod); + SWITCH_CASE(NOZErrorCodeZipFailedToWriteEntry); + SWITCH_CASE(NOZErrorCodeZipFailedToCompressEntry); + + SWITCH_CASE(NOZErrorCodeUnzipUnknown); + SWITCH_CASE(NOZErrorCodeUnzipCannotOpenZip); + SWITCH_CASE(NOZErrorCodeUnzipInvalidZipFile); + SWITCH_CASE(NOZErrorCodeUnzipMustOpenUnzipperBeforeManipulating); + SWITCH_CASE(NOZErrorCodeUnzipCannotReadCentralDirectory); + SWITCH_CASE(NOZErrorCodeUnzipCentralDirectoryRecordCountsDoNotAlign); + SWITCH_CASE(NOZErrorCodeUnzipCentralDirectoryRecordsDoNotCompleteWithEOCDRecord); + SWITCH_CASE(NOZErrorCodeUnzipMultipleDiskZipArchivesNotSupported); + SWITCH_CASE(NOZErrorCodeUnzipCouldNotReadCentralDirectoryRecord); + SWITCH_CASE(NOZErrorCodeUnzipUnsupportedRecordVersion); + SWITCH_CASE(NOZErrorCodeUnzipDecompressionMethodNotSupported); + SWITCH_CASE(NOZErrorCodeUnzipDecompressionEncryptionNotSupported); + SWITCH_CASE(NOZErrorCodeUnzipIndexOutOfBounds); + SWITCH_CASE(NOZErrorCodeUnzipCannotReadFileEntry); + SWITCH_CASE(NOZErrorCodeUnzipCannotDecompressFileEntry); + SWITCH_CASE(NOZErrorCodeUnzipChecksumMissmatch); + SWITCH_CASE(NOZErrorCodeUnzipFailedToDecompressEntry); + } + +#undef SWITCH_CASE + + return @"Unknown"; +} + +NSError *NOZErrorCreate(NOZErrorCode code, NSDictionary *ui) +{ + NSMutableDictionary *mUserInfo = [NSMutableDictionary dictionaryWithDictionary:ui]; + mUserInfo[@"errorCodeString"] = NOZErrorCodeToString(code); + return [NSError errorWithDomain:NOZErrorDomain code:code userInfo:mUserInfo]; +} diff --git a/ZipUtilities/NOZUnzipper.m b/ZipUtilities/NOZUnzipper.m index 1447db3..f1c1bb4 100644 --- a/ZipUtilities/NOZUnzipper.m +++ b/ZipUtilities/NOZUnzipper.m @@ -111,18 +111,22 @@ - (instancetype)init - (BOOL)openAndReturnError:(out NSError **)error { - NSError *stackError = NOZError(NOZErrorCodeUnzipCannotOpenZip, @{ @"zipFilePath" : [self zipFilePath] ?: [NSNull null] }); + NSError *stackError = NOZErrorCreate(NOZErrorCodeUnzipCannotOpenZip, @{ @"zipFilePath" : [self zipFilePath] ?: [NSNull null] }); _standardizedFilePath = [self.zipFilePath stringByStandardizingPath]; if (_standardizedFilePath.UTF8String) { _internal.file = fopen(_standardizedFilePath.UTF8String, "r"); if (_internal.file) { - _internal.endOfFilePosition = fseeko(_internal.file, 0, SEEK_END); + if (0 == fseeko(_internal.file, 0, SEEK_END)) { + _internal.endOfFilePosition = ftello(_internal.file); + } else { + _internal.endOfFilePosition = (off_t)[[[NSFileManager defaultManager] attributesOfItemAtPath:_standardizedFilePath error:nil] fileSize]; + } _internal.endOfCentralDirectorySignaturePosition = [self private_locateSignature:NOZMagicNumberEndOfCentralDirectoryRecord]; if (_internal.endOfCentralDirectorySignaturePosition) { return YES; } else { [self closeAndReturnError:NULL]; - stackError = NOZError(NOZErrorCodeUnzipInvalidZipFile, @{ @"zipFilePath" : self.zipFilePath }); + stackError = NOZErrorCreate(NOZErrorCodeUnzipInvalidZipFile, @{ @"zipFilePath" : self.zipFilePath }); } } } @@ -153,7 +157,7 @@ - (NOZCentralDirectory *)readCentralDirectoryAndReturnError:(out NSError **)erro }); if (!_internal.file || !_internal.endOfCentralDirectorySignaturePosition) { - stackError = NOZError(NOZErrorCodeUnzipMustOpenUnzipperBeforeManipulating, nil); + stackError = NOZErrorCreate(NOZErrorCodeUnzipMustOpenUnzipperBeforeManipulating, nil); return nil; } @@ -161,12 +165,12 @@ - (NOZCentralDirectory *)readCentralDirectoryAndReturnError:(out NSError **)erro @autoreleasepool { if (![cd readEndOfCentralDirectoryRecordAtPosition:_internal.endOfCentralDirectorySignaturePosition inFile:_internal.file]) { - stackError = NOZError(NOZErrorCodeUnzipCannotReadCentralDirectory, nil); + stackError = NOZErrorCreate(NOZErrorCodeUnzipCannotReadCentralDirectory, nil); return nil; } if (![cd readCentralDirectoryEntriesWithFile:_internal.file]) { - stackError = NOZError(NOZErrorCodeUnzipCannotReadCentralDirectory, nil); + stackError = NOZErrorCreate(NOZErrorCodeUnzipCannotReadCentralDirectory, nil); return nil; } @@ -183,7 +187,7 @@ - (NOZCentralDirectoryRecord *)readRecordAtIndex:(NSUInteger)index error:(out NS { if (index >= _centralDirectory.recordCount) { if (error) { - *error = NOZError(NOZErrorCodeUnzipIndexOutOfBounds, nil); + *error = NOZErrorCreate(NOZErrorCodeUnzipIndexOutOfBounds, nil); } return nil; } @@ -214,24 +218,24 @@ - (BOOL)enumerateByteRangesOfRecord:(NOZCentralDirectoryRecord *)record @autoreleasepool { if (!_internal.file) { - stackError = NOZError(NOZErrorCodeUnzipMustOpenUnzipperBeforeManipulating, nil); + stackError = NOZErrorCreate(NOZErrorCodeUnzipMustOpenUnzipperBeforeManipulating, nil); return NO; } if (![record isOwnedByCentralDirectory:_centralDirectory]) { - stackError = NOZError(NOZErrorCodeUnzipCannotReadFileEntry, nil); + stackError = NOZErrorCreate(NOZErrorCodeUnzipCannotReadFileEntry, nil); return NO; } if (![self private_locateCompressedDataOfRecord:record]) { - stackError = NOZError(NOZErrorCodeUnzipCannotReadFileEntry, nil); + stackError = NOZErrorCreate(NOZErrorCodeUnzipCannotReadFileEntry, nil); return NO; } do { NOZErrorCode code = [record validate]; if (0 != code) { - stackError = NOZError(code, nil); + stackError = NOZErrorCreate(code, nil); return NO; } } while (0); @@ -241,7 +245,7 @@ - (BOOL)enumerateByteRangesOfRecord:(NOZCentralDirectoryRecord *)record _currentUnzipping.offsetToFirstByte = ftello(_internal.file); if (_currentUnzipping.offsetToFirstByte == -1) { - stackError = NOZError(NOZErrorCodeUnzipCannotReadFileEntry, nil); + stackError = NOZErrorCreate(NOZErrorCodeUnzipCannotReadFileEntry, nil); return NO; } @@ -264,12 +268,12 @@ - (BOOL)enumerateByteRangesOfRecord:(NOZCentralDirectoryRecord *)record }); if (!_currentDecoder || !_currentDecoderContext) { - stackError = NOZError(NOZErrorCodeUnzipDecompressionMethodNotSupported, nil); + stackError = NOZErrorCreate(NOZErrorCodeUnzipDecompressionMethodNotSupported, nil); return NO; } if (![_currentDecoder initializeDecoderContext:_currentDecoderContext]) { - stackError = NOZError(NOZErrorCodeUnzipFailedToDecompressEntry, nil); + stackError = NOZErrorCreate(NOZErrorCodeUnzipFailedToDecompressEntry, nil); return NO; } @@ -281,7 +285,7 @@ - (BOOL)enumerateByteRangesOfRecord:(NOZCentralDirectoryRecord *)record } if (![_currentDecoder finalizeDecoderContext:_currentDecoderContext]) { - stackError = NOZError(NOZErrorCodeUnzipFailedToDecompressEntry, nil); + stackError = NOZErrorCreate(NOZErrorCodeUnzipFailedToDecompressEntry, nil); return NO; } } @@ -545,7 +549,7 @@ - (BOOL)private_deflateWithProgressBlock:(NOZProgressBlock)progressBlock __block BOOL success = YES; noz_defer(^{ if (!success && error && !*error) { - *error = NOZError(NOZErrorCodeUnzipCannotDecompressFileEntry, nil); + *error = NOZErrorCreate(NOZErrorCodeUnzipCannotDecompressFileEntry, nil); } }); @@ -592,7 +596,7 @@ - (BOOL)private_deflateWithProgressBlock:(NOZProgressBlock)progressBlock if (_currentUnzipping.crc32 != _currentUnzipping.entry->fileDescriptor.crc32) { success = NO; if (error) { - *error = NOZError(NOZErrorCodeUnzipChecksumMissmatch, nil); + *error = NOZErrorCreate(NOZErrorCodeUnzipChecksumMissmatch, nil); } return NO; @@ -625,7 +629,7 @@ - (instancetype)init - (instancetype)initWithKnownFileSize:(SInt64)fileSize { if (self = [super init]) { - _totalUncompressedSize = fileSize; + _totalCompressedSize = fileSize; } return self; } @@ -786,7 +790,7 @@ - (BOOL)validateCentralDirectoryAndReturnError:(NSError **)error __block NSDictionary *userInfo = nil; noz_defer(^{ if (code && error) { - *error = NOZError(code, userInfo); + *error = NOZErrorCreate(code, userInfo); } }); diff --git a/ZipUtilities/NOZUtils.h b/ZipUtilities/NOZUtils.h index eaf2df5..46ab493 100644 --- a/ZipUtilities/NOZUtils.h +++ b/ZipUtilities/NOZUtils.h @@ -25,7 +25,16 @@ // SOFTWARE. // -#import +#import "NOZCompression.h" + +@protocol NOZEncoder; +@protocol NOZDecoder; //! Block for providing progress to. Used by `NOZCompressOperation` and `NOZDecompressOperation`. -typedef void(^NOZProgressBlock)(int64_t totalBytes, int64_t bytesComplete, int64_t bytesCompletedThisPass, BOOL *abort); +typedef void(^NOZProgressBlock)(int64_t totalBytes, int64_t bytesComplete, int64_t bytesCompletedThisPass, BOOL * __nonnull abort); + +//! Convenience function to compress a file without ZIP archive wrapping +FOUNDATION_EXTERN BOOL NOZEncodeFile(NSString * __nonnull sourceFile, NSString * __nonnull destinationFile, id __nonnull encoder, NOZCompressionLevel level, NSError * __nullable * __nullable error); + +//! Convenience function to decompress a file without ZIP archive wrapping +FOUNDATION_EXTERN BOOL NOZDecodeFile(NSString * __nonnull sourceFile, NSString * __nonnull destinationFile, id __nonnull decoder, NSError * __nullable * __nullable error); diff --git a/ZipUtilities/NOZUtils.m b/ZipUtilities/NOZUtils.m index 67d09a1..58a164e 100644 --- a/ZipUtilities/NOZUtils.m +++ b/ZipUtilities/NOZUtils.m @@ -25,6 +25,7 @@ // SOFTWARE. // +#import "NOZ_Project.h" #import "NOZUtils_Project.h" #include "zlib.h" @@ -83,3 +84,196 @@ void NOZFileEntryCleanFree(NOZFileEntryT* entry) entry = nextEntry; } } + +static BOOL _NOZOpenInputOutputFiles(NSString * __nonnull sourceFilePath, FILE * __nullable * __nonnull sourceFile, NSString * __nonnull destinationFilePath, FILE * __nonnull * __nullable destinationFile, NSError * __nullable * __nullable error); +static BOOL _NOZOpenInputOutputFiles(NSString *sourceFilePath, FILE **sourceFile, NSString *destinationFilePath, FILE **destinationFile, NSError **error) +{ + NSFileManager *fm = [NSFileManager defaultManager]; + __block FILE *inFile = NULL; + __block FILE *outFile = NULL; + __block NSError *stackError = nil; + noz_defer(^{ + if (stackError) { + if (error) { + *error = stackError; + } + if (inFile) { + fclose(inFile); + } + if (outFile) { + fclose(outFile); + [fm removeItemAtPath:destinationFilePath error:NULL]; + } + } else { + if (inFile) { + *sourceFile = inFile; + } + if (outFile) { + *destinationFile = outFile; + } + } + }); + + inFile = fopen(sourceFilePath.UTF8String, "r"); + if (!inFile) { + stackError = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:@{ @"sourceFile" : sourceFilePath ?: [NSNull null] }]; + return NO; + } + + if (![fm createDirectoryAtPath:[destinationFilePath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:&stackError]) { + return NO; + } + + if ([fm fileExistsAtPath:destinationFilePath]) { + stackError = [NSError errorWithDomain:NSPOSIXErrorDomain code:EEXIST userInfo:@{ @"destinationFile" : destinationFilePath }]; + return NO; + } + + outFile = fopen(destinationFilePath.UTF8String, "w"); + if (!outFile) { + stackError = [NSError errorWithDomain:NSPOSIXErrorDomain code:errno userInfo:@{ @"destinationFile" : destinationFilePath }]; + return NO; + } + + return YES; +} + +BOOL NOZEncodeFile(NSString *sourceFile, NSString *destinationFile, id encoder, NOZCompressionLevel level, NSError **error) +{ + NSFileManager *fm = [NSFileManager defaultManager]; + __block FILE *uncompressedFile = NULL; + __block FILE *compressedFile = NULL; + __block NSError *stackError = nil; + noz_defer(^{ + if (stackError) { + if (error) { + *error = stackError; + } + } + if (uncompressedFile) { + fclose(uncompressedFile); + } + if (compressedFile) { + fclose(compressedFile); + if (stackError) { + [fm removeItemAtPath:destinationFile error:NULL]; + } + } + }); + + if (!encoder) { + stackError = [NSError errorWithDomain:NSPOSIXErrorDomain code:EINVAL userInfo:NULL]; + return NO; + } + + if (!_NOZOpenInputOutputFiles(sourceFile, &uncompressedFile, destinationFile, &compressedFile, &stackError)) { + return NO; + } + + id context = [encoder createContextWithBitFlags:0 compressionLevel:level flushCallback:^BOOL(id theEncoder, id theContext, const Byte *bufferToFlush, size_t length) { + if (length != fwrite(bufferToFlush, 1, length, compressedFile)) { + return NO; + } + return YES; + }]; + + if (![encoder initializeEncoderContext:context]) { + stackError = [NSError errorWithDomain:NSPOSIXErrorDomain code:EIO userInfo:nil]; + return NO; + } + + do { + const size_t bufferSize = 1024 * 1024; + Byte buffer[bufferSize]; + while (!feof(uncompressedFile)) { + const size_t bytesRead = fread(buffer, 1, bufferSize, uncompressedFile); + if (bytesRead < bufferSize && ferror(uncompressedFile)) { + stackError = [NSError errorWithDomain:NSPOSIXErrorDomain code:EIO userInfo:nil]; + return NO; + } + if (![encoder encodeBytes:buffer length:bytesRead context:context]) { + stackError = [NSError errorWithDomain:NSPOSIXErrorDomain code:EIO userInfo:nil]; + return NO; + } + } + } while (0); + + if (![encoder finalizeEncoderContext:context]) { + stackError = [NSError errorWithDomain:NSPOSIXErrorDomain code:EIO userInfo:nil]; + return NO; + } + + fflush(compressedFile); + + return YES; +} + +BOOL NOZDecodeFile(NSString *sourceFile, NSString *destinationFile, id decoder, NSError **error) +{ + NSFileManager *fm = [NSFileManager defaultManager]; + __block FILE *uncompressedFile = NULL; + __block FILE *compressedFile = NULL; + __block NSError *stackError = nil; + noz_defer(^{ + if (stackError) { + if (error) { + *error = stackError; + } + } + if (uncompressedFile) { + fclose(uncompressedFile); + } + if (compressedFile) { + fclose(compressedFile); + if (stackError) { + [fm removeItemAtPath:destinationFile error:NULL]; + } + } + }); + + if (!decoder) { + stackError = [NSError errorWithDomain:NSPOSIXErrorDomain code:EINVAL userInfo:NULL]; + return NO; + } + + if (!_NOZOpenInputOutputFiles(sourceFile, &compressedFile, destinationFile, &uncompressedFile, &stackError)) { + return NO; + } + + id context = [decoder createContextForDecodingWithBitFlags:0 flushCallback:^BOOL(id theDecoder, id theContext, const Byte *bufferToFlush, size_t length) { + if (length != fwrite(bufferToFlush, 1, length, uncompressedFile)) { + return NO; + } + return YES; + }]; + + if (![decoder initializeDecoderContext:context]) { + stackError = [NSError errorWithDomain:NSPOSIXErrorDomain code:EIO userInfo:nil]; + return NO; + } + + do { + const size_t bufferSize = 1024 * 1024; + Byte buffer[bufferSize]; + while (!context.hasFinished) { + const size_t bytesRead = fread(buffer, 1, bufferSize, compressedFile); + if (ferror(compressedFile)) { + stackError = [NSError errorWithDomain:NSPOSIXErrorDomain code:EIO userInfo:nil]; + return NO; + } + if (![decoder decodeBytes:buffer length:bytesRead context:context]) { + stackError = [NSError errorWithDomain:NSPOSIXErrorDomain code:EIO userInfo:nil]; + return NO; + } + } + } while (0); + + if (![decoder finalizeDecoderContext:context]) { + stackError = [NSError errorWithDomain:NSPOSIXErrorDomain code:EIO userInfo:nil]; + return NO; + } + + fflush(uncompressedFile); + + return YES; +} diff --git a/ZipUtilities/NOZZipper.m b/ZipUtilities/NOZZipper.m index b11d28f..68d9866 100644 --- a/ZipUtilities/NOZZipper.m +++ b/ZipUtilities/NOZZipper.m @@ -134,7 +134,7 @@ - (BOOL)openWithMode:(NOZZipperMode)mode error:(out NSError **)error }); if (!_standardizedZipFilePath.UTF8String) { - stackError = NOZError(NOZErrorCodeZipInvalidFilePath, _zipFilePath ? @{ @"zipFilePath" : _zipFilePath } : nil); + stackError = NOZErrorCreate(NOZErrorCodeZipInvalidFilePath, _zipFilePath ? @{ @"zipFilePath" : _zipFilePath } : nil); return NO; } @@ -154,7 +154,7 @@ - (BOOL)openWithMode:(NOZZipperMode)mode error:(out NSError **)error // { // fopenMode = "r+"; // if (![fm fileExistsAtPath:_standardizedZipFilePath]) { -// stackError = NOZError(NOZErrorCodeZipCannotOpenExistingZip, @{ @"zipFilePath" : _zipFilePath }); +// stackError = NOZErrorCreate(NOZErrorCodeZipCannotOpenExistingZip, @{ @"zipFilePath" : _zipFilePath }); // return NO; // } // break; @@ -163,7 +163,7 @@ - (BOOL)openWithMode:(NOZZipperMode)mode error:(out NSError **)error default: { if ([fm fileExistsAtPath:_standardizedZipFilePath]) { - stackError = NOZError(NOZErrorCodeZipCannotCreateZip, @{ @"zipFilePath" : _zipFilePath }); + stackError = NOZErrorCreate(NOZErrorCodeZipCannotCreateZip, @{ @"zipFilePath" : _zipFilePath }); return NO; } break; @@ -172,8 +172,8 @@ - (BOOL)openWithMode:(NOZZipperMode)mode error:(out NSError **)error _internal.file = fopen(_standardizedZipFilePath.UTF8String, fopenMode); if (!_internal.file) { - // stackError = NOZError((NOZZipperModeOpenExisting == mode) ? NOZErrorCodeZipCannotOpenExistingZip : NOZErrorCodeZipCannotCreateZip, @{ @"zipFilePath" : _zipFilePath }); - stackError = NOZError(NOZErrorCodeZipCannotCreateZip, @{ @"zipFilePath" : _zipFilePath }); + // stackError = NOZErrorCreate((NOZZipperModeOpenExisting == mode) ? NOZErrorCodeZipCannotOpenExistingZip : NOZErrorCodeZipCannotCreateZip, @{ @"zipFilePath" : _zipFilePath }); + stackError = NOZErrorCreate(NOZErrorCodeZipCannotCreateZip, @{ @"zipFilePath" : _zipFilePath }); return NO; } noz_defer(^{ @@ -260,7 +260,7 @@ - (BOOL)private_forciblyClose:(BOOL)forceClose error:(out NSError **)error [self private_freeLinkedList]; return NO; } else if (!forceClose && NULL != _internal.currentEntry) { - stackError = NOZError(NOZErrorCodeZipFailedToCloseCurrentEntry, nil); + stackError = NOZErrorCreate(NOZErrorCodeZipFailedToCloseCurrentEntry, nil); return NO; } @@ -286,12 +286,12 @@ - (BOOL)private_forciblyClose:(BOOL)forceClose error:(out NSError **)error }); if (![self private_writeCentralDirectoryRecords]) { - stackError = NOZError(NOZErrorCodeZipFailedToWriteZip, nil); + stackError = NOZErrorCreate(NOZErrorCodeZipFailedToWriteZip, nil); return NO; } if (![self private_writeEndOfCentralDirectoryRecord]) { - stackError = NOZError(NOZErrorCodeZipFailedToWriteZip, nil); + stackError = NOZErrorCreate(NOZErrorCodeZipFailedToWriteZip, nil); return NO; } @@ -302,9 +302,9 @@ - (BOOL)private_openEntry:(id)entry error:(out NSError **)error { __block BOOL errorEncountered = NO; - noz_defer(^{ if (errorEncountered && error) { *error = NOZError(NOZErrorCodeZipCannotOpenNewEntry, nil); } }); + noz_defer(^{ if (errorEncountered && error) { *error = NOZErrorCreate(NOZErrorCodeZipCannotOpenNewEntry, nil); } }); - NSUInteger nameSize = [entry.name lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; + const NSUInteger nameSize = [entry.name lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; if (nameSize > UINT16_MAX || nameSize == 0) { errorEncountered = YES; return NO; @@ -356,7 +356,7 @@ - (BOOL)private_openEntry:(id)entry }]; if (!_currentEncoder || !_currentEncoderContext) { if (error) { - *error = NOZError(NOZErrorCodeZipDoesNotSupportCompressionMethod, @{ @"method" : @(_internal.currentEntry->fileHeader.compressionMethod) }); + *error = NOZErrorCreate(NOZErrorCodeZipDoesNotSupportCompressionMethod, @{ @"method" : @(_internal.currentEntry->fileHeader.compressionMethod) }); } _currentEncoder = nil; _internal.currentEntry = NULL; @@ -389,7 +389,7 @@ - (BOOL)private_writeEntry:(id)entry if ((*abort)) { *error = [NSError errorWithDomain:NSPOSIXErrorDomain code:ECANCELED userInfo:nil]; } else if (!success && !*error) { - *error = NOZError(NOZErrorCodeZipFailedToWriteEntry, nil); + *error = NOZErrorCreate(NOZErrorCodeZipFailedToWriteEntry, nil); } } }); @@ -468,7 +468,7 @@ - (BOOL)private_closeCurrentOpenEntryAndReturnError:(out NSError **)error _internal.currentEntry = NULL; if (!success && error) { - *error = NOZError(NOZErrorCodeZipFailedToCloseCurrentEntry, nil); + *error = NOZErrorCreate(NOZErrorCodeZipFailedToCloseCurrentEntry, nil); } return success; @@ -488,10 +488,7 @@ - (BOOL)private_flushWriteBuffer:(const Byte*)buffer length:(size_t)length BOOL success = YES; - size_t bytesWritten = fwrite(buffer, - 1, - length, - _internal.file); + const size_t bytesWritten = fwrite(buffer, 1, length, _internal.file); if (bytesWritten != length) { success = NO; } @@ -520,14 +517,14 @@ - (BOOL)private_populateRecordsForCurrentOpenEntryWithEntry:(id UINT32_MAX || (ftello(_internal.file) - _internal.beginBytePosition) > (UINT32_MAX - UINT8_MAX)) { if (error) { - *error = NOZError(NOZErrorCodeZipDoesNotSupportZip64, nil); + *error = NOZErrorCreate(NOZErrorCodeZipDoesNotSupportZip64, nil); } return NO; } @@ -601,7 +598,7 @@ - (BOOL)private_populateRecordsForCurrentOpenEntryWithEntry:(idfileHeader; - SInt64 oldPosition = ftello(_internal.file); + const SInt64 oldPosition = ftello(_internal.file); if (writeSig) { PRIVATE_WRITE(NOZMagicNumberLocalFileHeader); @@ -617,8 +614,8 @@ - (BOOL)private_writeLocalFileHeaderForEntry:(NOZFileEntryT *)entry signature:(B PRIVATE_WRITE(header->nameSize); PRIVATE_WRITE(header->extraFieldSize); - SInt64 diff = ftello(_internal.file) - oldPosition; - SInt64 expectedBytesWritten = 30; + const SInt64 diff = ftello(_internal.file) - oldPosition; + const SInt64 expectedBytesWritten = 30; return (diff == expectedBytesWritten); } @@ -637,14 +634,14 @@ - (BOOL)private_writeLocalFileHeaderForCurrentEntryAndReturnError:(out NSError * } if (success && entry->fileHeader.extraFieldSize > 0) { - size_t bytesWritten = fwrite(entry->extraField, 1, (size_t)entry->fileHeader.extraFieldSize, _internal.file); + const size_t bytesWritten = fwrite(entry->extraField, 1, (size_t)entry->fileHeader.extraFieldSize, _internal.file); if (bytesWritten != (size_t)entry->fileHeader.extraFieldSize) { success = NO; } } if (!success && error) { - *error = NOZError(NOZErrorCodeZipCannotOpenNewEntry, nil); + *error = NOZErrorCreate(NOZErrorCodeZipCannotOpenNewEntry, nil); } return success; @@ -661,7 +658,7 @@ - (BOOL)private_finishEncoding _currentEncoderContext = nil; }); - BOOL success = [_currentEncoder finalizeEncoderContext:_currentEncoderContext]; + const BOOL success = [_currentEncoder finalizeEncoderContext:_currentEncoderContext]; if (_currentEncoderContext.encodedDataWasText) { _internal.currentEntry->centralDirectoryRecord.internalFileAttributes |= (1 << 0) /* text */; } @@ -673,7 +670,7 @@ - (BOOL)private_writeLocalFileDescriptorForEntry:(NOZFileEntryT *)entry signatur BOOL success = YES; NOZLocalFileDescriptorT *fileDescriptor = &entry->fileDescriptor; - SInt64 oldPosition = ftello(_internal.file); + const SInt64 oldPosition = ftello(_internal.file); if (writeSignature) { PRIVATE_WRITE(NOZMagicNumberDataDescriptor); @@ -715,7 +712,7 @@ - (BOOL)private_writeCentralDirectoryRecord:(NOZFileEntryT *)entry _internal.endOfCentralDirectoryRecord.archiveStartToCentralDirectoryStartOffset = (UInt32)(ftello(_internal.file) - _internal.beginBytePosition); } - SInt64 oldPosition = ftello(_internal.file); + const SInt64 oldPosition = ftello(_internal.file); SInt64 expectedBytesWritten = 46; NOZCentralDirectoryFileRecordT *record = &entry->centralDirectoryRecord; @@ -748,7 +745,7 @@ - (BOOL)private_writeCentralDirectoryRecord:(NOZFileEntryT *)entry fwrite(entry->comment, 1, (size_t)record->commentSize, _internal.file); } - SInt64 bytesWritten = (ftello(_internal.file) - oldPosition); + const SInt64 bytesWritten = (ftello(_internal.file) - oldPosition); _internal.endOfCentralDirectoryRecord.centralDirectorySize += bytesWritten; if (bytesWritten != expectedBytesWritten) { return NO; @@ -766,7 +763,7 @@ - (BOOL)private_writeCentralDirectoryRecord:(NOZFileEntryT *)entry - (BOOL)private_writeEndOfCentralDirectoryRecord { - SInt64 oldPosition = ftello(_internal.file); + const SInt64 oldPosition = ftello(_internal.file); SInt64 expectedBytesWritten = 22; PRIVATE_WRITE(NOZMagicNumberEndOfCentralDirectoryRecord); @@ -783,7 +780,7 @@ - (BOOL)private_writeEndOfCentralDirectoryRecord fwrite(_internal.comment, 1, (size_t)_internal.endOfCentralDirectoryRecord.commentSize, _internal.file); } - SInt64 bytesWritten = ftello(_internal.file) - oldPosition; + const SInt64 bytesWritten = ftello(_internal.file) - oldPosition; return bytesWritten == expectedBytesWritten; } diff --git a/ZipUtilities/NOZ_Project.h b/ZipUtilities/NOZ_Project.h index 39c4e74..c5d0eaf 100644 --- a/ZipUtilities/NOZ_Project.h +++ b/ZipUtilities/NOZ_Project.h @@ -79,15 +79,6 @@ NS_INLINE void noz_deferFunc(__strong noz_defer_block_t __nonnull * __nonnull bl actualBlock(); } -#pragma mark Error - -#import "NOZError.h" - -NS_INLINE NSError * __nonnull NOZError(NOZErrorCode code, NSDictionary * __nullable ui) -{ - return [NSError errorWithDomain:NOZErrorDomain code:code userInfo:ui]; -} - #pragma mark DOS Time FOUNDATION_EXTERN void noz_dos_date_from_NSDate(NSDate *__nullable dateObject, UInt16*__nonnull dateOut, UInt16*__nonnull timeOut); diff --git a/ZipUtilities/OSX-Info.plist b/ZipUtilities/OSX-Info.plist index e7df435..c8fbff4 100644 --- a/ZipUtilities/OSX-Info.plist +++ b/ZipUtilities/OSX-Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType FMWK CFBundleShortVersionString - 1.9.3 + 1.10.0 CFBundleSignature ???? CFBundleVersion diff --git a/noz/NOZCLI.h b/noz/NOZCLI.h new file mode 100644 index 0000000..5f9137a --- /dev/null +++ b/noz/NOZCLI.h @@ -0,0 +1,48 @@ +// +// NOZCLI.h +// ZipUtilities +// +// Created by Nolan O'Brien on 5/7/17. +// Copyright © 2017 NSProgrammer. All rights reserved. +// + +#import + +#import + +@class MethodInfo; + +FOUNDATION_EXTERN int NOZCLI_main(NSString *exe, NSString *exeDir, NSString *currentDir, NSArray *args); +FOUNDATION_EXTERN void NOZCLI_printUsage(NSString *exe); + +FOUNDATION_EXTERN void NOZCLI_registerExtraEncoders(void); + +FOUNDATION_EXTERN void NOZCLI_printError(NSError *error); +FOUNDATION_EXTERN NSString *NOZCLI_normalizedPath(NSString *envPath, NSString *fileArg); +FOUNDATION_EXTERN double NOZCLI_computeCompressionRatio(long long uncompressedBytes, long long compressedBytes); + +FOUNDATION_EXTERN MethodInfo *NOZCLI_lookupMethod(NOZCompressionMethod method); +FOUNDATION_EXTERN MethodInfo *NOZCLI_lookupMethodByName(NSString *method); + +FOUNDATION_EXTERN NSArray *NOZCLI_allMethods(void); +FOUNDATION_EXTERN NSArray *NOZCLI_allUnsupportedMethods(void); +FOUNDATION_EXTERN NSArray *NOZCLI_allDefaultMethods(void); +FOUNDATION_EXTERN NSArray *NOZCLI_allExtendedMethods(void); + +FOUNDATION_EXTERN NSArray *NOZCLI_allModes(void); + +@interface MethodInfo : NSObject + +@property (nonatomic, copy, readonly) NSString *name; +@property (nonatomic, readonly) NOZCompressionMethod method; +@property (nonatomic, readonly) NSUInteger levels; +@property (nonatomic, readonly) NSUInteger defaultLevel; + +@property (nonatomic, readonly) id encoder; +@property (nonatomic, readonly) id decoder; +@property (nonatomic, readonly, getter=isDefaultCodec) BOOL defaultCodec; + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +@end diff --git a/noz/NOZCLI.m b/noz/NOZCLI.m new file mode 100644 index 0000000..2438f98 --- /dev/null +++ b/noz/NOZCLI.m @@ -0,0 +1,312 @@ +// +// NOZCLI.m +// ZipUtilities +// +// Created by Nolan O'Brien on 5/7/17. +// Copyright © 2017 NSProgrammer. All rights reserved. +// + +#import "NOZCLI.h" + +#import "NOZCLICompressMode.h" +#import "NOZCLIDecompressMode.h" +#import "NOZCLIDumpMode.h" +#import "NOZCLIMethodMode.h" +#import "NOZCLIUnzipMode.h" +#import "NOZCLIZipMode.h" + +#import "NOZXAppleCompressionCoder.h" +#import "NOZXBrotliCompressionCoder.h" +#import "NOZXZStandardCompressionCoder.h" + +#define kMethodBrotli (101) +#define kMethodZStandard (102) + +@implementation MethodInfo + ++ (instancetype)methodInfoWithName:(NSString *)name method:(NOZCompressionMethod)method levels:(NSUInteger)levels defaultLevel:(NSUInteger)defaultLevel encoder:(id)encoder decoder:(id)decoder isDefault:(BOOL)defaultEncoder +{ + return [[self alloc] initWithName:name method:method levels:levels defaultLevel:defaultLevel encoder:encoder decoder:decoder isDefault:defaultEncoder]; +} + +- (instancetype)initWithName:(NSString *)name method:(NOZCompressionMethod)method levels:(NSUInteger)levels defaultLevel:(NSUInteger)defaultLevel encoder:(id)encoder decoder:(id)decoder isDefault:(BOOL)defaultEncoder +{ + if (self = [super init]) { + _name = [name copy]; + _method = method; + _levels = levels; + _defaultLevel = defaultLevel; + _defaultCodec = defaultEncoder; + _encoder = encoder; + _decoder = decoder; + } + return self; +} + +- (NSString *)description +{ + NSString *codecInfo = nil; + if (_method == NOZCompressionMethodNone) { + codecInfo = @"Default"; + } else if (!_encoder || !_decoder) { + codecInfo = @"Unsupported"; + } else if (_defaultCodec) { + codecInfo = @"Default"; + } else { + codecInfo = @"Extended"; + } + + return [NSString stringWithFormat:@"<%@: %p, name=\"%@\", methodEnum=%u, levels=%tu, codec=%@>", NSStringFromClass([self class]), self, _name, (unsigned int)_method, _levels, codecInfo]; +} + +@end + +#define METHOD(theName, theMethod, theLevels, theDefaultLevel, theEncoder, theDecoder, theIsDefault) \ +[MethodInfo methodInfoWithName:(theName) method:(theMethod) levels:(theLevels) defaultLevel:(theDefaultLevel) encoder:(theEncoder) decoder:(theDecoder) isDefault:(theIsDefault)] + +#define ADD_METHOD(theArray, theName, theMethod, theIsDefault) \ +do { \ + NOZCompressionMethod the_method = (theMethod); \ + id the_encoder = [[NOZCompressionLibrary sharedInstance] encoderForMethod:the_method]; \ + id the_decoder = [[NOZCompressionLibrary sharedInstance] decoderForMethod:the_method]; \ + if (!the_encoder || !the_decoder) { \ + the_encoder = nil; \ + the_decoder = nil; \ + } \ + NSUInteger the_levels = [the_encoder respondsToSelector:@selector(numberOfCompressionLevels)] ? [the_encoder numberOfCompressionLevels] : 0; \ + NSUInteger the_defaultLevel = [the_encoder respondsToSelector:@selector(defaultCompressionLevel)] ? [the_encoder defaultCompressionLevel] : 0; \ + [(theArray) addObject:METHOD((theName), the_method, the_levels, the_defaultLevel, the_encoder, the_decoder, (theIsDefault))]; \ +} while (0) + +#define UNS_ADD_METHOD(theArray, theName, theMethod) \ +do { \ + NOZCompressionMethod the_method = (theMethod); \ + id the_encoder = [[NOZCompressionLibrary sharedInstance] encoderForMethod:the_method]; \ + id the_decoder = [[NOZCompressionLibrary sharedInstance] decoderForMethod:the_method]; \ + if (the_encoder && the_decoder) { \ + break; \ + } \ + [(theArray) addObject:METHOD((theName), the_method, 0, 0, nil, nil, NO)]; \ +} while (0) + +int NOZCLI_main(NSString *exe, NSString *exeDir, NSString *currentDir, NSArray *args) +{ + if (args.count == 0) { + return -1; + } + + NOZCLI_registerExtraEncoders(); + + NSString *modeFlag = args[0]; + args = [args subarrayWithRange:NSMakeRange(1, args.count - 1)]; + + NSArray *modes = NOZCLI_allModes(); + + for (Class mode in modes) { + if ([modeFlag isEqualToString:[mode modeFlag]]) { + id info = [mode infoFromArgs:args environmentPath:currentDir]; + return [mode run:info]; + } + } + + return -1; +} + +void NOZCLI_printUsage(NSString *exe) +{ + if (exe) { + exe = @"noz"; + } + + printf("%s is the ZipUtilities CLI\n\n", exe.UTF8String); + + NSArray *modes = NOZCLI_allModes(); + + for (Class mode in modes) { + NSString *modeDescription = [NSString stringWithFormat:@"%@ mode:\n\t%@ %@ %@", [mode modeName], exe, [mode modeFlag], [mode modeExecutionDescription]]; + printf("%s\n", modeDescription.UTF8String); + } + + printf("%s", "\n"); + + for (Class mode in modes) { + NSUInteger count = [mode modeExtraArgumentsSectionCount]; + if (count > 0) { + for (NSUInteger i = 0; i < count; i++) { + NSString *name = [mode modeExtraArgumentsSectionName:i]; + NSArray *items = [mode modeExtraArgumentsSectionDescriptions:i]; + printf("%s:\n-------------------------------\n", name.UTF8String); + for (NSString *item in items) { + printf("\t%s\n", item.UTF8String); + } + printf("%s", "\n"); + } + } + } +} + +NSArray *NOZCLI_allModes() +{ + return @[ + [NOZCLIMethodMode class], + [NOZCLIDumpMode class], + [NOZCLICompressMode class], + [NOZCLIDecompressMode class], + [NOZCLIZipMode class], + [NOZCLIUnzipMode class], + ]; +} + +void NOZCLI_printError(NSError *error) +{ + NSString *errorString = [NSString stringWithFormat:@"ERROR: %@", error]; + printf("%s\n", errorString.UTF8String); +} + +NSString *NOZCLI_normalizedPath(NSString *envPath, NSString *fileArg) +{ + if (fileArg) { + if ([fileArg hasPrefix:@"/"]) { + // leave as-is + } else if ([fileArg hasPrefix:@"~"]) { + fileArg = [fileArg stringByExpandingTildeInPath]; + } else { + fileArg = [envPath stringByAppendingPathComponent:fileArg]; + } + } + + return fileArg; +} + +double NOZCLI_computeCompressionRatio(long long uncompressedBytes, long long compressedBytes) +{ + double ratio; + if (uncompressedBytes > 0 && compressedBytes > 0) { + ratio = ((double)uncompressedBytes / (double)compressedBytes); + } else { + ratio = NAN; + } + return ratio; +} + +void NOZCLI_registerExtraEncoders(void) +{ + NOZCompressionLibrary *library = [NOZCompressionLibrary sharedInstance]; + + if ([NOZXAppleCompressionCoder isSupported]) { + // Apple's Compression Lib is only supported on iOS 9+ and Mac OS X 10.11+ + + // LZMA + [library setEncoder:[NOZXAppleCompressionCoder encoderWithAlgorithm:COMPRESSION_LZMA] + forMethod:NOZCompressionMethodLZMA]; + [library setDecoder:[NOZXAppleCompressionCoder decoderWithAlgorithm:COMPRESSION_LZMA] + forMethod:NOZCompressionMethodLZMA]; + + // LZ4 + [library setEncoder:[NOZXAppleCompressionCoder encoderWithAlgorithm:COMPRESSION_LZ4] + forMethod:(NOZCompressionMethod)COMPRESSION_LZ4]; + [library setDecoder:[NOZXAppleCompressionCoder decoderWithAlgorithm:COMPRESSION_LZ4] + forMethod:(NOZCompressionMethod)COMPRESSION_LZ4]; + + // Apple LZFSE - the new hotness for compression from Apple + [library setEncoder:[NOZXAppleCompressionCoder encoderWithAlgorithm:COMPRESSION_LZFSE] + forMethod:(NOZCompressionMethod)COMPRESSION_LZFSE]; + [library setDecoder:[NOZXAppleCompressionCoder decoderWithAlgorithm:COMPRESSION_LZFSE] + forMethod:(NOZCompressionMethod)COMPRESSION_LZFSE]; + } + + [library setEncoder:[NOZXBrotliCompressionCoder encoder] + forMethod:kMethodBrotli]; + [library setDecoder:[NOZXBrotliCompressionCoder decoder] + forMethod:kMethodBrotli]; + + [library setEncoder:[NOZXZStandardCompressionCoder encoder] + forMethod:kMethodZStandard]; + [library setDecoder:[NOZXZStandardCompressionCoder decoder] + forMethod:kMethodZStandard]; +} + +NSArray *NOZCLI_allMethods() +{ + NSMutableArray *methods = [[NSMutableArray alloc] init]; + [methods addObjectsFromArray:NOZCLI_allDefaultMethods()]; + [methods addObjectsFromArray:NOZCLI_allExtendedMethods()]; + [methods addObjectsFromArray:NOZCLI_allUnsupportedMethods()]; + return methods; +} + +MethodInfo *NOZCLI_lookupMethod(NOZCompressionMethod method) +{ + for (MethodInfo *info in NOZCLI_allMethods()) { + if (info.method == method) { + return info; + } + } + return nil; +} + +MethodInfo *NOZCLI_lookupMethodByName(NSString *method) +{ + for (MethodInfo *info in NOZCLI_allMethods()) { + if ([info.name isEqualToString:method]) { + return info; + } + } + return nil; +} + +NSArray *NOZCLI_allUnsupportedMethods() +{ + NSMutableArray *methods = [[NSMutableArray alloc] init]; + + UNS_ADD_METHOD(methods, @"Shrink", NOZCompressionMethodShrink); + UNS_ADD_METHOD(methods, @"Reduce #1", NOZCompressionMethodReduce1); + UNS_ADD_METHOD(methods, @"Reduce #2", NOZCompressionMethodReduce2); + UNS_ADD_METHOD(methods, @"Reduce #3", NOZCompressionMethodReduce3); + UNS_ADD_METHOD(methods, @"Reduce #4", NOZCompressionMethodReduce4); + UNS_ADD_METHOD(methods, @"Implode", NOZCompressionMethodImplode); + UNS_ADD_METHOD(methods, @"*PKWare Reserved*", NOZCompressionMethodReserved7); + UNS_ADD_METHOD(methods, @"Deflate", NOZCompressionMethodDeflate); + UNS_ADD_METHOD(methods, @"Deflate64", NOZCompressionMethodDeflate64); + UNS_ADD_METHOD(methods, @"IBM TERSE (old)", NOZCompressionMethodIBMTERSEOld); + UNS_ADD_METHOD(methods, @"*PKWare Reserved*", NOZCompressionMethodReserved11); + UNS_ADD_METHOD(methods, @"BZip2", NOZCompressionMethodBZip2); + UNS_ADD_METHOD(methods, @"*PKWare Reserved*", NOZCompressionMethodReserved13); + UNS_ADD_METHOD(methods, @"LZMA", NOZCompressionMethodLZMA); + UNS_ADD_METHOD(methods, @"*PKWare Reserved*", NOZCompressionMethodReserved15); + UNS_ADD_METHOD(methods, @"*PKWare Reserved*", NOZCompressionMethodReserved16); + UNS_ADD_METHOD(methods, @"*PKWare Reserved*", NOZCompressionMethodReserved17); + UNS_ADD_METHOD(methods, @"IBM TERSE (new)", NOZCompressionMethodIBMTERSENew); + UNS_ADD_METHOD(methods, @"LZ77", NOZCompressionMethodLZ77); + + UNS_ADD_METHOD(methods, @"WAV Pack", NOZCompressionMethodWAVPack); + UNS_ADD_METHOD(methods, @"PPM v1 rev1", NOZCompressionMethodPPMv1rev1); + + return methods; +} + +NSArray *NOZCLI_allDefaultMethods() +{ + NSMutableArray *methods = [[NSMutableArray alloc] init]; + + [methods addObject:METHOD(@"None", NOZCompressionMethodNone, 0, 0, nil, nil, YES)]; + ADD_METHOD(methods, @"Deflate", NOZCompressionMethodDeflate, YES); + + return methods; +} + +NSArray *NOZCLI_allExtendedMethods() +{ + NSMutableArray *methods = [[NSMutableArray alloc] init]; + + ADD_METHOD(methods, @"ZStandard", kMethodZStandard, NO); + ADD_METHOD(methods, @"Brotli", kMethodBrotli, NO); + + if ([NOZXAppleCompressionCoder isSupported]) { + ADD_METHOD(methods, @"LZMA", NOZCompressionMethodLZMA, NO); + ADD_METHOD(methods, @"LZ4", (NOZCompressionMethod)COMPRESSION_LZ4, NO); + ADD_METHOD(methods, @"LZFSE", (NOZCompressionMethod)COMPRESSION_LZFSE, NO); + } + + return methods; +} diff --git a/noz/NOZCLICompressMode.h b/noz/NOZCLICompressMode.h new file mode 100644 index 0000000..68f1322 --- /dev/null +++ b/noz/NOZCLICompressMode.h @@ -0,0 +1,24 @@ +// +// NOZCLICompressMode.h +// ZipUtilities +// +// Created by Nolan O'Brien on 5/7/17. +// Copyright © 2017 NSProgrammer. All rights reserved. +// + +#import "NOZCLIModeProtocol.h" + +@interface NOZCLICompressModeInfo : NSObject + +@property (nonatomic, copy, readonly) NSString *method; +@property (nonatomic, readonly) NSInteger level; +@property (nonatomic, copy, readonly) NSString *inputFile; +@property (nonatomic, copy, readonly) NSString *outputFile; + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +@end + +@interface NOZCLICompressMode : NSObject +@end diff --git a/noz/NOZCLICompressMode.m b/noz/NOZCLICompressMode.m new file mode 100644 index 0000000..432f292 --- /dev/null +++ b/noz/NOZCLICompressMode.m @@ -0,0 +1,171 @@ +// +// NOZCLICompressMode.m +// ZipUtilities +// +// Created by Nolan O'Brien on 5/7/17. +// Copyright © 2017 NSProgrammer. All rights reserved. +// + +#import "NOZCLI.h" +#import "NOZCLICompressMode.h" + +@interface NOZCLICompressModeInfo () +@property (nonatomic, readonly) MethodInfo *methodInfo; +@end + +@implementation NOZCLICompressModeInfo + +- (instancetype)initWithMethodInfo:(MethodInfo *)methodInfo level:(NSInteger)level inputFile:(NSString *)inputFile outputFile:(NSString *)outputFile +{ + if (self = [super init]) { + _methodInfo = methodInfo; + _method = [methodInfo.name copy]; + _level = level; + _inputFile = [inputFile copy]; + _outputFile = [outputFile copy]; + } + return self; +} + +@end + +@implementation NOZCLICompressMode + ++ (NSString *)modeFlag +{ + return @"-c"; +} + ++ (NSString *)modeName +{ + return @"Compress"; +} + ++ (NSString *)modeExecutionDescription +{ + return @"-m METHOD [-l LEVEL] -i in_file -o out_file"; +} + ++ (NSUInteger)modeExtraArgumentsSectionCount +{ + return 0; +} + ++ (NSString *)modeExtraArgumentsSectionName:(NSUInteger)sectionIndex +{ + return nil; +} + ++ (NSArray *)modeExtraArgumentsSectionDescriptions:(NSUInteger)sectionIndex +{ + return nil; +} + ++ (id)infoFromArgs:(NSArray *)args environmentPath:(NSString *)envPath +{ + NSString *level = nil; + NSString *inputFile = nil; + NSString *outputFile = nil; + NSString *method = nil; + + for (NSUInteger i = 0; i < args.count; i++) { + NSString *arg = args[i]; + if ([arg isEqualToString:@"-m"]) { + i++; + if (i < args.count) { + method = args[i]; + } + } else if ([arg isEqualToString:@"-l"]) { + i++; + if (i < args.count) { + level = args[i]; + } + } else if ([arg isEqualToString:@"-i"]) { + i++; + if (i < args.count) { + inputFile = args[i]; + } + } else if ([arg isEqualToString:@"-o"]) { + i++; + if (i < args.count) { + outputFile = args[i]; + } + } else { + return nil; + } + } + + if (!method) { + return nil; + } + + BOOL isDir = NO; + MethodInfo *methodInfo = NOZCLI_lookupMethodByName(method); + inputFile = NOZCLI_normalizedPath(envPath, inputFile); + outputFile = NOZCLI_normalizedPath(envPath, outputFile); + + if (!methodInfo) { + printf("no such compression method \"%s\"!\n", method.UTF8String); + return nil; + } + + if (!methodInfo.encoder || !methodInfo.decoder) { + printf("unsupported method \"%s\"!\n", method.UTF8String); + return nil; + } + + if (!inputFile || ![[NSFileManager defaultManager] fileExistsAtPath:inputFile isDirectory:&isDir] || isDir) { + return nil; + } + + if (!outputFile) { + return nil; + } + + NSInteger levelValue = -1; + if (level) { + levelValue = [level integerValue]; + if (levelValue < 1 || (NSUInteger)levelValue > methodInfo.levels) { + printf("invalid level (%zi) for method \"%s\"!\n", levelValue, methodInfo.name.UTF8String); + return nil; + } + } + + return [[NOZCLICompressModeInfo alloc] initWithMethodInfo:methodInfo level:levelValue inputFile:inputFile outputFile:outputFile]; +} + ++ (int)run:(NOZCLICompressModeInfo *)info +{ + if (!info) { + return -1; + } + + id encoder = info.methodInfo.encoder; + if (!encoder) { + return -1; + } + + NOZCompressionLevel level = NOZCompressionLevelDefault; + if (info.level > 0) { + level = NOZCompressionLevelFromCustomEncoderLevel(1, info.methodInfo.levels, (NSUInteger)info.level); + } + + NSError *error = nil; + if (!NOZEncodeFile(info.inputFile, info.outputFile, encoder, level, &error)) { + NOZCLI_printError(error); + return -2; + } + + NSFileManager *fm = [NSFileManager defaultManager]; + long long inSize = (long long)[[fm attributesOfItemAtPath:info.inputFile error:NULL] fileSize]; + long long outSize = (long long)[[fm attributesOfItemAtPath:info.outputFile error:NULL] fileSize]; + double ratio = NOZCLI_computeCompressionRatio(inSize, outSize); + NSString *printMessage = [NSString stringWithFormat:@"input size: %@\noutput size: %@\ncompression ratio: %f\n", + [NSByteCountFormatter stringFromByteCount:inSize countStyle:NSByteCountFormatterCountStyleBinary], + [NSByteCountFormatter stringFromByteCount:outSize countStyle:NSByteCountFormatterCountStyleBinary], + ratio]; + printf("%s", printMessage.UTF8String); + return 1; +} + +@end diff --git a/noz/NOZCLIDecompressMode.h b/noz/NOZCLIDecompressMode.h new file mode 100644 index 0000000..2ab99e3 --- /dev/null +++ b/noz/NOZCLIDecompressMode.h @@ -0,0 +1,23 @@ +// +// NOZCLIDecompressMode.h +// ZipUtilities +// +// Created by Nolan O'Brien on 5/7/17. +// Copyright © 2017 NSProgrammer. All rights reserved. +// + +#import "NOZCLIModeProtocol.h" + +@interface NOZCLIDecompressModeInfo : NSObject + +@property (nonatomic, copy, readonly) NSString *method; +@property (nonatomic, copy, readonly) NSString *inputFile; +@property (nonatomic, copy, readonly) NSString *outputFile; + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +@end + +@interface NOZCLIDecompressMode : NSObject +@end diff --git a/noz/NOZCLIDecompressMode.m b/noz/NOZCLIDecompressMode.m new file mode 100644 index 0000000..89d6721 --- /dev/null +++ b/noz/NOZCLIDecompressMode.m @@ -0,0 +1,152 @@ +// +// NOZCLIDecompressMode.m +// ZipUtilities +// +// Created by Nolan O'Brien on 5/7/17. +// Copyright © 2017 NSProgrammer. All rights reserved. +// + +#import "NOZCLI.h" +#import "NOZCLIDecompressMode.h" + +@interface NOZCLIDecompressModeInfo () +@property (nonatomic, readonly) MethodInfo *methodInfo; +@end + +@implementation NOZCLIDecompressModeInfo + +- (instancetype)initWithMethodInfo:(MethodInfo *)methodInfo inputFile:(NSString *)inputFile outputFile:(NSString *)outputFile +{ + if (self = [super init]) { + _methodInfo = methodInfo; + _method = [methodInfo.name copy]; + _inputFile = [inputFile copy]; + _outputFile = [outputFile copy]; + } + return self; +} + +@end + +@implementation NOZCLIDecompressMode + ++ (NSString *)modeFlag +{ + return @"-d"; +} + ++ (NSString *)modeName +{ + return @"Decompress"; +} + ++ (NSString *)modeExecutionDescription +{ + return @"-m METHOD -i in_file -o out_file"; +} + ++ (NSUInteger)modeExtraArgumentsSectionCount +{ + return 0; +} + ++ (NSString *)modeExtraArgumentsSectionName:(NSUInteger)sectionIndex +{ + return nil; +} + ++ (NSArray *)modeExtraArgumentsSectionDescriptions:(NSUInteger)sectionIndex +{ + return nil; +} + ++ (id)infoFromArgs:(NSArray *)args environmentPath:(NSString *)envPath +{ + NSString *inputFile = nil; + NSString *outputFile = nil; + NSString *method = nil; + + for (NSUInteger i = 0; i < args.count; i++) { + NSString *arg = args[i]; + if ([arg isEqualToString:@"-m"]) { + i++; + if (i < args.count) { + method = args[i]; + } + } else if ([arg isEqualToString:@"-i"]) { + i++; + if (i < args.count) { + inputFile = args[i]; + } + } else if ([arg isEqualToString:@"-o"]) { + i++; + if (i < args.count) { + outputFile = args[i]; + } + } else { + return nil; + } + } + + if (!method) { + return nil; + } + + BOOL isDir = NO; + MethodInfo *methodInfo = NOZCLI_lookupMethodByName(method); + inputFile = NOZCLI_normalizedPath(envPath, inputFile); + outputFile = NOZCLI_normalizedPath(envPath, outputFile); + + if (!methodInfo) { + printf("no such compression method \"%s\"!\n", method.UTF8String); + return nil; + } + + if (!methodInfo.encoder || !methodInfo.decoder) { + printf("unsupported method \"%s\"!\n", method.UTF8String); + return nil; + } + + if (!inputFile || ![[NSFileManager defaultManager] fileExistsAtPath:inputFile isDirectory:&isDir] || isDir) { + return nil; + } + + if (!outputFile) { + return nil; + } + + return [[NOZCLIDecompressModeInfo alloc] initWithMethodInfo:methodInfo inputFile:inputFile outputFile:outputFile]; +} + ++ (int)run:(NOZCLIDecompressModeInfo *)info +{ + if (!info) { + return -1; + } + + id decoder = info.methodInfo.decoder; + if (!decoder) { + return -1; + } + + NSError *error = nil; + if (!NOZDecodeFile(info.inputFile, info.outputFile, decoder, &error)) { + NOZCLI_printError(error); + return -2; + } + + NSFileManager *fm = [NSFileManager defaultManager]; + long long inSize = (long long)[[fm attributesOfItemAtPath:info.inputFile error:NULL] fileSize]; + long long outSize = (long long)[[fm attributesOfItemAtPath:info.outputFile error:NULL] fileSize]; + double ratio = NOZCLI_computeCompressionRatio(outSize, inSize); + NSString *printMessage = [NSString stringWithFormat:@"input size: %@\noutput size: %@\ncompression ratio: %f\n", + [NSByteCountFormatter stringFromByteCount:inSize countStyle:NSByteCountFormatterCountStyleBinary], + [NSByteCountFormatter stringFromByteCount:outSize countStyle:NSByteCountFormatterCountStyleBinary], + ratio]; + printf("%s", printMessage.UTF8String); + + return 1; +} + +@end + diff --git a/noz/NOZCLIDumpMode.h b/noz/NOZCLIDumpMode.h new file mode 100644 index 0000000..f0491af --- /dev/null +++ b/noz/NOZCLIDumpMode.h @@ -0,0 +1,24 @@ +// +// NOZCLIDumpMode.h +// ZipUtilities +// +// Created by Nolan O'Brien on 5/7/17. +// Copyright © 2017 NSProgrammer. All rights reserved. +// + +#import "NOZCLIModeProtocol.h" + +@interface NOZCLIDumpModeInfo : NSObject + +@property (nonatomic, readonly) BOOL list; +@property (nonatomic, readonly) BOOL silenceArchiveInfo; +@property (nonatomic, readonly) BOOL verbose; +@property (nonatomic, copy, readonly) NSString *filePath; + +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; + +@end + +@interface NOZCLIDumpMode : NSObject +@end diff --git a/noz/NOZCLIDumpMode.m b/noz/NOZCLIDumpMode.m new file mode 100644 index 0000000..5eada52 --- /dev/null +++ b/noz/NOZCLIDumpMode.m @@ -0,0 +1,189 @@ +// +// NOZCLIDumpMode.m +// ZipUtilities +// +// Created by Nolan O'Brien on 5/7/17. +// Copyright © 2017 NSProgrammer. All rights reserved. +// + +#import + +#import "NOZCLI.h" +#import "NOZCLIDumpMode.h" + +@implementation NOZCLIDumpModeInfo + +- (instancetype)initWithFilePath:(NSString *)filePath list:(BOOL)list verbose:(BOOL)verbose silenceArchiveInfo:(BOOL)silence +{ + if (self = [super init]) { + _filePath = [filePath copy]; + _list = list; + _silenceArchiveInfo = silence; + _verbose = verbose; + } + return self; +} + +@end + +@implementation NOZCLIDumpMode + ++ (NSString *)modeFlag +{ + return @"-D"; +} + ++ (NSString *)modeName +{ + return @"Dump"; +} + ++ (NSString *)modeExecutionDescription +{ + return @"[dump_options] -i zip_file"; +} + ++ (NSUInteger)modeExtraArgumentsSectionCount +{ + return 1; +} + ++ (NSString *)modeExtraArgumentsSectionName:(NSUInteger)sectionIndex +{ + return @"dump_options"; +} + ++ (NSArray *)modeExtraArgumentsSectionDescriptions:(NSUInteger)sectionIndex +{ + return @[ + @"-L list all entries", + @"-v verbose info", + @"-s silence the archive info (the default info that is output)" + ]; +} + ++ (id)infoFromArgs:(NSArray *)args environmentPath:(NSString *)envPath +{ + BOOL list = NO; + BOOL verbose = NO; + BOOL silenceArchiveInfo = NO; + NSString *file = nil; + + for (NSInteger i = 0; i < ((NSInteger)args.count - 1); i++) { + NSString *arg = args[(NSUInteger)i]; + if ([arg isEqualToString:@"-L"]) { + list = YES; + } else if ([arg isEqualToString:@"-v"]) { + verbose = YES; + } else if ([arg isEqualToString:@"-s"]) { + silenceArchiveInfo = YES; + } else if ([arg isEqualToString:@"-i"]) { + i++; + file = args[(NSUInteger)i]; + } else { + return nil; + } + } + + file = NOZCLI_normalizedPath(envPath, file); + + BOOL isDir = NO; + if (!file || ![[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDir] || isDir) { + return nil; + } + + return [[NOZCLIDumpModeInfo alloc] initWithFilePath:file list:list verbose:verbose silenceArchiveInfo:silenceArchiveInfo]; +} + ++ (int)run:(NOZCLIDumpModeInfo *)info +{ + if (!info) { + return -1; + } + + NSError *error = nil; + NOZUnzipper *unzipper = [[NOZUnzipper alloc] initWithZipFile:info.filePath]; + if (![unzipper openAndReturnError:&error]) { + NOZCLI_printError(error); + return -2; + } + + NOZCentralDirectory *centralDirectory = [unzipper readCentralDirectoryAndReturnError:&error]; + if (!centralDirectory) { + NOZCLI_printError(error); + return -2; + } + + if (!info.silenceArchiveInfo) { + [self dumpCentralDirectory:centralDirectory info:info]; + } + + if (info.list) { + [unzipper enumerateManifestEntriesUsingBlock:^(NOZCentralDirectoryRecord *record, NSUInteger index, BOOL *stop) { + [self dumpRecord:record info:info]; + }]; + } + + return 1; +} + ++ (void)dumpCentralDirectory:(NOZCentralDirectory *)centralDirectory info:(NOZCLIDumpModeInfo *)info +{ + NSString *compressedSize = [NSByteCountFormatter stringFromByteCount:centralDirectory.totalCompressedSize countStyle:NSByteCountFormatterCountStyleBinary]; + NSString *uncompressedSize = [NSByteCountFormatter stringFromByteCount:centralDirectory.totalUncompressedSize countStyle:NSByteCountFormatterCountStyleBinary]; + double ratio = NOZCLI_computeCompressionRatio(centralDirectory.totalUncompressedSize, centralDirectory.totalCompressedSize); + + printf("uncompressed: %s", uncompressedSize.UTF8String); + if (info.verbose) { + printf(" (%lli bytes)", centralDirectory.totalUncompressedSize); + } + printf("\n"); + + printf("compressed: %s", compressedSize.UTF8String); + if (info.verbose) { + printf(" (%lli bytes)", centralDirectory.totalCompressedSize); + } + printf("\n"); + + if (info.verbose) { + printf("compression ratio: %f\n", ratio); + printf("record count: %tu\n", centralDirectory.recordCount); + if (centralDirectory.globalComment) { + printf("comment: \"%s\"\n", centralDirectory.globalComment.UTF8String); + } + printf("path: %s\n", info.filePath.UTF8String); + } +} + ++ (void)dumpRecord:(NOZCentralDirectoryRecord *)record info:(NOZCLIDumpModeInfo *)info +{ + printf("%s\n", record.name.UTF8String); + if (info.verbose) { + NSString *compressedSize = [NSByteCountFormatter stringFromByteCount:record.compressedSize countStyle:NSByteCountFormatterCountStyleBinary]; + NSString *uncompressedSize = [NSByteCountFormatter stringFromByteCount:record.uncompressedSize countStyle:NSByteCountFormatterCountStyleBinary]; + double ratio = NOZCLI_computeCompressionRatio(record.uncompressedSize, record.compressedSize); + + printf("\tuncompressed: %s, (%lli bytes)\n", uncompressedSize.UTF8String, record.uncompressedSize); + printf("\tcompressed: %s, (%lli bytes)\n", compressedSize.UTF8String, record.compressedSize); + printf("\tcompression ratio: %f\n", ratio); + + MethodInfo *methodInfo = NOZCLI_lookupMethod(record.compressionMethod); + NSUInteger methodLevel = 0; + if (methodInfo && methodInfo.levels > 0) { + methodLevel = NOZCompressionLevelToCustomEncoderLevel(record.compressionLevel, 1, methodInfo.levels, methodInfo.defaultLevel); + } + + printf("\tcompression method: %s (%u)\n", (info) ? methodInfo.name.UTF8String : "unknown", (unsigned int)record.compressionMethod); + printf("\tcompression level: %f", record.compressionLevel); + if (methodLevel > 0) { + printf(" (%tu of %tu)", methodLevel, methodInfo.levels); + } + printf("\n"); + + if (record.comment) { + printf("\tcomment: \"%s\"\n", record.comment.UTF8String); + } + } +} + +@end diff --git a/noz/NOZCLIMethodMode.h b/noz/NOZCLIMethodMode.h new file mode 100644 index 0000000..2b2180e --- /dev/null +++ b/noz/NOZCLIMethodMode.h @@ -0,0 +1,17 @@ +// +// NOZCLIMethodMode.h +// ZipUtilities +// +// Created by Nolan O'Brien on 5/8/17. +// Copyright © 2017 NSProgrammer. All rights reserved. +// + +#import "NOZCLIModeProtocol.h" + +@interface NOZCLIMethodModeInfo : NSObject +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; +@end + +@interface NOZCLIMethodMode : NSObject +@end diff --git a/noz/NOZCLIMethodMode.m b/noz/NOZCLIMethodMode.m new file mode 100644 index 0000000..efa9fca --- /dev/null +++ b/noz/NOZCLIMethodMode.m @@ -0,0 +1,80 @@ +// +// NOZCLIMethodMode.m +// ZipUtilities +// +// Created by Nolan O'Brien on 5/8/17. +// Copyright © 2017 NSProgrammer. All rights reserved. +// + +#import "NOZCLI.h" +#import "NOZCLIMethodMode.h" + +@implementation NOZCLIMethodModeInfo + +- (instancetype)initInternal +{ + return [super init]; +} + +@end + +@implementation NOZCLIMethodMode + ++ (NSString *)modeFlag +{ + return @"-A"; +} + ++ (NSString *)modeName +{ + return @"All Methods"; +} + ++ (NSString *)modeExecutionDescription +{ + return @""; +} + ++ (NSUInteger)modeExtraArgumentsSectionCount +{ + return 0; +} + ++ (NSString *)modeExtraArgumentsSectionName:(NSUInteger)sectionIndex +{ + return nil; +} + ++ (NSArray *)modeExtraArgumentsSectionDescriptions:(NSUInteger)sectionIndex +{ + return nil; +} + ++ (id)infoFromArgs:(NSArray *)args environmentPath:(NSString *)envPath +{ + return [[NOZCLIMethodModeInfo alloc] initInternal]; +} + ++ (int)run:(NOZCLIMethodModeInfo *)unused +{ + for (MethodInfo *info in NOZCLI_allMethods()) { + printf("(%u) \"%s\":\n", (unsigned int)info.method, info.name.UTF8String); + if (info.levels > 0) { + printf("\tLevels: 1-%tu, Default Level: %tu\n", info.levels, info.defaultLevel); + } + printf("\tSupport: "); + if (info.method == NOZCompressionMethodNone) { + printf("Default"); + } else if (!info.encoder || !info.decoder) { + printf("Unsupported"); + } else if (info.isDefaultCodec) { + printf("Default"); + } else { + printf("Extended"); + } + printf("\n"); + } + return 1; +} + +@end diff --git a/noz/NOZCLIModeProtocol.h b/noz/NOZCLIModeProtocol.h new file mode 100644 index 0000000..0ee1af2 --- /dev/null +++ b/noz/NOZCLIModeProtocol.h @@ -0,0 +1,27 @@ +// +// NOZCLIModeProtocol.h +// ZipUtilities +// +// Created by Nolan O'Brien on 5/8/17. +// Copyright © 2017 NSProgrammer. All rights reserved. +// + +#import + +@protocol NOZCLIModeInfoProtocol +@end + +@protocol NOZCLIModeProtocol + ++ (NSString *)modeFlag; ++ (NSString *)modeName; ++ (NSString *)modeExecutionDescription; + ++ (NSUInteger)modeExtraArgumentsSectionCount; ++ (NSString *)modeExtraArgumentsSectionName:(NSUInteger)sectionIndex; ++ (NSArray *)modeExtraArgumentsSectionDescriptions:(NSUInteger)sectionIndex; + ++ (id)infoFromArgs:(NSArray *)args environmentPath:(NSString *)envPath; ++ (int)run:(id)info; + +@end diff --git a/noz/NOZCLIUnzipMode.h b/noz/NOZCLIUnzipMode.h new file mode 100644 index 0000000..0e33b8c --- /dev/null +++ b/noz/NOZCLIUnzipMode.h @@ -0,0 +1,17 @@ +// +// NOZCLIUnzipMode.h +// ZipUtilities +// +// Created by Nolan O'Brien on 5/7/17. +// Copyright © 2017 NSProgrammer. All rights reserved. +// + +#import "NOZCLIModeProtocol.h" + +@interface NOZCLIUnzipModeInfo : NSObject +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; +@end + +@interface NOZCLIUnzipMode : NSObject +@end diff --git a/noz/NOZCLIUnzipMode.m b/noz/NOZCLIUnzipMode.m new file mode 100644 index 0000000..ab655de --- /dev/null +++ b/noz/NOZCLIUnzipMode.m @@ -0,0 +1,428 @@ +// +// NOZCLIUnzipMode.m +// ZipUtilities +// +// Created by Nolan O'Brien on 5/7/17. +// Copyright © 2017 NSProgrammer. All rights reserved. +// + +#import "NOZCLI.h" +#import "NOZCLIUnzipMode.h" + +@interface NOZCLIUnzipDecompressDelegate : NSObject +@end + +@interface NOZCLIUnzipModeEntryInfo : NSObject + +@property (nonatomic, copy, readonly, nullable) NSString *methodName; +@property (nonatomic, copy, readonly, nullable) NSString *outputPath; +@property (nonatomic, copy, readonly, nonnull) NSString *entryName; + ++ (NSArray *)entryInfosFromArgs:(NSArray *)args basePath:(NSString *)basePath environmentPath:(NSString *)envPath; + +@end + +@interface NOZCLIUnzipModeInfo () + +@property (nonatomic, readonly, copy) NSString *inputFilePath; +@property (nonatomic, readonly) BOOL forceGuessUnknownMethod; +@property (nonatomic, readonly) BOOL forceFailUnknownMethod; +@property (nonatomic, readonly, copy) NSDictionary *methodToNumberMap; +@property (nonatomic, readonly, copy) NSString *baseOutputPath; +@property (nonatomic, readonly, copy) NSArray *entryInfos; + +- (instancetype)initWithInputFilePath:(NSString *)inputFilePath + forceGuessUnknownMethod:(BOOL)guessUnknown + forceFailUnknownMethod:(BOOL)failUnknown + methodToNumberMap:(NSDictionary *)map + baseOutputPath:(NSString *)baseOutputPath + entryInfos:(NSArray *)entryInfos; + +@end + +@implementation NOZCLIUnzipModeInfo + +- (instancetype)initWithInputFilePath:(NSString *)inputFilePath + forceGuessUnknownMethod:(BOOL)guessUnknown + forceFailUnknownMethod:(BOOL)failUnknown + methodToNumberMap:(NSDictionary *)map + baseOutputPath:(NSString *)baseOutputPath + entryInfos:(NSArray *)entryInfos +{ + if (self = [super init]) { + _inputFilePath = [inputFilePath copy]; + _forceGuessUnknownMethod = guessUnknown; + _forceFailUnknownMethod = failUnknown; + _methodToNumberMap = [map copy]; + _baseOutputPath = [baseOutputPath copy]; + _entryInfos = [entryInfos copy]; + } + return self; +} + +@end + +@implementation NOZCLIUnzipMode + ++ (NSString *)modeFlag +{ + return @"-u"; +} + ++ (NSString *)modeName +{ + return @"Unzip"; +} + ++ (NSString *)modeExecutionDescription +{ + return @"[unzip_options] -i zip_file [-e [entry_options] entry1 [... [-e [entry_options] entryN]]]"; +} + ++ (NSUInteger)modeExtraArgumentsSectionCount +{ + return 2; +} + ++ (NSString *)modeExtraArgumentsSectionName:(NSUInteger)sectionIndex +{ + if (1 == sectionIndex) { + return @"unzip entry_options"; + } + return @"unzip_options"; +} + ++ (NSArray *)modeExtraArgumentsSectionDescriptions:(NSUInteger)sectionIndex +{ + if (1 == sectionIndex) { + return @[ + @"-o OUTPUT_FILE provide the specific output file", + @"-m METHOD override the method to unzip the entry with", + ]; + } + return @[ + @"-f forcibly guess METHOD when unzipping an unknown METHOD", + @"-F forcibly fail when unzipping an unknown METHOD", + @"-M METHOD NUMBER map a METHOD to a different archive number... this impacts unzipping!", + @"-b BASE_PATH provide the base path output to. Default is directory named after archive, './zip_file/'", + ]; +} + ++ (id)infoFromArgs:(NSArray *)args environmentPath:(NSString *)envPath +{ + BOOL forceGuessUnknownMethod = NO; + BOOL forceFailUnknownMethod = NO; + NSMutableDictionary *methodToNumberMap = [[NSMutableDictionary alloc] init]; + NSString *baseOutputPath = nil; + NSString *inputFilePath = nil; + NSArray *entryInfos = nil; + + for (NSUInteger i = 0; i < args.count; i++) { + NSString *arg = args[i]; + if ([arg isEqualToString:@"-f"]) { + forceGuessUnknownMethod = YES; + } else if ([arg isEqualToString:@"-F"]) { + forceFailUnknownMethod = YES; + } else if ([arg isEqualToString:@"-b"]) { + i++; + if (i < args.count) { + baseOutputPath = NOZCLI_normalizedPath(envPath, args[i]); + } else { + return nil; + } + } else if ([arg isEqualToString:@"-M"]) { + i++; + if (i < (args.count - 1)) { + NSString *methodName = args[i]; + i++; + NSString *methodNumberString = args[i]; + NSNumber *methodNumber = @(methodNumberString.integerValue); + + BOOL valid = YES; + if (methodNumber.integerValue < 0) { + valid = NO; + } else if (methodNumber.integerValue == 0 && ![methodNumberString isEqualToString:@"0"]) { + valid = NO; + } else if (methodNumber.integerValue > UINT16_MAX) { + valid = NO; + } + + if (!valid) { + printf("method map from '%s' to '%s' is invalid ('%s' is not a valid method archive number)\n", methodName.UTF8String, methodNumberString.UTF8String, methodNumberString.UTF8String); + return nil; + } + + methodToNumberMap[methodName] = methodNumber; + } else { + return nil; + } + } else if ([arg isEqualToString:@"-e"]) { + NSArray *subargs = [args subarrayWithRange:NSMakeRange(i, args.count - i)]; + entryInfos = [NOZCLIUnzipModeEntryInfo entryInfosFromArgs:subargs basePath:baseOutputPath environmentPath:envPath]; + if (entryInfos.count == 0) { + return nil; + } else { + break; + } + } else if ([arg isEqualToString:@"-i"]) { + i++; + if (i < args.count) { + inputFilePath = NOZCLI_normalizedPath(envPath, args[i]); + } else { + return nil; + } + } else { + return nil; + } + } + + if (!baseOutputPath) { + baseOutputPath = [[envPath stringByAppendingPathComponent:inputFilePath.lastPathComponent] stringByDeletingPathExtension]; + } + + return [[NOZCLIUnzipModeInfo alloc] initWithInputFilePath:inputFilePath + forceGuessUnknownMethod:forceGuessUnknownMethod + forceFailUnknownMethod:forceFailUnknownMethod + methodToNumberMap:methodToNumberMap + baseOutputPath:baseOutputPath + entryInfos:entryInfos]; +} + ++ (int)run:(NOZCLIUnzipModeInfo *)info +{ + NOZCompressionLibrary *lib = [NOZCompressionLibrary sharedInstance]; + NSMutableDictionary *methodMap = [[NSMutableDictionary alloc] init]; + for (NSString *methodName in info.methodToNumberMap.allKeys) { + MethodInfo *methodInfo = NOZCLI_lookupMethodByName(methodName); + if (!methodInfo) { + printf("No such method name: %s\n", methodName.UTF8String); + return -1; + } + NSNumber *methodNumber = info.methodToNumberMap[methodName]; + methodMap[methodNumber] = methodInfo; + } + for (NSNumber *methodNumber in methodMap.allKeys) { + MethodInfo *methodInfo = methodMap[methodNumber]; + [lib setEncoder:methodInfo.encoder forMethod:methodNumber.unsignedShortValue]; + [lib setDecoder:methodInfo.decoder forMethod:methodNumber.unsignedShortValue]; + } + + if (0 == info.entryInfos.count) { + id decompressDelegate = [[NOZCLIUnzipDecompressDelegate alloc] init]; + NOZDecompressRequest *request = [[NOZDecompressRequest alloc] initWithSourceFilePath:info.inputFilePath destinationDirectoryPath:info.baseOutputPath]; + NOZDecompressOperation *op = [[NOZDecompressOperation alloc] initWithRequest:request delegate:decompressDelegate]; + [op start]; // will run synchronously + NOZDecompressResult *result = op.result; + if (result.operationError) { + NOZCLI_printError(result.operationError); + return -2; + } + + if (!result.didSucceed) { + printf("FAILED!\n"); + return -2; + } + + printf("compression ratio: %f\n", result.compressionRatio); + return 0; + } + + NOZUnzipper *unzipper = [[NOZUnzipper alloc] initWithZipFile:info.inputFilePath]; + + NSError *error = nil; + if (![unzipper openAndReturnError:&error]) { + NOZCLI_printError(error); + return -2; + } + + if (![unzipper readCentralDirectoryAndReturnError:&error]) { + NOZCLI_printError(error); + return -2; + } + + NOZProgressBlock progressBlock = ^(int64_t totalBytes, int64_t bytesComplete, int64_t bytesCompletedThisPass, BOOL *abort) { +// const double progress = (double)bytesComplete / (double)totalBytes; +// printf("%zi%%\n", (NSInteger)(progress * 100.)); + }; + NSFileManager *fm = [NSFileManager defaultManager]; + NSString *tmpDir = [NSTemporaryDirectory() stringByAppendingPathComponent:[NSUUID UUID].UUIDString]; + for (NOZCLIUnzipModeEntryInfo *entry in info.entryInfos) { + NSUInteger index = [unzipper indexForRecordWithName:entry.entryName]; + if (NSNotFound == index) { + [fm removeItemAtPath:tmpDir error:NULL]; + printf("no such Zip record named '%s'\n", entry.entryName.UTF8String); + return -2; + } + NOZCentralDirectoryRecord *record = [unzipper readRecordAtIndex:index error:&error]; + if (!record) { + [fm removeItemAtPath:tmpDir error:NULL]; + NOZCLI_printError(error); + return -2; + } + + printf("%s\n", record.name.UTF8String); + + if (![unzipper saveRecord:record toDirectory:tmpDir options:NOZUnzipperSaveRecordOptionIgnoreIntermediatePath progressBlock:progressBlock error:&error]) { + [fm removeItemAtPath:tmpDir error:NULL]; + NOZCLI_printError(error); + return -2; + } + + NSString *tmpPath = [tmpDir stringByAppendingPathComponent:record.name.lastPathComponent]; + NSString *dstPath = entry.outputPath ?: [info.baseOutputPath stringByAppendingPathComponent:entry.entryName]; + + [fm createDirectoryAtPath:[dstPath stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:NULL]; + + if (![fm moveItemAtPath:tmpPath toPath:dstPath error:&error]) { + [fm removeItemAtPath:tmpDir error:NULL]; + NOZCLI_printError(error); + return -2; + } + } + [fm removeItemAtPath:tmpDir error:NULL]; + + [unzipper closeAndReturnError:NULL]; + + return 0; +} + +@end + +@implementation NOZCLIUnzipModeEntryInfo + ++ (NSArray *)entryInfosFromArgs:(NSArray *)args basePath:(NSString *)basePath environmentPath:(NSString *)envPath +{ + NSMutableArray *entries = [[NSMutableArray alloc] init]; + NSMutableIndexSet *eIndexes = [[args indexesOfObjectsPassingTest:^BOOL(NSString *arg, NSUInteger idx, BOOL *stop) { + return [arg isEqualToString:@"-e"]; + }] mutableCopy]; + + NSMutableArray *> *entryArgs = [[NSMutableArray alloc] init]; + if (eIndexes.count == 0) { + return nil; + } + + NSUInteger prevIndex = NSNotFound; + do { + const NSUInteger curIndex = eIndexes.firstIndex; + [eIndexes removeIndex:curIndex]; + if (prevIndex != NSNotFound) { + [entryArgs addObject:[args subarrayWithRange:NSMakeRange(prevIndex, curIndex - prevIndex)]]; + if (!eIndexes.count) { + [entryArgs addObject:[args subarrayWithRange:NSMakeRange(curIndex, args.count - curIndex)]]; + } + } + prevIndex = curIndex; + } while (eIndexes.count); + + if (entryArgs.count == 0) { + return nil; + } + + for (NSArray *argsForSingleEntry in entryArgs) { + NOZCLIUnzipModeEntryInfo *entry = [NOZCLIUnzipModeEntryInfo entryFromArgs:argsForSingleEntry basePath:basePath environmentPath:envPath]; + if (!entry) { + printf("invalid arguments for unzipping a specific entry!\n"); + for (NSString *arg in argsForSingleEntry) { + printf("%s ", arg.UTF8String); + } + printf("\n"); + } + [entries addObject:entry]; + } + + return entries; +} + ++ (instancetype)entryFromArgs:(NSArray *)args basePath:(NSString *)basePath environmentPath:(NSString *)environmentPath +{ + NSString *name = nil; + NSString *outputPath = nil; + NSString *methodName = nil; + BOOL leadsWithCorrectFlag = NO; + + for (NSUInteger i = 0; i < args.count; i++) { + NSString *arg = args[i]; + if (!leadsWithCorrectFlag) { + leadsWithCorrectFlag = [arg isEqualToString:@"-e"]; + if (!leadsWithCorrectFlag) { + break; + } + continue; + } + + if ([arg isEqualToString:@"-o"]) { + i++; + if (i >= args.count) { + return nil; + } + outputPath = args[i]; + } else if ([arg isEqualToString:@"-m"]) { + i++; + if (i >= args.count) { + return nil; + } + methodName = args[i]; + } else { + if (name) { + return nil; + } + name = arg; + } + } + + if (!name) { + return nil; + } + + if (!leadsWithCorrectFlag) { + return nil; + } + + outputPath = NOZCLI_normalizedPath(basePath ?: environmentPath, outputPath); + + return [[self alloc] initWithName:name method:methodName outputPath:outputPath]; +} + +- (instancetype)initWithName:(NSString *)name method:(NSString *)methodName outputPath:(NSString *)outputPath +{ + if (self = [super init]) { + _entryName = [name copy]; + _methodName = [methodName copy]; + _outputPath = [outputPath copy]; + } + return self; +} + +- (NSString *)description +{ + return [NSString stringWithFormat:@"<%@ %p, name=%@, method=%@, output=%@>", NSStringFromClass([self class]), self, _entryName, _methodName, _outputPath]; +} + +@end + +@implementation NOZCLIUnzipDecompressDelegate +{ + NSInteger _lastProgress; +} + +- (void)decompressOperation:(NOZDecompressOperation *)op didCompleteWithResult:(NOZDecompressResult *)result +{ +} + +- (void)decompressOperation:(NOZDecompressOperation *)op didUpdateProgress:(float)progress +{ + const NSInteger progressInt = (NSInteger)(progress * 100.f); + if (progressInt == _lastProgress) { + return; + } + _lastProgress = progressInt; + // printf("%zi%%\n", progressInt); +} + +- (BOOL)shouldDecompressOperation:(NOZDecompressOperation *)op overwriteFileAtPath:(NSString *)path +{ + return NO; +} + +@end diff --git a/noz/NOZCLIZipMode.h b/noz/NOZCLIZipMode.h new file mode 100644 index 0000000..a3fa56b --- /dev/null +++ b/noz/NOZCLIZipMode.h @@ -0,0 +1,17 @@ +// +// NOZCLIZipMode.h +// ZipUtilities +// +// Created by Nolan O'Brien on 5/7/17. +// Copyright © 2017 NSProgrammer. All rights reserved. +// + +#import "NOZCLIModeProtocol.h" + +@interface NOZCLIZipModeInfo : NSObject +- (instancetype)init NS_UNAVAILABLE; ++ (instancetype)new NS_UNAVAILABLE; +@end + +@interface NOZCLIZipMode : NSObject +@end diff --git a/noz/NOZCLIZipMode.m b/noz/NOZCLIZipMode.m new file mode 100644 index 0000000..9e6b244 --- /dev/null +++ b/noz/NOZCLIZipMode.m @@ -0,0 +1,327 @@ +// +// NOZCLIZipMode.m +// ZipUtilities +// +// Created by Nolan O'Brien on 5/7/17. +// Copyright © 2017 NSProgrammer. All rights reserved. +// + +#import "NOZCLI.h" +#import "NOZCLIZipMode.h" + +@interface NOZCLIZipModeEntryInfo : NSObject + +@property (nonatomic, copy, readonly) NSString *comment; +@property (nonatomic, copy, readonly) NSString *name; +@property (nonatomic, copy, readonly) NSString *level; +@property (nonatomic, copy, readonly) NSString *methodName; +@property (nonatomic, copy, readonly) NSString *entryPath; +@property (nonatomic, readonly) BOOL permitHiddenFiles; +@property (nonatomic, readonly) BOOL recurse; + ++ (NSArray *)entryInfosFromArgs:(NSArray *)args environmentPath:(NSString *)envPath; ++ (instancetype)entryFromArgs:(NSArray *)args environmentPath:(NSString *)envPath; +- (instancetype)initWithEntryPath:(NSString *)entryPath + name:(NSString *)name + level:(NSString *)level + methodName:(NSString *)methodName + comment:(NSString *)comment + permitHiddenFiles:(BOOL)permitHiddenFiles + recurse:(BOOL)recurse; + +@end + +@interface NOZCLIZipModeInfo () + +@property (nonatomic, copy, readonly) NSString *globalComment; +@property (nonatomic, copy, readonly) NSDictionary *methodToNumberMap; +@property (nonatomic, copy, readonly) NSArray *entryInfos; +@property (nonatomic, copy, readonly) NSString *outputFile; +@property (nonatomic, copy, readonly) NSString *envPath; + +- (instancetype)initWithGlobalComment:(NSString *)globalComment + methodToNumberMap:(NSDictionary *)methodToNumberMap + entryInfos:(NSArray *)entryInfos + outputFile:(NSString *)outputFile + environmentPath:(NSString *)envPath; + +@end + +@implementation NOZCLIZipMode + ++ (NSString *)modeFlag +{ + return @"-z"; +} + ++ (NSString *)modeName +{ + return @"Zip (NYI)"; +} + ++ (NSString *)modeExecutionDescription +{ + return @"[zip_options] -o output_file -i [file_options] input_file1 [... [-i [file_options] intpu_fileN]]"; +} + ++ (NSUInteger)modeExtraArgumentsSectionCount +{ + return 2; +} + ++ (NSString *)modeExtraArgumentsSectionName:(NSUInteger)sectionIndex +{ + if (1 == sectionIndex) { + return @"zip file_options"; + } + return @"zip_options"; +} + ++ (NSArray *)modeExtraArgumentsSectionDescriptions:(NSUInteger)sectionIndex +{ + if (1 == sectionIndex) { + return @[ + @"-c COMMENT provide an archive entry comment", + @"-n NAME override the name", + @"-m METHOD specify a compression method, default is \"deflate\" (see METHODS below)", + @"-l LEVEL specify a compression level, levels are defined per METHOD each with their own default", + @"-h permit hidden file(s)", + @"-f don't recurse into the director if provided path was a directory (default is to recurse)", + ]; + } + return @[ + @"-c COMMENT provide an archive comment", + @"-M METHOD NUMBER map a METHOD to a different archive number... this impacts unzipping!", + ]; +} + ++ (id)infoFromArgs:(NSArray *)args environmentPath:(NSString *)envPath +{ + NSString *globalComment = nil; + NSMutableDictionary *methodToNumberMap = [[NSMutableDictionary alloc] init]; + NSString *outputFile = nil; + NSArray *entryInfos = nil; + + for (NSUInteger i = 0; i < args.count; i++) { + NSString *arg = args[i]; + if ([arg isEqualToString:@"-c"]) { + i++; + if (i < args.count) { + globalComment = args[i]; + } else { + return nil; + } + } else if ([arg isEqualToString:@"-o"]) { + i++; + if (i < args.count) { + outputFile = NOZCLI_normalizedPath(envPath, args[i]); + } else { + return nil; + } + } else if ([arg isEqualToString:@"-M"]) { + i++; + if (i < (args.count - 1)) { + NSString *methodName = args[i]; + i++; + NSString *methodNumberString = args[i]; + NSNumber *methodNumber = @(methodNumberString.integerValue); + + BOOL valid = YES; + if (methodNumber.integerValue < 0) { + valid = NO; + } else if (methodNumber.integerValue == 0 && ![methodNumberString isEqualToString:@"0"]) { + valid = NO; + } else if (methodNumber.integerValue > UINT16_MAX) { + valid = NO; + } + + if (!valid) { + printf("method map from '%s' to '%s' is invalid ('%s' is not a valid method archive number)\n", methodName.UTF8String, methodNumberString.UTF8String, methodNumberString.UTF8String); + return nil; + } + + methodToNumberMap[methodName] = methodNumber; + } else { + return nil; + } + } else if ([arg isEqualToString:@"-i"]) { + NSArray *subargs = [args subarrayWithRange:NSMakeRange(i, args.count - i)]; + entryInfos = [NOZCLIZipModeEntryInfo entryInfosFromArgs:subargs environmentPath:envPath]; + if (entryInfos.count == 0) { + return nil; + } else { + break; + } + } else { + return nil; + } + } + + + return [[NOZCLIZipModeInfo alloc] initWithGlobalComment:globalComment + methodToNumberMap:methodToNumberMap + entryInfos:entryInfos + outputFile:outputFile + environmentPath:envPath]; +} + ++ (int)run:(NOZCLIZipModeInfo *)info +{ + printf("NYI!\n"); + return -1; +} + +@end + +@implementation NOZCLIZipModeEntryInfo + ++ (NSArray *)entryInfosFromArgs:(NSArray *)args environmentPath:(NSString *)envPath +{ + NSMutableArray *entries = [[NSMutableArray alloc] init]; + NSMutableIndexSet *eIndexes = [[args indexesOfObjectsPassingTest:^BOOL(NSString *arg, NSUInteger idx, BOOL *stop) { + return [arg isEqualToString:@"-i"]; + }] mutableCopy]; + + NSMutableArray *> *entryArgs = [[NSMutableArray alloc] init]; + if (eIndexes.count == 0) { + return nil; + } + + NSUInteger prevIndex = NSNotFound; + do { + const NSUInteger curIndex = eIndexes.firstIndex; + [eIndexes removeIndex:curIndex]; + if (prevIndex != NSNotFound) { + [entryArgs addObject:[args subarrayWithRange:NSMakeRange(prevIndex, curIndex - prevIndex)]]; + if (!eIndexes.count) { + [entryArgs addObject:[args subarrayWithRange:NSMakeRange(curIndex, args.count - curIndex)]]; + } + } + prevIndex = curIndex; + } while (eIndexes.count); + + if (entryArgs.count == 0) { + return nil; + } + + for (NSArray *argsForSingleEntry in entryArgs) { + NOZCLIZipModeEntryInfo *entry = [NOZCLIZipModeEntryInfo entryFromArgs:argsForSingleEntry environmentPath:envPath]; + if (!entry) { + printf("invalid arguments for zipping a specific file!\n"); + for (NSString *arg in argsForSingleEntry) { + printf("%s ", arg.UTF8String); + } + printf("\n"); + } + [entries addObject:entry]; + } + + return entries; +} + ++ (instancetype)entryFromArgs:(NSArray *)args environmentPath:(NSString *)envPath +{ + NSString *comment = nil; + NSString *name = nil; + NSString *level = nil; + NSString *methodName = nil; + NSString *entryPath = nil; + BOOL permitHiddenFiles = NO; + BOOL recurse = YES; + + for (NSUInteger i = 0; i < args.count; i++) { + NSString *arg = args[i]; + if (!entryPath) { + if (![arg isEqualToString:@"-i"]) { + break; + } + i++; + if (i >= args.count) { + return nil; + } + entryPath = args[i]; + continue; + } + + if ([arg isEqualToString:@"-c"]) { + i++; + if (i >= args.count) { + return nil; + } + comment = args[i]; + } else if ([arg isEqualToString:@"-n"]) { + i++; + if (i >= args.count) { + return nil; + } + name = args[i]; + } else if ([arg isEqualToString:@"-m"]) { + i++; + if (i >= args.count) { + return nil; + } + methodName = args[i]; + } else if ([arg isEqualToString:@"-l"]) { + i++; + if (i >= args.count) { + return nil; + } + level = args[i]; + } else if ([arg isEqualToString:@"-h"]) { + permitHiddenFiles = YES; + } else if ([arg isEqualToString:@"-f"]) { + recurse = NO; + } else { + return nil; + } + } + + entryPath = NOZCLI_normalizedPath(envPath, envPath); + if (!entryPath) { + return nil; + } + + return [[self alloc] initWithEntryPath:entryPath name:name level:level methodName:methodName comment:comment permitHiddenFiles:permitHiddenFiles recurse:recurse]; +} + +- (instancetype)initWithEntryPath:(NSString *)entryPath + name:(NSString *)name + level:(NSString *)level + methodName:(NSString *)methodName + comment:(NSString *)comment + permitHiddenFiles:(BOOL)permitHiddenFiles + recurse:(BOOL)recurse +{ + if (self = [super init]) { + _entryPath = [entryPath copy]; + _name = [name copy]; + _level = [level copy]; + _methodName = [methodName copy]; + _comment = [comment copy]; + _permitHiddenFiles = permitHiddenFiles; + _recurse = recurse; + } + return self; +} + +@end + +@implementation NOZCLIZipModeInfo + +- (instancetype)initWithGlobalComment:(NSString *)globalComment + methodToNumberMap:(NSDictionary *)methodToNumberMap + entryInfos:(NSArray *)entryInfos + outputFile:(NSString *)outputFile + environmentPath:(NSString *)envPath +{ + if (self = [super init]) { + _globalComment = [globalComment copy]; + _methodToNumberMap = [methodToNumberMap copy]; + _entryInfos = [entryInfos copy]; + _outputFile = [outputFile copy]; + _envPath = [envPath copy]; + } + return self; +} + +@end diff --git a/noz/main.m b/noz/main.m new file mode 100644 index 0000000..eccc584 --- /dev/null +++ b/noz/main.m @@ -0,0 +1,44 @@ +// +// main.m +// noz +// +// Created by Nolan O'Brien on 5/6/17. +// Copyright © 2017 NSProgrammer. All rights reserved. +// + +#import "NOZCLI.h" + +static NSArray *parseArgs(int argc, const char * argv[]); + +int main(int argc, const char * argv[]) +{ + int retVal = -1; + @autoreleasepool { + NSString *exe = nil; + NSArray *args = parseArgs(argc, argv); + if (args.count > 0) { + NSString *path = args[0]; + exe = [path lastPathComponent]; + path = [path stringByDeletingLastPathComponent]; + args = [args subarrayWithRange:NSMakeRange(1, args.count - 1)]; + NSString *currentDir = @(getenv("PWD")); + + retVal = NOZCLI_main(exe, path, currentDir, args); + } + + if (retVal == -1) { + NOZCLI_printUsage(exe); + } + } + + return retVal; +} + +static NSArray *parseArgs(int argc, const char * argv[]) +{ + NSMutableArray *args = [[NSMutableArray alloc] init]; + for (int c = 0; c < argc; c++) { + [args addObject:@(argv[c])]; + } + return [args copy]; +}