diff --git a/.gitignore b/.gitignore index 3ee5ebb..04c30e7 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,9 @@ build **/xcuserdata/* analyzer-output/** +# Generated by a Run Script build phase +Source/GeneratedSwiftImport.h + UnzipKitDemo/Pods/* UnzipKitDemo/Podfile.lock UnzipKitDemo/Carthage/* diff --git a/.travis.yml b/.travis.yml index c9a253d..f1e42cf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,9 +27,13 @@ matrix: script: ./Scripts/install-demo-libs.sh && xcodebuild -workspace UnzipKitDemo/UnzipKitDemo.xcworkspace -scheme UnzipKitDemo -destination 'platform=iOS Simulator,name=iPhone 7,OS=latest' -configuration Release analyze test ENABLE_NS_ASSERTIONS=1 CLANG_ANALYZER_OUTPUT=html CLANG_ANALYZER_OUTPUT_DIR=analyzer-output && [[ -z `find analyzer-output -name "*.html"` ]] - stage: Validate - env: Name=CocoaPods + env: Name=CocoaPods-Framework script: ./Scripts/cocoapod-validate.sh + - stage: Validate + env: Name=CocoaPods-Static-Lib + script: ./Scripts/cocoapod-validate.sh --use-libraries + - stage: Validate env: Name=Carthage script: ./Scripts/carthage-validate.sh diff --git a/README.md b/README.md index 89de8d5..681f1b3 100644 --- a/README.md +++ b/README.md @@ -100,9 +100,9 @@ You can also modify Zip archives: * Write data as a stream to the archive (from disk or over the network), using a block: ```Objective-C - BOOL success = [archive writeIntoBuffer:@"dir/filename.png" - error:&error - block: + BOOL success = [archive writeIntoBufferAtPath:@"dir/filename.png" + error:&error + block: ^BOOL(BOOL(^writeData)(const void *bytes, unsigned int length), NSError**(actionError)) { for (NSUInteger i = 0; i <= someFile.length; i += bufferSize) { const void *bytes = // some data @@ -139,9 +139,7 @@ The following methods support `NSProgress` and `NSProgressReporting`: * `performOnDataInArchive:error:` * `extractBufferedDataFromFile:error:action:` * `writeData:filePath:error:`* -* `writeData:filePath:fileDate:error:`* -* `writeData:filePath:fileDate:compressionMethod:password:error:`* -* `writeData:filePath:fileDate:compressionMethod:password:overwrite:error:`* +* `writeData:props:error:`* _* the `writeData...` methods don't support cancellation like the read-only methods do @@ -203,7 +201,7 @@ If you don't have a hierarchy of `NSProgress` instances, or if you want to obser Using either method above, you can call `[progress cancel]` to stop the operation in progress. It will cause the operation to fail, returning `nil` or `NO` (depending on the return type, and give an error with error code `UZKErrorCodeUserCancelled`. -Note: Cancellation is only supported on extraction methods, not write methods. +_Note: Cancellation is only supported on extraction methods, not write methods.__ # Documentation diff --git a/Scripts/cocoapod-validate.sh b/Scripts/cocoapod-validate.sh index 57fcc73..03b1a73 100755 --- a/Scripts/cocoapod-validate.sh +++ b/Scripts/cocoapod-validate.sh @@ -11,6 +11,6 @@ pod env # Using sed to remove logging from output until CocoaPods issue #7577 is implemented and I can use the # OS_ACTIVITY_MODE = disable environment variable from the test spec scheme -pod lib lint --verbose | sed -l '/xctest\[/d; /^$/d' +pod lib lint --verbose "$@" | sed -l '/xctest\[/d; /^$/d' . Scripts/unset-travis-tag.sh \ No newline at end of file diff --git a/Scripts/generate-swift-import-header.sh b/Scripts/generate-swift-import-header.sh new file mode 100755 index 0000000..f97ad06 --- /dev/null +++ b/Scripts/generate-swift-import-header.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +# Different styles of import statement need to be used for the Swift generated header, +# depending on the target type (static library or dynamic framework). This script reads +# the PACKAGE_TYPE environment variable Xcode sets to create the correct one at build +# time, allowing the library to be built as either type from CocoaPods + +# static library: com.apple.product-type.library.static +# dynamic framework: com.apple.package-type.wrapper.framework +[[ "${PACKAGE_TYPE}" = "com.apple.package-type.wrapper.framework" ]] \ + && SWIFTIMPORT="<${PRODUCT_MODULE_NAME}/${PRODUCT_MODULE_NAME}-Swift.h>" \ + || SWIFTIMPORT="\"${PRODUCT_MODULE_NAME}-Swift.h\"" + +if [ -z "$PODS_TARGET_SRCROOT" ]; then + PODS_TARGET_SRCROOT=${SOURCE_ROOT} + echo "Building in Xcode instead of CocoaPods. Overriding PODS_TARGET_SRCROOT with SOURCE_ROOT" +fi + +IMPORT_TEXT=\ +"/** +* +* This header was generated by a Run Script build phase. See +* Scripts/generate-swift-import-header.sh for more information +* +*/ + +#ifndef GeneratedSwiftImport_h +#define GeneratedSwiftImport_h + +#import ${SWIFTIMPORT} + +#endif /* GeneratedSwiftImport_h */ +" +echo "$IMPORT_TEXT" > ${PODS_TARGET_SRCROOT}/Source/GeneratedSwiftImport.h diff --git a/Source/UZKArchive.h b/Source/UZKArchive.h index 81c4619..657f8f0 100644 --- a/Source/UZKArchive.h +++ b/Source/UZKArchive.h @@ -9,6 +9,8 @@ #import "UZKFileInfo.h" +@class ZipFileProperties; + /** * Defines the various error codes that the listing and extraction methods return. * These are returned in NSError's [code]([NSError code]) field. @@ -406,7 +408,22 @@ extern NSString *UZKErrorDomain; error:(NSError **)error; /** - * Writes the data to the zip file, overwriting it if a file of that name already exists in the archive + * Writes the data to the zip file, overwriting it if a file of that name already exists + * in the archive. Supports NSProgress for progress reporting, which DOES NOT allow cancellation + * in the middle of writing + * + * @param data Data to write into the archive + * @param props Specifies the properties of the file being archived + * @param error Contains an NSError object when there was an error writing to the archive + * + * @return YES if successful, NO on error + */ +- (BOOL)writeData:(NSData *)data + props:(ZipFileProperties *)props + error:(NSError **)error; + +/** + * DEPRECATED: Writes the data to the zip file, overwriting it if a file of that name already exists in the archive * * @param data Data to write into the archive * @param filePath The full path to the target file in the archive @@ -418,10 +435,11 @@ extern NSString *UZKErrorDomain; - (BOOL)writeData:(NSData *)data filePath:(NSString *)filePath fileDate:(nullable NSDate *)fileDate - error:(NSError **)error; + error:(NSError **)error +__deprecated_msg("Use -writeData:props:error: instead"); /** - * Writes the data to the zip file, overwriting it if a file of that name already exists in the archive + * DEPRECATED: Writes the data to the zip file, overwriting it if a file of that name already exists in the archive * * @param data Data to write into the archive * @param filePath The full path to the target file in the archive @@ -437,10 +455,11 @@ extern NSString *UZKErrorDomain; fileDate:(nullable NSDate *)fileDate compressionMethod:(UZKCompressionMethod)method password:(nullable NSString *)password - error:(NSError **)error; + error:(NSError **)error +__deprecated_msg("Use -writeData:props:error: instead"); /** - * Writes the data to the zip file, overwriting only if specified with the overwrite flag. Overwriting + * DEPRECATED: Writes the data to the zip file, overwriting only if specified with the overwrite flag. Overwriting * presents a tradeoff: the whole archive needs to be copied (minus the file to be overwritten) before * the write begins. For a large archive, this can be slow. On the other hand, when not overwriting, * the size of the archive will grow each time the file is written. @@ -463,10 +482,11 @@ compressionMethod:(UZKCompressionMethod)method compressionMethod:(UZKCompressionMethod)method password:(nullable NSString *)password overwrite:(BOOL)overwrite - error:(NSError **)error; + error:(NSError **)error +__deprecated_msg("Use -writeData:props:error: instead"); /** - * Writes the data to the zip file, overwriting only if specified with the overwrite flag. Overwriting + * DEPRECATED: Writes the data to the zip file, overwriting only if specified with the overwrite flag. Overwriting * presents a tradeoff: the whole archive needs to be copied (minus the file to be overwritten) before * the write begins. For a large archive, this can be slow. On the other hand, when not overwriting, * the size of the archive will grow each time the file is written. @@ -491,7 +511,8 @@ compressionMethod:(UZKCompressionMethod)method compressionMethod:(UZKCompressionMethod)method password:(nullable NSString *)password overwrite:(BOOL)overwrite - error:(NSError **)error; + error:(NSError **)error +__deprecated_msg("Use -writeData:props:error: instead"); /** * Writes data to the zip file in pieces, allowing you to stream the write, so the entire contents @@ -511,12 +532,34 @@ compressionMethod:(UZKCompressionMethod)method * * @return YES if successful, NO on error */ -- (BOOL)writeIntoBuffer:(NSString *)filePath +- (BOOL)writeIntoBufferAtPath:(NSString *)filePath + error:(NSError **)error + block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError **actionError))action; + +/** + * Writes data to the zip file in pieces, allowing you to stream the write, so the entire contents + * don't need to reside in memory at once. It overwrites an existing file with the same name. + * + * @param props Specifies the properties of the file being archived + * @param error Contains an NSError object when there was an error writing to the archive + * @param action Contains your code to loop through the source bytes and write them to the + * archive. Each time a chunk of data is ready to be written, call writeData, + * passing in a pointer to the bytes and their length. Return YES if successful, + * or NO on error (in which case, you should assign the actionError parameter + * + * - *writeData* Call this block to write some bytes into the archive. It returns NO if the + * write failed. If this happens, you should return from the action block, and + * handle the NSError returned into the error reference + * - *actionError* Assign to an NSError instance before returning NO + * + * @return YES if successful, NO on error + */ +- (BOOL)writeIntoBuffer:(ZipFileProperties *)props error:(NSError **)error block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError **actionError))action; /** - * Writes data to the zip file in pieces, allowing you to stream the write, so the entire contents + * DEPRECATED: Writes data to the zip file in pieces, allowing you to stream the write, so the entire contents * don't need to reside in memory at once. It overwrites an existing file with the same name. * * @param filePath The full path to the target file in the archive @@ -537,10 +580,11 @@ compressionMethod:(UZKCompressionMethod)method - (BOOL)writeIntoBuffer:(NSString *)filePath fileDate:(nullable NSDate *)fileDate error:(NSError **)error - block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError **actionError))action; + block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError **actionError))action +__deprecated_msg("Use -writeIntoBuffer:props:error:block: instead"); /** - * Writes data to the zip file in pieces, allowing you to stream the write, so the entire contents + * DEPRECATED: Writes data to the zip file in pieces, allowing you to stream the write, so the entire contents * don't need to reside in memory at once. It overwrites an existing file with the same name. * * @param filePath The full path to the target file in the archive @@ -563,10 +607,11 @@ compressionMethod:(UZKCompressionMethod)method fileDate:(nullable NSDate *)fileDate compressionMethod:(UZKCompressionMethod)method error:(NSError **)error - block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError **actionError))action; + block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError **actionError))action +__deprecated_msg("Use -writeIntoBuffer:props:error:block: instead"); /** - * Writes data to the zip file in pieces, allowing you to stream the write, so the entire contents + * DEPRECATED: Writes data to the zip file in pieces, allowing you to stream the write, so the entire contents * don't need to reside in memory at once. It overwrites an existing file with the same name, only if * specified with the overwrite flag. Overwriting presents a tradeoff: the whole archive needs to be * copied (minus the file to be overwritten) before the write begins. For a large archive, this can @@ -597,10 +642,11 @@ compressionMethod:(UZKCompressionMethod)method compressionMethod:(UZKCompressionMethod)method overwrite:(BOOL)overwrite error:(NSError **)error - block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError **actionError))action; + block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError **actionError))action +__deprecated_msg("Use -writeIntoBuffer:props:error:block: instead"); /** - * Writes data to the zip file in pieces, allowing you to stream the write, so the entire contents + * DEPRECATED: Writes data to the zip file in pieces, allowing you to stream the write, so the entire contents * don't need to reside in memory at once. It overwrites an existing file with the same name, only if * specified with the overwrite flag. Overwriting presents a tradeoff: the whole archive needs to be * copied (minus the file to be overwritten) before the write begins. For a large archive, this can @@ -634,10 +680,11 @@ compressionMethod:(UZKCompressionMethod)method overwrite:(BOOL)overwrite CRC:(unsigned long)preCRC error:(NSError **)error - block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError **actionError))action; + block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError **actionError))action +__deprecated_msg("Use -writeIntoBuffer:props:error:block: instead"); /** - * Writes data to the zip file in pieces, allowing you to stream the write, so the entire contents + * DEPRECATED: Writes data to the zip file in pieces, allowing you to stream the write, so the entire contents * don't need to reside in memory at once. It overwrites an existing file with the same name, only if * specified with the overwrite flag. Overwriting presents a tradeoff: the whole archive needs to be * copied (minus the file to be overwritten) before the write begins. For a large archive, this can @@ -673,11 +720,12 @@ compressionMethod:(UZKCompressionMethod)method CRC:(unsigned long)preCRC password:(nullable NSString *)password error:(NSError **)error - block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError **actionError))action; + block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError **actionError))action +__deprecated_msg("Use -writeIntoBuffer:props:error:block: instead"); /** - * Writes data to the zip file in pieces, allowing you to stream the write, so the entire contents + * DEPRECATED: Writes data to the zip file in pieces, allowing you to stream the write, so the entire contents * don't need to reside in memory at once. It overwrites an existing file with the same name, only if * specified with the overwrite flag. Overwriting presents a tradeoff: the whole archive needs to be * copied (minus the file to be overwritten) before the write begins. For a large archive, this can @@ -715,7 +763,8 @@ compressionMethod:(UZKCompressionMethod)method CRC:(unsigned long)preCRC password:(nullable NSString *)password error:(NSError **)error - block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError **actionError))action; + block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError **actionError))action +__deprecated_msg("Use -writeIntoBuffer:props:error:block: instead"); /** * Removes the given file from the archive diff --git a/Source/UZKArchive.m b/Source/UZKArchive.m index 44208c4..cc687ab 100644 --- a/Source/UZKArchive.m +++ b/Source/UZKArchive.m @@ -6,9 +6,10 @@ #import "UZKArchive.h" +#import "GeneratedSwiftImport.h" + #import "zip.h" -#import "UZKFileInfo.h" #import "UZKFileInfo_Private.h" #import "UnzipKitMacros.h" #import "NSURL+UnzipKitExtensions.h" @@ -958,7 +959,7 @@ - (BOOL)checkDataIntegrityOfFile:(NSString *)filePath if (extractedCRC != fileInfo.CRC) { UZKLogError("CRC mismatch in '%{public}@': expected %010lu, found %010lu", - fileInfo.filename, (unsigned long)fileInfo.CRC, extractedCRC) + fileInfo.filename, (uLong)fileInfo.CRC, extractedCRC) dataIsValid = NO; } @@ -984,11 +985,7 @@ - (BOOL)writeData:(NSData *)data error:(NSError * __autoreleasing*)error { return [self writeData:data - filePath:filePath - fileDate:nil - compressionMethod:UZKCompressionMethodDefault - password:nil - overwrite:YES + props:[[ZipFileProperties alloc] init:filePath] error:error]; } @@ -1013,12 +1010,13 @@ - (BOOL)writeData:(NSData *)data password:(NSString *)password error:(NSError * __autoreleasing*)error { + ZipFileProperties *props = [[ZipFileProperties alloc] init:filePath]; + props.timestamp = fileDate; + props.compressionMethod = method; + props.password = password; + return [self writeData:data - filePath:filePath - fileDate:fileDate - compressionMethod:method - password:password - overwrite:YES + props:props error:error]; } @@ -1030,13 +1028,14 @@ - (BOOL)writeData:(NSData *)data overwrite:(BOOL)overwrite error:(NSError * __autoreleasing*)error { + ZipFileProperties *props = [[ZipFileProperties alloc] init:filePath]; + props.timestamp = fileDate; + props.compressionMethod = method; + props.password = password; + props.overwriteIfInArchive = overwrite; + return [self writeData:data - filePath:filePath - fileDate:fileDate - posixPermissions:0 - compressionMethod:method - password:password - overwrite:overwrite + props:props error:error]; } @@ -1048,13 +1047,27 @@ - (BOOL)writeData:(NSData *)data password:(NSString *)password overwrite:(BOOL)overwrite error:(NSError * __autoreleasing*)error +{ + ZipFileProperties *props = [[ZipFileProperties alloc] init:filePath]; + props.timestamp = fileDate; + props.permissions = permissions; + props.compressionMethod = method; + props.password = password; + props.overwriteIfInArchive = overwrite; + + return [self writeData:data + props:props + error:error]; +} + +- (BOOL)writeData:(NSData *)data + props:(ZipFileProperties *)props + error:(NSError * __autoreleasing*)error { UZKCreateActivity("Writing Data"); - UZKLogInfo("Writing data to archive. filePath: %{public}@, fileDate: %{time_t}ld, compressionMethod: %ld, password: %{public}@, " - "overwrite: %{public}@, error pointer specified: %{public}@", - filePath, lrint(fileDate.timeIntervalSince1970), (long)method, password != nil ? @"" : @"(null)", overwrite ? @"YES" : @"NO", - error ? @"YES" : @"NO"); + UZKLogInfo("Writing data to archive. Properties: %{public}@, error pointer specified: %{public}@", + props, error ? @"YES" : @"NO"); const NSUInteger bufferSize = 4096; //Arbitrary const void *bytes = data.bytes; @@ -1064,6 +1077,7 @@ - (BOOL)writeData:(NSData *)data __weak UZKArchive *welf = self; uLong calculatedCRC = crc32(0, data.bytes, (uInt)data.length); + props.crc = calculatedCRC; UZKLogDebug("Calculated CRC: %010lu", calculatedCRC); BOOL success = [self performWriteAction:^int(uLong *crc, NSError * __autoreleasing*innerError) { @@ -1091,29 +1105,17 @@ - (BOOL)writeData:(NSData *)data return ZIP_OK; } - filePath:filePath - fileDate:fileDate - posixPermissions:permissions - compressionMethod:method - password:password - overwrite:overwrite - CRC:calculatedCRC + props:props error:error]; return success; } -- (BOOL)writeIntoBuffer:(NSString *)filePath - error:(NSError * __autoreleasing*)error - block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError * __autoreleasing*actionError))action +- (BOOL)writeIntoBufferAtPath:(NSString *)filePath + error:(NSError * __autoreleasing*)error + block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError * __autoreleasing*actionError))action { - return [self writeIntoBuffer:filePath - fileDate:nil - posixPermissions:0 - compressionMethod:UZKCompressionMethodDefault - overwrite:YES - CRC:0 - password:nil + return [self writeIntoBuffer:[[ZipFileProperties alloc] init:filePath] error:error block:action]; } @@ -1123,15 +1125,10 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath error:(NSError * __autoreleasing*)error block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError * __autoreleasing*actionError))action { - return [self writeIntoBuffer:filePath - fileDate:fileDate - posixPermissions:0 - compressionMethod:UZKCompressionMethodDefault - overwrite:YES - CRC:0 - password:nil - error:error - block:action]; + ZipFileProperties *props = [[ZipFileProperties alloc] init:filePath]; + props.timestamp = fileDate; + + return [self writeIntoBuffer:props error:error block:action]; } - (BOOL)writeIntoBuffer:(NSString *)filePath @@ -1140,15 +1137,11 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath error:(NSError * __autoreleasing*)error block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError * __autoreleasing*actionError))action { - return [self writeIntoBuffer:filePath - fileDate:fileDate - posixPermissions:0 - compressionMethod:method - overwrite:YES - CRC:0 - password:nil - error:error - block:action]; + ZipFileProperties *props = [[ZipFileProperties alloc] init:filePath]; + props.timestamp = fileDate; + props.compressionMethod = method; + + return [self writeIntoBuffer:props error:error block:action]; } - (BOOL)writeIntoBuffer:(NSString *)filePath @@ -1158,15 +1151,12 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath error:(NSError * __autoreleasing*)error block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError * __autoreleasing*actionError))action { - return [self writeIntoBuffer:filePath - fileDate:fileDate - posixPermissions:0 - compressionMethod:method - overwrite:overwrite - CRC:0 - password:nil - error:error - block:action]; + ZipFileProperties *props = [[ZipFileProperties alloc] init:filePath]; + props.timestamp = fileDate; + props.compressionMethod = method; + props.overwriteIfInArchive = overwrite; + + return [self writeIntoBuffer:props error:error block:action]; } - (BOOL)writeIntoBuffer:(NSString *)filePath @@ -1177,15 +1167,13 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath error:(NSError *__autoreleasing *)error block:(BOOL (^)(BOOL (^)(const void *, unsigned int), NSError *__autoreleasing *))action { - return [self writeIntoBuffer:filePath - fileDate:fileDate - posixPermissions:0 - compressionMethod:method - overwrite:overwrite - CRC:preCRC - password:nil - error:error - block:action]; + ZipFileProperties *props = [[ZipFileProperties alloc] init:filePath]; + props.timestamp = fileDate; + props.compressionMethod = method; + props.overwriteIfInArchive = overwrite; + props.crc = preCRC; + + return [self writeIntoBuffer:props error:error block:action]; } - (BOOL)writeIntoBuffer:(NSString *)filePath @@ -1197,15 +1185,14 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath error:(NSError *__autoreleasing *)error block:(BOOL (^)(BOOL (^)(const void *, unsigned int), NSError *__autoreleasing *))action { - return [self writeIntoBuffer:filePath - fileDate:fileDate - posixPermissions:0 - compressionMethod:method - overwrite:overwrite - CRC:preCRC - password:password - error:error - block:action]; + ZipFileProperties *props = [[ZipFileProperties alloc] init:filePath]; + props.timestamp = fileDate; + props.compressionMethod = method; + props.overwriteIfInArchive = overwrite; + props.crc = preCRC; + props.password = password; + + return [self writeIntoBuffer:props error:error block:action]; } - (BOOL)writeIntoBuffer:(NSString *)filePath @@ -1217,15 +1204,30 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath password:(NSString *)password error:(NSError *__autoreleasing *)error block:(BOOL (^)(BOOL (^)(const void *, unsigned int), NSError *__autoreleasing *))action +{ + ZipFileProperties *props = [[ZipFileProperties alloc] init:filePath]; + props.timestamp = fileDate; + props.permissions = permissions; + props.compressionMethod = method; + props.overwriteIfInArchive = overwrite; + props.crc = preCRC; + props.password = password; + + return [self writeIntoBuffer:props error:error block:action]; +} + +- (BOOL)writeIntoBuffer:(ZipFileProperties *)props + error:(NSError *__autoreleasing *)error + block:(BOOL (^)(BOOL (^)(const void *, unsigned int), NSError *__autoreleasing *))action { UZKCreateActivity("Writing Into Buffer"); - UZKLogInfo("Writing data into buffer. filePath: %{public}@, fileDate: %{time_t}ld, compressionMethod: %ld, " - "overwrite: %{public}@, CRC: %010lu, password: %{public}@, error pointer specified: %{public}@", - filePath, lrint(fileDate.timeIntervalSince1970), (long)method, overwrite ? @"YES" : @"NO", preCRC, - password != nil ? @"" : @"(null)", error ? @"YES" : @"NO"); + UZKLogInfo("Writing data into buffer. Properties: %{public}@, error pointer specified: %{public}@", + props, error ? @"YES" : @"NO"); - NSAssert(preCRC != 0 || ([password length] == 0 && [self.password length] == 0), + uLong preCRC = props.crc; + + NSAssert(preCRC != 0 || ([props.password length] == 0 && [self.password length] == 0), @"Cannot provide a password when writing into a buffer, " "unless a CRC is provided up front for inclusion in the header", nil); @@ -1265,18 +1267,12 @@ - (BOOL)writeIntoBuffer:(NSString *)filePath preCRCStr, calculatedCRCStr]; UZKLogError("UZKErrorCodePreCRCMismatch: %{public}@", detail); return [welf assignError:innerError code:UZKErrorCodePreCRCMismatch - detail:detail]; + detail:detail]; } return result; } - filePath:filePath - fileDate:fileDate - posixPermissions:permissions - compressionMethod:method - password:password - overwrite:overwrite - CRC:preCRC + props:props error:error]; return success; @@ -1609,7 +1605,7 @@ - (BOOL)deleteFile:(NSString *)filePath error:(NSError * __autoreleasing*)error // Close destination archive UZKLogDebug("Closing file in destination archive"); - err = zipCloseFileInZipRaw64(dest_zip, unzipInfo.uncompressed_size, unzipInfo.crc); + err = zipCloseFileInZipRaw64(dest_zip, unzipInfo.uncompressed_size, (uLong)unzipInfo.crc); if (err != UNZ_OK) { NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error closing %@ in destination zip while deleting %@ (%d)", @"UnzipKit", _resources, @"Detailed error string"), currentFileName, filePath, err]; @@ -1813,19 +1809,15 @@ - (BOOL)performActionWithArchiveOpen:(void(^)(NSError * __autoreleasing*innerErr } - (BOOL)performWriteAction:(int(^)(uLong *crc, NSError * __autoreleasing*innerError))write - filePath:(NSString *)filePath - fileDate:(NSDate *)fileDate - posixPermissions:(short)permissions - compressionMethod:(UZKCompressionMethod)method - password:(NSString *)password - overwrite:(BOOL)overwrite - CRC:(uLong)crc + props:(ZipFileProperties *)props error:(NSError * __autoreleasing*)error { UZKCreateActivity("Performing Write"); - if (overwrite) { - UZKLogInfo("Overwriting %{public}@ if it already exists. Will look for existing file to delete", filePath); + NSString *password = props.password; + + if (props.overwriteIfInArchive) { + UZKLogInfo("Overwriting %{public}@ if it already exists. Will look for existing file to delete", props.fullFilePath); NSError *listFilesError = nil; NSArray *existingFiles; @@ -1835,11 +1827,11 @@ - (BOOL)performWriteAction:(int(^)(uLong *crc, NSError * __autoreleasing*innerEr existingFiles = [self listFileInfo:&listFilesError]; } - if (existingFiles) { - UZKLogDebug("Existing files found. Looking for matches to filePath %{public}@", filePath); + if ([existingFiles count]) { + UZKLogDebug("Existing files found. Looking for matches to filePath %{public}@", props.fullFilePath); NSIndexSet *matchingFiles = [existingFiles indexesOfObjectsPassingTest: ^BOOL(UZKFileInfo *info, NSUInteger idx, BOOL *stop) { - if ([info.filename isEqualToString:filePath]) { + if ([info.filename isEqualToString:props.fullFilePath]) { *stop = YES; return YES; } @@ -1847,16 +1839,16 @@ - (BOOL)performWriteAction:(int(^)(uLong *crc, NSError * __autoreleasing*innerEr return NO; }]; - if (matchingFiles.count > 0 && ![self deleteFile:filePath error:error]) { - UZKLogError("Failed to delete %{public}@ before writing new data for it", filePath); + if (matchingFiles.count > 0 && ![self deleteFile:props.fullFilePath error:error]) { + UZKLogError("Failed to delete %{public}@ before writing new data for it", props.fullFilePath); return NO; } } } if (!password) { - UZKLogDebug("No password specified for file. Using archive's password: %{public}@", password != nil ? @"" : @"(null)"); password = self.password; + UZKLogDebug("No password specified for file. Using archive's password: %{public}@", password != nil ? @"" : @"(null)"); } __weak UZKArchive *welf = self; @@ -1864,9 +1856,9 @@ - (BOOL)performWriteAction:(int(^)(uLong *crc, NSError * __autoreleasing*innerEr BOOL success = [self performActionWithArchiveOpen:^(NSError * __autoreleasing*innerError) { UZKCreateActivity("Performing Write Action"); - UZKLogDebug("Making zip_fileinfo struct for date %{time_t}ld", lrint(fileDate.timeIntervalSince1970)); - zip_fileinfo zi = [UZKArchive zipFileInfoForDate:fileDate - posixPermissions:permissions]; + UZKLogDebug("Making zip_fileinfo struct for date %{time_t}ld", lrint(props.timestamp.timeIntervalSince1970)); + zip_fileinfo zi = [UZKArchive zipFileInfoForDate:props.timestamp + posixPermissions:props.permissions]; const char *passwordStr = NULL; @@ -1877,19 +1869,19 @@ - (BOOL)performWriteAction:(int(^)(uLong *crc, NSError * __autoreleasing*innerEr UZKLogDebug("Opening new file..."); int err = zipOpenNewFileInZip3(welf.zipFile, - filePath.UTF8String, + props.fullFilePath.UTF8String, &zi, NULL, 0, NULL, 0, NULL, - (method != UZKCompressionMethodNone) ? Z_DEFLATED : 0, - method, + (props.compressionMethod != UZKCompressionMethodNone) ? Z_DEFLATED : 0, + props.compressionMethod, 0, -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, passwordStr, - crc); + props.crc); if (err != ZIP_OK) { NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error opening file '%@' for write (%d)", @"UnzipKit", _resources, @"Detailed error string"), - filePath, err]; + props.fullFilePath, err]; UZKLogError("UZKErrorCodeFileOpenForWrite: %{public}@", detail); [welf assignError:innerError code:UZKErrorCodeFileOpenForWrite detail:detail]; @@ -1901,7 +1893,7 @@ - (BOOL)performWriteAction:(int(^)(uLong *crc, NSError * __autoreleasing*innerEr err = write(&outCRC, innerError); if (err < 0) { NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error writing to file '%@' (%d)", @"UnzipKit", _resources, @"Detailed error string"), - filePath, err]; + props.fullFilePath, err]; UZKLogError("UZKErrorCodeFileOpenForWrite: %{public}@", detail); [welf assignError:innerError code:UZKErrorCodeFileWrite detail:detail]; @@ -1912,7 +1904,7 @@ - (BOOL)performWriteAction:(int(^)(uLong *crc, NSError * __autoreleasing*innerEr err = zipCloseFileInZipRaw(self.zipFile, 0, outCRC); if (err != ZIP_OK) { NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error closing file '%@' for write (%d)", @"UnzipKit", _resources, @"Detailed error string"), - filePath, err]; + props.fullFilePath, err]; UZKLogError("UZKErrorCodeFileOpenForWrite: %{public}@", detail); [welf assignError:innerError code:UZKErrorCodeFileWrite detail:detail]; diff --git a/Source/UnzipKit.h b/Source/UnzipKit.h index d390a9d..8864a29 100644 --- a/Source/UnzipKit.h +++ b/Source/UnzipKit.h @@ -15,5 +15,5 @@ FOUNDATION_EXPORT double UnzipKitVersionNumber; FOUNDATION_EXPORT const unsigned char UnzipKitVersionString[]; -#import "UZKArchive.h" -#import "UZKFileInfo.h" +#import +#import diff --git a/Source/ZipFileProperties.swift b/Source/ZipFileProperties.swift new file mode 100644 index 0000000..e5244e3 --- /dev/null +++ b/Source/ZipFileProperties.swift @@ -0,0 +1,75 @@ +// +// ZipFileArgs.swift +// UnzipKit +// +// Created by Dov Frankel on 8/1/19. +// Copyright © 2019 Abbey Code. All rights reserved. +// + +import Foundation + +// Not a struct because of Objective-C compatibility +@objc public class ZipFileProperties: NSObject { + + + // MARK: - Required + + /// The full path and filename of the file to be written + @objc public var fullFilePath: String + + + // MARK: - Optional/Defaulted + + /// The UZKCompressionMethod to use (Default, None, Fastest, Best) + @objc public var compressionMethod = UZKCompressionMethod.default + + /** + The CRC-32 checksum for the data being written. Only required + if encrypting the file, otherwise it will be calculated automatically + */ + @objc public var crc: UInt = 0 + + /** + If true, and the file exists, delete it before writing. If false, append + the data into the archive without removing it first (legacy Objective-Zip + behavior). Turn this off to gain speed at the expense of creating bloated + archives. Defaults to true + */ + @objc public var overwriteIfInArchive = true + + /// Override the password associated with the rest of the archive (not a recommended practice) + @objc public var password: String? = nil + + /** + The desired POSIX permissions of the archived file (e.g. 0o644 in Swift + or 0644U in Objective-C). Defaults to 644 (Read/Write for owner, + read-only for group and others) + */ + @objc public var permissions: Int16 = 0o644 + + /// The timestamp of the file to be written + @objc public var timestamp: Date? + + + // MARK: - Initializer + + @objc public init(_ fullFilePath: String) { + self.fullFilePath = fullFilePath + } + + + // MARK: - Overrides + + public override var description: String { + let crcStr = String(crc, radix: 16).uppercased() + let password = self.password != nil ? "" : "none" + let permissionStr = String(permissions, radix: 8).uppercased() + + return """ + { fullFilePath: \(fullFilePath), compressionMethod: \(compressionMethod), crc: \(crcStr), + overwriteIfInArchive: \(overwriteIfInArchive), password: \(password), + permissions: \(permissionStr), timestamp: \(timestamp?.description ?? "none") } + """.replacingOccurrences(of: "\n", with: " "); + } + +} diff --git a/Tests/CheckDataTests.m b/Tests/CheckDataTests.m index fe1f748..fceeb75 100644 --- a/Tests/CheckDataTests.m +++ b/Tests/CheckDataTests.m @@ -7,7 +7,7 @@ // #import "UZKArchiveTestCase.h" -#import "UnzipKit.h" +@import UnzipKit; @interface CheckDataTests : UZKArchiveTestCase @end diff --git a/Tests/CommentsTests.m b/Tests/CommentsTests.m index 3a26b7e..90a7cd4 100644 --- a/Tests/CommentsTests.m +++ b/Tests/CommentsTests.m @@ -7,7 +7,7 @@ // #import "UZKArchiveTestCase.h" -#import "UnzipKit.h" +@import UnzipKit; @interface CommentsTests : UZKArchiveTestCase @end diff --git a/Tests/DeleteFileTests.m b/Tests/DeleteFileTests.m index 71db954..02715a8 100644 --- a/Tests/DeleteFileTests.m +++ b/Tests/DeleteFileTests.m @@ -7,7 +7,7 @@ // #import "UZKArchiveTestCase.h" -#import "UnzipKit.h" +@import UnzipKit; @interface DeleteFileTests : UZKArchiveTestCase @end diff --git a/Tests/ErrorHandlingTests.m b/Tests/ErrorHandlingTests.m index 8f4d783..eb48188 100644 --- a/Tests/ErrorHandlingTests.m +++ b/Tests/ErrorHandlingTests.m @@ -7,7 +7,7 @@ // #import "UZKArchiveTestCase.h" -#import "UnzipKit.h" +@import UnzipKit; @interface ErrorHandlingTests : UZKArchiveTestCase @end diff --git a/Tests/ExtractBufferedDataTests.m b/Tests/ExtractBufferedDataTests.m index d341e01..ff5d045 100644 --- a/Tests/ExtractBufferedDataTests.m +++ b/Tests/ExtractBufferedDataTests.m @@ -6,7 +6,7 @@ // Copyright (c) 2015 Abbey Code. All rights reserved. // -#import "UnzipKit.h" +@import UnzipKit; #import "UZKArchiveTestCase.h" #import "UnzipKitMacros.h" diff --git a/Tests/ExtractDataTests.m b/Tests/ExtractDataTests.m index 3c71d27..3b2a193 100644 --- a/Tests/ExtractDataTests.m +++ b/Tests/ExtractDataTests.m @@ -7,7 +7,7 @@ // #import "UZKArchiveTestCase.h" -#import "UnzipKit.h" +@import UnzipKit; #import "UnzipKitMacros.h" @interface ExtractDataTests : UZKArchiveTestCase diff --git a/Tests/FileDescriptorUsageTests.m b/Tests/FileDescriptorUsageTests.m index a824da7..d750105 100644 --- a/Tests/FileDescriptorUsageTests.m +++ b/Tests/FileDescriptorUsageTests.m @@ -7,7 +7,7 @@ // #import "UZKArchiveTestCase.h" -#import "UnzipKit.h" +@import UnzipKit; @interface FileDescriptorUsageTests : UZKArchiveTestCase @end @@ -143,6 +143,72 @@ - (void)testFileDescriptorUsage_WriteIntoArchive NSString *fileContents = [NSString stringWithFormat:@"This is a string %d", x]; NSData *newFileData = [fileContents dataUsingEncoding:NSUTF8StringEncoding]; NSString *fileName = fileList.lastObject; + BOOL writeResult = [archive writeData:newFileData + filePath:fileName + error:&writeError]; + XCTAssertTrue(writeResult, @"Failed to write to archive (attempt %d)", x); + XCTAssertNil(writeError, @"Error writing to archive (attempt %d)", x); + + NSError *extractError = nil; + NSData *extractedData = [archive extractDataFromFile:fileName + error:&extractError]; + XCTAssertEqualObjects(extractedData, newFileData, @"Incorrect data written to file (attempt %d)", x); + XCTAssertNil(extractError, @"Error extracting from archive (attempt %d)", x); + } + } + + NSInteger finalFileCount = [self numberOfOpenFileHandles]; + + XCTAssertEqualWithAccuracy(initialFileCount, finalFileCount, 5, @"File descriptors were left open"); +} + + +- (void)testFileDescriptorUsage_WriteIntoArchive_deprecatedOverload +{ + NSInteger initialFileCount = [self numberOfOpenFileHandles]; + + NSURL *testArchiveOriginalURL = [self largeArchive]; + NSString *testArchiveName = testArchiveOriginalURL.lastPathComponent; + NSFileManager *fm = [NSFileManager defaultManager]; + + for (NSInteger i = 0; i < 100; i++) { + // Keep this test from stalling out the build + printf("testFileDescriptorUsage_WriteIntoArchive: Iteration %ld/100\n", (long)i); + + NSString *tempDir = [self randomDirectoryName]; + NSURL *tempDirURL = [self.tempDirectory URLByAppendingPathComponent:tempDir]; + NSURL *testArchiveCopyURL = [tempDirURL URLByAppendingPathComponent:testArchiveName]; + + NSError *error = nil; + [fm createDirectoryAtURL:tempDirURL + withIntermediateDirectories:YES + attributes:nil + error:&error]; + + XCTAssertNil(error, @"Error creating temp directory: %@", tempDirURL); + + [fm copyItemAtURL:testArchiveOriginalURL toURL:testArchiveCopyURL error:&error]; + XCTAssertNil(error, @"Error copying test archive \n from: %@ \n\n to: %@", testArchiveOriginalURL, testArchiveCopyURL); + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveCopyURL error:nil]; + + NSArray *fileList = [archive listFilenames:&error]; + XCTAssertNotNil(fileList, @"No filenames listed"); + + for (NSString *fileName in fileList) { + NSData *fileData = [archive extractDataFromFile:fileName + error:&error]; + XCTAssertNotNil(fileData, @"No data extracted"); + XCTAssertNil(error, @"Error extracting data"); + } + + for (int x = 0; x < 50; x++) { + NSError *writeError = nil; + NSString *fileContents = [NSString stringWithFormat:@"This is a string %d", x]; + NSData *newFileData = [fileContents dataUsingEncoding:NSUTF8StringEncoding]; + NSString *fileName = fileList.lastObject; +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" BOOL writeResult = [archive writeData:newFileData filePath:fileName fileDate:[NSDate date] @@ -150,6 +216,7 @@ - (void)testFileDescriptorUsage_WriteIntoArchive password:nil overwrite:YES error:&writeError]; +#pragma clang diagnostic pop XCTAssertTrue(writeResult, @"Failed to write to archive (attempt %d)", x); XCTAssertNil(writeError, @"Error writing to archive (attempt %d)", x); diff --git a/Tests/ListFileInfoTests.m b/Tests/ListFileInfoTests.m index dd2f830..4d66005 100644 --- a/Tests/ListFileInfoTests.m +++ b/Tests/ListFileInfoTests.m @@ -7,7 +7,7 @@ // #import "UZKArchiveTestCase.h" -#import "UnzipKit.h" +@import UnzipKit; @interface ListFileInfoTests : UZKArchiveTestCase @end diff --git a/Tests/ListFilenamesTests.m b/Tests/ListFilenamesTests.m index 77eca2b..42b2322 100644 --- a/Tests/ListFilenamesTests.m +++ b/Tests/ListFilenamesTests.m @@ -7,7 +7,7 @@ // #import "UZKArchiveTestCase.h" -#import "UnzipKit.h" +@import UnzipKit; @interface ListFilenamesTests : UZKArchiveTestCase @end diff --git a/Tests/ModesTests.m b/Tests/ModesTests.m index 9d739bc..06287c1 100644 --- a/Tests/ModesTests.m +++ b/Tests/ModesTests.m @@ -7,7 +7,7 @@ // #import "UZKArchiveTestCase.h" -#import "UnzipKit.h" +@import UnzipKit; @interface ModesTests : UZKArchiveTestCase @@ -72,9 +72,9 @@ - (void)testModes_ReadWhileWriting UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; NSError *writeError = nil; - [archive writeIntoBuffer:@"newFile.zip" - error:&writeError - block: + [archive writeIntoBufferAtPath:@"newFile.zip" + error:&writeError + block: ^BOOL(BOOL(^writeData)(const void *bytes, unsigned int length), NSError**(actionError)) { NSError *readError = nil; [archive listFilenames:&readError]; @@ -93,15 +93,15 @@ - (void)testModes_NestedWrites UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; NSError *outerWriteError = nil; - [archive writeIntoBuffer:@"newFile.zip" - error:&outerWriteError - block: + [archive writeIntoBufferAtPath:@"newFile.zip" + error:&outerWriteError + block: ^BOOL(BOOL(^writeData)(const void *bytes, unsigned int length), NSError**(actionError)) { NSError *innerWriteError = nil; - [archive writeIntoBuffer:@"newFile.zip" - error:&innerWriteError - block:^BOOL(BOOL(^writeData)(const void *bytes, unsigned int length), NSError**(actionError)) {return YES;}]; - XCTAssertNotNil(innerWriteError, @"Nested write operation succeeded"); + [archive writeIntoBufferAtPath:@"newFile.zip" + error:&innerWriteError + block:^BOOL(BOOL(^writeData)(const void *bytes, unsigned int length), NSError**(actionError)) {return YES;}]; + XCTAssertNotNil(innerWriteError, @"Nested write operation succeeded"); XCTAssertEqual(innerWriteError.code, UZKErrorCodeFileWrite, @"Wrong error code returned"); return YES; diff --git a/Tests/MultithreadingTests.m b/Tests/MultithreadingTests.m index 8e11988..bce0df5 100644 --- a/Tests/MultithreadingTests.m +++ b/Tests/MultithreadingTests.m @@ -7,7 +7,7 @@ // #import "UZKArchiveTestCase.h" -#import "UnzipKit.h" +@import UnzipKit; #import "UnzipKitMacros.h" @interface MultithreadingTests : UZKArchiveTestCase diff --git a/Tests/PasswordProtectionTests.m b/Tests/PasswordProtectionTests.m index e942d98..0221997 100644 --- a/Tests/PasswordProtectionTests.m +++ b/Tests/PasswordProtectionTests.m @@ -7,7 +7,8 @@ // #import "UZKArchiveTestCase.h" -#import "UnzipKit.h" +@import UnzipKit; + @interface PasswordProtectionTests : UZKArchiveTestCase @end @@ -49,6 +50,44 @@ - (void)testIsPasswordProtected_PasswordRequired_LastFileOnly password = @"111111"; } + ZipFileProperties *props = [[ZipFileProperties alloc] init:testFile]; + props.password = password; + BOOL result = [writeArchive writeData:fileData + props:props + error:&writeError]; + + XCTAssertTrue(result, @"Error writing archive data"); + XCTAssertNil(writeError, @"Error writing to file %@: %@", testFile, writeError); + }]; + + UZKArchive *readArchive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + XCTAssertTrue(readArchive.isPasswordProtected, @"isPasswordProtected = NO for password-protected archive"); +} + +- (void)testIsPasswordProtected_PasswordRequired_LastFileOnly_deprecatedOverload +{ + NSArray *testFiles = [self.nonZipTestFilePaths.allObjects sortedArrayUsingSelector:@selector(compare:)]; + NSMutableArray *testFileData = [NSMutableArray arrayWithCapacity:testFiles.count]; + + NSURL *testArchiveURL = [self.tempDirectory URLByAppendingPathComponent:@"testIsPasswordProtected_PasswordRequired_LastFileOnly.zip"]; + + UZKArchive *writeArchive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + __block NSError *writeError = nil; + + [testFiles enumerateObjectsUsingBlock:^(NSString *testFile, NSUInteger idx, BOOL *stop) { + NSData *fileData = [NSData dataWithContentsOfURL:self.testFileURLs[testFile]]; + [testFileData addObject:fileData]; + + NSString *password = nil; + + if (idx == testFiles.count - 1) { + password = @"111111"; + } + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" BOOL result = [writeArchive writeData:fileData filePath:testFile fileDate:nil @@ -59,7 +98,8 @@ - (void)testIsPasswordProtected_PasswordRequired_LastFileOnly XCTAssertTrue(result, @"Error writing archive data"); XCTAssertNil(writeError, @"Error writing to file %@: %@", testFile, writeError); }]; - +#pragma clang diagnostic pop + UZKArchive *readArchive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; XCTAssertTrue(readArchive.isPasswordProtected, @"isPasswordProtected = NO for password-protected archive"); diff --git a/Tests/PerformOnDataTests.m b/Tests/PerformOnDataTests.m index c631458..1b4f5e3 100644 --- a/Tests/PerformOnDataTests.m +++ b/Tests/PerformOnDataTests.m @@ -7,7 +7,7 @@ // #import "UZKArchiveTestCase.h" -#import "UnzipKit.h" +@import UnzipKit; @interface PerformOnDataTests : UZKArchiveTestCase @end diff --git a/Tests/PerformOnFilesTests.m b/Tests/PerformOnFilesTests.m index c0908f4..f0038f0 100644 --- a/Tests/PerformOnFilesTests.m +++ b/Tests/PerformOnFilesTests.m @@ -7,7 +7,7 @@ // #import "UZKArchiveTestCase.h" -#import "UnzipKit.h" +@import UnzipKit; @interface PerformOnFilesTests : UZKArchiveTestCase @end diff --git a/Tests/PermissionsTests.swift b/Tests/PermissionsTests.swift index 265d83b..e6cd55b 100644 --- a/Tests/PermissionsTests.swift +++ b/Tests/PermissionsTests.swift @@ -7,6 +7,7 @@ // import XCTest +import UnzipKit class PermissionsTests: UZKArchiveTestCase { @@ -120,8 +121,9 @@ class PermissionsTests: UZKArchiveTestCase { let expectedPermissions: Int16 = 0o742 - try! writeArchive.write(testFileData, filePath: testFilename, fileDate: nil, posixPermissions: expectedPermissions, - compressionMethod: .default, password: nil, overwrite: true) + let props = ZipFileProperties(testFilename) + props.permissions = expectedPermissions; + try! writeArchive.write(testFileData, props: props) let readArchive = try! UZKArchive(url: testArchiveURL) let fileList = try! readArchive.listFileInfo() @@ -131,7 +133,29 @@ class PermissionsTests: UZKArchiveTestCase { XCTAssertEqual(actualPermissions, expectedPermissions) } + + func testWriteData_NonDefault_deprecatedOverload() { + let testArchiveURL = tempDirectory.appendingPathComponent("PermissionsTestWriteData.zip") + let testFilename = nonZipTestFilePaths.first! + let testFileURL = testFileURLs[testFilename] as! URL + let testFileData = try! Data(contentsOf: testFileURL) + + let writeArchive = try! UZKArchive(url: testArchiveURL) + + let expectedPermissions: Int16 = 0o742 + + try! writeArchive.deprecatedWrite(testFileData, filePath: testFilename, fileDate: nil, posixPermissions: expectedPermissions, + compressionMethod: .default, password: nil, overwrite: true) + let readArchive = try! UZKArchive(url: testArchiveURL) + let fileList = try! readArchive.listFileInfo() + + let writtenFileInfo = fileList.first { $0.filename == testFilename } + let actualPermissions = writtenFileInfo!.posixPermissions + + XCTAssertEqual(actualPermissions, expectedPermissions) + } + func testWriteIntoBuffer_Default() { let testArchiveURL = tempDirectory.appendingPathComponent("PermissionsTestWriteBufferedData.zip") let testFilename = nonZipTestFilePaths.first! @@ -139,7 +163,7 @@ class PermissionsTests: UZKArchiveTestCase { let testFileData = try! Data(contentsOf: testFileURL) let writeArchive = try! UZKArchive(url: testArchiveURL) - try! writeArchive.write(intoBuffer: testFilename) { (writeDataHandler, error) in + try! writeArchive.writeIntoBuffer(atPath: testFilename) { (writeDataHandler, error) in let buffer = testFileData.withUnsafeBytes { $0.baseAddress?.assumingMemoryBound(to: UInt32.self) } @@ -164,8 +188,37 @@ class PermissionsTests: UZKArchiveTestCase { let expectedPermissions: Int16 = 0o764 let writeArchive = try! UZKArchive(url: testArchiveURL) - try! writeArchive.write(intoBuffer: testFilename, fileDate: nil, posixPermissions: expectedPermissions, - compressionMethod: .default, overwrite: false, crc: 0, password: nil) + let props = ZipFileProperties(testFilename) + props.permissions = expectedPermissions + props.overwriteIfInArchive = false + try! writeArchive.write(intoBuffer: props) + { (writeDataHandler, error) in + let buffer = testFileData.withUnsafeBytes { + $0.baseAddress?.assumingMemoryBound(to: UInt32.self) + } + return writeDataHandler(buffer!, UInt32(testFileData.count)) + } + + let readArchive = try! UZKArchive(url: testArchiveURL) + let fileList = try! readArchive.listFileInfo() + + let writtenFileInfo = fileList.first { $0.filename == testFilename } + let actualPermissions = writtenFileInfo!.posixPermissions + + XCTAssertEqual(actualPermissions, expectedPermissions) + } + + func testWriteIntoBuffer_NonDefault_deprecatedOverload() { + let testArchiveURL = tempDirectory.appendingPathComponent("PermissionsTestWriteBufferedData_CustomPermissions.zip") + let testFilename = nonZipTestFilePaths.first! + let testFileURL = testFileURLs[testFilename] as! URL + let testFileData = try! Data(contentsOf: testFileURL) + + let expectedPermissions: Int16 = 0o764 + + let writeArchive = try! UZKArchive(url: testArchiveURL) + try! writeArchive.deprecatedWrite(intoBuffer: testFilename, fileDate: nil, posixPermissions: expectedPermissions, + compressionMethod: .default, overwrite: false, crc: 0, password: nil) { (writeDataHandler, error) in let buffer = testFileData.withUnsafeBytes { $0.baseAddress?.assumingMemoryBound(to: UInt32.self) diff --git a/Tests/PropertyTests.m b/Tests/PropertyTests.m index 136545a..8d5de5a 100644 --- a/Tests/PropertyTests.m +++ b/Tests/PropertyTests.m @@ -7,7 +7,7 @@ // #import "UZKArchiveTestCase.h" -#import "UnzipKit.h" +@import UnzipKit; @interface PropertyTests : UZKArchiveTestCase @end diff --git a/Tests/UZKArchive+Deprecated.h b/Tests/UZKArchive+Deprecated.h new file mode 100644 index 0000000..72a41ee --- /dev/null +++ b/Tests/UZKArchive+Deprecated.h @@ -0,0 +1,53 @@ +// +// UZKArchive+Deprecated.h +// UnzipKit +// +// Created by Dov Frankel on 8/12/19. +// Copyright © 2019 Abbey Code. All rights reserved. +// + +#import + +#import "UZKArchive.h" + +@interface UZKArchive (Deprecated) + +NS_ASSUME_NONNULL_BEGIN + +- (BOOL)deprecatedWriteData:(NSData *)data + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + error:(NSError **)error; + +- (BOOL)deprecatedWriteData:(NSData *)data + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + error:(NSError **)error; + +- (BOOL)deprecatedWriteData:(NSData *)data + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + posixPermissions:(short)permissions + compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + error:(NSError **)error; + +- (BOOL)deprecatedWriteIntoBuffer:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + posixPermissions:(short)permissions + compressionMethod:(UZKCompressionMethod)method + overwrite:(BOOL)overwrite + CRC:(unsigned long)preCRC + password:(nullable NSString *)password + error:(NSError **)error + block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError **actionError))action; + +NS_ASSUME_NONNULL_END + +@end diff --git a/Tests/UZKArchive+Deprecated.m b/Tests/UZKArchive+Deprecated.m new file mode 100644 index 0000000..cc0422d --- /dev/null +++ b/Tests/UZKArchive+Deprecated.m @@ -0,0 +1,97 @@ +// +// UZKArchive+Deprecated.m +// UnzipKit +// +// Created by Dov Frankel on 8/12/19. +// Copyright © 2019 Abbey Code. All rights reserved. +// + +#import "UZKArchive+Deprecated.h" +#import "UZKArchive.h" + +@implementation UZKArchive (Deprecated) + +- (BOOL)deprecatedWriteData:(NSData *)data + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + error:(NSError *__autoreleasing *)error +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return [self writeData:data + filePath:filePath + fileDate:fileDate + compressionMethod:method + password:password + error:error]; +#pragma clang diagnostic pop +} + +- (BOOL)deprecatedWriteData:(NSData *)data + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + error:(NSError *__autoreleasing *)error +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return [self writeData:data + filePath:filePath + fileDate:fileDate + compressionMethod:method + password:password + overwrite:overwrite + error:error]; +#pragma clang diagnostic pop +} + +- (BOOL)deprecatedWriteData:(NSData *)data + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + posixPermissions:(short)permissions + compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + error:(NSError *__autoreleasing *)error +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return [self writeData:data + filePath:filePath + fileDate:fileDate + posixPermissions:permissions + compressionMethod:method + password:password + overwrite:overwrite + error:error]; +#pragma clang diagnostic pop +} + +- (BOOL)deprecatedWriteIntoBuffer:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + posixPermissions:(short)permissions + compressionMethod:(UZKCompressionMethod)method + overwrite:(BOOL)overwrite + CRC:(unsigned long)preCRC + password:(nullable NSString *)password + error:(NSError *__autoreleasing *)error + block:(BOOL(^)(BOOL(^writeData)(const void *bytes, unsigned int length), NSError **actionError))action +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return [self writeIntoBuffer:filePath + fileDate:fileDate + posixPermissions:permissions + compressionMethod:method + overwrite:overwrite + CRC:preCRC + password:password + error:error + block:action]; +#pragma clang diagnostic pop +} +@end diff --git a/Tests/UZKArchiveTestCase.m b/Tests/UZKArchiveTestCase.m index 01c761b..37fac77 100644 --- a/Tests/UZKArchiveTestCase.m +++ b/Tests/UZKArchiveTestCase.m @@ -15,7 +15,9 @@ #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wundef" -#if UNIFIED_LOGGING_SUPPORTED +// UnzipKit compiles the library files into the test target directly, so these +// are defined inside UZKArchive.m there. Only necessary in Xcode project +#if defined(UNIFIED_LOGGING_SUPPORTED) && defined(CODE_IMPORTED_AS_LIB) os_log_t unzipkit_log; BOOL unzipkitIsAtLeast10_13SDK; #endif diff --git a/Tests/UnzipKitTests-Bridging-Header.h b/Tests/UnzipKitTests-Bridging-Header.h index 6ba7233..40fe7be 100644 --- a/Tests/UnzipKitTests-Bridging-Header.h +++ b/Tests/UnzipKitTests-Bridging-Header.h @@ -5,4 +5,5 @@ #import "UZKArchive.h" #import "zip.h" -#import "UZKArchiveTestCase.h" \ No newline at end of file +#import "UZKArchiveTestCase.h" +#import "UZKArchive+Deprecated.h" diff --git a/Tests/WriteBufferedDataTests.m b/Tests/WriteBufferedDataTests.m index 7245866..ceda811 100644 --- a/Tests/WriteBufferedDataTests.m +++ b/Tests/WriteBufferedDataTests.m @@ -8,7 +8,8 @@ #import "UZKArchiveTestCase.h" #import "zip.h" -#import "UnzipKit.h" +@import UnzipKit; + @interface WriteBufferedDataTests : UZKArchiveTestCase @end @@ -37,6 +38,65 @@ - (void)testWriteInfoBuffer NSError *writeError = nil; const void *bytes = fileData.bytes; + ZipFileProperties *props = [[ZipFileProperties alloc] init:testFile]; + props.timestamp = testDates[idx]; + + BOOL result = [archive writeIntoBuffer:props + error:&writeError + block: + ^BOOL(BOOL(^writeData)(const void *bytes, unsigned int length), NSError**(actionError)) { + for (NSUInteger i = 0; i <= fileData.length; i += bufferSize) { + unsigned int size = (unsigned int)MIN(fileData.length - i, bufferSize); + BOOL writeSuccess = writeData(&bytes[i], size); + XCTAssertTrue(writeSuccess, @"Failed to write buffered data"); + } + + return YES; + }]; + + XCTAssertTrue(result, @"Error writing archive data"); + XCTAssertNil(writeError, @"Error writing to file %@: %@", testFile, writeError); + }]; + + __block NSError *readError = nil; + __block NSUInteger idx = 0; + + [archive performOnDataInArchive:^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + NSData *expectedData = testFileData[idx]; + unsigned long expectedCRC = crc32(0, expectedData.bytes, (unsigned int)expectedData.length); + + XCTAssertEqualObjects(fileInfo.filename, testFiles[idx], @"Incorrect filename in archive"); + XCTAssertEqualObjects(fileInfo.timestamp, testDates[idx], @"Incorrect timestamp in archive"); + XCTAssertEqual(fileInfo.CRC, expectedCRC, @"CRC of extracted data doesn't match what was written"); + XCTAssertEqualObjects(fileData, expectedData, @"Data extracted doesn't match what was written"); + + idx++; + } error:&readError]; +} + +- (void)testWriteInfoBuffer_deprecatedOverload +{ + NSArray *testFiles = [self.nonZipTestFilePaths.allObjects sortedArrayUsingSelector:@selector(compare:)]; + NSArray *testDates = @[[[UZKArchiveTestCase dateFormatter] dateFromString:@"12/20/2014 9:35 AM"], + [[UZKArchiveTestCase dateFormatter] dateFromString:@"12/21/2014 10:00 AM"], + [[UZKArchiveTestCase dateFormatter] dateFromString:@"12/22/2014 11:54 PM"]]; + NSMutableArray *testFileData = [NSMutableArray arrayWithCapacity:testFiles.count]; + + NSURL *testArchiveURL = [self.tempDirectory URLByAppendingPathComponent:@"WriteIntoBufferTest.zip"]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + unsigned int bufferSize = 1024; //Arbitrary + + [testFiles enumerateObjectsUsingBlock:^(NSString *testFile, NSUInteger idx, BOOL *stop) { + NSData *fileData = [NSData dataWithContentsOfURL:self.testFileURLs[testFile]]; + [testFileData addObject:fileData]; + + NSError *writeError = nil; + const void *bytes = fileData.bytes; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" BOOL result = [archive writeIntoBuffer:testFile fileDate:testDates[idx] compressionMethod:UZKCompressionMethodDefault @@ -56,6 +116,7 @@ - (void)testWriteInfoBuffer XCTAssertTrue(result, @"Error writing archive data"); XCTAssertNil(writeError, @"Error writing to file %@: %@", testFile, writeError); }]; +#pragma clang diagnostic pop __block NSError *readError = nil; __block NSUInteger idx = 0; @@ -83,6 +144,38 @@ - (void)testWriteInfoBuffer_Failure NSError *writeError = nil; + ZipFileProperties *props = [[ZipFileProperties alloc] init:@"Test File A.txt"]; + props.timestamp = [[UZKArchiveTestCase dateFormatter] dateFromString:@"12/20/2014 9:35 AM"]; + + BOOL result = [archive writeIntoBuffer:props + error:&writeError + block: + ^BOOL(BOOL(^writeData)(const void *bytes, unsigned int length), NSError**(actionError)) { + NSError *bufferError = [NSError errorWithDomain:@"UnzipKitUnitTest" + code:errorCode + userInfo:@{}]; + *actionError = bufferError; + + return NO; + }]; + + XCTAssertFalse(result, @"Success returned during failure writing archive data"); + XCTAssertNotNil(writeError, @"No error after failure writing to archive"); + XCTAssertEqual(writeError.code, errorCode, @"Wrong error code returned"); +} + +- (void)testWriteInfoBuffer_Failure_deprecatedOverload +{ + NSURL *testArchiveURL = [self.tempDirectory URLByAppendingPathComponent:@"WriteIntoBufferTest_Failure.zip"]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSInteger errorCode = 718; + + NSError *writeError = nil; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" BOOL result = [archive writeIntoBuffer:@"Test File A.txt" fileDate:[[UZKArchiveTestCase dateFormatter] dateFromString:@"12/20/2014 9:35 AM"] compressionMethod:UZKCompressionMethodDefault @@ -97,7 +190,8 @@ - (void)testWriteInfoBuffer_Failure return NO; }]; - +#pragma clang diagnostic pop + XCTAssertFalse(result, @"Success returned during failure writing archive data"); XCTAssertNotNil(writeError, @"No error after failure writing to archive"); XCTAssertEqual(writeError.code, errorCode, @"Wrong error code returned"); @@ -120,6 +214,49 @@ - (void)testWriteInfoBuffer_PasswordGiven const void *bytes = fileData.bytes; + ZipFileProperties *props = [[ZipFileProperties alloc] init:testFile]; + props.crc = 841856539; + + BOOL result = [archive writeIntoBuffer:props + error:&writeError + block: + ^BOOL(BOOL(^writeData)(const void *bytes, unsigned int length), NSError**(actionError)) { + for (NSUInteger i = 0; i <= fileData.length; i += bufferSize) { + unsigned int size = (unsigned int)MIN(fileData.length - i, bufferSize); + BOOL writeSuccess = writeData(&bytes[i], size); + XCTAssertTrue(writeSuccess, @"Failed to write buffered data"); + } + + return YES; + }]; + + XCTAssertTrue(result, @"Error writing archive data"); + XCTAssertNil(writeError, @"Error writing to file %@: %@", testFile, writeError); + + BOOL extractSuccess = [self extractArchive:testArchiveURL + password:password]; + + XCTAssertTrue(extractSuccess, @"Failed to extract archive (encryption is incorrect)"); +} + +- (void)testWriteInfoBuffer_PasswordGiven_deprecatedOverload +{ + NSURL *testArchiveURL = [self.tempDirectory URLByAppendingPathComponent:@"testWriteInfoBuffer_PasswordGiven.zip"]; + + NSString *password = @"a password"; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL password:password error:nil]; + + NSError *writeError = nil; + + unsigned int bufferSize = 1024; //Arbitrary + + NSString *testFile = @"Test File A.txt"; + NSData *fileData = [NSData dataWithContentsOfURL:self.testFileURLs[testFile]]; + + const void *bytes = fileData.bytes; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" BOOL result = [archive writeIntoBuffer:testFile fileDate:nil compressionMethod:UZKCompressionMethodDefault @@ -136,7 +273,8 @@ - (void)testWriteInfoBuffer_PasswordGiven return YES; }]; - +#pragma clang diagnostic pop + XCTAssertTrue(result, @"Error writing archive data"); XCTAssertNil(writeError, @"Error writing to file %@: %@", testFile, writeError); @@ -155,6 +293,28 @@ - (void)testWriteInfoBuffer_PasswordGiven_NoCRC NSError *writeError = nil; + ZipFileProperties *props = [[ZipFileProperties alloc] init:@"Test File A.txt"]; + props.timestamp = [[UZKArchiveTestCase dateFormatter] dateFromString:@"12/20/2014 9:35 AM"]; + + XCTAssertThrows([archive writeIntoBuffer:props + error:&writeError + block: + ^BOOL(BOOL(^writeData)(const void *bytes, unsigned int length), NSError**(actionError)) { + return YES; + }], + @"No assertion failed when streaming an encypted file with no CRC given"); +} + +- (void)testWriteInfoBuffer_PasswordGiven_NoCRC_deprecatedOverload +{ + NSURL *testArchiveURL = [self.tempDirectory URLByAppendingPathComponent:@"testWriteInfoBuffer_PasswordGiven_NoCRC.zip"]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL password:@"a password" error:nil]; + + NSError *writeError = nil; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" XCTAssertThrows([archive writeIntoBuffer:@"Test File A.txt" fileDate:[[UZKArchiveTestCase dateFormatter] dateFromString:@"12/20/2014 9:35 AM"] compressionMethod:UZKCompressionMethodDefault @@ -165,6 +325,7 @@ - (void)testWriteInfoBuffer_PasswordGiven_NoCRC return YES; }], @"No assertion failed when streaming an encypted file with no CRC given"); +#pragma clang diagnostic pop } - (void)testWriteInfoBuffer_PasswordGiven_MismatchedCRC @@ -182,6 +343,46 @@ - (void)testWriteInfoBuffer_PasswordGiven_MismatchedCRC const void *bytes = fileData.bytes; + ZipFileProperties *props = [[ZipFileProperties alloc] init:@"Test File A.txt"]; + props.crc = 3; + + BOOL result = [archive writeIntoBuffer:props + error:&writeError + block: + ^BOOL(BOOL(^writeData)(const void *bytes, unsigned int length), NSError**(actionError)) { + for (NSUInteger i = 0; i <= fileData.length; i += bufferSize) { + unsigned int size = (unsigned int)MIN(fileData.length - i, bufferSize); + BOOL writeSuccess = writeData(&bytes[i], size); + XCTAssertTrue(writeSuccess, @"Failed to write buffered data"); + } + + return YES; + }]; + + XCTAssertFalse(result, @"No error writing archive data"); + XCTAssertNotNil(writeError, @"No error writing to file"); + XCTAssertEqual(writeError.code, UZKErrorCodePreCRCMismatch, @"Wrong error code returned for CRC mismatch"); + XCTAssertTrue([writeError.localizedRecoverySuggestion containsString:@"0000000003"], @"Bad CRC not included in message"); + XCTAssertTrue([writeError.localizedRecoverySuggestion containsString:@"0841856539"], @"Good CRC not included in message"); +} + +- (void)testWriteInfoBuffer_PasswordGiven_MismatchedCRC_deprecatedOverload +{ + NSURL *testArchiveURL = [self.tempDirectory URLByAppendingPathComponent:@"testWriteInfoBuffer_PasswordGiven_MismatchedCRC.zip"]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL password:@"a password" error:nil]; + + NSError *writeError = nil; + + unsigned int bufferSize = 1024; //Arbitrary + + NSString *testFile = @"Test File A.txt"; + NSData *fileData = [NSData dataWithContentsOfURL:self.testFileURLs[testFile]]; + + const void *bytes = fileData.bytes; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" BOOL result = [archive writeIntoBuffer:testFile fileDate:nil compressionMethod:UZKCompressionMethodDefault @@ -198,7 +399,8 @@ - (void)testWriteInfoBuffer_PasswordGiven_MismatchedCRC return YES; }]; - +#pragma clang diagnostic pop + XCTAssertFalse(result, @"No error writing archive data"); XCTAssertNotNil(writeError, @"No error writing to file"); XCTAssertEqual(writeError.code, UZKErrorCodePreCRCMismatch, @"Wrong error code returned for CRC mismatch"); diff --git a/Tests/WriteDataTests.swift b/Tests/WriteDataTests.swift index f265bf6..84e0377 100644 --- a/Tests/WriteDataTests.swift +++ b/Tests/WriteDataTests.swift @@ -32,8 +32,49 @@ class WriteDataTests: UZKArchiveTestCase { testFileData.append(fileData!) do { - try archive.write(fileData!, filePath: testFilePath, fileDate: testDates[index], - compressionMethod: .default, password: nil) + let props = ZipFileProperties(testFilePath) + props.timestamp = testDates[index] + try archive.write(fileData!, props: props) + } catch let error as NSError { + XCTFail("Error writing to file \(testFilePath): \(error)") + } + } + + var index = 0 + + try! archive.performOnData(inArchive: { (fileInfo, fileData, stop) -> Void in + let expectedData = testFileData[index] + let expectedCRC = crc32(0, (expectedData as NSData).bytes.bindMemory(to: Bytef.self, capacity: expectedData.count), uInt(expectedData.count)) + + XCTAssertEqual(fileInfo.filename, testFilePaths[index], "Incorrect filename in archive") + XCTAssertEqual(fileInfo.timestamp, testDates[index]!, "Incorrect timestamp in archive") + XCTAssertEqual(fileInfo.crc, expectedCRC, "CRC of extracted data doesn't match what was written") + XCTAssertEqual(fileData, expectedData, "Data extracted doesn't match what was written") + + index += 1; + }) + + XCTAssert(index > 0, "No data iterated through") + } + + func testWriteData_deprecatedOverload() { + let testFilePaths = [String](nonZipTestFilePaths).sorted(by: <) + let testDates = [ + UZKArchiveTestCase.dateFormatter().date(from: "12/20/2014 9:35 AM"), + UZKArchiveTestCase.dateFormatter().date(from: "12/21/2014 10:00 AM"), + UZKArchiveTestCase.dateFormatter().date(from: "12/22/2014 11:54 PM")] + var testFileData = [Data]() + + let testArchiveURL = tempDirectory.appendingPathComponent("WriteDataTest.zip") + let archive = try! UZKArchive(url: testArchiveURL) + + for (index, testFilePath) in testFilePaths.enumerated() { + let fileData = try? Data(contentsOf: testFileURLs[testFilePath] as! URL) + testFileData.append(fileData!) + + do { + try archive.deprecatedWrite(fileData!, filePath: testFilePath, fileDate: testDates[index], + compressionMethod: .default, password: nil) } catch let error as NSError { XCTFail("Error writing to file \(testFilePath): \(error)") } @@ -72,8 +113,49 @@ class WriteDataTests: UZKArchiveTestCase { testFileData.append(fileData!) do { - try archive.write(fileData!, filePath: testFilePath, fileDate: testDates[index], - compressionMethod: .default, password: nil) + let props = ZipFileProperties(testFilePath) + props.timestamp = testDates[index] + try archive.write(fileData!, props: props) + } catch let error as NSError { + XCTFail("Error writing to file \(testFilePath): \(error)") + } + } + + var index = 0 + + try! archive.performOnData(inArchive: { (fileInfo, fileData, stop) -> Void in + let expectedData = testFileData[index] + let expectedCRC = crc32(0, (expectedData as NSData).bytes.bindMemory(to: Bytef.self, capacity: expectedData.count), uInt(expectedData.count)) + + XCTAssertEqual(fileInfo.filename, testFilePaths[index], "Incorrect filename in archive") + XCTAssertEqual(fileInfo.timestamp, testDates[index]!, "Incorrect timestamp in archive") + XCTAssertEqual(fileInfo.crc, expectedCRC, "CRC of extracted data doesn't match what was written") + XCTAssertEqual(fileData, expectedData, "Data extracted doesn't match what was written") + + index += 1; + }) + + XCTAssert(index > 0, "No data iterated through") + } + + func testWriteData_Unicode_deprecatedOverload() { + let testFilePaths = [String](nonZipUnicodeFilePaths).sorted(by: <) + let testDates = [ + UZKArchiveTestCase.dateFormatter().date(from: "12/20/2014 9:35 AM"), + UZKArchiveTestCase.dateFormatter().date(from: "12/21/2014 10:00 AM"), + UZKArchiveTestCase.dateFormatter().date(from: "12/22/2014 11:54 PM")] + var testFileData = [Data]() + + let testArchiveURL = tempDirectory.appendingPathComponent("UnicodeWriteDataTest.zip") + let archive = try! UZKArchive(url: testArchiveURL) + + for (index, testFilePath) in testFilePaths.enumerated() { + let fileData = try? Data(contentsOf: unicodeFileURLs[testFilePath] as! URL) + testFileData.append(fileData!) + + do { + try archive.deprecatedWrite(fileData!, filePath: testFilePath, fileDate: testDates[index], + compressionMethod: .default, password: nil) } catch let error as NSError { XCTFail("Error writing to file \(testFilePath): \(error)") } @@ -112,8 +194,9 @@ class WriteDataTests: UZKArchiveTestCase { testFileData.append(fileData!) do { - try archive.write(fileData!, filePath: testFilePath, fileDate: testDates[index], - compressionMethod: .default, password: nil) + let props = ZipFileProperties(testFilePath) + props.timestamp = testDates[index] + try archive.write(fileData!, props: props) } catch let error as NSError { XCTFail("Error writing to file \(testFilePath): \(error)") } @@ -142,8 +225,83 @@ class WriteDataTests: UZKArchiveTestCase { let x = testFilePaths.count - 1 - i do { - try archive.write(testFileData[x], filePath: testFilePaths[i], - fileDate: testDates[x], compressionMethod: .default, password: nil) + let props = ZipFileProperties(testFilePaths[i]) + props.timestamp = testDates[x] + try archive.write(testFileData[x], props: props) + } catch let error as NSError { + XCTFail("Error writing to file \(testFilePaths[x]) with data of " + + "file \(testFilePaths[i]): \(error)") + } + } + + var forwardIndex = 0 + + try! archive.performOnData(inArchive: { (fileInfo, fileData, stop) -> Void in + XCTAssertEqual(fileInfo.filename, testFilePaths[forwardIndex], "Incorrect filename in archive"); + + let reverseIndex = testFilePaths.count - 1 - forwardIndex + + let expectedData = testFileData[reverseIndex] + let expectedCRC = crc32(0, (expectedData as NSData).bytes.bindMemory(to: Bytef.self, capacity: expectedData.count), uInt(expectedData.count)) + + XCTAssertEqual(fileInfo.timestamp, testDates[reverseIndex]!, "Incorrect timestamp in archive") + XCTAssertEqual(fileInfo.crc, expectedCRC, "CRC of extracted data doesn't match what was written") + XCTAssertEqual(fileData, expectedData, "Data extracted doesn't match what was written") + + forwardIndex += 1; + }) + + XCTAssert(index > 0, "No data iterated through") + } + + func testWriteData_Overwrite_deprecatedOverload() { + let testFilePaths = [String](nonZipTestFilePaths).sorted(by: <) + let testDates = [ + UZKArchiveTestCase.dateFormatter().date(from: "12/20/2014 9:35 AM"), + UZKArchiveTestCase.dateFormatter().date(from: "12/21/2014 10:00 AM"), + UZKArchiveTestCase.dateFormatter().date(from: "12/22/2014 11:54 PM")] + var testFileData = [Data]() + + let testArchiveURL = tempDirectory.appendingPathComponent("RewriteDataTest.zip") + let archive = try! UZKArchive(url: testArchiveURL) + + for (index, testFilePath) in testFilePaths.enumerated() { + let fileData = try? Data(contentsOf: testFileURLs[testFilePath] as! URL) + testFileData.append(fileData!) + + do { + try archive.deprecatedWrite(fileData!, filePath: testFilePath, fileDate: testDates[index], + compressionMethod: .default, password: nil) + } catch let error as NSError { + XCTFail("Error writing to file \(testFilePath): \(error)") + } + } + + var index = 0 + + try! archive.performOnData(inArchive: { (fileInfo, fileData, stop) -> Void in + let expectedData = testFileData[index] + let expectedCRC = crc32(0, (expectedData as NSData).bytes.bindMemory(to: Bytef.self, capacity: expectedData.count), uInt(expectedData.count)) + + XCTAssertEqual(fileInfo.filename, testFilePaths[index], "Incorrect filename in archive") + XCTAssertEqual(fileInfo.timestamp, testDates[index]!, "Incorrect timestamp in archive") + XCTAssertEqual(fileInfo.crc, expectedCRC, "CRC of extracted data doesn't match what was written") + XCTAssertEqual(fileData, expectedData, "Data extracted doesn't match what was written") + + index += 1; + }) + + XCTAssert(index > 0, "No data iterated through") + + // Now write the files' contents to the zip in reverse + NSLog("Testing a second write, by reversing the contents and timestamps of the files from the first run") + + for i in 0.. Void in + let expectedData = testFileData[index] + let expectedCRC = crc32(0, (expectedData as NSData).bytes.bindMemory(to: Bytef.self, capacity: expectedData.count), uInt(expectedData.count)) + + XCTAssertEqual(fileInfo.filename, testFilePaths[index], "Incorrect filename in archive") + XCTAssertEqual(fileInfo.timestamp, testDates[index]!, "Incorrect timestamp in archive") + XCTAssertEqual(fileInfo.crc, expectedCRC, "CRC of extracted data doesn't match what was written") + XCTAssertEqual(fileData, expectedData, "Data extracted doesn't match what was written") + + index += 1; + }) + + XCTAssert(index > 0, "No data iterated through") + + // Now write the files' contents to the zip in reverse + NSLog("Testing a second write, by reversing the contents and timestamps of the files from the first run") + + for i in 0.. Void in + XCTAssertEqual(fileInfo.filename, testFilePaths[forwardIndex], "Incorrect filename in archive"); + + let reverseIndex = testFilePaths.count - 1 - forwardIndex + + let expectedData = testFileData[reverseIndex] + let expectedCRC = crc32(0, (expectedData as NSData).bytes.bindMemory(to: Bytef.self, capacity: expectedData.count), uInt(expectedData.count)) + + XCTAssertEqual(fileInfo.timestamp, testDates[reverseIndex]!, "Incorrect timestamp in archive") + XCTAssertEqual(fileInfo.crc, expectedCRC, "CRC of extracted data doesn't match what was written") + XCTAssertEqual(fileData, expectedData, "Data extracted doesn't match what was written") + + forwardIndex += 1; + }) + + XCTAssert(index > 0, "No data iterated through") + } + + func testWriteData_Overwrite_Unicode_deprecatedOverload() { + let testFilePaths = [String](nonZipUnicodeFilePaths).sorted(by: <) + let testDates = [ + UZKArchiveTestCase.dateFormatter().date(from: "12/20/2014 9:35 AM"), + UZKArchiveTestCase.dateFormatter().date(from: "12/21/2014 10:00 AM"), + UZKArchiveTestCase.dateFormatter().date(from: "12/22/2014 11:54 PM")] + var testFileData = [Data]() + + let testArchiveURL = tempDirectory.appendingPathComponent("RewriteDataTest.zip") + let archive = try! UZKArchive(url: testArchiveURL) + + for (index, testFilePath) in testFilePaths.enumerated() { + let fileData = try? Data(contentsOf: unicodeFileURLs[testFilePath] as! URL) + testFileData.append(fileData!) + + do { + try archive.deprecatedWrite(fileData!, filePath: testFilePath, fileDate: testDates[index], + compressionMethod: .default, password: nil) } catch let error as NSError { XCTFail("Error writing to file \(testFilePath): \(error)") } @@ -216,8 +450,8 @@ class WriteDataTests: UZKArchiveTestCase { let x = testFilePaths.count - 1 - i do { - try archive.write(testFileData[x], filePath: testFilePaths[i], - fileDate: testDates[x], compressionMethod: .default, password: nil) + try archive.deprecatedWrite(testFileData[x], filePath: testFilePaths[i], + fileDate: testDates[x], compressionMethod: .default, password: nil) } catch let error as NSError { XCTFail("Error writing to file \(testFilePaths[x]) with data of " + "file \(testFilePaths[i]): \(error)") @@ -260,8 +494,71 @@ class WriteDataTests: UZKArchiveTestCase { testFileData.append(fileData!) do { - try archive.write(fileData!, filePath: testFilePath, fileDate: testDates[index], - compressionMethod: .default, password: nil, overwrite: false) + let props = ZipFileProperties(testFilePath) + props.overwriteIfInArchive = false + props.timestamp = testDates[index] + try archive.write(fileData!, props: props) + } catch let error as NSError { + XCTFail("Error writing to file \(testFilePath): \(error)") + } + } + + var index = 0 + + try! archive.performOnData(inArchive: { (fileInfo, fileData, stop) -> Void in + let expectedData = testFileData[index] + let expectedCRC = crc32(0, (expectedData as NSData).bytes.bindMemory(to: Bytef.self, capacity: expectedData.count), uInt(expectedData.count)) + + XCTAssertEqual(fileInfo.filename, testFilePaths[index], "Incorrect filename in archive") + XCTAssertEqual(fileInfo.timestamp, testDates[index]!, "Incorrect timestamp in archive") + XCTAssertEqual(fileInfo.crc, expectedCRC, "CRC of extracted data doesn't match what was written") + XCTAssertEqual(fileData, expectedData, "Data extracted doesn't match what was written") + + index += 1; + }) + + XCTAssert(index > 0, "No data iterated through") + + // Now write the files' contents to the zip in reverse + + for i in 0.. 0 { + XCTAssertEqual(lastFileSize, fileSize.uint64Value, "File changed size between writes") + } + + lastFileSize = fileSize.uint64Value + } + } + + func testWriteData_MultipleWrites_deprecatedOverload() { + let testArchiveURL = tempDirectory.appendingPathComponent("MultipleDataWriteTest.zip") + let testFilename = nonZipTestFilePaths.first! + let testFileURL = testFileURLs[testFilename] as! URL + let testFileData = try! Data(contentsOf: testFileURL) + + let archive = try! UZKArchive(url: testArchiveURL) + + var lastFileSize: UInt64 = 0 + + for _ in 0..<100 { + do { + try archive.deprecatedWrite(testFileData, filePath: testFilename, fileDate: nil, + compressionMethod: .default, password: nil) + } catch let error as NSError { + XCTFail("Error writing to file \(testFileURL): \(error)") + } + + let fm = FileManager.default + let fileAttributes = try! fm.attributesOfItem(atPath: testArchiveURL.path) let fileSize = fileAttributes[FileAttributeKey.size] as! NSNumber if lastFileSize > 0 { @@ -360,8 +686,31 @@ class WriteDataTests: UZKArchiveTestCase { let archive = try! UZKArchive(url: testArchiveURL) do { - try archive.write(testFileData, filePath: testFilename, fileDate: nil, - compressionMethod: .default, password: nil) + try archive.write(testFileData, filePath: testFilename) + } catch let error as NSError { + XCTFail("Error writing to file \(testFileURL): \(error)") + } + + let fileList = try! archive.listFileInfo() + let writtenFileInfo = fileList.first! + + let expectedDate = Date().timeIntervalSinceReferenceDate + let actualDate = writtenFileInfo.timestamp.timeIntervalSinceReferenceDate + + XCTAssertEqual(actualDate, expectedDate, accuracy: 30, "Incorrect default date value written to file") + } + + func testWriteData_DefaultDate_deprecatedOverload() { + let testArchiveURL = tempDirectory.appendingPathComponent("DefaultDateWriteTest.zip") + let testFilename = nonZipTestFilePaths.first! + let testFileURL = testFileURLs[testFilename] as! URL + let testFileData = try! Data(contentsOf: testFileURL) + + let archive = try! UZKArchive(url: testArchiveURL) + + do { + try archive.deprecatedWrite(testFileData, filePath: testFilename, fileDate: nil, + compressionMethod: .default, password: nil) } catch let error as NSError { XCTFail("Error writing to file \(testFileURL): \(error)") } @@ -449,9 +798,52 @@ class WriteDataTests: UZKArchiveTestCase { let newTextData = newText.data(using: String.Encoding.utf8) var writeSuccessful = true do { - try archive.write(newTextData!, filePath: textFileName, fileDate: nil, - compressionMethod: UZKCompressionMethod.default, password: nil, - overwrite: true) + try archive.write(newTextData!, filePath: textFileName) + } catch let error { + NSLog("Error writing data to archive on external volume: \(error)") + writeSuccessful = false + } + + XCTAssertTrue(writeSuccessful, "Failed to update archive on external volume") + + let archivedFileData = try! archive.extractData(fromFile: textFileName) + XCTAssertNotNil(archivedFileData, "No data extracted from file in archive on external volume") + + let archivedText = NSString(data: archivedFileData, encoding: String.Encoding.utf8.rawValue)! + XCTAssertEqual(archivedText as String, newText, "Incorrect text extracted from archive on external volume") + } + + func testWriteData_ExternalVolume_deprecatedOverload() { + // Create a simple zip file + let tempDirURL = URL(fileURLWithPath: self.randomDirectoryName()) + let textFileName = "testWriteData_ExternalVolume.txt" + let textFileURL = tempDirURL.appendingPathComponent(textFileName) + try! FileManager.default.createDirectory(at: tempDirURL, withIntermediateDirectories: true, attributes: [:]) + try! "This is the original text".write(to: textFileURL, atomically: false, encoding: String.Encoding.utf8) + let tempZipFileURL = self.archive(withFiles: [textFileURL]) + NSLog("Original ZIP file: \(String(describing: tempZipFileURL?.path))") + + // Write that zip file to contents of a DMG and mount it + let dmgSourceFolderURL = tempDirURL.appendingPathComponent("DMGSource") + try! FileManager.default.createDirectory(at: dmgSourceFolderURL, withIntermediateDirectories: true, attributes: [:]) + try! FileManager.default.copyItem(at: tempZipFileURL!, to: dmgSourceFolderURL.appendingPathComponent(tempZipFileURL!.lastPathComponent)) + let dmgURL = tempDirURL.appendingPathComponent("testWriteData_ExternalVolume.dmg") + let mountPoint = createAndMountDMG(path: dmgURL, source: dmgSourceFolderURL, fileSystem: .HFS)! + NSLog("Disk image: \(dmgURL.path)") + defer { + unmountDMG(URL: mountPoint) + } + + // Update a file from the archive with overwrite=YES + let externalVolumeZipURL = mountPoint.appendingPathComponent(tempZipFileURL!.lastPathComponent) + let archive = try! UZKArchive(url: externalVolumeZipURL) + let newText = "This is the new text" + let newTextData = newText.data(using: String.Encoding.utf8) + var writeSuccessful = true + do { + try archive.deprecatedWrite(newTextData!, filePath: textFileName, fileDate: nil, + compressionMethod: UZKCompressionMethod.default, password: nil, + overwrite: true) } catch let error { NSLog("Error writing data to archive on external volume: \(error)") writeSuccessful = false diff --git a/Tests/ZipFileDetectionTests.m b/Tests/ZipFileDetectionTests.m index 34d5384..c35b1af 100644 --- a/Tests/ZipFileDetectionTests.m +++ b/Tests/ZipFileDetectionTests.m @@ -7,7 +7,7 @@ // #import "UZKArchiveTestCase.h" -#import "UnzipKit.h" +@import UnzipKit; @interface ZipFileDetectionTests : UZKArchiveTestCase @end diff --git a/UnzipKit.podspec b/UnzipKit.podspec index 32a73ea..ca3d3c4 100644 --- a/UnzipKit.podspec +++ b/UnzipKit.podspec @@ -7,29 +7,38 @@ Pod::Spec.new do |s| s.author = { "Dov Frankel" => "dov@abbey-code.com" } s.social_media_url = "https://twitter.com/dovfrankel" s.source = { :git => "https://github.com/abbeycode/UnzipKit.git", :tag => "#{s.version}" } - s.ios.deployment_target = "9.0" - s.osx.deployment_target = "10.9" + s.ios.deployment_target = "12.0" + s.osx.deployment_target = "10.14" + s.swift_version = "5.0" + s.library = "z" s.requires_arc = 'Source/**/*' s.public_header_files = "Source/UnzipKit.h", "Source/UZKArchive.h", "Source/UZKFileInfo.h" s.private_header_files = "Source/UZKFileInfo_Private.h" - s.source_files = "Source/**/*.{h,m}" + s.source_files = "Source/**/*.{h,m,swift}" s.exclude_files = 'Resources/**/Info.plist' s.resource_bundles = { 'UnzipKitResources' => ['Resources/**/*'] } + s.script_phases = { :name => "Generate UnzipKit Swift Header", + :script => "\"${PODS_TARGET_SRCROOT}\"/Scripts/generate-swift-import-header.sh", + :execution_position => :before_compile } s.test_spec 'Tests' do |test_spec| - test_spec.source_files = 'Tests/*.{h,m}' - test_spec.exclude_files = 'Tests/ExtractFilesTests.m' + test_spec.source_files = 'Tests/*.{h,m,swift}' + test_spec.exclude_files = 'Tests/ExtractFilesTests.m', + 'Tests/UnzipKitTests-Bridging-Header.h' + test_spec.preserve_paths = 'Tests/UnzipKitTests-Bridging-Header.h' test_spec.resources = ['Tests/Test Data'] - test_spec.pod_target_xcconfig = { "OTHER_CFLAGS" => "$(inherited) -Wno-unguarded-availability" } + test_spec.pod_target_xcconfig = { + "OTHER_CFLAGS" => "$(inherited) -Wno-unguarded-availability", + "SWIFT_OBJC_BRIDGING_HEADER" => "$(PODS_TARGET_SRCROOT)/Tests/UnzipKitTests-Bridging-Header.h" + } test_spec.scheme = { # Disable logging. Comment this line if you need diagnostic info :environment_variables => { "OS_ACTIVITY_MODE" => "disable" } } end - s.library = "z" s.subspec "minizip-lib" do |ss| ss.private_header_files = "Lib/MiniZip/*.h" diff --git a/UnzipKit.xcodeproj/project.pbxproj b/UnzipKit.xcodeproj/project.pbxproj index f4168f7..a715a15 100644 --- a/UnzipKit.xcodeproj/project.pbxproj +++ b/UnzipKit.xcodeproj/project.pbxproj @@ -21,6 +21,9 @@ 7A5652241F90E01C006B782E /* CheckDataTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A5652231F90E01C006B782E /* CheckDataTests.m */; }; 7A5A97011F89808900BCA061 /* ProgressReportingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A5A97001F89808900BCA061 /* ProgressReportingTests.m */; }; 7AA77FC822C16CF600121052 /* PermissionsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AA77FC722C16CF600121052 /* PermissionsTests.swift */; }; + 7AA9F194230199990076AD43 /* UZKArchive+Deprecated.h in Headers */ = {isa = PBXBuildFile; fileRef = 7AA9F192230199990076AD43 /* UZKArchive+Deprecated.h */; }; + 7AA9F195230199990076AD43 /* UZKArchive+Deprecated.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AA9F193230199990076AD43 /* UZKArchive+Deprecated.m */; }; + 7AB0E6AA22F3179F00AAE12F /* ZipFileProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AB0E6A922F3179F00AAE12F /* ZipFileProperties.swift */; }; 961A9BB51B306881007C4C6B /* WriteDataTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 961A9BB41B306881007C4C6B /* WriteDataTests.swift */; }; 962F9DA61D5D286B00205BEC /* UnzipKit.strings in Resources */ = {isa = PBXBuildFile; fileRef = 962F9DA41D5D286B00205BEC /* UnzipKit.strings */; }; 962F9DA81D5D288B00205BEC /* UnzipKitResources.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 962F9D9E1D5D281E00205BEC /* UnzipKitResources.bundle */; }; @@ -82,6 +85,9 @@ 7A5652231F90E01C006B782E /* CheckDataTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CheckDataTests.m; sourceTree = ""; }; 7A5A97001F89808900BCA061 /* ProgressReportingTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ProgressReportingTests.m; sourceTree = ""; }; 7AA77FC722C16CF600121052 /* PermissionsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionsTests.swift; sourceTree = ""; }; + 7AA9F192230199990076AD43 /* UZKArchive+Deprecated.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UZKArchive+Deprecated.h"; sourceTree = ""; }; + 7AA9F193230199990076AD43 /* UZKArchive+Deprecated.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "UZKArchive+Deprecated.m"; sourceTree = ""; }; + 7AB0E6A922F3179F00AAE12F /* ZipFileProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZipFileProperties.swift; sourceTree = ""; }; 961A9BB31B306880007C4C6B /* UnzipKitTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = "UnzipKitTests-Bridging-Header.h"; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; 961A9BB41B306881007C4C6B /* WriteDataTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WriteDataTests.swift; sourceTree = ""; }; 961A9BB61B306902007C4C6B /* UZKArchiveTestCase.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UZKArchiveTestCase.h; sourceTree = ""; }; @@ -225,6 +231,7 @@ 96EA65FF1A40E31900685B6D /* UZKFileInfo.h */, 963603521BFB7F6500BF0C4F /* UZKFileInfo_Private.h */, 96EA66001A40E31900685B6D /* UZKFileInfo.m */, + 7AB0E6A922F3179F00AAE12F /* ZipFileProperties.swift */, 96EA65A11A40AEAE00685B6D /* Supporting Files */, ); name = UnzipKit; @@ -245,6 +252,8 @@ 96EA65BF1A40BF1A00685B6D /* Test Data */, 961A9BB61B306902007C4C6B /* UZKArchiveTestCase.h */, 96FCC8401B306CDD00726AC7 /* UZKArchiveTestCase.m */, + 7AA9F192230199990076AD43 /* UZKArchive+Deprecated.h */, + 7AA9F193230199990076AD43 /* UZKArchive+Deprecated.m */, 963386B71EE89A49006B16BF /* UtilityMethods.swift */, 7A5652231F90E01C006B782E /* CheckDataTests.m */, 968C40DB1B586401004C128E /* CommentsTests.m */, @@ -338,6 +347,7 @@ buildActionMask = 2147483647; files = ( 96EA65BC1A40B2EC00685B6D /* UZKArchive.h in Headers */, + 7AA9F194230199990076AD43 /* UZKArchive+Deprecated.h in Headers */, 96EA66011A40E31900685B6D /* UZKFileInfo.h in Headers */, 96EA65A41A40AEAE00685B6D /* UnzipKit.h in Headers */, 963603531BFB815600BF0C4F /* UZKFileInfo_Private.h in Headers */, @@ -387,6 +397,7 @@ isa = PBXNativeTarget; buildConfigurationList = 96EA65B41A40AEAE00685B6D /* Build configuration list for PBXNativeTarget "UnzipKit" */; buildPhases = ( + 7A900754230AD74C004A95E5 /* ShellScript */, 96EA65991A40AEAE00685B6D /* Sources */, 96EA659A1A40AEAE00685B6D /* Frameworks */, 96EA659B1A40AEAE00685B6D /* Headers */, @@ -440,7 +451,7 @@ }; 96EA659D1A40AEAE00685B6D = { CreatedOnToolsVersion = 6.1.1; - LastSwiftMigration = 0830; + LastSwiftMigration = 1030; }; 96EA65A81A40AEAE00685B6D = { CreatedOnToolsVersion = 6.1.1; @@ -496,6 +507,26 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 7A900754230AD74C004A95E5 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SOURCE_ROOT}\"/Scripts/generate-swift-import-header.sh\n"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 7A0029131F93DB5800618503 /* Sources */ = { isa = PBXSourcesBuildPhase; @@ -519,6 +550,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 7AB0E6AA22F3179F00AAE12F /* ZipFileProperties.swift in Sources */, + 7AA9F195230199990076AD43 /* UZKArchive+Deprecated.m in Sources */, 96EA65BD1A40B2EC00685B6D /* UZKArchive.m in Sources */, 96EA66021A40E31900685B6D /* UZKFileInfo.m in Sources */, 965CF00C1D241A8F00C80A88 /* NSURL+UnzipKitExtensions.m in Sources */, @@ -711,8 +744,8 @@ GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", "$(inherited)", + "DEBUG=1", ); GCC_SYMBOLS_PRIVATE_EXTERN = NO; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -808,6 +841,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -827,6 +861,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "com.abbey-code.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -835,7 +870,10 @@ buildSettings = { CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; - GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; + GCC_PREPROCESSOR_DEFINITIONS = ( + "$(inherited)", + "CODE_IMPORTED_AS_LIB=1", + ); INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks $(DT_TOOLCHAIN_DIR)/usr/lib/swift/iphonesimulator"; PRODUCT_BUNDLE_IDENTIFIER = "com.abbey-code.$(PRODUCT_NAME:rfc1034identifier)"; @@ -861,6 +899,7 @@ buildSettings = { CLANG_ENABLE_MODULES = YES; COMBINE_HIDPI_IMAGES = YES; + GCC_PREPROCESSOR_DEFINITIONS = "CODE_IMPORTED_AS_LIB=1"; INFOPLIST_FILE = Tests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks $(DT_TOOLCHAIN_DIR)/usr/lib/swift/iphonesimulator"; PRODUCT_BUNDLE_IDENTIFIER = "com.abbey-code.$(PRODUCT_NAME:rfc1034identifier)"; diff --git a/UnzipKitDemo/Podfile b/UnzipKitDemo/Podfile index 4744369..01e588e 100644 --- a/UnzipKitDemo/Podfile +++ b/UnzipKitDemo/Podfile @@ -1,4 +1,4 @@ -platform :ios, '9.0' +platform :ios, '12.0' target 'UnzipKitDemo' do pod "UnzipKit", :path => "..", :testspecs => ['Tests'] diff --git a/UnzipKitDemo/UnzipKitDemo.xcodeproj/project.pbxproj b/UnzipKitDemo/UnzipKitDemo.xcodeproj/project.pbxproj index 695d821..598b422 100644 --- a/UnzipKitDemo/UnzipKitDemo.xcodeproj/project.pbxproj +++ b/UnzipKitDemo/UnzipKitDemo.xcodeproj/project.pbxproj @@ -14,12 +14,11 @@ 969E2FEC1AD573F100E19F7A /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 969E2FEB1AD573F100E19F7A /* Images.xcassets */; }; 969E2FEF1AD573F100E19F7A /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 969E2FED1AD573F100E19F7A /* LaunchScreen.xib */; }; 969E30091AD57BD000E19F7A /* Test Data in Resources */ = {isa = PBXBuildFile; fileRef = 969E30081AD57BD000E19F7A /* Test Data */; }; - D058D1B1EDCAA17D37F1EEC5 /* libPods-UnzipKitDemo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 836C8D3D2EBCC1B567DEBA7E /* libPods-UnzipKitDemo.a */; }; + E503D0FBEE04B7BC727B57B6 /* libPods-UnzipKitDemo.a in Frameworks */ = {isa = PBXBuildFile; fileRef = D3795F70E736484A471E6F15 /* libPods-UnzipKitDemo.a */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 2F87D9A1D0DCA68C622CCE05 /* Pods-UnzipKitDemo.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnzipKitDemo.debug.xcconfig"; path = "Pods/Target Support Files/Pods-UnzipKitDemo/Pods-UnzipKitDemo.debug.xcconfig"; sourceTree = ""; }; - 836C8D3D2EBCC1B567DEBA7E /* libPods-UnzipKitDemo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-UnzipKitDemo.a"; sourceTree = BUILT_PRODUCTS_DIR; }; 969381281D209CF5001B2ED8 /* libPods-UnzipKitDemo.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = "libPods-UnzipKitDemo.a"; path = "../../../Library/Developer/Xcode/DerivedData/UnzipKitDemo-hdmwkglyskhqhncppjlrcqmehjld/Build/Products/Debug-iphonesimulator/libPods-UnzipKitDemo.a"; sourceTree = ""; }; 9693812A1D209CFA001B2ED8 /* libUnzipKit.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libUnzipKit.a; path = "../../../Library/Developer/Xcode/DerivedData/UnzipKitDemo-hdmwkglyskhqhncppjlrcqmehjld/Build/Products/Debug-iphonesimulator/UnzipKit/libUnzipKit.a"; sourceTree = ""; }; 969E2FDF1AD573F100E19F7A /* UnzipKitDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UnzipKitDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -32,6 +31,7 @@ 969E30041AD5798D00E19F7A /* UnzipKitDemo-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UnzipKitDemo-Bridging-Header.h"; sourceTree = SOURCE_ROOT; }; 969E30081AD57BD000E19F7A /* Test Data */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "Test Data"; path = "../../Tests/Test Data"; sourceTree = ""; }; D07031CAE5D79F16E6A159A8 /* Pods-UnzipKitDemo.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-UnzipKitDemo.release.xcconfig"; path = "Pods/Target Support Files/Pods-UnzipKitDemo/Pods-UnzipKitDemo.release.xcconfig"; sourceTree = ""; }; + D3795F70E736484A471E6F15 /* libPods-UnzipKitDemo.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-UnzipKitDemo.a"; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -40,7 +40,7 @@ buildActionMask = 2147483647; files = ( 9693812B1D209CFA001B2ED8 /* libUnzipKit.a in Frameworks */, - D058D1B1EDCAA17D37F1EEC5 /* libPods-UnzipKitDemo.a in Frameworks */, + E503D0FBEE04B7BC727B57B6 /* libPods-UnzipKitDemo.a in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -102,7 +102,7 @@ children = ( 9693812A1D209CFA001B2ED8 /* libUnzipKit.a */, 969381281D209CF5001B2ED8 /* libPods-UnzipKitDemo.a */, - 836C8D3D2EBCC1B567DEBA7E /* libPods-UnzipKitDemo.a */, + D3795F70E736484A471E6F15 /* libPods-UnzipKitDemo.a */, ); name = Frameworks; sourceTree = ""; @@ -118,7 +118,7 @@ 969E2FDB1AD573F100E19F7A /* Sources */, 969E2FDC1AD573F100E19F7A /* Frameworks */, 969E2FDD1AD573F100E19F7A /* Resources */, - FFBBDB5F70B02F25F7B1C9FA /* [CP] Copy Pods Resources */, + E71BD50F86C41C113D4362A9 /* [CP] Copy Pods Resources */, ); buildRules = ( ); @@ -196,13 +196,13 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - FFBBDB5F70B02F25F7B1C9FA /* [CP] Copy Pods Resources */ = { + E71BD50F86C41C113D4362A9 /* [CP] Copy Pods Resources */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( ); inputPaths = ( - "${SRCROOT}/Pods/Target Support Files/Pods-UnzipKitDemo/Pods-UnzipKitDemo-resources.sh", + "${PODS_ROOT}/Target Support Files/Pods-UnzipKitDemo/Pods-UnzipKitDemo-resources.sh", "${PODS_CONFIGURATION_BUILD_DIR}/UnzipKit/UnzipKitResources.bundle", ); name = "[CP] Copy Pods Resources"; @@ -211,7 +211,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-UnzipKitDemo/Pods-UnzipKitDemo-resources.sh\"\n"; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-UnzipKitDemo/Pods-UnzipKitDemo-resources.sh\"\n"; showEnvVarsInLog = 0; }; /* End PBXShellScriptBuildPhase section */ @@ -296,7 +296,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.2; MTL_ENABLE_DEBUG_INFO = YES; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; @@ -347,7 +347,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 9.0; + IPHONEOS_DEPLOYMENT_TARGET = 12.2; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; diff --git a/UnzipKitDemo/UnzipKitDemo.xcodeproj/xcshareddata/xcschemes/UnzipKitDemo.xcscheme b/UnzipKitDemo/UnzipKitDemo.xcodeproj/xcshareddata/xcschemes/UnzipKitDemo.xcscheme index 53691fb..fa4e044 100644 --- a/UnzipKitDemo/UnzipKitDemo.xcodeproj/xcshareddata/xcschemes/UnzipKitDemo.xcscheme +++ b/UnzipKitDemo/UnzipKitDemo.xcodeproj/xcshareddata/xcschemes/UnzipKitDemo.xcscheme @@ -1,6 +1,6 @@