diff --git a/Cartfile b/Cartfile index 0e0dd90..c7a1724 100644 --- a/Cartfile +++ b/Cartfile @@ -1,2 +1,3 @@ github "abbeycode/UnrarKit" github "abbeycode/UnzipKit" +github "sindresorhus/DockProgress" diff --git a/Cartfile.resolved b/Cartfile.resolved new file mode 100644 index 0000000..145a4d4 --- /dev/null +++ b/Cartfile.resolved @@ -0,0 +1,3 @@ +github "abbeycode/UnrarKit" "2.9" +github "abbeycode/UnzipKit" "1.9" +github "sindresorhus/DockProgress" "v3.2.0" diff --git a/Carthage/Build/.DockProgress.version b/Carthage/Build/.DockProgress.version new file mode 100644 index 0000000..ce0bf86 --- /dev/null +++ b/Carthage/Build/.DockProgress.version @@ -0,0 +1,11 @@ +{ + "commitish" : "v3.2.0", + "Mac" : [ + { + "hash" : "13e7fe07ca491fe900ae7c858e66797a66d0a2e1dffde3a2c0b64188b211012e", + "name" : "DockProgress", + "linking" : "dynamic", + "swiftToolchainVersion" : "5.4 (swiftlang-1205.0.26.9 clang-1205.0.19.55)" + } + ] +} \ No newline at end of file diff --git a/Carthage/Build/.UnrarKit.version b/Carthage/Build/.UnrarKit.version new file mode 100644 index 0000000..ba37cb6 --- /dev/null +++ b/Carthage/Build/.UnrarKit.version @@ -0,0 +1,23 @@ +{ + "Mac" : [ + { + "name" : "UnrarKit", + "hash" : "0ee8db439c431777277ec76976faa8a1d19ba93d3f6977094746350e942215d3", + "linking" : "dynamic" + } + ], + "watchOS" : [ + + ], + "tvOS" : [ + + ], + "commitish" : "2.9", + "iOS" : [ + { + "name" : "UnrarKit", + "hash" : "2c752a88c360be277b938f55190d07bc6688ce0452932b4fbf52a12e9bfcf5d0", + "linking" : "dynamic" + } + ] +} \ No newline at end of file diff --git a/Carthage/Build/.UnzipKit.version b/Carthage/Build/.UnzipKit.version new file mode 100644 index 0000000..a0a6756 --- /dev/null +++ b/Carthage/Build/.UnzipKit.version @@ -0,0 +1,23 @@ +{ + "Mac" : [ + { + "name" : "UnzipKit", + "hash" : "9abff02fa1d67e3e8a850a88223b68dc71c18639ddec837f69fd982b96ad7f65", + "linking" : "dynamic" + } + ], + "watchOS" : [ + + ], + "tvOS" : [ + + ], + "commitish" : "1.9", + "iOS" : [ + { + "name" : "UnzipKit", + "hash" : "9d5e11808c6d978519ec6c1e814060b11c9a804e102061d93a7d8004829f2614", + "linking" : "dynamic" + } + ] +} \ No newline at end of file diff --git a/Carthage/Build/Mac/DockProgress.framework.dSYM/Contents/Info.plist b/Carthage/Build/Mac/DockProgress.framework.dSYM/Contents/Info.plist new file mode 100644 index 0000000..1243eca --- /dev/null +++ b/Carthage/Build/Mac/DockProgress.framework.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.DockProgress + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 3.2.0 + CFBundleVersion + 1 + + diff --git a/Carthage/Build/Mac/DockProgress.framework.dSYM/Contents/Resources/DWARF/DockProgress b/Carthage/Build/Mac/DockProgress.framework.dSYM/Contents/Resources/DWARF/DockProgress new file mode 100644 index 0000000..5c1abd4 Binary files /dev/null and b/Carthage/Build/Mac/DockProgress.framework.dSYM/Contents/Resources/DWARF/DockProgress differ diff --git a/Carthage/Build/Mac/DockProgress.framework/DockProgress b/Carthage/Build/Mac/DockProgress.framework/DockProgress new file mode 120000 index 0000000..6b0f242 --- /dev/null +++ b/Carthage/Build/Mac/DockProgress.framework/DockProgress @@ -0,0 +1 @@ +Versions/Current/DockProgress \ No newline at end of file diff --git a/Carthage/Build/Mac/DockProgress.framework/Headers b/Carthage/Build/Mac/DockProgress.framework/Headers new file mode 120000 index 0000000..a177d2a --- /dev/null +++ b/Carthage/Build/Mac/DockProgress.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/Carthage/Build/Mac/DockProgress.framework/Modules b/Carthage/Build/Mac/DockProgress.framework/Modules new file mode 120000 index 0000000..5736f31 --- /dev/null +++ b/Carthage/Build/Mac/DockProgress.framework/Modules @@ -0,0 +1 @@ +Versions/Current/Modules \ No newline at end of file diff --git a/Carthage/Build/Mac/DockProgress.framework/Resources b/Carthage/Build/Mac/DockProgress.framework/Resources new file mode 120000 index 0000000..953ee36 --- /dev/null +++ b/Carthage/Build/Mac/DockProgress.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/Carthage/Build/Mac/DockProgress.framework/Versions/A/DockProgress b/Carthage/Build/Mac/DockProgress.framework/Versions/A/DockProgress new file mode 100755 index 0000000..661f474 Binary files /dev/null and b/Carthage/Build/Mac/DockProgress.framework/Versions/A/DockProgress differ diff --git a/Carthage/Build/Mac/DockProgress.framework/Versions/A/Headers/DockProgress-Swift.h b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Headers/DockProgress-Swift.h new file mode 100644 index 0000000..6c8dac0 --- /dev/null +++ b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Headers/DockProgress-Swift.h @@ -0,0 +1,444 @@ +#if 0 +#elif defined(__arm64__) && __arm64__ +// Generated by Apple Swift version 5.4 (swiftlang-1205.0.26.9 clang-1205.0.19.55) +#ifndef DOCKPROGRESS_SWIFT_H +#define DOCKPROGRESS_SWIFT_H +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#include +#include +#include +#include + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif + +#if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +#else +# define SWIFT_RUNTIME_NAME(X) +#endif +#if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +#else +# define SWIFT_COMPILE_NAME(X) +#endif +#if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +#else +# define SWIFT_METHOD_FAMILY(X) +#endif +#if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +#else +# define SWIFT_NOESCAPE +#endif +#if __has_attribute(ns_consumed) +# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) +#else +# define SWIFT_RELEASES_ARGUMENT +#endif +#if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +# define SWIFT_WARN_UNUSED_RESULT +#endif +#if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +#else +# define SWIFT_NORETURN +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif + +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif + +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif + +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if defined(__has_attribute) && __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +#else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +#endif +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#if __has_feature(modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +#endif + +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="DockProgress",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + + + + + + + + +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#pragma clang diagnostic pop +#endif + +#elif defined(__x86_64__) && __x86_64__ +// Generated by Apple Swift version 5.4 (swiftlang-1205.0.26.9 clang-1205.0.19.55) +#ifndef DOCKPROGRESS_SWIFT_H +#define DOCKPROGRESS_SWIFT_H +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgcc-compat" + +#if !defined(__has_include) +# define __has_include(x) 0 +#endif +#if !defined(__has_attribute) +# define __has_attribute(x) 0 +#endif +#if !defined(__has_feature) +# define __has_feature(x) 0 +#endif +#if !defined(__has_warning) +# define __has_warning(x) 0 +#endif + +#if __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#include +#include +#include +#include + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if __has_include() +# include +# elif !defined(__cplusplus) +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +typedef unsigned int swift_uint2 __attribute__((__ext_vector_type__(2))); +typedef unsigned int swift_uint3 __attribute__((__ext_vector_type__(3))); +typedef unsigned int swift_uint4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif +#if !defined(SWIFT_CLASS_PROPERTY) +# if __has_feature(objc_class_property) +# define SWIFT_CLASS_PROPERTY(...) __VA_ARGS__ +# else +# define SWIFT_CLASS_PROPERTY(...) +# endif +#endif + +#if __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +#else +# define SWIFT_RUNTIME_NAME(X) +#endif +#if __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +#else +# define SWIFT_COMPILE_NAME(X) +#endif +#if __has_attribute(objc_method_family) +# define SWIFT_METHOD_FAMILY(X) __attribute__((objc_method_family(X))) +#else +# define SWIFT_METHOD_FAMILY(X) +#endif +#if __has_attribute(noescape) +# define SWIFT_NOESCAPE __attribute__((noescape)) +#else +# define SWIFT_NOESCAPE +#endif +#if __has_attribute(ns_consumed) +# define SWIFT_RELEASES_ARGUMENT __attribute__((ns_consumed)) +#else +# define SWIFT_RELEASES_ARGUMENT +#endif +#if __has_attribute(warn_unused_result) +# define SWIFT_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +# define SWIFT_WARN_UNUSED_RESULT +#endif +#if __has_attribute(noreturn) +# define SWIFT_NORETURN __attribute__((noreturn)) +#else +# define SWIFT_NORETURN +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif +#if !defined(SWIFT_RESILIENT_CLASS) +# if __has_attribute(objc_class_stub) +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) __attribute__((objc_class_stub)) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_class_stub)) SWIFT_CLASS_NAMED(SWIFT_NAME) +# else +# define SWIFT_RESILIENT_CLASS(SWIFT_NAME) SWIFT_CLASS(SWIFT_NAME) +# define SWIFT_RESILIENT_CLASS_NAMED(SWIFT_NAME) SWIFT_CLASS_NAMED(SWIFT_NAME) +# endif +#endif + +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif + +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif + +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM_ATTR) +# if defined(__has_attribute) && __has_attribute(enum_extensibility) +# define SWIFT_ENUM_ATTR(_extensibility) __attribute__((enum_extensibility(_extensibility))) +# else +# define SWIFT_ENUM_ATTR(_extensibility) +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name, _extensibility) enum _name : _type _name; enum SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# if __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_ATTR(_extensibility) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME, _extensibility) SWIFT_ENUM(_type, _name, _extensibility) +# endif +#endif +#if !defined(SWIFT_UNAVAILABLE) +# define SWIFT_UNAVAILABLE __attribute__((unavailable)) +#endif +#if !defined(SWIFT_UNAVAILABLE_MSG) +# define SWIFT_UNAVAILABLE_MSG(msg) __attribute__((unavailable(msg))) +#endif +#if !defined(SWIFT_AVAILABILITY) +# define SWIFT_AVAILABILITY(plat, ...) __attribute__((availability(plat, __VA_ARGS__))) +#endif +#if !defined(SWIFT_WEAK_IMPORT) +# define SWIFT_WEAK_IMPORT __attribute__((weak_import)) +#endif +#if !defined(SWIFT_DEPRECATED) +# define SWIFT_DEPRECATED __attribute__((deprecated)) +#endif +#if !defined(SWIFT_DEPRECATED_MSG) +# define SWIFT_DEPRECATED_MSG(...) __attribute__((deprecated(__VA_ARGS__))) +#endif +#if __has_feature(attribute_diagnose_if_objc) +# define SWIFT_DEPRECATED_OBJC(Msg) __attribute__((diagnose_if(1, Msg, "warning"))) +#else +# define SWIFT_DEPRECATED_OBJC(Msg) SWIFT_DEPRECATED_MSG(Msg) +#endif +#if !defined(IBSegueAction) +# define IBSegueAction +#endif +#if __has_feature(modules) +#if __has_warning("-Watimport-in-framework-header") +#pragma clang diagnostic ignored "-Watimport-in-framework-header" +#endif +#endif + +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" +#if __has_warning("-Wpragma-clang-attribute") +# pragma clang diagnostic ignored "-Wpragma-clang-attribute" +#endif +#pragma clang diagnostic ignored "-Wunknown-pragmas" +#pragma clang diagnostic ignored "-Wnullability" + +#if __has_attribute(external_source_symbol) +# pragma push_macro("any") +# undef any +# pragma clang attribute push(__attribute__((external_source_symbol(language="Swift", defined_in="DockProgress",generated_declaration))), apply_to=any(function,enum,objc_interface,objc_category,objc_protocol)) +# pragma pop_macro("any") +#endif + + + + + + + + +#if __has_attribute(external_source_symbol) +# pragma clang attribute pop +#endif +#pragma clang diagnostic pop +#endif + +#endif diff --git a/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/arm64-apple-macos.swiftdoc b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/arm64-apple-macos.swiftdoc new file mode 100644 index 0000000..eb5053c Binary files /dev/null and b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/arm64-apple-macos.swiftdoc differ diff --git a/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/arm64-apple-macos.swiftmodule b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/arm64-apple-macos.swiftmodule new file mode 100644 index 0000000..512a204 Binary files /dev/null and b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/arm64-apple-macos.swiftmodule differ diff --git a/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/arm64.swiftdoc b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/arm64.swiftdoc new file mode 100644 index 0000000..eb5053c Binary files /dev/null and b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/arm64.swiftdoc differ diff --git a/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/arm64.swiftmodule b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/arm64.swiftmodule new file mode 100644 index 0000000..512a204 Binary files /dev/null and b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/arm64.swiftmodule differ diff --git a/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/x86_64-apple-macos.swiftdoc b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/x86_64-apple-macos.swiftdoc new file mode 100644 index 0000000..3d42eac Binary files /dev/null and b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/x86_64-apple-macos.swiftdoc differ diff --git a/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/x86_64-apple-macos.swiftmodule b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/x86_64-apple-macos.swiftmodule new file mode 100644 index 0000000..71c14e4 Binary files /dev/null and b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/x86_64-apple-macos.swiftmodule differ diff --git a/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/x86_64.swiftdoc b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/x86_64.swiftdoc new file mode 100644 index 0000000..3d42eac Binary files /dev/null and b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/x86_64.swiftdoc differ diff --git a/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/x86_64.swiftmodule b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/x86_64.swiftmodule new file mode 100644 index 0000000..71c14e4 Binary files /dev/null and b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Modules/DockProgress.swiftmodule/x86_64.swiftmodule differ diff --git a/Carthage/Build/Mac/DockProgress.framework/Versions/A/Resources/Info.plist b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Resources/Info.plist new file mode 100644 index 0000000..422ce73 --- /dev/null +++ b/Carthage/Build/Mac/DockProgress.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,42 @@ + + + + + BuildMachineOSBuild + 20E241 + CFBundleExecutable + DockProgress + CFBundleIdentifier + DockProgress + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + DockProgress + CFBundlePackageType + FMWK + CFBundleShortVersionString + 3.2.0 + CFBundleSupportedPlatforms + + MacOSX + + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 12E262 + DTPlatformName + macosx + DTPlatformVersion + 11.3 + DTSDKBuild + 20E214 + DTSDKName + macosx11.3 + DTXcode + 1250 + DTXcodeBuild + 12E262 + LSMinimumSystemVersion + 10.12 + + diff --git a/Carthage/Build/Mac/DockProgress.framework/Versions/Current b/Carthage/Build/Mac/DockProgress.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/Carthage/Build/Mac/DockProgress.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/Carthage/Build/Mac/UnrarKit.framework.dSYM/Contents/Info.plist b/Carthage/Build/Mac/UnrarKit.framework.dSYM/Contents/Info.plist new file mode 100644 index 0000000..c7fe283 --- /dev/null +++ b/Carthage/Build/Mac/UnrarKit.framework.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.com.abbey-code.UnrarKit + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 2.9 + CFBundleVersion + 2.9 + + diff --git a/Carthage/Build/Mac/UnrarKit.framework.dSYM/Contents/Resources/DWARF/UnrarKit b/Carthage/Build/Mac/UnrarKit.framework.dSYM/Contents/Resources/DWARF/UnrarKit new file mode 100644 index 0000000..ca76e96 Binary files /dev/null and b/Carthage/Build/Mac/UnrarKit.framework.dSYM/Contents/Resources/DWARF/UnrarKit differ diff --git a/Carthage/Build/Mac/UnrarKit.framework/Headers b/Carthage/Build/Mac/UnrarKit.framework/Headers new file mode 120000 index 0000000..a177d2a --- /dev/null +++ b/Carthage/Build/Mac/UnrarKit.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/Carthage/Build/Mac/UnrarKit.framework/Modules b/Carthage/Build/Mac/UnrarKit.framework/Modules new file mode 120000 index 0000000..5736f31 --- /dev/null +++ b/Carthage/Build/Mac/UnrarKit.framework/Modules @@ -0,0 +1 @@ +Versions/Current/Modules \ No newline at end of file diff --git a/Carthage/Build/Mac/UnrarKit.framework/Resources b/Carthage/Build/Mac/UnrarKit.framework/Resources new file mode 120000 index 0000000..953ee36 --- /dev/null +++ b/Carthage/Build/Mac/UnrarKit.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/Carthage/Build/Mac/UnrarKit.framework/UnrarKit b/Carthage/Build/Mac/UnrarKit.framework/UnrarKit new file mode 120000 index 0000000..361e5ac --- /dev/null +++ b/Carthage/Build/Mac/UnrarKit.framework/UnrarKit @@ -0,0 +1 @@ +Versions/Current/UnrarKit \ No newline at end of file diff --git a/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/URKArchive.h b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/URKArchive.h new file mode 100644 index 0000000..bd064cb --- /dev/null +++ b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/URKArchive.h @@ -0,0 +1,496 @@ +// +// URKArchive.h +// UnrarKit +// +// + +#import +#import +#import "UnrarKitMacros.h" + +RarosHppIgnore +#import "raros.hpp" +#pragma clang diagnostic pop + +DllHppIgnore +#import "dll.hpp" +#pragma clang diagnostic pop + +@class URKFileInfo; + +/** + * Defines the various error codes that the listing and extraction methods return. + * These are returned in NSError's [code]([NSError code]) field. + */ +typedef NS_ENUM(NSInteger, URKErrorCode) { + + /** + * The archive's header is empty + */ + URKErrorCodeEndOfArchive = ERAR_END_ARCHIVE, + + /** + * The library ran out of memory while reading the archive + */ + URKErrorCodeNoMemory = ERAR_NO_MEMORY, + + /** + * The header is broken + */ + URKErrorCodeBadData = ERAR_BAD_DATA, + + /** + * The archive is not a valid RAR file + */ + URKErrorCodeBadArchive = ERAR_BAD_ARCHIVE, + + /** + * The archive is an unsupported RAR format or version + */ + URKErrorCodeUnknownFormat = ERAR_UNKNOWN_FORMAT, + + /** + * Failed to open a reference to the file + */ + URKErrorCodeOpen = ERAR_EOPEN, + + /** + * Failed to create the target directory for extraction + */ + URKErrorCodeCreate = ERAR_ECREATE, + + /** + * Failed to close the archive + */ + URKErrorCodeClose = ERAR_ECLOSE, + + /** + * Failed to read the archive + */ + URKErrorCodeRead = ERAR_EREAD, + + /** + * Failed to write a file to disk + */ + URKErrorCodeWrite = ERAR_EWRITE, + + /** + * The archive header's comments are larger than the buffer size + */ + URKErrorCodeSmall = ERAR_SMALL_BUF, + + /** + * The cause of the error is unspecified + */ + URKErrorCodeUnknown = ERAR_UNKNOWN, + + /** + * A password was not given for a password-protected archive + */ + URKErrorCodeMissingPassword = ERAR_MISSING_PASSWORD, + + /** + * No data was returned from the archive + */ + URKErrorCodeArchiveNotFound = 101, + + /** + * User cancelled the operation + */ + URKErrorCodeUserCancelled = 102, + + /** + * Error converting string to UTF-8 + */ + URKErrorCodeStringConversion = 103, +}; + +typedef NSString *const URKProgressInfoKey; + + +/** + * Defines the keys passed in `-[NSProgress userInfo]` for certain methods + */ +static URKProgressInfoKey _Nonnull + /** + * For `extractFilesTo:overwrite:error:`, this key contains an instance of URKFileInfo with the file currently being extracted + */ + URKProgressInfoKeyFileInfoExtracting = @"URKProgressInfoKeyFileInfoExtracting"; + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *URKErrorDomain; + +/** + * An Objective-C/Cocoa wrapper around the unrar library + */ +@interface URKArchive : NSObject +// Minimum of iOS 9, macOS 10.11 SDKs +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED > 90000) || (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED > 101100) + +#endif + + +/** + * The URL of the archive + */ +@property(nullable, weak, atomic, readonly) NSURL *fileURL; + +/** + * The filename of the archive + */ +@property(nullable, weak, atomic, readonly) NSString *filename; + +/** + * The password of the archive + */ +@property(nullable, nonatomic, strong) NSString *password; + +/** + * The total uncompressed size (in bytes) of all files in the archive. Returns nil on errors + */ +@property(nullable, atomic, readonly) NSNumber *uncompressedSize; + +/** + * The total compressed size (in bytes) of the archive. Returns nil on errors + */ +@property(nullable, atomic, readonly) NSNumber *compressedSize; + +/** + * True if the file is one volume of a multi-part archive + */ +@property(atomic, readonly) BOOL hasMultipleVolumes; + +/** + * Can be used for progress reporting, but it's not necessary. You can also use + * implicit progress reporting. If you don't use it, one will still be created, + * which will become a child progress of whichever one is the current NSProgress + * instance. + * + * To use this, assign it before beginning an operation that reports progress. Once + * the method you're calling has a reference to it, it will nil it out. Please check + * for nil before assigning it to avoid concurrency conflicts. + */ +@property(nullable, strong) NSProgress *progress; + + +/** + * **DEPRECATED:** Creates and returns an archive at the given path + * + * @param filePath A path to the archive file + */ ++ (nullable instancetype)rarArchiveAtPath:(NSString *)filePath __deprecated_msg("Use -initWithPath:error: instead"); + +/** + * **DEPRECATED:** Creates and returns an archive at the given URL + * + * @param fileURL The URL of the archive file + */ ++ (nullable instancetype)rarArchiveAtURL:(NSURL *)fileURL __deprecated_msg("Use -initWithURL:error: instead"); + +/** + * **DEPRECATED:** Creates and returns an archive at the given path, with a given password + * + * @param filePath A path to the archive file + * @param password The passowrd of the given archive + */ ++ (nullable instancetype)rarArchiveAtPath:(NSString *)filePath password:(NSString *)password __deprecated_msg("Use -initWithPath:password:error: instead"); + +/** + * **DEPRECATED:** Creates and returns an archive at the given URL, with a given password + * + * @param fileURL The URL of the archive file + * @param password The passowrd of the given archive + */ ++ (nullable instancetype)rarArchiveAtURL:(NSURL *)fileURL password:(NSString *)password __deprecated_msg("Use -initWithURL:password:error: instead"); + + +/** + * Do not use the default initializer + */ +- (instancetype)init NS_UNAVAILABLE; + +/** + * Creates and returns an archive at the given path + * + * @param filePath A path to the archive file + * @param error Contains any error during initialization + * + * @return Returns an initialized URKArchive, unless there's a problem creating a bookmark to the path + */ +- (nullable instancetype)initWithPath:(NSString *)filePath error:(NSError **)error; + +/** + * Creates and returns an archive at the given URL + * + * @param fileURL The URL of the archive file + * @param error Contains any error during initialization + * + * @return Returns an initialized URKArchive, unless there's a problem creating a bookmark to the URL + */ +- (nullable instancetype)initWithURL:(NSURL *)fileURL error:(NSError **)error; + +/** + * Creates and returns an archive at the given path, with a given password + * + * @param filePath A path to the archive file + * @param password The passowrd of the given archive + * @param error Contains any error during initialization + * + * @return Returns an initialized URKArchive, unless there's a problem creating a bookmark to the path + */ +- (nullable instancetype)initWithPath:(NSString *)filePath password:(NSString *)password error:(NSError **)error; + +/** + * Creates and returns an archive at the given URL, with a given password + * + * @param fileURL The URL of the archive file + * @param password The passowrd of the given archive + * @param error Contains any error during initialization + * + * @return Returns an initialized URKArchive, unless there's a problem creating a bookmark to the URL + */ +- (nullable instancetype)initWithURL:(NSURL *)fileURL password:(NSString *)password error:(NSError **)error; + + +/** + * Determines whether a file is a RAR archive by reading the signature + * + * @param filePath Path to the file being checked + * + * @return YES if the file exists and contains a signature indicating it is a RAR archive + */ ++ (BOOL)pathIsARAR:(NSString *)filePath; + +/** + * Determines whether a file is a RAR archive by reading the signature + * + * @param fileURL URL of the file being checked + * + * @return YES if the file exists and contains a signature indicating it is a RAR archive + */ ++ (BOOL)urlIsARAR:(NSURL *)fileURL; + +/** + * Lists the names of the files in the archive + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return Returns a list of NSString containing the paths within the archive's contents, or nil if an error was encountered + */ +- (nullable NSArray *)listFilenames:(NSError **)error; + +/** + * Lists the various attributes of each file in the archive + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return Returns a list of URKFileInfo objects, which contain metadata about the archive's files, or nil if an error was encountered + */ +- (nullable NSArray *)listFileInfo:(NSError **)error; + +/** + * Iterates the header of the archive, calling the block with each archived file's info. + * + * WARNING: There is no filtering of duplicate header entries. If a file is listed twice, `action` + * will be called twice with that file's path + * + * @param action The action to perform using the data. Must be non-nil + * + * - *fileInfo* The metadata of the file within the archive + * - *stop* Set to YES to stop reading the archive + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return Returns NO if an error was encountered + */ +- (BOOL) iterateFileInfo:(void(^)(URKFileInfo *fileInfo, BOOL *stop))action + error:(NSError **)error; + +/** + * Lists the URLs of volumes in a single- or multi-volume archive + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return Returns the list of URLs of all volumes of the archive + */ +- (nullable NSArray *)listVolumeURLs:(NSError **)error; + +/** + * Writes all files in the archive to the given path. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction. Use the progress property (as explained in the README) to + * retrieve more detailed information, such as the current file being extracted, number of files extracted, + * and the URKFileInfo instance being extracted + * + * @param filePath The destination path of the unarchived files + * @param overwrite YES to overwrite files in the destination directory, NO otherwise + * @param error Contains an NSError object when there was an error reading the archive + * + * @return YES on successful extraction, NO if an error was encountered + */ +- (BOOL)extractFilesTo:(NSString *)filePath + overwrite:(BOOL)overwrite + error:(NSError **)error; + +/** + * **DEPRECATED:** Writes all files in the archive to the given path + * + * @param filePath The destination path of the unarchived files + * @param overwrite YES to overwrite files in the destination directory, NO otherwise + * @param progressBlock Called every so often to report the progress of the extraction + * + * - *currentFile* The info about the file that's being extracted + * - *percentArchiveDecompressed* The percentage of the archive that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return YES on successful extraction, NO if an error was encountered + */ +- (BOOL)extractFilesTo:(NSString *)filePath + overwrite:(BOOL)overwrite + progress:(nullable void (^)(URKFileInfo *currentFile, CGFloat percentArchiveDecompressed))progressBlock + error:(NSError **)error __deprecated_msg("Use -extractFilesTo:overwrite:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * Unarchive a single file from the archive into memory. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction + * + * @param fileInfo The info of the file within the archive to be expanded. Only the filename property is used + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractData:(URKFileInfo *)fileInfo + error:(NSError **)error; + +/** + * **DEPRECATED:** Unarchive a single file from the archive into memory + * + * @param fileInfo The info of the file within the archive to be expanded. Only the filename property is used + * @param progressBlock Called every so often to report the progress of the extraction + * + * - *percentDecompressed* The percentage of the archive that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractData:(URKFileInfo *)fileInfo + progress:(nullable void (^)(CGFloat percentDecompressed))progressBlock + error:(NSError **)error __deprecated_msg("Use -extractData:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * Unarchive a single file from the archive into memory. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction + * + * @param filePath The path of the file within the archive to be expanded + * + * - *percentDecompressed* The percentage of the file that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractDataFromFile:(NSString *)filePath + error:(NSError **)error; + +/** + * **DEPRECATED:** Unarchive a single file from the archive into memory + * + * @param filePath The path of the file within the archive to be expanded + * @param progressBlock Called every so often to report the progress of the extraction + * + * - *percentDecompressed* The percentage of the file that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractDataFromFile:(NSString *)filePath + progress:(nullable void (^)(CGFloat percentDecompressed))progressBlock + error:(NSError **)error __deprecated_msg("Use -extractDataFromFile:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * Loops through each file in the archive in alphabetical order, allowing you to perform an + * action using its info. Supports NSProgress for progress reporting, which also allows + * cancellation of the operation in the middle + * + * @param action The action to perform using the data + * + * - *fileInfo* The metadata of the file within the archive + * - *stop* Set to YES to stop reading the archive + * + * @param error Contains an error if any was returned + * + * @return YES if no errors were encountered, NO otherwise + */ +- (BOOL)performOnFilesInArchive:(void(^)(URKFileInfo *fileInfo, BOOL *stop))action + error:(NSError **)error; + +/** + * Extracts each file in the archive into memory, allowing you to perform an action + * on it (not sorted). Supports NSProgress for progress reporting, which also allows + * cancellation of the operation in the middle + * + * @param action The action to perform using the data + * + * - *fileInfo* The metadata of the file within the archive + * - *fileData* The full data of the file in the archive + * - *stop* Set to YES to stop reading the archive + * + * @param error Contains an error if any was returned + * + * @return YES if no errors were encountered, NO otherwise + */ +- (BOOL)performOnDataInArchive:(void(^)(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop))action + error:(NSError **)error; + +/** + * Unarchive a single file from the archive into memory. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction + * + * @param filePath The path of the file within the archive to be expanded + * @param error Contains an NSError object when there was an error reading the archive + * @param action The block to run for each chunk of data, each of size <= bufferSize + * + * - *dataChunk* The data read from the archived file. Read bytes and length to write the data + * - *percentDecompressed* The percentage of the file that has been decompressed + * + * @return YES if all data was read successfully, NO if an error was encountered + */ +- (BOOL)extractBufferedDataFromFile:(NSString *)filePath + error:(NSError **)error + action:(void(^)(NSData *dataChunk, CGFloat percentDecompressed))action; + +/** + * YES if archive protected with a password, NO otherwise + */ +- (BOOL)isPasswordProtected; + +/** + * Tests whether the provided password unlocks the archive + * + * @return YES if correct password or archive is not password protected, NO if password is wrong + */ +- (BOOL)validatePassword; + +/** + Extract each file in the archive, checking whether the data matches the CRC checksum + stored at the time it was written + + @return YES if the data is all correct, false if any check failed + */ +- (BOOL)checkDataIntegrity; + +/** + Extract a particular file, to determine if its data matches the CRC + checksum stored at the time it written + + @param filePath The file in the archive to check + + @return YES if the data is correct, false if any check failed + */ +- (BOOL)checkDataIntegrityOfFile:(NSString *)filePath; + +@end +NS_ASSUME_NONNULL_END diff --git a/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/URKFileInfo.h b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/URKFileInfo.h new file mode 100644 index 0000000..5bf2c95 --- /dev/null +++ b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/URKFileInfo.h @@ -0,0 +1,158 @@ +// +// URKFileInfo.h +// UnrarKit +// + +#import +#import "UnrarKitMacros.h" + +RarosHppIgnore +#import "raros.hpp" +#pragma clang diagnostic pop + +DllHppIgnore +#import "dll.hpp" +#pragma clang diagnostic pop + +/* See http://www.forensicswiki.org/wiki/RAR and + http://www.rarlab.com/technote.htm#filehead for + more information about the RAR File Header spec */ + +/** + * Defines the packing methods that can be used on a file in an archive + */ +typedef NS_ENUM(NSUInteger, URKCompressionMethod) { + + /** + * No compression is used + */ + URKCompressionMethodStorage = 0x30, + + /** + * Fastest compression + */ + URKCompressionMethodFastest = 0x31, + + /** + * Fast compression + */ + URKCompressionMethodFast = 0x32, + + /** + * Normal compression + */ + URKCompressionMethodNormal = 0x33, + + /** + * Good compression + */ + URKCompressionMethodGood = 0x34, + + /** + * Best compression + */ + URKCompressionMethodBest = 0x35, +}; + +/** + * Defines the various operating systems that can be used when archiving + */ +typedef NS_ENUM(NSUInteger, URKHostOS) { + + /** + * MS-DOS + */ + URKHostOSMSDOS = 0, + + /** + * OS/2 + */ + URKHostOSOS2 = 1, + + /** + * Windows + */ + URKHostOSWindows = 2, + + /** + * Unix + */ + URKHostOSUnix = 3, + + /** + * Mac OS + */ + URKHostOSMacOS = 4, + + /** + * BeOS + */ + URKHostOSBeOS = 5, +}; + +/** + * A wrapper around a RAR archive's file header, defining the various fields + * it contains + */ +@interface URKFileInfo : NSObject + +/** + * The name of the file's archive + */ +@property (readonly, strong) NSString *archiveName; + +/** + * The name of the file + */ +@property (readonly, strong) NSString *filename; + +/** + * The timestamp of the file + */ +@property (readonly, strong) NSDate *timestamp; + +/** + * The CRC checksum of the file + */ +@property (readonly, assign) NSUInteger CRC; + +/** + * Size of the uncompressed file + */ +@property (readonly, assign) long long uncompressedSize; + +/** + * Size of the compressed file + */ +@property (readonly, assign) long long compressedSize; + +/** + * YES if the file will be continued of the next volume + */ +@property (readonly) BOOL isEncryptedWithPassword; + +/** + * YES if the file is a directory + */ +@property (readonly) BOOL isDirectory; + +/** + * The type of compression + */ +@property (readonly, assign) URKCompressionMethod compressionMethod; + +/** + * The OS of the file + */ +@property (readonly, assign) URKHostOS hostOS; + +/** + * Returns a URKFileInfo instance for the given extended header data + * + * @param fileHeader The header data for a RAR file + * + * @return an instance of URKFileInfo + */ ++ (instancetype) fileInfo:(struct RARHeaderDataEx *)fileHeader; + +@end diff --git a/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/UnrarKit.h b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/UnrarKit.h new file mode 100644 index 0000000..78db3b3 --- /dev/null +++ b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/UnrarKit.h @@ -0,0 +1,19 @@ +// +// UnrarKit.h +// UnrarKit +// +// Created by Dov Frankel on 1/9/2015. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import + +//! Project version number for UnrarKit. +FOUNDATION_EXPORT double UnrarKitVersionNumber; + +//! Project version string for UnrarKit. +FOUNDATION_EXPORT const unsigned char UnrarKitVersionString[]; + + +#import "URKArchive.h" +#import "URKFileInfo.h" diff --git a/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/UnrarKitMacros.h b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/UnrarKitMacros.h new file mode 100644 index 0000000..aea9343 --- /dev/null +++ b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/UnrarKitMacros.h @@ -0,0 +1,126 @@ +// +// UnrarKitMacros.h +// UnrarKit +// +// Created by Dov Frankel on 8/8/17. +// Copyright © 2017 Abbey Code. All rights reserved. +// + +#ifndef UnrarKitMacros_h +#define UnrarKitMacros_h + +//#import "Availability.h" +//#import "AvailabilityInternal.h" + +#define _stringify(a) #a + +#define RarHppIgnore \ +_Pragma( _stringify( clang diagnostic push ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wcast-align" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wextra-semi" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wold-style-cast" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wpadded" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wreserved-id-macro" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wshorten-64-to-32" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wcast-qual" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wundef" ) ) \ + +#define DllHppIgnore \ +_Pragma( _stringify( clang diagnostic push ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wreserved-id-macro" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wstrict-prototypes" ) ) \ + +#define RarosHppIgnore \ +_Pragma( _stringify( clang diagnostic push ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wreserved-id-macro" ) ) \ + + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundef" +#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" + + +// iOS 10, macOS 10.12, tvOS 10.0, watchOS 3.0 +#define UNIFIED_LOGGING_SUPPORTED \ +__IPHONE_OS_VERSION_MIN_REQUIRED >= 100000 \ +|| __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200 \ +|| __TV_OS_VERSION_MIN_REQUIRED >= 100000 \ +|| __WATCH_OS_VERSION_MIN_REQUIRED >= 30000 + +#if TARGET_OS_IPHONE +#define SDK_10_13_MAJOR 11 +#define SDK_10_13_MINOR 0 +#else +#define SDK_10_13_MAJOR 10 +#define SDK_10_13_MINOR 13 +#endif + +#if UNIFIED_LOGGING_SUPPORTED +#import +#import + +// Called from +[UnrarKit initialize] and +[URKArchiveTestCase setUp] +extern os_log_t unrarkit_log; // Declared in URKArchive.m +extern BOOL unrarkitIsAtLeast10_13SDK; // Declared in URKArchive.m +#define URKLogInit() \ + unrarkit_log = os_log_create("com.abbey-code.UnrarKit", "General"); \ + \ + NSOperatingSystemVersion minVersion; \ + minVersion.majorVersion = SDK_10_13_MAJOR; \ + minVersion.minorVersion = SDK_10_13_MINOR; \ + minVersion.patchVersion = 0; \ + unrarkitIsAtLeast10_13SDK = [[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:minVersion]; \ + URKLogDebug("Is >= 10.13 (or iOS 11): %@", unrarkitIsAtLeast10_13SDK ? @"YES" : @"NO"); + +#define URKLog(format, ...) os_log(unrarkit_log, format, ##__VA_ARGS__); +#define URKLogInfo(format, ...) os_log_info(unrarkit_log, format, ##__VA_ARGS__); +#define URKLogDebug(format, ...) os_log_debug(unrarkit_log, format, ##__VA_ARGS__); + + +#define URKLogError(format, ...) \ + if (unrarkitIsAtLeast10_13SDK) os_log_error(unrarkit_log, format, ##__VA_ARGS__); \ + else os_log_with_type(unrarkit_log, OS_LOG_TYPE_ERROR, format, ##__VA_ARGS__); + +#define URKLogFault(format, ...) \ + if (unrarkitIsAtLeast10_13SDK) os_log_fault(unrarkit_log, format, ##__VA_ARGS__); \ + else os_log_with_type(unrarkit_log, OS_LOG_TYPE_FAULT, format, ##__VA_ARGS__); + + +#define URKCreateActivity(name) \ +os_activity_t activity = os_activity_create(name, OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); \ +os_activity_scope(activity); + + +#else // Fall back to regular NSLog + +// No-op, as nothing needs to be initialized +#define URKLogInit() (void)0 + + +// Only used below +#define _removeLogFormatTokens(format) [[@format \ + stringByReplacingOccurrencesOfString:@"{public}" withString:@""] \ + stringByReplacingOccurrencesOfString:@"{iec-bytes}" withString:@""] +#define _nsLogWithoutWarnings(format, ...) \ +_Pragma( _stringify( clang diagnostic push ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wformat-nonliteral" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wformat-security" ) ) \ +NSLog(_removeLogFormatTokens(format), ##__VA_ARGS__); \ +_Pragma( _stringify( clang diagnostic pop ) ) + +// All levels do the same thing +#define URKLog(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); +#define URKLogInfo(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); +#define URKLogDebug(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); +#define URKLogError(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); +#define URKLogFault(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); + +// No-op, as no equivalent to Activities exists +#define URKCreateActivity(name) (void)0 + + +#pragma clang diagnostic pop + +#endif // UNIFIED_LOGGING_SUPPORTED + +#endif /* UnrarKitMacros_h */ diff --git a/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/dll.hpp b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/dll.hpp new file mode 100644 index 0000000..7f82906 --- /dev/null +++ b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/dll.hpp @@ -0,0 +1,185 @@ +#ifndef _UNRAR_DLL_ +#define _UNRAR_DLL_ + +#pragma pack(1) + +#define ERAR_SUCCESS 0 +#define ERAR_END_ARCHIVE 10 +#define ERAR_NO_MEMORY 11 +#define ERAR_BAD_DATA 12 +#define ERAR_BAD_ARCHIVE 13 +#define ERAR_UNKNOWN_FORMAT 14 +#define ERAR_EOPEN 15 +#define ERAR_ECREATE 16 +#define ERAR_ECLOSE 17 +#define ERAR_EREAD 18 +#define ERAR_EWRITE 19 +#define ERAR_SMALL_BUF 20 +#define ERAR_UNKNOWN 21 +#define ERAR_MISSING_PASSWORD 22 +#define ERAR_EREFERENCE 23 +#define ERAR_BAD_PASSWORD 24 + +#define RAR_OM_LIST 0 +#define RAR_OM_EXTRACT 1 +#define RAR_OM_LIST_INCSPLIT 2 + +#define RAR_SKIP 0 +#define RAR_TEST 1 +#define RAR_EXTRACT 2 + +#define RAR_VOL_ASK 0 +#define RAR_VOL_NOTIFY 1 + +#define RAR_DLL_VERSION 8 + +#define RAR_HASH_NONE 0 +#define RAR_HASH_CRC32 1 +#define RAR_HASH_BLAKE2 2 + + +#ifdef _UNIX +#define CALLBACK +#define PASCAL +#define LONG long +#define HANDLE void * +#define LPARAM long +#define UINT unsigned int +#endif + +#define RHDF_SPLITBEFORE 0x01 +#define RHDF_SPLITAFTER 0x02 +#define RHDF_ENCRYPTED 0x04 +#define RHDF_SOLID 0x10 +#define RHDF_DIRECTORY 0x20 + + +struct RARHeaderData +{ + char ArcName[260]; + char FileName[260]; + unsigned int Flags; + unsigned int PackSize; + unsigned int UnpSize; + unsigned int HostOS; + unsigned int FileCRC; + unsigned int FileTime; + unsigned int UnpVer; + unsigned int Method; + unsigned int FileAttr; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; +}; + + +struct RARHeaderDataEx +{ + char ArcName[1024]; + wchar_t ArcNameW[1024]; + char FileName[1024]; + wchar_t FileNameW[1024]; + unsigned int Flags; + unsigned int PackSize; + unsigned int PackSizeHigh; + unsigned int UnpSize; + unsigned int UnpSizeHigh; + unsigned int HostOS; + unsigned int FileCRC; + unsigned int FileTime; + unsigned int UnpVer; + unsigned int Method; + unsigned int FileAttr; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; + unsigned int DictSize; + unsigned int HashType; + char Hash[32]; + unsigned int RedirType; + wchar_t *RedirName; + unsigned int RedirNameSize; + unsigned int DirTarget; + unsigned int MtimeLow; + unsigned int MtimeHigh; + unsigned int CtimeLow; + unsigned int CtimeHigh; + unsigned int AtimeLow; + unsigned int AtimeHigh; + unsigned int Reserved[988]; +}; + + +struct RAROpenArchiveData +{ + char *ArcName; + unsigned int OpenMode; + unsigned int OpenResult; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; +}; + +typedef int (CALLBACK *UNRARCALLBACK)(UINT msg,LPARAM UserData,LPARAM P1,LPARAM P2); + +#define ROADF_VOLUME 0x0001 +#define ROADF_COMMENT 0x0002 +#define ROADF_LOCK 0x0004 +#define ROADF_SOLID 0x0008 +#define ROADF_NEWNUMBERING 0x0010 +#define ROADF_SIGNED 0x0020 +#define ROADF_RECOVERY 0x0040 +#define ROADF_ENCHEADERS 0x0080 +#define ROADF_FIRSTVOLUME 0x0100 + +struct RAROpenArchiveDataEx +{ + char *ArcName; + wchar_t *ArcNameW; + unsigned int OpenMode; + unsigned int OpenResult; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; + unsigned int Flags; + UNRARCALLBACK Callback; + LPARAM UserData; + unsigned int Reserved[28]; +}; + +enum UNRARCALLBACK_MESSAGES { + UCM_CHANGEVOLUME,UCM_PROCESSDATA,UCM_NEEDPASSWORD,UCM_CHANGEVOLUMEW, + UCM_NEEDPASSWORDW +}; + +typedef int (PASCAL *CHANGEVOLPROC)(char *ArcName,int Mode); +typedef int (PASCAL *PROCESSDATAPROC)(unsigned char *Addr,int Size); + +#ifdef __cplusplus +extern "C" { +#endif + +HANDLE PASCAL RAROpenArchive(struct RAROpenArchiveData *ArchiveData); +HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *ArchiveData); +int PASCAL RARCloseArchive(HANDLE hArcData); +int PASCAL RARReadHeader(HANDLE hArcData,struct RARHeaderData *HeaderData); +int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *HeaderData); +int PASCAL RARProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName); +int PASCAL RARProcessFileW(HANDLE hArcData,int Operation,wchar_t *DestPath,wchar_t *DestName); +void PASCAL RARSetCallback(HANDLE hArcData,UNRARCALLBACK Callback,LPARAM UserData); +void PASCAL RARSetChangeVolProc(HANDLE hArcData,CHANGEVOLPROC ChangeVolProc); +void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataProc); +void PASCAL RARSetPassword(HANDLE hArcData,char *Password); +int PASCAL RARGetDllVersion(); + +#ifdef __cplusplus +} +#endif + +#pragma pack() + +#endif diff --git a/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/raros.hpp b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/raros.hpp new file mode 100644 index 0000000..4f4f2ae --- /dev/null +++ b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Headers/raros.hpp @@ -0,0 +1,36 @@ +#ifndef _RAR_RAROS_ +#define _RAR_RAROS_ + +#ifdef __EMX__ + #define _EMX +#endif + +#ifdef __DJGPP__ + #define _DJGPP + #define _EMX +#endif + +#if defined(__WIN32__) || defined(_WIN32) + #define _WIN_ALL // Defined for all Windows platforms, 32 and 64 bit, mobile and desktop. + #ifdef _M_X64 + #define _WIN_64 + #else + #define _WIN_32 + #endif +#endif + +#if defined(ANDROID) || defined(__ANDROID__) + #define _UNIX + #define _ANDROID +#endif + +#ifdef __APPLE__ + #define _UNIX + #define _APPLE +#endif + +#if !defined(_EMX) && !defined(_WIN_ALL) && !defined(_BEOS) && !defined(_APPLE) + #define _UNIX +#endif + +#endif diff --git a/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Modules/module.modulemap b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Modules/module.modulemap new file mode 100644 index 0000000..ba14d5a --- /dev/null +++ b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module UnrarKit { + umbrella header "UnrarKit.h" + + export * + module * { export * } +} diff --git a/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Resources/Info.plist b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Resources/Info.plist new file mode 100644 index 0000000..49d07d6 --- /dev/null +++ b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,44 @@ + + + + + BuildMachineOSBuild + 17D47 + CFBundleDevelopmentRegion + English + CFBundleExecutable + UnrarKit + CFBundleIdentifier + com.abbey-code.UnrarKit + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + UnrarKit + CFBundlePackageType + FMWK + CFBundleShortVersionString + 2.9 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 2.9 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 9E145 + DTPlatformVersion + GM + DTSDKBuild + 17E189 + DTSDKName + macosx10.13 + DTXcode + 0930 + DTXcodeBuild + 9E145 + + diff --git a/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Resources/UnrarKitResources.bundle/Contents/Info.plist b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Resources/UnrarKitResources.bundle/Contents/Info.plist new file mode 100644 index 0000000..e9f384d --- /dev/null +++ b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Resources/UnrarKitResources.bundle/Contents/Info.plist @@ -0,0 +1,44 @@ + + + + + BuildMachineOSBuild + 17D47 + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.abbey-code.UnrarKitResources + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + UnrarKitResources + CFBundlePackageType + BNDL + CFBundleShortVersionString + 2.9 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 2.9 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 9E145 + DTPlatformVersion + GM + DTSDKBuild + 17E189 + DTSDKName + macosx10.13 + DTXcode + 0930 + DTXcodeBuild + 9E145 + NSHumanReadableCopyright + Copyright © 2017 Abbey Code. All rights reserved. + + diff --git a/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Resources/UnrarKitResources.bundle/Contents/Resources/en.lproj/UnrarKit.strings b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Resources/UnrarKitResources.bundle/Contents/Resources/en.lproj/UnrarKit.strings new file mode 100644 index 0000000..df1e671 Binary files /dev/null and b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/Resources/UnrarKitResources.bundle/Contents/Resources/en.lproj/UnrarKit.strings differ diff --git a/Carthage/Build/Mac/UnrarKit.framework/Versions/A/UnrarKit b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/UnrarKit new file mode 100755 index 0000000..d2fb1ee Binary files /dev/null and b/Carthage/Build/Mac/UnrarKit.framework/Versions/A/UnrarKit differ diff --git a/Carthage/Build/Mac/UnrarKit.framework/Versions/Current b/Carthage/Build/Mac/UnrarKit.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/Carthage/Build/Mac/UnrarKit.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/Carthage/Build/Mac/UnzipKit.framework.dSYM/Contents/Info.plist b/Carthage/Build/Mac/UnzipKit.framework.dSYM/Contents/Info.plist new file mode 100644 index 0000000..ef5a736 --- /dev/null +++ b/Carthage/Build/Mac/UnzipKit.framework.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.com.abbey-code.UnzipKit + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.9 + CFBundleVersion + 1.9 + + diff --git a/Carthage/Build/Mac/UnzipKit.framework.dSYM/Contents/Resources/DWARF/UnzipKit b/Carthage/Build/Mac/UnzipKit.framework.dSYM/Contents/Resources/DWARF/UnzipKit new file mode 100644 index 0000000..015353b Binary files /dev/null and b/Carthage/Build/Mac/UnzipKit.framework.dSYM/Contents/Resources/DWARF/UnzipKit differ diff --git a/Carthage/Build/Mac/UnzipKit.framework/Headers b/Carthage/Build/Mac/UnzipKit.framework/Headers new file mode 120000 index 0000000..a177d2a --- /dev/null +++ b/Carthage/Build/Mac/UnzipKit.framework/Headers @@ -0,0 +1 @@ +Versions/Current/Headers \ No newline at end of file diff --git a/Carthage/Build/Mac/UnzipKit.framework/Modules b/Carthage/Build/Mac/UnzipKit.framework/Modules new file mode 120000 index 0000000..5736f31 --- /dev/null +++ b/Carthage/Build/Mac/UnzipKit.framework/Modules @@ -0,0 +1 @@ +Versions/Current/Modules \ No newline at end of file diff --git a/Carthage/Build/Mac/UnzipKit.framework/PrivateHeaders b/Carthage/Build/Mac/UnzipKit.framework/PrivateHeaders new file mode 120000 index 0000000..d8e5645 --- /dev/null +++ b/Carthage/Build/Mac/UnzipKit.framework/PrivateHeaders @@ -0,0 +1 @@ +Versions/Current/PrivateHeaders \ No newline at end of file diff --git a/Carthage/Build/Mac/UnzipKit.framework/Resources b/Carthage/Build/Mac/UnzipKit.framework/Resources new file mode 120000 index 0000000..953ee36 --- /dev/null +++ b/Carthage/Build/Mac/UnzipKit.framework/Resources @@ -0,0 +1 @@ +Versions/Current/Resources \ No newline at end of file diff --git a/Carthage/Build/Mac/UnzipKit.framework/UnzipKit b/Carthage/Build/Mac/UnzipKit.framework/UnzipKit new file mode 120000 index 0000000..6593b4d --- /dev/null +++ b/Carthage/Build/Mac/UnzipKit.framework/UnzipKit @@ -0,0 +1 @@ +Versions/Current/UnzipKit \ No newline at end of file diff --git a/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Headers/UZKArchive.h b/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Headers/UZKArchive.h new file mode 100644 index 0000000..ce99538 --- /dev/null +++ b/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Headers/UZKArchive.h @@ -0,0 +1,949 @@ +// +// UZKArchive.h +// UnzipKit +// +// + +#import +#import + +#import "UZKFileInfo.h" + +/** + * Defines the various error codes that the listing and extraction methods return. + * These are returned in NSError's [code]([NSError code]) field. + */ +typedef NS_ENUM(NSInteger, UZKErrorCode) { + + /** + * An error from zlib reading or writing the file (UNZ_ERRNO/ZIP_ERRNO) + */ + UZKErrorCodeZLibError = -1, + + /** + * An error with a parameter, usually the file name (UNZ_PARAMERROR/ZIP_PARAMERROR) + */ + UZKErrorCodeParameterError = -102, + + /** + * The Zip file appears to be corrupted, or invalid (UNZ_BADZIPFILE/ZIP_BADZIPFILE) + */ + UZKErrorCodeBadZipFile = -103, + + /** + * An error internal to MiniZip (UNZ_INTERNALERROR/ZIP_INTERNALERROR) + */ + UZKErrorCodeInternalError = -104, + + /** + * The decompressed file's CRC doesn't match the original file's CRC (UNZ_CRCERROR) + */ + UZKErrorCodeCRCError = -105, + + /** + * Failure to find/open the archive + */ + UZKErrorCodeArchiveNotFound = 101, + + /** + * Error reading or advancing through the archive + */ + UZKErrorCodeFileNavigationError = 102, + + /** + * Error finding a file in the archive + */ + UZKErrorCodeFileNotFoundInArchive = 103, + + /** + * Error writing an extracted file to disk + */ + UZKErrorCodeOutputError = 104, + + /** + * The destination directory is a file. Not used anymore + */ + UZKErrorCodeOutputErrorPathIsAFile = 105, + + /** + * Password given doesn't decrypt the archive + */ + UZKErrorCodeInvalidPassword = 106, + + /** + * Error reading a file in the archive + */ + UZKErrorCodeFileRead = 107, + + /** + * Error opening a file in the archive for writing + */ + UZKErrorCodeFileOpenForWrite = 108, + + /** + * Error writing a file in the archive + */ + UZKErrorCodeFileWrite = 109, + + /** + * Error closing the file in the archive + */ + UZKErrorCodeFileCloseWriting = 110, + + /** + * Error deleting a file in the archive + */ + UZKErrorCodeDeleteFile = 111, + + /** + * Tried to read before all writes have completed, or vise-versa + */ + UZKErrorCodeMixedModeAccess = 112, + + /** + * Error reading the global comment of the archive + */ + UZKErrorCodeReadComment = 113, + + /** + * The CRC given up front doesn't match the calculated CRC + */ + UZKErrorCodePreCRCMismatch = 114, + + /** + * The zip is compressed using Deflate64 (compression method 9), which isn't supported + */ + UZKErrorCodeDeflate64 = 115, + + /** + * User cancelled the operation + */ + UZKErrorCodeUserCancelled = 116, +}; + + +typedef NSString *const UZKProgressInfoKey; + +/** + * Defines the keys passed in `-[NSProgress userInfo]` for certain methods + */ +static UZKProgressInfoKey _Nonnull +/** + * For `extractFilesTo:overwrite:error:`, this key contains an instance of URKFileInfo with the file currently being extracted + */ +UZKProgressInfoKeyFileInfoExtracting = @"UZKProgressInfoKeyFileInfoExtracting"; + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *UZKErrorDomain; + +@interface UZKArchive : NSObject +// Minimum of iOS 9, macOS 10.11 SDKs +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED > 90000) || (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED > 101100) + +#endif + +/** + * The URL of the archive. Returns nil if the URL becomes unreachable + */ +@property(weak, nonatomic, readonly, nullable) NSURL *fileURL; + +/** + * The filename of the archive. Returns nil if the archive file becomes unreachable + */ +@property(weak, nonatomic, readonly, nullable) NSString *filename; + +/** + * The password of the archive + */ +@property(strong, nullable) NSString *password; + +/** + * The global comment inside the archive + * + * Comments are written in UTF-8, and read in UTF-8 and Windows/CP-1252, falling back to defaultCStringEncoding + */ +@property(retain, atomic, nullable) NSString *comment; + +/** + * Can be used for progress reporting, but it's not necessary. You can also use + * implicit progress reporting. If you don't use it, one will still be created, + * which will become a child progress of whichever one is the current NSProgress + * instance. + * + * To use this, assign it before beginning an operation that reports progress. Once + * the method you're calling has a reference to it, it will nil it out. Please check + * for nil before assigning it to avoid concurrency conflicts. + */ +@property(nullable, strong) NSProgress *progress; + + +/** + * DEPRECATED: Creates and returns an archive at the given path + * + * @param filePath A path to the archive file + * + * @return Returns a UZKArchive object, or nil if the path isn't reachable + */ ++ (nullable instancetype)zipArchiveAtPath:(NSString *)filePath __deprecated_msg("Use -initWithPath:error: instead"); + +/** + * DEPRECATED: Creates and returns an archive at the given URL + * + * @param fileURL The URL of the archive file + * + * @return Returns a UZKArchive object, or nil if the URL isn't reachable + */ ++ (nullable instancetype)zipArchiveAtURL:(NSURL *)fileURL __deprecated_msg("Use -initWithURL:error: instead"); + +/** + * DEPRECATED: Creates and returns an archive at the given path, with a given password + * + * @param filePath A path to the archive file + * @param password The password of the given archive + * + * @return Returns a UZKArchive object, or nil if the path isn't reachable + */ ++ (nullable instancetype)zipArchiveAtPath:(NSString *)filePath password:(nullable NSString *)password __deprecated_msg("Use -initWithPath:password:error: instead"); + +/** + * DEPRECATED: Creates and returns an archive at the given URL, with a given password + * + * @param fileURL The URL of the archive file + * @param password The password of the given archive + * + * @return Returns a UZKArchive object, or nil if the URL isn't reachable + */ ++ (nullable instancetype)zipArchiveAtURL:(NSURL *)fileURL password:(nullable NSString *)password __deprecated_msg("Use -initWithURL:password:error: instead");; + + +/** + * Creates and returns an archive at the given path + * + * @param filePath A path to the archive file + * @param error Returns an error code if the object can't be initialized + * + * @return Returns a UZKArchive object, or nil if the path isn't reachable + */ +- (nullable instancetype)initWithPath:(NSString *)filePath error:(NSError **)error; + +/** + * Creates and returns an archive at the given URL + * + * @param fileURL The URL of the archive file + * @param error Returns an error code if the object can't be initialized + * + * @return Returns a UZKArchive object, or nil if the URL isn't reachable + */ +- (nullable instancetype)initWithURL:(NSURL *)fileURL error:(NSError **)error; + +/** + * Creates and returns an archive at the given path, with a given password + * + * @param filePath A path to the archive file + * @param password The password of the given archive + * @param error Returns an error code if the object can't be initialized + * + * @return Returns a UZKArchive object, or nil if the path isn't reachable + */ +- (nullable instancetype)initWithPath:(NSString *)filePath password:(nullable NSString *)password error:(NSError **)error; + +/** + * Creates and returns an archive at the given URL, with a given password + * + * @param fileURL The URL of the archive file + * @param password The password of the given archive + * @param error Returns an error code if the object can't be initialized + * + * @return Returns a UZKArchive object, or nil if the URL isn't reachable + */ +- (nullable instancetype)initWithURL:(NSURL *)fileURL password:(nullable NSString *)password error:(NSError **)error; + + + +#pragma mark - Read Methods + + +/** + * Determines whether a file is a Zip file by reading the header + * + * @param filePath Path to the file being checked + * + * @return YES if the file exists and contains a signature indicating it is a Zip file + */ ++ (BOOL)pathIsAZip:(NSString *)filePath; + +/** + * Determines whether a file is a Zip file by reading the header + * + * @param fileURL URL of the file being checked + * + * @return YES if the file exists and contains a signature indicating it is a Zip file + */ ++ (BOOL)urlIsAZip:(NSURL *)fileURL; + + +/** + * Lists the names of the files in the archive + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return Returns a list of NSString containing the paths within the archive's contents, or nil if an error was encountered + */ +- (nullable NSArray *)listFilenames:(NSError **)error; + +/** + * Lists the various attributes of each file in the archive + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return Returns a list of UZKFileInfo objects, which contain metadata about the archive's files, or nil if an error was encountered + */ +- (nullable NSArray *)listFileInfo:(NSError **)error; + +/** + * Writes all files in the archive to the given path. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction. Use the progress property (as explained in the README) to + * retrieve more detailed information, such as the current file being extracted, number of files extracted, + * and the URKFileInfo instance being extracted + * + * @param destinationDirectory The destination path of the unarchived files + * @param overwrite YES to overwrite files in the destination directory, NO otherwise + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return YES on successful extraction, NO if an error was encountered + */ +- (BOOL)extractFilesTo:(NSString *)destinationDirectory + overwrite:(BOOL)overwrite + error:(NSError **)error; + +/** + * **DEPRECATED:** Writes all files in the archive to the given path + * + * @param destinationDirectory The destination path of the unarchived files + * @param overwrite YES to overwrite files in the destination directory, NO otherwise + * @param progress Called every so often to report the progress of the extraction + * + * - *currentFile* The info about the file that's being extracted + * - *percentArchiveDecompressed* The percentage of the archive that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return YES on successful extraction, NO if an error was encountered + */ +- (BOOL)extractFilesTo:(NSString *)destinationDirectory + overwrite:(BOOL)overwrite + progress:(nullable void (^)(UZKFileInfo *currentFile, CGFloat percentArchiveDecompressed))progress + error:(NSError **)error __deprecated_msg("Use -extractFilesTo:overwrite:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * Unarchive a single file from the archive into memory. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction + * + * @param fileInfo The info of the file within the archive to be expanded. Only the filename property is used + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractData:(UZKFileInfo *)fileInfo + error:(NSError **)error; + +/** + * **DEPRECATED:** Unarchive a single file from the archive into memory + * + * @param fileInfo The info of the file within the archive to be expanded. Only the filename property is used + * @param progress Called every so often to report the progress of the extraction + * + * - *percentDecompressed* The percentage of the archive that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractData:(UZKFileInfo *)fileInfo + progress:(nullable void (^)(CGFloat percentDecompressed))progress + error:(NSError **)error __deprecated_msg("Use -extractData:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * Unarchive a single file from the archive into memory. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction + * + * @param filePath The path of the file within the archive to be expanded + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractDataFromFile:(NSString *)filePath + error:(NSError **)error; + +/** + * **DEPRECATED:** Unarchive a single file from the archive into memory + * + * @param filePath The path of the file within the archive to be expanded + * @param progress Called every so often to report the progress of the extraction + * + * - *percentDecompressed* The percentage of the file that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractDataFromFile:(NSString *)filePath + progress:(nullable void (^)(CGFloat percentDecompressed))progress + error:(NSError **)error __deprecated_msg("Use -extractDataFromFile:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * Loops through each file in the archive into memory, allowing you to perform an action + * using its info. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of the operation + * + * @param action The action to perform using the data + * + * - *fileInfo* The metadata of the file within the archive + * - *stop* Set to YES to stop reading the archive + * + * @param error Contains an error if any was returned + * + * @return YES if no errors were encountered, NO otherwise + */ +- (BOOL)performOnFilesInArchive:(void(^)(UZKFileInfo *fileInfo, BOOL *stop))action + error:(NSError **)error; + +/** + * Extracts each file in the archive into memory, allowing you to perform an action + * on it. Supports NSProgress for progress reporting, which also allows cancellation + * in the middle of the operation + * + * @param action The action to perform using the data + * + * - *fileInfo* The metadata of the file within the archive + * - *fileData* The full data of the file in the archive + * - *stop* Set to YES to stop reading the archive + * + * @param error Contains an error if any was returned + * + * @return YES if no errors were encountered, NO otherwise + */ +- (BOOL)performOnDataInArchive:(void(^)(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop))action + error:(NSError **)error; + +/** + * Unarchive a single file from the archive into memory. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction + * + * @param filePath The path of the file within the archive to be expanded + * @param error Contains an NSError object when there was an error reading the archive + * @param action The block to run for each chunk of data, each of size <= bufferSize + * + * - *dataChunk* The data read from the archived file. Read bytes and length to write the data + * - *percentDecompressed* The percentage of the file that has been decompressed + * + * @return YES if all data was read successfully, NO if an error was encountered + */ +- (BOOL)extractBufferedDataFromFile:(NSString *)filePath + error:(NSError **)error + action:(void(^)(NSData *dataChunk, CGFloat percentDecompressed))action; + +/** + * YES if archive protected with a password, NO otherwise + */ +- (BOOL)isPasswordProtected; + +/** + * Tests whether the provided password unlocks the archive + * + * @return YES if correct password or archive is not password protected, NO if password is wrong + */ +- (BOOL)validatePassword; + +/** + Extract each file in the archive, checking whether the data matches the CRC checksum + stored at the time it was written + + @return YES if the data is all correct, false if any check failed + */ +- (BOOL)checkDataIntegrity; + +/** + Extract a particular file, to determine if its data matches the CRC + checksum stored at the time it written + + @param filePath The file in the archive to check + + @return YES if the data is correct, false if any check failed + */ +- (BOOL)checkDataIntegrityOfFile:(NSString *)filePath; + + + +#pragma mark - Write Methods + + +/** + * 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 filePath The full path to the target file in the archive + * @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 + filePath:(NSString *)filePath + 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 + * @param progress Called every so often to report the progress of the compression + * + * - *percentCompressed* The percentage of the file that has been compressed + * + * @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 + filePath:(NSString *)filePath + progress:(nullable void (^)(CGFloat percentCompressed))progress + error:(NSError **)error __deprecated_msg("Use -writeData:filePath:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * 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 + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + 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 + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param progress Called every so often to report the progress of the compression + * + * - *percentCompressed* The percentage of the file that has been compressed + * + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + progress:(nullable void (^)(CGFloat percentCompressed))progress + error:(NSError **)error __deprecated_msg("Use -writeData:filePath:fileDate:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * 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 + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + 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 + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @param progress Called every so often to report the progress of the compression + * + * - *percentCompressed* The percentage of the file that has been compressed + * + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + progress:(nullable void (^)(CGFloat percentCompressed))progress + error:(NSError **)error __deprecated_msg("Use -writeData:filePath:fileDate:compressionMethod:password:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * 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. + * + * @param data Data to write into the archive + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + error:(NSError **)error; + +/** + * 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. + * + * @param data Data to write into the archive + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param permissions The desired POSIX permissions of the file in the archive + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + posixPermissions:(short)permissions +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + error:(NSError **)error; + +/** + * **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. + * + * @param data Data to write into the archive + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param progress Called every so often to report the progress of the compression + * + * - *percentCompressed* The percentage of the file that has been compressed + * + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + progress:(nullable void (^)(CGFloat percentCompressed))progress + error:(NSError **)error __deprecated_msg("Use -writeData:filePath:fileDate:compressionMethod:password:overwrite:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * **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. + * + * @param data Data to write into the archive + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param permissions The desired POSIX permissions of the file in the archive + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param progress Called every so often to report the progress of the compression + * + * - *percentCompressed* The percentage of the file that has been compressed + * + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + posixPermissions:(short)permissions +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + progress:(nullable void (^)(CGFloat percentCompressed))progress + error:(NSError **)error __deprecated_msg("Use -writeData:filePath:fileDate:permissions:compressionMethod:password:overwrite:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * 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 + * @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:(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 filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @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:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + 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 filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @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:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + compressionMethod:(UZKCompressionMethod)method + 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, 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. + * + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @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:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + compressionMethod:(UZKCompressionMethod)method + overwrite:(BOOL)overwrite + 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, 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. + * + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param preCRC The CRC-32 for the data being sent. Only necessary if encrypting the file. + Pass 0 otherwise + * @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:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + 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; + +/** + * 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 + * be slow. On the other hand, when not overwriting, the size of the archive will grow each time + * the file is written. + * + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param preCRC The CRC-32 for the data being sent. Only necessary if encrypting the file. + * Pass 0 otherwise + * @param password Override the password associated with the archive (not recommended) + * @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:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + 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; + + +/** + * 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 + * be slow. On the other hand, when not overwriting, the size of the archive will grow each time + * the file is written. + * + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param permissions The desired POSIX permissions of the file in the archive + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param preCRC The CRC-32 for the data being sent. Only necessary if encrypting the file. + * Pass 0 otherwise + * @param password Override the password associated with the archive (not recommended) + * @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:(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; + +/** + * Removes the given file from the archive + * + * @param filePath The file in the archive you wish to delete + * @param error Contains an NSError object when there was an error writing to the archive + * + * @return YES if the file was successfully deleted, NO otherwise + */ +- (BOOL)deleteFile:(NSString *)filePath error:(NSError **)error; + + +@end +NS_ASSUME_NONNULL_END diff --git a/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Headers/UZKFileInfo.h b/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Headers/UZKFileInfo.h new file mode 100644 index 0000000..e14248e --- /dev/null +++ b/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Headers/UZKFileInfo.h @@ -0,0 +1,90 @@ +// +// UZKFileInfo.h +// UnzipKit +// +// + +#import + + + +@class UZKArchive; + +/** + * Defines the various compression levels that can be applied to a file + */ +typedef NS_ENUM(NSInteger, UZKCompressionMethod) { + /** + * Default level + */ + UZKCompressionMethodDefault= -1, + + /** + * No compression + */ + UZKCompressionMethodNone= 0, + + /** + * Fastest compression + */ + UZKCompressionMethodFastest= 1, + + /** + * Best (slowest) compression + */ + UZKCompressionMethodBest= 9 +}; + + +@interface UZKFileInfo : NSObject + +/** + * The name of the file + */ +@property (readonly, strong) NSString *filename; + +/** + * The timestamp of the file + */ +@property (readonly, nonatomic) NSDate *timestamp; + +/** + * The CRC checksum of the file + */ +@property (readonly) NSUInteger CRC; + +/** + * Size of the uncompressed file + */ +@property (readonly) unsigned long long int uncompressedSize; + +/** + * Size of the compressed file + */ +@property (readonly) unsigned long long int compressedSize; + +/** + * YES if the file will be continued of the next volume + */ +@property (readonly) BOOL isEncryptedWithPassword; + +/** + * YES if the file is a directory + */ +@property (readonly) BOOL isDirectory; + +/** + * The type of compression + */ +@property (readonly) UZKCompressionMethod compressionMethod; + +/** + * The POSIX permissions of the file, like you would get by retrieving the `NSFilePosixPermissions` + * key from the attributes NSFileManager returns. Assign in octal form, like 0777 in Objective-C or + * 0o777 in Swift + */ +@property (nonatomic, readonly) short posixPermissions; + + + +@end diff --git a/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Headers/UnzipKit.h b/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Headers/UnzipKit.h new file mode 100644 index 0000000..d390a9d --- /dev/null +++ b/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Headers/UnzipKit.h @@ -0,0 +1,19 @@ +// +// UnzipKit.h +// UnzipKit +// +// Created by Dov Frankel on 12/16/14. +// Copyright (c) 2014 Abbey Code. All rights reserved. +// + +#import + +//! Project version number for UnzipKit. +FOUNDATION_EXPORT double UnzipKitVersionNumber; + +//! Project version string for UnzipKit. +FOUNDATION_EXPORT const unsigned char UnzipKitVersionString[]; + + +#import "UZKArchive.h" +#import "UZKFileInfo.h" diff --git a/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Modules/module.modulemap b/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Modules/module.modulemap new file mode 100644 index 0000000..58ada25 --- /dev/null +++ b/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module UnzipKit { + umbrella header "UnzipKit.h" + + export * + module * { export * } +} diff --git a/Carthage/Build/Mac/UnzipKit.framework/Versions/A/PrivateHeaders/UZKFileInfo_Private.h b/Carthage/Build/Mac/UnzipKit.framework/Versions/A/PrivateHeaders/UZKFileInfo_Private.h new file mode 100644 index 0000000..bcce4fb --- /dev/null +++ b/Carthage/Build/Mac/UnzipKit.framework/Versions/A/PrivateHeaders/UZKFileInfo_Private.h @@ -0,0 +1,23 @@ +// +// UZKFileInfo_Private.h +// UnzipKit +// +// + +@import Foundation; + +#import "unzip.h" + +@interface UZKFileInfo (Private) + +/** + * Returns a UZKFileInfo instance for the given extended header data + * + * @param fileInfo The header data for a Zip file + * @param filename The archive that contains the file + * + * @return an instance of UZKFileInfo + */ ++ (instancetype) fileInfo:(unz_file_info64 *)fileInfo filename:(NSString *)filename; + +@end \ No newline at end of file diff --git a/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Resources/Info.plist b/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Resources/Info.plist new file mode 100644 index 0000000..2664c85 --- /dev/null +++ b/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Resources/Info.plist @@ -0,0 +1,46 @@ + + + + + BuildMachineOSBuild + 17D47 + CFBundleDevelopmentRegion + en + CFBundleExecutable + UnzipKit + CFBundleIdentifier + com.abbey-code.UnzipKit + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + UnzipKit + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.9 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 1.9 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 9E145 + DTPlatformVersion + GM + DTSDKBuild + 17E189 + DTSDKName + macosx10.13 + DTXcode + 0930 + DTXcodeBuild + 9E145 + NSHumanReadableCopyright + © 2017 Abbey Code. All rights reserved. + + diff --git a/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Resources/UnzipKitResources.bundle/Contents/Info.plist b/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Resources/UnzipKitResources.bundle/Contents/Info.plist new file mode 100644 index 0000000..86fed6a --- /dev/null +++ b/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Resources/UnzipKitResources.bundle/Contents/Info.plist @@ -0,0 +1,44 @@ + + + + + BuildMachineOSBuild + 17D47 + CFBundleDevelopmentRegion + en + CFBundleIdentifier + com.abbey-code.UnzipKitResources + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + UnzipKitResources + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.9 + CFBundleSignature + ???? + CFBundleSupportedPlatforms + + MacOSX + + CFBundleVersion + 1.9 + DTCompiler + com.apple.compilers.llvm.clang.1_0 + DTPlatformBuild + 9E145 + DTPlatformVersion + GM + DTSDKBuild + 17E189 + DTSDKName + macosx10.13 + DTXcode + 0930 + DTXcodeBuild + 9E145 + NSHumanReadableCopyright + Copyright © 2019 Abbey Code. All rights reserved. + + diff --git a/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Resources/UnzipKitResources.bundle/Contents/Resources/en.lproj/UnzipKit.strings b/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Resources/UnzipKitResources.bundle/Contents/Resources/en.lproj/UnzipKit.strings new file mode 100644 index 0000000..baa4322 Binary files /dev/null and b/Carthage/Build/Mac/UnzipKit.framework/Versions/A/Resources/UnzipKitResources.bundle/Contents/Resources/en.lproj/UnzipKit.strings differ diff --git a/Carthage/Build/Mac/UnzipKit.framework/Versions/A/UnzipKit b/Carthage/Build/Mac/UnzipKit.framework/Versions/A/UnzipKit new file mode 100755 index 0000000..23c355d Binary files /dev/null and b/Carthage/Build/Mac/UnzipKit.framework/Versions/A/UnzipKit differ diff --git a/Carthage/Build/Mac/UnzipKit.framework/Versions/Current b/Carthage/Build/Mac/UnzipKit.framework/Versions/Current new file mode 120000 index 0000000..8c7e5a6 --- /dev/null +++ b/Carthage/Build/Mac/UnzipKit.framework/Versions/Current @@ -0,0 +1 @@ +A \ No newline at end of file diff --git a/Carthage/Build/iOS/2C82B111-5AC6-3661-95D4-A6AF7CBD8646.bcsymbolmap b/Carthage/Build/iOS/2C82B111-5AC6-3661-95D4-A6AF7CBD8646.bcsymbolmap new file mode 100644 index 0000000..09a241e --- /dev/null +++ b/Carthage/Build/iOS/2C82B111-5AC6-3661-95D4-A6AF7CBD8646.bcsymbolmap @@ -0,0 +1,771 @@ +BCSymbolMap Version: 2.0 ++[UZKArchive zipArchiveAtPath:] ++[UZKArchive zipArchiveAtURL:] ++[UZKArchive zipArchiveAtPath:password:] ++[UZKArchive zipArchiveAtURL:password:] ++[UZKArchive initialize] +___24+[UZKArchive initialize]_block_invoke +-[UZKArchive init] +-[UZKArchive initWithPath:error:] +-[UZKArchive initWithURL:error:] +-[UZKArchive initWithPath:password:error:] +-[UZKArchive initWithURL:password:error:] +-[UZKArchive initWithFile:error:] +-[UZKArchive initWithFile:password:error:] +-[UZKArchive fileURL] +-[UZKArchive filename] +-[UZKArchive comment] +-[UZKArchive setComment:] ++[UZKArchive pathIsAZip:] ++[UZKArchive urlIsAZip:] +-[UZKArchive listFilenames:] +-[UZKArchive listFileInfo:] +___27-[UZKArchive listFileInfo:]_block_invoke +___copy_helper_block_ +___destroy_helper_block_ +-[UZKArchive extractFilesTo:overwrite:error:] +-[UZKArchive extractFilesTo:overwrite:progress:error:] +___54-[UZKArchive extractFilesTo:overwrite:progress:error:]_block_invoke +___54-[UZKArchive extractFilesTo:overwrite:progress:error:]_block_invoke.170 +___copy_helper_block_.173 +___destroy_helper_block_.174 +___copy_helper_block_.207 +___destroy_helper_block_.208 +-[UZKArchive extractData:error:] +-[UZKArchive extractData:progress:error:] +-[UZKArchive extractDataFromFile:error:] +-[UZKArchive extractDataFromFile:progress:error:] +___49-[UZKArchive extractDataFromFile:progress:error:]_block_invoke +___copy_helper_block_.219 +___destroy_helper_block_.220 +-[UZKArchive performOnFilesInArchive:error:] +___44-[UZKArchive performOnFilesInArchive:error:]_block_invoke +___copy_helper_block_.237 +___destroy_helper_block_.238 +-[UZKArchive performOnDataInArchive:error:] +___43-[UZKArchive performOnDataInArchive:error:]_block_invoke +___copy_helper_block_.248 +___destroy_helper_block_.249 +-[UZKArchive extractBufferedDataFromFile:error:action:] +___55-[UZKArchive extractBufferedDataFromFile:error:action:]_block_invoke +___copy_helper_block_.270 +___destroy_helper_block_.271 +-[UZKArchive isPasswordProtected] +-[UZKArchive validatePassword] +___30-[UZKArchive validatePassword]_block_invoke +-[UZKArchive checkDataIntegrity] +-[UZKArchive checkDataIntegrityOfFile:] +___39-[UZKArchive checkDataIntegrityOfFile:]_block_invoke +___copy_helper_block_.296 +___destroy_helper_block_.297 +-[UZKArchive writeData:filePath:error:] +-[UZKArchive writeData:filePath:progress:error:] +-[UZKArchive writeData:filePath:fileDate:error:] +-[UZKArchive writeData:filePath:fileDate:progress:error:] +-[UZKArchive writeData:filePath:fileDate:compressionMethod:password:error:] +-[UZKArchive writeData:filePath:fileDate:compressionMethod:password:progress:error:] +-[UZKArchive writeData:filePath:fileDate:compressionMethod:password:overwrite:error:] +-[UZKArchive writeData:filePath:fileDate:compressionMethod:password:overwrite:progress:error:] +-[UZKArchive writeData:filePath:fileDate:posixPermissions:compressionMethod:password:overwrite:error:] +-[UZKArchive writeData:filePath:fileDate:posixPermissions:compressionMethod:password:overwrite:progress:error:] +___111-[UZKArchive writeData:filePath:fileDate:posixPermissions:compressionMethod:password:overwrite:progress:error:]_block_invoke +___copy_helper_block_.318 +___destroy_helper_block_.319 +-[UZKArchive writeIntoBuffer:error:block:] +-[UZKArchive writeIntoBuffer:fileDate:error:block:] +-[UZKArchive writeIntoBuffer:fileDate:compressionMethod:error:block:] +-[UZKArchive writeIntoBuffer:fileDate:compressionMethod:overwrite:error:block:] +-[UZKArchive writeIntoBuffer:fileDate:compressionMethod:overwrite:CRC:error:block:] +-[UZKArchive writeIntoBuffer:fileDate:compressionMethod:overwrite:CRC:password:error:block:] +-[UZKArchive writeIntoBuffer:fileDate:posixPermissions:compressionMethod:overwrite:CRC:password:error:block:] +___109-[UZKArchive writeIntoBuffer:fileDate:posixPermissions:compressionMethod:overwrite:CRC:password:error:block:]_block_invoke +___109-[UZKArchive writeIntoBuffer:fileDate:posixPermissions:compressionMethod:overwrite:CRC:password:error:block:]_block_invoke.326 +___copy_helper_block_.327 +___destroy_helper_block_.328 +___copy_helper_block_.337 +___destroy_helper_block_.338 +-[UZKArchive deleteFile:error:] +-[UZKArchive performActionWithArchiveOpen:inMode:error:] +-[UZKArchive performWriteAction:filePath:fileDate:posixPermissions:compressionMethod:password:overwrite:CRC:error:] +___115-[UZKArchive performWriteAction:filePath:fileDate:posixPermissions:compressionMethod:password:overwrite:CRC:error:]_block_invoke +___copy_helper_block_.414 +___destroy_helper_block_.415 +___115-[UZKArchive performWriteAction:filePath:fileDate:posixPermissions:compressionMethod:password:overwrite:CRC:error:]_block_invoke.424 +___copy_helper_block_.435 +___destroy_helper_block_.436 +-[UZKArchive openFile:inMode:withPassword:error:] +-[UZKArchive closeFile:inMode:] +-[UZKArchive currentFileInZipInfo:] +-[UZKArchive locateFileInZip:error:] +-[UZKArchive openFile:] +-[UZKArchive readFile:length:error:] +-[UZKArchive readGlobalComment] +___Block_byref_object_copy_ +___Block_byref_object_dispose_ +___31-[UZKArchive readGlobalComment]_block_invoke +___copy_helper_block_.522 +___destroy_helper_block_.523 +-[UZKArchive storeFileBookmark:error:] ++[UZKArchive figureOutCString:] ++[UZKArchive errorNameForErrorCode:] ++[UZKArchive zipFileInfoForDate:posixPermissions:] +-[UZKArchive assignError:code:detail:] +-[UZKArchive assignError:code:detail:underlyer:] +-[UZKArchive isDeflate64:] +-[UZKArchive beginProgressOperation:] +-[UZKArchive password] +-[UZKArchive setPassword:] +-[UZKArchive progress] +-[UZKArchive setProgress:] +-[UZKArchive fileBookmark] +-[UZKArchive setFileBookmark:] +-[UZKArchive fallbackURL] +-[UZKArchive setFallbackURL:] +-[UZKArchive openCount] +-[UZKArchive setOpenCount:] +-[UZKArchive mode] +-[UZKArchive setMode:] +-[UZKArchive zipFile] +-[UZKArchive setZipFile:] +-[UZKArchive unzFile] +-[UZKArchive setUnzFile:] +-[UZKArchive archiveContents] +-[UZKArchive setArchiveContents:] +-[UZKArchive threadLock] +-[UZKArchive setThreadLock:] +-[UZKArchive commentRetrieved] +-[UZKArchive setCommentRetrieved:] +-[UZKArchive .cxx_destruct] +__resources +_initialize.onceToken +___block_descriptor_tmp +___block_literal_global +LOS_LOG0 +LOS_ACT1 +LOS_LOG3 +LOS_LOG4 +LOS_LOG5 +LOS_LOG6 +LOS_LOG7 +LOS_LOG8 +LOS_LOG9 +_OBJC_IVAR_$_UZKArchive._openCount +_OBJC_IVAR_$_UZKArchive._mode +_OBJC_IVAR_$_UZKArchive._fallbackURL +_OBJC_IVAR_$_UZKArchive._password +_OBJC_IVAR_$_UZKArchive._threadLock +_OBJC_IVAR_$_UZKArchive._commentRetrieved +LOS_ACT10 +LOS_LOG12 +LOS_LOG13 +LOS_LOG14 +LOS_LOG15 +LOS_LOG16 +LOS_LOG17 +LOS_LOG18 +LOS_LOG19 +LOS_LOG20 +LOS_ACT21 +LOS_ACT23 +LOS_LOG25 +_OBJC_IVAR_$_UZKArchive._comment +LOS_ACT26 +LOS_LOG28 +LOS_LOG29 +LOS_LOG30 +LOS_ACT31 +LOS_LOG33 +LOS_LOG34 +LOS_LOG35 +LOS_LOG36 +LOS_LOG37 +LOS_LOG38 +LOS_LOG39 +LOS_LOG40 +LOS_ACT41 +LOS_LOG43 +LOS_ACT44 +LOS_LOG46 +LOS_ACT47 +LOS_LOG49 +LOS_LOG50 +LOS_ACT51 +LOS_LOG53 +LOS_LOG54 +LOS_LOG55 +LOS_LOG56 +LOS_LOG57 +LOS_LOG58 +LOS_LOG59 +LOS_LOG60 +LOS_LOG61 +LOS_LOG62 +LOS_LOG63 +LOS_LOG64 +LOS_LOG65 +LOS_LOG66 +___block_descriptor_tmp.122 +LOS_ACT67 +LOS_LOG69 +LOS_LOG70 +LOS_LOG71 +LOS_ACT72 +LOS_LOG74 +LOS_LOG75 +LOS_LOG76 +LOS_LOG77 +LOS_LOG78 +LOS_LOG79 +LOS_LOG80 +LOS_LOG81 +LOS_LOG82 +LOS_LOG83 +LOS_LOG84 +LOS_LOG85 +LOS_LOG86 +LOS_LOG87 +LOS_LOG88 +LOS_LOG89 +LOS_LOG90 +LOS_LOG91 +LOS_LOG92 +___block_descriptor_tmp.176 +LOS_LOG93 +LOS_LOG94 +LOS_LOG95 +LOS_LOG96 +___block_descriptor_tmp.209 +LOS_ACT97 +LOS_LOG99 +LOS_LOG100 +___block_descriptor_tmp.221 +LOS_LOG101 +LOS_LOG102 +LOS_LOG103 +LOS_ACT104 +LOS_LOG106 +LOS_LOG107 +LOS_LOG108 +LOS_LOG109 +LOS_ACT110 +LOS_LOG112 +LOS_LOG113 +LOS_LOG114 +___block_descriptor_tmp.239 +LOS_LOG115 +LOS_LOG116 +LOS_ACT117 +LOS_LOG119 +LOS_LOG120 +LOS_LOG121 +LOS_LOG122 +LOS_LOG123 +LOS_LOG124 +LOS_LOG125 +___block_descriptor_tmp.251 +LOS_ACT126 +LOS_LOG128 +LOS_LOG129 +LOS_LOG130 +LOS_LOG131 +LOS_LOG132 +LOS_LOG133 +LOS_LOG134 +LOS_LOG135 +LOS_LOG136 +LOS_LOG137 +LOS_LOG138 +LOS_LOG139 +LOS_LOG140 +LOS_LOG141 +LOS_LOG142 +LOS_LOG143 +LOS_LOG144 +LOS_LOG145 +___block_descriptor_tmp.272 +LOS_LOG146 +LOS_LOG147 +LOS_ACT148 +LOS_LOG150 +LOS_LOG151 +LOS_LOG152 +LOS_LOG153 +LOS_ACT154 +LOS_LOG156 +LOS_LOG157 +LOS_LOG158 +LOS_LOG159 +___block_descriptor_tmp.280 +___block_literal_global.281 +LOS_LOG160 +LOS_LOG161 +LOS_ACT162 +LOS_LOG164 +LOS_LOG165 +LOS_LOG166 +LOS_LOG167 +___block_descriptor_tmp.299 +LOS_LOG168 +LOS_LOG169 +LOS_ACT170 +LOS_LOG172 +LOS_LOG173 +LOS_LOG174 +LOS_ACT175 +LOS_LOG177 +LOS_LOG178 +LOS_LOG179 +LOS_LOG180 +LOS_LOG181 +___block_descriptor_tmp.321 +LOS_ACT182 +LOS_LOG184 +LOS_ACT185 +LOS_LOG187 +LOS_LOG188 +LOS_LOG189 +LOS_LOG190 +LOS_LOG191 +___block_descriptor_tmp.330 +LOS_LOG192 +LOS_LOG193 +___block_descriptor_tmp.339 +LOS_ACT194 +LOS_LOG196 +LOS_LOG197 +LOS_LOG198 +LOS_LOG199 +LOS_LOG200 +LOS_LOG201 +LOS_LOG202 +LOS_LOG203 +LOS_LOG204 +LOS_LOG205 +LOS_LOG206 +LOS_LOG207 +LOS_LOG208 +LOS_LOG209 +LOS_LOG210 +LOS_LOG211 +LOS_LOG212 +LOS_LOG213 +LOS_LOG214 +LOS_LOG215 +LOS_LOG216 +LOS_LOG217 +LOS_LOG218 +LOS_LOG219 +LOS_LOG220 +LOS_LOG221 +LOS_LOG222 +LOS_LOG223 +LOS_LOG224 +LOS_LOG225 +LOS_LOG226 +LOS_LOG227 +LOS_LOG228 +LOS_LOG229 +LOS_LOG230 +LOS_LOG231 +LOS_LOG232 +LOS_LOG233 +LOS_LOG234 +LOS_LOG235 +LOS_LOG236 +LOS_LOG237 +LOS_LOG238 +LOS_LOG239 +LOS_LOG240 +LOS_LOG241 +LOS_LOG242 +LOS_LOG243 +LOS_LOG244 +LOS_LOG245 +LOS_LOG246 +LOS_LOG247 +LOS_LOG248 +LOS_LOG249 +LOS_LOG250 +LOS_LOG251 +LOS_LOG252 +LOS_LOG253 +LOS_LOG254 +LOS_LOG255 +LOS_LOG256 +LOS_LOG257 +LOS_LOG258 +LOS_LOG259 +LOS_LOG260 +LOS_LOG261 +LOS_LOG262 +LOS_LOG263 +LOS_LOG264 +LOS_LOG265 +LOS_LOG266 +LOS_LOG267 +LOS_LOG268 +LOS_LOG269 +LOS_LOG270 +LOS_LOG271 +LOS_LOG272 +LOS_LOG273 +LOS_LOG274 +LOS_LOG275 +LOS_LOG276 +LOS_LOG277 +LOS_LOG278 +LOS_LOG279 +LOS_LOG280 +LOS_LOG281 +LOS_LOG282 +LOS_LOG283 +LOS_LOG284 +LOS_LOG285 +LOS_LOG286 +LOS_LOG287 +LOS_LOG288 +LOS_LOG289 +LOS_LOG290 +LOS_LOG291 +LOS_LOG292 +LOS_LOG293 +LOS_LOG294 +LOS_LOG295 +LOS_LOG296 +LOS_LOG297 +LOS_LOG298 +LOS_ACT299 +LOS_LOG301 +LOS_LOG302 +LOS_LOG303 +LOS_ACT304 +LOS_LOG306 +LOS_LOG307 +LOS_LOG308 +___block_descriptor_tmp.417 +LOS_LOG309 +LOS_LOG310 +LOS_LOG311 +LOS_ACT312 +LOS_LOG314 +LOS_LOG315 +LOS_LOG316 +LOS_LOG317 +LOS_LOG318 +LOS_LOG319 +LOS_LOG320 +LOS_LOG321 +LOS_LOG322 +LOS_LOG323 +LOS_LOG324 +___block_descriptor_tmp.437 +LOS_ACT325 +LOS_LOG327 +LOS_LOG328 +LOS_LOG329 +LOS_LOG330 +LOS_LOG331 +LOS_LOG332 +LOS_LOG333 +LOS_LOG334 +LOS_LOG335 +LOS_LOG336 +LOS_LOG337 +LOS_LOG338 +LOS_LOG339 +LOS_LOG340 +LOS_LOG341 +LOS_LOG342 +LOS_LOG343 +LOS_LOG344 +LOS_LOG345 +LOS_LOG346 +LOS_LOG347 +LOS_LOG348 +LOS_LOG349 +LOS_LOG350 +LOS_LOG351 +LOS_LOG352 +LOS_LOG353 +LOS_LOG354 +LOS_ACT355 +LOS_LOG357 +LOS_LOG358 +LOS_LOG359 +LOS_LOG360 +LOS_LOG361 +LOS_LOG362 +LOS_LOG363 +LOS_LOG364 +LOS_LOG365 +LOS_LOG366 +LOS_ACT367 +LOS_LOG369 +LOS_LOG370 +LOS_LOG371 +LOS_ACT372 +LOS_LOG374 +LOS_LOG375 +LOS_LOG376 +LOS_LOG377 +LOS_LOG378 +LOS_LOG379 +LOS_LOG380 +LOS_LOG381 +LOS_ACT382 +LOS_LOG384 +LOS_LOG385 +LOS_LOG386 +LOS_LOG387 +LOS_LOG388 +LOS_LOG389 +LOS_LOG390 +LOS_LOG391 +LOS_LOG392 +LOS_ACT393 +LOS_LOG395 +LOS_LOG396 +LOS_LOG397 +LOS_LOG398 +LOS_LOG399 +LOS_ACT400 +LOS_LOG402 +LOS_LOG403 +LOS_ACT404 +LOS_LOG406 +LOS_LOG407 +LOS_LOG408 +LOS_LOG409 +LOS_LOG410 +LOS_LOG411 +LOS_LOG412 +LOS_LOG413 +LOS_LOG414 +LOS_LOG415 +LOS_LOG416 +LOS_LOG417 +LOS_LOG418 +___block_descriptor_tmp.524 +LOS_ACT419 +LOS_LOG421 +LOS_LOG422 +LOS_LOG423 +LOS_ACT424 +LOS_LOG426 +LOS_LOG427 +LOS_LOG428 +LOS_LOG429 +LOS_ACT430 +LOS_LOG432 +LOS_ACT433 +_OBJC_IVAR_$_UZKArchive._progress +_OBJC_IVAR_$_UZKArchive._fileBookmark +_OBJC_IVAR_$_UZKArchive._zipFile +_OBJC_IVAR_$_UZKArchive._unzFile +_OBJC_IVAR_$_UZKArchive._archiveContents +l_OBJC_PROTOCOL_$_NSObject +l_OBJC_LABEL_PROTOCOL_$_NSObject +l_OBJC_PROTOCOL_$_NSProgressReporting +l_OBJC_LABEL_PROTOCOL_$_NSProgressReporting +Apple LLVM version 9.1.0 (clang-902.0.39.1) +/Users/travis/build/abbeycode/UnzipKit/Source/UZKArchive.m +/Users/travis/build/abbeycode/UnzipKit +/Users/travis/build/abbeycode/UnzipKit/Source/UZKArchive.h +__os_log_helper_16_0_1_4_0 +__os_log_helper_16_0_0 +__os_log_helper_16_2_2_4_66_4_66 +__destroy_helper_block_ +__copy_helper_block_ +__31-[UZKArchive readGlobalComment]_block_invoke +__os_log_helper_16_2_1_4_66 +__Block_byref_object_dispose_ +__Block_byref_object_copy_ +__os_log_helper_16_0_2_4_0_4_0 +__os_log_helper_16_2_2_4_0_4_66 +__os_log_helper_16_2_2_4_34_4_34 +__115-[UZKArchive performWriteAction:filePath:fileDate:posixPermissions:compressionMethod:password:overwrite:CRC:error:]_block_invoke.424 +__115-[UZKArchive performWriteAction:filePath:fileDate:posixPermissions:compressionMethod:password:overwrite:CRC:error:]_block_invoke +__os_log_helper_16_2_1_4_34 +__109-[UZKArchive writeIntoBuffer:fileDate:posixPermissions:compressionMethod:overwrite:CRC:password:error:block:]_block_invoke.326 +__109-[UZKArchive writeIntoBuffer:fileDate:posixPermissions:compressionMethod:overwrite:CRC:password:error:block:]_block_invoke +__os_log_helper_16_2_7_4_66_4_0_4_0_4_66_4_0_4_66_4_66 +__111-[UZKArchive writeData:filePath:fileDate:posixPermissions:compressionMethod:password:overwrite:progress:error:]_block_invoke +__os_log_helper_16_0_1_8_0 +__os_log_helper_16_2_7_4_66_4_0_4_0_4_66_4_66_4_66_4_66 +__39-[UZKArchive checkDataIntegrityOfFile:]_block_invoke +__os_log_helper_16_2_3_4_66_4_0_4_0 +__30-[UZKArchive validatePassword]_block_invoke +__55-[UZKArchive extractBufferedDataFromFile:error:action:]_block_invoke +__43-[UZKArchive performOnDataInArchive:error:]_block_invoke +__44-[UZKArchive performOnFilesInArchive:error:]_block_invoke +__49-[UZKArchive extractDataFromFile:progress:error:]_block_invoke +__os_log_helper_16_0_2_4_0_8_0 +__54-[UZKArchive extractFilesTo:overwrite:progress:error:]_block_invoke.170 +__54-[UZKArchive extractFilesTo:overwrite:progress:error:]_block_invoke +__27-[UZKArchive listFileInfo:]_block_invoke +__os_log_helper_16_2_3_4_66_4_66_4_66 +__24+[UZKArchive initialize]_block_invoke +__os_log_helper_16_2_1_4_64 +/Applications/Xcode-9.3.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.3.sdk/usr/include/dispatch/once.h ++[UZKFileInfo fileInfo:filename:] +-[UZKFileInfo initWithFileInfo:filename:] +-[UZKFileInfo timestamp] +-[UZKFileInfo readCompressionMethod:flag:] +-[UZKFileInfo readDate:] +-[UZKFileInfo filename] +-[UZKFileInfo CRC] +-[UZKFileInfo uncompressedSize] +-[UZKFileInfo compressedSize] +-[UZKFileInfo isEncryptedWithPassword] +-[UZKFileInfo isDirectory] +-[UZKFileInfo compressionMethod] +-[UZKFileInfo posixPermissions] +-[UZKFileInfo zipTMUDate] +-[UZKFileInfo setZipTMUDate:] +-[UZKFileInfo .cxx_destruct] +_OBJC_IVAR_$_UZKFileInfo._filename +_OBJC_IVAR_$_UZKFileInfo._uncompressedSize +_OBJC_IVAR_$_UZKFileInfo._compressedSize +_OBJC_IVAR_$_UZKFileInfo._zipTMUDate +_OBJC_IVAR_$_UZKFileInfo._CRC +_OBJC_IVAR_$_UZKFileInfo._isEncryptedWithPassword +_OBJC_IVAR_$_UZKFileInfo._isDirectory +_OBJC_IVAR_$_UZKFileInfo._compressionMethod +_OBJC_IVAR_$_UZKFileInfo._posixPermissions +_OBJC_IVAR_$_UZKFileInfo._timestamp +/Users/travis/build/abbeycode/UnzipKit/Source/UZKFileInfo.m +/Users/travis/build/abbeycode/UnzipKit/Source/UZKFileInfo.h +-[NSURL(UnzipKitExtensions) volumeName] +LOS_LOG1 +/Users/travis/build/abbeycode/UnzipKit/Source/Extensions/NSURL+UnzipKitExtensions.m +_fopen_file_func +_fread_file_func +_fwrite_file_func +_ftell_file_func +_fseek_file_func +_fclose_file_func +_ferror_file_func +_fopen64_file_func +_ftell64_file_func +_fseek64_file_func +/Users/travis/build/abbeycode/UnzipKit/Lib/MiniZip/ioapi.c +fseek64_file_func +ftell64_file_func +fopen64_file_func +fill_fopen64_filefunc +ferror_file_func +fclose_file_func +fseek_file_func +ftell_file_func +fwrite_file_func +fread_file_func +fopen_file_func +fill_fopen_filefunc +fill_zlib_filefunc64_32_def_from_filefunc32 +call_ztell64 +call_zseek64 +call_zopen64 +_unzOpenInternal +_unz64local_GetCurrentFileInfoInternal +_unz64local_getLong +_unz64local_getLong64 +_unz64local_getShort +/Users/travis/build/abbeycode/UnzipKit/Lib/MiniZip/unzip.c +unz64local_getShort +unz64local_getByte +unz64local_getLong64 +unz64local_getLong +unzSetOffset +unzSetOffset64 +unzGetOffset +unzGetOffset64 +unzGetGlobalComment +unzGetLocalExtrafield +unzeof +unztell64 +unztell +unzReadCurrentFile +update_keys +/Users/travis/build/abbeycode/UnzipKit/Lib/MiniZip/crypt.h +decrypt_byte +unzGetCurrentFileZStreamPos64 +unzOpenCurrentFile2 +unzOpenCurrentFilePassword +unzOpenCurrentFile +unzOpenCurrentFile3 +init_keys +unz64local_CheckCurrentFileCoherencyHeader +unzGoToFilePos +unzGoToFilePos64 +unzGetFilePos +unzGetFilePos64 +unzLocateFile +unzGetCurrentFileInfo64 +unzGoToFirstFile +unzGoToNextFile +unzGetCurrentFileInfo +unz64local_GetCurrentFileInfoInternal +unz64local_DosDateToTmuDate +unzGetGlobalInfo +unzGetGlobalInfo64 +unzCloseCurrentFile +unzClose +unzOpen64 +unzOpen +unzOpen2_64 +unzOpenInternal +unz64local_SearchCentralDir +unz64local_SearchCentralDir64 +unzOpen2 +unzStringFileNameCompare +strcmpcasenosensitive_internal +_zip64local_getLong +_zip64local_getLong64 +_zip64local_getShort +_add_data_in_datablock +_zip64FlushWriteBuffer +_init_keys +_update_keys +_crypthead.calls +/Users/travis/build/abbeycode/UnzipKit/Lib/MiniZip/zip.c +zipRemoveExtraInfoBlock +zipClose +free_linkedlist +free_datablock +zipCloseFileInZip +zipCloseFileInZipRaw +Write_GlobalComment +zip64local_putValue +Write_EndOfCentralDirectoryRecord +Write_Zip64EndOfCentralDirectoryRecord +Write_Zip64EndOfCentralDirectoryLocator +zipCloseFileInZipRaw64 +zip64local_putValue_inmemory +zip64FlushWriteBuffer +zipWriteInFileInZip +zipOpenNewFileInZip +zipOpenNewFileInZip64 +zipOpenNewFileInZip2_64 +zipOpenNewFileInZip2 +zipOpenNewFileInZip3_64 +zipOpenNewFileInZip3 +zipOpenNewFileInZip4 +zipOpenNewFileInZip4_64 +crypthead +zip64local_TmzDateToDosDate +Write_LocalFileHeader +zipOpen64 +zipOpen +zipOpen2_64 +zipOpen2 +zipOpen3 +init_linkedlist +add_data_in_datablock +allocate_new_datablock +zip64local_getShort +zip64local_getByte +zip64local_getLong64 +zip64local_getLong +LoadCentralDirectoryRecord +zip64local_SearchCentralDir +zip64local_SearchCentralDir64 diff --git a/Carthage/Build/iOS/61DBE496-1C13-3301-B76D-D92617470611.bcsymbolmap b/Carthage/Build/iOS/61DBE496-1C13-3301-B76D-D92617470611.bcsymbolmap new file mode 100644 index 0000000..c11f043 --- /dev/null +++ b/Carthage/Build/iOS/61DBE496-1C13-3301-B76D-D92617470611.bcsymbolmap @@ -0,0 +1,772 @@ +BCSymbolMap Version: 2.0 ++[UZKArchive zipArchiveAtPath:] ++[UZKArchive zipArchiveAtURL:] ++[UZKArchive zipArchiveAtPath:password:] ++[UZKArchive zipArchiveAtURL:password:] ++[UZKArchive initialize] +___24+[UZKArchive initialize]_block_invoke +-[UZKArchive init] +-[UZKArchive initWithPath:error:] +-[UZKArchive initWithURL:error:] +-[UZKArchive initWithPath:password:error:] +-[UZKArchive initWithURL:password:error:] +-[UZKArchive initWithFile:error:] +-[UZKArchive initWithFile:password:error:] +-[UZKArchive fileURL] +-[UZKArchive filename] +-[UZKArchive comment] +-[UZKArchive setComment:] ++[UZKArchive pathIsAZip:] ++[UZKArchive urlIsAZip:] +-[UZKArchive listFilenames:] +-[UZKArchive listFileInfo:] +___27-[UZKArchive listFileInfo:]_block_invoke +___copy_helper_block_ +___destroy_helper_block_ +-[UZKArchive extractFilesTo:overwrite:error:] +-[UZKArchive extractFilesTo:overwrite:progress:error:] +___54-[UZKArchive extractFilesTo:overwrite:progress:error:]_block_invoke +___54-[UZKArchive extractFilesTo:overwrite:progress:error:]_block_invoke.170 +___copy_helper_block_.173 +___destroy_helper_block_.174 +___copy_helper_block_.207 +___destroy_helper_block_.208 +-[UZKArchive extractData:error:] +-[UZKArchive extractData:progress:error:] +-[UZKArchive extractDataFromFile:error:] +-[UZKArchive extractDataFromFile:progress:error:] +___49-[UZKArchive extractDataFromFile:progress:error:]_block_invoke +___copy_helper_block_.219 +___destroy_helper_block_.220 +-[UZKArchive performOnFilesInArchive:error:] +___44-[UZKArchive performOnFilesInArchive:error:]_block_invoke +___copy_helper_block_.237 +___destroy_helper_block_.238 +-[UZKArchive performOnDataInArchive:error:] +___43-[UZKArchive performOnDataInArchive:error:]_block_invoke +___copy_helper_block_.248 +___destroy_helper_block_.249 +-[UZKArchive extractBufferedDataFromFile:error:action:] +___55-[UZKArchive extractBufferedDataFromFile:error:action:]_block_invoke +___copy_helper_block_.270 +___destroy_helper_block_.271 +-[UZKArchive isPasswordProtected] +-[UZKArchive validatePassword] +___30-[UZKArchive validatePassword]_block_invoke +-[UZKArchive checkDataIntegrity] +-[UZKArchive checkDataIntegrityOfFile:] +___39-[UZKArchive checkDataIntegrityOfFile:]_block_invoke +___copy_helper_block_.296 +___destroy_helper_block_.297 +-[UZKArchive writeData:filePath:error:] +-[UZKArchive writeData:filePath:progress:error:] +-[UZKArchive writeData:filePath:fileDate:error:] +-[UZKArchive writeData:filePath:fileDate:progress:error:] +-[UZKArchive writeData:filePath:fileDate:compressionMethod:password:error:] +-[UZKArchive writeData:filePath:fileDate:compressionMethod:password:progress:error:] +-[UZKArchive writeData:filePath:fileDate:compressionMethod:password:overwrite:error:] +-[UZKArchive writeData:filePath:fileDate:compressionMethod:password:overwrite:progress:error:] +-[UZKArchive writeData:filePath:fileDate:posixPermissions:compressionMethod:password:overwrite:error:] +-[UZKArchive writeData:filePath:fileDate:posixPermissions:compressionMethod:password:overwrite:progress:error:] +___111-[UZKArchive writeData:filePath:fileDate:posixPermissions:compressionMethod:password:overwrite:progress:error:]_block_invoke +___copy_helper_block_.318 +___destroy_helper_block_.319 +-[UZKArchive writeIntoBuffer:error:block:] +-[UZKArchive writeIntoBuffer:fileDate:error:block:] +-[UZKArchive writeIntoBuffer:fileDate:compressionMethod:error:block:] +-[UZKArchive writeIntoBuffer:fileDate:compressionMethod:overwrite:error:block:] +-[UZKArchive writeIntoBuffer:fileDate:compressionMethod:overwrite:CRC:error:block:] +-[UZKArchive writeIntoBuffer:fileDate:compressionMethod:overwrite:CRC:password:error:block:] +-[UZKArchive writeIntoBuffer:fileDate:posixPermissions:compressionMethod:overwrite:CRC:password:error:block:] +___109-[UZKArchive writeIntoBuffer:fileDate:posixPermissions:compressionMethod:overwrite:CRC:password:error:block:]_block_invoke +___109-[UZKArchive writeIntoBuffer:fileDate:posixPermissions:compressionMethod:overwrite:CRC:password:error:block:]_block_invoke.326 +___copy_helper_block_.327 +___destroy_helper_block_.328 +___copy_helper_block_.337 +___destroy_helper_block_.338 +-[UZKArchive deleteFile:error:] +-[UZKArchive performActionWithArchiveOpen:inMode:error:] +-[UZKArchive performWriteAction:filePath:fileDate:posixPermissions:compressionMethod:password:overwrite:CRC:error:] +___115-[UZKArchive performWriteAction:filePath:fileDate:posixPermissions:compressionMethod:password:overwrite:CRC:error:]_block_invoke +___copy_helper_block_.414 +___destroy_helper_block_.415 +___115-[UZKArchive performWriteAction:filePath:fileDate:posixPermissions:compressionMethod:password:overwrite:CRC:error:]_block_invoke.424 +___copy_helper_block_.435 +___destroy_helper_block_.436 +-[UZKArchive openFile:inMode:withPassword:error:] +-[UZKArchive closeFile:inMode:] +-[UZKArchive currentFileInZipInfo:] +-[UZKArchive locateFileInZip:error:] +-[UZKArchive openFile:] +-[UZKArchive readFile:length:error:] +-[UZKArchive readGlobalComment] +___Block_byref_object_copy_ +___Block_byref_object_dispose_ +___31-[UZKArchive readGlobalComment]_block_invoke +___copy_helper_block_.522 +___destroy_helper_block_.523 +-[UZKArchive storeFileBookmark:error:] ++[UZKArchive figureOutCString:] ++[UZKArchive errorNameForErrorCode:] ++[UZKArchive zipFileInfoForDate:posixPermissions:] +-[UZKArchive assignError:code:detail:] +-[UZKArchive assignError:code:detail:underlyer:] +-[UZKArchive isDeflate64:] +-[UZKArchive beginProgressOperation:] +-[UZKArchive password] +-[UZKArchive setPassword:] +-[UZKArchive progress] +-[UZKArchive setProgress:] +-[UZKArchive fileBookmark] +-[UZKArchive setFileBookmark:] +-[UZKArchive fallbackURL] +-[UZKArchive setFallbackURL:] +-[UZKArchive openCount] +-[UZKArchive setOpenCount:] +-[UZKArchive mode] +-[UZKArchive setMode:] +-[UZKArchive zipFile] +-[UZKArchive setZipFile:] +-[UZKArchive unzFile] +-[UZKArchive setUnzFile:] +-[UZKArchive archiveContents] +-[UZKArchive setArchiveContents:] +-[UZKArchive threadLock] +-[UZKArchive setThreadLock:] +-[UZKArchive commentRetrieved] +-[UZKArchive setCommentRetrieved:] +-[UZKArchive .cxx_destruct] +__resources +_initialize.onceToken +___block_descriptor_tmp +___block_literal_global +LOS_LOG0 +LOS_ACT1 +LOS_LOG3 +LOS_LOG4 +LOS_LOG5 +LOS_LOG6 +LOS_LOG7 +LOS_LOG8 +LOS_LOG9 +_OBJC_IVAR_$_UZKArchive._openCount +_OBJC_IVAR_$_UZKArchive._mode +_OBJC_IVAR_$_UZKArchive._fallbackURL +_OBJC_IVAR_$_UZKArchive._password +_OBJC_IVAR_$_UZKArchive._threadLock +_OBJC_IVAR_$_UZKArchive._commentRetrieved +LOS_ACT10 +LOS_LOG12 +LOS_LOG13 +LOS_LOG14 +LOS_LOG15 +LOS_LOG16 +LOS_LOG17 +LOS_LOG18 +LOS_LOG19 +LOS_LOG20 +LOS_ACT21 +LOS_ACT23 +LOS_LOG25 +_OBJC_IVAR_$_UZKArchive._comment +LOS_ACT26 +LOS_LOG28 +LOS_LOG29 +LOS_LOG30 +LOS_ACT31 +LOS_LOG33 +LOS_LOG34 +LOS_LOG35 +LOS_LOG36 +LOS_LOG37 +LOS_LOG38 +LOS_LOG39 +LOS_LOG40 +LOS_ACT41 +LOS_LOG43 +LOS_ACT44 +LOS_LOG46 +LOS_ACT47 +LOS_LOG49 +LOS_LOG50 +LOS_ACT51 +LOS_LOG53 +LOS_LOG54 +LOS_LOG55 +LOS_LOG56 +LOS_LOG57 +LOS_LOG58 +LOS_LOG59 +LOS_LOG60 +LOS_LOG61 +LOS_LOG62 +LOS_LOG63 +LOS_LOG64 +LOS_LOG65 +LOS_LOG66 +___block_descriptor_tmp.122 +LOS_ACT67 +LOS_LOG69 +LOS_LOG70 +LOS_LOG71 +LOS_ACT72 +LOS_LOG74 +LOS_LOG75 +LOS_LOG76 +LOS_LOG77 +LOS_LOG78 +LOS_LOG79 +LOS_LOG80 +LOS_LOG81 +LOS_LOG82 +LOS_LOG83 +LOS_LOG84 +LOS_LOG85 +LOS_LOG86 +LOS_LOG87 +LOS_LOG88 +LOS_LOG89 +LOS_LOG90 +LOS_LOG91 +LOS_LOG92 +___block_descriptor_tmp.176 +LOS_LOG93 +LOS_LOG94 +LOS_LOG95 +LOS_LOG96 +___block_descriptor_tmp.209 +LOS_ACT97 +LOS_LOG99 +LOS_LOG100 +___block_descriptor_tmp.221 +LOS_LOG101 +LOS_LOG102 +LOS_LOG103 +LOS_ACT104 +LOS_LOG106 +LOS_LOG107 +LOS_LOG108 +LOS_LOG109 +LOS_ACT110 +LOS_LOG112 +LOS_LOG113 +LOS_LOG114 +___block_descriptor_tmp.239 +LOS_LOG115 +LOS_LOG116 +LOS_ACT117 +LOS_LOG119 +LOS_LOG120 +LOS_LOG121 +LOS_LOG122 +LOS_LOG123 +LOS_LOG124 +LOS_LOG125 +___block_descriptor_tmp.251 +LOS_ACT126 +LOS_LOG128 +LOS_LOG129 +LOS_LOG130 +LOS_LOG131 +LOS_LOG132 +LOS_LOG133 +LOS_LOG134 +LOS_LOG135 +LOS_LOG136 +LOS_LOG137 +LOS_LOG138 +LOS_LOG139 +LOS_LOG140 +LOS_LOG141 +LOS_LOG142 +LOS_LOG143 +LOS_LOG144 +LOS_LOG145 +___block_descriptor_tmp.272 +LOS_LOG146 +LOS_LOG147 +LOS_ACT148 +LOS_LOG150 +LOS_LOG151 +LOS_LOG152 +LOS_LOG153 +LOS_ACT154 +LOS_LOG156 +LOS_LOG157 +LOS_LOG158 +LOS_LOG159 +___block_descriptor_tmp.280 +___block_literal_global.281 +LOS_LOG160 +LOS_LOG161 +LOS_ACT162 +LOS_LOG164 +LOS_LOG165 +LOS_LOG166 +LOS_LOG167 +___block_descriptor_tmp.299 +LOS_LOG168 +LOS_LOG169 +LOS_ACT170 +LOS_LOG172 +LOS_LOG173 +LOS_LOG174 +LOS_ACT175 +LOS_LOG177 +LOS_LOG178 +LOS_LOG179 +LOS_LOG180 +LOS_LOG181 +___block_descriptor_tmp.321 +LOS_ACT182 +LOS_LOG184 +LOS_ACT185 +LOS_LOG187 +LOS_LOG188 +LOS_LOG189 +LOS_LOG190 +LOS_LOG191 +___block_descriptor_tmp.330 +LOS_LOG192 +LOS_LOG193 +___block_descriptor_tmp.339 +LOS_ACT194 +LOS_LOG196 +LOS_LOG197 +LOS_LOG198 +LOS_LOG199 +LOS_LOG200 +LOS_LOG201 +LOS_LOG202 +LOS_LOG203 +LOS_LOG204 +LOS_LOG205 +LOS_LOG206 +LOS_LOG207 +LOS_LOG208 +LOS_LOG209 +LOS_LOG210 +LOS_LOG211 +LOS_LOG212 +LOS_LOG213 +LOS_LOG214 +LOS_LOG215 +LOS_LOG216 +LOS_LOG217 +LOS_LOG218 +LOS_LOG219 +LOS_LOG220 +LOS_LOG221 +LOS_LOG222 +LOS_LOG223 +LOS_LOG224 +LOS_LOG225 +LOS_LOG226 +LOS_LOG227 +LOS_LOG228 +LOS_LOG229 +LOS_LOG230 +LOS_LOG231 +LOS_LOG232 +LOS_LOG233 +LOS_LOG234 +LOS_LOG235 +LOS_LOG236 +LOS_LOG237 +LOS_LOG238 +LOS_LOG239 +LOS_LOG240 +LOS_LOG241 +LOS_LOG242 +LOS_LOG243 +LOS_LOG244 +LOS_LOG245 +LOS_LOG246 +LOS_LOG247 +LOS_LOG248 +LOS_LOG249 +LOS_LOG250 +LOS_LOG251 +LOS_LOG252 +LOS_LOG253 +LOS_LOG254 +LOS_LOG255 +LOS_LOG256 +LOS_LOG257 +LOS_LOG258 +LOS_LOG259 +LOS_LOG260 +LOS_LOG261 +LOS_LOG262 +LOS_LOG263 +LOS_LOG264 +LOS_LOG265 +LOS_LOG266 +LOS_LOG267 +LOS_LOG268 +LOS_LOG269 +LOS_LOG270 +LOS_LOG271 +LOS_LOG272 +LOS_LOG273 +LOS_LOG274 +LOS_LOG275 +LOS_LOG276 +LOS_LOG277 +LOS_LOG278 +LOS_LOG279 +LOS_LOG280 +LOS_LOG281 +LOS_LOG282 +LOS_LOG283 +LOS_LOG284 +LOS_LOG285 +LOS_LOG286 +LOS_LOG287 +LOS_LOG288 +LOS_LOG289 +LOS_LOG290 +LOS_LOG291 +LOS_LOG292 +LOS_LOG293 +LOS_LOG294 +LOS_LOG295 +LOS_LOG296 +LOS_LOG297 +LOS_LOG298 +LOS_ACT299 +LOS_LOG301 +LOS_LOG302 +LOS_LOG303 +LOS_ACT304 +LOS_LOG306 +LOS_LOG307 +LOS_LOG308 +___block_descriptor_tmp.417 +LOS_LOG309 +LOS_LOG310 +LOS_LOG311 +LOS_ACT312 +LOS_LOG314 +LOS_LOG315 +LOS_LOG316 +LOS_LOG317 +LOS_LOG318 +LOS_LOG319 +LOS_LOG320 +LOS_LOG321 +LOS_LOG322 +LOS_LOG323 +LOS_LOG324 +___block_descriptor_tmp.437 +LOS_ACT325 +LOS_LOG327 +LOS_LOG328 +LOS_LOG329 +LOS_LOG330 +LOS_LOG331 +LOS_LOG332 +LOS_LOG333 +LOS_LOG334 +LOS_LOG335 +LOS_LOG336 +LOS_LOG337 +LOS_LOG338 +LOS_LOG339 +LOS_LOG340 +LOS_LOG341 +LOS_LOG342 +LOS_LOG343 +LOS_LOG344 +LOS_LOG345 +LOS_LOG346 +LOS_LOG347 +LOS_LOG348 +LOS_LOG349 +LOS_LOG350 +LOS_LOG351 +LOS_LOG352 +LOS_LOG353 +LOS_LOG354 +LOS_ACT355 +LOS_LOG357 +LOS_LOG358 +LOS_LOG359 +LOS_LOG360 +LOS_LOG361 +LOS_LOG362 +LOS_LOG363 +LOS_LOG364 +LOS_LOG365 +LOS_LOG366 +LOS_ACT367 +LOS_LOG369 +LOS_LOG370 +LOS_LOG371 +LOS_ACT372 +LOS_LOG374 +LOS_LOG375 +LOS_LOG376 +LOS_LOG377 +LOS_LOG378 +LOS_LOG379 +LOS_LOG380 +LOS_LOG381 +LOS_ACT382 +LOS_LOG384 +LOS_LOG385 +LOS_LOG386 +LOS_LOG387 +LOS_LOG388 +LOS_LOG389 +LOS_LOG390 +LOS_LOG391 +LOS_LOG392 +LOS_ACT393 +LOS_LOG395 +LOS_LOG396 +LOS_LOG397 +LOS_LOG398 +LOS_LOG399 +LOS_ACT400 +LOS_LOG402 +LOS_LOG403 +LOS_ACT404 +LOS_LOG406 +LOS_LOG407 +LOS_LOG408 +LOS_LOG409 +LOS_LOG410 +LOS_LOG411 +LOS_LOG412 +LOS_LOG413 +LOS_LOG414 +LOS_LOG415 +LOS_LOG416 +LOS_LOG417 +LOS_LOG418 +___block_descriptor_tmp.524 +LOS_ACT419 +LOS_LOG421 +LOS_LOG422 +LOS_LOG423 +LOS_ACT424 +LOS_LOG426 +LOS_LOG427 +LOS_LOG428 +LOS_LOG429 +LOS_ACT430 +LOS_LOG432 +LOS_ACT433 +_OBJC_IVAR_$_UZKArchive._progress +_OBJC_IVAR_$_UZKArchive._fileBookmark +_OBJC_IVAR_$_UZKArchive._zipFile +_OBJC_IVAR_$_UZKArchive._unzFile +_OBJC_IVAR_$_UZKArchive._archiveContents +l_OBJC_PROTOCOL_$_NSObject +l_OBJC_LABEL_PROTOCOL_$_NSObject +l_OBJC_PROTOCOL_$_NSProgressReporting +l_OBJC_LABEL_PROTOCOL_$_NSProgressReporting +Apple LLVM version 9.1.0 (clang-902.0.39.1) +/Users/travis/build/abbeycode/UnzipKit/Source/UZKArchive.m +/Users/travis/build/abbeycode/UnzipKit +/Users/travis/build/abbeycode/UnzipKit/Source/UZKArchive.h +__os_log_helper_16_0_1_8_0 +__os_log_helper_16_0_0 +__os_log_helper_16_2_2_8_66_8_66 +__destroy_helper_block_ +__copy_helper_block_ +__31-[UZKArchive readGlobalComment]_block_invoke +__os_log_helper_16_2_1_8_66 +__Block_byref_object_dispose_ +__Block_byref_object_copy_ +__os_log_helper_16_0_2_4_0_4_0 +__os_log_helper_16_2_2_4_0_8_66 +__os_log_helper_16_2_2_8_34_8_34 +__os_log_helper_16_0_2_8_0_8_0 +__115-[UZKArchive performWriteAction:filePath:fileDate:posixPermissions:compressionMethod:password:overwrite:CRC:error:]_block_invoke.424 +__115-[UZKArchive performWriteAction:filePath:fileDate:posixPermissions:compressionMethod:password:overwrite:CRC:error:]_block_invoke +__os_log_helper_16_2_1_8_34 +__109-[UZKArchive writeIntoBuffer:fileDate:posixPermissions:compressionMethod:overwrite:CRC:password:error:block:]_block_invoke.326 +__os_log_helper_16_0_1_4_0 +__109-[UZKArchive writeIntoBuffer:fileDate:posixPermissions:compressionMethod:overwrite:CRC:password:error:block:]_block_invoke +__os_log_helper_16_2_7_8_66_8_0_8_0_8_66_8_0_8_66_8_66 +__111-[UZKArchive writeData:filePath:fileDate:posixPermissions:compressionMethod:password:overwrite:progress:error:]_block_invoke +__os_log_helper_16_2_7_8_66_8_0_8_0_8_66_8_66_8_66_8_66 +__39-[UZKArchive checkDataIntegrityOfFile:]_block_invoke +__os_log_helper_16_2_3_8_66_8_0_8_0 +__30-[UZKArchive validatePassword]_block_invoke +__55-[UZKArchive extractBufferedDataFromFile:error:action:]_block_invoke +__43-[UZKArchive performOnDataInArchive:error:]_block_invoke +__44-[UZKArchive performOnFilesInArchive:error:]_block_invoke +__49-[UZKArchive extractDataFromFile:progress:error:]_block_invoke +__os_log_helper_16_2_2_8_0_8_66 +__54-[UZKArchive extractFilesTo:overwrite:progress:error:]_block_invoke.170 +__54-[UZKArchive extractFilesTo:overwrite:progress:error:]_block_invoke +__27-[UZKArchive listFileInfo:]_block_invoke +__os_log_helper_16_2_3_8_66_8_66_8_66 +__24+[UZKArchive initialize]_block_invoke +__os_log_helper_16_2_1_8_64 +/Applications/Xcode-9.3.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.3.sdk/usr/include/dispatch/once.h ++[UZKFileInfo fileInfo:filename:] +-[UZKFileInfo initWithFileInfo:filename:] +-[UZKFileInfo timestamp] +-[UZKFileInfo readCompressionMethod:flag:] +-[UZKFileInfo readDate:] +-[UZKFileInfo filename] +-[UZKFileInfo CRC] +-[UZKFileInfo uncompressedSize] +-[UZKFileInfo compressedSize] +-[UZKFileInfo isEncryptedWithPassword] +-[UZKFileInfo isDirectory] +-[UZKFileInfo compressionMethod] +-[UZKFileInfo posixPermissions] +-[UZKFileInfo zipTMUDate] +-[UZKFileInfo setZipTMUDate:] +-[UZKFileInfo .cxx_destruct] +_OBJC_IVAR_$_UZKFileInfo._filename +_OBJC_IVAR_$_UZKFileInfo._uncompressedSize +_OBJC_IVAR_$_UZKFileInfo._compressedSize +_OBJC_IVAR_$_UZKFileInfo._zipTMUDate +_OBJC_IVAR_$_UZKFileInfo._CRC +_OBJC_IVAR_$_UZKFileInfo._isEncryptedWithPassword +_OBJC_IVAR_$_UZKFileInfo._isDirectory +_OBJC_IVAR_$_UZKFileInfo._compressionMethod +_OBJC_IVAR_$_UZKFileInfo._posixPermissions +_OBJC_IVAR_$_UZKFileInfo._timestamp +/Users/travis/build/abbeycode/UnzipKit/Source/UZKFileInfo.m +/Users/travis/build/abbeycode/UnzipKit/Source/UZKFileInfo.h +-[NSURL(UnzipKitExtensions) volumeName] +LOS_LOG1 +/Users/travis/build/abbeycode/UnzipKit/Source/Extensions/NSURL+UnzipKitExtensions.m +_fopen_file_func +_fread_file_func +_fwrite_file_func +_ftell_file_func +_fseek_file_func +_fclose_file_func +_ferror_file_func +_fopen64_file_func +_ftell64_file_func +_fseek64_file_func +/Users/travis/build/abbeycode/UnzipKit/Lib/MiniZip/ioapi.c +fseek64_file_func +ftell64_file_func +fopen64_file_func +fill_fopen64_filefunc +ferror_file_func +fclose_file_func +fseek_file_func +ftell_file_func +fwrite_file_func +fread_file_func +fopen_file_func +fill_fopen_filefunc +fill_zlib_filefunc64_32_def_from_filefunc32 +call_ztell64 +call_zseek64 +call_zopen64 +_unzOpenInternal +_unz64local_GetCurrentFileInfoInternal +_unz64local_getLong +_unz64local_getLong64 +_unz64local_getShort +/Users/travis/build/abbeycode/UnzipKit/Lib/MiniZip/unzip.c +unz64local_getShort +unz64local_getByte +unz64local_getLong64 +unz64local_getLong +unzSetOffset +unzSetOffset64 +unzGetOffset +unzGetOffset64 +unzGetGlobalComment +unzGetLocalExtrafield +unzeof +unztell64 +unztell +unzReadCurrentFile +update_keys +/Users/travis/build/abbeycode/UnzipKit/Lib/MiniZip/crypt.h +decrypt_byte +unzGetCurrentFileZStreamPos64 +unzOpenCurrentFile2 +unzOpenCurrentFilePassword +unzOpenCurrentFile +unzOpenCurrentFile3 +init_keys +unz64local_CheckCurrentFileCoherencyHeader +unzGoToFilePos +unzGoToFilePos64 +unzGetFilePos +unzGetFilePos64 +unzLocateFile +unzGetCurrentFileInfo64 +unzGoToFirstFile +unzGoToNextFile +unzGetCurrentFileInfo +unz64local_GetCurrentFileInfoInternal +unz64local_DosDateToTmuDate +unzGetGlobalInfo +unzGetGlobalInfo64 +unzCloseCurrentFile +unzClose +unzOpen64 +unzOpen +unzOpen2_64 +unzOpenInternal +unz64local_SearchCentralDir +unz64local_SearchCentralDir64 +unzOpen2 +unzStringFileNameCompare +strcmpcasenosensitive_internal +_zip64local_getLong +_zip64local_getLong64 +_zip64local_getShort +_add_data_in_datablock +_zip64FlushWriteBuffer +_init_keys +_update_keys +_crypthead.calls +/Users/travis/build/abbeycode/UnzipKit/Lib/MiniZip/zip.c +zipRemoveExtraInfoBlock +zipClose +free_linkedlist +free_datablock +zipCloseFileInZip +zipCloseFileInZipRaw +Write_GlobalComment +zip64local_putValue +Write_EndOfCentralDirectoryRecord +Write_Zip64EndOfCentralDirectoryRecord +Write_Zip64EndOfCentralDirectoryLocator +zipCloseFileInZipRaw64 +zip64local_putValue_inmemory +zip64FlushWriteBuffer +zipWriteInFileInZip +zipOpenNewFileInZip +zipOpenNewFileInZip64 +zipOpenNewFileInZip2_64 +zipOpenNewFileInZip2 +zipOpenNewFileInZip3_64 +zipOpenNewFileInZip3 +zipOpenNewFileInZip4 +zipOpenNewFileInZip4_64 +crypthead +zip64local_TmzDateToDosDate +Write_LocalFileHeader +zipOpen64 +zipOpen +zipOpen2_64 +zipOpen2 +zipOpen3 +init_linkedlist +add_data_in_datablock +allocate_new_datablock +zip64local_getShort +zip64local_getByte +zip64local_getLong64 +zip64local_getLong +LoadCentralDirectoryRecord +zip64local_SearchCentralDir +zip64local_SearchCentralDir64 diff --git a/Carthage/Build/iOS/DB023541-A06E-3431-B577-7DF9E839AD04.bcsymbolmap b/Carthage/Build/iOS/DB023541-A06E-3431-B577-7DF9E839AD04.bcsymbolmap new file mode 100644 index 0000000..847be97 --- /dev/null +++ b/Carthage/Build/iOS/DB023541-A06E-3431-B577-7DF9E839AD04.bcsymbolmap @@ -0,0 +1,1236 @@ +BCSymbolMap Version: 2.0 ++[URKFileInfo fileInfo:] +-[URKFileInfo initWithFileHeader:] +-[URKFileInfo parseDOSDate:] +-[URKFileInfo archiveName] +-[URKFileInfo filename] +-[URKFileInfo timestamp] +-[URKFileInfo CRC] +-[URKFileInfo uncompressedSize] +-[URKFileInfo compressedSize] +-[URKFileInfo isEncryptedWithPassword] +-[URKFileInfo isDirectory] +-[URKFileInfo compressionMethod] +-[URKFileInfo hostOS] +-[URKFileInfo .cxx_destruct] +LOS_ACT0 +LOS_LOG2 +_OBJC_IVAR_$_URKFileInfo._filename +_OBJC_IVAR_$_URKFileInfo._archiveName +_OBJC_IVAR_$_URKFileInfo._uncompressedSize +_OBJC_IVAR_$_URKFileInfo._compressedSize +_OBJC_IVAR_$_URKFileInfo._compressionMethod +_OBJC_IVAR_$_URKFileInfo._hostOS +_OBJC_IVAR_$_URKFileInfo._timestamp +_OBJC_IVAR_$_URKFileInfo._CRC +_OBJC_IVAR_$_URKFileInfo._isEncryptedWithPassword +_OBJC_IVAR_$_URKFileInfo._isDirectory +LOS_ACT3 +LOS_LOG5 +Apple LLVM version 9.1.0 (clang-902.0.39.1) +/Users/travis/build/abbeycode/UnrarKit/Classes/URKFileInfo.m +/Users/travis/build/abbeycode/UnrarKit +/Users/travis/build/abbeycode/UnrarKit/Classes/URKFileInfo.h +__os_log_helper_16_0_0 ++[NSString(UnrarKit) stringWithUnichars:] +/Users/travis/build/abbeycode/UnrarKit/Classes/Categories/NSString+UnrarKit.mm ++[URKArchive rarArchiveAtPath:] ++[URKArchive rarArchiveAtURL:] ++[URKArchive rarArchiveAtPath:password:] ++[URKArchive rarArchiveAtURL:password:] ++[URKArchive initialize] +___24+[URKArchive initialize]_block_invoke +-[URKArchive init] +-[URKArchive initWithPath:error:] +-[URKArchive initWithURL:error:] +-[URKArchive initWithPath:password:error:] +-[URKArchive initWithURL:password:error:] +-[URKArchive initWithFile:error:] +-[URKArchive initWithFile:password:error:] +___clang_call_terminate +-[URKArchive fileURL] +-[URKArchive filename] +-[URKArchive uncompressedSize] +-[URKArchive compressedSize] +-[URKArchive hasMultipleVolumes] ++[URKArchive pathIsARAR:] ++[URKArchive urlIsARAR:] +-[URKArchive listFilenames:] +-[URKArchive listFileInfo:] +___27-[URKArchive listFileInfo:]_block_invoke +___copy_helper_block_ +___destroy_helper_block_ +-[URKArchive iterateFileInfo:error:] +-[URKArchive listVolumeURLs:] +-[URKArchive extractFilesTo:overwrite:error:] +-[URKArchive extractFilesTo:overwrite:progress:error:] +___54-[URKArchive extractFilesTo:overwrite:progress:error:]_block_invoke +___54-[URKArchive extractFilesTo:overwrite:progress:error:]_block_invoke.171 +___copy_helper_block_.172 +___destroy_helper_block_.173 +___copy_helper_block_.188 +___destroy_helper_block_.189 +-[URKArchive extractData:error:] +-[URKArchive extractData:progress:error:] +-[URKArchive extractDataFromFile:error:] +-[URKArchive extractDataFromFile:progress:error:] +___Block_byref_object_copy_ +___Block_byref_object_dispose_ +___49-[URKArchive extractDataFromFile:progress:error:]_block_invoke +___49-[URKArchive extractDataFromFile:progress:error:]_block_invoke.204 +___copy_helper_block_.207 +___destroy_helper_block_.208 +___copy_helper_block_.213 +___destroy_helper_block_.214 +-[URKArchive performOnFilesInArchive:error:] +___44-[URKArchive performOnFilesInArchive:error:]_block_invoke +___copy_helper_block_.218 +___destroy_helper_block_.219 +-[URKArchive performOnDataInArchive:error:] +___43-[URKArchive performOnDataInArchive:error:]_block_invoke +___copy_helper_block_.226 +___destroy_helper_block_.227 +-[URKArchive extractBufferedDataFromFile:error:action:] +___55-[URKArchive extractBufferedDataFromFile:error:action:]_block_invoke +___55-[URKArchive extractBufferedDataFromFile:error:action:]_block_invoke.229 +___copy_helper_block_.230 +___destroy_helper_block_.231 +___copy_helper_block_.233 +___destroy_helper_block_.234 +-[URKArchive isPasswordProtected] +-[URKArchive validatePassword] +___30-[URKArchive validatePassword]_block_invoke +___copy_helper_block_.240 +___destroy_helper_block_.241 +-[URKArchive checkDataIntegrity] +-[URKArchive checkDataIntegrityOfFile:] +___39-[URKArchive checkDataIntegrityOfFile:]_block_invoke +___copy_helper_block_.251 +___destroy_helper_block_.252 +-[URKArchive performActionWithArchiveOpen:inMode:error:] +-[URKArchive _unrarOpenFile:inMode:withPassword:error:] +-[URKArchive closeFile] +-[URKArchive iterateAllFileInfo:error:] +___39-[URKArchive iterateAllFileInfo:error:]_block_invoke +___copy_helper_block_.272 +___destroy_helper_block_.273 +-[URKArchive allFileInfo:] +___26-[URKArchive allFileInfo:]_block_invoke +___copy_helper_block_.275 +___destroy_helper_block_.276 +-[URKArchive errorNameForErrorCode:detail:] +-[URKArchive assignError:code:errorName:] +-[URKArchive assignError:code:underlyer:errorName:] +-[URKArchive headerContainsErrors:] +-[URKArchive beginProgressOperation:] ++[URKArchive firstVolumeURL:] +-[URKArchive password] +-[URKArchive setPassword:] +-[URKArchive progress] +-[URKArchive setProgress:] +-[URKArchive rarFile] +-[URKArchive setRarFile:] +-[URKArchive header] +-[URKArchive setHeader:] +-[URKArchive flags] +-[URKArchive setFlags:] +-[URKArchive fileBookmark] +-[URKArchive setFileBookmark:] +-[URKArchive threadLock] +-[URKArchive setThreadLock:] +-[URKArchive .cxx_destruct] +__ZL10_resources +__ZZ24+[URKArchive initialize]E9onceToken +___block_descriptor_tmp +___block_literal_global +LOS_LOG0 +LOS_LOG1 +LOS_LOG6 +LOS_LOG7 +LOS_LOG8 +LOS_LOG9 +_OBJC_IVAR_$_URKArchive._fileBookmark +_OBJC_IVAR_$_URKArchive._password +_OBJC_IVAR_$_URKArchive._threadLock +LOS_LOG10 +LOS_LOG11 +LOS_ACT12 +LOS_LOG14 +LOS_LOG15 +LOS_LOG16 +LOS_LOG17 +LOS_LOG18 +LOS_ACT19 +LOS_ACT21 +LOS_LOG23 +LOS_LOG24 +LOS_LOG25 +LOS_ACT26 +LOS_LOG28 +LOS_LOG29 +LOS_LOG30 +LOS_LOG31 +LOS_LOG32 +LOS_ACT33 +LOS_LOG35 +LOS_LOG36 +LOS_ACT37 +LOS_LOG39 +LOS_LOG40 +LOS_LOG41 +LOS_LOG42 +LOS_LOG43 +LOS_LOG44 +LOS_LOG45 +LOS_ACT46 +LOS_LOG48 +LOS_ACT49 +LOS_ACT51 +LOS_LOG53 +___block_descriptor_tmp.121 +LOS_LOG54 +LOS_LOG55 +LOS_LOG56 +LOS_ACT57 +LOS_LOG59 +LOS_LOG60 +LOS_LOG61 +LOS_ACT62 +LOS_ACT64 +LOS_LOG66 +LOS_LOG67 +LOS_LOG68 +LOS_ACT69 +LOS_LOG71 +LOS_LOG72 +LOS_LOG73 +LOS_LOG74 +LOS_LOG75 +LOS_LOG76 +LOS_LOG77 +LOS_LOG78 +LOS_ACT79 +LOS_LOG81 +___block_descriptor_tmp.175 +LOS_LOG82 +LOS_LOG83 +LOS_LOG84 +LOS_LOG85 +LOS_LOG86 +___block_descriptor_tmp.191 +LOS_ACT87 +LOS_ACT89 +LOS_LOG91 +LOS_LOG92 +LOS_LOG93 +LOS_LOG94 +LOS_LOG95 +LOS_LOG96 +LOS_LOG97 +LOS_LOG98 +LOS_LOG99 +LOS_LOG100 +LOS_LOG101 +LOS_LOG102 +___block_descriptor_tmp.210 +LOS_LOG103 +LOS_LOG104 +LOS_LOG105 +LOS_LOG106 +___block_descriptor_tmp.215 +LOS_ACT107 +LOS_LOG109 +LOS_LOG110 +LOS_LOG111 +LOS_LOG112 +LOS_ACT113 +LOS_LOG115 +LOS_LOG116 +LOS_LOG117 +___block_descriptor_tmp.221 +LOS_ACT118 +LOS_LOG120 +LOS_LOG121 +LOS_LOG122 +LOS_LOG123 +LOS_LOG124 +LOS_LOG125 +LOS_LOG126 +LOS_LOG127 +LOS_LOG128 +LOS_LOG129 +LOS_LOG130 +LOS_LOG131 +LOS_LOG132 +LOS_LOG133 +LOS_LOG134 +___block_descriptor_tmp.228 +LOS_ACT135 +LOS_ACT137 +LOS_LOG139 +LOS_LOG140 +LOS_LOG141 +LOS_LOG142 +LOS_LOG143 +LOS_LOG144 +LOS_LOG145 +LOS_LOG146 +LOS_LOG147 +LOS_LOG148 +LOS_LOG149 +LOS_LOG150 +LOS_LOG151 +___block_descriptor_tmp.232 +LOS_LOG152 +LOS_LOG153 +LOS_LOG154 +LOS_LOG155 +LOS_LOG156 +___block_descriptor_tmp.235 +LOS_LOG157 +LOS_LOG158 +LOS_ACT159 +LOS_LOG161 +LOS_LOG162 +LOS_LOG163 +LOS_LOG164 +LOS_LOG165 +LOS_LOG166 +LOS_LOG167 +LOS_LOG168 +LOS_LOG169 +LOS_LOG170 +LOS_ACT171 +LOS_ACT173 +LOS_LOG175 +LOS_LOG176 +LOS_LOG177 +LOS_LOG178 +LOS_LOG179 +___block_descriptor_tmp.242 +LOS_LOG180 +LOS_LOG181 +LOS_ACT182 +LOS_LOG184 +LOS_ACT185 +LOS_LOG187 +LOS_LOG188 +LOS_LOG189 +LOS_LOG190 +LOS_LOG191 +LOS_LOG192 +___block_descriptor_tmp.253 +LOS_LOG193 +LOS_LOG194 +LOS_ACT195 +LOS_LOG197 +LOS_LOG198 +LOS_LOG199 +LOS_ACT200 +LOS_LOG202 +LOS_ACT203 +LOS_LOG205 +LOS_ACT206 +LOS_LOG208 +LOS_LOG209 +LOS_LOG210 +LOS_LOG211 +LOS_LOG212 +LOS_LOG213 +LOS_LOG214 +LOS_LOG215 +LOS_ACT216 +LOS_LOG218 +LOS_LOG219 +LOS_LOG220 +LOS_LOG221 +LOS_LOG222 +LOS_LOG223 +LOS_LOG224 +LOS_LOG225 +LOS_LOG226 +LOS_ACT227 +LOS_LOG229 +LOS_LOG230 +LOS_ACT231 +LOS_ACT233 +LOS_LOG235 +LOS_LOG236 +LOS_LOG237 +LOS_LOG238 +LOS_LOG239 +LOS_LOG240 +LOS_LOG241 +LOS_LOG242 +___block_descriptor_tmp.274 +LOS_ACT243 +LOS_LOG245 +___block_descriptor_tmp.277 +LOS_LOG246 +LOS_LOG247 +LOS_LOG248 +LOS_ACT249 +LOS_LOG251 +LOS_LOG252 +LOS_ACT253 +LOS_ACT255 +LOS_LOG257 +LOS_LOG258 +LOS_LOG259 +LOS_LOG260 +LOS_LOG261 +LOS_LOG262 +LOS_LOG263 +LOS_LOG264 +LOS_LOG265 +LOS_LOG266 +LOS_LOG267 +_OBJC_IVAR_$_URKArchive._progress +_OBJC_IVAR_$_URKArchive._rarFile +_OBJC_IVAR_$_URKArchive._header +_OBJC_IVAR_$_URKArchive._flags +l_OBJC_PROTOCOL_$_NSObject +l_OBJC_LABEL_PROTOCOL_$_NSObject +l_OBJC_PROTOCOL_$_NSProgressReporting +l_OBJC_LABEL_PROTOCOL_$_NSProgressReporting +/Users/travis/build/abbeycode/UnrarKit/Classes/URKArchive.mm +/Users/travis/build/abbeycode/UnrarKit/Classes/URKArchive.h +__os_log_helper_16_2_1_4_66 +__os_log_helper_16_2_2_4_66_4_0 +__destroy_helper_block_ +__copy_helper_block_ +__26-[URKArchive allFileInfo:]_block_invoke +__os_log_helper_16_0_1_4_0 +__39-[URKArchive iterateAllFileInfo:error:]_block_invoke +__39-[URKArchive checkDataIntegrityOfFile:]_block_invoke +__os_log_helper_16_2_3_4_66_4_0_4_0 +__os_log_helper_16_2_2_4_66_4_66 +__30-[URKArchive validatePassword]_block_invoke +__os_log_helper_16_0_2_4_0_4_0 +__55-[URKArchive extractBufferedDataFromFile:error:action:]_block_invoke.229 +__os_log_helper_16_0_2_4_0_8_0 +__55-[URKArchive extractBufferedDataFromFile:error:action:]_block_invoke +__os_log_helper_16_0_2_8_0_8_0 +CallbackProc +__43-[URKArchive performOnDataInArchive:error:]_block_invoke +__os_log_helper_16_0_1_8_0 +__44-[URKArchive performOnFilesInArchive:error:]_block_invoke +BufferedReadCallbackProc +__49-[URKArchive extractDataFromFile:progress:error:]_block_invoke.204 +__49-[URKArchive extractDataFromFile:progress:error:]_block_invoke +__Block_byref_object_dispose_ +__Block_byref_object_copy_ +AllowCancellationCallbackProc +__54-[URKArchive extractFilesTo:overwrite:progress:error:]_block_invoke.171 +__54-[URKArchive extractFilesTo:overwrite:progress:error:]_block_invoke +__os_log_helper_16_2_2_4_66_8_0 +__27-[URKArchive listFileInfo:]_block_invoke +__os_log_helper_16_2_3_4_66_4_66_4_66 +__24+[URKArchive initialize]_block_invoke +__os_log_helper_16_2_1_4_64 +/Applications/Xcode-9.3.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.3.sdk/usr/include/dispatch/once.h +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/strlist.cpp +~Array +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/array.hpp +Search +RestorePosition +GetString +operator[] +Size +Rewind +SavePosition +GetStringA +Array +CleanData +Add +AddString +AddStringA +StringList +Reset +__ZZ7GetWidePKcE8StrTable +__ZZ7GetWidePKcE6StrNum +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/strfn.cpp +GetCmdParam +GetWide +itoa +wcsncatz +strncatz +wcsncpyz +wcsnicompc +wcsicompc +LowAscii +GetDigits +BinToHex +IsAlpha +IsSpace +IsDigit +etoupperw +etoupper +toupper +/Applications/Xcode-9.3.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.3.sdk/usr/include/_ctype.h +loctoupper +loctolower +tolower +RemoveLF +RemoveEOL +strnicomp +stricomp +ArcCharToWide +strncpyz +IntToExt +NullToEmpty +__ZL10GenArcNamePwPKwjRb +__ZZ15EnumConfigPathsjPwmbE8ConfPath +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/pathfn.cpp +GetWideName +GenArcName +PointToName +IsPathDiv +wcschr +/Applications/Xcode-9.3.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/wchar.h +__libcpp_wcschr +RarTime +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/timefn.hpp +GenerateArchiveName +VolNameToFirstName +FindData +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/find.hpp +ParseVersionFileName +wcsrchr +__libcpp_wcsrchr +GetPathRoot +IsDriveLetter +IsFullRootPath +IsFullPath +ConvertNameToFull +DosSlashToUnix +UnixSlashToDos +MakeNameUsable +/Applications/Xcode-9.3.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/string.h +__libcpp_strchr +IsNameUsable +wcspbrk +__libcpp_wcspbrk +NextVolumeName +GetVolNumPart +GetConfigName +EnumConfigPaths +RemoveNameFromPath +GetFilePath +MakeName +AddEndSlash +GetPathDisk +IsWildcard +CmpExt +SetSFXExt +GetExt +SetExt +SetName +ConvertPath +PointToLastChar +IsDriveDiv +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/smallfn.cpp +ToPercentUnlim +ToPercent +__GLOBAL__sub_I_global.cpp +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/global.cpp +_GLOBAL__sub_I_global.cpp +__cxx_global_var_init +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/global.hpp +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/file.cpp +~SaveFilePos +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/savepos.hpp +IsOpened +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/file.hpp +Copy +IsDevice +GetFD +GetOpenFileTime +SetCloseFileTimeByName +IsSet +SetCloseFileTime +SetOpenFileTime +Flush +Truncate +PutByte +GetByte +Prealloc +Tell +FileLength +SaveFilePos +RawSeek +Seek +DirectRead +Read +Write +Rename +Close +WCreate +TCreate +Create +WOpen +TOpen +Open +operator= +~File +Delete +File +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/filefn.cpp +DelFile +RenameFile +CalcFileSum +uiMsg +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/ui.hpp +uiMsgStore +SetFileAttr +GetFileAttr +PrepareToDelete +IsDeleteAllowed +IsLink +IsUnreadable +IsDir +WildFileExist +FileExist +GetFreeDisk +IsRemovable +SetDirTime +mprintf +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/consio.hpp +CreatePath +MakeDir +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/filcreat.cpp +GetAutoRenamedName +FileCreate +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/archive.cpp +Unload +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/qopen.hpp +FullHeaderSize +SeekToNext +IsSignature +WCheckOpen +uiMsg +operator<< +CheckOpen +IsArchive +GetHeaderType +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/archive.hpp +uiMsg +CheckArc +~Archive +~FileHeader +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/headers.hpp +Archive +FileHeader +ViewComment +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/arccmt.cpp +ReadCommentData +Alloc +Addr +Push +GetComment +SetDestSize +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/unpack.hpp +SetNoFileHeader +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/rdwrfn.hpp +SetPackedSizeToRead +EnableShowProgress +SetTestMode +__ZZN7Archive17ConvertAttributesEvE4mask +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/arcread.cpp +ReadSubData +SetSubHeader +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/secpassword.hpp +GetStartPos +ConvertAttributes +IsArcDir +ProcessExtra50 +DataLeft +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/rawread.hpp +SetPos +UnkEncVerMsg +uiMsg +GetPos +ConvertFileHeader +ConvertNameCase +RequestArcPassword +UnexpEndArcMsg +SearchRR +CmpName +SearchSubBlock +SearchBlock +BrokenHeaderMsg +ReadHeader50 +~RawRead +SafeAdd +SetCrypt +ReadHeader15 +ReadHeader14 +ReadHeader +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/unicode.cpp +atoilw +atoiw +toupperw +towupper +/Applications/Xcode-9.3.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.3.sdk/usr/include/_wctype.h +wcsupper +wcslower +towlower +tolowerw +wcscasestr +wcsnicomp +wcsicomp +IsTextUtf8 +WideToUtfSize +RawToWide +WideToRaw +UtfToWide +CharToWide +WideToUtf +WideToChar +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/system.cpp +Wait +MonoClock +SetPriority +InitSystemOptions +__ZL11hmac_sha256PKhmS0_mPhP14sha256_contextPbS3_S4_ +__ZL16InitSubstTable20 +__ZZL13TimeRandomizePhmE5Count +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/crypt.cpp +GetRnd +TimeRandomize +SetCryptKeys +DecryptBlock +Decrypt13 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/crypt1.cpp +~CryptData +~KDF3CacheItem +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/crypt.hpp +~KDF5CacheItem +CryptData +KDF5CacheItem +KDF3CacheItem +ConvertHashToMAC +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/crypt5.cpp +RawPut4 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/rawint.hpp +SetKey50 +hmac_sha256 +pbkdf2 +SetKey30 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/crypt3.cpp +DecryptBlock20 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/crypt2.cpp +RawGet4 +UpdKeys20 +EncryptBlock20 +Swap20 +SetKey20 +Crypt15 +SetCmt13Encryption +SetAV15Encryption +SetKey15 +SetKey13 +__GLOBAL__sub_I_crc.cpp +__ZL10CallInit32 +__ZL10crc_tables +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/crc.cpp +_GLOBAL__sub_I_crc.cpp +CallInitCRC +InitTables +InitCRC32 +Checksum14 +CRC32 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/rawread.cpp +RawGetV +GetCRC50 +GetCRC15 +GetW +GetB +GetVSize +GetV +Get8 +Get4 +Get2 +Get1 +RawRead +SoftReset +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/encname.cpp +Decode +EncodeFileName +__ZL5matchPKwS0_b +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/match.cpp +match +mwcsicompc +mwcsnicompc +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/timefn.cpp +IsLeapYear +GetMonthName +Adjust +SetCurrentTime +SetUnix +SetUnixNS +SetAgeText +SetIsoText +SetLocal +GetText +SetDos +GetDos +GetUnixNS +SetWin +GetWin +GetUnix +GetLocal +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/rdwrfn.cpp +SetUnpackToMemory +SetEncryption +GetUnpackedData +SetFiles +ShowUnpWrite +UnpWrite +GetRAROptions +ShowUnpRead +UnpRead +~ComprDataIO +ComprDataIO +Init +__ZL7LogName +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/consio.cpp +OutComment +IsCommentUnsafe +SetConsoleRedirectCharset +SetConsoleMsgStream +InitConsole +InitLogOptions +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/log.cpp +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/options.cpp +~RAROptions +RAROptions +__ZZ13ProcessSignaliE10BreakCount +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/errhnd.cpp +SetSystemErrorCode +GetSystemErrorCode +GetSysErrMsg +SetSignalHandlers +ProcessSignal +Throw +UnknownMethodMsg +SetErrorCode +uiMsg +ChecksumFailedMsg +ArcBrokenMsg +uiMsg +WriteErrorMsg +ReadErrorMsg +CreateErrorMsg +OpenErrorMsg +GeneralErrMsg +SeekError +Exit +AskRepeatWrite +WriteError +AskRepeatRead +ReadError +SysErrMsg +CloseError +OpenError +MemoryErrorMsg +MemoryError +ErrorHandler +Clean +__ZZN5RarVM7PrepareEPhjP18VM_PreparedProgramE7StdList +__ZZN5RarVM21ExecuteStandardFilterE18VM_StandardFiltersE5Masks +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/rarvm.cpp +FilterItanium_SetBits +FilterItanium_GetBits +SetMemory +ReadData +Prepare +ExecuteStandardFilter +Execute +~RarVM +RarVM +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/secpassword.cpp +operator== +cleandata +Get +Process +SecHideData +Length +~SecPassword +SecPassword +Set +__ZL1S +__ZL2T1 +__ZL2T2 +__ZL2T3 +__ZL2T4 +__ZL2T5 +__ZL2T6 +__ZL2T7 +__ZL2T8 +__ZL2S5 +__ZL4rcon +__ZL2U1 +__ZL2U2 +__ZL2U3 +__ZL2U4 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/rijndael.cpp +blockDecrypt +Copy128 +Xor128 +blockEncrypt +keyEncToDec +keySched +Rijndael +GenerateTables +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/getbits.cpp +SetExternalBuffer +fgetbits +getbits +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/getbits.hpp +faddbits +addbits +~BitInput +BitInput +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/sha1.cpp +sha1_done +sha1_init +RawPutBE4 +sha1_process_rar29 +sha1_process +SHA1Transform +ByteSwap32 +__ZL16sha256_transformP14sha256_context +__ZL1K +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/sha256.cpp +sha256_done +sha256_init +sha256_transform +RawGetBE4 +sha256_process +__ZL14blake2s_updateP13blake2s_statePKhm +__ZL13blake2s_finalP13blake2s_statePh +__ZL16blake2s_compressP13blake2s_statePKh +__ZL10blake2s_IV +__ZL13blake2s_sigma +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/blake2s.cpp +blake2s_compress +blake2s_final +blake2s_set_lastblock +blake2s_set_lastnode +blake2s_increment_counter +blake2sp_final +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/blake2sp.cpp +blake2sp_update +blake2s_update +Update +blake2sp_init +blake2s_init_param +init +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/blake2s.hpp +__ZZN9HashValue4InitE9HASH_TYPEE9EmptyHash +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/hash.cpp +Cmp +GetCRC32 +Result +blake2sp_state +blake2s_state +set_pointers +~DataHash +DataHash +__ZL11UnixSymlinkPKcPKwP7RarTimeS4_ +__ZL16CalcAllowedDepthPKw +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/extinfo.cpp +ExtractSymlink +CalcAllowedDepth +SetFileHeaderExtra +SetExtraInfo +SetExtraInfo20 +ExtractUnixLink50 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/ulinks.cpp +UnixSymlink +IsRelativeSymlinkSafe +LinkInPath +ExtractUnixLink30 +SetUnixOwner +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/uowners.cpp +ExtractUnixOwner30 +ExtractUnixOwner20 +GetStreamNameNTFS +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/win32stm.cpp +ExtractHardlink +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/hardlinks.cpp +SlashToNative +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/pathfn.hpp +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/extract.cpp +UnstoreFile +ExtractFileCopy +uiMsg +ExtrCreateFile +SetHandleType +ExtrCreateDir +ExtrDllGetPassword +CheckUnpVer +ExtrPrepareName +ExtractCurrentFile +SetAllowDelete +SetSkipUnpCRC +operator< +operator>= +ItemsCount +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/strlist.hpp +ExtractArchiveInit +ExtractArchive +DoExtract +GetErrorCount +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/errhnd.hpp +GetErrorCode +SetCurrentCommand +~CmdExtract +CmdExtract +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/volume.cpp +MergeArchive +DllVolNotify +DllVolChange +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/find.cpp +FastFind +Next +uiMsg +SetMask +~FindFile +FindFile +__ZZN8ModelPPM16RestartModelRareEvE10InitBinEsc +__ZZN6Unpack7ShortLZEvE9ShortLen1 +__ZZN6Unpack7ShortLZEvE9ShortXor1 +__ZZN6Unpack7ShortLZEvE9ShortLen2 +__ZZN6Unpack7ShortLZEvE9ShortXor2 +__ZL5DecL2 +__ZL5PosL2 +__ZL5DecL1 +__ZL5PosL1 +__ZL6DecHf2 +__ZL6PosHf2 +__ZL6DecHf1 +__ZL6PosHf1 +__ZL6DecHf0 +__ZL6PosHf0 +__ZL6DecHf4 +__ZL6PosHf4 +__ZL6DecHf3 +__ZL6PosHf3 +__ZZN6Unpack8Unpack20EbE7DDecode +__ZZN6Unpack8Unpack20EbE5DBits +__ZZN6Unpack8Unpack29EbE7LDecode +__ZZN6Unpack8Unpack29EbE5LBits +__ZZN6Unpack8Unpack29EbE7DDecode +__ZZN6Unpack8Unpack29EbE5DBits +__ZZN6Unpack8Unpack29EbE16DBitLengthCounts +__ZZN6Unpack8Unpack29EbE8SDDecode +__ZZN6Unpack8Unpack29EbE6SDBits +__ZL9ExpEscape +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/unpack.cpp +CreateSuccessors +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/model.cpp +createChild +AllocContext +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/suballoc.cpp +RemoveNode +update +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/model.hpp +DoUnpack +~Unpack +~FragmentedWindow +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/unpack50frag.cpp +~ModelPPM +~SubAllocator +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/suballoc.hpp +StopSubAllocator +Unpack +UnpInitData15 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/unpack15.cpp +ModelPPM +SubAllocator +FragmentedWindow +UnpInitData50 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/unpack50.cpp +UnpWriteData +GetBlockSize +ApplyFilter +CopyData +InitFilters +ReadFilterData +AddFilter +ReadFilter +CopyString +getbits32 +UnpWriteBuf +ReadTables +DecodeNumber +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/unpackinline.cpp +ReadBlockHeader +Unpack5 +SlotToLength +InsertOldDist +UnpInitData30 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/unpack30.cpp +ExecuteCode +UnpWriteArea +InitFilters30 +AddVMCode +Overflow +UnpackFilter30 +VM_PreparedProgram +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/rarvm.hpp +InitBitInput +ReadVMCode +ReadEndOfBlock +ReadVMCodePPM +SafePPMDecodeChar +UnpWriteBuf30 +ReadTables30 +UnpReadBuf30 +Unpack29 +UnpInitData20 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/unpack20.cpp +MakeDecodeTables +ReadLastTables +DecodeAudio +ReadTables20 +Unpack20 +CopyString20 +CorrHuff +DecodeNum +CopyString15 +ShortLZ +LongLZ +HuffDecode +UnpWriteBuf20 +GetFlagsBuf +InitHuff +UnpReadBuf +UnpInitData +Unpack15 +UpdateModel +AllocUnits +U2B +ExpandUnits +InsertNode +_PPMD_SWAP +decodeSymbol2 +update2 +GetCurrentCount +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/coder.cpp +makeEscFreq2 +getMean +decodeSymbol1 +update1 +DecodeChar +ClearMask +decodeBinSymbol +GetCurrentShiftCount +GetChar +DecodeInit +GetAllocatedMemory +CleanUp +rescale +ShrinkUnits +SplitBlock +FreeUnits +StartModelRare +RestartModelRare +GlueFreeBlocks +MBPtr +insertAt +AllocUnitsRare +InitSubAllocator +StartSubAllocator +InitDecoder +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/headers.cpp +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/cmddata.cpp +ReportWrongSwitches +uiMsg +CheckWinSize +GetArcName +AddArcName +ProcessCommand +~StringList +IsProcessFile +SizeCheck +TimeCheck +operator<= +ExclDirByAttr +CheckArgs +ExclCheck +OutTitle +OutHelp +eprintf +GetExclAttr +BadSwitch +ReadConfig +ProcessSwitchesString +AllocCmdParam +IsSwitch +ParseEnvVar +ProcessSwitch +ParseDone +ParseArg +PreprocessArg +ParseCommandLine +CommandData +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/ui.cpp +uiGetMonthName +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/uisilent.cpp +uiGiveTick +uiIsAborted +uiAlarm +uiGetPassword +Msg +uiProcessProgress +uiExtractProgress +uiStartFileExtract +uiStartArchiveExtract +uiAskReplace +uiAskReplaceEx +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/uicommon.cpp +uiInit +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/filestr.cpp +DetectTextEncoding +ReadTextFile +operator+ +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/scantree.cpp +ScanError +GetFilteredMask +ExpandFolderMask +FindProc +GetNextMask +GetNext +~ScanTree +ScanTree +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/qopen.cpp +ReadRaw +ReadNext +ReadBuffer +Load +SetProhibitQOpen +~QuickOpen +QuickOpen +__ZL13RarErrorToDll8RAR_EXIT +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/dll.cpp +DataSet +~CommandData +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/cmddata.hpp +RARGetDllVersion +RARSetPassword +RARSetProcessDataProc +RARSetCallback +RARSetChangeVolProc +RARProcessFileW +ProcessFile +RARProcessFile +RARReadHeaderEx +RARReadHeader +RARCloseArchive +~DataSet +RarErrorToDll +RAROpenArchiveEx +RAROpenArchive diff --git a/Carthage/Build/iOS/F765DD24-CC0C-3A6E-A6D4-DB28E3D85D68.bcsymbolmap b/Carthage/Build/iOS/F765DD24-CC0C-3A6E-A6D4-DB28E3D85D68.bcsymbolmap new file mode 100644 index 0000000..ec7cb21 --- /dev/null +++ b/Carthage/Build/iOS/F765DD24-CC0C-3A6E-A6D4-DB28E3D85D68.bcsymbolmap @@ -0,0 +1,1238 @@ +BCSymbolMap Version: 2.0 ++[URKFileInfo fileInfo:] +-[URKFileInfo initWithFileHeader:] +-[URKFileInfo parseDOSDate:] +-[URKFileInfo archiveName] +-[URKFileInfo filename] +-[URKFileInfo timestamp] +-[URKFileInfo CRC] +-[URKFileInfo uncompressedSize] +-[URKFileInfo compressedSize] +-[URKFileInfo isEncryptedWithPassword] +-[URKFileInfo isDirectory] +-[URKFileInfo compressionMethod] +-[URKFileInfo hostOS] +-[URKFileInfo .cxx_destruct] +LOS_ACT0 +LOS_LOG2 +_OBJC_IVAR_$_URKFileInfo._filename +_OBJC_IVAR_$_URKFileInfo._archiveName +_OBJC_IVAR_$_URKFileInfo._uncompressedSize +_OBJC_IVAR_$_URKFileInfo._compressedSize +_OBJC_IVAR_$_URKFileInfo._compressionMethod +_OBJC_IVAR_$_URKFileInfo._hostOS +_OBJC_IVAR_$_URKFileInfo._timestamp +_OBJC_IVAR_$_URKFileInfo._CRC +_OBJC_IVAR_$_URKFileInfo._isEncryptedWithPassword +_OBJC_IVAR_$_URKFileInfo._isDirectory +LOS_ACT3 +LOS_LOG5 +Apple LLVM version 9.1.0 (clang-902.0.39.1) +/Users/travis/build/abbeycode/UnrarKit/Classes/URKFileInfo.m +/Users/travis/build/abbeycode/UnrarKit +/Users/travis/build/abbeycode/UnrarKit/Classes/URKFileInfo.h +__os_log_helper_16_0_0 ++[NSString(UnrarKit) stringWithUnichars:] +/Users/travis/build/abbeycode/UnrarKit/Classes/Categories/NSString+UnrarKit.mm ++[URKArchive rarArchiveAtPath:] ++[URKArchive rarArchiveAtURL:] ++[URKArchive rarArchiveAtPath:password:] ++[URKArchive rarArchiveAtURL:password:] ++[URKArchive initialize] +___24+[URKArchive initialize]_block_invoke +-[URKArchive init] +-[URKArchive initWithPath:error:] +-[URKArchive initWithURL:error:] +-[URKArchive initWithPath:password:error:] +-[URKArchive initWithURL:password:error:] +-[URKArchive initWithFile:error:] +-[URKArchive initWithFile:password:error:] +___clang_call_terminate +-[URKArchive fileURL] +-[URKArchive filename] +-[URKArchive uncompressedSize] +-[URKArchive compressedSize] +-[URKArchive hasMultipleVolumes] ++[URKArchive pathIsARAR:] ++[URKArchive urlIsARAR:] +-[URKArchive listFilenames:] +-[URKArchive listFileInfo:] +___27-[URKArchive listFileInfo:]_block_invoke +___copy_helper_block_ +___destroy_helper_block_ +-[URKArchive iterateFileInfo:error:] +-[URKArchive listVolumeURLs:] +-[URKArchive extractFilesTo:overwrite:error:] +-[URKArchive extractFilesTo:overwrite:progress:error:] +___54-[URKArchive extractFilesTo:overwrite:progress:error:]_block_invoke +___54-[URKArchive extractFilesTo:overwrite:progress:error:]_block_invoke.171 +___copy_helper_block_.172 +___destroy_helper_block_.173 +___copy_helper_block_.188 +___destroy_helper_block_.189 +-[URKArchive extractData:error:] +-[URKArchive extractData:progress:error:] +-[URKArchive extractDataFromFile:error:] +-[URKArchive extractDataFromFile:progress:error:] +___Block_byref_object_copy_ +___Block_byref_object_dispose_ +___49-[URKArchive extractDataFromFile:progress:error:]_block_invoke +___49-[URKArchive extractDataFromFile:progress:error:]_block_invoke.204 +___copy_helper_block_.207 +___destroy_helper_block_.208 +___copy_helper_block_.213 +___destroy_helper_block_.214 +-[URKArchive performOnFilesInArchive:error:] +___44-[URKArchive performOnFilesInArchive:error:]_block_invoke +___copy_helper_block_.218 +___destroy_helper_block_.219 +-[URKArchive performOnDataInArchive:error:] +___43-[URKArchive performOnDataInArchive:error:]_block_invoke +___copy_helper_block_.226 +___destroy_helper_block_.227 +-[URKArchive extractBufferedDataFromFile:error:action:] +___55-[URKArchive extractBufferedDataFromFile:error:action:]_block_invoke +___55-[URKArchive extractBufferedDataFromFile:error:action:]_block_invoke.229 +___copy_helper_block_.230 +___destroy_helper_block_.231 +___copy_helper_block_.233 +___destroy_helper_block_.234 +-[URKArchive isPasswordProtected] +-[URKArchive validatePassword] +___30-[URKArchive validatePassword]_block_invoke +___copy_helper_block_.240 +___destroy_helper_block_.241 +-[URKArchive checkDataIntegrity] +-[URKArchive checkDataIntegrityOfFile:] +___39-[URKArchive checkDataIntegrityOfFile:]_block_invoke +___copy_helper_block_.251 +___destroy_helper_block_.252 +-[URKArchive performActionWithArchiveOpen:inMode:error:] +-[URKArchive _unrarOpenFile:inMode:withPassword:error:] +-[URKArchive closeFile] +-[URKArchive iterateAllFileInfo:error:] +___39-[URKArchive iterateAllFileInfo:error:]_block_invoke +___copy_helper_block_.272 +___destroy_helper_block_.273 +-[URKArchive allFileInfo:] +___26-[URKArchive allFileInfo:]_block_invoke +___copy_helper_block_.275 +___destroy_helper_block_.276 +-[URKArchive errorNameForErrorCode:detail:] +-[URKArchive assignError:code:errorName:] +-[URKArchive assignError:code:underlyer:errorName:] +-[URKArchive headerContainsErrors:] +-[URKArchive beginProgressOperation:] ++[URKArchive firstVolumeURL:] +-[URKArchive password] +-[URKArchive setPassword:] +-[URKArchive progress] +-[URKArchive setProgress:] +-[URKArchive rarFile] +-[URKArchive setRarFile:] +-[URKArchive header] +-[URKArchive setHeader:] +-[URKArchive flags] +-[URKArchive setFlags:] +-[URKArchive fileBookmark] +-[URKArchive setFileBookmark:] +-[URKArchive threadLock] +-[URKArchive setThreadLock:] +-[URKArchive .cxx_destruct] +__ZL10_resources +__ZZ24+[URKArchive initialize]E9onceToken +___block_descriptor_tmp +___block_literal_global +LOS_LOG0 +LOS_LOG1 +LOS_LOG6 +LOS_LOG7 +LOS_LOG8 +LOS_LOG9 +_OBJC_IVAR_$_URKArchive._fileBookmark +_OBJC_IVAR_$_URKArchive._password +_OBJC_IVAR_$_URKArchive._threadLock +LOS_LOG10 +LOS_LOG11 +LOS_ACT12 +LOS_LOG14 +LOS_LOG15 +LOS_LOG16 +LOS_LOG17 +LOS_LOG18 +LOS_ACT19 +LOS_ACT21 +LOS_LOG23 +LOS_LOG24 +LOS_LOG25 +LOS_ACT26 +LOS_LOG28 +LOS_LOG29 +LOS_LOG30 +LOS_LOG31 +LOS_LOG32 +LOS_ACT33 +LOS_LOG35 +LOS_LOG36 +LOS_ACT37 +LOS_LOG39 +LOS_LOG40 +LOS_LOG41 +LOS_LOG42 +LOS_LOG43 +LOS_LOG44 +LOS_LOG45 +LOS_ACT46 +LOS_LOG48 +LOS_ACT49 +LOS_ACT51 +LOS_LOG53 +___block_descriptor_tmp.121 +LOS_LOG54 +LOS_LOG55 +LOS_LOG56 +LOS_ACT57 +LOS_LOG59 +LOS_LOG60 +LOS_LOG61 +LOS_ACT62 +LOS_ACT64 +LOS_LOG66 +LOS_LOG67 +LOS_LOG68 +LOS_ACT69 +LOS_LOG71 +LOS_LOG72 +LOS_LOG73 +LOS_LOG74 +LOS_LOG75 +LOS_LOG76 +LOS_LOG77 +LOS_LOG78 +LOS_ACT79 +LOS_LOG81 +___block_descriptor_tmp.175 +LOS_LOG82 +LOS_LOG83 +LOS_LOG84 +LOS_LOG85 +LOS_LOG86 +___block_descriptor_tmp.191 +LOS_ACT87 +LOS_ACT89 +LOS_LOG91 +LOS_LOG92 +LOS_LOG93 +LOS_LOG94 +LOS_LOG95 +LOS_LOG96 +LOS_LOG97 +LOS_LOG98 +LOS_LOG99 +LOS_LOG100 +LOS_LOG101 +LOS_LOG102 +___block_descriptor_tmp.210 +LOS_LOG103 +LOS_LOG104 +LOS_LOG105 +LOS_LOG106 +___block_descriptor_tmp.215 +LOS_ACT107 +LOS_LOG109 +LOS_LOG110 +LOS_LOG111 +LOS_LOG112 +LOS_ACT113 +LOS_LOG115 +LOS_LOG116 +LOS_LOG117 +___block_descriptor_tmp.221 +LOS_ACT118 +LOS_LOG120 +LOS_LOG121 +LOS_LOG122 +LOS_LOG123 +LOS_LOG124 +LOS_LOG125 +LOS_LOG126 +LOS_LOG127 +LOS_LOG128 +LOS_LOG129 +LOS_LOG130 +LOS_LOG131 +LOS_LOG132 +LOS_LOG133 +LOS_LOG134 +___block_descriptor_tmp.228 +LOS_ACT135 +LOS_ACT137 +LOS_LOG139 +LOS_LOG140 +LOS_LOG141 +LOS_LOG142 +LOS_LOG143 +LOS_LOG144 +LOS_LOG145 +LOS_LOG146 +LOS_LOG147 +LOS_LOG148 +LOS_LOG149 +LOS_LOG150 +LOS_LOG151 +___block_descriptor_tmp.232 +LOS_LOG152 +LOS_LOG153 +LOS_LOG154 +LOS_LOG155 +LOS_LOG156 +___block_descriptor_tmp.235 +LOS_LOG157 +LOS_LOG158 +LOS_ACT159 +LOS_LOG161 +LOS_LOG162 +LOS_LOG163 +LOS_LOG164 +LOS_LOG165 +LOS_LOG166 +LOS_LOG167 +LOS_LOG168 +LOS_LOG169 +LOS_LOG170 +LOS_ACT171 +LOS_ACT173 +LOS_LOG175 +LOS_LOG176 +LOS_LOG177 +LOS_LOG178 +LOS_LOG179 +___block_descriptor_tmp.242 +LOS_LOG180 +LOS_LOG181 +LOS_ACT182 +LOS_LOG184 +LOS_ACT185 +LOS_LOG187 +LOS_LOG188 +LOS_LOG189 +LOS_LOG190 +LOS_LOG191 +LOS_LOG192 +___block_descriptor_tmp.253 +LOS_LOG193 +LOS_LOG194 +LOS_ACT195 +LOS_LOG197 +LOS_LOG198 +LOS_LOG199 +LOS_ACT200 +LOS_LOG202 +LOS_ACT203 +LOS_LOG205 +LOS_ACT206 +LOS_LOG208 +LOS_LOG209 +LOS_LOG210 +LOS_LOG211 +LOS_LOG212 +LOS_LOG213 +LOS_LOG214 +LOS_LOG215 +LOS_ACT216 +LOS_LOG218 +LOS_LOG219 +LOS_LOG220 +LOS_LOG221 +LOS_LOG222 +LOS_LOG223 +LOS_LOG224 +LOS_LOG225 +LOS_LOG226 +LOS_ACT227 +LOS_LOG229 +LOS_LOG230 +LOS_ACT231 +LOS_ACT233 +LOS_LOG235 +LOS_LOG236 +LOS_LOG237 +LOS_LOG238 +LOS_LOG239 +LOS_LOG240 +LOS_LOG241 +LOS_LOG242 +___block_descriptor_tmp.274 +LOS_ACT243 +LOS_LOG245 +___block_descriptor_tmp.277 +LOS_LOG246 +LOS_LOG247 +LOS_LOG248 +LOS_ACT249 +LOS_LOG251 +LOS_LOG252 +LOS_ACT253 +LOS_ACT255 +LOS_LOG257 +LOS_LOG258 +LOS_LOG259 +LOS_LOG260 +LOS_LOG261 +LOS_LOG262 +LOS_LOG263 +LOS_LOG264 +LOS_LOG265 +LOS_LOG266 +LOS_LOG267 +_OBJC_IVAR_$_URKArchive._progress +_OBJC_IVAR_$_URKArchive._rarFile +_OBJC_IVAR_$_URKArchive._header +_OBJC_IVAR_$_URKArchive._flags +l_OBJC_PROTOCOL_$_NSObject +l_OBJC_LABEL_PROTOCOL_$_NSObject +l_OBJC_PROTOCOL_$_NSProgressReporting +l_OBJC_LABEL_PROTOCOL_$_NSProgressReporting +/Users/travis/build/abbeycode/UnrarKit/Classes/URKArchive.mm +/Users/travis/build/abbeycode/UnrarKit/Classes/URKArchive.h +__os_log_helper_16_2_1_8_66 +NSMakeRange +/Applications/Xcode-9.3.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.3.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSRange.h +__os_log_helper_16_2_2_8_66_4_0 +__destroy_helper_block_ +__copy_helper_block_ +__26-[URKArchive allFileInfo:]_block_invoke +__os_log_helper_16_0_1_8_0 +__39-[URKArchive iterateAllFileInfo:error:]_block_invoke +__39-[URKArchive checkDataIntegrityOfFile:]_block_invoke +__os_log_helper_16_2_3_8_66_8_0_8_0 +__os_log_helper_16_2_2_8_66_8_66 +__30-[URKArchive validatePassword]_block_invoke +__os_log_helper_16_0_2_4_0_4_0 +__55-[URKArchive extractBufferedDataFromFile:error:action:]_block_invoke.229 +__os_log_helper_16_0_2_8_0_8_0 +__55-[URKArchive extractBufferedDataFromFile:error:action:]_block_invoke +CallbackProc +__43-[URKArchive performOnDataInArchive:error:]_block_invoke +__44-[URKArchive performOnFilesInArchive:error:]_block_invoke +BufferedReadCallbackProc +__49-[URKArchive extractDataFromFile:progress:error:]_block_invoke.204 +__49-[URKArchive extractDataFromFile:progress:error:]_block_invoke +__Block_byref_object_dispose_ +__Block_byref_object_copy_ +AllowCancellationCallbackProc +__54-[URKArchive extractFilesTo:overwrite:progress:error:]_block_invoke.171 +__54-[URKArchive extractFilesTo:overwrite:progress:error:]_block_invoke +__os_log_helper_16_2_2_8_66_8_0 +__27-[URKArchive listFileInfo:]_block_invoke +__os_log_helper_16_2_3_8_66_8_66_8_66 +__24+[URKArchive initialize]_block_invoke +__os_log_helper_16_2_1_8_64 +/Applications/Xcode-9.3.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.3.sdk/usr/include/dispatch/once.h +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/strlist.cpp +~Array +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/array.hpp +Search +RestorePosition +GetString +operator[] +Size +Rewind +SavePosition +GetStringA +Array +CleanData +Add +AddString +AddStringA +StringList +Reset +__ZZ7GetWidePKcE8StrTable +__ZZ7GetWidePKcE6StrNum +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/strfn.cpp +GetCmdParam +GetWide +itoa +wcsncatz +strncatz +wcsncpyz +wcsnicompc +wcsicompc +LowAscii +GetDigits +BinToHex +IsAlpha +IsSpace +IsDigit +etoupperw +etoupper +toupper +/Applications/Xcode-9.3.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.3.sdk/usr/include/_ctype.h +loctoupper +loctolower +tolower +RemoveLF +RemoveEOL +strnicomp +stricomp +ArcCharToWide +strncpyz +IntToExt +NullToEmpty +__ZL10GenArcNamePwPKwjRb +__ZZ15EnumConfigPathsjPwmbE8ConfPath +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/pathfn.cpp +GetWideName +GenArcName +GetFilePath +wcschr +/Applications/Xcode-9.3.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/wchar.h +__libcpp_wcschr +RarTime +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/timefn.hpp +GenerateArchiveName +VolNameToFirstName +FindData +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/find.hpp +ParseVersionFileName +wcsrchr +__libcpp_wcsrchr +GetPathRoot +IsDriveLetter +IsFullRootPath +IsFullPath +IsPathDiv +ConvertNameToFull +DosSlashToUnix +UnixSlashToDos +MakeNameUsable +/Applications/Xcode-9.3.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include/c++/v1/string.h +__libcpp_strchr +IsNameUsable +wcspbrk +__libcpp_wcspbrk +NextVolumeName +GetVolNumPart +GetConfigName +EnumConfigPaths +RemoveNameFromPath +MakeName +AddEndSlash +GetPathDisk +IsWildcard +CmpExt +SetSFXExt +GetExt +SetExt +SetName +ConvertPath +PointToLastChar +IsDriveDiv +PointToName +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/smallfn.cpp +ToPercentUnlim +ToPercent +__GLOBAL__sub_I_global.cpp +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/global.cpp +_GLOBAL__sub_I_global.cpp +__cxx_global_var_init +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/global.hpp +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/file.cpp +~SaveFilePos +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/savepos.hpp +IsOpened +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/file.hpp +Copy +IsDevice +GetFD +GetOpenFileTime +SetCloseFileTimeByName +IsSet +SetCloseFileTime +SetOpenFileTime +Flush +Truncate +PutByte +GetByte +Prealloc +Tell +FileLength +SaveFilePos +RawSeek +Seek +DirectRead +Read +Write +Rename +Close +WCreate +TCreate +Create +WOpen +TOpen +Open +operator= +~File +Delete +File +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/filefn.cpp +DelFile +RenameFile +CalcFileSum +uiMsg +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/ui.hpp +uiMsgStore +SetFileAttr +GetFileAttr +PrepareToDelete +IsDeleteAllowed +IsLink +IsUnreadable +IsDir +WildFileExist +FileExist +GetFreeDisk +IsRemovable +SetDirTime +mprintf +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/consio.hpp +CreatePath +MakeDir +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/filcreat.cpp +GetAutoRenamedName +FileCreate +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/archive.cpp +Unload +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/qopen.hpp +FullHeaderSize +SeekToNext +IsSignature +WCheckOpen +uiMsg +operator<< +CheckOpen +IsArchive +GetHeaderType +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/archive.hpp +uiMsg +CheckArc +~Archive +~FileHeader +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/headers.hpp +Archive +FileHeader +ViewComment +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/arccmt.cpp +ReadCommentData +Alloc +Addr +Push +GetComment +SetDestSize +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/unpack.hpp +SetNoFileHeader +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/rdwrfn.hpp +SetPackedSizeToRead +EnableShowProgress +SetTestMode +__ZZN7Archive17ConvertAttributesEvE4mask +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/arcread.cpp +ReadSubData +SetSubHeader +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/secpassword.hpp +GetStartPos +ConvertAttributes +IsArcDir +ProcessExtra50 +DataLeft +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/rawread.hpp +SetPos +UnkEncVerMsg +uiMsg +GetPos +ConvertFileHeader +ConvertNameCase +RequestArcPassword +UnexpEndArcMsg +SearchRR +CmpName +SearchSubBlock +SearchBlock +BrokenHeaderMsg +ReadHeader50 +~RawRead +SafeAdd +SetCrypt +ReadHeader15 +ReadHeader14 +ReadHeader +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/unicode.cpp +atoilw +atoiw +toupperw +towupper +/Applications/Xcode-9.3.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS11.3.sdk/usr/include/_wctype.h +wcsupper +wcslower +towlower +tolowerw +wcscasestr +wcsnicomp +wcsicomp +IsTextUtf8 +WideToUtfSize +RawToWide +WideToRaw +UtfToWide +CharToWide +WideToUtf +WideToChar +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/system.cpp +Wait +MonoClock +SetPriority +InitSystemOptions +__ZL11hmac_sha256PKhmS0_mPhP14sha256_contextPbS3_S4_ +__ZL16InitSubstTable20 +__ZZL13TimeRandomizePhmE5Count +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/crypt.cpp +GetRnd +TimeRandomize +SetCryptKeys +DecryptBlock +Decrypt13 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/crypt1.cpp +~CryptData +~KDF3CacheItem +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/crypt.hpp +~KDF5CacheItem +CryptData +KDF5CacheItem +KDF3CacheItem +ConvertHashToMAC +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/crypt5.cpp +RawPut4 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/rawint.hpp +SetKey50 +hmac_sha256 +pbkdf2 +SetKey30 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/crypt3.cpp +DecryptBlock20 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/crypt2.cpp +RawGet4 +UpdKeys20 +EncryptBlock20 +Swap20 +SetKey20 +Crypt15 +SetCmt13Encryption +SetAV15Encryption +SetKey15 +SetKey13 +__GLOBAL__sub_I_crc.cpp +__ZL10CallInit32 +__ZL10crc_tables +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/crc.cpp +_GLOBAL__sub_I_crc.cpp +CallInitCRC +InitTables +InitCRC32 +Checksum14 +CRC32 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/rawread.cpp +RawGetV +GetCRC50 +GetCRC15 +GetW +GetB +GetVSize +GetV +Get8 +Get4 +Get2 +Get1 +RawRead +SoftReset +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/encname.cpp +Decode +EncodeFileName +__ZL5matchPKwS0_b +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/match.cpp +match +mwcsicompc +mwcsnicompc +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/timefn.cpp +IsLeapYear +GetMonthName +Adjust +SetCurrentTime +SetUnix +SetUnixNS +SetAgeText +SetIsoText +SetLocal +GetText +SetDos +GetDos +GetUnixNS +SetWin +GetWin +GetUnix +GetLocal +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/rdwrfn.cpp +SetUnpackToMemory +SetEncryption +GetUnpackedData +SetFiles +ShowUnpWrite +UnpWrite +GetRAROptions +ShowUnpRead +UnpRead +~ComprDataIO +ComprDataIO +Init +__ZL7LogName +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/consio.cpp +OutComment +IsCommentUnsafe +SetConsoleRedirectCharset +SetConsoleMsgStream +InitConsole +InitLogOptions +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/log.cpp +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/options.cpp +~RAROptions +RAROptions +__ZZ13ProcessSignaliE10BreakCount +__ZTS8RAR_EXIT +__ZTI8RAR_EXIT +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/errhnd.cpp +SetSystemErrorCode +GetSystemErrorCode +GetSysErrMsg +SetSignalHandlers +ProcessSignal +Throw +UnknownMethodMsg +SetErrorCode +uiMsg +ChecksumFailedMsg +ArcBrokenMsg +uiMsg +WriteErrorMsg +ReadErrorMsg +CreateErrorMsg +OpenErrorMsg +GeneralErrMsg +SeekError +Exit +AskRepeatWrite +WriteError +AskRepeatRead +ReadError +SysErrMsg +CloseError +OpenError +MemoryErrorMsg +MemoryError +ErrorHandler +Clean +__ZZN5RarVM7PrepareEPhjP18VM_PreparedProgramE7StdList +__ZZN5RarVM21ExecuteStandardFilterE18VM_StandardFiltersE5Masks +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/rarvm.cpp +FilterItanium_SetBits +FilterItanium_GetBits +SetMemory +ReadData +Prepare +ExecuteStandardFilter +Execute +~RarVM +RarVM +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/secpassword.cpp +operator== +cleandata +Length +Get +Process +SecHideData +~SecPassword +SecPassword +Set +__ZL1S +__ZL2T1 +__ZL2T2 +__ZL2T3 +__ZL2T4 +__ZL2T5 +__ZL2T6 +__ZL2T7 +__ZL2T8 +__ZL2S5 +__ZL4rcon +__ZL2U1 +__ZL2U2 +__ZL2U3 +__ZL2U4 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/rijndael.cpp +blockDecrypt +Copy128 +Xor128 +blockEncrypt +keyEncToDec +keySched +Rijndael +GenerateTables +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/getbits.cpp +SetExternalBuffer +fgetbits +getbits +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/getbits.hpp +faddbits +addbits +~BitInput +BitInput +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/sha1.cpp +sha1_done +sha1_init +RawPutBE4 +sha1_process_rar29 +sha1_process +SHA1Transform +ByteSwap32 +__ZL16sha256_transformP14sha256_context +__ZL1K +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/sha256.cpp +sha256_done +sha256_init +sha256_transform +RawGetBE4 +sha256_process +__ZL14blake2s_updateP13blake2s_statePKhm +__ZL13blake2s_finalP13blake2s_statePh +__ZL16blake2s_compressP13blake2s_statePKh +__ZL10blake2s_IV +__ZL13blake2s_sigma +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/blake2s.cpp +blake2s_compress +blake2s_final +blake2s_set_lastblock +blake2s_set_lastnode +blake2s_increment_counter +blake2sp_final +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/blake2sp.cpp +blake2sp_update +blake2s_update +Update +blake2sp_init +blake2s_init_param +init +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/blake2s.hpp +__ZZN9HashValue4InitE9HASH_TYPEE9EmptyHash +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/hash.cpp +Cmp +GetCRC32 +Result +blake2sp_state +blake2s_state +set_pointers +~DataHash +DataHash +__ZL11UnixSymlinkPKcPKwP7RarTimeS4_ +__ZL16CalcAllowedDepthPKw +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/extinfo.cpp +ExtractSymlink +CalcAllowedDepth +SetFileHeaderExtra +SetExtraInfo +SetExtraInfo20 +ExtractUnixLink50 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/ulinks.cpp +UnixSymlink +IsRelativeSymlinkSafe +LinkInPath +ExtractUnixLink30 +SetUnixOwner +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/uowners.cpp +ExtractUnixOwner30 +ExtractUnixOwner20 +GetStreamNameNTFS +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/win32stm.cpp +ExtractHardlink +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/hardlinks.cpp +SlashToNative +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/pathfn.hpp +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/extract.cpp +UnstoreFile +ExtractFileCopy +uiMsg +ExtrCreateFile +SetHandleType +ExtrCreateDir +ExtrDllGetPassword +CheckUnpVer +ExtrPrepareName +ExtractCurrentFile +SetAllowDelete +SetSkipUnpCRC +operator< +operator>= +ItemsCount +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/strlist.hpp +ExtractArchiveInit +ExtractArchive +DoExtract +GetErrorCount +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/errhnd.hpp +GetErrorCode +SetCurrentCommand +~CmdExtract +CmdExtract +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/volume.cpp +MergeArchive +DllVolNotify +DllVolChange +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/find.cpp +FastFind +Next +uiMsg +SetMask +~FindFile +FindFile +__ZZN8ModelPPM16RestartModelRareEvE10InitBinEsc +__ZZN6Unpack7ShortLZEvE9ShortLen1 +__ZZN6Unpack7ShortLZEvE9ShortXor1 +__ZZN6Unpack7ShortLZEvE9ShortLen2 +__ZZN6Unpack7ShortLZEvE9ShortXor2 +__ZL5DecL2 +__ZL5PosL2 +__ZL5DecL1 +__ZL5PosL1 +__ZL6DecHf2 +__ZL6PosHf2 +__ZL6DecHf1 +__ZL6PosHf1 +__ZL6DecHf0 +__ZL6PosHf0 +__ZL6DecHf4 +__ZL6PosHf4 +__ZL6DecHf3 +__ZL6PosHf3 +__ZZN6Unpack8Unpack20EbE7DDecode +__ZZN6Unpack8Unpack20EbE5DBits +__ZZN6Unpack8Unpack29EbE7LDecode +__ZZN6Unpack8Unpack29EbE5LBits +__ZZN6Unpack8Unpack29EbE7DDecode +__ZZN6Unpack8Unpack29EbE5DBits +__ZZN6Unpack8Unpack29EbE16DBitLengthCounts +__ZZN6Unpack8Unpack29EbE8SDDecode +__ZZN6Unpack8Unpack29EbE6SDBits +__ZL9ExpEscape +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/unpack.cpp +CreateSuccessors +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/model.cpp +createChild +AllocContext +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/suballoc.cpp +RemoveNode +DoUnpack +~Unpack +~FragmentedWindow +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/unpack50frag.cpp +~ModelPPM +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/model.hpp +~SubAllocator +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/suballoc.hpp +StopSubAllocator +Unpack +UnpInitData15 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/unpack15.cpp +ModelPPM +SubAllocator +FragmentedWindow +UnpInitData50 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/unpack50.cpp +UnpWriteData +GetBlockSize +ApplyFilter +CopyData +InitFilters +ReadFilterData +AddFilter +ReadFilter +CopyString +getbits32 +UnpWriteBuf +ReadTables +DecodeNumber +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/unpackinline.cpp +ReadBlockHeader +Unpack5 +SlotToLength +InsertOldDist +UnpInitData30 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/unpack30.cpp +ExecuteCode +UnpWriteArea +InitFilters30 +AddVMCode +Overflow +UnpackFilter30 +VM_PreparedProgram +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/rarvm.hpp +InitBitInput +ReadVMCode +ReadEndOfBlock +ReadVMCodePPM +SafePPMDecodeChar +UnpWriteBuf30 +ReadTables30 +UnpReadBuf30 +Unpack29 +UnpInitData20 +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/unpack20.cpp +MakeDecodeTables +ReadLastTables +DecodeAudio +ReadTables20 +Unpack20 +CopyString20 +CorrHuff +DecodeNum +CopyString15 +ShortLZ +LongLZ +HuffDecode +UnpWriteBuf20 +GetFlagsBuf +InitHuff +UnpReadBuf +UnpInitData +Unpack15 +UpdateModel +AllocUnits +U2B +ExpandUnits +InsertNode +_PPMD_SWAP +decodeSymbol2 +update2 +update +GetCurrentCount +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/coder.cpp +makeEscFreq2 +getMean +decodeSymbol1 +update1 +DecodeChar +ClearMask +decodeBinSymbol +GetCurrentShiftCount +GetChar +DecodeInit +GetAllocatedMemory +CleanUp +rescale +ShrinkUnits +SplitBlock +FreeUnits +StartModelRare +RestartModelRare +GlueFreeBlocks +MBPtr +insertAt +AllocUnitsRare +InitSubAllocator +StartSubAllocator +InitDecoder +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/headers.cpp +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/cmddata.cpp +ReportWrongSwitches +uiMsg +CheckWinSize +GetArcName +AddArcName +ProcessCommand +~StringList +IsProcessFile +SizeCheck +TimeCheck +operator<= +ExclDirByAttr +CheckArgs +ExclCheck +OutTitle +OutHelp +eprintf +GetExclAttr +BadSwitch +ReadConfig +ProcessSwitchesString +AllocCmdParam +IsSwitch +ParseEnvVar +ProcessSwitch +ParseDone +ParseArg +PreprocessArg +ParseCommandLine +CommandData +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/ui.cpp +uiGetMonthName +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/uisilent.cpp +uiGiveTick +uiIsAborted +uiAlarm +uiGetPassword +Msg +uiProcessProgress +uiExtractProgress +uiStartFileExtract +uiStartArchiveExtract +uiAskReplace +uiAskReplaceEx +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/uicommon.cpp +uiInit +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/filestr.cpp +DetectTextEncoding +ReadTextFile +operator+ +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/scantree.cpp +ScanError +GetFilteredMask +ExpandFolderMask +FindProc +GetNextMask +GetNext +~ScanTree +ScanTree +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/qopen.cpp +ReadRaw +ReadNext +ReadBuffer +Load +SetProhibitQOpen +~QuickOpen +QuickOpen +__ZL13RarErrorToDll8RAR_EXIT +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/dll.cpp +DataSet +~CommandData +/Users/travis/build/abbeycode/UnrarKit/Libraries/unrar/cmddata.hpp +RARGetDllVersion +RARSetPassword +RARSetProcessDataProc +RARSetCallback +RARSetChangeVolProc +RARProcessFileW +ProcessFile +RARProcessFile +RARReadHeaderEx +RARReadHeader +RARCloseArchive +~DataSet +RarErrorToDll +RAROpenArchiveEx +RAROpenArchive diff --git a/Carthage/Build/iOS/UnrarKit.framework.dSYM/Contents/Info.plist b/Carthage/Build/iOS/UnrarKit.framework.dSYM/Contents/Info.plist new file mode 100644 index 0000000..c7fe283 --- /dev/null +++ b/Carthage/Build/iOS/UnrarKit.framework.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.com.abbey-code.UnrarKit + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 2.9 + CFBundleVersion + 2.9 + + diff --git a/Carthage/Build/iOS/UnrarKit.framework.dSYM/Contents/Resources/DWARF/UnrarKit b/Carthage/Build/iOS/UnrarKit.framework.dSYM/Contents/Resources/DWARF/UnrarKit new file mode 100644 index 0000000..1aa0730 Binary files /dev/null and b/Carthage/Build/iOS/UnrarKit.framework.dSYM/Contents/Resources/DWARF/UnrarKit differ diff --git a/Carthage/Build/iOS/UnrarKit.framework/Headers/URKArchive.h b/Carthage/Build/iOS/UnrarKit.framework/Headers/URKArchive.h new file mode 100644 index 0000000..bd064cb --- /dev/null +++ b/Carthage/Build/iOS/UnrarKit.framework/Headers/URKArchive.h @@ -0,0 +1,496 @@ +// +// URKArchive.h +// UnrarKit +// +// + +#import +#import +#import "UnrarKitMacros.h" + +RarosHppIgnore +#import "raros.hpp" +#pragma clang diagnostic pop + +DllHppIgnore +#import "dll.hpp" +#pragma clang diagnostic pop + +@class URKFileInfo; + +/** + * Defines the various error codes that the listing and extraction methods return. + * These are returned in NSError's [code]([NSError code]) field. + */ +typedef NS_ENUM(NSInteger, URKErrorCode) { + + /** + * The archive's header is empty + */ + URKErrorCodeEndOfArchive = ERAR_END_ARCHIVE, + + /** + * The library ran out of memory while reading the archive + */ + URKErrorCodeNoMemory = ERAR_NO_MEMORY, + + /** + * The header is broken + */ + URKErrorCodeBadData = ERAR_BAD_DATA, + + /** + * The archive is not a valid RAR file + */ + URKErrorCodeBadArchive = ERAR_BAD_ARCHIVE, + + /** + * The archive is an unsupported RAR format or version + */ + URKErrorCodeUnknownFormat = ERAR_UNKNOWN_FORMAT, + + /** + * Failed to open a reference to the file + */ + URKErrorCodeOpen = ERAR_EOPEN, + + /** + * Failed to create the target directory for extraction + */ + URKErrorCodeCreate = ERAR_ECREATE, + + /** + * Failed to close the archive + */ + URKErrorCodeClose = ERAR_ECLOSE, + + /** + * Failed to read the archive + */ + URKErrorCodeRead = ERAR_EREAD, + + /** + * Failed to write a file to disk + */ + URKErrorCodeWrite = ERAR_EWRITE, + + /** + * The archive header's comments are larger than the buffer size + */ + URKErrorCodeSmall = ERAR_SMALL_BUF, + + /** + * The cause of the error is unspecified + */ + URKErrorCodeUnknown = ERAR_UNKNOWN, + + /** + * A password was not given for a password-protected archive + */ + URKErrorCodeMissingPassword = ERAR_MISSING_PASSWORD, + + /** + * No data was returned from the archive + */ + URKErrorCodeArchiveNotFound = 101, + + /** + * User cancelled the operation + */ + URKErrorCodeUserCancelled = 102, + + /** + * Error converting string to UTF-8 + */ + URKErrorCodeStringConversion = 103, +}; + +typedef NSString *const URKProgressInfoKey; + + +/** + * Defines the keys passed in `-[NSProgress userInfo]` for certain methods + */ +static URKProgressInfoKey _Nonnull + /** + * For `extractFilesTo:overwrite:error:`, this key contains an instance of URKFileInfo with the file currently being extracted + */ + URKProgressInfoKeyFileInfoExtracting = @"URKProgressInfoKeyFileInfoExtracting"; + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *URKErrorDomain; + +/** + * An Objective-C/Cocoa wrapper around the unrar library + */ +@interface URKArchive : NSObject +// Minimum of iOS 9, macOS 10.11 SDKs +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED > 90000) || (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED > 101100) + +#endif + + +/** + * The URL of the archive + */ +@property(nullable, weak, atomic, readonly) NSURL *fileURL; + +/** + * The filename of the archive + */ +@property(nullable, weak, atomic, readonly) NSString *filename; + +/** + * The password of the archive + */ +@property(nullable, nonatomic, strong) NSString *password; + +/** + * The total uncompressed size (in bytes) of all files in the archive. Returns nil on errors + */ +@property(nullable, atomic, readonly) NSNumber *uncompressedSize; + +/** + * The total compressed size (in bytes) of the archive. Returns nil on errors + */ +@property(nullable, atomic, readonly) NSNumber *compressedSize; + +/** + * True if the file is one volume of a multi-part archive + */ +@property(atomic, readonly) BOOL hasMultipleVolumes; + +/** + * Can be used for progress reporting, but it's not necessary. You can also use + * implicit progress reporting. If you don't use it, one will still be created, + * which will become a child progress of whichever one is the current NSProgress + * instance. + * + * To use this, assign it before beginning an operation that reports progress. Once + * the method you're calling has a reference to it, it will nil it out. Please check + * for nil before assigning it to avoid concurrency conflicts. + */ +@property(nullable, strong) NSProgress *progress; + + +/** + * **DEPRECATED:** Creates and returns an archive at the given path + * + * @param filePath A path to the archive file + */ ++ (nullable instancetype)rarArchiveAtPath:(NSString *)filePath __deprecated_msg("Use -initWithPath:error: instead"); + +/** + * **DEPRECATED:** Creates and returns an archive at the given URL + * + * @param fileURL The URL of the archive file + */ ++ (nullable instancetype)rarArchiveAtURL:(NSURL *)fileURL __deprecated_msg("Use -initWithURL:error: instead"); + +/** + * **DEPRECATED:** Creates and returns an archive at the given path, with a given password + * + * @param filePath A path to the archive file + * @param password The passowrd of the given archive + */ ++ (nullable instancetype)rarArchiveAtPath:(NSString *)filePath password:(NSString *)password __deprecated_msg("Use -initWithPath:password:error: instead"); + +/** + * **DEPRECATED:** Creates and returns an archive at the given URL, with a given password + * + * @param fileURL The URL of the archive file + * @param password The passowrd of the given archive + */ ++ (nullable instancetype)rarArchiveAtURL:(NSURL *)fileURL password:(NSString *)password __deprecated_msg("Use -initWithURL:password:error: instead"); + + +/** + * Do not use the default initializer + */ +- (instancetype)init NS_UNAVAILABLE; + +/** + * Creates and returns an archive at the given path + * + * @param filePath A path to the archive file + * @param error Contains any error during initialization + * + * @return Returns an initialized URKArchive, unless there's a problem creating a bookmark to the path + */ +- (nullable instancetype)initWithPath:(NSString *)filePath error:(NSError **)error; + +/** + * Creates and returns an archive at the given URL + * + * @param fileURL The URL of the archive file + * @param error Contains any error during initialization + * + * @return Returns an initialized URKArchive, unless there's a problem creating a bookmark to the URL + */ +- (nullable instancetype)initWithURL:(NSURL *)fileURL error:(NSError **)error; + +/** + * Creates and returns an archive at the given path, with a given password + * + * @param filePath A path to the archive file + * @param password The passowrd of the given archive + * @param error Contains any error during initialization + * + * @return Returns an initialized URKArchive, unless there's a problem creating a bookmark to the path + */ +- (nullable instancetype)initWithPath:(NSString *)filePath password:(NSString *)password error:(NSError **)error; + +/** + * Creates and returns an archive at the given URL, with a given password + * + * @param fileURL The URL of the archive file + * @param password The passowrd of the given archive + * @param error Contains any error during initialization + * + * @return Returns an initialized URKArchive, unless there's a problem creating a bookmark to the URL + */ +- (nullable instancetype)initWithURL:(NSURL *)fileURL password:(NSString *)password error:(NSError **)error; + + +/** + * Determines whether a file is a RAR archive by reading the signature + * + * @param filePath Path to the file being checked + * + * @return YES if the file exists and contains a signature indicating it is a RAR archive + */ ++ (BOOL)pathIsARAR:(NSString *)filePath; + +/** + * Determines whether a file is a RAR archive by reading the signature + * + * @param fileURL URL of the file being checked + * + * @return YES if the file exists and contains a signature indicating it is a RAR archive + */ ++ (BOOL)urlIsARAR:(NSURL *)fileURL; + +/** + * Lists the names of the files in the archive + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return Returns a list of NSString containing the paths within the archive's contents, or nil if an error was encountered + */ +- (nullable NSArray *)listFilenames:(NSError **)error; + +/** + * Lists the various attributes of each file in the archive + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return Returns a list of URKFileInfo objects, which contain metadata about the archive's files, or nil if an error was encountered + */ +- (nullable NSArray *)listFileInfo:(NSError **)error; + +/** + * Iterates the header of the archive, calling the block with each archived file's info. + * + * WARNING: There is no filtering of duplicate header entries. If a file is listed twice, `action` + * will be called twice with that file's path + * + * @param action The action to perform using the data. Must be non-nil + * + * - *fileInfo* The metadata of the file within the archive + * - *stop* Set to YES to stop reading the archive + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return Returns NO if an error was encountered + */ +- (BOOL) iterateFileInfo:(void(^)(URKFileInfo *fileInfo, BOOL *stop))action + error:(NSError **)error; + +/** + * Lists the URLs of volumes in a single- or multi-volume archive + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return Returns the list of URLs of all volumes of the archive + */ +- (nullable NSArray *)listVolumeURLs:(NSError **)error; + +/** + * Writes all files in the archive to the given path. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction. Use the progress property (as explained in the README) to + * retrieve more detailed information, such as the current file being extracted, number of files extracted, + * and the URKFileInfo instance being extracted + * + * @param filePath The destination path of the unarchived files + * @param overwrite YES to overwrite files in the destination directory, NO otherwise + * @param error Contains an NSError object when there was an error reading the archive + * + * @return YES on successful extraction, NO if an error was encountered + */ +- (BOOL)extractFilesTo:(NSString *)filePath + overwrite:(BOOL)overwrite + error:(NSError **)error; + +/** + * **DEPRECATED:** Writes all files in the archive to the given path + * + * @param filePath The destination path of the unarchived files + * @param overwrite YES to overwrite files in the destination directory, NO otherwise + * @param progressBlock Called every so often to report the progress of the extraction + * + * - *currentFile* The info about the file that's being extracted + * - *percentArchiveDecompressed* The percentage of the archive that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return YES on successful extraction, NO if an error was encountered + */ +- (BOOL)extractFilesTo:(NSString *)filePath + overwrite:(BOOL)overwrite + progress:(nullable void (^)(URKFileInfo *currentFile, CGFloat percentArchiveDecompressed))progressBlock + error:(NSError **)error __deprecated_msg("Use -extractFilesTo:overwrite:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * Unarchive a single file from the archive into memory. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction + * + * @param fileInfo The info of the file within the archive to be expanded. Only the filename property is used + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractData:(URKFileInfo *)fileInfo + error:(NSError **)error; + +/** + * **DEPRECATED:** Unarchive a single file from the archive into memory + * + * @param fileInfo The info of the file within the archive to be expanded. Only the filename property is used + * @param progressBlock Called every so often to report the progress of the extraction + * + * - *percentDecompressed* The percentage of the archive that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractData:(URKFileInfo *)fileInfo + progress:(nullable void (^)(CGFloat percentDecompressed))progressBlock + error:(NSError **)error __deprecated_msg("Use -extractData:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * Unarchive a single file from the archive into memory. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction + * + * @param filePath The path of the file within the archive to be expanded + * + * - *percentDecompressed* The percentage of the file that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractDataFromFile:(NSString *)filePath + error:(NSError **)error; + +/** + * **DEPRECATED:** Unarchive a single file from the archive into memory + * + * @param filePath The path of the file within the archive to be expanded + * @param progressBlock Called every so often to report the progress of the extraction + * + * - *percentDecompressed* The percentage of the file that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractDataFromFile:(NSString *)filePath + progress:(nullable void (^)(CGFloat percentDecompressed))progressBlock + error:(NSError **)error __deprecated_msg("Use -extractDataFromFile:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * Loops through each file in the archive in alphabetical order, allowing you to perform an + * action using its info. Supports NSProgress for progress reporting, which also allows + * cancellation of the operation in the middle + * + * @param action The action to perform using the data + * + * - *fileInfo* The metadata of the file within the archive + * - *stop* Set to YES to stop reading the archive + * + * @param error Contains an error if any was returned + * + * @return YES if no errors were encountered, NO otherwise + */ +- (BOOL)performOnFilesInArchive:(void(^)(URKFileInfo *fileInfo, BOOL *stop))action + error:(NSError **)error; + +/** + * Extracts each file in the archive into memory, allowing you to perform an action + * on it (not sorted). Supports NSProgress for progress reporting, which also allows + * cancellation of the operation in the middle + * + * @param action The action to perform using the data + * + * - *fileInfo* The metadata of the file within the archive + * - *fileData* The full data of the file in the archive + * - *stop* Set to YES to stop reading the archive + * + * @param error Contains an error if any was returned + * + * @return YES if no errors were encountered, NO otherwise + */ +- (BOOL)performOnDataInArchive:(void(^)(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop))action + error:(NSError **)error; + +/** + * Unarchive a single file from the archive into memory. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction + * + * @param filePath The path of the file within the archive to be expanded + * @param error Contains an NSError object when there was an error reading the archive + * @param action The block to run for each chunk of data, each of size <= bufferSize + * + * - *dataChunk* The data read from the archived file. Read bytes and length to write the data + * - *percentDecompressed* The percentage of the file that has been decompressed + * + * @return YES if all data was read successfully, NO if an error was encountered + */ +- (BOOL)extractBufferedDataFromFile:(NSString *)filePath + error:(NSError **)error + action:(void(^)(NSData *dataChunk, CGFloat percentDecompressed))action; + +/** + * YES if archive protected with a password, NO otherwise + */ +- (BOOL)isPasswordProtected; + +/** + * Tests whether the provided password unlocks the archive + * + * @return YES if correct password or archive is not password protected, NO if password is wrong + */ +- (BOOL)validatePassword; + +/** + Extract each file in the archive, checking whether the data matches the CRC checksum + stored at the time it was written + + @return YES if the data is all correct, false if any check failed + */ +- (BOOL)checkDataIntegrity; + +/** + Extract a particular file, to determine if its data matches the CRC + checksum stored at the time it written + + @param filePath The file in the archive to check + + @return YES if the data is correct, false if any check failed + */ +- (BOOL)checkDataIntegrityOfFile:(NSString *)filePath; + +@end +NS_ASSUME_NONNULL_END diff --git a/Carthage/Build/iOS/UnrarKit.framework/Headers/URKFileInfo.h b/Carthage/Build/iOS/UnrarKit.framework/Headers/URKFileInfo.h new file mode 100644 index 0000000..5bf2c95 --- /dev/null +++ b/Carthage/Build/iOS/UnrarKit.framework/Headers/URKFileInfo.h @@ -0,0 +1,158 @@ +// +// URKFileInfo.h +// UnrarKit +// + +#import +#import "UnrarKitMacros.h" + +RarosHppIgnore +#import "raros.hpp" +#pragma clang diagnostic pop + +DllHppIgnore +#import "dll.hpp" +#pragma clang diagnostic pop + +/* See http://www.forensicswiki.org/wiki/RAR and + http://www.rarlab.com/technote.htm#filehead for + more information about the RAR File Header spec */ + +/** + * Defines the packing methods that can be used on a file in an archive + */ +typedef NS_ENUM(NSUInteger, URKCompressionMethod) { + + /** + * No compression is used + */ + URKCompressionMethodStorage = 0x30, + + /** + * Fastest compression + */ + URKCompressionMethodFastest = 0x31, + + /** + * Fast compression + */ + URKCompressionMethodFast = 0x32, + + /** + * Normal compression + */ + URKCompressionMethodNormal = 0x33, + + /** + * Good compression + */ + URKCompressionMethodGood = 0x34, + + /** + * Best compression + */ + URKCompressionMethodBest = 0x35, +}; + +/** + * Defines the various operating systems that can be used when archiving + */ +typedef NS_ENUM(NSUInteger, URKHostOS) { + + /** + * MS-DOS + */ + URKHostOSMSDOS = 0, + + /** + * OS/2 + */ + URKHostOSOS2 = 1, + + /** + * Windows + */ + URKHostOSWindows = 2, + + /** + * Unix + */ + URKHostOSUnix = 3, + + /** + * Mac OS + */ + URKHostOSMacOS = 4, + + /** + * BeOS + */ + URKHostOSBeOS = 5, +}; + +/** + * A wrapper around a RAR archive's file header, defining the various fields + * it contains + */ +@interface URKFileInfo : NSObject + +/** + * The name of the file's archive + */ +@property (readonly, strong) NSString *archiveName; + +/** + * The name of the file + */ +@property (readonly, strong) NSString *filename; + +/** + * The timestamp of the file + */ +@property (readonly, strong) NSDate *timestamp; + +/** + * The CRC checksum of the file + */ +@property (readonly, assign) NSUInteger CRC; + +/** + * Size of the uncompressed file + */ +@property (readonly, assign) long long uncompressedSize; + +/** + * Size of the compressed file + */ +@property (readonly, assign) long long compressedSize; + +/** + * YES if the file will be continued of the next volume + */ +@property (readonly) BOOL isEncryptedWithPassword; + +/** + * YES if the file is a directory + */ +@property (readonly) BOOL isDirectory; + +/** + * The type of compression + */ +@property (readonly, assign) URKCompressionMethod compressionMethod; + +/** + * The OS of the file + */ +@property (readonly, assign) URKHostOS hostOS; + +/** + * Returns a URKFileInfo instance for the given extended header data + * + * @param fileHeader The header data for a RAR file + * + * @return an instance of URKFileInfo + */ ++ (instancetype) fileInfo:(struct RARHeaderDataEx *)fileHeader; + +@end diff --git a/Carthage/Build/iOS/UnrarKit.framework/Headers/UnrarKit.h b/Carthage/Build/iOS/UnrarKit.framework/Headers/UnrarKit.h new file mode 100644 index 0000000..78db3b3 --- /dev/null +++ b/Carthage/Build/iOS/UnrarKit.framework/Headers/UnrarKit.h @@ -0,0 +1,19 @@ +// +// UnrarKit.h +// UnrarKit +// +// Created by Dov Frankel on 1/9/2015. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import + +//! Project version number for UnrarKit. +FOUNDATION_EXPORT double UnrarKitVersionNumber; + +//! Project version string for UnrarKit. +FOUNDATION_EXPORT const unsigned char UnrarKitVersionString[]; + + +#import "URKArchive.h" +#import "URKFileInfo.h" diff --git a/Carthage/Build/iOS/UnrarKit.framework/Headers/UnrarKitMacros.h b/Carthage/Build/iOS/UnrarKit.framework/Headers/UnrarKitMacros.h new file mode 100644 index 0000000..aea9343 --- /dev/null +++ b/Carthage/Build/iOS/UnrarKit.framework/Headers/UnrarKitMacros.h @@ -0,0 +1,126 @@ +// +// UnrarKitMacros.h +// UnrarKit +// +// Created by Dov Frankel on 8/8/17. +// Copyright © 2017 Abbey Code. All rights reserved. +// + +#ifndef UnrarKitMacros_h +#define UnrarKitMacros_h + +//#import "Availability.h" +//#import "AvailabilityInternal.h" + +#define _stringify(a) #a + +#define RarHppIgnore \ +_Pragma( _stringify( clang diagnostic push ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wcast-align" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wextra-semi" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wold-style-cast" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wpadded" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wreserved-id-macro" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wshorten-64-to-32" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wcast-qual" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wundef" ) ) \ + +#define DllHppIgnore \ +_Pragma( _stringify( clang diagnostic push ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wreserved-id-macro" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wstrict-prototypes" ) ) \ + +#define RarosHppIgnore \ +_Pragma( _stringify( clang diagnostic push ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wreserved-id-macro" ) ) \ + + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundef" +#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" + + +// iOS 10, macOS 10.12, tvOS 10.0, watchOS 3.0 +#define UNIFIED_LOGGING_SUPPORTED \ +__IPHONE_OS_VERSION_MIN_REQUIRED >= 100000 \ +|| __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200 \ +|| __TV_OS_VERSION_MIN_REQUIRED >= 100000 \ +|| __WATCH_OS_VERSION_MIN_REQUIRED >= 30000 + +#if TARGET_OS_IPHONE +#define SDK_10_13_MAJOR 11 +#define SDK_10_13_MINOR 0 +#else +#define SDK_10_13_MAJOR 10 +#define SDK_10_13_MINOR 13 +#endif + +#if UNIFIED_LOGGING_SUPPORTED +#import +#import + +// Called from +[UnrarKit initialize] and +[URKArchiveTestCase setUp] +extern os_log_t unrarkit_log; // Declared in URKArchive.m +extern BOOL unrarkitIsAtLeast10_13SDK; // Declared in URKArchive.m +#define URKLogInit() \ + unrarkit_log = os_log_create("com.abbey-code.UnrarKit", "General"); \ + \ + NSOperatingSystemVersion minVersion; \ + minVersion.majorVersion = SDK_10_13_MAJOR; \ + minVersion.minorVersion = SDK_10_13_MINOR; \ + minVersion.patchVersion = 0; \ + unrarkitIsAtLeast10_13SDK = [[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:minVersion]; \ + URKLogDebug("Is >= 10.13 (or iOS 11): %@", unrarkitIsAtLeast10_13SDK ? @"YES" : @"NO"); + +#define URKLog(format, ...) os_log(unrarkit_log, format, ##__VA_ARGS__); +#define URKLogInfo(format, ...) os_log_info(unrarkit_log, format, ##__VA_ARGS__); +#define URKLogDebug(format, ...) os_log_debug(unrarkit_log, format, ##__VA_ARGS__); + + +#define URKLogError(format, ...) \ + if (unrarkitIsAtLeast10_13SDK) os_log_error(unrarkit_log, format, ##__VA_ARGS__); \ + else os_log_with_type(unrarkit_log, OS_LOG_TYPE_ERROR, format, ##__VA_ARGS__); + +#define URKLogFault(format, ...) \ + if (unrarkitIsAtLeast10_13SDK) os_log_fault(unrarkit_log, format, ##__VA_ARGS__); \ + else os_log_with_type(unrarkit_log, OS_LOG_TYPE_FAULT, format, ##__VA_ARGS__); + + +#define URKCreateActivity(name) \ +os_activity_t activity = os_activity_create(name, OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); \ +os_activity_scope(activity); + + +#else // Fall back to regular NSLog + +// No-op, as nothing needs to be initialized +#define URKLogInit() (void)0 + + +// Only used below +#define _removeLogFormatTokens(format) [[@format \ + stringByReplacingOccurrencesOfString:@"{public}" withString:@""] \ + stringByReplacingOccurrencesOfString:@"{iec-bytes}" withString:@""] +#define _nsLogWithoutWarnings(format, ...) \ +_Pragma( _stringify( clang diagnostic push ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wformat-nonliteral" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wformat-security" ) ) \ +NSLog(_removeLogFormatTokens(format), ##__VA_ARGS__); \ +_Pragma( _stringify( clang diagnostic pop ) ) + +// All levels do the same thing +#define URKLog(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); +#define URKLogInfo(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); +#define URKLogDebug(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); +#define URKLogError(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); +#define URKLogFault(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); + +// No-op, as no equivalent to Activities exists +#define URKCreateActivity(name) (void)0 + + +#pragma clang diagnostic pop + +#endif // UNIFIED_LOGGING_SUPPORTED + +#endif /* UnrarKitMacros_h */ diff --git a/Carthage/Build/iOS/UnrarKit.framework/Headers/dll.hpp b/Carthage/Build/iOS/UnrarKit.framework/Headers/dll.hpp new file mode 100644 index 0000000..7f82906 --- /dev/null +++ b/Carthage/Build/iOS/UnrarKit.framework/Headers/dll.hpp @@ -0,0 +1,185 @@ +#ifndef _UNRAR_DLL_ +#define _UNRAR_DLL_ + +#pragma pack(1) + +#define ERAR_SUCCESS 0 +#define ERAR_END_ARCHIVE 10 +#define ERAR_NO_MEMORY 11 +#define ERAR_BAD_DATA 12 +#define ERAR_BAD_ARCHIVE 13 +#define ERAR_UNKNOWN_FORMAT 14 +#define ERAR_EOPEN 15 +#define ERAR_ECREATE 16 +#define ERAR_ECLOSE 17 +#define ERAR_EREAD 18 +#define ERAR_EWRITE 19 +#define ERAR_SMALL_BUF 20 +#define ERAR_UNKNOWN 21 +#define ERAR_MISSING_PASSWORD 22 +#define ERAR_EREFERENCE 23 +#define ERAR_BAD_PASSWORD 24 + +#define RAR_OM_LIST 0 +#define RAR_OM_EXTRACT 1 +#define RAR_OM_LIST_INCSPLIT 2 + +#define RAR_SKIP 0 +#define RAR_TEST 1 +#define RAR_EXTRACT 2 + +#define RAR_VOL_ASK 0 +#define RAR_VOL_NOTIFY 1 + +#define RAR_DLL_VERSION 8 + +#define RAR_HASH_NONE 0 +#define RAR_HASH_CRC32 1 +#define RAR_HASH_BLAKE2 2 + + +#ifdef _UNIX +#define CALLBACK +#define PASCAL +#define LONG long +#define HANDLE void * +#define LPARAM long +#define UINT unsigned int +#endif + +#define RHDF_SPLITBEFORE 0x01 +#define RHDF_SPLITAFTER 0x02 +#define RHDF_ENCRYPTED 0x04 +#define RHDF_SOLID 0x10 +#define RHDF_DIRECTORY 0x20 + + +struct RARHeaderData +{ + char ArcName[260]; + char FileName[260]; + unsigned int Flags; + unsigned int PackSize; + unsigned int UnpSize; + unsigned int HostOS; + unsigned int FileCRC; + unsigned int FileTime; + unsigned int UnpVer; + unsigned int Method; + unsigned int FileAttr; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; +}; + + +struct RARHeaderDataEx +{ + char ArcName[1024]; + wchar_t ArcNameW[1024]; + char FileName[1024]; + wchar_t FileNameW[1024]; + unsigned int Flags; + unsigned int PackSize; + unsigned int PackSizeHigh; + unsigned int UnpSize; + unsigned int UnpSizeHigh; + unsigned int HostOS; + unsigned int FileCRC; + unsigned int FileTime; + unsigned int UnpVer; + unsigned int Method; + unsigned int FileAttr; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; + unsigned int DictSize; + unsigned int HashType; + char Hash[32]; + unsigned int RedirType; + wchar_t *RedirName; + unsigned int RedirNameSize; + unsigned int DirTarget; + unsigned int MtimeLow; + unsigned int MtimeHigh; + unsigned int CtimeLow; + unsigned int CtimeHigh; + unsigned int AtimeLow; + unsigned int AtimeHigh; + unsigned int Reserved[988]; +}; + + +struct RAROpenArchiveData +{ + char *ArcName; + unsigned int OpenMode; + unsigned int OpenResult; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; +}; + +typedef int (CALLBACK *UNRARCALLBACK)(UINT msg,LPARAM UserData,LPARAM P1,LPARAM P2); + +#define ROADF_VOLUME 0x0001 +#define ROADF_COMMENT 0x0002 +#define ROADF_LOCK 0x0004 +#define ROADF_SOLID 0x0008 +#define ROADF_NEWNUMBERING 0x0010 +#define ROADF_SIGNED 0x0020 +#define ROADF_RECOVERY 0x0040 +#define ROADF_ENCHEADERS 0x0080 +#define ROADF_FIRSTVOLUME 0x0100 + +struct RAROpenArchiveDataEx +{ + char *ArcName; + wchar_t *ArcNameW; + unsigned int OpenMode; + unsigned int OpenResult; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; + unsigned int Flags; + UNRARCALLBACK Callback; + LPARAM UserData; + unsigned int Reserved[28]; +}; + +enum UNRARCALLBACK_MESSAGES { + UCM_CHANGEVOLUME,UCM_PROCESSDATA,UCM_NEEDPASSWORD,UCM_CHANGEVOLUMEW, + UCM_NEEDPASSWORDW +}; + +typedef int (PASCAL *CHANGEVOLPROC)(char *ArcName,int Mode); +typedef int (PASCAL *PROCESSDATAPROC)(unsigned char *Addr,int Size); + +#ifdef __cplusplus +extern "C" { +#endif + +HANDLE PASCAL RAROpenArchive(struct RAROpenArchiveData *ArchiveData); +HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *ArchiveData); +int PASCAL RARCloseArchive(HANDLE hArcData); +int PASCAL RARReadHeader(HANDLE hArcData,struct RARHeaderData *HeaderData); +int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *HeaderData); +int PASCAL RARProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName); +int PASCAL RARProcessFileW(HANDLE hArcData,int Operation,wchar_t *DestPath,wchar_t *DestName); +void PASCAL RARSetCallback(HANDLE hArcData,UNRARCALLBACK Callback,LPARAM UserData); +void PASCAL RARSetChangeVolProc(HANDLE hArcData,CHANGEVOLPROC ChangeVolProc); +void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataProc); +void PASCAL RARSetPassword(HANDLE hArcData,char *Password); +int PASCAL RARGetDllVersion(); + +#ifdef __cplusplus +} +#endif + +#pragma pack() + +#endif diff --git a/Carthage/Build/iOS/UnrarKit.framework/Headers/raros.hpp b/Carthage/Build/iOS/UnrarKit.framework/Headers/raros.hpp new file mode 100644 index 0000000..4f4f2ae --- /dev/null +++ b/Carthage/Build/iOS/UnrarKit.framework/Headers/raros.hpp @@ -0,0 +1,36 @@ +#ifndef _RAR_RAROS_ +#define _RAR_RAROS_ + +#ifdef __EMX__ + #define _EMX +#endif + +#ifdef __DJGPP__ + #define _DJGPP + #define _EMX +#endif + +#if defined(__WIN32__) || defined(_WIN32) + #define _WIN_ALL // Defined for all Windows platforms, 32 and 64 bit, mobile and desktop. + #ifdef _M_X64 + #define _WIN_64 + #else + #define _WIN_32 + #endif +#endif + +#if defined(ANDROID) || defined(__ANDROID__) + #define _UNIX + #define _ANDROID +#endif + +#ifdef __APPLE__ + #define _UNIX + #define _APPLE +#endif + +#if !defined(_EMX) && !defined(_WIN_ALL) && !defined(_BEOS) && !defined(_APPLE) + #define _UNIX +#endif + +#endif diff --git a/Carthage/Build/iOS/UnrarKit.framework/Info.plist b/Carthage/Build/iOS/UnrarKit.framework/Info.plist new file mode 100644 index 0000000..66dcb2e Binary files /dev/null and b/Carthage/Build/iOS/UnrarKit.framework/Info.plist differ diff --git a/Carthage/Build/iOS/UnrarKit.framework/Modules/module.modulemap b/Carthage/Build/iOS/UnrarKit.framework/Modules/module.modulemap new file mode 100644 index 0000000..ba14d5a --- /dev/null +++ b/Carthage/Build/iOS/UnrarKit.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module UnrarKit { + umbrella header "UnrarKit.h" + + export * + module * { export * } +} diff --git a/Carthage/Build/iOS/UnrarKit.framework/UnrarKit b/Carthage/Build/iOS/UnrarKit.framework/UnrarKit new file mode 100755 index 0000000..23fe062 Binary files /dev/null and b/Carthage/Build/iOS/UnrarKit.framework/UnrarKit differ diff --git a/Carthage/Build/iOS/UnrarKit.framework/UnrarKitResources.bundle/Info.plist b/Carthage/Build/iOS/UnrarKit.framework/UnrarKitResources.bundle/Info.plist new file mode 100644 index 0000000..30476c2 Binary files /dev/null and b/Carthage/Build/iOS/UnrarKit.framework/UnrarKitResources.bundle/Info.plist differ diff --git a/Carthage/Build/iOS/UnrarKit.framework/UnrarKitResources.bundle/en.lproj/UnrarKit.strings b/Carthage/Build/iOS/UnrarKit.framework/UnrarKitResources.bundle/en.lproj/UnrarKit.strings new file mode 100644 index 0000000..d52de02 Binary files /dev/null and b/Carthage/Build/iOS/UnrarKit.framework/UnrarKitResources.bundle/en.lproj/UnrarKit.strings differ diff --git a/Carthage/Build/iOS/UnzipKit.framework.dSYM/Contents/Info.plist b/Carthage/Build/iOS/UnzipKit.framework.dSYM/Contents/Info.plist new file mode 100644 index 0000000..ef5a736 --- /dev/null +++ b/Carthage/Build/iOS/UnzipKit.framework.dSYM/Contents/Info.plist @@ -0,0 +1,20 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + com.apple.xcode.dsym.com.abbey-code.UnzipKit + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + dSYM + CFBundleSignature + ???? + CFBundleShortVersionString + 1.9 + CFBundleVersion + 1.9 + + diff --git a/Carthage/Build/iOS/UnzipKit.framework.dSYM/Contents/Resources/DWARF/UnzipKit b/Carthage/Build/iOS/UnzipKit.framework.dSYM/Contents/Resources/DWARF/UnzipKit new file mode 100644 index 0000000..12696d1 Binary files /dev/null and b/Carthage/Build/iOS/UnzipKit.framework.dSYM/Contents/Resources/DWARF/UnzipKit differ diff --git a/Carthage/Build/iOS/UnzipKit.framework/Headers/UZKArchive.h b/Carthage/Build/iOS/UnzipKit.framework/Headers/UZKArchive.h new file mode 100644 index 0000000..ce99538 --- /dev/null +++ b/Carthage/Build/iOS/UnzipKit.framework/Headers/UZKArchive.h @@ -0,0 +1,949 @@ +// +// UZKArchive.h +// UnzipKit +// +// + +#import +#import + +#import "UZKFileInfo.h" + +/** + * Defines the various error codes that the listing and extraction methods return. + * These are returned in NSError's [code]([NSError code]) field. + */ +typedef NS_ENUM(NSInteger, UZKErrorCode) { + + /** + * An error from zlib reading or writing the file (UNZ_ERRNO/ZIP_ERRNO) + */ + UZKErrorCodeZLibError = -1, + + /** + * An error with a parameter, usually the file name (UNZ_PARAMERROR/ZIP_PARAMERROR) + */ + UZKErrorCodeParameterError = -102, + + /** + * The Zip file appears to be corrupted, or invalid (UNZ_BADZIPFILE/ZIP_BADZIPFILE) + */ + UZKErrorCodeBadZipFile = -103, + + /** + * An error internal to MiniZip (UNZ_INTERNALERROR/ZIP_INTERNALERROR) + */ + UZKErrorCodeInternalError = -104, + + /** + * The decompressed file's CRC doesn't match the original file's CRC (UNZ_CRCERROR) + */ + UZKErrorCodeCRCError = -105, + + /** + * Failure to find/open the archive + */ + UZKErrorCodeArchiveNotFound = 101, + + /** + * Error reading or advancing through the archive + */ + UZKErrorCodeFileNavigationError = 102, + + /** + * Error finding a file in the archive + */ + UZKErrorCodeFileNotFoundInArchive = 103, + + /** + * Error writing an extracted file to disk + */ + UZKErrorCodeOutputError = 104, + + /** + * The destination directory is a file. Not used anymore + */ + UZKErrorCodeOutputErrorPathIsAFile = 105, + + /** + * Password given doesn't decrypt the archive + */ + UZKErrorCodeInvalidPassword = 106, + + /** + * Error reading a file in the archive + */ + UZKErrorCodeFileRead = 107, + + /** + * Error opening a file in the archive for writing + */ + UZKErrorCodeFileOpenForWrite = 108, + + /** + * Error writing a file in the archive + */ + UZKErrorCodeFileWrite = 109, + + /** + * Error closing the file in the archive + */ + UZKErrorCodeFileCloseWriting = 110, + + /** + * Error deleting a file in the archive + */ + UZKErrorCodeDeleteFile = 111, + + /** + * Tried to read before all writes have completed, or vise-versa + */ + UZKErrorCodeMixedModeAccess = 112, + + /** + * Error reading the global comment of the archive + */ + UZKErrorCodeReadComment = 113, + + /** + * The CRC given up front doesn't match the calculated CRC + */ + UZKErrorCodePreCRCMismatch = 114, + + /** + * The zip is compressed using Deflate64 (compression method 9), which isn't supported + */ + UZKErrorCodeDeflate64 = 115, + + /** + * User cancelled the operation + */ + UZKErrorCodeUserCancelled = 116, +}; + + +typedef NSString *const UZKProgressInfoKey; + +/** + * Defines the keys passed in `-[NSProgress userInfo]` for certain methods + */ +static UZKProgressInfoKey _Nonnull +/** + * For `extractFilesTo:overwrite:error:`, this key contains an instance of URKFileInfo with the file currently being extracted + */ +UZKProgressInfoKeyFileInfoExtracting = @"UZKProgressInfoKeyFileInfoExtracting"; + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *UZKErrorDomain; + +@interface UZKArchive : NSObject +// Minimum of iOS 9, macOS 10.11 SDKs +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED > 90000) || (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED > 101100) + +#endif + +/** + * The URL of the archive. Returns nil if the URL becomes unreachable + */ +@property(weak, nonatomic, readonly, nullable) NSURL *fileURL; + +/** + * The filename of the archive. Returns nil if the archive file becomes unreachable + */ +@property(weak, nonatomic, readonly, nullable) NSString *filename; + +/** + * The password of the archive + */ +@property(strong, nullable) NSString *password; + +/** + * The global comment inside the archive + * + * Comments are written in UTF-8, and read in UTF-8 and Windows/CP-1252, falling back to defaultCStringEncoding + */ +@property(retain, atomic, nullable) NSString *comment; + +/** + * Can be used for progress reporting, but it's not necessary. You can also use + * implicit progress reporting. If you don't use it, one will still be created, + * which will become a child progress of whichever one is the current NSProgress + * instance. + * + * To use this, assign it before beginning an operation that reports progress. Once + * the method you're calling has a reference to it, it will nil it out. Please check + * for nil before assigning it to avoid concurrency conflicts. + */ +@property(nullable, strong) NSProgress *progress; + + +/** + * DEPRECATED: Creates and returns an archive at the given path + * + * @param filePath A path to the archive file + * + * @return Returns a UZKArchive object, or nil if the path isn't reachable + */ ++ (nullable instancetype)zipArchiveAtPath:(NSString *)filePath __deprecated_msg("Use -initWithPath:error: instead"); + +/** + * DEPRECATED: Creates and returns an archive at the given URL + * + * @param fileURL The URL of the archive file + * + * @return Returns a UZKArchive object, or nil if the URL isn't reachable + */ ++ (nullable instancetype)zipArchiveAtURL:(NSURL *)fileURL __deprecated_msg("Use -initWithURL:error: instead"); + +/** + * DEPRECATED: Creates and returns an archive at the given path, with a given password + * + * @param filePath A path to the archive file + * @param password The password of the given archive + * + * @return Returns a UZKArchive object, or nil if the path isn't reachable + */ ++ (nullable instancetype)zipArchiveAtPath:(NSString *)filePath password:(nullable NSString *)password __deprecated_msg("Use -initWithPath:password:error: instead"); + +/** + * DEPRECATED: Creates and returns an archive at the given URL, with a given password + * + * @param fileURL The URL of the archive file + * @param password The password of the given archive + * + * @return Returns a UZKArchive object, or nil if the URL isn't reachable + */ ++ (nullable instancetype)zipArchiveAtURL:(NSURL *)fileURL password:(nullable NSString *)password __deprecated_msg("Use -initWithURL:password:error: instead");; + + +/** + * Creates and returns an archive at the given path + * + * @param filePath A path to the archive file + * @param error Returns an error code if the object can't be initialized + * + * @return Returns a UZKArchive object, or nil if the path isn't reachable + */ +- (nullable instancetype)initWithPath:(NSString *)filePath error:(NSError **)error; + +/** + * Creates and returns an archive at the given URL + * + * @param fileURL The URL of the archive file + * @param error Returns an error code if the object can't be initialized + * + * @return Returns a UZKArchive object, or nil if the URL isn't reachable + */ +- (nullable instancetype)initWithURL:(NSURL *)fileURL error:(NSError **)error; + +/** + * Creates and returns an archive at the given path, with a given password + * + * @param filePath A path to the archive file + * @param password The password of the given archive + * @param error Returns an error code if the object can't be initialized + * + * @return Returns a UZKArchive object, or nil if the path isn't reachable + */ +- (nullable instancetype)initWithPath:(NSString *)filePath password:(nullable NSString *)password error:(NSError **)error; + +/** + * Creates and returns an archive at the given URL, with a given password + * + * @param fileURL The URL of the archive file + * @param password The password of the given archive + * @param error Returns an error code if the object can't be initialized + * + * @return Returns a UZKArchive object, or nil if the URL isn't reachable + */ +- (nullable instancetype)initWithURL:(NSURL *)fileURL password:(nullable NSString *)password error:(NSError **)error; + + + +#pragma mark - Read Methods + + +/** + * Determines whether a file is a Zip file by reading the header + * + * @param filePath Path to the file being checked + * + * @return YES if the file exists and contains a signature indicating it is a Zip file + */ ++ (BOOL)pathIsAZip:(NSString *)filePath; + +/** + * Determines whether a file is a Zip file by reading the header + * + * @param fileURL URL of the file being checked + * + * @return YES if the file exists and contains a signature indicating it is a Zip file + */ ++ (BOOL)urlIsAZip:(NSURL *)fileURL; + + +/** + * Lists the names of the files in the archive + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return Returns a list of NSString containing the paths within the archive's contents, or nil if an error was encountered + */ +- (nullable NSArray *)listFilenames:(NSError **)error; + +/** + * Lists the various attributes of each file in the archive + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return Returns a list of UZKFileInfo objects, which contain metadata about the archive's files, or nil if an error was encountered + */ +- (nullable NSArray *)listFileInfo:(NSError **)error; + +/** + * Writes all files in the archive to the given path. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction. Use the progress property (as explained in the README) to + * retrieve more detailed information, such as the current file being extracted, number of files extracted, + * and the URKFileInfo instance being extracted + * + * @param destinationDirectory The destination path of the unarchived files + * @param overwrite YES to overwrite files in the destination directory, NO otherwise + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return YES on successful extraction, NO if an error was encountered + */ +- (BOOL)extractFilesTo:(NSString *)destinationDirectory + overwrite:(BOOL)overwrite + error:(NSError **)error; + +/** + * **DEPRECATED:** Writes all files in the archive to the given path + * + * @param destinationDirectory The destination path of the unarchived files + * @param overwrite YES to overwrite files in the destination directory, NO otherwise + * @param progress Called every so often to report the progress of the extraction + * + * - *currentFile* The info about the file that's being extracted + * - *percentArchiveDecompressed* The percentage of the archive that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return YES on successful extraction, NO if an error was encountered + */ +- (BOOL)extractFilesTo:(NSString *)destinationDirectory + overwrite:(BOOL)overwrite + progress:(nullable void (^)(UZKFileInfo *currentFile, CGFloat percentArchiveDecompressed))progress + error:(NSError **)error __deprecated_msg("Use -extractFilesTo:overwrite:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * Unarchive a single file from the archive into memory. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction + * + * @param fileInfo The info of the file within the archive to be expanded. Only the filename property is used + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractData:(UZKFileInfo *)fileInfo + error:(NSError **)error; + +/** + * **DEPRECATED:** Unarchive a single file from the archive into memory + * + * @param fileInfo The info of the file within the archive to be expanded. Only the filename property is used + * @param progress Called every so often to report the progress of the extraction + * + * - *percentDecompressed* The percentage of the archive that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractData:(UZKFileInfo *)fileInfo + progress:(nullable void (^)(CGFloat percentDecompressed))progress + error:(NSError **)error __deprecated_msg("Use -extractData:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * Unarchive a single file from the archive into memory. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction + * + * @param filePath The path of the file within the archive to be expanded + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractDataFromFile:(NSString *)filePath + error:(NSError **)error; + +/** + * **DEPRECATED:** Unarchive a single file from the archive into memory + * + * @param filePath The path of the file within the archive to be expanded + * @param progress Called every so often to report the progress of the extraction + * + * - *percentDecompressed* The percentage of the file that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractDataFromFile:(NSString *)filePath + progress:(nullable void (^)(CGFloat percentDecompressed))progress + error:(NSError **)error __deprecated_msg("Use -extractDataFromFile:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * Loops through each file in the archive into memory, allowing you to perform an action + * using its info. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of the operation + * + * @param action The action to perform using the data + * + * - *fileInfo* The metadata of the file within the archive + * - *stop* Set to YES to stop reading the archive + * + * @param error Contains an error if any was returned + * + * @return YES if no errors were encountered, NO otherwise + */ +- (BOOL)performOnFilesInArchive:(void(^)(UZKFileInfo *fileInfo, BOOL *stop))action + error:(NSError **)error; + +/** + * Extracts each file in the archive into memory, allowing you to perform an action + * on it. Supports NSProgress for progress reporting, which also allows cancellation + * in the middle of the operation + * + * @param action The action to perform using the data + * + * - *fileInfo* The metadata of the file within the archive + * - *fileData* The full data of the file in the archive + * - *stop* Set to YES to stop reading the archive + * + * @param error Contains an error if any was returned + * + * @return YES if no errors were encountered, NO otherwise + */ +- (BOOL)performOnDataInArchive:(void(^)(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop))action + error:(NSError **)error; + +/** + * Unarchive a single file from the archive into memory. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction + * + * @param filePath The path of the file within the archive to be expanded + * @param error Contains an NSError object when there was an error reading the archive + * @param action The block to run for each chunk of data, each of size <= bufferSize + * + * - *dataChunk* The data read from the archived file. Read bytes and length to write the data + * - *percentDecompressed* The percentage of the file that has been decompressed + * + * @return YES if all data was read successfully, NO if an error was encountered + */ +- (BOOL)extractBufferedDataFromFile:(NSString *)filePath + error:(NSError **)error + action:(void(^)(NSData *dataChunk, CGFloat percentDecompressed))action; + +/** + * YES if archive protected with a password, NO otherwise + */ +- (BOOL)isPasswordProtected; + +/** + * Tests whether the provided password unlocks the archive + * + * @return YES if correct password or archive is not password protected, NO if password is wrong + */ +- (BOOL)validatePassword; + +/** + Extract each file in the archive, checking whether the data matches the CRC checksum + stored at the time it was written + + @return YES if the data is all correct, false if any check failed + */ +- (BOOL)checkDataIntegrity; + +/** + Extract a particular file, to determine if its data matches the CRC + checksum stored at the time it written + + @param filePath The file in the archive to check + + @return YES if the data is correct, false if any check failed + */ +- (BOOL)checkDataIntegrityOfFile:(NSString *)filePath; + + + +#pragma mark - Write Methods + + +/** + * 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 filePath The full path to the target file in the archive + * @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 + filePath:(NSString *)filePath + 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 + * @param progress Called every so often to report the progress of the compression + * + * - *percentCompressed* The percentage of the file that has been compressed + * + * @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 + filePath:(NSString *)filePath + progress:(nullable void (^)(CGFloat percentCompressed))progress + error:(NSError **)error __deprecated_msg("Use -writeData:filePath:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * 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 + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + 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 + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param progress Called every so often to report the progress of the compression + * + * - *percentCompressed* The percentage of the file that has been compressed + * + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + progress:(nullable void (^)(CGFloat percentCompressed))progress + error:(NSError **)error __deprecated_msg("Use -writeData:filePath:fileDate:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * 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 + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + 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 + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @param progress Called every so often to report the progress of the compression + * + * - *percentCompressed* The percentage of the file that has been compressed + * + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + progress:(nullable void (^)(CGFloat percentCompressed))progress + error:(NSError **)error __deprecated_msg("Use -writeData:filePath:fileDate:compressionMethod:password:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * 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. + * + * @param data Data to write into the archive + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + error:(NSError **)error; + +/** + * 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. + * + * @param data Data to write into the archive + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param permissions The desired POSIX permissions of the file in the archive + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + posixPermissions:(short)permissions +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + error:(NSError **)error; + +/** + * **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. + * + * @param data Data to write into the archive + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param progress Called every so often to report the progress of the compression + * + * - *percentCompressed* The percentage of the file that has been compressed + * + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + progress:(nullable void (^)(CGFloat percentCompressed))progress + error:(NSError **)error __deprecated_msg("Use -writeData:filePath:fileDate:compressionMethod:password:overwrite:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * **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. + * + * @param data Data to write into the archive + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param permissions The desired POSIX permissions of the file in the archive + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param progress Called every so often to report the progress of the compression + * + * - *percentCompressed* The percentage of the file that has been compressed + * + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + posixPermissions:(short)permissions +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + progress:(nullable void (^)(CGFloat percentCompressed))progress + error:(NSError **)error __deprecated_msg("Use -writeData:filePath:fileDate:permissions:compressionMethod:password:overwrite:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * 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 + * @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:(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 filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @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:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + 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 filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @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:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + compressionMethod:(UZKCompressionMethod)method + 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, 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. + * + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @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:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + compressionMethod:(UZKCompressionMethod)method + overwrite:(BOOL)overwrite + 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, 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. + * + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param preCRC The CRC-32 for the data being sent. Only necessary if encrypting the file. + Pass 0 otherwise + * @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:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + 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; + +/** + * 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 + * be slow. On the other hand, when not overwriting, the size of the archive will grow each time + * the file is written. + * + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param preCRC The CRC-32 for the data being sent. Only necessary if encrypting the file. + * Pass 0 otherwise + * @param password Override the password associated with the archive (not recommended) + * @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:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + 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; + + +/** + * 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 + * be slow. On the other hand, when not overwriting, the size of the archive will grow each time + * the file is written. + * + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param permissions The desired POSIX permissions of the file in the archive + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param preCRC The CRC-32 for the data being sent. Only necessary if encrypting the file. + * Pass 0 otherwise + * @param password Override the password associated with the archive (not recommended) + * @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:(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; + +/** + * Removes the given file from the archive + * + * @param filePath The file in the archive you wish to delete + * @param error Contains an NSError object when there was an error writing to the archive + * + * @return YES if the file was successfully deleted, NO otherwise + */ +- (BOOL)deleteFile:(NSString *)filePath error:(NSError **)error; + + +@end +NS_ASSUME_NONNULL_END diff --git a/Carthage/Build/iOS/UnzipKit.framework/Headers/UZKFileInfo.h b/Carthage/Build/iOS/UnzipKit.framework/Headers/UZKFileInfo.h new file mode 100644 index 0000000..e14248e --- /dev/null +++ b/Carthage/Build/iOS/UnzipKit.framework/Headers/UZKFileInfo.h @@ -0,0 +1,90 @@ +// +// UZKFileInfo.h +// UnzipKit +// +// + +#import + + + +@class UZKArchive; + +/** + * Defines the various compression levels that can be applied to a file + */ +typedef NS_ENUM(NSInteger, UZKCompressionMethod) { + /** + * Default level + */ + UZKCompressionMethodDefault= -1, + + /** + * No compression + */ + UZKCompressionMethodNone= 0, + + /** + * Fastest compression + */ + UZKCompressionMethodFastest= 1, + + /** + * Best (slowest) compression + */ + UZKCompressionMethodBest= 9 +}; + + +@interface UZKFileInfo : NSObject + +/** + * The name of the file + */ +@property (readonly, strong) NSString *filename; + +/** + * The timestamp of the file + */ +@property (readonly, nonatomic) NSDate *timestamp; + +/** + * The CRC checksum of the file + */ +@property (readonly) NSUInteger CRC; + +/** + * Size of the uncompressed file + */ +@property (readonly) unsigned long long int uncompressedSize; + +/** + * Size of the compressed file + */ +@property (readonly) unsigned long long int compressedSize; + +/** + * YES if the file will be continued of the next volume + */ +@property (readonly) BOOL isEncryptedWithPassword; + +/** + * YES if the file is a directory + */ +@property (readonly) BOOL isDirectory; + +/** + * The type of compression + */ +@property (readonly) UZKCompressionMethod compressionMethod; + +/** + * The POSIX permissions of the file, like you would get by retrieving the `NSFilePosixPermissions` + * key from the attributes NSFileManager returns. Assign in octal form, like 0777 in Objective-C or + * 0o777 in Swift + */ +@property (nonatomic, readonly) short posixPermissions; + + + +@end diff --git a/Carthage/Build/iOS/UnzipKit.framework/Headers/UnzipKit.h b/Carthage/Build/iOS/UnzipKit.framework/Headers/UnzipKit.h new file mode 100644 index 0000000..d390a9d --- /dev/null +++ b/Carthage/Build/iOS/UnzipKit.framework/Headers/UnzipKit.h @@ -0,0 +1,19 @@ +// +// UnzipKit.h +// UnzipKit +// +// Created by Dov Frankel on 12/16/14. +// Copyright (c) 2014 Abbey Code. All rights reserved. +// + +#import + +//! Project version number for UnzipKit. +FOUNDATION_EXPORT double UnzipKitVersionNumber; + +//! Project version string for UnzipKit. +FOUNDATION_EXPORT const unsigned char UnzipKitVersionString[]; + + +#import "UZKArchive.h" +#import "UZKFileInfo.h" diff --git a/Carthage/Build/iOS/UnzipKit.framework/Info.plist b/Carthage/Build/iOS/UnzipKit.framework/Info.plist new file mode 100644 index 0000000..87ef0a8 Binary files /dev/null and b/Carthage/Build/iOS/UnzipKit.framework/Info.plist differ diff --git a/Carthage/Build/iOS/UnzipKit.framework/Modules/module.modulemap b/Carthage/Build/iOS/UnzipKit.framework/Modules/module.modulemap new file mode 100644 index 0000000..58ada25 --- /dev/null +++ b/Carthage/Build/iOS/UnzipKit.framework/Modules/module.modulemap @@ -0,0 +1,6 @@ +framework module UnzipKit { + umbrella header "UnzipKit.h" + + export * + module * { export * } +} diff --git a/Carthage/Build/iOS/UnzipKit.framework/PrivateHeaders/UZKFileInfo_Private.h b/Carthage/Build/iOS/UnzipKit.framework/PrivateHeaders/UZKFileInfo_Private.h new file mode 100644 index 0000000..bcce4fb --- /dev/null +++ b/Carthage/Build/iOS/UnzipKit.framework/PrivateHeaders/UZKFileInfo_Private.h @@ -0,0 +1,23 @@ +// +// UZKFileInfo_Private.h +// UnzipKit +// +// + +@import Foundation; + +#import "unzip.h" + +@interface UZKFileInfo (Private) + +/** + * Returns a UZKFileInfo instance for the given extended header data + * + * @param fileInfo The header data for a Zip file + * @param filename The archive that contains the file + * + * @return an instance of UZKFileInfo + */ ++ (instancetype) fileInfo:(unz_file_info64 *)fileInfo filename:(NSString *)filename; + +@end \ No newline at end of file diff --git a/Carthage/Build/iOS/UnzipKit.framework/UnzipKit b/Carthage/Build/iOS/UnzipKit.framework/UnzipKit new file mode 100755 index 0000000..ca5cd4c Binary files /dev/null and b/Carthage/Build/iOS/UnzipKit.framework/UnzipKit differ diff --git a/Carthage/Build/iOS/UnzipKit.framework/UnzipKitResources.bundle/Info.plist b/Carthage/Build/iOS/UnzipKit.framework/UnzipKitResources.bundle/Info.plist new file mode 100644 index 0000000..361d0c2 Binary files /dev/null and b/Carthage/Build/iOS/UnzipKit.framework/UnzipKitResources.bundle/Info.plist differ diff --git a/Carthage/Build/iOS/UnzipKit.framework/UnzipKitResources.bundle/en.lproj/UnzipKit.strings b/Carthage/Build/iOS/UnzipKit.framework/UnzipKitResources.bundle/en.lproj/UnzipKit.strings new file mode 100644 index 0000000..3e8fa1d Binary files /dev/null and b/Carthage/Build/iOS/UnzipKit.framework/UnzipKitResources.bundle/en.lproj/UnzipKit.strings differ diff --git a/Carthage/Checkouts/DockProgress/.editorconfig b/Carthage/Checkouts/DockProgress/.editorconfig new file mode 100644 index 0000000..aaac325 --- /dev/null +++ b/Carthage/Checkouts/DockProgress/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +indent_style = tab +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true diff --git a/Carthage/Checkouts/DockProgress/.gitattributes b/Carthage/Checkouts/DockProgress/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/Carthage/Checkouts/DockProgress/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/Carthage/Checkouts/DockProgress/.github/funding.yml b/Carthage/Checkouts/DockProgress/.github/funding.yml new file mode 100644 index 0000000..15edf6e --- /dev/null +++ b/Carthage/Checkouts/DockProgress/.github/funding.yml @@ -0,0 +1,4 @@ +github: sindresorhus +open_collective: sindresorhus +patreon: sindresorhus +custom: https://sindresorhus.com/donate diff --git a/Carthage/Checkouts/DockProgress/.gitignore b/Carthage/Checkouts/DockProgress/.gitignore new file mode 100644 index 0000000..0854237 --- /dev/null +++ b/Carthage/Checkouts/DockProgress/.gitignore @@ -0,0 +1,4 @@ +/.build +/Packages +xcuserdata +project.xcworkspace diff --git a/Carthage/Checkouts/DockProgress/.swiftlint.yml b/Carthage/Checkouts/DockProgress/.swiftlint.yml new file mode 100644 index 0000000..8619d1d --- /dev/null +++ b/Carthage/Checkouts/DockProgress/.swiftlint.yml @@ -0,0 +1,181 @@ +whitelist_rules: + - anyobject_protocol + - array_init + - attributes + - block_based_kvo + - class_delegate_protocol + - closing_brace + - closure_end_indentation + - closure_parameter_position + - closure_spacing + - collection_alignment + - colon + - comma + - compiler_protocol_init + - conditional_returns_on_newline + - contains_over_filter_count + - contains_over_filter_is_empty + - contains_over_first_not_nil + - contains_over_range_nil_comparison + - control_statement + - custom_rules + - deployment_target + - discarded_notification_center_observer + - discouraged_direct_init + - discouraged_object_literal + - discouraged_optional_boolean + - discouraged_optional_collection + - duplicate_enum_cases + - duplicate_imports + - dynamic_inline + - empty_collection_literal + - empty_count + - empty_enum_arguments + - empty_parameters + - empty_parentheses_with_trailing_closure + - empty_string + - empty_xctest_method + - enum_case_associated_value_count + - explicit_init + - fallthrough + - fatal_error_message + - first_where + - flatmap_over_map_reduce + - for_where + - generic_type_name + - identical_operands + - identifier_name + - implicit_getter + - implicit_return + - inert_defer + - is_disjoint + - joined_default_parameter + - last_where + - leading_whitespace + - legacy_cggeometry_functions + - legacy_constant + - legacy_constructor + - legacy_hashing + - legacy_multiple + - legacy_nsgeometry_functions + - legacy_random + - literal_expression_end_indentation + - lower_acl_than_parent + - mark + - modifier_order + - multiline_arguments + - multiline_function_chains + - multiline_literal_brackets + - multiline_parameters + - multiline_parameters_brackets + - nimble_operator + - no_extension_access_modifier + - no_fallthrough_only + - no_space_in_method_call + - notification_center_detachment + - nsobject_prefer_isequal + - number_separator + - object_literal + - opening_brace + - operator_usage_whitespace + - operator_whitespace + - orphaned_doc_comment + - overridden_super_call + - prefer_self_type_over_type_of_self + - private_action + - private_outlet + - private_unit_test + - prohibited_super_call + - protocol_property_accessors_order + - reduce_boolean + - reduce_into + - redundant_discardable_let + - redundant_nil_coalescing + - redundant_objc_attribute + - redundant_optional_initialization + - redundant_set_access_control + - redundant_string_enum_value + - redundant_type_annotation + - redundant_void_return + - required_enum_case + - return_arrow_whitespace + - shorthand_operator + - sorted_first_last + - statement_position + - static_operator + - strong_iboutlet + - superfluous_disable_command + - switch_case_alignment + - switch_case_on_newline + - syntactic_sugar + - toggle_bool + - trailing_closure + - trailing_comma + - trailing_newline + - trailing_semicolon + - trailing_whitespace + - unavailable_function + - unneeded_break_in_switch + - unneeded_parentheses_in_closure_argument + - unowned_variable_capture + - untyped_error_in_catch + - unused_closure_parameter + - unused_control_flow_label + - unused_enumerated + - unused_optional_binding + - unused_setter_value + - valid_ibinspectable + - vertical_parameter_alignment + - vertical_parameter_alignment_on_call + - vertical_whitespace_closing_braces + - vertical_whitespace_opening_braces + - void_return + - weak_delegate + - xct_specific_matcher + - xctfail_message + - yoda_condition +analyzer_rules: + - unused_declaration + - unused_import +force_cast: warning +force_unwrapping: warning +number_separator: + minimum_length: 5 +object_literal: + image_literal: false +discouraged_object_literal: + color_literal: false +identifier_name: + max_length: + warning: 100 + error: 100 + min_length: + warning: 2 + error: 2 + validates_start_with_lowercase: false + allowed_symbols: + - '_' + excluded: + - 'x' + - 'y' + - 'a' + - 'b' + - 'x1' + - 'x2' + - 'y1' + - 'y2' +deployment_target: + macOS_deployment_target: '10.12' +custom_rules: + no_nsrect: + regex: '\bNSRect\b' + match_kinds: typeidentifier + message: 'Use CGRect instead of NSRect' + no_nssize: + regex: '\bNSSize\b' + match_kinds: typeidentifier + message: 'Use CGSize instead of NSSize' + no_nspoint: + regex: '\bNSPoint\b' + match_kinds: typeidentifier + message: 'Use CGPoint instead of NSPoint' diff --git a/Carthage/Checkouts/DockProgress/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata b/Carthage/Checkouts/DockProgress/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/Carthage/Checkouts/DockProgress/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Carthage/Checkouts/DockProgress/DockProgress.podspec b/Carthage/Checkouts/DockProgress/DockProgress.podspec new file mode 100644 index 0000000..a2db12b --- /dev/null +++ b/Carthage/Checkouts/DockProgress/DockProgress.podspec @@ -0,0 +1,13 @@ +Pod::Spec.new do |s| + s.name = 'DockProgress' + s.version = '3.2.0' + s.summary = 'Show progress in your app\'s Dock icon' + s.license = 'MIT' + s.homepage = 'https://github.com/sindresorhus/DockProgress' + s.social_media_url = 'https://twitter.com/sindresorhus' + s.authors = { 'Sindre Sorhus' => 'sindresorhus@gmail.com' } + s.source = { :git => 'https://github.com/sindresorhus/DockProgress.git', :tag => "v#{s.version}" } + s.source_files = 'Sources/**/*.swift' + s.swift_version = '5.3' + s.platform = :macos, '10.12' +end diff --git a/Carthage/Checkouts/DockProgress/DockProgress.xcodeproj/DockProgress_Info.plist b/Carthage/Checkouts/DockProgress/DockProgress.xcodeproj/DockProgress_Info.plist new file mode 100644 index 0000000..33c22f5 --- /dev/null +++ b/Carthage/Checkouts/DockProgress/DockProgress.xcodeproj/DockProgress_Info.plist @@ -0,0 +1,22 @@ + + + + + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + $(MARKETING_VERSION) + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/Carthage/Checkouts/DockProgress/DockProgress.xcodeproj/project.pbxproj b/Carthage/Checkouts/DockProgress/DockProgress.xcodeproj/project.pbxproj new file mode 100644 index 0000000..8bdac81 --- /dev/null +++ b/Carthage/Checkouts/DockProgress/DockProgress.xcodeproj/project.pbxproj @@ -0,0 +1,590 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + E3FB30C420EA5DBC009BA1BD /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = E3FB30C320EA5DBC009BA1BD /* AppDelegate.swift */; }; + E3FB30C920EA5DBE009BA1BD /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = E3FB30C720EA5DBE009BA1BD /* MainMenu.xib */; }; + E3FB30CF20EA5EBD009BA1BD /* DockProgress.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = "DockProgress::DockProgress::Product" /* DockProgress.framework */; }; + E3FB30D020EA5EBD009BA1BD /* DockProgress.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = "DockProgress::DockProgress::Product" /* DockProgress.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + E3FEB1AB21DC4F70009C38CA /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E3FEB1AA21DC4F70009C38CA /* Images.xcassets */; }; + OBJ_19 /* DockProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_9 /* DockProgress.swift */; }; + OBJ_20 /* Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_10 /* Utilities.swift */; }; + OBJ_27 /* Package.swift in Sources */ = {isa = PBXBuildFile; fileRef = OBJ_6 /* Package.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + E3FB30D120EA5EBD009BA1BD /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = OBJ_1 /* Project object */; + proxyType = 1; + remoteGlobalIDString = "DockProgress::DockProgress"; + remoteInfo = DockProgress; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + E3FB30D320EA5EBD009BA1BD /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + E3FB30D020EA5EBD009BA1BD /* DockProgress.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + "DockProgress::DockProgress::Product" /* DockProgress.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DockProgress.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + E3FB30C120EA5DBC009BA1BD /* DockProgressExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DockProgressExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + E3FB30C320EA5DBC009BA1BD /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = AppDelegate.swift; sourceTree = ""; usesTabs = 1; }; + E3FB30C820EA5DBE009BA1BD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + E3FB30CA20EA5DBE009BA1BD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + E3FEB1AA21DC4F70009C38CA /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + OBJ_10 /* Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = Utilities.swift; sourceTree = ""; usesTabs = 1; }; + OBJ_6 /* Package.swift */ = {isa = PBXFileReference; explicitFileType = sourcecode.swift; fileEncoding = 4; lineEnding = 0; path = Package.swift; sourceTree = ""; usesTabs = 1; }; + OBJ_9 /* DockProgress.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = DockProgress.swift; sourceTree = ""; usesTabs = 1; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + E3FB30BE20EA5DBC009BA1BD /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + E3FB30CF20EA5EBD009BA1BD /* DockProgress.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_21 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + E3FB30C220EA5DBC009BA1BD /* Example */ = { + isa = PBXGroup; + children = ( + E3FB30C320EA5DBC009BA1BD /* AppDelegate.swift */, + E3FB30C720EA5DBE009BA1BD /* MainMenu.xib */, + E3FB30CA20EA5DBE009BA1BD /* Info.plist */, + E3FEB1AA21DC4F70009C38CA /* Images.xcassets */, + ); + path = Example; + sourceTree = ""; + }; + OBJ_12 /* Products */ = { + isa = PBXGroup; + children = ( + "DockProgress::DockProgress::Product" /* DockProgress.framework */, + E3FB30C120EA5DBC009BA1BD /* DockProgressExample.app */, + ); + name = Products; + sourceTree = BUILT_PRODUCTS_DIR; + }; + OBJ_5 = { + isa = PBXGroup; + children = ( + OBJ_6 /* Package.swift */, + OBJ_7 /* Sources */, + E3FB30C220EA5DBC009BA1BD /* Example */, + OBJ_12 /* Products */, + ); + sourceTree = ""; + usesTabs = 1; + }; + OBJ_7 /* Sources */ = { + isa = PBXGroup; + children = ( + OBJ_8 /* DockProgress */, + ); + name = Sources; + sourceTree = SOURCE_ROOT; + }; + OBJ_8 /* DockProgress */ = { + isa = PBXGroup; + children = ( + OBJ_9 /* DockProgress.swift */, + OBJ_10 /* Utilities.swift */, + ); + name = DockProgress; + path = Sources/DockProgress; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + "DockProgress::DockProgress" /* DockProgress */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_15 /* Build configuration list for PBXNativeTarget "DockProgress" */; + buildPhases = ( + E3BFC67621FBB9B400C16B1A /* SwiftLint */, + OBJ_18 /* Sources */, + OBJ_21 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DockProgress; + productName = DockProgress; + productReference = "DockProgress::DockProgress::Product" /* DockProgress.framework */; + productType = "com.apple.product-type.framework"; + }; + "DockProgress::SwiftPMPackageDescription" /* DockProgressPackageDescription */ = { + isa = PBXNativeTarget; + buildConfigurationList = OBJ_23 /* Build configuration list for PBXNativeTarget "DockProgressPackageDescription" */; + buildPhases = ( + OBJ_26 /* Sources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = DockProgressPackageDescription; + productName = DockProgressPackageDescription; + productType = "com.apple.product-type.framework"; + }; + E3FB30C020EA5DBC009BA1BD /* DockProgressExample */ = { + isa = PBXNativeTarget; + buildConfigurationList = E3FB30CE20EA5DBE009BA1BD /* Build configuration list for PBXNativeTarget "DockProgressExample" */; + buildPhases = ( + E3FB30BD20EA5DBC009BA1BD /* Sources */, + E3FB30BE20EA5DBC009BA1BD /* Frameworks */, + E3FB30BF20EA5DBC009BA1BD /* Resources */, + E3FB30D320EA5EBD009BA1BD /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + E3FB30D220EA5EBD009BA1BD /* PBXTargetDependency */, + ); + name = DockProgressExample; + productName = DockProgressExample; + productReference = E3FB30C120EA5DBC009BA1BD /* DockProgressExample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + OBJ_1 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0940; + LastUpgradeCheck = 1200; + TargetAttributes = { + "DockProgress::DockProgress" = { + LastSwiftMigration = 1020; + }; + E3FB30C020EA5DBC009BA1BD = { + CreatedOnToolsVersion = 9.4.1; + LastSwiftMigration = 1020; + }; + }; + }; + buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "DockProgress" */; + compatibilityVersion = "Xcode 12.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = OBJ_5; + productRefGroup = OBJ_12 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + "DockProgress::DockProgress" /* DockProgress */, + "DockProgress::SwiftPMPackageDescription" /* DockProgressPackageDescription */, + E3FB30C020EA5DBC009BA1BD /* DockProgressExample */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + E3FB30BF20EA5DBC009BA1BD /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E3FB30C920EA5DBE009BA1BD /* MainMenu.xib in Resources */, + E3FEB1AB21DC4F70009C38CA /* Images.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + E3BFC67621FBB9B400C16B1A /* SwiftLint */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = SwiftLint; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "if which swiftlint >/dev/null; then\n swiftlint\nelse\n echo \"warning: SwiftLint not installed\"\nfi\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + E3FB30BD20EA5DBC009BA1BD /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + E3FB30C420EA5DBC009BA1BD /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_18 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_19 /* DockProgress.swift in Sources */, + OBJ_20 /* Utilities.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + OBJ_26 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 0; + files = ( + OBJ_27 /* Package.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + E3FB30D220EA5EBD009BA1BD /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = "DockProgress::DockProgress" /* DockProgress */; + targetProxy = E3FB30D120EA5EBD009BA1BD /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + E3FB30C720EA5DBE009BA1BD /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + E3FB30C820EA5DBE009BA1BD /* Base */, + ); + name = MainMenu.xib; + sourceTree = ""; + usesTabs = 1; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + E3FB30CC20EA5DBE009BA1BD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Manual; + COMBINE_HIDPI_IMAGES = YES; + DEVELOPMENT_TEAM = ""; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + INFOPLIST_FILE = Example/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = com.sindresorhus.DockProgressExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + E3FB30CD20EA5DBE009BA1BD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Manual; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEVELOPMENT_TEAM = ""; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + INFOPLIST_FILE = Example/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = com.sindresorhus.DockProgressExample; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + OBJ_16 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = DockProgress.xcodeproj/DockProgress_Info.plist; + MARKETING_VERSION = 3.2.0; + OTHER_CFLAGS = "$(inherited)"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = DockProgress; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGET_NAME = DockProgress; + }; + name = Debug; + }; + OBJ_17 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; + ENABLE_TESTABILITY = YES; + FRAMEWORK_SEARCH_PATHS = ( + "$(inherited)", + "$(PLATFORM_DIR)/Developer/Library/Frameworks", + ); + HEADER_SEARCH_PATHS = "$(inherited)"; + INFOPLIST_FILE = DockProgress.xcodeproj/DockProgress_Info.plist; + MARKETING_VERSION = 3.2.0; + OTHER_CFLAGS = "$(inherited)"; + OTHER_LDFLAGS = "$(inherited)"; + OTHER_SWIFT_FLAGS = "$(inherited)"; + PRODUCT_BUNDLE_IDENTIFIER = DockProgress; + PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)"; + PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; + TARGET_NAME = DockProgress; + }; + name = Release; + }; + OBJ_24 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD = /usr/bin/true; + OTHER_SWIFT_FLAGS = "-swift-version 4 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk"; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + OBJ_25 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + LD = /usr/bin/true; + OTHER_SWIFT_FLAGS = "-swift-version 4 -I $(TOOLCHAIN_DIR)/usr/lib/swift/pm/4 -target x86_64-apple-macosx10.10 -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk"; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; + OBJ_3 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_NS_ASSERTIONS = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.12; + ONLY_ACTIVE_ARCH = YES; + OTHER_SWIFT_FLAGS = "-DXcode"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SUPPORTED_PLATFORMS = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + USE_HEADERMAP = NO; + }; + name = Debug; + }; + OBJ_4 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = s; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.12; + OTHER_SWIFT_FLAGS = "-DXcode"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SUPPORTED_PLATFORMS = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = SWIFT_PACKAGE; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + SWIFT_VERSION = 5.0; + USE_HEADERMAP = NO; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + E3FB30CE20EA5DBE009BA1BD /* Build configuration list for PBXNativeTarget "DockProgressExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + E3FB30CC20EA5DBE009BA1BD /* Debug */, + E3FB30CD20EA5DBE009BA1BD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + OBJ_15 /* Build configuration list for PBXNativeTarget "DockProgress" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_16 /* Debug */, + OBJ_17 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + OBJ_2 /* Build configuration list for PBXProject "DockProgress" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_3 /* Debug */, + OBJ_4 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + OBJ_23 /* Build configuration list for PBXNativeTarget "DockProgressPackageDescription" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + OBJ_24 /* Debug */, + OBJ_25 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = OBJ_1 /* Project object */; +} diff --git a/Carthage/Checkouts/DockProgress/DockProgress.xcodeproj/xcshareddata/xcschemes/DockProgress-Package.xcscheme b/Carthage/Checkouts/DockProgress/DockProgress.xcodeproj/xcshareddata/xcschemes/DockProgress-Package.xcscheme new file mode 100644 index 0000000..7a669f5 --- /dev/null +++ b/Carthage/Checkouts/DockProgress/DockProgress.xcodeproj/xcshareddata/xcschemes/DockProgress-Package.xcscheme @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Carthage/Checkouts/DockProgress/DockProgress.xcodeproj/xcshareddata/xcschemes/DockProgressExample.xcscheme b/Carthage/Checkouts/DockProgress/DockProgress.xcodeproj/xcshareddata/xcschemes/DockProgressExample.xcscheme new file mode 100644 index 0000000..f37d784 --- /dev/null +++ b/Carthage/Checkouts/DockProgress/DockProgress.xcodeproj/xcshareddata/xcschemes/DockProgressExample.xcscheme @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Carthage/Checkouts/DockProgress/DockProgress.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist b/Carthage/Checkouts/DockProgress/DockProgress.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..d661bbd --- /dev/null +++ b/Carthage/Checkouts/DockProgress/DockProgress.xcodeproj/xcshareddata/xcschemes/xcschememanagement.plist @@ -0,0 +1,12 @@ + + + + SchemeUserState + + DockProgress-Package.xcscheme + + + SuppressBuildableAutocreation + + + diff --git a/Carthage/Checkouts/DockProgress/Example/AppDelegate.swift b/Carthage/Checkouts/DockProgress/Example/AppDelegate.swift new file mode 100644 index 0000000..84f9ae9 --- /dev/null +++ b/Carthage/Checkouts/DockProgress/Example/AppDelegate.swift @@ -0,0 +1,39 @@ +import Cocoa +import DockProgress + +@main +final class AppDelegate: NSObject, NSApplicationDelegate { + func borrowIconFromApp(_ app: String) { + let icon = NSWorkspace.shared.icon(forFile: NSWorkspace.shared.fullPath(forApplication: app)!) + icon.size = CGSize(width: 128, height: 128) + NSApp.applicationIconImage = icon + } + + func applicationDidFinishLaunching(_ notification: Notification) { + borrowIconFromApp("Photos") + + let styles: [DockProgress.ProgressStyle] = [ + .bar, + .squircle(color: .systemGray), + .circle(radius: 30, color: .white), + .badge(color: .systemBlue, badgeValue: { Int(DockProgress.progress * 12) }) + ] + + var stylesIterator = styles.makeIterator() + _ = stylesIterator.next() + + Timer.scheduledTimer(withTimeInterval: 0.02, repeats: true) { _ in + DockProgress.progress += 0.01 + + if DockProgress.progress > 1 { + if let style = stylesIterator.next() { + DockProgress.resetProgress() + DockProgress.style = style + } else { + // Reset iterator when all is looped. + stylesIterator = styles.makeIterator() + } + } + } + } +} diff --git a/Carthage/Checkouts/DockProgress/Example/Base.lproj/MainMenu.xib b/Carthage/Checkouts/DockProgress/Example/Base.lproj/MainMenu.xib new file mode 100644 index 0000000..c2035d5 --- /dev/null +++ b/Carthage/Checkouts/DockProgress/Example/Base.lproj/MainMenu.xib @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Carthage/Checkouts/DockProgress/Example/Images.xcassets/AppIcon.appiconset/Contents.json b/Carthage/Checkouts/DockProgress/Example/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..50ab7bd --- /dev/null +++ b/Carthage/Checkouts/DockProgress/Example/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,58 @@ +{ + "images" : [ + { + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Carthage/Checkouts/DockProgress/Example/Info.plist b/Carthage/Checkouts/DockProgress/Example/Info.plist new file mode 100644 index 0000000..95f6cad --- /dev/null +++ b/Carthage/Checkouts/DockProgress/Example/Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/Carthage/Checkouts/DockProgress/Package.swift b/Carthage/Checkouts/DockProgress/Package.swift new file mode 100644 index 0000000..8fe59b2 --- /dev/null +++ b/Carthage/Checkouts/DockProgress/Package.swift @@ -0,0 +1,22 @@ +// swift-tools-version:5.3 +import PackageDescription + +let package = Package( + name: "DockProgress", + platforms: [ + .macOS(.v10_12) + ], + products: [ + .library( + name: "DockProgress", + targets: [ + "DockProgress" + ] + ) + ], + targets: [ + .target( + name: "DockProgress" + ) + ] +) diff --git a/Carthage/Checkouts/DockProgress/Sources/DockProgress/DockProgress.swift b/Carthage/Checkouts/DockProgress/Sources/DockProgress/DockProgress.swift new file mode 100644 index 0000000..5c6f805 --- /dev/null +++ b/Carthage/Checkouts/DockProgress/Sources/DockProgress/DockProgress.swift @@ -0,0 +1,238 @@ +import Cocoa + +public enum DockProgress { + private static var previousProgress: Double = 0 + private static var progressObserver: NSKeyValueObservation? + private static var finishedObserver: NSKeyValueObservation? + + private static let dockImageView = with(NSImageView()) { + NSApp.dockTile.contentView = $0 + } + + public static weak var progressInstance: Progress? { + didSet { + guard let progressInstance = progressInstance else { + progressObserver = nil + finishedObserver = nil + resetProgress() + return + } + + progressObserver = progressInstance.observe(\.fractionCompleted) { sender, _ in + guard + !sender.isCancelled, + !sender.isFinished + else { + return + } + + progress = sender.fractionCompleted + } + + finishedObserver = progressInstance.observe(\.isFinished) { sender, _ in + guard + !sender.isCancelled, + sender.isFinished + else { + return + } + + progress = 1 + } + } + } + + public static var progress: Double = 0 { + didSet { + if previousProgress == 0 || (progress - previousProgress).magnitude > 0.01 { + previousProgress = progress + updateDockIcon() + } + } + } + + /// Reset the `progress` without animating. + public static func resetProgress() { + progress = 0 + previousProgress = 0 + updateDockIcon() + } + + public enum ProgressStyle { + case bar + case squircle(inset: Double? = nil, color: NSColor = .controlAccentColorPolyfill) + case circle(radius: Double, color: NSColor = .controlAccentColorPolyfill) + case badge(color: NSColor = .controlAccentColorPolyfill, badgeValue: () -> Int) + case custom(drawHandler: (_ rect: CGRect) -> Void) + } + + public static var style: ProgressStyle = .bar + + // TODO: Make the progress smoother by also animating the steps between each call to `updateDockIcon()` + private static func updateDockIcon() { + // TODO: If the `progress` is 1, draw the full circle, then schedule another draw in n milliseconds to hide it + DispatchQueue.main.async { + guard let appIcon = NSApp.applicationIconImage else { + return + } + + let icon = (0..<1).contains(progress) ? draw(appIcon) : appIcon + // TODO: Make this better by drawing in the `contentView` directly instead of using an image + dockImageView.image = icon + NSApp.dockTile.display() + } + } + + private static func draw(_ appIcon: NSImage) -> NSImage { + NSImage(size: appIcon.size, flipped: false) { dstRect in + NSGraphicsContext.current?.imageInterpolation = .high + appIcon.draw(in: dstRect) + + switch self.style { + case .bar: + self.drawProgressBar(dstRect) + case .squircle(let inset, let color): + self.drawProgressSquircle(dstRect, inset: inset, color: color) + case .circle(let radius, let color): + self.drawProgressCircle(dstRect, radius: radius, color: color) + case .badge(let color, let badgeValue): + self.drawProgressBadge(dstRect, color: color, badgeLabel: badgeValue()) + case .custom(let drawingHandler): + drawingHandler(dstRect) + } + + return true + } + } + + private static func drawProgressBar(_ dstRect: CGRect) { + func roundedRect(_ rect: CGRect) { + NSBezierPath(roundedRect: rect, cornerRadius: rect.height / 2).fill() + } + + let bar = CGRect(x: 0, y: 20, width: dstRect.width, height: 10) + NSColor.white.withAlpha(0.8).set() + roundedRect(bar) + + let barInnerBg = bar.insetBy(dx: 0.5, dy: 0.5) + NSColor.black.withAlpha(0.8).set() + roundedRect(barInnerBg) + + var barProgress = bar.insetBy(dx: 1, dy: 1) + barProgress.size.width = barProgress.width * CGFloat(progress) + NSColor.white.set() + roundedRect(barProgress) + } + + private static func drawProgressSquircle(_ dstRect: CGRect, inset: Double? = nil, color: NSColor) { + guard let cgContext = NSGraphicsContext.current?.cgContext else { + return + } + + let defaultInset: CGFloat = 14.4 + + var rect = dstRect.insetBy(dx: defaultInset, dy: defaultInset) + + if let inset = inset { + rect = rect.insetBy(dx: CGFloat(inset), dy: CGFloat(inset)) + } + + let progressSquircle = ProgressSquircleShapeLayer(rect: rect) + progressSquircle.strokeColor = color.cgColor + progressSquircle.lineWidth = 5 + progressSquircle.progress = progress + progressSquircle.render(in: cgContext) + } + + private static func drawProgressCircle(_ dstRect: CGRect, radius: Double, color: NSColor) { + guard let cgContext = NSGraphicsContext.current?.cgContext else { + return + } + + let progressCircle = ProgressCircleShapeLayer(radius: radius, center: dstRect.center) + progressCircle.strokeColor = color.cgColor + progressCircle.lineWidth = 4 + progressCircle.progress = progress + progressCircle.render(in: cgContext) + } + + private static func drawProgressBadge(_ dstRect: CGRect, color: NSColor, badgeLabel: Int) { + guard let cgContext = NSGraphicsContext.current?.cgContext else { + return + } + + let radius = dstRect.width / 4.8 + let newCenter = CGPoint(x: dstRect.maxX - radius - 4, y: dstRect.minY + radius + 4) + + // Background + let badge = ProgressCircleShapeLayer(radius: Double(radius), center: newCenter) + badge.fillColor = CGColor(red: 0.94, green: 0.96, blue: 1, alpha: 1) + badge.shadowColor = .black + badge.shadowOpacity = 0.3 + badge.masksToBounds = false + badge.shadowOffset = CGSize(width: -1, height: 1) + badge.shadowPath = badge.path + + // Progress circle + let lineWidth: CGFloat = 6 + let innerRadius = radius - lineWidth / 2 + let progressCircle = ProgressCircleShapeLayer(radius: Double(innerRadius), center: newCenter) + progressCircle.strokeColor = color.cgColor + progressCircle.lineWidth = lineWidth + progressCircle.lineCap = .butt + progressCircle.progress = progress + + // Label + let dimension = badge.bounds.height - 5 + let rect = CGRect(origin: progressCircle.bounds.origin, size: CGSize(width: dimension, height: dimension)) + let textLayer = VerticallyCenteredTextLayer(frame: rect, center: newCenter) + let badgeText = kiloShortStringFromInt(number: badgeLabel) + textLayer.foregroundColor = CGColor(red: 0.23, green: 0.23, blue: 0.24, alpha: 1) + textLayer.string = badgeText + textLayer.fontSize = scaledBadgeFontSize(text: badgeText) + textLayer.font = NSFont.helveticaNeueBold + textLayer.alignmentMode = .center + textLayer.truncationMode = .end + + badge.addSublayer(textLayer) + badge.addSublayer(progressCircle) + badge.render(in: cgContext) + } + + /** + ``` + 999 => 999 + 1000 => 1K + 1100 => 1K + 2000 => 2K + 10000 => 9K+ + ``` + */ + private static func kiloShortStringFromInt(number: Int) -> String { + let sign = number.signum() + let absNumber = abs(number) + + if absNumber < 1000 { + return "\(number)" + } else if absNumber < 10_000 { + return "\(sign * Int(absNumber / 1000))k" + } else { + return "\(sign * 9)k+" + } + } + + private static func scaledBadgeFontSize(text: String) -> CGFloat { + switch text.count { + case 1: + return 30 + case 2: + return 23 + case 3: + return 19 + case 4: + return 15 + default: + return 0 + } + } +} diff --git a/Carthage/Checkouts/DockProgress/Sources/DockProgress/Utilities.swift b/Carthage/Checkouts/DockProgress/Sources/DockProgress/Utilities.swift new file mode 100644 index 0000000..db80046 --- /dev/null +++ b/Carthage/Checkouts/DockProgress/Sources/DockProgress/Utilities.swift @@ -0,0 +1,272 @@ +import Cocoa + + +/** +Convenience function for initializing an object and modifying its properties. + +``` +let label = with(NSTextField()) { + $0.stringValue = "Foo" + $0.textColor = .systemBlue + view.addSubview($0) +} +``` +*/ +@discardableResult +func with(_ item: T, update: (inout T) throws -> Void) rethrows -> T { + var this = item + try update(&this) + return this +} + + +extension NSBezierPath { + /** + Create a path for a superellipse that fits inside the given rect. + */ + static func superellipse(in rect: CGRect, cornerRadius: Double) -> Self { + let minSide = min(rect.width, rect.height) + let radius = min(CGFloat(cornerRadius), minSide / 2) + + let topLeft = CGPoint(x: rect.minX, y: rect.minY) + let topRight = CGPoint(x: rect.maxX, y: rect.minY) + let bottomLeft = CGPoint(x: rect.minX, y: rect.maxY) + let bottomRight = CGPoint(x: rect.maxX, y: rect.maxY) + + // Top side (clockwise) + let point1 = CGPoint(x: rect.minX + radius, y: rect.minY) + let point2 = CGPoint(x: rect.maxX - radius, y: rect.minY) + + // Right side (clockwise) + let point3 = CGPoint(x: rect.maxX, y: rect.minY + radius) + let point4 = CGPoint(x: rect.maxX, y: rect.maxY - radius) + + // Bottom side (clockwise) + let point5 = CGPoint(x: rect.maxX - radius, y: rect.maxY) + let point6 = CGPoint(x: rect.minX + radius, y: rect.maxY) + + // Left side (clockwise) + let point7 = CGPoint(x: rect.minX, y: rect.maxY - radius) + let point8 = CGPoint(x: rect.minX, y: rect.minY + radius) + + let path = self.init() + path.move(to: point1) + path.addLine(to: point2) + path.addCurve(to: point3, controlPoint1: topRight, controlPoint2: topRight) + path.addLine(to: point4) + path.addCurve(to: point5, controlPoint1: bottomRight, controlPoint2: bottomRight) + path.addLine(to: point6) + path.addCurve(to: point7, controlPoint1: bottomLeft, controlPoint2: bottomLeft) + path.addLine(to: point8) + path.addCurve(to: point1, controlPoint1: topLeft, controlPoint2: topLeft) + + return path + } + + /** + Create a path for a squircle that fits inside the given `rect`. + + - Important: The given `rect` must be square. + */ + static func squircle(rect: CGRect) -> Self { + assert(rect.width == rect.height) + return superellipse(in: rect, cornerRadius: Double(rect.width / 2)) + } +} + + +final class ProgressSquircleShapeLayer: CAShapeLayer { + convenience init(rect: CGRect) { + self.init() + fillColor = nil + lineCap = .round + position = .zero + strokeEnd = 0 + + let cgPath = NSBezierPath + .squircle(rect: rect) + .rotating(byRadians: .pi, centerPoint: rect.center) + .reversed + .cgPath + + path = cgPath + bounds = cgPath.boundingBox + } + + var progress: Double { + get { Double(strokeEnd) } + set { + // Multiplying by `1.02` ensures that the start and end points meet at the end. Needed because of the round line cap. + strokeEnd = CGFloat(newValue * 1.02) + } + } +} + + +extension NSBezierPath { + /// For making a circle progress indicator. + static func progressCircle(radius: Double, center: CGPoint) -> Self { + let startAngle: CGFloat = 90 + let path = self.init() + path.appendArc( + withCenter: center, + radius: CGFloat(radius), + startAngle: startAngle, + endAngle: startAngle - 360, + clockwise: true + ) + return path + } +} + + +final class ProgressCircleShapeLayer: CAShapeLayer { + convenience init(radius: Double, center: CGPoint) { + self.init() + fillColor = nil + lineCap = .round + position = center + strokeEnd = 0 + + let cgPath = NSBezierPath.progressCircle(radius: radius, center: center).cgPath + path = cgPath + bounds = cgPath.boundingBox + } + + var progress: Double { + get { Double(strokeEnd) } + set { + // Multiplying by `1.02` ensures that the start and end points meet at the end. Needed because of the round line cap. + strokeEnd = CGFloat(newValue * 1.02) + } + } +} + + +extension NSColor { + func withAlpha(_ alpha: Double) -> NSColor { + withAlphaComponent(CGFloat(alpha)) + } +} + + +extension NSFont { + static let helveticaNeueBold = NSFont(name: "HelveticaNeue-Bold", size: 0) +} + + +extension CGRect { + var center: CGPoint { + get { CGPoint(x: midX, y: midY) } + set { + origin = CGPoint( + x: newValue.x - (size.width / 2), + y: newValue.y - (size.height / 2) + ) + } + } +} + + +extension NSBezierPath { + /// UIKit polyfill. + var cgPath: CGPath { + let path = CGMutablePath() + var points = [CGPoint](repeating: .zero, count: 3) + + for index in 0.. Self { + copy() as! Self + } + + func rotationTransform(byRadians radians: Double, centerPoint point: CGPoint) -> AffineTransform { + var transform = AffineTransform() + transform.translate(x: point.x, y: point.y) + transform.rotate(byRadians: CGFloat(radians)) + transform.translate(x: -point.x, y: -point.y) + return transform + } + + func rotating(byRadians radians: Double, centerPoint point: CGPoint) -> Self { + let path = copyPath() + + guard radians != 0 else { + return path + } + + let transform = rotationTransform(byRadians: radians, centerPoint: point) + path.transform(using: transform) + return path + } +} + + +/// Fixes the vertical alignment issue of the `CATextLayer` class. +final class VerticallyCenteredTextLayer: CATextLayer { + convenience init(frame rect: CGRect, center: CGPoint) { + self.init() + frame = rect + frame.center = center + contentsScale = NSScreen.main?.backingScaleFactor ?? 2 + } + + // From https://stackoverflow.com/a/44055040/6863743 + override func draw(in context: CGContext) { + let height = bounds.size.height + let deltaY = ((height - fontSize) / 2 - fontSize / 10) * -1 + + context.saveGState() + context.translateBy(x: 0, y: deltaY) + super.draw(in: context) + context.restoreGState() + } +} + + +/// macOS 10.14 polyfill. +extension NSColor { + public static let controlAccentColorPolyfill: NSColor = { + if #available(macOS 10.14, *) { + return NSColor.controlAccentColor + } else { + // swiftlint:disable:next object_literal + return NSColor(red: 0.10, green: 0.47, blue: 0.98, alpha: 1) + } + }() +} diff --git a/Carthage/Checkouts/DockProgress/license b/Carthage/Checkouts/DockProgress/license new file mode 100644 index 0000000..e7af2f7 --- /dev/null +++ b/Carthage/Checkouts/DockProgress/license @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) Sindre Sorhus (sindresorhus.com) + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Carthage/Checkouts/DockProgress/readme.md b/Carthage/Checkouts/DockProgress/readme.md new file mode 100644 index 0000000..2cd3078 --- /dev/null +++ b/Carthage/Checkouts/DockProgress/readme.md @@ -0,0 +1,124 @@ +# DockProgress + +> Show progress in your app's Dock icon + + + +This package is used in production by the [Gifski app](https://github.com/sindresorhus/Gifski). You might also like some of my [other apps](https://sindresorhus.com/apps). + +## Requirements + +- macOS 10.12+ +- Xcode 12+ +- Swift 5.3+ + +## Install + +#### Swift Package Manager + +Add `https://github.com/sindresorhus/DockProgress` in the [“Swift Package Manager” tab in Xcode](https://developer.apple.com/documentation/xcode/adding_package_dependencies_to_your_app). + +#### Carthage + +``` +github "sindresorhus/DockProgress" +``` + +#### CocoaPods + +```ruby +pod 'DockProgress' +``` + +## Usage + +### Manually set the progress + +```swift +import Cocoa +import DockProgress + +foo.onUpdate = { progress in + DockProgress.progress = progress +} +``` + +### Specify a [`Progress` instance](https://developer.apple.com/documentation/foundation/progress) + +```swift +import Cocoa +import DockProgress + +let progress = Progress(totalUnitCount: 1) +progress?.becomeCurrent(withPendingUnitCount: 1) + +DockProgress.progressInstance = progress +``` + +The given `Progress` instance is weakly stored. It's up to you to retain it. + +## Styles + +It comes with three styles. PR welcome for more. + +Check out the example app in the Xcode project. + +You can also draw a custom progress with `.custom(drawHandler: (_ rect: CGRect) -> Void)`. + +### Bar + +![](screenshot-bar.gif) + +```swift +import DockProgress + +DockProgress.style = .bar +``` + +This is the default. + +### Squircle + + + +```swift +import DockProgress + +DockProgress.style = .squircle(color: NSColor.white.withAlphaComponent(0.5)) +``` + +By default, it should perfectly fit a macOS 11 icon, but there's a `inset` parameter if you need to make any adjustments. + +### Circle + +![](screenshot-circle.gif) + +```swift +import DockProgress + +DockProgress.style = .circle(radius: 55, color: .systemBlue) +``` + +Make sure to set a `radius` that matches your app icon. + +### Badge + +![](screenshot-badge.gif) + +```swift +import DockProgress + +DockProgress.style = .badge(color: .systemBlue, badgeValue: { getDownloadCount() }) +``` + +Large `badgeValue` numbers will be written in kilo short notation, for example, `1012` → `1k`. + +Note: The `badgeValue` is not meant to be used as a numeric percentage. It's for things like count of downloads, number of files being converted, etc. + +## Related + +- [Defaults](https://github.com/sindresorhus/Defaults) - Swifty and modern UserDefaults +- [Preferences](https://github.com/sindresorhus/Preferences) - Add a preferences window to your macOS app in minutes +- [KeyboardShortcuts](https://github.com/sindresorhus/KeyboardShortcuts) - Add user-customizable global keyboard shortcuts to your macOS app +- [LaunchAtLogin](https://github.com/sindresorhus/LaunchAtLogin) - Add "Launch at Login" functionality to your macOS app +- [More…](https://github.com/search?q=user%3Asindresorhus+language%3Aswift) diff --git a/Carthage/Checkouts/DockProgress/screenshot-badge.gif b/Carthage/Checkouts/DockProgress/screenshot-badge.gif new file mode 100644 index 0000000..5be7536 Binary files /dev/null and b/Carthage/Checkouts/DockProgress/screenshot-badge.gif differ diff --git a/Carthage/Checkouts/DockProgress/screenshot-bar.gif b/Carthage/Checkouts/DockProgress/screenshot-bar.gif new file mode 100644 index 0000000..4e4ea58 Binary files /dev/null and b/Carthage/Checkouts/DockProgress/screenshot-bar.gif differ diff --git a/Carthage/Checkouts/DockProgress/screenshot-circle.gif b/Carthage/Checkouts/DockProgress/screenshot-circle.gif new file mode 100644 index 0000000..6c6750a Binary files /dev/null and b/Carthage/Checkouts/DockProgress/screenshot-circle.gif differ diff --git a/Carthage/Checkouts/DockProgress/screenshot-squircle.gif b/Carthage/Checkouts/DockProgress/screenshot-squircle.gif new file mode 100644 index 0000000..cf560c4 Binary files /dev/null and b/Carthage/Checkouts/DockProgress/screenshot-squircle.gif differ diff --git a/Carthage/Checkouts/DockProgress/screenshot.gif b/Carthage/Checkouts/DockProgress/screenshot.gif new file mode 100644 index 0000000..ce03555 Binary files /dev/null and b/Carthage/Checkouts/DockProgress/screenshot.gif differ diff --git a/Carthage/Checkouts/UnrarKit/.gitignore b/Carthage/Checkouts/UnrarKit/.gitignore new file mode 100644 index 0000000..f032122 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/.gitignore @@ -0,0 +1,8 @@ +build +.DS_Store + +CarthageValidation +analyzer-output + +**/*.xccheckout +**/xcuserdata/* diff --git a/Carthage/Checkouts/UnrarKit/.travis.yml b/Carthage/Checkouts/UnrarKit/.travis.yml new file mode 100644 index 0000000..4be4f70 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/.travis.yml @@ -0,0 +1,36 @@ +language: objective-c +osx_image: xcode9.3 + +before_script: + # Make log level less verbose. Temporarily undo if more info is needed + - sudo log config --mode "level:default" + +matrix: + include: + - stage: Test + env: Name=Mac + # The CLANG arguments and find command fail the build on analyzer errors + script: xcodebuild -workspace UnrarKit.xcworkspace -scheme UnrarKit -sdk macosx -configuration Release -quiet analyze test CLANG_ANALYZER_OUTPUT=html CLANG_ANALYZER_OUTPUT_DIR=analyzer-output && [[ -z `find analyzer-output -name "*.html"` ]] + + - stage: Test + env: Name=iOS + # The CLANG arguments and find command fail the build on analyzer errors + script: xcodebuild -workspace UnrarKit.xcworkspace -scheme UnrarKit -destination 'platform=iOS Simulator,name=iPhone 7,OS=latest' -configuration Release analyze test CLANG_ANALYZER_OUTPUT=html CLANG_ANALYZER_OUTPUT_DIR=analyzer-output && [[ -z `find analyzer-output -name "*.html"` ]] + + - stage: Test + env: Name=ExampleAppBuild + # The CLANG arguments and find command fail the build on analyzer errors + script: xcodebuild -workspace UnrarKit.xcworkspace -scheme UnrarExample -sdk iphonesimulator -configuration Release analyze CLANG_ANALYZER_OUTPUT=html CLANG_ANALYZER_OUTPUT_DIR=analyzer-output && [[ -z `find analyzer-output -name "*.html"` ]] + + - stage: Validate + env: Name=CocoaPods + script: ./Scripts/cocoapod-validate.sh + + - stage: Validate + env: Name=Carthage + script: ./Scripts/carthage-validate.sh + + - stage: Release + if: tag IS present + before_install: brew upgrade python # Needs Python 3 + script: ./Scripts/push-output.sh diff --git a/Carthage/Checkouts/UnrarKit/CHANGELOG.md b/Carthage/Checkouts/UnrarKit/CHANGELOG.md new file mode 100644 index 0000000..f47b8a4 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/CHANGELOG.md @@ -0,0 +1,139 @@ +# UnrarKit CHANGELOG + +## 2.9 + +* Added support for `NSProgress` and `NSProgressReporting` in all extraction and iteration methods (Issue #34) +* Added enhanced support for multivolume archives (PRs #59, #38 - Thanks to [@aonez](https://github.com/aonez) for the idea and implementation!) +* Added methods for checking data integrity of archived files (Issue #26, PR #61 - Thanks to [@amosavian](https://github.com/amosavian) for the suggestion!) +* Added new method `-iterateFileInfo:error:` that takes a block, allowing for lazy iteration of file info, without building up an in-memory array (Issue #73 - Thanks to [@yanex](https://github.com/yanex) for the suggestion!) +* Added detailed logging using new unified logging framework. See [the readme](README.md) for more details (Issue #35) +* Added localized details to returned `NSError` objects (Issue #45) +* Fixed bug when listing file info for multivolume archive that resulted in duplicate items (Issue #67 - Thanks to [@skito](https://github.com/skito) for catching this) +* Moved `unrar` sources into a static library, and addressed a wide variety of warnings exposed by the `-Weverything` flag (Issue #56) +* Upgraded UnRAR library to v5.6.3 (Issue #77) +* Switched to Travis Build Stages instead of the unofficial Travis-After-All (Issue #42) +* Added CocoaPods Test Spec, so your test suite can also run UnrarKit's unit tests Issue #44 +* Fixed warnings from Xcode 9 (Issue #51) +* Removed iOS-specific targets, after allowing macOS framework and unit test bundles to be cross-platform (Issue #55) + + +## 2.8.1 + +Updated to UnRAR library v 5.5.5 (Issue #43 - Thanks to [@Jegge](https://github.com/Jegge) for the suggestion!) + +## 2.8 + +* Add fields for total compressed and uncompressed sizes of archive (Issue #32 - Thanks to @gerchicov-bp for the suggestion!) +* Upgraded to UnRAR library v5.4.5 (PR #36 - Thanks to @aonez for the suggestion!) +* Began importing `Foundation` instead of `UIKit` or `Cocoa` in `UnrarKit.h` (PR #37 - Thanks to @amosavian for the suggestion!) + +## 2.7.1 + +* Pushing tagged builds to CocoaPods from Travis +* Adding release notes to GitHub + +## 2.7 + +Updated to the latest version of the UnRAR library (v5.3.11) + + +## 2.6 + +* Added full support for Carthage (Issue #22) +* Added annotations for nullability, improving compatibility with Xcode 7 and Swift + + +## 2.5.3 + +Fixed Podspec bug causing build errors when building as a framework with CocoaPods (Issue #28) + + +## 2.5.2 + +Moved off of deprecated `xcconfig` attribute in podspec (Issue #25) + + +## 2.5.1 + +Improved performance of the `-isPasswordProtected` method (Issue #24) + + +## 2.5 + +Fixed bug in -extractFilesTo:overwrite:progress:error: that would sometimes cause garbage characters in the extracted files' names (Issue #20) + + +## 2.4.3 + +Tweaked isPasswordProtected so it doesn't log an error message when an archive has a header password (Issue #21) + + +## 2.4.2 + +Fixed bug causing validatePassword to return NO for valid passwords in RAR5 archives (Issue #19) + + +## 2.4.1 + +Decreased size of library, by removing large sample archives (Issue #18), and added more information to the readme file + + +## 2.4 + +Added methods to detect whether a file is a RAR archive (Issue #17) + + +## 2.3 + +* Full Unicode support (Issue #11) +* Better support for moving files during a decompression into memory by adding a new block-based method that streams the file (Issue #4) +* Added pervasive use of new [URKFileInfo](Classes/URKFileInfo.h) class, which exposes several metadata fields of each file, rather than relying on passing filenames around (Issue #7 - Thanks, @mmcdole!) +* Added methods to test whether an archive is password-protected, and to test a given password (Issue #10 - Thanks, @scinfu!) +* Added progress reporting callbacks to most methods (Issue #6) +* Added several block-based methods that allow a guarantee of completing successfully, even if a file moves or gets deleted (Issue #5) +* Now fully thread-safe, even accessing the same archive object on different threads (it will block, instead of crashing) + + +## 2.2.4 + +Added -lc++ to CocoaPods linker flags, so that a .mm file is no longer required for a successful build + + +## 2.2.2 + +Added documentation, full Travis CI integration + + +## 2.2 + +Upgraded to unrar library 5.2.1 + + +## 2.1 + +Fixed bug in NSErrors generated + + +## 2.0.7 + +Fixed major leak of file descriptors, causing clients to run out of file descriptors + + +## 2.0.6 + +Added requires_arc flag to podspec + + +## 2.0.5 + +Fixed an Xcode 6 compilation bug + + +## 2.0.2 + +First release in CocoaPods spec repo + + +## 2.0.0 + +Initial release diff --git a/Carthage/Checkouts/UnrarKit/Classes/Categories/NSString+UnrarKit.h b/Carthage/Checkouts/UnrarKit/Classes/Categories/NSString+UnrarKit.h new file mode 100644 index 0000000..2ddd6dc --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Classes/Categories/NSString+UnrarKit.h @@ -0,0 +1,13 @@ +// +// NSString+UnrarKit.h +// UnrarKit +// +// + +#import + +@interface NSString (UnrarKit) + ++ (instancetype)stringWithUnichars:(wchar_t *)unichars; + +@end diff --git a/Carthage/Checkouts/UnrarKit/Classes/Categories/NSString+UnrarKit.mm b/Carthage/Checkouts/UnrarKit/Classes/Categories/NSString+UnrarKit.mm new file mode 100644 index 0000000..729f184 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Classes/Categories/NSString+UnrarKit.mm @@ -0,0 +1,22 @@ +// +// NSString+UnrarKit.m +// UnrarKit +// +// + +#import "NSString+UnrarKit.h" +#import "UnrarKitMacros.h" + +RarHppIgnore +#import "rar.hpp" +#pragma clang diagnostic pop + +@implementation NSString (UnrarKit) + ++ (instancetype)stringWithUnichars:(wchar_t *)unichars { + return [[NSString alloc] initWithBytes:unichars + length:wcslen(unichars) * sizeof(*unichars) + encoding:NSUTF32LittleEndianStringEncoding]; +} + +@end diff --git a/Carthage/Checkouts/UnrarKit/Classes/URKArchive.h b/Carthage/Checkouts/UnrarKit/Classes/URKArchive.h new file mode 100644 index 0000000..bd064cb --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Classes/URKArchive.h @@ -0,0 +1,496 @@ +// +// URKArchive.h +// UnrarKit +// +// + +#import +#import +#import "UnrarKitMacros.h" + +RarosHppIgnore +#import "raros.hpp" +#pragma clang diagnostic pop + +DllHppIgnore +#import "dll.hpp" +#pragma clang diagnostic pop + +@class URKFileInfo; + +/** + * Defines the various error codes that the listing and extraction methods return. + * These are returned in NSError's [code]([NSError code]) field. + */ +typedef NS_ENUM(NSInteger, URKErrorCode) { + + /** + * The archive's header is empty + */ + URKErrorCodeEndOfArchive = ERAR_END_ARCHIVE, + + /** + * The library ran out of memory while reading the archive + */ + URKErrorCodeNoMemory = ERAR_NO_MEMORY, + + /** + * The header is broken + */ + URKErrorCodeBadData = ERAR_BAD_DATA, + + /** + * The archive is not a valid RAR file + */ + URKErrorCodeBadArchive = ERAR_BAD_ARCHIVE, + + /** + * The archive is an unsupported RAR format or version + */ + URKErrorCodeUnknownFormat = ERAR_UNKNOWN_FORMAT, + + /** + * Failed to open a reference to the file + */ + URKErrorCodeOpen = ERAR_EOPEN, + + /** + * Failed to create the target directory for extraction + */ + URKErrorCodeCreate = ERAR_ECREATE, + + /** + * Failed to close the archive + */ + URKErrorCodeClose = ERAR_ECLOSE, + + /** + * Failed to read the archive + */ + URKErrorCodeRead = ERAR_EREAD, + + /** + * Failed to write a file to disk + */ + URKErrorCodeWrite = ERAR_EWRITE, + + /** + * The archive header's comments are larger than the buffer size + */ + URKErrorCodeSmall = ERAR_SMALL_BUF, + + /** + * The cause of the error is unspecified + */ + URKErrorCodeUnknown = ERAR_UNKNOWN, + + /** + * A password was not given for a password-protected archive + */ + URKErrorCodeMissingPassword = ERAR_MISSING_PASSWORD, + + /** + * No data was returned from the archive + */ + URKErrorCodeArchiveNotFound = 101, + + /** + * User cancelled the operation + */ + URKErrorCodeUserCancelled = 102, + + /** + * Error converting string to UTF-8 + */ + URKErrorCodeStringConversion = 103, +}; + +typedef NSString *const URKProgressInfoKey; + + +/** + * Defines the keys passed in `-[NSProgress userInfo]` for certain methods + */ +static URKProgressInfoKey _Nonnull + /** + * For `extractFilesTo:overwrite:error:`, this key contains an instance of URKFileInfo with the file currently being extracted + */ + URKProgressInfoKeyFileInfoExtracting = @"URKProgressInfoKeyFileInfoExtracting"; + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *URKErrorDomain; + +/** + * An Objective-C/Cocoa wrapper around the unrar library + */ +@interface URKArchive : NSObject +// Minimum of iOS 9, macOS 10.11 SDKs +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED > 90000) || (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED > 101100) + +#endif + + +/** + * The URL of the archive + */ +@property(nullable, weak, atomic, readonly) NSURL *fileURL; + +/** + * The filename of the archive + */ +@property(nullable, weak, atomic, readonly) NSString *filename; + +/** + * The password of the archive + */ +@property(nullable, nonatomic, strong) NSString *password; + +/** + * The total uncompressed size (in bytes) of all files in the archive. Returns nil on errors + */ +@property(nullable, atomic, readonly) NSNumber *uncompressedSize; + +/** + * The total compressed size (in bytes) of the archive. Returns nil on errors + */ +@property(nullable, atomic, readonly) NSNumber *compressedSize; + +/** + * True if the file is one volume of a multi-part archive + */ +@property(atomic, readonly) BOOL hasMultipleVolumes; + +/** + * Can be used for progress reporting, but it's not necessary. You can also use + * implicit progress reporting. If you don't use it, one will still be created, + * which will become a child progress of whichever one is the current NSProgress + * instance. + * + * To use this, assign it before beginning an operation that reports progress. Once + * the method you're calling has a reference to it, it will nil it out. Please check + * for nil before assigning it to avoid concurrency conflicts. + */ +@property(nullable, strong) NSProgress *progress; + + +/** + * **DEPRECATED:** Creates and returns an archive at the given path + * + * @param filePath A path to the archive file + */ ++ (nullable instancetype)rarArchiveAtPath:(NSString *)filePath __deprecated_msg("Use -initWithPath:error: instead"); + +/** + * **DEPRECATED:** Creates and returns an archive at the given URL + * + * @param fileURL The URL of the archive file + */ ++ (nullable instancetype)rarArchiveAtURL:(NSURL *)fileURL __deprecated_msg("Use -initWithURL:error: instead"); + +/** + * **DEPRECATED:** Creates and returns an archive at the given path, with a given password + * + * @param filePath A path to the archive file + * @param password The passowrd of the given archive + */ ++ (nullable instancetype)rarArchiveAtPath:(NSString *)filePath password:(NSString *)password __deprecated_msg("Use -initWithPath:password:error: instead"); + +/** + * **DEPRECATED:** Creates and returns an archive at the given URL, with a given password + * + * @param fileURL The URL of the archive file + * @param password The passowrd of the given archive + */ ++ (nullable instancetype)rarArchiveAtURL:(NSURL *)fileURL password:(NSString *)password __deprecated_msg("Use -initWithURL:password:error: instead"); + + +/** + * Do not use the default initializer + */ +- (instancetype)init NS_UNAVAILABLE; + +/** + * Creates and returns an archive at the given path + * + * @param filePath A path to the archive file + * @param error Contains any error during initialization + * + * @return Returns an initialized URKArchive, unless there's a problem creating a bookmark to the path + */ +- (nullable instancetype)initWithPath:(NSString *)filePath error:(NSError **)error; + +/** + * Creates and returns an archive at the given URL + * + * @param fileURL The URL of the archive file + * @param error Contains any error during initialization + * + * @return Returns an initialized URKArchive, unless there's a problem creating a bookmark to the URL + */ +- (nullable instancetype)initWithURL:(NSURL *)fileURL error:(NSError **)error; + +/** + * Creates and returns an archive at the given path, with a given password + * + * @param filePath A path to the archive file + * @param password The passowrd of the given archive + * @param error Contains any error during initialization + * + * @return Returns an initialized URKArchive, unless there's a problem creating a bookmark to the path + */ +- (nullable instancetype)initWithPath:(NSString *)filePath password:(NSString *)password error:(NSError **)error; + +/** + * Creates and returns an archive at the given URL, with a given password + * + * @param fileURL The URL of the archive file + * @param password The passowrd of the given archive + * @param error Contains any error during initialization + * + * @return Returns an initialized URKArchive, unless there's a problem creating a bookmark to the URL + */ +- (nullable instancetype)initWithURL:(NSURL *)fileURL password:(NSString *)password error:(NSError **)error; + + +/** + * Determines whether a file is a RAR archive by reading the signature + * + * @param filePath Path to the file being checked + * + * @return YES if the file exists and contains a signature indicating it is a RAR archive + */ ++ (BOOL)pathIsARAR:(NSString *)filePath; + +/** + * Determines whether a file is a RAR archive by reading the signature + * + * @param fileURL URL of the file being checked + * + * @return YES if the file exists and contains a signature indicating it is a RAR archive + */ ++ (BOOL)urlIsARAR:(NSURL *)fileURL; + +/** + * Lists the names of the files in the archive + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return Returns a list of NSString containing the paths within the archive's contents, or nil if an error was encountered + */ +- (nullable NSArray *)listFilenames:(NSError **)error; + +/** + * Lists the various attributes of each file in the archive + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return Returns a list of URKFileInfo objects, which contain metadata about the archive's files, or nil if an error was encountered + */ +- (nullable NSArray *)listFileInfo:(NSError **)error; + +/** + * Iterates the header of the archive, calling the block with each archived file's info. + * + * WARNING: There is no filtering of duplicate header entries. If a file is listed twice, `action` + * will be called twice with that file's path + * + * @param action The action to perform using the data. Must be non-nil + * + * - *fileInfo* The metadata of the file within the archive + * - *stop* Set to YES to stop reading the archive + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return Returns NO if an error was encountered + */ +- (BOOL) iterateFileInfo:(void(^)(URKFileInfo *fileInfo, BOOL *stop))action + error:(NSError **)error; + +/** + * Lists the URLs of volumes in a single- or multi-volume archive + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return Returns the list of URLs of all volumes of the archive + */ +- (nullable NSArray *)listVolumeURLs:(NSError **)error; + +/** + * Writes all files in the archive to the given path. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction. Use the progress property (as explained in the README) to + * retrieve more detailed information, such as the current file being extracted, number of files extracted, + * and the URKFileInfo instance being extracted + * + * @param filePath The destination path of the unarchived files + * @param overwrite YES to overwrite files in the destination directory, NO otherwise + * @param error Contains an NSError object when there was an error reading the archive + * + * @return YES on successful extraction, NO if an error was encountered + */ +- (BOOL)extractFilesTo:(NSString *)filePath + overwrite:(BOOL)overwrite + error:(NSError **)error; + +/** + * **DEPRECATED:** Writes all files in the archive to the given path + * + * @param filePath The destination path of the unarchived files + * @param overwrite YES to overwrite files in the destination directory, NO otherwise + * @param progressBlock Called every so often to report the progress of the extraction + * + * - *currentFile* The info about the file that's being extracted + * - *percentArchiveDecompressed* The percentage of the archive that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return YES on successful extraction, NO if an error was encountered + */ +- (BOOL)extractFilesTo:(NSString *)filePath + overwrite:(BOOL)overwrite + progress:(nullable void (^)(URKFileInfo *currentFile, CGFloat percentArchiveDecompressed))progressBlock + error:(NSError **)error __deprecated_msg("Use -extractFilesTo:overwrite:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * Unarchive a single file from the archive into memory. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction + * + * @param fileInfo The info of the file within the archive to be expanded. Only the filename property is used + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractData:(URKFileInfo *)fileInfo + error:(NSError **)error; + +/** + * **DEPRECATED:** Unarchive a single file from the archive into memory + * + * @param fileInfo The info of the file within the archive to be expanded. Only the filename property is used + * @param progressBlock Called every so often to report the progress of the extraction + * + * - *percentDecompressed* The percentage of the archive that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractData:(URKFileInfo *)fileInfo + progress:(nullable void (^)(CGFloat percentDecompressed))progressBlock + error:(NSError **)error __deprecated_msg("Use -extractData:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * Unarchive a single file from the archive into memory. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction + * + * @param filePath The path of the file within the archive to be expanded + * + * - *percentDecompressed* The percentage of the file that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractDataFromFile:(NSString *)filePath + error:(NSError **)error; + +/** + * **DEPRECATED:** Unarchive a single file from the archive into memory + * + * @param filePath The path of the file within the archive to be expanded + * @param progressBlock Called every so often to report the progress of the extraction + * + * - *percentDecompressed* The percentage of the file that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractDataFromFile:(NSString *)filePath + progress:(nullable void (^)(CGFloat percentDecompressed))progressBlock + error:(NSError **)error __deprecated_msg("Use -extractDataFromFile:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * Loops through each file in the archive in alphabetical order, allowing you to perform an + * action using its info. Supports NSProgress for progress reporting, which also allows + * cancellation of the operation in the middle + * + * @param action The action to perform using the data + * + * - *fileInfo* The metadata of the file within the archive + * - *stop* Set to YES to stop reading the archive + * + * @param error Contains an error if any was returned + * + * @return YES if no errors were encountered, NO otherwise + */ +- (BOOL)performOnFilesInArchive:(void(^)(URKFileInfo *fileInfo, BOOL *stop))action + error:(NSError **)error; + +/** + * Extracts each file in the archive into memory, allowing you to perform an action + * on it (not sorted). Supports NSProgress for progress reporting, which also allows + * cancellation of the operation in the middle + * + * @param action The action to perform using the data + * + * - *fileInfo* The metadata of the file within the archive + * - *fileData* The full data of the file in the archive + * - *stop* Set to YES to stop reading the archive + * + * @param error Contains an error if any was returned + * + * @return YES if no errors were encountered, NO otherwise + */ +- (BOOL)performOnDataInArchive:(void(^)(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop))action + error:(NSError **)error; + +/** + * Unarchive a single file from the archive into memory. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction + * + * @param filePath The path of the file within the archive to be expanded + * @param error Contains an NSError object when there was an error reading the archive + * @param action The block to run for each chunk of data, each of size <= bufferSize + * + * - *dataChunk* The data read from the archived file. Read bytes and length to write the data + * - *percentDecompressed* The percentage of the file that has been decompressed + * + * @return YES if all data was read successfully, NO if an error was encountered + */ +- (BOOL)extractBufferedDataFromFile:(NSString *)filePath + error:(NSError **)error + action:(void(^)(NSData *dataChunk, CGFloat percentDecompressed))action; + +/** + * YES if archive protected with a password, NO otherwise + */ +- (BOOL)isPasswordProtected; + +/** + * Tests whether the provided password unlocks the archive + * + * @return YES if correct password or archive is not password protected, NO if password is wrong + */ +- (BOOL)validatePassword; + +/** + Extract each file in the archive, checking whether the data matches the CRC checksum + stored at the time it was written + + @return YES if the data is all correct, false if any check failed + */ +- (BOOL)checkDataIntegrity; + +/** + Extract a particular file, to determine if its data matches the CRC + checksum stored at the time it written + + @param filePath The file in the archive to check + + @return YES if the data is correct, false if any check failed + */ +- (BOOL)checkDataIntegrityOfFile:(NSString *)filePath; + +@end +NS_ASSUME_NONNULL_END diff --git a/Carthage/Checkouts/UnrarKit/Classes/URKArchive.mm b/Carthage/Checkouts/UnrarKit/Classes/URKArchive.mm new file mode 100644 index 0000000..d00c3b8 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Classes/URKArchive.mm @@ -0,0 +1,1644 @@ +// +// URKArchive.mm +// UnrarKit +// +// + +#import "URKArchive.h" +#import "URKFileInfo.h" +#import "UnrarKitMacros.h" +#import "NSString+UnrarKit.h" + +#import "zlib.h" + +RarHppIgnore +#import "rar.hpp" +#pragma clang diagnostic pop + + +NSString *URKErrorDomain = @"URKErrorDomain"; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundef" +#if UNIFIED_LOGGING_SUPPORTED +os_log_t unrarkit_log; +BOOL unrarkitIsAtLeast10_13SDK; +#endif +#pragma clang diagnostic pop + +static NSBundle *_resources = nil; + + +@interface URKArchive () + +- (instancetype)initWithFile:(NSURL *)fileURL password:(NSString*)password error:(NSError * __autoreleasing *)error +// iOS 7, macOS 10.9 +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED > 70000) || (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED > 1090) +NS_DESIGNATED_INITIALIZER +#endif +; + +@property (assign) HANDLE rarFile; +@property (assign) struct RARHeaderDataEx *header; +@property (assign) struct RAROpenArchiveDataEx *flags; + +@property (strong) NSData *fileBookmark; + +@property (strong) NSObject *threadLock; + +@end + + +@implementation URKArchive + + + +#pragma mark - Deprecated Convenience Methods + + ++ (URKArchive *)rarArchiveAtPath:(NSString *)filePath +{ + return [[URKArchive alloc] initWithPath:filePath error:nil]; +} + ++ (URKArchive *)rarArchiveAtURL:(NSURL *)fileURL +{ + return [[URKArchive alloc] initWithURL:fileURL error:nil]; +} + ++ (URKArchive *)rarArchiveAtPath:(NSString *)filePath password:(NSString *)password +{ + return [[URKArchive alloc] initWithPath:filePath password:password error:nil]; +} + ++ (URKArchive *)rarArchiveAtURL:(NSURL *)fileURL password:(NSString *)password +{ + return [[URKArchive alloc] initWithURL:fileURL password:password error:nil]; +} + + + +#pragma mark - Initializers + + ++ (void)initialize { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSBundle *mainBundle = [NSBundle mainBundle]; + NSURL *resourcesURL = [mainBundle URLForResource:@"UnrarKitResources" withExtension:@"bundle"]; + + _resources = (resourcesURL + ? [NSBundle bundleWithURL:resourcesURL] + : mainBundle); + + URKLogInit(); + }); +} + +- (instancetype)init { + URKLogError("Attempted to use -init method, which is no longer supported"); + @throw [NSException exceptionWithName:NSInternalInconsistencyException + reason:@"-init is not a valid initializer for the class URKArchive" + userInfo:nil]; + return nil; +} + +- (instancetype)initWithPath:(NSString *)filePath error:(NSError * __autoreleasing *)error +{ + return [self initWithFile:[NSURL fileURLWithPath:filePath] error:error]; +} + +- (instancetype)initWithURL:(NSURL *)fileURL error:(NSError * __autoreleasing *)error +{ + return [self initWithFile:fileURL error:error]; +} + +- (instancetype)initWithPath:(NSString *)filePath password:(NSString *)password error:(NSError * __autoreleasing *)error +{ + return [self initWithFile:[NSURL fileURLWithPath:filePath] password:password error:error]; +} + +- (instancetype)initWithURL:(NSURL *)fileURL password:(NSString *)password error:(NSError * __autoreleasing *)error +{ + return [self initWithFile:fileURL password:password error:error]; +} + +- (instancetype)initWithFile:(NSURL *)fileURL error:(NSError * __autoreleasing *)error +{ + return [self initWithFile:fileURL password:nil error:error]; +} + +- (instancetype)initWithFile:(NSURL *)fileURL password:(NSString*)password error:(NSError * __autoreleasing *)error +{ + URKCreateActivity("Init Archive"); + + URKLogInfo("Initializing archive with URL %{public}@, path %{public}@, password %{public}@", fileURL, fileURL.path, [password length] != 0 ? @"given" : @"not given"); + + if (!fileURL) { + URKLogError("Cannot initialize archive with nil URL"); + return nil; + } + + if ((self = [super init])) { + if (error) { + *error = nil; + } + + NSURL *firstVolumeURL = [URKArchive firstVolumeURL:fileURL]; + NSString * _Nonnull fileURLAbsoluteString = static_cast(fileURL.absoluteString); + if (firstVolumeURL && ![firstVolumeURL.absoluteString isEqualToString:fileURLAbsoluteString]) { + URKLogDebug("Overriding fileURL with first volume URL: %{public}@", firstVolumeURL); + fileURL = firstVolumeURL; + } + + URKLogDebug("Initializing private fields"); + + NSError *bookmarkError = nil; + _fileBookmark = [fileURL bookmarkDataWithOptions:0 + includingResourceValuesForKeys:@[] + relativeToURL:nil + error:&bookmarkError]; + _password = password; + _threadLock = [[NSObject alloc] init]; + + if (bookmarkError) { + URKLogFault("Error creating bookmark to RAR archive: %{public}@", bookmarkError); + + if (error) { + *error = bookmarkError; + } + + return nil; + } + } + + return self; +} + + +#pragma mark - Properties + + +- (NSURL *)fileURL +{ + URKCreateActivity("Read Archive URL"); + + BOOL bookmarkIsStale = NO; + NSError *error = nil; + + NSURL *result = [NSURL URLByResolvingBookmarkData:self.fileBookmark + options:0 + relativeToURL:nil + bookmarkDataIsStale:&bookmarkIsStale + error:&error]; + + if (error) { + URKLogFault("Error resolving bookmark to RAR archive: %{public}@", error); + return nil; + } + + if (bookmarkIsStale) { + URKLogDebug("Refreshing stale bookmark"); + self.fileBookmark = [result bookmarkDataWithOptions:0 + includingResourceValuesForKeys:@[] + relativeToURL:nil + error:&error]; + + if (error) { + URKLogFault("Error creating fresh bookmark to RAR archive: %{public}@", error); + } + } + + return result; +} + +- (NSString *)filename +{ + URKCreateActivity("Read Archive Filename"); + + NSURL *url = self.fileURL; + + if (!url) { + return nil; + } + + return url.path; +} + +- (NSNumber *)uncompressedSize +{ + URKCreateActivity("Read Archive Uncompressed Size"); + + NSError *listError = nil; + NSArray *fileInfo = [self listFileInfo:&listError]; + + if (!fileInfo) { + URKLogError("Error getting uncompressed size: %{public}@", listError); + return nil; + } + + if (fileInfo.count == 0) { + URKLogInfo("No files in archive. Size == 0"); + return 0; + } + + return [fileInfo valueForKeyPath:@"@sum.uncompressedSize"]; +} + +- (NSNumber *)compressedSize +{ + URKCreateActivity("Read Archive Compressed Size"); + + NSString *filePath = self.filename; + + if (!filePath) { + URKLogError("Can't get compressed size, since a file path can't be resolved"); + return nil; + } + + URKLogInfo("Reading archive file attributes..."); + NSError *attributesError = nil; + NSDictionary *attributes = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath + error:&attributesError]; + + if (!attributes) { + URKLogError("Error getting compressed size of %{public}@: %{public}@", filePath, attributesError); + return nil; + } + + return [NSNumber numberWithUnsignedLongLong:attributes.fileSize]; +} + +- (BOOL)hasMultipleVolumes +{ + URKCreateActivity("Check If Multi-Volume Archive"); + + NSError *listError = nil; + NSArray *volumeURLs = [self listVolumeURLs:&listError]; + + if (!volumeURLs) { + URKLogError("Error getting file volumes list: %{public}@", listError); + return false; + } + + return volumeURLs.count > 1; +} + + + +#pragma mark - Zip file detection + + ++ (BOOL)pathIsARAR:(NSString *)filePath +{ + URKCreateActivity("Determining File Type (Path)"); + + NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:filePath]; + + if (!handle) { + URKLogError("No file handle returned for path: %{public}@", filePath); + return NO; + } + + @try { + NSData *fileData = [handle readDataOfLength:8]; + + if (fileData.length < 8) { + URKLogDebug("No file handle returned for path: %{public}@", filePath); + return NO; + } + + const unsigned char *dataBytes = (const unsigned char *)fileData.bytes; + + // Check the magic numbers for all versions (Rar!..) + if (dataBytes[0] != 0x52 || + dataBytes[1] != 0x61 || + dataBytes[2] != 0x72 || + dataBytes[3] != 0x21 || + dataBytes[4] != 0x1A || + dataBytes[5] != 0x07) { + URKLogDebug("File is not a RAR. Magic numbers != 'Rar!..'"); + return NO; + } + + // Check for v1.5 and on + if (dataBytes[6] == 0x00) { + URKLogDebug("File is a RAR >= v1.5"); + return YES; + } + + // Check for v5.0 + if (dataBytes[6] == 0x01 && + dataBytes[7] == 0x00) { + URKLogDebug("File is a RAR >= v5.0"); + return YES; + } + + URKLogDebug("File is not a RAR. Unknown contents in 7th and 8th bytes (%02X %02X)", dataBytes[6], dataBytes[7]); + } + @finally { + [handle closeFile]; + } + + return NO; +} + ++ (BOOL)urlIsARAR:(NSURL *)fileURL +{ + URKCreateActivity("Determining File Type (URL)"); + + if (!fileURL || !fileURL.path) { + URKLogDebug("File is not a RAR: nil URL or path"); + return NO; + } + + NSString *_Nonnull path = static_cast(fileURL.path); + return [URKArchive pathIsARAR:path]; +} + + + +#pragma mark - Public Methods + + +- (NSArray *)listFilenames:(NSError * __autoreleasing *)error +{ + URKCreateActivity("Listing Filenames"); + + NSArray *files = [self listFileInfo:error]; + return [files valueForKey:@"filename"]; +} + +- (NSArray *)listFileInfo:(NSError * __autoreleasing *)error +{ + URKCreateActivity("Listing File Info"); + + NSMutableSet *distinctFilenames = [NSMutableSet set]; + NSMutableArray *distinctFileInfo = [NSMutableArray array]; + NSError *innerError = nil; + + BOOL wasSuccessful = [self iterateFileInfo:^(URKFileInfo * _Nonnull fileInfo, BOOL * _Nonnull stop) { + if (![distinctFilenames containsObject:fileInfo.filename]) { + [distinctFileInfo addObject:fileInfo]; + [distinctFilenames addObject:fileInfo.filename]; + } else { + URKLogDebug("Skipping %{public}@ from list of file info, since it's already represented (probably from another archive volume)", fileInfo.filename); + } + } + error:&innerError]; + + if (!wasSuccessful) { + URKLogError("Failed to iterate file info: %{public}@", innerError); + + if (error && innerError) { + *error = innerError; + } + + return nil; + } + + URKLogDebug("Found %lu file info items", (unsigned long)distinctFileInfo.count); + return [NSArray arrayWithArray:distinctFileInfo]; +} + +- (BOOL) iterateFileInfo:(void(^)(URKFileInfo *fileInfo, BOOL *stop))action + error:(NSError * __autoreleasing *)error +{ + URKCreateActivity("Iterating File Info"); + NSAssert(action != nil, @"'action' is a required argument"); + + NSError *innerError = nil; + + URKLogDebug("Beginning to iterate through contents of %{public}@", self.filename); + + BOOL wasSuccessful = [self iterateAllFileInfo:action + error:&innerError]; + + if (!wasSuccessful) { + URKLogError("Failed to iterate all file info: %{public}@", innerError); + + if (error && innerError) { + *error = innerError; + } + + return NO; + } + + return YES; +} + +- (nullable NSArray *)listVolumeURLs:(NSError * __autoreleasing *)error +{ + URKCreateActivity("Listing Volume URLs"); + + NSArray *allFileInfo = [self allFileInfo:error]; + + if (!allFileInfo) { + return nil; + } + + NSMutableSet *volumeURLs = [[NSMutableSet alloc] init]; + + for (URKFileInfo* info in allFileInfo) { + NSURL *archiveURL = [NSURL fileURLWithPath:info.archiveName]; + + if (archiveURL) { + [volumeURLs addObject:archiveURL]; + } + } + + SEL sortBySelector = @selector(path); + NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:NSStringFromSelector(sortBySelector) ascending:YES]; + NSArray *sortedVolumes = [volumeURLs sortedArrayUsingDescriptors:@[sortDescriptor]]; + + return sortedVolumes; +} + +- (BOOL)extractFilesTo:(NSString *)filePath + overwrite:(BOOL)overwrite + error:(NSError * __autoreleasing *)error +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return [self extractFilesTo:filePath + overwrite:overwrite + progress:nil + error:error]; +#pragma clang diagnostic pop +} + +- (BOOL)extractFilesTo:(NSString *)filePath + overwrite:(BOOL)overwrite + progress:(void (^)(URKFileInfo *currentFile, CGFloat percentArchiveDecompressed))progressBlock + error:(NSError * __autoreleasing *)error +{ + URKCreateActivity("Extracting Files to Directory"); + + __block BOOL result = YES; + + NSError *listError = nil; + NSArray *fileInfos = [self listFileInfo:&listError]; + + if (!fileInfos || listError) { + URKLogError("Error listing contents of archive: %{public}@", listError); + + if (error) { + *error = listError; + } + + return NO; + } + + NSNumber *totalSize = [fileInfos valueForKeyPath:@"@sum.uncompressedSize"]; + __block long long bytesDecompressed = 0; + + NSProgress *progress = [self beginProgressOperation:totalSize.longLongValue]; + progress.kind = NSProgressKindFile; + + URKLogDebug("Archive has total size of %{iec-bytes}lld", totalSize.longLongValue); + + __weak URKArchive *welf = self; + + BOOL success = [self performActionWithArchiveOpen:^(NSError **innerError) { + URKCreateActivity("Performing File Extraction"); + + int RHCode = 0, PFCode = 0, filesExtracted = 0; + URKFileInfo *fileInfo; + + URKLogInfo("Extracting to %{public}@", filePath); + + URKLogDebug("Reading through RAR header looking for files..."); + while ((RHCode = RARReadHeaderEx(welf.rarFile, welf.header)) == ERAR_SUCCESS) { + fileInfo = [URKFileInfo fileInfo:welf.header]; + URKLogDebug("Extracting %{public}@ (%{iec-bytes}lld)", fileInfo.filename, fileInfo.uncompressedSize); + NSURL *extractedURL = [[NSURL fileURLWithPath:filePath] URLByAppendingPathComponent:fileInfo.filename]; + [progress setUserInfoObject:extractedURL + forKey:NSProgressFileURLKey]; + [progress setUserInfoObject:fileInfo + forKey:URKProgressInfoKeyFileInfoExtracting]; + + if ([self headerContainsErrors:innerError]) { + URKLogError("Header contains an error") + result = NO; + return; + } + + if (progress.isCancelled) { + NSString *errorName = nil; + [self assignError:innerError code:URKErrorCodeUserCancelled errorName:&errorName]; + URKLogInfo("Halted file extraction due to user cancellation: %{public}@", errorName); + result = NO; + return; + } + + char cFilePath[2048]; + BOOL utf8ConversionSucceeded = [filePath getCString:cFilePath + maxLength:sizeof(cFilePath) + encoding:NSUTF8StringEncoding]; + if (!utf8ConversionSucceeded) { + NSString *errorName = nil; + [self assignError:innerError code:URKErrorCodeStringConversion errorName:&errorName]; + URKLogError("Error converting file to UTF-8 (buffer too short?)"); + result = NO; + return; + } + + BOOL (^shouldCancelBlock)() = ^BOOL { + URKCreateActivity("shouldCancelBlock"); + URKLogDebug("Progress.isCancelled: %{public}@", progress.isCancelled ? @"YES" : @"NO") + return progress.isCancelled; + }; + RARSetCallback(welf.rarFile, AllowCancellationCallbackProc, (long)shouldCancelBlock); + + if ((PFCode = RARProcessFile(welf.rarFile, RAR_EXTRACT, cFilePath, NULL)) != 0) { + RARSetCallback(welf.rarFile, NULL, NULL); + + NSString *errorName = nil; + NSInteger errorCode = progress.isCancelled ? URKErrorCodeUserCancelled : PFCode; + [self assignError:innerError code:errorCode errorName:&errorName]; + URKLogError("Error extracting file: %{public}@ (%ld)", errorName, (long)errorCode); + result = NO; + return; + } + + [progress setUserInfoObject:@(++filesExtracted) + forKey:NSProgressFileCompletedCountKey]; + [progress setUserInfoObject:@(fileInfos.count) + forKey:NSProgressFileTotalCountKey]; + progress.completedUnitCount += fileInfo.uncompressedSize; + + URKLogDebug("Finished extracting %{public}@. Extraction %f complete", fileInfo.filename, progress.fractionCompleted); + + if (progressBlock) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdouble-promotion" + // I would change the signature of this block, but it's been deprecated already, + // so it'll just get dropped eventually, and it made sense to silence the warning + progressBlock(fileInfo, bytesDecompressed / totalSize.floatValue); +#pragma clang diagnostic pop + } + + bytesDecompressed += fileInfo.uncompressedSize; + } + + RARSetCallback(welf.rarFile, NULL, NULL); + + if (RHCode != ERAR_SUCCESS && RHCode != ERAR_END_ARCHIVE) { + NSString *errorName = nil; + [self assignError:innerError code:RHCode errorName:&errorName]; + URKLogError("Error reading file header: %{public}@ (%d)", errorName, RHCode); + result = NO; + } + + if (progressBlock) { + progressBlock(fileInfo, 1.0); + } + + } inMode:RAR_OM_EXTRACT error:error]; + + return success && result; +} + +- (NSData *)extractData:(URKFileInfo *)fileInfo + error:(NSError * __autoreleasing *)error +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return [self extractDataFromFile:fileInfo.filename progress:nil error:error]; +#pragma clang diagnostic pop +} + +- (NSData *)extractData:(URKFileInfo *)fileInfo + progress:(void (^)(CGFloat percentDecompressed))progressBlock + error:(NSError * __autoreleasing *)error +{ + return [self extractDataFromFile:fileInfo.filename progress:progressBlock error:error]; +} + +- (NSData *)extractDataFromFile:(NSString *)filePath + error:(NSError * __autoreleasing *)error +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return [self extractDataFromFile:filePath progress:nil error:error]; +#pragma clang diagnostic pop +} + +- (NSData *)extractDataFromFile:(NSString *)filePath + progress:(void (^)(CGFloat percentDecompressed))progressBlock + error:(NSError * __autoreleasing *)error +{ + URKCreateActivity("Extracting Data from File"); + + NSProgress *progress = [self beginProgressOperation:0]; + + __block NSData *result = nil; + __weak URKArchive *welf = self; + + BOOL success = [self performActionWithArchiveOpen:^(NSError **innerError) { + URKCreateActivity("Performing Extraction"); + + int RHCode = 0, PFCode = 0; + URKFileInfo *fileInfo; + + URKLogDebug("Reading through RAR header looking for files..."); + while ((RHCode = RARReadHeaderEx(welf.rarFile, welf.header)) == ERAR_SUCCESS) { + if ([self headerContainsErrors:innerError]) { + URKLogError("Header contains an error") + return; + } + + fileInfo = [URKFileInfo fileInfo:welf.header]; + + if ([fileInfo.filename isEqualToString:filePath]) { + URKLogDebug("Extracting %{public}@", fileInfo.filename); + break; + } + else { + URKLogDebug("Skipping %{public}@", fileInfo.filename); + if ((PFCode = RARProcessFileW(welf.rarFile, RAR_SKIP, NULL, NULL)) != 0) { + NSString *errorName = nil; + [self assignError:innerError code:(NSInteger)PFCode errorName:&errorName]; + URKLogError("Error skipping file: %{public}@ (%d)", errorName, PFCode); + return; + } + } + } + + if (RHCode != ERAR_SUCCESS) { + NSString *errorName = nil; + [self assignError:innerError code:RHCode errorName:&errorName]; + URKLogError("Error reading file header: %{public}@ (%d)", errorName, RHCode); + return; + } + + // Empty file, or a directory + if (fileInfo.uncompressedSize == 0) { + URKLogDebug("%{public}@ is empty or a directory", fileInfo.filename); + result = [NSData data]; + return; + } + + NSMutableData *fileData = [NSMutableData dataWithCapacity:(NSUInteger)fileInfo.uncompressedSize]; + CGFloat totalBytes = fileInfo.uncompressedSize; + progress.totalUnitCount = totalBytes; + __block long long bytesRead = 0; + + if (progressBlock) { + progressBlock(0.0); + } + + BOOL (^bufferedReadBlock)(NSData*) = ^BOOL(NSData *dataChunk) { + URKLogDebug("Appending buffered data (%lu bytes)", (unsigned long)dataChunk.length); + [fileData appendData:dataChunk]; + progress.completedUnitCount += dataChunk.length; + + bytesRead += dataChunk.length; + + if (progressBlock) { + progressBlock(bytesRead / totalBytes); + } + + if (progress.isCancelled) { + URKLogInfo("Cancellation initiated"); + return NO; + } + + return YES; + }; + RARSetCallback(welf.rarFile, BufferedReadCallbackProc, (long)bufferedReadBlock); + + URKLogInfo("Processing file..."); + PFCode = RARProcessFile(welf.rarFile, RAR_TEST, NULL, NULL); + + RARSetCallback(welf.rarFile, NULL, NULL); + + if (progress.isCancelled) { + NSString *errorName = nil; + [self assignError:innerError code:URKErrorCodeUserCancelled errorName:&errorName]; + URKLogInfo("Returning nil data from extraction due to user cancellation: %{public}@", errorName); + return; + } + + if (PFCode != 0) { + NSString *errorName = nil; + [self assignError:innerError code:(NSInteger)PFCode errorName:&errorName]; + URKLogError("Error extracting file data: %{public}@ (%d)", errorName, PFCode); + return; + } + + result = [NSData dataWithData:fileData]; + } inMode:RAR_OM_EXTRACT error:error]; + + if (!success) { + return nil; + } + + return result; +} + +- (BOOL)performOnFilesInArchive:(void(^)(URKFileInfo *fileInfo, BOOL *stop))action + error:(NSError * __autoreleasing *)error +{ + URKCreateActivity("Performing Action on Each File"); + + URKLogInfo("Listing file info"); + + NSError *listError = nil; + NSArray *fileInfo = [self listFileInfo:&listError]; + + if (listError || !fileInfo) { + URKLogError("Failed to list the files in the archive: %{public}@", listError); + + if (error) { + *error = listError; + } + + return NO; + } + + + NSProgress *progress = [self beginProgressOperation:fileInfo.count]; + + URKLogInfo("Sorting file info by name/path"); + + NSArray *sortedFileInfo = [fileInfo sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"filename" ascending:YES]]]; + + { + URKCreateActivity("Iterating Each File Info"); + + [sortedFileInfo enumerateObjectsUsingBlock:^(URKFileInfo *info, NSUInteger idx, BOOL *stop) { + if (progress.isCancelled) { + URKLogInfo("PerformOnFiles iteration was cancelled"); + *stop = YES; + } + + URKLogDebug("Performing action on %{public}@", info.filename); + action(info, stop); + progress.completedUnitCount += 1; + + if (*stop) { + URKLogInfo("Action dictated an early stop"); + progress.completedUnitCount = progress.totalUnitCount; + } + }]; + } + + return YES; +} + +- (BOOL)performOnDataInArchive:(void (^)(URKFileInfo *, NSData *, BOOL *))action + error:(NSError * __autoreleasing *)error +{ + URKCreateActivity("Performing Action on Each File's Data"); + + NSError *listError = nil; + NSArray *fileInfo = [self listFileInfo:&listError]; + + if (!fileInfo || listError) { + URKLogError("Error listing contents of archive: %{public}@", listError); + + if (error) { + *error = listError; + } + + return NO; + } + + NSNumber *totalSize = [fileInfo valueForKeyPath:@"@sum.uncompressedSize"]; + __weak URKArchive *welf = self; + + BOOL success = [self performActionWithArchiveOpen:^(NSError **innerError) { + int RHCode = 0, PFCode = 0; + + BOOL stop = NO; + + NSProgress *progress = [self beginProgressOperation:totalSize.longLongValue]; + + URKLogDebug("Reading through RAR header looking for files..."); + while ((RHCode = RARReadHeaderEx(welf.rarFile, welf.header)) == 0) { + if (stop || progress.isCancelled) { + URKLogDebug("Action dictated an early stop"); + return; + } + + if ([self headerContainsErrors:innerError]) { + URKLogError("Header contains an error") + return; + } + + URKFileInfo *info = [URKFileInfo fileInfo:welf.header]; + URKLogDebug("Performing action on %{public}@", info.filename); + + // Empty file, or a directory + if (info.uncompressedSize == 0) { + URKLogDebug("%{public}@ is an empty file, or a directory", info.filename); + action(info, [NSData data], &stop); + continue; + } + + UInt8 *buffer = (UInt8 *)malloc((size_t)info.uncompressedSize * sizeof(UInt8)); + UInt8 *callBackBuffer = buffer; + + RARSetCallback(welf.rarFile, CallbackProc, (long) &callBackBuffer); + + URKLogInfo("Processing file..."); + PFCode = RARProcessFile(welf.rarFile, RAR_TEST, NULL, NULL); + + if (PFCode != 0) { + NSString *errorName = nil; + [self assignError:innerError code:(NSInteger)PFCode errorName:&errorName]; + URKLogError("Error processing file: %{public}@ (%d)", errorName, PFCode); + return; + } + + URKLogDebug("Performing action on data (%lld bytes)", info.uncompressedSize); + NSData *data = [NSData dataWithBytesNoCopy:buffer length:(NSUInteger)info.uncompressedSize freeWhenDone:YES]; + action(info, data, &stop); + + progress.completedUnitCount += data.length; + } + + if (progress.isCancelled) { + NSString *errorName = nil; + [self assignError:innerError code:URKErrorCodeUserCancelled errorName:&errorName]; + URKLogInfo("Returning NO from performOnData:error: due to user cancellation: %{public}@", errorName); + return; + } + + if (RHCode != ERAR_SUCCESS && RHCode != ERAR_END_ARCHIVE) { + NSString *errorName = nil; + [self assignError:innerError code:RHCode errorName:&errorName]; + URKLogError("Error reading file header: %{public}@ (%d)", errorName, RHCode); + return; + } + } inMode:RAR_OM_EXTRACT error:error]; + + return success; +} + +- (BOOL)extractBufferedDataFromFile:(NSString *)filePath + error:(NSError * __autoreleasing *)error + action:(void(^)(NSData *dataChunk, CGFloat percentDecompressed))action +{ + URKCreateActivity("Extracting Buffered Data"); + + NSError *actionError = nil; + + NSProgress *progress = [self beginProgressOperation:0]; + + __weak URKArchive *welf = self; + + BOOL success = [self performActionWithArchiveOpen:^(NSError **innerError) { + URKCreateActivity("Performing action"); + + int RHCode = 0, PFCode = 0; + URKFileInfo *fileInfo; + + URKLogInfo("Looping through files, looking for %{public}@...", filePath); + + while ((RHCode = RARReadHeaderEx(welf.rarFile, welf.header)) == ERAR_SUCCESS) { + if ([self headerContainsErrors:innerError]) { + URKLogDebug("Header contains error") + return; + } + + URKLogDebug("Getting file info from header"); + fileInfo = [URKFileInfo fileInfo:welf.header]; + + if ([fileInfo.filename isEqualToString:filePath]) { + URKLogDebug("Found desired file"); + break; + } + else { + URKLogDebug("Skipping file..."); + if ((PFCode = RARProcessFile(welf.rarFile, RAR_SKIP, NULL, NULL)) != 0) { + NSString *errorName = nil; + [self assignError:innerError code:(NSInteger)PFCode errorName:&errorName]; + URKLogError("Failed to skip file: %{public}@ (%d)", errorName, PFCode); + return; + } + } + } + + long long totalBytes = fileInfo.uncompressedSize; + progress.totalUnitCount = totalBytes; + + if (RHCode != ERAR_SUCCESS) { + NSString *errorName = nil; + [self assignError:innerError code:RHCode errorName:&errorName]; + URKLogError("Header read yielded error: %{public}@ (%d)", errorName, RHCode); + return; + } + + // Empty file, or a directory + if (totalBytes == 0) { + URKLogInfo("File is empty or a directory"); + return; + } + + __block long long bytesRead = 0; + + // Repeating the argument instead of using positional specifiers, because they don't work with the {} formatters + URKLogDebug("Uncompressed size: %{iec-bytes}lld (%lld bytes) in file", totalBytes, totalBytes); + + BOOL (^bufferedReadBlock)(NSData*) = ^BOOL(NSData *dataChunk) { + if (progress.isCancelled) { + URKLogInfo("Buffered data read cancelled"); + return NO; + } + + bytesRead += dataChunk.length; + progress.completedUnitCount += dataChunk.length; + + double progressPercent = bytesRead / static_cast(totalBytes); + URKLogDebug("Read data chunk of size %lu (%.3f%% complete). Calling handler...", (unsigned long)dataChunk.length, progressPercent * 100); + action(dataChunk, progressPercent); + return YES; + }; + RARSetCallback(welf.rarFile, BufferedReadCallbackProc, (long)bufferedReadBlock); + + URKLogDebug("Processing file..."); + PFCode = RARProcessFile(welf.rarFile, RAR_TEST, NULL, NULL); + + RARSetCallback(welf.rarFile, NULL, NULL); + + if (progress.isCancelled) { + NSString *errorName = nil; + [self assignError:innerError code:URKErrorCodeUserCancelled errorName:&errorName]; + URKLogError("Buffered data extraction has been cancelled: %{public}@", errorName); + return; + } + + if (PFCode != 0) { + NSString *errorName = nil; + [self assignError:innerError code:(NSInteger)PFCode errorName:&errorName]; + URKLogError("Error processing file: %{public}@ (%d)", errorName, PFCode); + } + } inMode:RAR_OM_EXTRACT error:&actionError]; + + if (error) { + *error = actionError; + + if (actionError) { + URKLogError("Error reading buffered data from file\nfilePath: %{public}@\nerror: %{public}@", filePath, actionError); + } + } + + return success && !actionError; +} + +- (BOOL)isPasswordProtected +{ + URKCreateActivity("Checking Password Protection"); + + @try { + URKLogDebug("Opening archive"); + + NSError *error = nil; + if (![self _unrarOpenFile:self.filename + inMode:RAR_OM_EXTRACT + withPassword:nil + error:&error]) + { + URKLogError("Failed to open archive while checking for password: %{public}@", error); + return NO; + } + + URKLogDebug("Reading header and starting processing..."); + + int RHCode = RARReadHeaderEx(self.rarFile, self.header); + int PFCode = RARProcessFile(self.rarFile, RAR_SKIP, NULL, NULL); + + URKLogDebug("Checking header"); + if ([self headerContainsErrors:&error]) { + if (error.code == ERAR_MISSING_PASSWORD) { + URKLogDebug("Password is missing"); + return YES; + } + + URKLogError("Errors in header while checking for password: %{public}@", error); + } + + if (RHCode == ERAR_MISSING_PASSWORD || PFCode == ERAR_MISSING_PASSWORD) { + URKLogDebug("Missing password indicated by RHCode (%d) or PFCode (%d)", RHCode, PFCode); + return YES; + } + } + @finally { + [self closeFile]; + } + + URKLogDebug("Archive is not password protected"); + return NO; +} + +- (BOOL)validatePassword +{ + URKCreateActivity("Validating Password"); + + __block NSError *error = nil; + __block BOOL passwordIsGood = YES; + __weak URKArchive *welf = self; + + BOOL success = [self performActionWithArchiveOpen:^(NSError **innerError) { + URKCreateActivity("Performing action"); + + URKLogDebug("Opening and processing archive..."); + + int RHCode = RARReadHeaderEx(welf.rarFile, welf.header); + int PFCode = RARProcessFile(welf.rarFile, RAR_TEST, NULL, NULL); + + if ([self headerContainsErrors:innerError]) { + if (error.code == ERAR_MISSING_PASSWORD) { + URKLogDebug("Password invalidated by header"); + passwordIsGood = NO; + } + else { + URKLogError("Errors in header while validating password: %{public}@", error); + } + + return; + } + + if (RHCode == ERAR_MISSING_PASSWORD || PFCode == ERAR_MISSING_PASSWORD + || RHCode == ERAR_BAD_DATA || PFCode == ERAR_BAD_DATA + || RHCode == ERAR_BAD_PASSWORD || PFCode == ERAR_BAD_PASSWORD) + { + URKLogDebug("Missing/bad password indicated by RHCode (%d) or PFCode (%d)", RHCode, PFCode); + passwordIsGood = NO; + return; + } + } inMode:RAR_OM_EXTRACT error:&error]; + + if (!success) { + URKLogError("Error validating password: %{public}@", error); + return NO; + } + + return passwordIsGood; +} + +- (BOOL)checkDataIntegrity +{ + return [self checkDataIntegrityOfFile:(NSString *_Nonnull)nil]; +} + +- (BOOL)checkDataIntegrityOfFile:(NSString *)filePath +{ + URKCreateActivity("Checking Data Integrity"); + + URKLogInfo("Checking integrity of %{public}@", filePath ? filePath : @"whole archive"); + + __block BOOL corruptDataFound = YES; + + NSError *performOnFilesError = nil; + [self performOnFilesInArchive:^(URKFileInfo *fileInfo, BOOL *stop) { + URKCreateActivity("Iterating through each file"); + corruptDataFound = NO; // Set inside here so invalid archives are marked as corrupt + if (filePath && ![fileInfo.filename isEqualToString:filePath]) return; + + URKLogDebug("Extracting '%{public}@ to check its CRC...", fileInfo.filename); + NSError *extractError = nil; + NSData *fileData = [self extractData:fileInfo error:&extractError]; + if (!fileData) { + URKLogError("Error extracting %{public}@: %{public}@", fileInfo.filename, extractError); + *stop = YES; + return; + } + + uLong expectedCRC = fileInfo.CRC; + uLong actualCRC = crc32((uLong)0, (const Bytef*)fileData.bytes, (uint)fileData.length); + URKLogDebug("Checking integrity of %{public}@. Expected CRC: %010lu vs. Actual: %010lu", + fileInfo.filename, expectedCRC, actualCRC); + if (expectedCRC != actualCRC) { + corruptDataFound = YES; + URKLogError("Corrupt data found (filename: %{public}@, expected CRC: %010lu, actual CRC: %010lu", + fileInfo.filename, expectedCRC, actualCRC); + } + + if (filePath) *stop = YES; + } error:&performOnFilesError]; + + if (performOnFilesError) { + URKLogError("Error checking data integrity: %{public}@", performOnFilesError); + } + + return !corruptDataFound; +} + + +#pragma mark - Callback Functions + + +int CALLBACK CallbackProc(UINT msg, long UserData, long P1, long P2) { + URKCreateActivity("CallbackProc"); + + UInt8 **buffer; + + switch(msg) { + case UCM_CHANGEVOLUME: + URKLogDebug("msg: UCM_CHANGEVOLUME"); + break; + + case UCM_PROCESSDATA: + URKLogDebug("msg: UCM_PROCESSDATA; Copying data"); + buffer = (UInt8 **) UserData; + memcpy(*buffer, (UInt8 *)P1, P2); + // advance the buffer ptr, original m_buffer ptr is untouched + *buffer += P2; + break; + + case UCM_NEEDPASSWORD: + URKLogDebug("msg: UCM_NEEDPASSWORD"); + break; + } + + return 0; +} + +int CALLBACK BufferedReadCallbackProc(UINT msg, long UserData, long P1, long P2) { + URKCreateActivity("BufferedReadCallbackProc"); + BOOL (^bufferedReadBlock)(NSData*) = (__bridge BOOL(^)(NSData*))(void *)UserData; + + if (msg == UCM_PROCESSDATA) { + @autoreleasepool { + URKLogDebug("msg: UCM_PROCESSDATA; Copying data chunk and calling read block"); + NSData *dataChunk = [NSData dataWithBytes:(UInt8 *)P1 length:P2]; + BOOL cancelRequested = !bufferedReadBlock(dataChunk); + + if (cancelRequested) { + return -1; + } + } + } + + return 0; +} + +int CALLBACK AllowCancellationCallbackProc(UINT msg, long UserData, long P1, long P2) { + URKCreateActivity("AllowCancellationCallbackProc"); + BOOL (^shouldCancelBlock)() = (__bridge BOOL(^)())(void *)UserData; + + if (!shouldCancelBlock) { + return 0; + } + + BOOL shouldCancel = shouldCancelBlock(); + if (shouldCancel) { + URKLogDebug("Operation cancelled in shouldCancelBlock()"); + } + + return shouldCancel ? -1 : 0; +} + + + +#pragma mark - Private Methods + + +- (BOOL)performActionWithArchiveOpen:(void(^)(NSError **innerError))action + inMode:(NSInteger)mode + error:(NSError * __autoreleasing *)error +{ + URKCreateActivity("-performActionWithArchiveOpen:inMode:error:"); + + @synchronized(self.threadLock) { + URKLogDebug("Entered lock"); + + if (error) { + URKLogDebug("Error pointer passed in"); + *error = nil; + } + + URKLogDebug("Opening archive"); + NSError *openFileError = nil; + + if (![self _unrarOpenFile:self.filename + inMode:mode + withPassword:self.password + error:&openFileError]) { + URKLogError("Failed to open archive: %{public}@", openFileError); + + if (error) { + *error = openFileError; + } + + return NO; + } + + NSError *actionError = nil; + + @try { + URKLogDebug("Calling action block"); + action(&actionError); + } + @finally { + [self closeFile]; + } + + if (actionError) { + URKLogError("Action block returned error: %{public}@", actionError); + + if (error){ + *error = actionError; + } + } + + return !actionError; + } +} + +- (BOOL)_unrarOpenFile:(NSString *)rarFile inMode:(NSInteger)mode withPassword:(NSString *)aPassword error:(NSError * __autoreleasing *)error +{ + URKCreateActivity("-_unrarOpenFile:inMode:withPassword:error:"); + + if (error) { + URKLogDebug("Error pointer passed in"); + *error = nil; + } + + URKLogDebug("Zeroing out fields..."); + + ErrHandler.Clean(); + + self.header = new RARHeaderDataEx; + bzero(self.header, sizeof(RARHeaderDataEx)); + self.flags = new RAROpenArchiveDataEx; + bzero(self.flags, sizeof(RAROpenArchiveDataEx)); + + URKLogDebug("Setting archive name..."); + + const char *filenameData = (const char *) [rarFile UTF8String]; + self.flags->ArcName = new char[strlen(filenameData) + 1]; + strcpy(self.flags->ArcName, filenameData); + self.flags->OpenMode = (uint)mode; + + URKLogDebug("Opening archive %{public}@...", rarFile); + + self.rarFile = RAROpenArchiveEx(self.flags); + if (self.rarFile == 0 || self.flags->OpenResult != 0) { + NSString *errorName = nil; + [self assignError:error code:(NSInteger)self.flags->OpenResult errorName:&errorName]; + URKLogError("Error opening archive: %{public}@ (%d)", errorName, self.flags->OpenResult); + return NO; + } + + if(aPassword != nil) { + URKLogDebug("Setting password..."); + + char cPassword[2048]; + BOOL utf8ConversionSucceeded = [aPassword getCString:cPassword + maxLength:sizeof(cPassword) + encoding:NSUTF8StringEncoding]; + if (!utf8ConversionSucceeded) { + NSString *errorName = nil; + [self assignError:error code:URKErrorCodeStringConversion errorName:&errorName]; + URKLogError("Error converting password to UTF-8 (buffer too short?)"); + return NO; + } + + RARSetPassword(self.rarFile, cPassword); + } + + return YES; +} + +- (BOOL)closeFile +{ + URKCreateActivity("-closeFile"); + + if (self.rarFile) { + URKLogDebug("Closing archive %{public}@...", self.filename); + RARCloseArchive(self.rarFile); + } + + URKLogDebug("Cleaning up fields..."); + + self.rarFile = 0; + + if (self.flags) + delete self.flags->ArcName; + delete self.flags; self.flags = 0; + delete self.header; self.header = 0; + return YES; +} + +- (BOOL) iterateAllFileInfo:(void(^)(URKFileInfo *fileInfo, BOOL *stop))action + error:(NSError * __autoreleasing *)error +{ + URKCreateActivity("-allFileInfo:"); + NSAssert(action != nil, @"'action' is a required argument"); + + __weak URKArchive *welf = self; + + BOOL wasSuccessful = [self performActionWithArchiveOpen:^(NSError **innerError) { + URKCreateActivity("Performing List Action"); + + int RHCode = 0, PFCode = 0; + + URKLogDebug("Reading through RAR header looking for files..."); + + while ((RHCode = RARReadHeaderEx(welf.rarFile, welf.header)) == 0) { + URKLogDebug("Calling iterateAllFileInfo handler"); + BOOL shouldStop = NO; + URKFileInfo *info = [URKFileInfo fileInfo:welf.header]; + action(info, &shouldStop); + + if (shouldStop) { + URKLogDebug("iterateAllFileInfo got signal to stop"); + return; + } + + URKLogDebug("Skipping to next file..."); + if ((PFCode = RARProcessFile(welf.rarFile, RAR_SKIP, NULL, NULL)) != 0) { + NSString *errorName = nil; + [self assignError:innerError code:(NSInteger)PFCode errorName:&errorName]; + URKLogError("Error skipping to next header file: %{public}@ (%d)", errorName, PFCode); + return; + } + } + + if (RHCode != ERAR_SUCCESS && RHCode != ERAR_END_ARCHIVE) { + NSString *errorName = nil; + [self assignError:innerError code:RHCode errorName:&errorName]; + URKLogError("Error reading RAR header: %{public}@ (%d)", errorName, RHCode); + } + } inMode:RAR_OM_LIST_INCSPLIT error:error]; + + return wasSuccessful; +} + +- (NSArray *) allFileInfo:(NSError * __autoreleasing *)error { + URKCreateActivity("-allFileInfo:"); + + NSMutableArray *fileInfos = [NSMutableArray array]; + NSError *innerError = nil; + + URKLogDebug("Iterating all file info"); + BOOL wasSuccessful = [self iterateAllFileInfo:^(URKFileInfo *fileInfo, BOOL *stop) { + [fileInfos addObject:fileInfo]; + } + error:&innerError]; + + if (!wasSuccessful || !fileInfos) { + URKLogError("File info iteration was not successful: %{public}@", innerError); + + if (error && innerError) { + *error = innerError; + } + + return nil; + } + + URKLogDebug("Found %lu files", (unsigned long)fileInfos.count); + return [NSArray arrayWithArray:fileInfos]; +} + +- (NSString *)errorNameForErrorCode:(NSInteger)errorCode detail:(NSString * __autoreleasing *)errorDetail +{ + NSAssert(errorDetail != NULL, @"errorDetail out parameter not given"); + + NSString *errorName; + NSString *detail = @""; + + switch (errorCode) { + case URKErrorCodeEndOfArchive: + errorName = @"ERAR_END_ARCHIVE"; + break; + + case URKErrorCodeNoMemory: + errorName = @"ERAR_NO_MEMORY"; + detail = NSLocalizedStringFromTableInBundle(@"Ran out of memory while reading archive", @"UnrarKit", _resources, @"Error detail string"); + break; + + case URKErrorCodeBadData: + errorName = @"ERAR_BAD_DATA"; + detail = NSLocalizedStringFromTableInBundle(@"Archive has a corrupt header", @"UnrarKit", _resources, @"Error detail string"); + break; + + case URKErrorCodeBadArchive: + errorName = @"ERAR_BAD_ARCHIVE"; + detail = NSLocalizedStringFromTableInBundle(@"File is not a valid RAR archive", @"UnrarKit", _resources, @"Error detail string"); + break; + + case URKErrorCodeUnknownFormat: + errorName = @"ERAR_UNKNOWN_FORMAT"; + detail = NSLocalizedStringFromTableInBundle(@"RAR headers encrypted in unknown format", @"UnrarKit", _resources, @"Error detail string"); + break; + + case URKErrorCodeOpen: + errorName = @"ERAR_EOPEN"; + detail = NSLocalizedStringFromTableInBundle(@"Failed to open a reference to the file", @"UnrarKit", _resources, @"Error detail string"); + break; + + case URKErrorCodeCreate: + errorName = @"ERAR_ECREATE"; + detail = NSLocalizedStringFromTableInBundle(@"Failed to create the target directory for extraction", @"UnrarKit", _resources, @"Error detail string"); + break; + + case URKErrorCodeClose: + errorName = @"ERAR_ECLOSE"; + detail = NSLocalizedStringFromTableInBundle(@"Error encountered while closing the archive", @"UnrarKit", _resources, @"Error detail string"); + break; + + case URKErrorCodeRead: + errorName = @"ERAR_EREAD"; + detail = NSLocalizedStringFromTableInBundle(@"Error encountered while reading the archive", @"UnrarKit", _resources, @"Error detail string"); + break; + + case URKErrorCodeWrite: + errorName = @"ERAR_EWRITE"; + detail = NSLocalizedStringFromTableInBundle(@"Error encountered while writing a file to disk", @"UnrarKit", _resources, @"Error detail string"); + break; + + case URKErrorCodeSmall: + errorName = @"ERAR_SMALL_BUF"; + detail = NSLocalizedStringFromTableInBundle(@"Buffer too small to contain entire comments", @"UnrarKit", _resources, @"Error detail string"); + break; + + case URKErrorCodeUnknown: + errorName = @"ERAR_UNKNOWN"; + detail = NSLocalizedStringFromTableInBundle(@"An unknown error occurred", @"UnrarKit", _resources, @"Error detail string"); + break; + + case URKErrorCodeMissingPassword: + errorName = @"ERAR_MISSING_PASSWORD"; + detail = NSLocalizedStringFromTableInBundle(@"No password given to unlock a protected archive", @"UnrarKit", _resources, @"Error detail string"); + break; + + case URKErrorCodeArchiveNotFound: + errorName = @"ERAR_ARCHIVE_NOT_FOUND"; + detail = NSLocalizedStringFromTableInBundle(@"Unable to find the archive", @"UnrarKit", _resources, @"Error detail string"); + break; + + case URKErrorCodeUserCancelled: + errorName = @"ERAR_USER_CANCELLED"; + detail = NSLocalizedStringFromTableInBundle(@"User cancelled the operation in progress", @"UnrarKit", _resources, @"Error detail string"); + break; + + + case URKErrorCodeStringConversion: + errorName = @"ERAR_UTF8_PATH_CONVERSION"; + detail = NSLocalizedStringFromTableInBundle(@"Error converting a string to UTF-8", @"UnrarKit", _resources, @"Error detail string"); + break; + + default: + errorName = [NSString stringWithFormat:@"Unknown (%ld)", (long)errorCode]; + detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Unknown error encountered (code %ld)", @"UnrarKit", _resources, @"Error detail string"), errorCode]; + break; + } + + *errorDetail = detail; + return errorName; +} + +- (BOOL)assignError:(NSError * __autoreleasing *)error code:(NSInteger)errorCode errorName:(NSString * __autoreleasing *)outErrorName +{ + return [self assignError:error code:errorCode underlyer:nil errorName:outErrorName]; +} + +- (BOOL)assignError:(NSError * __autoreleasing *)error code:(NSInteger)errorCode underlyer:(NSError *)underlyingError errorName:(NSString * __autoreleasing *)outErrorName +{ + NSAssert(outErrorName, @"An out variable for errorName must be provided"); + + NSString *errorDetail = nil; + *outErrorName = [self errorNameForErrorCode:errorCode detail:&errorDetail]; + + if (error) { + NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary: + @{NSLocalizedFailureReasonErrorKey: *outErrorName, + NSLocalizedDescriptionKey: errorDetail, + NSLocalizedRecoverySuggestionErrorKey: errorDetail}]; + + if (self.fileURL) { + userInfo[NSURLErrorKey] = self.fileURL; + } + + if (underlyingError) { + userInfo[NSUnderlyingErrorKey] = underlyingError; + } + + *error = [NSError errorWithDomain:URKErrorDomain + code:errorCode + userInfo:userInfo]; + } + + return NO; +} + +- (BOOL)headerContainsErrors:(NSError * __autoreleasing *)error +{ + URKCreateActivity("-headerContainsErrors:"); + + BOOL isPasswordProtected = self.header->Flags & 0x04; + + if (isPasswordProtected && !self.password) { + NSString *errorName = nil; + [self assignError:error code:ERAR_MISSING_PASSWORD errorName:&errorName]; + URKLogError("Password protected and no password specified: %{public}@ (%d)", errorName, ERAR_MISSING_PASSWORD); + return YES; + } + + return NO; +} + +- (NSProgress *)beginProgressOperation:(unsigned long long)totalUnitCount +{ + URKCreateActivity("-beginProgressOperation:"); + + NSProgress *progress; + progress = self.progress; + self.progress = nil; + + if (!progress) { + progress = [[NSProgress alloc] initWithParent:[NSProgress currentProgress] + userInfo:nil]; + } + + if (totalUnitCount > 0) { + progress.totalUnitCount = totalUnitCount; + } + + progress.cancellable = YES; + progress.pausable = NO; + + return progress; +} + ++ (NSURL *)firstVolumeURL:(NSURL *)volumeURL { + URKCreateActivity("+firstVolumeURL:"); + + URKLogDebug("Checking if the file is part of a multi-volume archive..."); + + if (!volumeURL) { + URKLogError("+firstVolumeURL: nil volumeURL passed") + } + + NSString *volumePath = volumeURL.path; + + NSError *regexError = nil; + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:@"(.part)([0-9]+)(.rar)$" + options:NSRegularExpressionCaseInsensitive + error:®exError]; + if (!regex) { + URKLogError("Error constructing filename regex") + return nil; + } + + NSString *firstVolumePath = nil; + + // Check if it's following the current convention, like "Archive.part03.rar" + NSTextCheckingResult *match = [regex firstMatchInString:volumePath options:0 range:NSMakeRange(0, volumePath.length)]; + if (match) { + URKLogDebug("The file is part of a multi-volume archive"); + + NSRange numberRange = [match rangeAtIndex:2]; + NSString * partOne = [[@"" stringByPaddingToLength:numberRange.length - 1 + withString:@"0" + startingAtIndex:0] + stringByAppendingString:@"1"]; + + NSString * regexTemplate = [NSString stringWithFormat:@"$1%@$3", partOne]; + firstVolumePath = [regex stringByReplacingMatchesInString:volumePath + options:0 + range:NSMakeRange(0, volumePath.length) + withTemplate:regexTemplate]; + } + + // It still might be a multivolume archive. Check for the legacy naming convention, like "Archive.r03" + else { + // After rXX, rar uses r-z and symbols like {}|~... so accepting anything but a number + NSError *legacyRegexError = nil; + regex = [NSRegularExpression regularExpressionWithPattern:@"(\\.[^0-9])([0-9]+)$" + options:NSRegularExpressionCaseInsensitive + error:&legacyRegexError]; + + if (!regex) { + URKLogError("Error constructing legacy filename regex") + return nil; + } + + match = [regex firstMatchInString:volumePath options:0 range:NSMakeRange(0, volumePath.length)]; + if (match) { + URKLogDebug("The archive is part of a legacy volume"); + firstVolumePath = [[volumePath stringByDeletingPathExtension] stringByAppendingPathExtension:@"rar"]; + } + } + + // If it's a volume of either naming convention, use it + if (firstVolumePath) { + if ([[NSFileManager defaultManager] fileExistsAtPath:firstVolumePath]) { + URKLogDebug("First volume part %{public}@ found. Using as the main archive", firstVolumePath); + return [NSURL fileURLWithPath:firstVolumePath]; + } + else { + URKLogInfo("First volume part not found: %{public}@. Skipping first volume selection", firstVolumePath); + return nil; + } + } + + return volumeURL; +} + +@end diff --git a/Carthage/Checkouts/UnrarKit/Classes/URKFileInfo.h b/Carthage/Checkouts/UnrarKit/Classes/URKFileInfo.h new file mode 100644 index 0000000..5bf2c95 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Classes/URKFileInfo.h @@ -0,0 +1,158 @@ +// +// URKFileInfo.h +// UnrarKit +// + +#import +#import "UnrarKitMacros.h" + +RarosHppIgnore +#import "raros.hpp" +#pragma clang diagnostic pop + +DllHppIgnore +#import "dll.hpp" +#pragma clang diagnostic pop + +/* See http://www.forensicswiki.org/wiki/RAR and + http://www.rarlab.com/technote.htm#filehead for + more information about the RAR File Header spec */ + +/** + * Defines the packing methods that can be used on a file in an archive + */ +typedef NS_ENUM(NSUInteger, URKCompressionMethod) { + + /** + * No compression is used + */ + URKCompressionMethodStorage = 0x30, + + /** + * Fastest compression + */ + URKCompressionMethodFastest = 0x31, + + /** + * Fast compression + */ + URKCompressionMethodFast = 0x32, + + /** + * Normal compression + */ + URKCompressionMethodNormal = 0x33, + + /** + * Good compression + */ + URKCompressionMethodGood = 0x34, + + /** + * Best compression + */ + URKCompressionMethodBest = 0x35, +}; + +/** + * Defines the various operating systems that can be used when archiving + */ +typedef NS_ENUM(NSUInteger, URKHostOS) { + + /** + * MS-DOS + */ + URKHostOSMSDOS = 0, + + /** + * OS/2 + */ + URKHostOSOS2 = 1, + + /** + * Windows + */ + URKHostOSWindows = 2, + + /** + * Unix + */ + URKHostOSUnix = 3, + + /** + * Mac OS + */ + URKHostOSMacOS = 4, + + /** + * BeOS + */ + URKHostOSBeOS = 5, +}; + +/** + * A wrapper around a RAR archive's file header, defining the various fields + * it contains + */ +@interface URKFileInfo : NSObject + +/** + * The name of the file's archive + */ +@property (readonly, strong) NSString *archiveName; + +/** + * The name of the file + */ +@property (readonly, strong) NSString *filename; + +/** + * The timestamp of the file + */ +@property (readonly, strong) NSDate *timestamp; + +/** + * The CRC checksum of the file + */ +@property (readonly, assign) NSUInteger CRC; + +/** + * Size of the uncompressed file + */ +@property (readonly, assign) long long uncompressedSize; + +/** + * Size of the compressed file + */ +@property (readonly, assign) long long compressedSize; + +/** + * YES if the file will be continued of the next volume + */ +@property (readonly) BOOL isEncryptedWithPassword; + +/** + * YES if the file is a directory + */ +@property (readonly) BOOL isDirectory; + +/** + * The type of compression + */ +@property (readonly, assign) URKCompressionMethod compressionMethod; + +/** + * The OS of the file + */ +@property (readonly, assign) URKHostOS hostOS; + +/** + * Returns a URKFileInfo instance for the given extended header data + * + * @param fileHeader The header data for a RAR file + * + * @return an instance of URKFileInfo + */ ++ (instancetype) fileInfo:(struct RARHeaderDataEx *)fileHeader; + +@end diff --git a/Carthage/Checkouts/UnrarKit/Classes/URKFileInfo.m b/Carthage/Checkouts/UnrarKit/Classes/URKFileInfo.m new file mode 100644 index 0000000..24232eb --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Classes/URKFileInfo.m @@ -0,0 +1,84 @@ +// +// URKFileInfo.m +// UnrarKit +// + +#import "URKFileInfo.h" +#import "UnrarKitMacros.h" + +#import "NSString+UnrarKit.h" + +@implementation URKFileInfo + + + +#pragma mark - Initialization + + ++ (instancetype) fileInfo:(struct RARHeaderDataEx *)fileHeader { + return [[URKFileInfo alloc] initWithFileHeader:fileHeader]; +} + +- (instancetype)initWithFileHeader:(struct RARHeaderDataEx *)fileHeader +{ + URKCreateActivity("Init URKFileInfo"); + + if ((self = [super init])) { + URKLogDebug("Setting file info fields"); + + _filename = [NSString stringWithUnichars:fileHeader->FileNameW]; + _archiveName = [NSString stringWithUnichars:fileHeader->ArcNameW]; + _uncompressedSize = (long long) fileHeader->UnpSizeHigh << 32 | fileHeader->UnpSize; + _compressedSize = (long long) fileHeader->PackSizeHigh << 32 | fileHeader->PackSize; + _compressionMethod = fileHeader->Method; + _hostOS = fileHeader->HostOS; + _timestamp = [self parseDOSDate:fileHeader->FileTime]; + _CRC = fileHeader->FileCRC; + + //_fileContinuedFromPreviousVolume = fileHeader->Flags & (1 << 0) + //_fileContinuedOnNextVolume = fileHeader->Flags & (1 << 1) + _isEncryptedWithPassword = fileHeader->Flags & (1 << 2); + //_fileHasComment = fileHeader->Flags & (1 << 3) + + _isDirectory = fileHeader->Flags & RHDF_DIRECTORY; + } + + return self; +} + + + +#pragma mark - Private Methods + + +- (NSDate *)parseDOSDate:(NSUInteger)dosTime +{ + URKCreateActivity("-parseDOSDate:"); + + if (dosTime == 0) { + URKLogDebug("DOS Time == 0"); + return nil; + } + + // MSDOS Date Format Parsing specified at this URL: + // http://www.cocoanetics.com/2012/02/decompressing-files-into-memory/ + + int year = ((dosTime>>25) & 127) + 1980; // 7 bits + int month = (dosTime>>21) & 15; // 4 bits + int day = (dosTime>>16) & 31; // 5 bits + int hour = (dosTime>>11) & 31; // 5 bits + int minute = (dosTime>>5) & 63; // 6 bits + int second = (dosTime & 31) * 2; // 5 bits + + NSDateComponents *components = [[NSDateComponents alloc] init]; + components.year = year; + components.month = month; + components.day = day; + components.hour = hour; + components.minute = minute; + components.second = second; + + return [[NSCalendar currentCalendar] dateFromComponents:components]; +} + +@end diff --git a/Carthage/Checkouts/UnrarKit/Classes/UnrarKit.h b/Carthage/Checkouts/UnrarKit/Classes/UnrarKit.h new file mode 100644 index 0000000..78db3b3 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Classes/UnrarKit.h @@ -0,0 +1,19 @@ +// +// UnrarKit.h +// UnrarKit +// +// Created by Dov Frankel on 1/9/2015. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import + +//! Project version number for UnrarKit. +FOUNDATION_EXPORT double UnrarKitVersionNumber; + +//! Project version string for UnrarKit. +FOUNDATION_EXPORT const unsigned char UnrarKitVersionString[]; + + +#import "URKArchive.h" +#import "URKFileInfo.h" diff --git a/Carthage/Checkouts/UnrarKit/Classes/UnrarKitMacros.h b/Carthage/Checkouts/UnrarKit/Classes/UnrarKitMacros.h new file mode 100644 index 0000000..aea9343 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Classes/UnrarKitMacros.h @@ -0,0 +1,126 @@ +// +// UnrarKitMacros.h +// UnrarKit +// +// Created by Dov Frankel on 8/8/17. +// Copyright © 2017 Abbey Code. All rights reserved. +// + +#ifndef UnrarKitMacros_h +#define UnrarKitMacros_h + +//#import "Availability.h" +//#import "AvailabilityInternal.h" + +#define _stringify(a) #a + +#define RarHppIgnore \ +_Pragma( _stringify( clang diagnostic push ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wcast-align" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wextra-semi" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wold-style-cast" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wpadded" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wreserved-id-macro" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wshorten-64-to-32" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wcast-qual" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wundef" ) ) \ + +#define DllHppIgnore \ +_Pragma( _stringify( clang diagnostic push ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wreserved-id-macro" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wstrict-prototypes" ) ) \ + +#define RarosHppIgnore \ +_Pragma( _stringify( clang diagnostic push ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wreserved-id-macro" ) ) \ + + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundef" +#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" + + +// iOS 10, macOS 10.12, tvOS 10.0, watchOS 3.0 +#define UNIFIED_LOGGING_SUPPORTED \ +__IPHONE_OS_VERSION_MIN_REQUIRED >= 100000 \ +|| __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200 \ +|| __TV_OS_VERSION_MIN_REQUIRED >= 100000 \ +|| __WATCH_OS_VERSION_MIN_REQUIRED >= 30000 + +#if TARGET_OS_IPHONE +#define SDK_10_13_MAJOR 11 +#define SDK_10_13_MINOR 0 +#else +#define SDK_10_13_MAJOR 10 +#define SDK_10_13_MINOR 13 +#endif + +#if UNIFIED_LOGGING_SUPPORTED +#import +#import + +// Called from +[UnrarKit initialize] and +[URKArchiveTestCase setUp] +extern os_log_t unrarkit_log; // Declared in URKArchive.m +extern BOOL unrarkitIsAtLeast10_13SDK; // Declared in URKArchive.m +#define URKLogInit() \ + unrarkit_log = os_log_create("com.abbey-code.UnrarKit", "General"); \ + \ + NSOperatingSystemVersion minVersion; \ + minVersion.majorVersion = SDK_10_13_MAJOR; \ + minVersion.minorVersion = SDK_10_13_MINOR; \ + minVersion.patchVersion = 0; \ + unrarkitIsAtLeast10_13SDK = [[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:minVersion]; \ + URKLogDebug("Is >= 10.13 (or iOS 11): %@", unrarkitIsAtLeast10_13SDK ? @"YES" : @"NO"); + +#define URKLog(format, ...) os_log(unrarkit_log, format, ##__VA_ARGS__); +#define URKLogInfo(format, ...) os_log_info(unrarkit_log, format, ##__VA_ARGS__); +#define URKLogDebug(format, ...) os_log_debug(unrarkit_log, format, ##__VA_ARGS__); + + +#define URKLogError(format, ...) \ + if (unrarkitIsAtLeast10_13SDK) os_log_error(unrarkit_log, format, ##__VA_ARGS__); \ + else os_log_with_type(unrarkit_log, OS_LOG_TYPE_ERROR, format, ##__VA_ARGS__); + +#define URKLogFault(format, ...) \ + if (unrarkitIsAtLeast10_13SDK) os_log_fault(unrarkit_log, format, ##__VA_ARGS__); \ + else os_log_with_type(unrarkit_log, OS_LOG_TYPE_FAULT, format, ##__VA_ARGS__); + + +#define URKCreateActivity(name) \ +os_activity_t activity = os_activity_create(name, OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); \ +os_activity_scope(activity); + + +#else // Fall back to regular NSLog + +// No-op, as nothing needs to be initialized +#define URKLogInit() (void)0 + + +// Only used below +#define _removeLogFormatTokens(format) [[@format \ + stringByReplacingOccurrencesOfString:@"{public}" withString:@""] \ + stringByReplacingOccurrencesOfString:@"{iec-bytes}" withString:@""] +#define _nsLogWithoutWarnings(format, ...) \ +_Pragma( _stringify( clang diagnostic push ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wformat-nonliteral" ) ) \ +_Pragma( _stringify( clang diagnostic ignored "-Wformat-security" ) ) \ +NSLog(_removeLogFormatTokens(format), ##__VA_ARGS__); \ +_Pragma( _stringify( clang diagnostic pop ) ) + +// All levels do the same thing +#define URKLog(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); +#define URKLogInfo(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); +#define URKLogDebug(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); +#define URKLogError(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); +#define URKLogFault(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); + +// No-op, as no equivalent to Activities exists +#define URKCreateActivity(name) (void)0 + + +#pragma clang diagnostic pop + +#endif // UNIFIED_LOGGING_SUPPORTED + +#endif /* UnrarKitMacros_h */ diff --git a/Carthage/Checkouts/UnrarKit/Example/.gitignore b/Carthage/Checkouts/UnrarKit/Example/.gitignore new file mode 100644 index 0000000..a7cbee1 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Example/.gitignore @@ -0,0 +1 @@ +/*.DS_Store diff --git a/Carthage/Checkouts/UnrarKit/Example/Classes/UnrarExampleAppDelegate.h b/Carthage/Checkouts/UnrarKit/Example/Classes/UnrarExampleAppDelegate.h new file mode 100644 index 0000000..170c048 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Example/Classes/UnrarExampleAppDelegate.h @@ -0,0 +1,17 @@ +// +// UnrarExampleAppDelegate.h +// UnrarExample +// +// + +#import + +@class UnrarExampleViewController; + +@interface UnrarExampleAppDelegate : NSObject + +@property (nonatomic, strong) IBOutlet UIWindow *window; +@property (nonatomic, strong) IBOutlet UnrarExampleViewController *viewController; + +@end + diff --git a/Carthage/Checkouts/UnrarKit/Example/Classes/UnrarExampleAppDelegate.m b/Carthage/Checkouts/UnrarKit/Example/Classes/UnrarExampleAppDelegate.m new file mode 100644 index 0000000..59c8bd6 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Example/Classes/UnrarExampleAppDelegate.m @@ -0,0 +1,76 @@ +// +// UnrarExampleAppDelegate.m +// UnrarExample +// +// + +#import "UnrarExampleAppDelegate.h" +#import "UnrarExampleViewController.h" + +@implementation UnrarExampleAppDelegate + + +#pragma mark - Application lifecycle + +- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { + + // Override point for customization after application launch. + + // Add the view controller's view to the window and display. + [self.window addSubview:self.viewController.view]; + [self.window makeKeyAndVisible]; + + return YES; +} + + +- (void)applicationWillResignActive:(UIApplication *)application { + /* + Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. + */ +} + + +- (void)applicationDidEnterBackground:(UIApplication *)application { + /* + Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + If your application supports background execution, called instead of applicationWillTerminate: when the user quits. + */ +} + + +- (void)applicationWillEnterForeground:(UIApplication *)application { + /* + Called as part of transition from the background to the inactive state: here you can undo many of the changes made on entering the background. + */ +} + + +- (void)applicationDidBecomeActive:(UIApplication *)application { + /* + Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + */ +} + + +- (void)applicationWillTerminate:(UIApplication *)application { + /* + Called when the application is about to terminate. + See also applicationDidEnterBackground:. + */ +} + + +#pragma mark - Memory management + +- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application { + /* + Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later. + */ +} + + + + +@end diff --git a/Carthage/Checkouts/UnrarKit/Example/Classes/UnrarExampleViewController.h b/Carthage/Checkouts/UnrarKit/Example/Classes/UnrarExampleViewController.h new file mode 100644 index 0000000..80b5825 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Example/Classes/UnrarExampleViewController.h @@ -0,0 +1,24 @@ +// +// UnrarExampleViewController.h +// UnrarExample +// +// + +#import + +@interface UnrarExampleViewController : UIViewController + + +@property (weak, nonatomic) IBOutlet UITextField *passwordField; +@property (weak, nonatomic) IBOutlet UITextView *fileListTextView; + +@property (weak, nonatomic) IBOutlet UILabel *extractionStepLabel; +@property (weak, nonatomic) IBOutlet UIProgressView *extractionProgressView; + + +- (IBAction)listFiles:(id)sender; +- (IBAction)extractLargeFile:(id)sender; +- (IBAction)cancelExtraction:(id)sender; + +@end + diff --git a/Carthage/Checkouts/UnrarKit/Example/Classes/UnrarExampleViewController.m b/Carthage/Checkouts/UnrarKit/Example/Classes/UnrarExampleViewController.m new file mode 100644 index 0000000..bc9e7d2 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Example/Classes/UnrarExampleViewController.m @@ -0,0 +1,231 @@ +// +// UnrarExampleViewController.m +// UnrarExample +// +// + +#import "UnrarExampleViewController.h" +@import UnrarKit; + +@interface UnrarExampleViewController () + +@property (strong) NSURL *largeArchiveURL; +@property (strong) NSProgress *currentExtractionProgress; + +@end + +static void *ProgressObserverContext = &ProgressObserverContext; + + +@implementation UnrarExampleViewController + + +- (void)awakeFromNib { + [super awakeFromNib]; + + self.extractionStepLabel.text = @""; + + NSFileManager *fm = [NSFileManager defaultManager]; + NSURL *docsDir = [[fm URLsForDirectory:NSDocumentDirectory + inDomains:NSUserDomainMask] firstObject]; + self.largeArchiveURL = [docsDir URLByAppendingPathComponent:@"large-archive.rar"]; +} + +- (IBAction)listFiles:(id)sender { + NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Test Archive (Password)" ofType:@"rar"]; + + NSError *archiveError = nil; + URKArchive *archive = [[URKArchive alloc] initWithPath:filePath error:&archiveError]; + archive.password = self.passwordField.text; + + if (!archive) { + UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Failed to create archive" + message:@"Error creating the archive" + preferredStyle:UIAlertControllerStyleAlert]; + [controller addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]]; + + [self presentViewController:controller animated:YES completion:nil]; + return; + } + + NSError *error = nil; + NSArray *filenames = [archive listFilenames:&error]; + + if (!filenames) { + self.fileListTextView.text = error.localizedDescription; + return; + } + + NSMutableString *fileList = [NSMutableString string]; + + for (NSString *filename in filenames) { + [fileList appendFormat:@"• %@\n", filename]; + } + + self.fileListTextView.text = fileList; +} + +- (IBAction)extractLargeFile:(id)sender { + NSProgress *progress = [NSProgress progressWithTotalUnitCount:1]; + self.currentExtractionProgress = progress; + [progress addObserver:self + forKeyPath:NSStringFromSelector(@selector(fractionCompleted)) + options:NSKeyValueObservingOptionInitial + context:ProgressObserverContext]; + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{ + [self updateExtractionStep:@"Creating large archive…"]; + + NSURL *archiveURL = [self createLargeArchive]; + + if (!archiveURL) { + return; + } + + [self updateExtractionStep:@"Extracting archive…"]; + + NSError *initError = nil; + URKArchive *archive = [[URKArchive alloc] initWithURL:archiveURL + error:&initError]; + + if (!archive) { + [self reportError:[NSString stringWithFormat:@"Failed to create URKArchive: %@", initError.localizedDescription]]; + return; + } + + NSString *firstFile = [[archive listFilenames:nil] firstObject]; + + [progress becomeCurrentWithPendingUnitCount:1]; + + NSError *extractError = nil; + NSData *data = [archive extractDataFromFile:firstFile + error:&extractError]; + + self.currentExtractionProgress = nil; + [progress removeObserver:self + forKeyPath:NSStringFromSelector(@selector(fractionCompleted)) + context:ProgressObserverContext]; + [progress resignCurrent]; + + if (!data) { + [self reportError:[NSString stringWithFormat:@"Failed to extract archive: %@", extractError.localizedDescription]]; + return; + } + + // On extraction completion: + [self updateExtractionStep:[NSString stringWithFormat:@"Extracted %lub", (unsigned long)data.length]]; + }); +} + +- (IBAction)cancelExtraction:(id)sender { + if (self.currentExtractionProgress) { + [self.currentExtractionProgress cancel]; + } +} + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context +{ + if (context == ProgressObserverContext) { + NSProgress *progress = object; + + [[NSOperationQueue mainQueue] addOperationWithBlock:^{ + [self.extractionProgressView setProgress:progress.fractionCompleted + animated:YES]; + }]; + } else { + [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; + } +} + +- (void)reportError:(NSString *)message { + [[NSOperationQueue mainQueue] addOperationWithBlock:^{ + self.fileListTextView.text = message; + }]; +} + +- (void)updateExtractionStep:(NSString *)message { + [[NSOperationQueue mainQueue] addOperationWithBlock:^{ + self.extractionStepLabel.text = message; + }]; +} + +- (void)updateProgress:(float)progress { + [[NSOperationQueue mainQueue] addOperationWithBlock:^{ + [self.extractionProgressView setProgress:progress animated:YES]; + }]; +} + +- (NSURL *)createLargeArchive { + [self reportError:@""]; + [self updateExtractionStep:@"Creating large text file…"]; + + [self updateProgress:0]; + + NSURL *largeFile = [self randomTextFileOfLength:100000000]; + + if (!largeFile) { + [self reportError:@"Failed to create large text file"]; + return nil; + } + + [self updateProgress:0]; + + [self updateExtractionStep:@"Compressing large text file…"]; + + // Create archive + NSURL *archiveURL = self.largeArchiveURL; + + if (![archiveURL checkResourceIsReachableAndReturnError:nil]) { + [self updateExtractionStep:@"No archive"]; + [self reportError: + @"The large archive has not been created yet. A Terminal command " + "has been copied to the clipboard. Press ⌘C to copy it out " + "of the Simulator. From a prompt at the UnrarKit/Example " + "directory, paste it and run"]; + + UIPasteboard *pasteboard = [UIPasteboard generalPasteboard]; + pasteboard.string = largeFile.path; + + return nil; + } + + return archiveURL; +} + +- (NSURL *)randomTextFileOfLength:(NSUInteger)numberOfCharacters { + NSFileManager *fm = [NSFileManager defaultManager]; + NSURL *docsDir = [[fm URLsForDirectory:NSDocumentDirectory + inDomains:NSUserDomainMask] firstObject]; + NSString *filename = [NSString stringWithFormat:@"long-random-str-%lu.txt", (unsigned long)numberOfCharacters]; + NSURL *fileURL = [docsDir URLByAppendingPathComponent:filename]; + + if ([fileURL checkResourceIsReachableAndReturnError:nil]) { + return fileURL; + } + + NSString *letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 .,?!\n"; + NSUInteger letterCount = letters.length; + + NSMutableString *randomString = [NSMutableString stringWithCapacity:numberOfCharacters]; + + for (NSUInteger i = 0; i < numberOfCharacters; i++) { + uint32_t charIndex = arc4random_uniform((uint32_t)letterCount); + [randomString appendFormat:@"%C", [letters characterAtIndex:charIndex]]; + + float progress = i / (float)numberOfCharacters; + [self updateProgress:progress]; + } + + NSError *error = nil; + if (![randomString writeToURL:fileURL atomically:YES encoding:NSUTF16StringEncoding error:&error]) { + return nil; + } + + return fileURL; +} + + +@end diff --git a/Carthage/Checkouts/UnrarKit/Example/Default-568h@2x.png b/Carthage/Checkouts/UnrarKit/Example/Default-568h@2x.png new file mode 100644 index 0000000..0891b7a Binary files /dev/null and b/Carthage/Checkouts/UnrarKit/Example/Default-568h@2x.png differ diff --git a/Carthage/Checkouts/UnrarKit/Example/MainWindow.xib b/Carthage/Checkouts/UnrarKit/Example/MainWindow.xib new file mode 100644 index 0000000..f0a54e5 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Example/MainWindow.xib @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Carthage/Checkouts/UnrarKit/Example/UnrarExample-Info.plist b/Carthage/Checkouts/UnrarKit/Example/UnrarExample-Info.plist new file mode 100644 index 0000000..276e6f6 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Example/UnrarExample-Info.plist @@ -0,0 +1,30 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleDisplayName + ${PRODUCT_NAME} + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + APPL + CFBundleSignature + ???? + CFBundleVersion + 1.0 + LSRequiresIPhoneOS + + NSMainNibFile + MainWindow + + diff --git a/Carthage/Checkouts/UnrarKit/Example/UnrarExample.xcodeproj/.gitignore b/Carthage/Checkouts/UnrarKit/Example/UnrarExample.xcodeproj/.gitignore new file mode 100644 index 0000000..62821f5 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Example/UnrarExample.xcodeproj/.gitignore @@ -0,0 +1,4 @@ +/rogerio.mode1v3 +/rogerio.pbxuser +/*.mode1v3 +/*.pbxuser diff --git a/Carthage/Checkouts/UnrarKit/Example/UnrarExample.xcodeproj/project.pbxproj b/Carthage/Checkouts/UnrarKit/Example/UnrarExample.xcodeproj/project.pbxproj new file mode 100644 index 0000000..2d57e06 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Example/UnrarExample.xcodeproj/project.pbxproj @@ -0,0 +1,355 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 1D3623260D0F684500981E51 /* UnrarExampleAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* UnrarExampleAppDelegate.m */; }; + 1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; }; + 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1D30AB110D05D00D00671497 /* Foundation.framework */; }; + 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */; }; + 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765A40DF7441C002DB57D /* CoreGraphics.framework */; }; + 2899E5220DE3E06400AC0155 /* UnrarExampleViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2899E5210DE3E06400AC0155 /* UnrarExampleViewController.xib */; }; + 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = 28AD733E0D9D9553002E5188 /* MainWindow.xib */; }; + 28D7ACF80DDB3853001CB0EB /* UnrarExampleViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 28D7ACF70DDB3853001CB0EB /* UnrarExampleViewController.m */; }; + 7A67C2EC1F86D1C400D7FA38 /* UnrarKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A67C2ED1F86D1C400D7FA38 /* UnrarKit.framework */; }; + 964547CB1B32026700202B28 /* Test Archive (Password).rar in Resources */ = {isa = PBXBuildFile; fileRef = 964547CA1B32026700202B28 /* Test Archive (Password).rar */; }; + 96CD2C1A18D4D823002D004A /* Default-568h@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 96CD2C1918D4D823002D004A /* Default-568h@2x.png */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 1D30AB110D05D00D00671497 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; + 1D3623240D0F684500981E51 /* UnrarExampleAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnrarExampleAppDelegate.h; sourceTree = ""; }; + 1D3623250D0F684500981E51 /* UnrarExampleAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UnrarExampleAppDelegate.m; sourceTree = ""; }; + 1D6058910D05DD3D006BFB54 /* UnrarExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = UnrarExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; + 288765A40DF7441C002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; + 2899E5210DE3E06400AC0155 /* UnrarExampleViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = UnrarExampleViewController.xib; sourceTree = ""; }; + 28AD733E0D9D9553002E5188 /* MainWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = MainWindow.xib; sourceTree = ""; }; + 28D7ACF60DDB3853001CB0EB /* UnrarExampleViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnrarExampleViewController.h; sourceTree = ""; }; + 28D7ACF70DDB3853001CB0EB /* UnrarExampleViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UnrarExampleViewController.m; sourceTree = ""; }; + 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; + 32CA4F630368D1EE00C91783 /* UnrarExample_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnrarExample_Prefix.pch; sourceTree = ""; }; + 7A67C2ED1F86D1C400D7FA38 /* UnrarKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = UnrarKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 8D1107310486CEB800E47090 /* UnrarExample-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "UnrarExample-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = ""; }; + 964547CA1B32026700202B28 /* Test Archive (Password).rar */ = {isa = PBXFileReference; lastKnownFileType = file; name = "Test Archive (Password).rar"; path = "../Tests/Test Data/Test Archive (Password).rar"; sourceTree = ""; }; + 96CD2C1918D4D823002D004A /* Default-568h@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x.png"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 1D60588F0D05DD3D006BFB54 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 7A67C2EC1F86D1C400D7FA38 /* UnrarKit.framework in Frameworks */, + 1D60589F0D05DD5A006BFB54 /* Foundation.framework in Frameworks */, + 1DF5F4E00D08C38300B7A737 /* UIKit.framework in Frameworks */, + 288765A50DF7441C002DB57D /* CoreGraphics.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 080E96DDFE201D6D7F000001 /* Classes */ = { + isa = PBXGroup; + children = ( + 1D3623240D0F684500981E51 /* UnrarExampleAppDelegate.h */, + 1D3623250D0F684500981E51 /* UnrarExampleAppDelegate.m */, + 28D7ACF60DDB3853001CB0EB /* UnrarExampleViewController.h */, + 28D7ACF70DDB3853001CB0EB /* UnrarExampleViewController.m */, + ); + path = Classes; + sourceTree = ""; + }; + 19C28FACFE9D520D11CA2CBB /* Products */ = { + isa = PBXGroup; + children = ( + 1D6058910D05DD3D006BFB54 /* UnrarExample.app */, + ); + name = Products; + sourceTree = ""; + }; + 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { + isa = PBXGroup; + children = ( + 96CD2C1918D4D823002D004A /* Default-568h@2x.png */, + 080E96DDFE201D6D7F000001 /* Classes */, + 29B97315FDCFA39411CA2CEA /* Other Sources */, + 29B97317FDCFA39411CA2CEA /* Resources */, + 29B97323FDCFA39411CA2CEA /* Frameworks */, + 19C28FACFE9D520D11CA2CBB /* Products */, + ); + name = CustomTemplate; + sourceTree = ""; + }; + 29B97315FDCFA39411CA2CEA /* Other Sources */ = { + isa = PBXGroup; + children = ( + 32CA4F630368D1EE00C91783 /* UnrarExample_Prefix.pch */, + 29B97316FDCFA39411CA2CEA /* main.m */, + ); + name = "Other Sources"; + sourceTree = ""; + }; + 29B97317FDCFA39411CA2CEA /* Resources */ = { + isa = PBXGroup; + children = ( + 2899E5210DE3E06400AC0155 /* UnrarExampleViewController.xib */, + 28AD733E0D9D9553002E5188 /* MainWindow.xib */, + 8D1107310486CEB800E47090 /* UnrarExample-Info.plist */, + 964547CA1B32026700202B28 /* Test Archive (Password).rar */, + ); + name = Resources; + sourceTree = ""; + }; + 29B97323FDCFA39411CA2CEA /* Frameworks */ = { + isa = PBXGroup; + children = ( + 7A67C2ED1F86D1C400D7FA38 /* UnrarKit.framework */, + 1DF5F4DF0D08C38300B7A737 /* UIKit.framework */, + 1D30AB110D05D00D00671497 /* Foundation.framework */, + 288765A40DF7441C002DB57D /* CoreGraphics.framework */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 1D6058900D05DD3D006BFB54 /* UnrarExample */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "UnrarExample" */; + buildPhases = ( + 1D60588D0D05DD3D006BFB54 /* Resources */, + 1D60588E0D05DD3D006BFB54 /* Sources */, + 1D60588F0D05DD3D006BFB54 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = UnrarExample; + productName = UnrarExample; + productReference = 1D6058910D05DD3D006BFB54 /* UnrarExample.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 29B97313FDCFA39411CA2CEA /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0930; + }; + buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "UnrarExample" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 1D6058900D05DD3D006BFB54 /* UnrarExample */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 1D60588D0D05DD3D006BFB54 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 964547CB1B32026700202B28 /* Test Archive (Password).rar in Resources */, + 28AD733F0D9D9553002E5188 /* MainWindow.xib in Resources */, + 2899E5220DE3E06400AC0155 /* UnrarExampleViewController.xib in Resources */, + 96CD2C1A18D4D823002D004A /* Default-568h@2x.png in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 1D60588E0D05DD3D006BFB54 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 1D60589B0D05DD56006BFB54 /* main.m in Sources */, + 1D3623260D0F684500981E51 /* UnrarExampleAppDelegate.m in Sources */, + 28D7ACF80DDB3853001CB0EB /* UnrarExampleViewController.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1D6058940D05DD3E006BFB54 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_OBJC_ARC = YES; + COPY_PHASE_STRIP = NO; + FRAMEWORK_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; + GCC_DYNAMIC_NO_PIC = NO; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = UnrarExample_Prefix.pch; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(BUILT_PRODUCTS_DIR)/../../Headers", + ); + INFOPLIST_FILE = "UnrarExample-Info.plist"; + OTHER_CFLAGS = "-DTARGET_OS_IPHONE"; + PRODUCT_BUNDLE_IDENTIFIER = "com.yourcompany.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = UnrarExample; + }; + name = Debug; + }; + 1D6058950D05DD3E006BFB54 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_OBJC_ARC = YES; + COPY_PHASE_STRIP = YES; + FRAMEWORK_SEARCH_PATHS = "$(BUILT_PRODUCTS_DIR)"; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = UnrarExample_Prefix.pch; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(BUILT_PRODUCTS_DIR)/../../Headers", + ); + INFOPLIST_FILE = "UnrarExample-Info.plist"; + OTHER_CFLAGS = ( + "-DTARGET_OS_IPHONE", + "-DNS_BLOCK_ASSERTIONS=1", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.yourcompany.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = UnrarExample; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + C01FCF4F08A954540054247B /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + ONLY_ACTIVE_ARCH = YES; + OTHER_CPLUSPLUSFLAGS = "$(OTHER_CFLAGS)"; + OTHER_LDFLAGS = ( + "-lc++", + "-all_load", + ); + PREBINDING = NO; + SDKROOT = iphoneos; + }; + name = Debug; + }; + C01FCF5008A954540054247B /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + OTHER_CFLAGS = "-DNS_BLOCK_ASSERTIONS=1"; + OTHER_LDFLAGS = ( + "-lc++", + "-all_load", + ); + PREBINDING = NO; + SDKROOT = iphoneos; + WARNING_CFLAGS = "-Wno-error=unused-command-line-argument"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1D6058960D05DD3E006BFB54 /* Build configuration list for PBXNativeTarget "UnrarExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1D6058940D05DD3E006BFB54 /* Debug */, + 1D6058950D05DD3E006BFB54 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + C01FCF4E08A954540054247B /* Build configuration list for PBXProject "UnrarExample" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + C01FCF4F08A954540054247B /* Debug */, + C01FCF5008A954540054247B /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; +} diff --git a/Carthage/Checkouts/UnrarKit/Example/UnrarExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Carthage/Checkouts/UnrarKit/Example/UnrarExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..cad001f --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Example/UnrarExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Carthage/Checkouts/UnrarKit/Example/UnrarExample.xcodeproj/xcshareddata/xcschemes/UnrarExample.xcscheme b/Carthage/Checkouts/UnrarKit/Example/UnrarExample.xcodeproj/xcshareddata/xcschemes/UnrarExample.xcscheme new file mode 100644 index 0000000..10829dc --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Example/UnrarExample.xcodeproj/xcshareddata/xcschemes/UnrarExample.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Carthage/Checkouts/UnrarKit/Example/UnrarExampleViewController.xib b/Carthage/Checkouts/UnrarKit/Example/UnrarExampleViewController.xib new file mode 100644 index 0000000..7c17dc6 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Example/UnrarExampleViewController.xib @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Carthage/Checkouts/UnrarKit/Example/UnrarExample_Prefix.pch b/Carthage/Checkouts/UnrarKit/Example/UnrarExample_Prefix.pch new file mode 100644 index 0000000..8388e09 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Example/UnrarExample_Prefix.pch @@ -0,0 +1,8 @@ +// +// Prefix header for all source files of the 'UnrarExample' target in the 'UnrarExample' project +// + +#ifdef __OBJC__ + #import + #import +#endif diff --git a/Carthage/Checkouts/UnrarKit/Example/main.m b/Carthage/Checkouts/UnrarKit/Example/main.m new file mode 100644 index 0000000..b055753 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Example/main.m @@ -0,0 +1,17 @@ +// +// main.m +// UnrarExample +// +// Created by Rogerio Pereira Araujo on 08/11/10. +// Copyright 2010 __MyCompanyName__. All rights reserved. +// + +#import + +int main(int argc, char *argv[]) { + + @autoreleasepool { + int retVal = UIApplicationMain(argc, argv, nil, nil); + return retVal; + } +} diff --git a/Carthage/Checkouts/UnrarKit/Example/makeLargeArchive.sh b/Carthage/Checkouts/UnrarKit/Example/makeLargeArchive.sh new file mode 100755 index 0000000..3df3b64 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Example/makeLargeArchive.sh @@ -0,0 +1,7 @@ +#!/bin/bash + + +export UNCOMPRESSED_FILE="$1" +export ARCHIVE_NAME="`dirname $1`/large-archive.rar" + +"../Tests/Test Data/bin/rar" a -ep ${ARCHIVE_NAME} ${UNCOMPRESSED_FILE} \ No newline at end of file diff --git a/Carthage/Checkouts/UnrarKit/LICENSE b/Carthage/Checkouts/UnrarKit/LICENSE new file mode 100644 index 0000000..8fd672d --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/LICENSE @@ -0,0 +1,5 @@ +© Dov Frankel, All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/acknow.txt b/Carthage/Checkouts/UnrarKit/Libraries/unrar/acknow.txt new file mode 100644 index 0000000..a68b672 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/acknow.txt @@ -0,0 +1,92 @@ + ACKNOWLEDGMENTS + +* We used "Screaming Fast Galois Field Arithmetic Using Intel + SIMD Instructions" paper by James S. Plank, Kevin M. Greenan + and Ethan L. Miller to improve Reed-Solomon coding performance. + Also we are grateful to Artem Drobanov and Bulat Ziganshin + for samples and ideas allowed to make Reed-Solomon coding + more efficient. + +* RAR text compression algorithm is based on Dmitry Shkarin PPMII + and Dmitry Subbotin carryless rangecoder public domain source code. + You may find it in ftp.elf.stuba.sk/pub/pc/pack. + +* RAR encryption includes parts of code from Szymon Stefanek + and Brian Gladman AES implementations also as Steve Reid SHA-1 source. + + --------------------------------------------------------------------------- + Copyright (c) 2002, Dr Brian Gladman < >, Worcester, UK. + All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software in both source and binary + form is allowed (with or without changes) provided that: + + 1. distributions of this source code include the above copyright + notice, this list of conditions and the following disclaimer; + + 2. distributions in binary form include the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other associated materials; + + 3. the copyright holder's name is not used to endorse products + built using this software without specific written permission. + + ALTERNATIVELY, provided that this notice is retained in full, this product + may be distributed under the terms of the GNU General Public License (GPL), + in which case the provisions of the GPL apply INSTEAD OF those given above. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + + Source code of this package also as other cryptographic technology + and computing project related links are available on Brian Gladman's + web site: http://www.gladman.me.uk + +* RAR uses CRC32 function based on Intel Slicing-by-8 algorithm. + Original Intel Slicing-by-8 code is available here: + + http://sourceforge.net/projects/slicing-by-8/ + + Original Intel Slicing-by-8 code is licensed under BSD License + available at http://www.opensource.org/licenses/bsd-license.html + + Copyright (c) 2004-2006 Intel Corporation. + All Rights Reserved + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer + in the documentation and/or other materials provided with + the distribution. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. + +* RAR archives may optionally include BLAKE2sp hash ( https://blake2.net ), + designed by Jean-Philippe Aumasson, Samuel Neves, Zooko Wilcox-O'Hearn + and Christian Winnerlein. + +* Useful hints provided by Alexander Khoroshev and Bulat Ziganshin allowed + to significantly improve RAR compression and speed. diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/arccmt.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/arccmt.cpp new file mode 100644 index 0000000..ca98b10 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/arccmt.cpp @@ -0,0 +1,173 @@ +static bool IsAnsiEscComment(const wchar *Data,size_t Size); + +bool Archive::GetComment(Array *CmtData) +{ + if (!MainComment) + return false; + SaveFilePos SavePos(*this); + +#ifndef SFX_MODULE + uint CmtLength; + if (Format==RARFMT14) + { + Seek(SFXSize+SIZEOF_MAINHEAD14,SEEK_SET); + CmtLength=GetByte(); + CmtLength+=(GetByte()<<8); + } + else +#endif + { + if (MainHead.CommentInHeader) + { + // Old style (RAR 2.9) archive comment embedded into the main + // archive header. + Seek(SFXSize+SIZEOF_MARKHEAD3+SIZEOF_MAINHEAD3,SEEK_SET); + if (!ReadHeader() || GetHeaderType()!=HEAD3_CMT) + return false; + } + else + { + // Current (RAR 3.0+) version of archive comment. + Seek(GetStartPos(),SEEK_SET); + return SearchSubBlock(SUBHEAD_TYPE_CMT)!=0 && ReadCommentData(CmtData); + } +#ifndef SFX_MODULE + // Old style (RAR 2.9) comment header embedded into the main + // archive header. + if (BrokenHeader) + { + uiMsg(UIERROR_CMTBROKEN,FileName); + return false; + } + CmtLength=CommHead.HeadSize-SIZEOF_COMMHEAD; +#endif + } +#ifndef SFX_MODULE + if (Format==RARFMT14 && MainHead.PackComment || Format!=RARFMT14 && CommHead.Method!=0x30) + { + if (Format!=RARFMT14 && (CommHead.UnpVer < 15 || CommHead.UnpVer > VER_UNPACK || CommHead.Method > 0x35)) + return false; + ComprDataIO DataIO; + DataIO.SetTestMode(true); + uint UnpCmtLength; + if (Format==RARFMT14) + { +#ifdef RAR_NOCRYPT + return false; +#else + UnpCmtLength=GetByte(); + UnpCmtLength+=(GetByte()<<8); + CmtLength-=2; + DataIO.SetCmt13Encryption(); + CommHead.UnpVer=15; +#endif + } + else + UnpCmtLength=CommHead.UnpSize; + DataIO.SetFiles(this,NULL); + DataIO.EnableShowProgress(false); + DataIO.SetPackedSizeToRead(CmtLength); + DataIO.UnpHash.Init(HASH_CRC32,1); + DataIO.SetNoFileHeader(true); // this->FileHead is not filled yet. + + Unpack CmtUnpack(&DataIO); + CmtUnpack.Init(0x10000,false); + CmtUnpack.SetDestSize(UnpCmtLength); + CmtUnpack.DoUnpack(CommHead.UnpVer,false); + + if (Format!=RARFMT14 && (DataIO.UnpHash.GetCRC32()&0xffff)!=CommHead.CommCRC) + { + uiMsg(UIERROR_CMTBROKEN,FileName); + return false; + } + else + { + byte *UnpData; + size_t UnpDataSize; + DataIO.GetUnpackedData(&UnpData,&UnpDataSize); +#ifdef _WIN_ALL + // If we ever decide to extend it to Android, we'll need to alloc + // 4x memory for OEM to UTF-8 output here. + OemToCharBuffA((char *)UnpData,(char *)UnpData,(DWORD)UnpDataSize); +#endif + CmtData->Alloc(UnpDataSize+1); + memset(CmtData->Addr(0),0,CmtData->Size()*sizeof(wchar)); + CharToWide((char *)UnpData,CmtData->Addr(0),CmtData->Size()); + CmtData->Alloc(wcslen(CmtData->Addr(0))); + } + } + else + { + if (CmtLength==0) + return false; + Array CmtRaw(CmtLength); + int ReadSize=Read(&CmtRaw[0],CmtLength); + if (ReadSize>=0 && (uint)ReadSizeAlloc(CmtLength+1); + CmtRaw.Push(0); +#ifdef _WIN_ALL + // If we ever decide to extend it to Android, we'll need to alloc + // 4x memory for OEM to UTF-8 output here. + OemToCharA((char *)&CmtRaw[0],(char *)&CmtRaw[0]); +#endif + CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size()); + CmtData->Alloc(wcslen(CmtData->Addr(0))); + } +#endif + return CmtData->Size() > 0; +} + + +bool Archive::ReadCommentData(Array *CmtData) +{ + Array CmtRaw; + if (!ReadSubData(&CmtRaw,NULL)) + return false; + size_t CmtSize=CmtRaw.Size(); + CmtRaw.Push(0); + CmtData->Alloc(CmtSize+1); + if (Format==RARFMT50) + UtfToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size()); + else + if ((SubHead.SubFlags & SUBHEAD_FLAGS_CMT_UNICODE)!=0) + { + RawToWide(&CmtRaw[0],CmtData->Addr(0),CmtSize/2); + (*CmtData)[CmtSize/2]=0; + + } + else + { + CharToWide((char *)&CmtRaw[0],CmtData->Addr(0),CmtData->Size()); + } + CmtData->Alloc(wcslen(CmtData->Addr(0))); // Set buffer size to actual comment length. + return true; +} + + +void Archive::ViewComment() +{ + if (Cmd->DisableComment) + return; + Array CmtBuf; + if (GetComment(&CmtBuf)) // In GUI too, so "Test" command detects broken comments. + { + size_t CmtSize=CmtBuf.Size(); + wchar *ChPtr=wcschr(&CmtBuf[0],0x1A); + if (ChPtr!=NULL) + CmtSize=ChPtr-&CmtBuf[0]; + mprintf(L"\n"); + OutComment(&CmtBuf[0],CmtSize); + } +} + + diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/archive.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/archive.cpp new file mode 100644 index 0000000..6532869 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/archive.cpp @@ -0,0 +1,336 @@ +#include "rar.hpp" + +#include "arccmt.cpp" + + +Archive::Archive(RAROptions *InitCmd) +{ + Cmd=NULL; // Just in case we'll have an exception in 'new' below. + + DummyCmd=(InitCmd==NULL); + Cmd=DummyCmd ? (new RAROptions):InitCmd; + + OpenShared=Cmd->OpenShared; + Format=RARFMT15; + Solid=false; + Volume=false; + MainComment=false; + Locked=false; + Signed=false; + FirstVolume=false; + NewNumbering=false; + SFXSize=0; + LatestTime.Reset(); + Protected=false; + Encrypted=false; + FailedHeaderDecryption=false; + BrokenHeader=false; + LastReadBlock=0; + + CurBlockPos=0; + NextBlockPos=0; + + + memset(&MainHead,0,sizeof(MainHead)); + memset(&CryptHead,0,sizeof(CryptHead)); + memset(&EndArcHead,0,sizeof(EndArcHead)); + + VolNumber=0; + VolWrite=0; + AddingFilesSize=0; + AddingHeadersSize=0; + *FirstVolumeName=0; + + Splitting=false; + NewArchive=false; + + SilentOpen=false; + +#ifdef USE_QOPEN + ProhibitQOpen=false; +#endif + +} + + +Archive::~Archive() +{ + if (DummyCmd) + delete Cmd; +} + + +void Archive::CheckArc(bool EnableBroken) +{ + if (!IsArchive(EnableBroken)) + { + // If FailedHeaderDecryption is set, we already reported that archive + // password is incorrect. + if (!FailedHeaderDecryption) + uiMsg(UIERROR_BADARCHIVE,FileName); + ErrHandler.Exit(RARX_FATAL); + } +} + + +#if !defined(SFX_MODULE) +void Archive::CheckOpen(const wchar *Name) +{ + TOpen(Name); + CheckArc(false); +} +#endif + + +bool Archive::WCheckOpen(const wchar *Name) +{ + if (!WOpen(Name)) + return false; + if (!IsArchive(false)) + { + uiMsg(UIERROR_BADARCHIVE,FileName); + Close(); + return false; + } + return true; +} + + +RARFORMAT Archive::IsSignature(const byte *D,size_t Size) +{ + RARFORMAT Type=RARFMT_NONE; + if (Size>=1 && D[0]==0x52) +#ifndef SFX_MODULE + if (Size>=4 && D[1]==0x45 && D[2]==0x7e && D[3]==0x5e) + Type=RARFMT14; + else +#endif + if (Size>=7 && D[1]==0x61 && D[2]==0x72 && D[3]==0x21 && D[4]==0x1a && D[5]==0x07) + { + // We check the last signature byte, so we can return a sensible + // warning in case we'll want to change the archive format + // sometimes in the future. + if (D[6]==0) + Type=RARFMT15; + else + if (D[6]==1) + Type=RARFMT50; + else + if (D[6]>1 && D[6]<5) + Type=RARFMT_FUTURE; + } + return Type; +} + + +bool Archive::IsArchive(bool EnableBroken) +{ + Encrypted=false; + BrokenHeader=false; // Might be left from previous volume. + +#ifndef SFX_MODULE + if (IsDevice()) + { + uiMsg(UIERROR_INVALIDNAME,FileName,FileName); + return false; + } +#endif + if (Read(MarkHead.Mark,SIZEOF_MARKHEAD3)!=SIZEOF_MARKHEAD3) + return false; + SFXSize=0; + + RARFORMAT Type; + if ((Type=IsSignature(MarkHead.Mark,SIZEOF_MARKHEAD3))!=RARFMT_NONE) + { + Format=Type; + if (Format==RARFMT14) + Seek(Tell()-SIZEOF_MARKHEAD3,SEEK_SET); + } + else + { + Array Buffer(MAXSFXSIZE); + long CurPos=(long)Tell(); + int ReadSize=Read(&Buffer[0],Buffer.Size()-16); + for (int I=0;I0 && CurPos<28 && ReadSize>31) + { + char *D=&Buffer[28-CurPos]; + if (D[0]!=0x52 || D[1]!=0x53 || D[2]!=0x46 || D[3]!=0x58) + continue; + } + SFXSize=CurPos+I; + Seek(SFXSize,SEEK_SET); + if (Format==RARFMT15 || Format==RARFMT50) + Read(MarkHead.Mark,SIZEOF_MARKHEAD3); + break; + } + if (SFXSize==0) + return false; + } + if (Format==RARFMT_FUTURE) + { + uiMsg(UIERROR_NEWRARFORMAT,FileName); + return false; + } + if (Format==RARFMT50) // RAR 5.0 signature is by one byte longer. + { + if (Read(MarkHead.Mark+SIZEOF_MARKHEAD3,1)!=1 || MarkHead.Mark[SIZEOF_MARKHEAD3]!=0) + return false; + MarkHead.HeadSize=SIZEOF_MARKHEAD5; + } + else + MarkHead.HeadSize=SIZEOF_MARKHEAD3; + +#ifdef RARDLL + // If callback function is not set, we cannot get the password, + // so we skip the initial header processing for encrypted header archive. + // It leads to skipped archive comment, but the rest of archive data + // is processed correctly. + if (Cmd->Callback==NULL) + SilentOpen=true; +#endif + + bool HeadersLeft; // Any headers left to read. + bool StartFound=false; // Main or encryption headers found. + // Skip the archive encryption header if any and read the main header. + while ((HeadersLeft=(ReadHeader()!=0))==true) // Additional parentheses to silence Clang. + { + SeekToNext(); + + HEADER_TYPE Type=GetHeaderType(); + // In RAR 5.0 we need to quit after reading HEAD_CRYPT if we wish to + // avoid the password prompt. + StartFound=Type==HEAD_MAIN || SilentOpen && Type==HEAD_CRYPT; + if (StartFound) + break; + } + + // This check allows to make RS based recovery even if password is incorrect. + // But we should not do it for EnableBroken or we'll get 'not RAR archive' + // messages when extracting encrypted archives with wrong password. + if (FailedHeaderDecryption && !EnableBroken) + return false; + + if (BrokenHeader || !StartFound) // Main archive header is corrupt or missing. + { + uiMsg(UIERROR_MHEADERBROKEN,FileName); + if (!EnableBroken) + return false; + } + + MainComment=MainHead.CommentInHeader; + + // If we process non-encrypted archive or can request a password, + // we set 'first volume' flag based on file attributes below. + // It is necessary for RAR 2.x archives, which did not have 'first volume' + // flag in main header. Also for all RAR formats we need to scan until + // first file header to set "comment" flag when reading service header. + // Unless we are in silent mode, we need to know about presence of comment + // immediately after IsArchive call. + if (HeadersLeft && (!SilentOpen || !Encrypted)) + { + SaveFilePos SavePos(*this); + int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos; + HEADER_TYPE SaveCurHeaderType=CurHeaderType; + + while (ReadHeader()!=0) + { + HEADER_TYPE HeaderType=GetHeaderType(); + if (HeaderType==HEAD_SERVICE) + { + // If we have a split service headers, it surely indicates non-first + // volume. But not split service header does not guarantee the first + // volume, because we can have split file after non-split archive + // comment. So we do not quit from loop here. + FirstVolume=Volume && !SubHead.SplitBefore; + } + else + if (HeaderType==HEAD_FILE) + { + FirstVolume=Volume && !FileHead.SplitBefore; + break; + } + else + if (HeaderType==HEAD_ENDARC) // Might happen if archive contains only a split service header. + break; + SeekToNext(); + } + CurBlockPos=SaveCurBlockPos; + NextBlockPos=SaveNextBlockPos; + CurHeaderType=SaveCurHeaderType; + } + if (!Volume || FirstVolume) + wcsncpyz(FirstVolumeName,FileName,ASIZE(FirstVolumeName)); + + return true; +} + + + + +void Archive::SeekToNext() +{ + Seek(NextBlockPos,SEEK_SET); +} + + + + + + +// Calculate the block size including encryption fields and padding if any. +uint Archive::FullHeaderSize(size_t Size) +{ + if (Encrypted) + { + Size = ALIGN_VALUE(Size, CRYPT_BLOCK_SIZE); // Align to encryption block size. + if (Format == RARFMT50) + Size += SIZE_INITV; + else + Size += SIZE_SALT30; + } + return uint(Size); +} + + + + +#ifdef USE_QOPEN +bool Archive::Open(const wchar *Name,uint Mode) +{ + // Important if we reuse Archive object and it has virtual QOpen + // file position not matching real. For example, for 'l -v volname'. + QOpen.Unload(); + + return File::Open(Name,Mode); +} + + +int Archive::Read(void *Data,size_t Size) +{ + size_t Result; + if (QOpen.Read(Data,Size,Result)) + return (int)Result; + return File::Read(Data,Size); +} + + +void Archive::Seek(int64 Offset,int Method) +{ + if (!QOpen.Seek(Offset,Method)) + File::Seek(Offset,Method); +} + + +int64 Archive::Tell() +{ + int64 QPos; + if (QOpen.Tell(&QPos)) + return QPos; + return File::Tell(); +} +#endif + diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/archive.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/archive.hpp new file mode 100644 index 0000000..da59973 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/archive.hpp @@ -0,0 +1,148 @@ +#ifndef _RAR_ARCHIVE_ +#define _RAR_ARCHIVE_ + +class PPack; +class RawRead; +class RawWrite; + +enum NOMODIFY_FLAGS +{ + NMDF_ALLOWLOCK=1,NMDF_ALLOWANYVOLUME=2,NMDF_ALLOWFIRSTVOLUME=4 +}; + +enum RARFORMAT {RARFMT_NONE,RARFMT14,RARFMT15,RARFMT50,RARFMT_FUTURE}; + +enum ADDSUBDATA_FLAGS +{ + ASDF_SPLIT = 1, // Allow to split archive just before header if necessary. + ASDF_COMPRESS = 2, // Allow to compress data following subheader. + ASDF_CRYPT = 4, // Encrypt data after subheader if password is set. + ASDF_CRYPTIFHEADERS = 8 // Encrypt data after subheader only in -hp mode. +}; + +class Archive:public File +{ + private: + void UpdateLatestTime(FileHeader *CurBlock); + void ConvertNameCase(wchar *Name); + void ConvertFileHeader(FileHeader *hd); + void WriteBlock50(HEADER_TYPE HeaderType,BaseBlock *wb,bool OnlySetSize,bool NonFinalWrite); + size_t ReadHeader14(); + size_t ReadHeader15(); + size_t ReadHeader50(); + void ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb); + void RequestArcPassword(); + void UnexpEndArcMsg(); + void BrokenHeaderMsg(); + void UnkEncVerMsg(const wchar *Name); + void UnkEncVerMsg(); + bool ReadCommentData(Array *CmtData); + +#if !defined(RAR_NOCRYPT) + CryptData HeadersCrypt; +#endif + ComprDataIO SubDataIO; + bool DummyCmd; + RAROptions *Cmd; + + + RarTime LatestTime; + int LastReadBlock; + HEADER_TYPE CurHeaderType; + + bool SilentOpen; +#ifdef USE_QOPEN + QuickOpen QOpen; + bool ProhibitQOpen; +#endif + public: + Archive(RAROptions *InitCmd=NULL); + ~Archive(); + static RARFORMAT IsSignature(const byte *D,size_t Size); + bool IsArchive(bool EnableBroken); + size_t SearchBlock(HEADER_TYPE HeaderType); + size_t SearchSubBlock(const wchar *Type); + size_t SearchRR(); + void WriteBlock(HEADER_TYPE HeaderType,BaseBlock *wb=NULL,bool OnlySetSize=false,bool NonFinalWrite=false); + void SetBlockSize(HEADER_TYPE HeaderType,BaseBlock *wb=NULL) {WriteBlock(HeaderType,wb,true);} + size_t ReadHeader(); + void CheckArc(bool EnableBroken); + void CheckOpen(const wchar *Name); + bool WCheckOpen(const wchar *Name); + bool GetComment(Array *CmtData); + void ViewComment(); + void SetLatestTime(RarTime *NewTime); + void SeekToNext(); + bool CheckAccess(); + bool IsArcDir(); + void ConvertAttributes(); + void VolSubtractHeaderSize(size_t SubSize); + uint FullHeaderSize(size_t Size); + int64 GetStartPos(); + void AddSubData(byte *SrcData,uint64 DataSize,File *SrcFile, + const wchar *Name,uint Flags); + bool ReadSubData(Array *UnpData,File *DestFile); + HEADER_TYPE GetHeaderType() {return CurHeaderType;}; + RAROptions* GetRAROptions() {return Cmd;} + void SetSilentOpen(bool Mode) {SilentOpen=Mode;} +#if 0 + void GetRecoveryInfo(bool Required,int64 *Size,int *Percent); +#endif +#ifdef USE_QOPEN + bool Open(const wchar *Name,uint Mode=FMF_READ); + int Read(void *Data,size_t Size); + void Seek(int64 Offset,int Method); + int64 Tell(); + void QOpenUnload() {QOpen.Unload();} + void SetProhibitQOpen(bool Mode) {ProhibitQOpen=Mode;} +#endif + + BaseBlock ShortBlock; + MarkHeader MarkHead; + MainHeader MainHead; + CryptHeader CryptHead; + FileHeader FileHead; + EndArcHeader EndArcHead; + SubBlockHeader SubBlockHead; + FileHeader SubHead; + CommentHeader CommHead; + ProtectHeader ProtectHead; + UnixOwnersHeader UOHead; + EAHeader EAHead; + StreamHeader StreamHead; + + int64 CurBlockPos; + int64 NextBlockPos; + + RARFORMAT Format; + bool Solid; + bool Volume; + bool MainComment; + bool Locked; + bool Signed; + bool FirstVolume; + bool NewNumbering; + bool Protected; + bool Encrypted; + size_t SFXSize; + bool BrokenHeader; + bool FailedHeaderDecryption; + +#if !defined(RAR_NOCRYPT) + byte ArcSalt[SIZE_SALT50]; +#endif + + bool Splitting; + + uint VolNumber; + int64 VolWrite; + uint64 AddingFilesSize; + uint64 AddingHeadersSize; + + bool NewArchive; + + wchar FirstVolumeName[NM]; +}; + + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/arcmem.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/arcmem.cpp new file mode 100644 index 0000000..e916ec3 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/arcmem.cpp @@ -0,0 +1,67 @@ +ArcMemory::ArcMemory() +{ + Loaded=false; + SeekPos=0; +} + + +void ArcMemory::Load(const byte *Data,size_t Size) +{ + ArcData.Alloc(Size); + memcpy(&ArcData[0],Data,Size); + Loaded=true; + SeekPos=0; +} + + +bool ArcMemory::Unload() +{ + if (!Loaded) + return false; + Loaded=false; + return true; +} + + +bool ArcMemory::Read(void *Data,size_t Size,size_t &Result) +{ + if (!Loaded) + return false; + Result=(size_t)Min(Size,ArcData.Size()-SeekPos); + memcpy(Data,&ArcData[(size_t)SeekPos],Result); + SeekPos+=Result; + return true; +} + + +bool ArcMemory::Seek(int64 Offset,int Method) +{ + if (!Loaded) + return false; + if (Method==SEEK_SET) + { + if (Offset<0) + SeekPos=0; + else + SeekPos=Min((uint64)Offset,ArcData.Size()); + } + else + if (Method==SEEK_CUR || Method==SEEK_END) + { + if (Method==SEEK_END) + SeekPos=ArcData.Size(); + SeekPos+=(uint64)Offset; + if (SeekPos>ArcData.Size()) + SeekPos=Offset<0 ? 0 : ArcData.Size(); + } + return true; +} + + +bool ArcMemory::Tell(int64 *Pos) +{ + if (!Loaded) + return false; + *Pos=SeekPos; + return true; +} diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/arcmem.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/arcmem.hpp new file mode 100644 index 0000000..6fbe7c3 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/arcmem.hpp @@ -0,0 +1,22 @@ +#ifndef _RAR_ARCMEM_ +#define _RAR_ARCMEM_ + +// Memory interface for software fuzzers. + +class ArcMemory +{ + private: + bool Loaded; + Array ArcData; + uint64 SeekPos; + public: + ArcMemory(); + void Load(const byte *Data,size_t Size); + bool Unload(); + bool IsLoaded() {return Loaded;} + bool Read(void *Data,size_t Size,size_t &Result); + bool Seek(int64 Offset,int Method); + bool Tell(int64 *Pos); +}; + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/arcread.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/arcread.cpp new file mode 100644 index 0000000..4045b5e --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/arcread.cpp @@ -0,0 +1,1448 @@ +#include "rar.hpp" + +size_t Archive::ReadHeader() +{ + // Once we failed to decrypt an encrypted block, there is no reason to + // attempt to do it further. We'll never be successful and only generate + // endless errors. + if (FailedHeaderDecryption) + return 0; + + CurBlockPos=Tell(); + + size_t ReadSize; + switch(Format) + { +#ifndef SFX_MODULE + case RARFMT14: + ReadSize=ReadHeader14(); + break; +#endif + case RARFMT15: + ReadSize=ReadHeader15(); + break; + case RARFMT50: + ReadSize=ReadHeader50(); + break; + } + + // It is important to check ReadSize>0 here, because it is normal + // for RAR2 and RAR3 archives without end of archive block to have + // NextBlockPos==CurBlockPos after the end of archive has reached. + if (ReadSize>0 && NextBlockPos<=CurBlockPos) + { + BrokenHeaderMsg(); + ReadSize=0; + } + + if (ReadSize==0) + CurHeaderType=HEAD_UNKNOWN; + + return ReadSize; +} + + +size_t Archive::SearchBlock(HEADER_TYPE HeaderType) +{ + size_t Size,Count=0; + while ((Size=ReadHeader())!=0 && + (HeaderType==HEAD_ENDARC || GetHeaderType()!=HEAD_ENDARC)) + { + if ((++Count & 127)==0) + Wait(); + if (GetHeaderType()==HeaderType) + return Size; + SeekToNext(); + } + return 0; +} + + +size_t Archive::SearchSubBlock(const wchar *Type) +{ + size_t Size,Count=0; + while ((Size=ReadHeader())!=0 && GetHeaderType()!=HEAD_ENDARC) + { + if ((++Count & 127)==0) + Wait(); + if (GetHeaderType()==HEAD_SERVICE && SubHead.CmpName(Type)) + return Size; + SeekToNext(); + } + return 0; +} + + +size_t Archive::SearchRR() +{ + // If locator extra field is available for recovery record, let's utilize it. + if (MainHead.Locator && MainHead.RROffset!=0) + { + uint64 CurPos=Tell(); + Seek(MainHead.RROffset,SEEK_SET); + size_t Size=ReadHeader(); + if (Size!=0 && !BrokenHeader && GetHeaderType()==HEAD_SERVICE && SubHead.CmpName(SUBHEAD_TYPE_RR)) + return Size; + Seek(CurPos,SEEK_SET); + } + // Otherwise scan the entire archive to find the recovery record. + return SearchSubBlock(SUBHEAD_TYPE_RR); +} + + +void Archive::UnexpEndArcMsg() +{ + int64 ArcSize=FileLength(); + + // If block positions are equal to file size, this is not an error. + // It can happen when we reached the end of older RAR 1.5 archive, + // which did not have the end of archive block. + if (CurBlockPos!=ArcSize || NextBlockPos!=ArcSize) + { + uiMsg(UIERROR_UNEXPEOF,FileName); + ErrHandler.SetErrorCode(RARX_WARNING); + } +} + + +void Archive::BrokenHeaderMsg() +{ + uiMsg(UIERROR_HEADERBROKEN,FileName); + BrokenHeader=true; + ErrHandler.SetErrorCode(RARX_CRC); +} + + +void Archive::UnkEncVerMsg(const wchar *Name) +{ + uiMsg(UIERROR_UNKNOWNENCMETHOD,FileName,Name); + ErrHandler.SetErrorCode(RARX_WARNING); +} + + +// Return f in case of signed integer overflow or negative parameters +// or v1+v2 otherwise. We use it for file offsets, which are signed +// for compatibility with off_t in POSIX file functions and third party code. +// Signed integer overflow is the undefined behavior according to +// C++ standard and it causes fuzzers to complain. +inline int64 SafeAdd(int64 v1,int64 v2,int64 f) +{ + return v1>=0 && v2>=0 && v1<=MAX_INT64-v2 ? v1+v2 : f; +} + + +size_t Archive::ReadHeader15() +{ + RawRead Raw(this); + + bool Decrypt=Encrypted && CurBlockPos>(int64)SFXSize+SIZEOF_MARKHEAD3; + + if (Decrypt) + { +#ifdef RAR_NOCRYPT // For rarext.dll and unrar_nocrypt.dll. + return 0; +#else + RequestArcPassword(); + + byte Salt[SIZE_SALT30]; + if (Read(Salt,SIZE_SALT30)!=SIZE_SALT30) + { + UnexpEndArcMsg(); + return 0; + } + HeadersCrypt.SetCryptKeys(false,CRYPT_RAR30,&Cmd->Password,Salt,NULL,0,NULL,NULL); + Raw.SetCrypt(&HeadersCrypt); +#endif + } + + Raw.Read(SIZEOF_SHORTBLOCKHEAD); + if (Raw.Size()==0) + { + UnexpEndArcMsg(); + return 0; + } + + ShortBlock.HeadCRC=Raw.Get2(); + + ShortBlock.Reset(); + + uint HeaderType=Raw.Get1(); + ShortBlock.Flags=Raw.Get2(); + ShortBlock.SkipIfUnknown=(ShortBlock.Flags & SKIP_IF_UNKNOWN)!=0; + ShortBlock.HeadSize=Raw.Get2(); + + ShortBlock.HeaderType=(HEADER_TYPE)HeaderType; + if (ShortBlock.HeadSizeReset(); + + *(BaseBlock *)hd=ShortBlock; + + hd->SplitBefore=(hd->Flags & LHD_SPLIT_BEFORE)!=0; + hd->SplitAfter=(hd->Flags & LHD_SPLIT_AFTER)!=0; + hd->Encrypted=(hd->Flags & LHD_PASSWORD)!=0; + hd->SaltSet=(hd->Flags & LHD_SALT)!=0; + hd->Solid=FileBlock && (hd->Flags & LHD_SOLID)!=0; + hd->SubBlock=!FileBlock && (hd->Flags & LHD_SOLID)!=0; + hd->Dir=(hd->Flags & LHD_WINDOWMASK)==LHD_DIRECTORY; + hd->WinSize=hd->Dir ? 0:0x10000<<((hd->Flags & LHD_WINDOWMASK)>>5); + hd->CommentInHeader=(hd->Flags & LHD_COMMENT)!=0; + hd->Version=(hd->Flags & LHD_VERSION)!=0; + + hd->DataSize=Raw.Get4(); + uint LowUnpSize=Raw.Get4(); + hd->HostOS=Raw.Get1(); + + hd->FileHash.Type=HASH_CRC32; + hd->FileHash.CRC32=Raw.Get4(); + + uint FileTime=Raw.Get4(); + hd->UnpVer=Raw.Get1(); + + // RAR15 did not use the special dictionary size to mark dirs. + if (hd->UnpVer<20 && (hd->FileAttr & 0x10)!=0) + hd->Dir=true; + + hd->Method=Raw.Get1()-0x30; + size_t NameSize=Raw.Get2(); + hd->FileAttr=Raw.Get4(); + + hd->CryptMethod=CRYPT_NONE; + if (hd->Encrypted) + switch(hd->UnpVer) + { + case 13: hd->CryptMethod=CRYPT_RAR13; break; + case 15: hd->CryptMethod=CRYPT_RAR15; break; + case 20: + case 26: hd->CryptMethod=CRYPT_RAR20; break; + default: hd->CryptMethod=CRYPT_RAR30; break; + } + + hd->HSType=HSYS_UNKNOWN; + if (hd->HostOS==HOST_UNIX || hd->HostOS==HOST_BEOS) + hd->HSType=HSYS_UNIX; + else + if (hd->HostOSHSType=HSYS_WINDOWS; + + hd->RedirType=FSREDIR_NONE; + + // RAR 4.x Unix symlink. + if (hd->HostOS==HOST_UNIX && (hd->FileAttr & 0xF000)==0xA000) + { + hd->RedirType=FSREDIR_UNIXSYMLINK; + *hd->RedirName=0; + } + + hd->Inherited=!FileBlock && (hd->SubFlags & SUBHEAD_FLAGS_INHERITED)!=0; + + hd->LargeFile=(hd->Flags & LHD_LARGE)!=0; + + uint HighPackSize,HighUnpSize; + if (hd->LargeFile) + { + HighPackSize=Raw.Get4(); + HighUnpSize=Raw.Get4(); + hd->UnknownUnpSize=(LowUnpSize==0xffffffff && HighUnpSize==0xffffffff); + } + else + { + HighPackSize=HighUnpSize=0; + // UnpSize equal to 0xffffffff without LHD_LARGE flag indicates + // that we do not know the unpacked file size and must unpack it + // until we find the end of file marker in compressed data. + hd->UnknownUnpSize=(LowUnpSize==0xffffffff); + } + hd->PackSize=INT32TO64(HighPackSize,hd->DataSize); + hd->UnpSize=INT32TO64(HighUnpSize,LowUnpSize); + if (hd->UnknownUnpSize) + hd->UnpSize=INT64NDF; + + char FileName[NM*4]; + size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1); + Raw.GetB((byte *)FileName,ReadNameSize); + FileName[ReadNameSize]=0; + + if (FileBlock) + { + *hd->FileName=0; + if ((hd->Flags & LHD_UNICODE)!=0) + { + EncodeFileName NameCoder; + size_t Length=strlen(FileName); + Length++; + if (ReadNameSize>Length) + NameCoder.Decode(FileName,ReadNameSize,(byte *)FileName+Length, + ReadNameSize-Length,hd->FileName, + ASIZE(hd->FileName)); + } + + if (*hd->FileName==0) + ArcCharToWide(FileName,hd->FileName,ASIZE(hd->FileName),ACTW_OEM); + +#ifndef SFX_MODULE + ConvertNameCase(hd->FileName); +#endif + ConvertFileHeader(hd); + } + else + { + CharToWide(FileName,hd->FileName,ASIZE(hd->FileName)); + + // Calculate the size of optional data. + int DataSize=int(hd->HeadSize-NameSize-SIZEOF_FILEHEAD3); + if ((hd->Flags & LHD_SALT)!=0) + DataSize-=SIZE_SALT30; + + if (DataSize>0) + { + // Here we read optional additional fields for subheaders. + // They are stored after the file name and before salt. + hd->SubData.Alloc(DataSize); + Raw.GetB(&hd->SubData[0],DataSize); + + } + + if (hd->CmpName(SUBHEAD_TYPE_CMT)) + MainComment=true; + } + if ((hd->Flags & LHD_SALT)!=0) + Raw.GetB(hd->Salt,SIZE_SALT30); + hd->mtime.SetDos(FileTime); + if ((hd->Flags & LHD_EXTTIME)!=0) + { + ushort Flags=Raw.Get2(); + RarTime *tbl[4]; + tbl[0]=&FileHead.mtime; + tbl[1]=&FileHead.ctime; + tbl[2]=&FileHead.atime; + tbl[3]=NULL; // Archive time is not used now. + for (int I=0;I<4;I++) + { + RarTime *CurTime=tbl[I]; + uint rmode=Flags>>(3-I)*4; + if ((rmode & 8)==0 || CurTime==NULL) + continue; + if (I!=0) + { + uint DosTime=Raw.Get4(); + CurTime->SetDos(DosTime); + } + RarLocalTime rlt; + CurTime->GetLocal(&rlt); + if (rmode & 4) + rlt.Second++; + rlt.Reminder=0; + int count=rmode&3; + for (int J=0;JSetLocal(&rlt); + } + } + // Set to 0 in case of overflow, so end of ReadHeader cares about it. + NextBlockPos=SafeAdd(NextBlockPos,hd->PackSize,0); + + bool CRCProcessedOnly=hd->CommentInHeader; + ushort HeaderCRC=Raw.GetCRC15(CRCProcessedOnly); + if (hd->HeadCRC!=HeaderCRC) + { + BrokenHeader=true; + ErrHandler.SetErrorCode(RARX_WARNING); + + // If we have a broken encrypted header, we do not need to display + // the error message here, because it will be displayed for such + // headers later in this function. Also such headers are unlikely + // to have anything sensible in file name field, so it is useless + // to display the file name. + if (!Decrypt) + uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName); + } + } + break; + case HEAD_ENDARC: + *(BaseBlock *)&EndArcHead=ShortBlock; + EndArcHead.NextVolume=(EndArcHead.Flags & EARC_NEXT_VOLUME)!=0; + EndArcHead.DataCRC=(EndArcHead.Flags & EARC_DATACRC)!=0; + EndArcHead.RevSpace=(EndArcHead.Flags & EARC_REVSPACE)!=0; + EndArcHead.StoreVolNumber=(EndArcHead.Flags & EARC_VOLNUMBER)!=0; + if (EndArcHead.DataCRC) + EndArcHead.ArcDataCRC=Raw.Get4(); + if (EndArcHead.StoreVolNumber) + VolNumber=EndArcHead.VolNumber=Raw.Get2(); + break; +#ifndef SFX_MODULE + case HEAD3_CMT: + *(BaseBlock *)&CommHead=ShortBlock; + CommHead.UnpSize=Raw.Get2(); + CommHead.UnpVer=Raw.Get1(); + CommHead.Method=Raw.Get1(); + CommHead.CommCRC=Raw.Get2(); + break; + case HEAD3_PROTECT: + *(BaseBlock *)&ProtectHead=ShortBlock; + ProtectHead.DataSize=Raw.Get4(); + ProtectHead.Version=Raw.Get1(); + ProtectHead.RecSectors=Raw.Get2(); + ProtectHead.TotalBlocks=Raw.Get4(); + Raw.GetB(ProtectHead.Mark,8); + NextBlockPos+=ProtectHead.DataSize; + break; + case HEAD3_OLDSERVICE: // RAR 2.9 and earlier. + *(BaseBlock *)&SubBlockHead=ShortBlock; + SubBlockHead.DataSize=Raw.Get4(); + NextBlockPos+=SubBlockHead.DataSize; + SubBlockHead.SubType=Raw.Get2(); + SubBlockHead.Level=Raw.Get1(); + switch(SubBlockHead.SubType) + { + case UO_HEAD: + *(SubBlockHeader *)&UOHead=SubBlockHead; + UOHead.OwnerNameSize=Raw.Get2(); + UOHead.GroupNameSize=Raw.Get2(); + if (UOHead.OwnerNameSize>=ASIZE(UOHead.OwnerName)) + UOHead.OwnerNameSize=ASIZE(UOHead.OwnerName)-1; + if (UOHead.GroupNameSize>=ASIZE(UOHead.GroupName)) + UOHead.GroupNameSize=ASIZE(UOHead.GroupName)-1; + Raw.GetB(UOHead.OwnerName,UOHead.OwnerNameSize); + Raw.GetB(UOHead.GroupName,UOHead.GroupNameSize); + UOHead.OwnerName[UOHead.OwnerNameSize]=0; + UOHead.GroupName[UOHead.GroupNameSize]=0; + break; + case NTACL_HEAD: + *(SubBlockHeader *)&EAHead=SubBlockHead; + EAHead.UnpSize=Raw.Get4(); + EAHead.UnpVer=Raw.Get1(); + EAHead.Method=Raw.Get1(); + EAHead.EACRC=Raw.Get4(); + break; + case STREAM_HEAD: + *(SubBlockHeader *)&StreamHead=SubBlockHead; + StreamHead.UnpSize=Raw.Get4(); + StreamHead.UnpVer=Raw.Get1(); + StreamHead.Method=Raw.Get1(); + StreamHead.StreamCRC=Raw.Get4(); + StreamHead.StreamNameSize=Raw.Get2(); + if (StreamHead.StreamNameSize>=ASIZE(StreamHead.StreamName)) + StreamHead.StreamNameSize=ASIZE(StreamHead.StreamName)-1; + Raw.GetB(StreamHead.StreamName,StreamHead.StreamNameSize); + StreamHead.StreamName[StreamHead.StreamNameSize]=0; + break; + } + break; +#endif + default: + if (ShortBlock.Flags & LONG_BLOCK) + NextBlockPos+=Raw.Get4(); + break; + } + + ushort HeaderCRC=Raw.GetCRC15(false); + + // Old AV header does not have header CRC properly set. + if (ShortBlock.HeadCRC!=HeaderCRC && ShortBlock.HeaderType!=HEAD3_SIGN && + ShortBlock.HeaderType!=HEAD3_AV) + { + bool Recovered=false; + if (ShortBlock.HeaderType==HEAD_ENDARC && EndArcHead.RevSpace) + { + // Last 7 bytes of recovered volume can contain zeroes, because + // REV files store its own information (volume number, etc.) here. + SaveFilePos SavePos(*this); + int64 Length=Tell(); + Seek(Length-7,SEEK_SET); + Recovered=true; + for (int J=0;J<7;J++) + if (GetByte()!=0) + Recovered=false; + } + if (!Recovered) + { + BrokenHeader=true; + ErrHandler.SetErrorCode(RARX_CRC); + + if (Decrypt) + { + uiMsg(UIERROR_CHECKSUMENC,FileName,FileName); + FailedHeaderDecryption=true; + return 0; + } + } + } + + return Raw.Size(); +} + + +size_t Archive::ReadHeader50() +{ + RawRead Raw(this); + + bool Decrypt=Encrypted && CurBlockPos>(int64)SFXSize+SIZEOF_MARKHEAD5; + + if (Decrypt) + { +#if defined(RAR_NOCRYPT) + return 0; +#else + + byte HeadersInitV[SIZE_INITV]; + if (Read(HeadersInitV,SIZE_INITV)!=SIZE_INITV) + { + UnexpEndArcMsg(); + return 0; + } + + while (true) // Repeat the password prompt for wrong passwords. + { + RequestArcPassword(); + + byte PswCheck[SIZE_PSWCHECK]; + HeadersCrypt.SetCryptKeys(false,CRYPT_RAR50,&Cmd->Password,CryptHead.Salt,HeadersInitV,CryptHead.Lg2Count,NULL,PswCheck); + // Verify password validity. + if (CryptHead.UsePswCheck && memcmp(PswCheck,CryptHead.PswCheck,SIZE_PSWCHECK)!=0) + { + // This message is used by Android GUI and Windows GUI and SFX to + // reset cached passwords. Update appropriate code if changed. + uiMsg(UIWAIT_BADPSW,FileName); + + Cmd->Password.Clean(); +#ifdef RARDLL + // Avoid new requests for unrar.dll to prevent the infinite loop + // if app always returns the same password. + ErrHandler.SetErrorCode(RARX_BADPWD); + Cmd->DllError=ERAR_BAD_PASSWORD; + ErrHandler.Exit(RARX_BADPWD); +#else + continue; // Request a password again. +#endif + } + break; + } + + Raw.SetCrypt(&HeadersCrypt); +#endif + } + + // Header size must not occupy more than 3 variable length integer bytes + // resulting in 2 MB maximum header size, so here we read 4 byte CRC32 + // followed by 3 bytes or less of header size. + const size_t FirstReadSize=7; // Smallest possible block size. + if (Raw.Read(FirstReadSize)=ShortBlock.HeadSize) + { + BrokenHeaderMsg(); + return 0; + } + } + + uint64 DataSize=0; + if ((ShortBlock.Flags & HFL_DATA)!=0) + DataSize=Raw.GetV(); + + NextBlockPos=CurBlockPos+FullHeaderSize(ShortBlock.HeadSize); + // Set to 0 in case of overflow, so end of ReadHeader cares about it. + NextBlockPos=SafeAdd(NextBlockPos,DataSize,0); + + switch(ShortBlock.HeaderType) + { + case HEAD_CRYPT: + { + *(BaseBlock *)&CryptHead=ShortBlock; + uint CryptVersion=(uint)Raw.GetV(); + if (CryptVersion>CRYPT_VERSION) + { + UnkEncVerMsg(FileName); + return 0; + } + uint EncFlags=(uint)Raw.GetV(); + CryptHead.UsePswCheck=(EncFlags & CHFL_CRYPT_PSWCHECK)!=0; + CryptHead.Lg2Count=Raw.Get1(); + if (CryptHead.Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX) + { + UnkEncVerMsg(FileName); + return 0; + } + Raw.GetB(CryptHead.Salt,SIZE_SALT50); + if (CryptHead.UsePswCheck) + { + Raw.GetB(CryptHead.PswCheck,SIZE_PSWCHECK); + + byte csum[SIZE_PSWCHECK_CSUM]; + Raw.GetB(csum,SIZE_PSWCHECK_CSUM); + + sha256_context ctx; + sha256_init(&ctx); + sha256_process(&ctx, CryptHead.PswCheck, SIZE_PSWCHECK); + + byte Digest[SHA256_DIGEST_SIZE]; + sha256_done(&ctx, Digest); + + CryptHead.UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0; + } + Encrypted=true; + } + break; + case HEAD_MAIN: + { + MainHead.Reset(); + *(BaseBlock *)&MainHead=ShortBlock; + uint ArcFlags=(uint)Raw.GetV(); + + Volume=(ArcFlags & MHFL_VOLUME)!=0; + Solid=(ArcFlags & MHFL_SOLID)!=0; + Locked=(ArcFlags & MHFL_LOCK)!=0; + Protected=(ArcFlags & MHFL_PROTECT)!=0; + Signed=false; + NewNumbering=true; + + if ((ArcFlags & MHFL_VOLNUMBER)!=0) + VolNumber=(uint)Raw.GetV(); + else + VolNumber=0; + FirstVolume=Volume && VolNumber==0; + + if (ExtraSize!=0) + ProcessExtra50(&Raw,(size_t)ExtraSize,&MainHead); + +#ifdef USE_QOPEN + if (!ProhibitQOpen && MainHead.Locator && MainHead.QOpenOffset>0 && Cmd->QOpenMode!=QOPEN_NONE) + { + // We seek to QO block in the end of archive when processing + // QOpen.Load, so we need to preserve current block positions + // to not break normal archive processing by calling function. + int64 SaveCurBlockPos=CurBlockPos,SaveNextBlockPos=NextBlockPos; + HEADER_TYPE SaveCurHeaderType=CurHeaderType; + + QOpen.Init(this,false); + QOpen.Load(MainHead.QOpenOffset); + + CurBlockPos=SaveCurBlockPos; + NextBlockPos=SaveNextBlockPos; + CurHeaderType=SaveCurHeaderType; + } +#endif + } + break; + case HEAD_FILE: + case HEAD_SERVICE: + { + FileHeader *hd=ShortBlock.HeaderType==HEAD_FILE ? &FileHead:&SubHead; + hd->Reset(); + *(BaseBlock *)hd=ShortBlock; + + bool FileBlock=ShortBlock.HeaderType==HEAD_FILE; + + hd->LargeFile=true; + + hd->PackSize=DataSize; + hd->FileFlags=(uint)Raw.GetV(); + hd->UnpSize=Raw.GetV(); + + hd->UnknownUnpSize=(hd->FileFlags & FHFL_UNPUNKNOWN)!=0; + if (hd->UnknownUnpSize) + hd->UnpSize=INT64NDF; + + hd->MaxSize=Max(hd->PackSize,hd->UnpSize); + hd->FileAttr=(uint)Raw.GetV(); + if ((hd->FileFlags & FHFL_UTIME)!=0) + hd->mtime.SetUnix((time_t)Raw.Get4()); + + hd->FileHash.Type=HASH_NONE; + if ((hd->FileFlags & FHFL_CRC32)!=0) + { + hd->FileHash.Type=HASH_CRC32; + hd->FileHash.CRC32=Raw.Get4(); + } + + hd->RedirType=FSREDIR_NONE; + + uint CompInfo=(uint)Raw.GetV(); + hd->Method=(CompInfo>>7) & 7; + + // "+ 50" to not mix with old RAR format algorithms. For example, + // we may need to use the compression algorithm 15 in the future, + // but it was already used in RAR 1.5 and Unpack needs to distinguish + // them. + hd->UnpVer=(CompInfo & 0x3f) + 50; + + hd->HostOS=(byte)Raw.GetV(); + size_t NameSize=(size_t)Raw.GetV(); + hd->Inherited=(ShortBlock.Flags & HFL_INHERITED)!=0; + + hd->HSType=HSYS_UNKNOWN; + if (hd->HostOS==HOST5_UNIX) + hd->HSType=HSYS_UNIX; + else + if (hd->HostOS==HOST5_WINDOWS) + hd->HSType=HSYS_WINDOWS; + + hd->SplitBefore=(hd->Flags & HFL_SPLITBEFORE)!=0; + hd->SplitAfter=(hd->Flags & HFL_SPLITAFTER)!=0; + hd->SubBlock=(hd->Flags & HFL_CHILD)!=0; + hd->Solid=FileBlock && (CompInfo & FCI_SOLID)!=0; + hd->Dir=(hd->FileFlags & FHFL_DIRECTORY)!=0; + hd->WinSize=hd->Dir ? 0:size_t(0x20000)<<((CompInfo>>10)&0xf); + + hd->CryptMethod=hd->Encrypted ? CRYPT_RAR50:CRYPT_NONE; + + char FileName[NM*4]; + size_t ReadNameSize=Min(NameSize,ASIZE(FileName)-1); + Raw.GetB((byte *)FileName,ReadNameSize); + FileName[ReadNameSize]=0; + + UtfToWide(FileName,hd->FileName,ASIZE(hd->FileName)); + + // Should do it before converting names, because extra fields can + // affect name processing, like in case of NTFS streams. + if (ExtraSize!=0) + ProcessExtra50(&Raw,(size_t)ExtraSize,hd); + + if (FileBlock) + { +#ifndef SFX_MODULE + ConvertNameCase(hd->FileName); +#endif + ConvertFileHeader(hd); + } + + if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_CMT)) + MainComment=true; + +#if 0 + // For RAR5 format we read the user specified recovery percent here. + // It would be useful to do it for shell extension too, so we display + // the correct recovery record size in archive properties. But then + // we would need to include the entire recovery record processing + // code to shell extension, which is not done now. + if (!FileBlock && hd->CmpName(SUBHEAD_TYPE_RR) && hd->SubData.Size()>0) + { + RecoveryPercent=hd->SubData[0]; + RSBlockHeader Header; + GetRRInfo(this,&Header); + RecoverySize=Header.RecSectionSize*Header.RecCount; + } +#endif + + if (BadCRC) // Add the file name to broken header message displayed above. + uiMsg(UIERROR_FHEADERBROKEN,Archive::FileName,hd->FileName); + } + break; + case HEAD_ENDARC: + { + *(BaseBlock *)&EndArcHead=ShortBlock; + uint ArcFlags=(uint)Raw.GetV(); + EndArcHead.NextVolume=(ArcFlags & EHFL_NEXTVOLUME)!=0; + EndArcHead.StoreVolNumber=false; + EndArcHead.DataCRC=false; + EndArcHead.RevSpace=false; + } + break; + } + + return Raw.Size(); +} + + +#if !defined(RAR_NOCRYPT) +void Archive::RequestArcPassword() +{ + if (!Cmd->Password.IsSet()) + { +#ifdef RARDLL + if (Cmd->Callback!=NULL) + { + wchar PasswordW[MAXPASSWORD]; + *PasswordW=0; + if (Cmd->Callback(UCM_NEEDPASSWORDW,Cmd->UserData,(LPARAM)PasswordW,ASIZE(PasswordW))==-1) + *PasswordW=0; + if (*PasswordW==0) + { + char PasswordA[MAXPASSWORD]; + *PasswordA=0; + if (Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1) + *PasswordA=0; + GetWideName(PasswordA,NULL,PasswordW,ASIZE(PasswordW)); + cleandata(PasswordA,sizeof(PasswordA)); + } + Cmd->Password.Set(PasswordW); + cleandata(PasswordW,sizeof(PasswordW)); + } + if (!Cmd->Password.IsSet()) + { + Close(); + Cmd->DllError=ERAR_MISSING_PASSWORD; + ErrHandler.Exit(RARX_USERBREAK); + } +#else + if (!uiGetPassword(UIPASSWORD_ARCHIVE,FileName,&Cmd->Password)) + { + Close(); + uiMsg(UIERROR_INCERRCOUNT); // Prevent archive deleting if delete after extraction is on. + ErrHandler.Exit(RARX_USERBREAK); + } +#endif + Cmd->ManualPassword=true; + } +} +#endif + + +void Archive::ProcessExtra50(RawRead *Raw,size_t ExtraSize,BaseBlock *bb) +{ + // Read extra data from the end of block skipping any fields before it. + size_t ExtraStart=Raw->Size()-ExtraSize; + if (ExtraStartGetPos()) + return; + Raw->SetPos(ExtraStart); + while (Raw->DataLeft()>=2) + { + int64 FieldSize=Raw->GetV(); // Needs to be signed for check below and can be negative. + if (FieldSize<=0 || Raw->DataLeft()==0 || FieldSize>(int64)Raw->DataLeft()) + break; + size_t NextPos=size_t(Raw->GetPos()+FieldSize); + uint64 FieldType=Raw->GetV(); + + FieldSize=int64(NextPos-Raw->GetPos()); // Field size without size and type fields. + + if (FieldSize<0) // FieldType is longer than expected extra field size. + break; + + if (bb->HeaderType==HEAD_MAIN) + { + MainHeader *hd=(MainHeader *)bb; + if (FieldType==MHEXTRA_LOCATOR) + { + hd->Locator=true; + uint Flags=(uint)Raw->GetV(); + if ((Flags & MHEXTRA_LOCATOR_QLIST)!=0) + { + uint64 Offset=Raw->GetV(); + if (Offset!=0) // 0 means that reserved space was not enough to write the offset. + hd->QOpenOffset=Offset+CurBlockPos; + } + if ((Flags & MHEXTRA_LOCATOR_RR)!=0) + { + uint64 Offset=Raw->GetV(); + if (Offset!=0) // 0 means that reserved space was not enough to write the offset. + hd->RROffset=Offset+CurBlockPos; + } + } + } + + if (bb->HeaderType==HEAD_FILE || bb->HeaderType==HEAD_SERVICE) + { + FileHeader *hd=(FileHeader *)bb; + switch(FieldType) + { + case FHEXTRA_CRYPT: + { + FileHeader *hd=(FileHeader *)bb; + uint EncVersion=(uint)Raw->GetV(); + if (EncVersion > CRYPT_VERSION) + UnkEncVerMsg(hd->FileName); + else + { + uint Flags=(uint)Raw->GetV(); + hd->UsePswCheck=(Flags & FHEXTRA_CRYPT_PSWCHECK)!=0; + hd->UseHashKey=(Flags & FHEXTRA_CRYPT_HASHMAC)!=0; + hd->Lg2Count=Raw->Get1(); + if (hd->Lg2Count>CRYPT5_KDF_LG2_COUNT_MAX) + UnkEncVerMsg(hd->FileName); + Raw->GetB(hd->Salt,SIZE_SALT50); + Raw->GetB(hd->InitV,SIZE_INITV); + if (hd->UsePswCheck) + { + Raw->GetB(hd->PswCheck,SIZE_PSWCHECK); + + // It is important to know if password check data is valid. + // If it is damaged and header CRC32 fails to detect it, + // archiver would refuse to decompress a possibly valid file. + // Since we want to be sure distinguishing a wrong password + // or corrupt file data, we use 64-bit password check data + // and to control its validity we use 32 bits of password + // check data SHA-256 additionally to 32-bit header CRC32. + byte csum[SIZE_PSWCHECK_CSUM]; + Raw->GetB(csum,SIZE_PSWCHECK_CSUM); + + sha256_context ctx; + sha256_init(&ctx); + sha256_process(&ctx, hd->PswCheck, SIZE_PSWCHECK); + + byte Digest[SHA256_DIGEST_SIZE]; + sha256_done(&ctx, Digest); + + hd->UsePswCheck=memcmp(csum,Digest,SIZE_PSWCHECK_CSUM)==0; + + // RAR 5.21 and earlier set PswCheck field in service records to 0 + // even if UsePswCheck was present. + if (bb->HeaderType==HEAD_SERVICE && memcmp(hd->PswCheck,"\0\0\0\0\0\0\0\0",SIZE_PSWCHECK)==0) + hd->UsePswCheck=0; + } + hd->SaltSet=true; + hd->CryptMethod=CRYPT_RAR50; + hd->Encrypted=true; + } + } + break; + case FHEXTRA_HASH: + { + FileHeader *hd=(FileHeader *)bb; + uint Type=(uint)Raw->GetV(); + if (Type==FHEXTRA_HASH_BLAKE2) + { + hd->FileHash.Type=HASH_BLAKE2; + Raw->GetB(hd->FileHash.Digest,BLAKE2_DIGEST_SIZE); + } + } + break; + case FHEXTRA_HTIME: + if (FieldSize>=5) + { + byte Flags=(byte)Raw->GetV(); + bool UnixTime=(Flags & FHEXTRA_HTIME_UNIXTIME)!=0; + if ((Flags & FHEXTRA_HTIME_MTIME)!=0) + if (UnixTime) + hd->mtime.SetUnix(Raw->Get4()); + else + hd->mtime.SetWin(Raw->Get8()); + if ((Flags & FHEXTRA_HTIME_CTIME)!=0) + if (UnixTime) + hd->ctime.SetUnix(Raw->Get4()); + else + hd->ctime.SetWin(Raw->Get8()); + if ((Flags & FHEXTRA_HTIME_ATIME)!=0) + if (UnixTime) + hd->atime.SetUnix((time_t)Raw->Get4()); + else + hd->atime.SetWin(Raw->Get8()); + if (UnixTime && (Flags & FHEXTRA_HTIME_UNIX_NS)!=0) // Add nanoseconds. + { + uint ns; + if ((Flags & FHEXTRA_HTIME_MTIME)!=0 && (ns=(Raw->Get4() & 0x3fffffff))<1000000000) + hd->mtime.Adjust(ns); + if ((Flags & FHEXTRA_HTIME_CTIME)!=0 && (ns=(Raw->Get4() & 0x3fffffff))<1000000000) + hd->ctime.Adjust(ns); + if ((Flags & FHEXTRA_HTIME_ATIME)!=0 && (ns=(Raw->Get4() & 0x3fffffff))<1000000000) + hd->atime.Adjust(ns); + } + } + break; + case FHEXTRA_VERSION: + if (FieldSize>=1) + { + Raw->GetV(); // Skip flags field. + uint Version=(uint)Raw->GetV(); + if (Version!=0) + { + hd->Version=true; + + wchar VerText[20]; + swprintf(VerText,ASIZE(VerText),L";%u",Version); + wcsncatz(hd->FileName,VerText,ASIZE(hd->FileName)); + } + } + break; + case FHEXTRA_REDIR: + { + hd->RedirType=(FILE_SYSTEM_REDIRECT)Raw->GetV(); + uint Flags=(uint)Raw->GetV(); + hd->DirTarget=(Flags & FHEXTRA_REDIR_DIR)!=0; + size_t NameSize=(size_t)Raw->GetV(); + + char UtfName[NM*4]; + *UtfName=0; + if (NameSizeGetB(UtfName,NameSize); + UtfName[NameSize]=0; + } +#ifdef _WIN_ALL + UnixSlashToDos(UtfName,UtfName,ASIZE(UtfName)); +#endif + UtfToWide(UtfName,hd->RedirName,ASIZE(hd->RedirName)); + } + break; + case FHEXTRA_UOWNER: + { + uint Flags=(uint)Raw->GetV(); + hd->UnixOwnerNumeric=(Flags & FHEXTRA_UOWNER_NUMUID)!=0; + hd->UnixGroupNumeric=(Flags & FHEXTRA_UOWNER_NUMGID)!=0; + *hd->UnixOwnerName=*hd->UnixGroupName=0; + if ((Flags & FHEXTRA_UOWNER_UNAME)!=0) + { + size_t Length=(size_t)Raw->GetV(); + Length=Min(Length,ASIZE(hd->UnixOwnerName)-1); + Raw->GetB(hd->UnixOwnerName,Length); + hd->UnixOwnerName[Length]=0; + } + if ((Flags & FHEXTRA_UOWNER_GNAME)!=0) + { + size_t Length=(size_t)Raw->GetV(); + Length=Min(Length,ASIZE(hd->UnixGroupName)-1); + Raw->GetB(hd->UnixGroupName,Length); + hd->UnixGroupName[Length]=0; + } +#ifdef _UNIX + if (hd->UnixOwnerNumeric) + hd->UnixOwnerID=(uid_t)Raw->GetV(); + if (hd->UnixGroupNumeric) + hd->UnixGroupID=(gid_t)Raw->GetV(); +#else + // Need these fields in Windows too for 'list' command, + // but uid_t and gid_t are not defined. + if (hd->UnixOwnerNumeric) + hd->UnixOwnerID=(uint)Raw->GetV(); + if (hd->UnixGroupNumeric) + hd->UnixGroupID=(uint)Raw->GetV(); +#endif + hd->UnixOwnerSet=true; + } + break; + case FHEXTRA_SUBDATA: + { + // RAR 5.21 and earlier set FHEXTRA_SUBDATA size to 1 less than + // required. It did not hurt extraction, because UnRAR 5.21 + // and earlier ignored this field and set FieldSize as data left + // in entire extra area. But now we set the correct field size + // and set FieldSize based on the actual extra record size, + // so we need to adjust it for those older archives here. + // FHEXTRA_SUBDATA in those archives always belongs to HEAD_SERVICE + // and always is last in extra area. So since its size is by 1 + // less than needed, we always have 1 byte left in extra area, + // which fact we use here to detect such archives. + if (bb->HeaderType==HEAD_SERVICE && Raw->Size()-NextPos==1) + FieldSize++; + + // We cannot allocate too much memory here, because above + // we check FieldSize againt Raw size and we control that Raw size + // is sensible when reading headers. + hd->SubData.Alloc((size_t)FieldSize); + Raw->GetB(hd->SubData.Addr(0),(size_t)FieldSize); + } + break; + } + } + + Raw->SetPos(NextPos); + } +} + + +#ifndef SFX_MODULE +size_t Archive::ReadHeader14() +{ + RawRead Raw(this); + if (CurBlockPos<=(int64)SFXSize) + { + Raw.Read(SIZEOF_MAINHEAD14); + MainHead.Reset(); + byte Mark[4]; + Raw.GetB(Mark,4); + uint HeadSize=Raw.Get2(); + if (HeadSize<7) + return false; + byte Flags=Raw.Get1(); + NextBlockPos=CurBlockPos+HeadSize; + CurHeaderType=HEAD_MAIN; + + Volume=(Flags & MHD_VOLUME)!=0; + Solid=(Flags & MHD_SOLID)!=0; + Locked=(Flags & MHD_LOCK)!=0; + MainHead.CommentInHeader=(Flags & MHD_COMMENT)!=0; + MainHead.PackComment=(Flags & MHD_PACK_COMMENT)!=0; + } + else + { + Raw.Read(SIZEOF_FILEHEAD14); + FileHead.Reset(); + + FileHead.HeaderType=HEAD_FILE; + FileHead.DataSize=Raw.Get4(); + FileHead.UnpSize=Raw.Get4(); + FileHead.FileHash.Type=HASH_RAR14; + FileHead.FileHash.CRC32=Raw.Get2(); + FileHead.HeadSize=Raw.Get2(); + if (FileHead.HeadSize<21) + return false; + uint FileTime=Raw.Get4(); + FileHead.FileAttr=Raw.Get1(); + FileHead.Flags=Raw.Get1()|LONG_BLOCK; + FileHead.UnpVer=(Raw.Get1()==2) ? 13 : 10; + size_t NameSize=Raw.Get1(); + FileHead.Method=Raw.Get1(); + + FileHead.SplitBefore=(FileHead.Flags & LHD_SPLIT_BEFORE)!=0; + FileHead.SplitAfter=(FileHead.Flags & LHD_SPLIT_AFTER)!=0; + FileHead.Encrypted=(FileHead.Flags & LHD_PASSWORD)!=0; + FileHead.CryptMethod=FileHead.Encrypted ? CRYPT_RAR13:CRYPT_NONE; + + FileHead.PackSize=FileHead.DataSize; + FileHead.WinSize=0x10000; + FileHead.Dir=(FileHead.FileAttr & 0x10)!=0; + + FileHead.HostOS=HOST_MSDOS; + FileHead.HSType=HSYS_WINDOWS; + + FileHead.mtime.SetDos(FileTime); + + Raw.Read(NameSize); + + char FileName[NM]; + Raw.GetB((byte *)FileName,Min(NameSize,ASIZE(FileName))); + FileName[NameSize]=0; + IntToExt(FileName,FileName,ASIZE(FileName)); + CharToWide(FileName,FileHead.FileName,ASIZE(FileHead.FileName)); + ConvertNameCase(FileHead.FileName); + + if (Raw.Size()!=0) + NextBlockPos=CurBlockPos+FileHead.HeadSize+FileHead.PackSize; + CurHeaderType=HEAD_FILE; + } + return NextBlockPos>CurBlockPos ? Raw.Size() : 0; +} +#endif + + +#ifndef SFX_MODULE +void Archive::ConvertNameCase(wchar *Name) +{ + if (Cmd->ConvertNames==NAMES_UPPERCASE) + wcsupper(Name); + if (Cmd->ConvertNames==NAMES_LOWERCASE) + wcslower(Name); +} +#endif + + +bool Archive::IsArcDir() +{ + return FileHead.Dir; +} + + +void Archive::ConvertAttributes() +{ +#if defined(_WIN_ALL) || defined(_EMX) + if (FileHead.HSType!=HSYS_WINDOWS) + FileHead.FileAttr=FileHead.Dir ? 0x10 : 0x20; +#endif +#ifdef _UNIX + // umask defines which permission bits must not be set by default + // when creating a file or directory. The typical default value + // for the process umask is S_IWGRP | S_IWOTH (octal 022), + // resulting in 0644 mode for new files. + // Normally umask is applied automatically when creating a file, + // but we set attributes with chmod later, so we need to calculate + // resulting attributes here. We do it only for non-Unix archives. + // We restore native Unix attributes as is, because it can be backup. + static mode_t mask = (mode_t) -1; + + if (mask == (mode_t) -1) + { + // umask call returns the current umask value. Argument (022) is not + // really important here. + mask = umask(022); + + // Restore the original umask value, which was changed to 022 above. + umask(mask); + } + + switch(FileHead.HSType) + { + case HSYS_WINDOWS: + { + // Mapping MSDOS, OS/2 and Windows file attributes to Unix. + + if (FileHead.FileAttr & 0x10) // FILE_ATTRIBUTE_DIRECTORY + { + // For directories we use 0777 mask. + FileHead.FileAttr=0777 & ~mask; + } + else + if (FileHead.FileAttr & 1) // FILE_ATTRIBUTE_READONLY + { + // For read only files we use 0444 mask with 'w' bits turned off. + FileHead.FileAttr=0444 & ~mask; + } + else + { + // umask does not set +x for regular files, so we use 0666 + // instead of 0777 as for directories. + FileHead.FileAttr=0666 & ~mask; + } + } + break; + case HSYS_UNIX: + break; + default: + if (FileHead.Dir) + FileHead.FileAttr=0x41ff & ~mask; + else + FileHead.FileAttr=0x81b6 & ~mask; + break; + } +#endif +} + + +void Archive::ConvertFileHeader(FileHeader *hd) +{ + if (hd->HSType==HSYS_UNKNOWN) + if (hd->Dir) + hd->FileAttr=0x10; + else + hd->FileAttr=0x20; + +#ifdef _WIN_ALL + if (hd->HSType==HSYS_UNIX) // Convert Unix, OS X and Android decomposed chracters to Windows precomposed. + ConvertToPrecomposed(hd->FileName,ASIZE(hd->FileName)); +#endif + + for (wchar *s=hd->FileName;*s!=0;s++) + { +#ifdef _UNIX + // Backslash is the invalid character for Windows file headers, + // but it can present in Unix file names extracted in Unix. + if (*s=='\\' && Format==RARFMT50 && hd->HSType==HSYS_WINDOWS) + *s='_'; +#endif + +#if defined(_WIN_ALL) || defined(_EMX) + // RAR 5.0 archives do not use '\' as path separator, so if we see it, + // it means that it is a part of Unix file name, which we cannot + // extract in Windows. + if (*s=='\\' && Format==RARFMT50) + *s='_'; + + // ':' in file names is allowed in Unix, but not in Windows. + // Even worse, file data will be written to NTFS stream on NTFS, + // so automatic name correction on file create error in extraction + // routine does not work. In Windows and DOS versions we better + // replace ':' now. + if (*s==':') + *s='_'; +#endif + + // This code must be performed only after other path separator checks, + // because it produces backslashes illegal for some of checks above. + // Backslash is allowed in file names in Unix, but not in Windows. + // Still, RAR 4.x uses backslashes as path separator even in Unix. + // Forward slash is not allowed in both systems. In RAR 5.0 we use + // the forward slash as universal path separator. + if (*s=='/' || *s=='\\' && Format!=RARFMT50) + *s=CPATHDIVIDER; + } +} + + +int64 Archive::GetStartPos() +{ + int64 StartPos=SFXSize+MarkHead.HeadSize; + if (Format==RARFMT15) + StartPos+=MainHead.HeadSize; + else // RAR 5.0. + StartPos+=CryptHead.HeadSize+FullHeaderSize(MainHead.HeadSize); + return StartPos; +} + + +bool Archive::ReadSubData(Array *UnpData,File *DestFile) +{ + if (BrokenHeader) + { + uiMsg(UIERROR_SUBHEADERBROKEN,FileName); + ErrHandler.SetErrorCode(RARX_CRC); + return false; + } + if (SubHead.Method>5 || SubHead.UnpVer>(Format==RARFMT50 ? VER_UNPACK5:VER_UNPACK)) + { + uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName); + return false; + } + + if (SubHead.PackSize==0 && !SubHead.SplitAfter) + return true; + + SubDataIO.Init(); + Unpack Unpack(&SubDataIO); + Unpack.Init(SubHead.WinSize,false); + + if (DestFile==NULL) + { + if (SubHead.UnpSize>0x1000000) + { + // So huge allocation must never happen in valid archives. + uiMsg(UIERROR_SUBHEADERUNKNOWN,FileName); + return false; + } + if (UnpData==NULL) + SubDataIO.SetTestMode(true); + else + { + UnpData->Alloc((size_t)SubHead.UnpSize); + SubDataIO.SetUnpackToMemory(&(*UnpData)[0],(uint)SubHead.UnpSize); + } + } + if (SubHead.Encrypted) + if (Cmd->Password.IsSet()) + SubDataIO.SetEncryption(false,SubHead.CryptMethod,&Cmd->Password, + SubHead.SaltSet ? SubHead.Salt:NULL,SubHead.InitV, + SubHead.Lg2Count,SubHead.HashKey,SubHead.PswCheck); + else + return false; + SubDataIO.UnpHash.Init(SubHead.FileHash.Type,1); + SubDataIO.SetPackedSizeToRead(SubHead.PackSize); + SubDataIO.EnableShowProgress(false); + SubDataIO.SetFiles(this,DestFile); + SubDataIO.UnpVolume=SubHead.SplitAfter; + SubDataIO.SetSubHeader(&SubHead,NULL); + Unpack.SetDestSize(SubHead.UnpSize); + if (SubHead.Method==0) + CmdExtract::UnstoreFile(SubDataIO,SubHead.UnpSize); + else + Unpack.DoUnpack(SubHead.UnpVer,false); + + if (!SubDataIO.UnpHash.Cmp(&SubHead.FileHash,SubHead.UseHashKey ? SubHead.HashKey:NULL)) + { + uiMsg(UIERROR_SUBHEADERDATABROKEN,FileName,SubHead.FileName); + ErrHandler.SetErrorCode(RARX_CRC); + if (UnpData!=NULL) + UnpData->Reset(); + return false; + } + return true; +} diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/array.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/array.hpp new file mode 100644 index 0000000..20d258d --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/array.hpp @@ -0,0 +1,191 @@ +#ifndef _RAR_ARRAY_ +#define _RAR_ARRAY_ + +extern ErrorHandler ErrHandler; + +template class Array +{ + private: + T *Buffer; + size_t BufSize; + size_t AllocSize; + size_t MaxSize; + bool Secure; // Clean memory if true. + public: + Array(); + Array(size_t Size); + Array(const Array &Src); // Copy constructor. + ~Array(); + inline void CleanData(); + inline T& operator [](size_t Item) const; + inline T* operator + (size_t Pos); + inline size_t Size(); // Returns the size in items, not in bytes. + void Add(size_t Items); + void Alloc(size_t Items); + void Reset(); + void SoftReset(); + void operator = (Array &Src); + void Push(T Item); + void Append(T *Item,size_t Count); + T* Addr(size_t Item) {return Buffer+Item;} + void SetMaxSize(size_t Size) {MaxSize=Size;} + T* Begin() {return Buffer;} + T* End() {return Buffer==NULL ? NULL:Buffer+BufSize;} + void SetSecure() {Secure=true;} +}; + + +template void Array::CleanData() +{ + Buffer=NULL; + BufSize=0; + AllocSize=0; + MaxSize=0; + Secure=false; +} + + +template Array::Array() +{ + CleanData(); +} + + +template Array::Array(size_t Size) +{ + CleanData(); + Add(Size); +} + + +// Copy constructor in case we need to pass an object as value. +template Array::Array(const Array &Src) +{ + CleanData(); + Alloc(Src.BufSize); + if (Src.BufSize!=0) + memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T)); +} + + +template Array::~Array() +{ + if (Buffer!=NULL) + { + if (Secure) + cleandata(Buffer,AllocSize*sizeof(T)); + free(Buffer); + } +} + + +template inline T& Array::operator [](size_t Item) const +{ + return Buffer[Item]; +} + + +template inline T* Array::operator +(size_t Pos) +{ + return Buffer+Pos; +} + + +template inline size_t Array::Size() +{ + return BufSize; +} + + +template void Array::Add(size_t Items) +{ + BufSize+=Items; + if (BufSize>AllocSize) + { + if (MaxSize!=0 && BufSize>MaxSize) + { + ErrHandler.GeneralErrMsg(L"Maximum allowed array size (%u) is exceeded",MaxSize); + ErrHandler.MemoryError(); + } + + size_t Suggested=AllocSize+AllocSize/4+32; + size_t NewSize=Max(BufSize,Suggested); + + T *NewBuffer; + if (Secure) + { + NewBuffer=(T *)malloc(NewSize*sizeof(T)); + if (NewBuffer==NULL) + ErrHandler.MemoryError(); + if (Buffer!=NULL) + { + memcpy(NewBuffer,Buffer,AllocSize*sizeof(T)); + cleandata(Buffer,AllocSize*sizeof(T)); + free(Buffer); + } + } + else + { + NewBuffer=(T *)realloc(Buffer,NewSize*sizeof(T)); + if (NewBuffer==NULL) + ErrHandler.MemoryError(); + } + Buffer=NewBuffer; + AllocSize=NewSize; + } +} + + +template void Array::Alloc(size_t Items) +{ + if (Items>AllocSize) + Add(Items-BufSize); + else + BufSize=Items; +} + + +template void Array::Reset() +{ + if (Buffer!=NULL) + { + free(Buffer); + Buffer=NULL; + } + BufSize=0; + AllocSize=0; +} + + +// Reset buffer size, but preserve already allocated memory if any, +// so we can reuse it without wasting time to allocation. +template void Array::SoftReset() +{ + BufSize=0; +} + + +template void Array::operator =(Array &Src) +{ + Reset(); + Alloc(Src.BufSize); + if (Src.BufSize!=0) + memcpy((void *)Buffer,(void *)Src.Buffer,Src.BufSize*sizeof(T)); +} + + +template void Array::Push(T Item) +{ + Add(1); + (*this)[Size()-1]=Item; +} + + +template void Array::Append(T *Items,size_t Count) +{ + size_t CurSize=Size(); + Add(Count); + memcpy(Buffer+CurSize,Items,Count*sizeof(T)); +} + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/blake2s.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/blake2s.cpp new file mode 100644 index 0000000..317603d --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/blake2s.cpp @@ -0,0 +1,183 @@ +// Based on public domain code written in 2012 by Samuel Neves + +#include "rar.hpp" + +#ifdef USE_SSE +#include "blake2s_sse.cpp" +#endif + +static void blake2s_init_param( blake2s_state *S, uint32 node_offset, uint32 node_depth); +static void blake2s_update( blake2s_state *S, const byte *in, size_t inlen ); +static void blake2s_final( blake2s_state *S, byte *digest ); + +#include "blake2sp.cpp" + +static const uint32 blake2s_IV[8] = +{ + 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL, + 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL +}; + +static const byte blake2s_sigma[10][16] = +{ + { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } , + { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } , + { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } , + { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } , + { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } , + { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } , + { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } , + { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } , + { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } , + { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } , +}; + +static inline void blake2s_set_lastnode( blake2s_state *S ) +{ + S->f[1] = ~0U; +} + + +/* Some helper functions, not necessarily useful */ +static inline void blake2s_set_lastblock( blake2s_state *S ) +{ + if( S->last_node ) blake2s_set_lastnode( S ); + + S->f[0] = ~0U; +} + + +static inline void blake2s_increment_counter( blake2s_state *S, const uint32 inc ) +{ + S->t[0] += inc; + S->t[1] += ( S->t[0] < inc ); +} + + +/* init2 xors IV with input parameter block */ +void blake2s_init_param( blake2s_state *S, uint32 node_offset, uint32 node_depth) +{ +#ifdef USE_SSE + if (_SSE_Version>=SSE_SSE2) + blake2s_init_sse(); +#endif + + S->init(); // Clean data. + for( int i = 0; i < 8; ++i ) + S->h[i] = blake2s_IV[i]; + + S->h[0] ^= 0x02080020; // We use BLAKE2sp parameters block. + S->h[2] ^= node_offset; + S->h[3] ^= (node_depth<<16)|0x20000000; +} + + +#define G(r,i,m,a,b,c,d) \ + a = a + b + m[blake2s_sigma[r][2*i+0]]; \ + d = rotr32(d ^ a, 16); \ + c = c + d; \ + b = rotr32(b ^ c, 12); \ + a = a + b + m[blake2s_sigma[r][2*i+1]]; \ + d = rotr32(d ^ a, 8); \ + c = c + d; \ + b = rotr32(b ^ c, 7); + + +static void blake2s_compress( blake2s_state *S, const byte block[BLAKE2S_BLOCKBYTES] ) +{ + uint32 m[16]; + uint32 v[16]; + + for( size_t i = 0; i < 16; ++i ) + m[i] = RawGet4( block + i * 4 ); + + for( size_t i = 0; i < 8; ++i ) + v[i] = S->h[i]; + + v[ 8] = blake2s_IV[0]; + v[ 9] = blake2s_IV[1]; + v[10] = blake2s_IV[2]; + v[11] = blake2s_IV[3]; + v[12] = S->t[0] ^ blake2s_IV[4]; + v[13] = S->t[1] ^ blake2s_IV[5]; + v[14] = S->f[0] ^ blake2s_IV[6]; + v[15] = S->f[1] ^ blake2s_IV[7]; + + for ( uint r = 0; r <= 9; ++r ) // No gain on i7 if unrolled, but exe size grows. + { + G(r,0,m,v[ 0],v[ 4],v[ 8],v[12]); + G(r,1,m,v[ 1],v[ 5],v[ 9],v[13]); + G(r,2,m,v[ 2],v[ 6],v[10],v[14]); + G(r,3,m,v[ 3],v[ 7],v[11],v[15]); + G(r,4,m,v[ 0],v[ 5],v[10],v[15]); + G(r,5,m,v[ 1],v[ 6],v[11],v[12]); + G(r,6,m,v[ 2],v[ 7],v[ 8],v[13]); + G(r,7,m,v[ 3],v[ 4],v[ 9],v[14]); + } + + for( size_t i = 0; i < 8; ++i ) + S->h[i] = S->h[i] ^ v[i] ^ v[i + 8]; +} + + +void blake2s_update( blake2s_state *S, const byte *in, size_t inlen ) +{ + while( inlen > 0 ) + { + size_t left = S->buflen; + size_t fill = 2 * BLAKE2S_BLOCKBYTES - left; + + if( inlen > fill ) + { + memcpy( S->buf + left, in, fill ); // Fill buffer + S->buflen += fill; + blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES ); + +#ifdef USE_SSE +#ifdef _WIN_32 // We use SSSE3 _mm_shuffle_epi8 only in x64 mode. + if (_SSE_Version>=SSE_SSE2) +#else + if (_SSE_Version>=SSE_SSSE3) +#endif + blake2s_compress_sse( S, S->buf ); + else + blake2s_compress( S, S->buf ); // Compress +#else + blake2s_compress( S, S->buf ); // Compress +#endif + + memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES ); // Shift buffer left + S->buflen -= BLAKE2S_BLOCKBYTES; + in += fill; + inlen -= fill; + } + else // inlen <= fill + { + memcpy( S->buf + left, in, (size_t)inlen ); + S->buflen += (size_t)inlen; // Be lazy, do not compress + in += inlen; + inlen = 0; + } + } +} + + +void blake2s_final( blake2s_state *S, byte *digest ) +{ + if( S->buflen > BLAKE2S_BLOCKBYTES ) + { + blake2s_increment_counter( S, BLAKE2S_BLOCKBYTES ); + blake2s_compress( S, S->buf ); + S->buflen -= BLAKE2S_BLOCKBYTES; + memcpy( S->buf, S->buf + BLAKE2S_BLOCKBYTES, S->buflen ); + } + + blake2s_increment_counter( S, ( uint32 )S->buflen ); + blake2s_set_lastblock( S ); + memset( S->buf + S->buflen, 0, 2 * BLAKE2S_BLOCKBYTES - S->buflen ); /* Padding */ + blake2s_compress( S, S->buf ); + + for( int i = 0; i < 8; ++i ) /* Output full hash */ + RawPut4( S->h[i], digest + 4 * i ); +} + diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/blake2s.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/blake2s.hpp new file mode 100644 index 0000000..7dd7157 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/blake2s.hpp @@ -0,0 +1,101 @@ +// Based on public domain code written in 2012 by Samuel Neves +#ifndef _RAR_BLAKE2_ +#define _RAR_BLAKE2_ + +#define BLAKE2_DIGEST_SIZE 32 + +enum blake2s_constant +{ + BLAKE2S_BLOCKBYTES = 64, + BLAKE2S_OUTBYTES = 32 +}; + + +// Alignment to 64 improves performance of both SSE and non-SSE versions. +// Alignment to n*16 is required for SSE version, so we selected 64. +// We use the custom alignment scheme instead of __declspec(align(x)), +// because it is less compiler dependent. Also the compiler directive +// does not help if structure is a member of class allocated through +// 'new' operator. +struct blake2s_state +{ + enum { BLAKE_ALIGNMENT = 64 }; + + // buffer and uint32 h[8], t[2], f[2]; + enum { BLAKE_DATA_SIZE = 48 + 2 * BLAKE2S_BLOCKBYTES }; + + byte ubuf[BLAKE_DATA_SIZE + BLAKE_ALIGNMENT]; + + byte *buf; // byte buf[2 * BLAKE2S_BLOCKBYTES]. + uint32 *h, *t, *f; // uint32 h[8], t[2], f[2]. + + size_t buflen; + byte last_node; + + blake2s_state() + { + set_pointers(); + } + + // Required when we declare and assign in the same command. + blake2s_state(blake2s_state &st) + { + set_pointers(); + *this=st; + } + + void set_pointers() + { + // Set aligned pointers. Must be done in constructor, not in Init(), + // so assignments like 'blake2sp_state res=blake2ctx' work correctly + // even if blake2sp_init is not called for 'res'. + buf = (byte *) ALIGN_VALUE(ubuf, BLAKE_ALIGNMENT); + h = (uint32 *) (buf + 2 * BLAKE2S_BLOCKBYTES); + t = h + 8; + f = t + 2; + } + + void init() + { + memset( ubuf, 0, sizeof( ubuf ) ); + buflen = 0; + last_node = 0; + } + + // Since we use pointers, the default = would work incorrectly. + blake2s_state& operator = (blake2s_state &st) + { + if (this != &st) + { + memcpy(buf, st.buf, BLAKE_DATA_SIZE); + buflen = st.buflen; + last_node = st.last_node; + } + return *this; + } +}; + + +#ifdef RAR_SMP +class ThreadPool; +#endif + +struct blake2sp_state +{ + blake2s_state S[8]; + blake2s_state R; + byte buf[8 * BLAKE2S_BLOCKBYTES]; + size_t buflen; + +#ifdef RAR_SMP + ThreadPool *ThPool; + uint MaxThreads; +#endif +}; + +void blake2sp_init( blake2sp_state *S ); +void blake2sp_update( blake2sp_state *S, const byte *in, size_t inlen ); +void blake2sp_final( blake2sp_state *S, byte *digest ); + +#endif + diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/blake2s_sse.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/blake2s_sse.cpp new file mode 100644 index 0000000..1a02f21 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/blake2s_sse.cpp @@ -0,0 +1,129 @@ +// Based on public domain code written in 2012 by Samuel Neves + +extern const byte blake2s_sigma[10][16]; + +// Initialization vector. +static __m128i blake2s_IV_0_3, blake2s_IV_4_7; + +#ifdef _WIN_64 +// Constants for cyclic rotation. Used in 64-bit mode in mm_rotr_epi32 macro. +static __m128i crotr8, crotr16; +#endif + +static void blake2s_init_sse() +{ + // We cannot initialize these 128 bit variables in place when declaring + // them globally, because global scope initialization is performed before + // our SSE check and it would make code incompatible with older non-SSE2 + // CPUs. Also we cannot initialize them as static inside of function + // using these variables, because SSE static initialization is not thread + // safe: first thread starts initialization and sets "init done" flag even + // if it is not done yet, second thread can attempt to access half-init + // SSE data. So we moved init code here. + + blake2s_IV_0_3 = _mm_setr_epi32( 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A ); + blake2s_IV_4_7 = _mm_setr_epi32( 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19 ); + +#ifdef _WIN_64 + crotr8 = _mm_set_epi8( 12, 15, 14, 13, 8, 11, 10, 9, 4, 7, 6, 5, 0, 3, 2, 1 ); + crotr16 = _mm_set_epi8( 13, 12, 15, 14, 9, 8, 11, 10, 5, 4, 7, 6, 1, 0, 3, 2 ); +#endif +} + + +#define LOAD(p) _mm_load_si128( (__m128i *)(p) ) +#define STORE(p,r) _mm_store_si128((__m128i *)(p), r) + +#ifdef _WIN_32 +// 32-bit mode has less SSE2 registers and in MSVC2008 it is more efficient +// to not use _mm_shuffle_epi8 here. +#define mm_rotr_epi32(r, c) ( \ + _mm_xor_si128(_mm_srli_epi32( (r), c ),_mm_slli_epi32( (r), 32-c )) ) +#else +#define mm_rotr_epi32(r, c) ( \ + c==8 ? _mm_shuffle_epi8(r,crotr8) \ + : c==16 ? _mm_shuffle_epi8(r,crotr16) \ + : _mm_xor_si128(_mm_srli_epi32( (r), c ),_mm_slli_epi32( (r), 32-c )) ) +#endif + + +#define G1(row1,row2,row3,row4,buf) \ + row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \ + row4 = _mm_xor_si128( row4, row1 ); \ + row4 = mm_rotr_epi32(row4, 16); \ + row3 = _mm_add_epi32( row3, row4 ); \ + row2 = _mm_xor_si128( row2, row3 ); \ + row2 = mm_rotr_epi32(row2, 12); + +#define G2(row1,row2,row3,row4,buf) \ + row1 = _mm_add_epi32( _mm_add_epi32( row1, buf), row2 ); \ + row4 = _mm_xor_si128( row4, row1 ); \ + row4 = mm_rotr_epi32(row4, 8); \ + row3 = _mm_add_epi32( row3, row4 ); \ + row2 = _mm_xor_si128( row2, row3 ); \ + row2 = mm_rotr_epi32(row2, 7); + +#define DIAGONALIZE(row1,row2,row3,row4) \ + row4 = _mm_shuffle_epi32( row4, _MM_SHUFFLE(2,1,0,3) ); \ + row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(1,0,3,2) ); \ + row2 = _mm_shuffle_epi32( row2, _MM_SHUFFLE(0,3,2,1) ); + +#define UNDIAGONALIZE(row1,row2,row3,row4) \ + row4 = _mm_shuffle_epi32( row4, _MM_SHUFFLE(0,3,2,1) ); \ + row3 = _mm_shuffle_epi32( row3, _MM_SHUFFLE(1,0,3,2) ); \ + row2 = _mm_shuffle_epi32( row2, _MM_SHUFFLE(2,1,0,3) ); + +#ifdef _WIN_64 + // MSVC 2008 in x64 mode expands _mm_set_epi32 to store to stack and load + // from stack operations, which are slower than this code. + #define _mm_set_epi32(i3,i2,i1,i0) \ + _mm_unpacklo_epi32(_mm_unpacklo_epi32(_mm_cvtsi32_si128(i0),_mm_cvtsi32_si128(i2)), \ + _mm_unpacklo_epi32(_mm_cvtsi32_si128(i1),_mm_cvtsi32_si128(i3))) +#endif + +// Original BLAKE2 SSE4.1 message loading code was a little slower in x86 mode +// and about the same in x64 mode in our test. Perhaps depends on compiler. +// We also tried _mm_i32gather_epi32 and _mm256_i32gather_epi32 AVX2 gather +// instructions here, but they did not show any speed gain on i7-6700K. +#define SSE_ROUND(m,row,r) \ +{ \ + __m128i buf; \ + buf=_mm_set_epi32(m[blake2s_sigma[r][6]],m[blake2s_sigma[r][4]],m[blake2s_sigma[r][2]],m[blake2s_sigma[r][0]]); \ + G1(row[0],row[1],row[2],row[3],buf); \ + buf=_mm_set_epi32(m[blake2s_sigma[r][7]],m[blake2s_sigma[r][5]],m[blake2s_sigma[r][3]],m[blake2s_sigma[r][1]]); \ + G2(row[0],row[1],row[2],row[3],buf); \ + DIAGONALIZE(row[0],row[1],row[2],row[3]); \ + buf=_mm_set_epi32(m[blake2s_sigma[r][14]],m[blake2s_sigma[r][12]],m[blake2s_sigma[r][10]],m[blake2s_sigma[r][8]]); \ + G1(row[0],row[1],row[2],row[3],buf); \ + buf=_mm_set_epi32(m[blake2s_sigma[r][15]],m[blake2s_sigma[r][13]],m[blake2s_sigma[r][11]],m[blake2s_sigma[r][9]]); \ + G2(row[0],row[1],row[2],row[3],buf); \ + UNDIAGONALIZE(row[0],row[1],row[2],row[3]); \ +} + + +static int blake2s_compress_sse( blake2s_state *S, const byte block[BLAKE2S_BLOCKBYTES] ) +{ + __m128i row[4]; + __m128i ff0, ff1; + + const uint32 *m = ( uint32 * )block; + + row[0] = ff0 = LOAD( &S->h[0] ); + row[1] = ff1 = LOAD( &S->h[4] ); + + row[2] = blake2s_IV_0_3; + row[3] = _mm_xor_si128( blake2s_IV_4_7, LOAD( &S->t[0] ) ); + SSE_ROUND( m, row, 0 ); + SSE_ROUND( m, row, 1 ); + SSE_ROUND( m, row, 2 ); + SSE_ROUND( m, row, 3 ); + SSE_ROUND( m, row, 4 ); + SSE_ROUND( m, row, 5 ); + SSE_ROUND( m, row, 6 ); + SSE_ROUND( m, row, 7 ); + SSE_ROUND( m, row, 8 ); + SSE_ROUND( m, row, 9 ); + STORE( &S->h[0], _mm_xor_si128( ff0, _mm_xor_si128( row[0], row[2] ) ) ); + STORE( &S->h[4], _mm_xor_si128( ff1, _mm_xor_si128( row[1], row[3] ) ) ); + return 0; +} diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/blake2sp.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/blake2sp.cpp new file mode 100644 index 0000000..da64588 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/blake2sp.cpp @@ -0,0 +1,153 @@ +/* + BLAKE2 reference source code package - reference C implementations + + Written in 2012 by Samuel Neves + + To the extent possible under law, the author(s) have dedicated all copyright + and related and neighboring rights to this software to the public domain + worldwide. This software is distributed without any warranty. + + You should have received a copy of the CC0 Public Domain Dedication along with + this software. If not, see . +*/ + +#define PARALLELISM_DEGREE 8 + +void blake2sp_init( blake2sp_state *S ) +{ + memset( S->buf, 0, sizeof( S->buf ) ); + S->buflen = 0; + + blake2s_init_param( &S->R, 0, 1 ); // Init root. + + for( uint i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2s_init_param( &S->S[i], i, 0 ); // Init leaf. + + S->R.last_node = 1; + S->S[PARALLELISM_DEGREE - 1].last_node = 1; +} + + +struct Blake2ThreadData +{ + void Update(); + blake2s_state *S; + const byte *in; + size_t inlen; +}; + + +void Blake2ThreadData::Update() +{ + size_t inlen__ = inlen; + const byte *in__ = ( const byte * )in; + + while( inlen__ >= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES ) + { +#ifdef USE_SSE + // We gain 5% in i7 SSE mode by prefetching next data block. + if (_SSE_Version>=SSE_SSE && inlen__ >= 2 * PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES) + _mm_prefetch((char*)(in__ + PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES), _MM_HINT_T0); +#endif + blake2s_update( S, in__, BLAKE2S_BLOCKBYTES ); + in__ += PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; + inlen__ -= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; + } +} + +#ifdef RAR_SMP +THREAD_PROC(Blake2Thread) +{ + Blake2ThreadData *td=(Blake2ThreadData *)Data; + td->Update(); +} +#endif + + +void blake2sp_update( blake2sp_state *S, const byte *in, size_t inlen ) +{ + size_t left = S->buflen; + size_t fill = sizeof( S->buf ) - left; + + if( left && inlen >= fill ) + { + memcpy( S->buf + left, in, fill ); + + for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2s_update( &S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, BLAKE2S_BLOCKBYTES ); + + in += fill; + inlen -= fill; + left = 0; + } + + Blake2ThreadData btd_array[PARALLELISM_DEGREE]; + +#ifdef RAR_SMP + uint ThreadNumber = inlen < 0x1000 ? 1 : S->MaxThreads; + + if (ThreadNumber==6 || ThreadNumber==7) // 6 and 7 threads work slower than 4 here. + ThreadNumber=4; +#else + uint ThreadNumber=1; +#endif + + for (size_t id__=0;id__inlen = inlen; + btd->in = in + id__ * BLAKE2S_BLOCKBYTES; + btd->S = &S->S[id__]; + +#ifdef RAR_SMP + if (ThreadNumber>1) + S->ThPool->AddTask(Blake2Thread,(void*)btd); + else + btd->Update(); +#else + btd->Update(); +#endif + id__++; + } +#ifdef RAR_SMP + if (S->ThPool!=NULL) // Can be NULL in -mt1 mode. + S->ThPool->WaitDone(); +#endif // RAR_SMP + } + + in += inlen - inlen % ( PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES ); + inlen %= PARALLELISM_DEGREE * BLAKE2S_BLOCKBYTES; + + if( inlen > 0 ) + memcpy( S->buf + left, in, (size_t)inlen ); + + S->buflen = left + (size_t)inlen; +} + + +void blake2sp_final( blake2sp_state *S, byte *digest ) +{ + byte hash[PARALLELISM_DEGREE][BLAKE2S_OUTBYTES]; + + for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) + { + if( S->buflen > i * BLAKE2S_BLOCKBYTES ) + { + size_t left = S->buflen - i * BLAKE2S_BLOCKBYTES; + + if( left > BLAKE2S_BLOCKBYTES ) left = BLAKE2S_BLOCKBYTES; + + blake2s_update( &S->S[i], S->buf + i * BLAKE2S_BLOCKBYTES, left ); + } + + blake2s_final( &S->S[i], hash[i] ); + } + + for( size_t i = 0; i < PARALLELISM_DEGREE; ++i ) + blake2s_update( &S->R, hash[i], BLAKE2S_OUTBYTES ); + + blake2s_final( &S->R, digest ); +} diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/cmddata.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/cmddata.cpp new file mode 100644 index 0000000..32b8412 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/cmddata.cpp @@ -0,0 +1,1407 @@ +#include "rar.hpp" + +CommandData::CommandData() +{ + Init(); +} + + +void CommandData::Init() +{ + RAROptions::Init(); + + *Command=0; + *ArcName=0; + FileLists=false; + NoMoreSwitches=false; + + ListMode=RCLM_AUTO; + + BareOutput=false; + + + FileArgs.Reset(); + ExclArgs.Reset(); + InclArgs.Reset(); + StoreArgs.Reset(); + ArcNames.Reset(); + NextVolSizes.Reset(); +} + + +// Return the pointer to next position in the string and store dynamically +// allocated command line parameter in Par. +static const wchar *AllocCmdParam(const wchar *CmdLine,wchar **Par) +{ + const wchar *NextCmd=GetCmdParam(CmdLine,NULL,0); + if (NextCmd==NULL) + return NULL; + size_t ParSize=NextCmd-CmdLine+2; // Parameter size including the trailing zero. + *Par=(wchar *)malloc(ParSize*sizeof(wchar)); + if (*Par==NULL) + return NULL; + return GetCmdParam(CmdLine,*Par,ParSize); +} + + +#if !defined(SFX_MODULE) +void CommandData::ParseCommandLine(bool Preprocess,int argc, char *argv[]) +{ + *Command=0; + NoMoreSwitches=false; +#ifdef CUSTOM_CMDLINE_PARSER + // In Windows we may prefer to implement our own command line parser + // to avoid replacing \" by " in standard parser. Such replacing corrupts + // destination paths like "dest path\" in extraction commands. + // Also our own parser is Unicode compatible. + const wchar *CmdLine=GetCommandLine(); + + wchar *Par; + for (bool FirstParam=true;;FirstParam=false) + { + if ((CmdLine=AllocCmdParam(CmdLine,&Par))==NULL) + break; + if (!FirstParam) // First parameter is the executable name. + if (Preprocess) + PreprocessArg(Par); + else + ParseArg(Par); + free(Par); + } +#else + Array Arg; + for (int I=1;I EnvStrW(strlen(EnvStr)+1); + CharToWide(EnvStr,&EnvStrW[0],EnvStrW.Size()); + ProcessSwitchesString(&EnvStrW[0]); + } +} +#endif + + + +#if !defined(SFX_MODULE) +// Preprocess those parameters, which must be processed before the rest of +// command line. Return 'false' to stop further processing. +void CommandData::PreprocessArg(const wchar *Arg) +{ + if (IsSwitch(Arg[0]) && !NoMoreSwitches) + { + Arg++; + if (Arg[0]=='-' && Arg[1]==0) // Switch "--". + NoMoreSwitches=true; + if (wcsicomp(Arg,L"cfg-")==0) + ConfigDisabled=true; + if (wcsnicomp(Arg,L"ilog",4)==0) + { + // Ensure that correct log file name is already set + // if we need to report an error when processing the command line. + ProcessSwitch(Arg); + InitLogOptions(LogName,ErrlogCharset); + } + if (wcsnicomp(Arg,L"sc",2)==0) + { + // Process -sc before reading any file lists. + ProcessSwitch(Arg); + if (*LogName!=0) + InitLogOptions(LogName,ErrlogCharset); + } + } + else + if (*Command==0) + wcsncpy(Command,Arg,ASIZE(Command)); // Need for rar.ini. +} +#endif + + +#if !defined(SFX_MODULE) +void CommandData::ReadConfig() +{ + StringList List; + if (ReadTextFile(DefConfigName,&List,true)) + { + wchar *Str; + while ((Str=List.GetString())!=NULL) + { + while (IsSpace(*Str)) + Str++; + if (wcsnicomp(Str,L"switches=",9)==0) + ProcessSwitchesString(Str+9); + if (*Command!=0) + { + wchar Cmd[16]; + wcsncpyz(Cmd,Command,ASIZE(Cmd)); + wchar C0=toupperw(Cmd[0]); + wchar C1=toupperw(Cmd[1]); + if (C0=='I' || C0=='L' || C0=='M' || C0=='S' || C0=='V') + Cmd[1]=0; + if (C0=='R' && (C1=='R' || C1=='V')) + Cmd[2]=0; + wchar SwName[16+ASIZE(Cmd)]; + swprintf(SwName,ASIZE(SwName),L"switches_%ls=",Cmd); + size_t Length=wcslen(SwName); + if (wcsnicomp(Str,SwName,Length)==0) + ProcessSwitchesString(Str+Length); + } + } + } +} +#endif + + +#if !defined(SFX_MODULE) +void CommandData::ProcessSwitchesString(const wchar *Str) +{ + wchar *Par; + while ((Str=AllocCmdParam(Str,&Par))!=NULL) + { + if (IsSwitch(*Par)) + ProcessSwitch(Par+1); + free(Par); + } +} +#endif + + +#if !defined(SFX_MODULE) +void CommandData::ProcessSwitch(const wchar *Switch) +{ + + switch(toupperw(Switch[0])) + { + case '@': + ListMode=Switch[1]=='+' ? RCLM_ACCEPT_LISTS:RCLM_REJECT_LISTS; + break; + case 'A': + switch(toupperw(Switch[1])) + { + case 'C': + ClearArc=true; + break; + case 'D': + AppendArcNameToPath=true; + break; +#ifndef SFX_MODULE + case 'G': + if (Switch[2]=='-' && Switch[3]==0) + GenerateArcName=0; + else + { + GenerateArcName=true; + wcsncpyz(GenerateMask,Switch+2,ASIZE(GenerateMask)); + } + break; +#endif + case 'I': + IgnoreGeneralAttr=true; + break; + case 'N': // Reserved for archive name. + break; + case 'O': + AddArcOnly=true; + break; + case 'P': + wcscpy(ArcPath,Switch+2); + break; + case 'S': + SyncFiles=true; + break; + default: + BadSwitch(Switch); + break; + } + break; + case 'C': + if (Switch[2]==0) + switch(toupperw(Switch[1])) + { + case '-': + DisableComment=true; + break; + case 'U': + ConvertNames=NAMES_UPPERCASE; + break; + case 'L': + ConvertNames=NAMES_LOWERCASE; + break; + } + break; + case 'D': + if (Switch[2]==0) + switch(toupperw(Switch[1])) + { + case 'S': + DisableSortSolid=true; + break; + case 'H': + OpenShared=true; + break; + case 'F': + DeleteFiles=true; + break; + } + break; + case 'E': + switch(toupperw(Switch[1])) + { + case 'P': + switch(Switch[2]) + { + case 0: + ExclPath=EXCL_SKIPWHOLEPATH; + break; + case '1': + ExclPath=EXCL_BASEPATH; + break; + case '2': + ExclPath=EXCL_SAVEFULLPATH; + break; + case '3': + ExclPath=EXCL_ABSPATH; + break; + } + break; + default: + if (Switch[1]=='+') + { + InclFileAttr|=GetExclAttr(Switch+2); + InclAttrSet=true; + } + else + ExclFileAttr|=GetExclAttr(Switch+1); + break; + } + break; + case 'F': + if (Switch[1]==0) + FreshFiles=true; + else + BadSwitch(Switch); + break; + case 'H': + switch (toupperw(Switch[1])) + { + case 'P': + EncryptHeaders=true; + if (Switch[2]!=0) + { + Password.Set(Switch+2); + cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0])); + } + else + if (!Password.IsSet()) + { + uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password); + eprintf(L"\n"); + } + break; + default : + BadSwitch(Switch); + break; + } + break; + case 'I': + if (wcsnicomp(Switch+1,L"LOG",3)==0) + { + wcsncpyz(LogName,Switch[4]!=0 ? Switch+4:DefLogName,ASIZE(LogName)); + break; + } + if (wcsicomp(Switch+1,L"SND")==0) + { + Sound=true; + break; + } + if (wcsicomp(Switch+1,L"ERR")==0) + { + MsgStream=MSG_STDERR; + // Set it immediately when parsing the command line, so it also + // affects messages issued while parsing the command line. + SetConsoleMsgStream(MSG_STDERR); + break; + } + if (wcsnicomp(Switch+1,L"EML",3)==0) + { + wcsncpyz(EmailTo,Switch[4]!=0 ? Switch+4:L"@",ASIZE(EmailTo)); + break; + } + if (wcsicomp(Switch+1,L"M")==0) + { + MoreInfo=true; + break; + } + if (wcsicomp(Switch+1,L"NUL")==0) + { + MsgStream=MSG_NULL; + SetConsoleMsgStream(MSG_NULL); + break; + } + if (toupperw(Switch[1])=='D') + { + for (uint I=2;Switch[I]!=0;I++) + switch(toupperw(Switch[I])) + { + case 'Q': + MsgStream=MSG_ERRONLY; + SetConsoleMsgStream(MSG_ERRONLY); + break; + case 'C': + DisableCopyright=true; + break; + case 'D': + DisableDone=true; + break; + case 'P': + DisablePercentage=true; + break; + } + break; + } + if (wcsnicomp(Switch+1,L"OFF",3)==0) + { + switch(Switch[4]) + { + case 0: + case '1': + Shutdown=POWERMODE_OFF; + break; + case '2': + Shutdown=POWERMODE_HIBERNATE; + break; + case '3': + Shutdown=POWERMODE_SLEEP; + break; + case '4': + Shutdown=POWERMODE_RESTART; + break; + } + break; + } + if (wcsicomp(Switch+1,L"VER")==0) + { + PrintVersion=true; + break; + } + break; + case 'K': + switch(toupperw(Switch[1])) + { + case 'B': + KeepBroken=true; + break; + case 0: + Lock=true; + break; + } + break; + case 'M': + switch(toupperw(Switch[1])) + { + case 'C': + { + const wchar *Str=Switch+2; + if (*Str=='-') + for (uint I=0;IMaxPoolThreads || Threads<1) + BadSwitch(Switch); + else + { + } + break; +#endif + default: + Method=Switch[1]-'0'; + if (Method>5 || Method<0) + BadSwitch(Switch); + break; + } + break; + case 'N': + case 'X': + if (Switch[1]!=0) + { + StringList *Args=toupperw(Switch[0])=='N' ? &InclArgs:&ExclArgs; + if (Switch[1]=='@' && !IsWildcard(Switch)) + ReadTextFile(Switch+2,Args,false,true,FilelistCharset,true,true,true); + else + Args->AddString(Switch+1); + } + break; + case 'O': + switch(toupperw(Switch[1])) + { + case '+': + Overwrite=OVERWRITE_ALL; + break; + case '-': + Overwrite=OVERWRITE_NONE; + break; + case 0: + Overwrite=OVERWRITE_FORCE_ASK; + break; +#ifdef _WIN_ALL + case 'C': + SetCompressedAttr=true; + break; +#endif + case 'H': + SaveHardLinks=true; + break; + + +#ifdef SAVE_LINKS + case 'L': + SaveSymLinks=true; + if (toupperw(Switch[2])=='A') + AbsoluteLinks=true; + break; +#endif +#ifdef _WIN_ALL + case 'N': + if (toupperw(Switch[2])=='I') + AllowIncompatNames=true; + break; +#endif + case 'R': + Overwrite=OVERWRITE_AUTORENAME; + break; +#ifdef _WIN_ALL + case 'S': + SaveStreams=true; + break; +#endif + case 'W': + ProcessOwners=true; + break; + default : + BadSwitch(Switch); + break; + } + break; + case 'P': + if (Switch[1]==0) + { + uiGetPassword(UIPASSWORD_GLOBAL,NULL,&Password); + eprintf(L"\n"); + } + else + { + Password.Set(Switch+1); + cleandata((void *)Switch,wcslen(Switch)*sizeof(Switch[0])); + } + break; +#ifndef SFX_MODULE + case 'Q': + if (toupperw(Switch[1])=='O') + switch(toupperw(Switch[2])) + { + case 0: + QOpenMode=QOPEN_AUTO; + break; + case '-': + QOpenMode=QOPEN_NONE; + break; + case '+': + QOpenMode=QOPEN_ALWAYS; + break; + default: + BadSwitch(Switch); + break; + } + else + BadSwitch(Switch); + break; +#endif + case 'R': + switch(toupperw(Switch[1])) + { + case 0: + Recurse=RECURSE_ALWAYS; + break; + case '-': + Recurse=RECURSE_DISABLE; + break; + case '0': + Recurse=RECURSE_WILDCARDS; + break; + case 'I': + { + Priority=atoiw(Switch+2); + if (Priority<0 || Priority>15) + BadSwitch(Switch); + const wchar *ChPtr=wcschr(Switch+2,':'); + if (ChPtr!=NULL) + { + SleepTime=atoiw(ChPtr+1); + if (SleepTime>1000) + BadSwitch(Switch); + InitSystemOptions(SleepTime); + } + SetPriority(Priority); + } + break; + } + break; + case 'S': + if (IsDigit(Switch[1])) + { + Solid|=SOLID_COUNT; + SolidCount=atoiw(&Switch[1]); + } + else + switch(toupperw(Switch[1])) + { + case 0: + Solid|=SOLID_NORMAL; + break; + case '-': + Solid=SOLID_NONE; + break; + case 'E': + Solid|=SOLID_FILEEXT; + break; + case 'V': + Solid|=Switch[2]=='-' ? SOLID_VOLUME_DEPENDENT:SOLID_VOLUME_INDEPENDENT; + break; + case 'D': + Solid|=SOLID_VOLUME_DEPENDENT; + break; + case 'L': + if (IsDigit(Switch[2])) + FileSizeLess=atoilw(Switch+2); + break; + case 'M': + if (IsDigit(Switch[2])) + FileSizeMore=atoilw(Switch+2); + break; + case 'C': + { + bool AlreadyBad=false; // Avoid reporting "bad switch" several times. + + RAR_CHARSET rch=RCH_DEFAULT; + switch(toupperw(Switch[2])) + { + case 'A': + rch=RCH_ANSI; + break; + case 'O': + rch=RCH_OEM; + break; + case 'U': + rch=RCH_UNICODE; + break; + case 'F': + rch=RCH_UTF8; + break; + default : + BadSwitch(Switch); + AlreadyBad=true; + break; + }; + if (!AlreadyBad) + if (Switch[3]==0) + CommentCharset=FilelistCharset=ErrlogCharset=RedirectCharset=rch; + else + for (uint I=3;Switch[I]!=0 && !AlreadyBad;I++) + switch(toupperw(Switch[I])) + { + case 'C': + CommentCharset=rch; + break; + case 'L': + FilelistCharset=rch; + break; + case 'R': + RedirectCharset=rch; + break; + default: + BadSwitch(Switch); + AlreadyBad=true; + break; + } + // Set it immediately when parsing the command line, so it also + // affects messages issued while parsing the command line. + SetConsoleRedirectCharset(RedirectCharset); + } + break; + + } + break; + case 'T': + switch(toupperw(Switch[1])) + { + case 'K': + ArcTime=ARCTIME_KEEP; + break; + case 'L': + ArcTime=ARCTIME_LATEST; + break; + case 'O': + FileTimeBefore.SetAgeText(Switch+2); + break; + case 'N': + FileTimeAfter.SetAgeText(Switch+2); + break; + case 'B': + FileTimeBefore.SetIsoText(Switch+2); + break; + case 'A': + FileTimeAfter.SetIsoText(Switch+2); + break; + case 'S': + { + EXTTIME_MODE Mode=EXTTIME_HIGH3; + bool CommonMode=Switch[2]>='0' && Switch[2]<='4'; + if (CommonMode) + Mode=(EXTTIME_MODE)(Switch[2]-'0'); + if (Mode==EXTTIME_HIGH1 || Mode==EXTTIME_HIGH2) // '2' and '3' not supported anymore. + Mode=EXTTIME_HIGH3; + if (Switch[2]=='-') + Mode=EXTTIME_NONE; + if (CommonMode || Switch[2]=='-' || Switch[2]=='+' || Switch[2]==0) + xmtime=xctime=xatime=Mode; + else + { + if (Switch[3]>='0' && Switch[3]<='4') + Mode=(EXTTIME_MODE)(Switch[3]-'0'); + if (Mode==EXTTIME_HIGH1 || Mode==EXTTIME_HIGH2) // '2' and '3' not supported anymore. + Mode=EXTTIME_HIGH3; + if (Switch[3]=='-') + Mode=EXTTIME_NONE; + switch(toupperw(Switch[2])) + { + case 'M': + xmtime=Mode; + break; + case 'C': + xctime=Mode; + break; + case 'A': + xatime=Mode; + break; + } + } + } + break; + case '-': + Test=false; + break; + case 0: + Test=true; + break; + default: + BadSwitch(Switch); + break; + } + break; + case 'U': + if (Switch[1]==0) + UpdateFiles=true; + else + BadSwitch(Switch); + break; + case 'V': + switch(toupperw(Switch[1])) + { + case 'P': + VolumePause=true; + break; + case 'E': + if (toupperw(Switch[2])=='R') + VersionControl=atoiw(Switch+3)+1; + break; + case '-': + VolSize=0; + break; + default: + VolSize=VOLSIZE_AUTO; // UnRAR -v switch for list command. + break; + } + break; + case 'W': + wcsncpyz(TempPath,Switch+1,ASIZE(TempPath)); + AddEndSlash(TempPath,ASIZE(TempPath)); + break; + case 'Y': + AllYes=true; + break; + case 'Z': + if (Switch[1]==0) + { + // If comment file is not specified, we read data from stdin. + wcscpy(CommentFile,L"stdin"); + } + else + wcsncpyz(CommentFile,Switch+1,ASIZE(CommentFile)); + break; + case '?' : + OutHelp(RARX_SUCCESS); + break; + default : + BadSwitch(Switch); + break; + } +} +#endif + + +#if !defined(SFX_MODULE) +void CommandData::BadSwitch(const wchar *Switch) +{ + mprintf(St(MUnknownOption),Switch); + ErrHandler.Exit(RARX_USERERROR); +} +#endif + + +void CommandData::OutTitle() +{ + if (BareOutput || DisableCopyright) + return; +#if defined(__GNUC__) && defined(SFX_MODULE) + mprintf(St(MCopyrightS)); +#else +#ifndef SILENT + static bool TitleShown=false; + if (TitleShown) + return; + TitleShown=true; + + wchar Version[80]; + if (RARVER_BETA!=0) + swprintf(Version,ASIZE(Version),L"%d.%02d %ls %d",RARVER_MAJOR,RARVER_MINOR,St(MBeta),RARVER_BETA); + else + swprintf(Version,ASIZE(Version),L"%d.%02d",RARVER_MAJOR,RARVER_MINOR); +#if defined(_WIN_32) || defined(_WIN_64) + wcsncatz(Version,L" ",ASIZE(Version)); +#endif +#ifdef _WIN_32 + wcsncatz(Version,St(Mx86),ASIZE(Version)); +#endif +#ifdef _WIN_64 + wcsncatz(Version,St(Mx64),ASIZE(Version)); +#endif + if (PrintVersion) + { + mprintf(L"%s",Version); + exit(0); + } + mprintf(St(MUCopyright),Version,RARVER_YEAR); +#endif +#endif +} + + +inline bool CmpMSGID(MSGID i1,MSGID i2) +{ +#ifdef MSGID_INT + return i1==i2; +#else + // If MSGID is const char*, we cannot compare pointers only. + // Pointers to different instances of same string can differ, + // so we need to compare complete strings. + return wcscmp(i1,i2)==0; +#endif +} + +void CommandData::OutHelp(RAR_EXIT ExitCode) +{ +#if !defined(SILENT) + OutTitle(); + static MSGID Help[]={ +#ifdef SFX_MODULE + // Console SFX switches definition. + MCHelpCmd,MSHelpCmdE,MSHelpCmdT,MSHelpCmdV +#else + // UnRAR switches definition. + MUNRARTitle1,MRARTitle2,MCHelpCmd,MCHelpCmdE,MCHelpCmdL, + MCHelpCmdP,MCHelpCmdT,MCHelpCmdV,MCHelpCmdX,MCHelpSw,MCHelpSwm, + MCHelpSwAT,MCHelpSwAC,MCHelpSwAD,MCHelpSwAG,MCHelpSwAI,MCHelpSwAP, + MCHelpSwCm,MCHelpSwCFGm,MCHelpSwCL,MCHelpSwCU, + MCHelpSwDH,MCHelpSwEP,MCHelpSwEP3,MCHelpSwF,MCHelpSwIDP,MCHelpSwIERR, + MCHelpSwINUL,MCHelpSwIOFF,MCHelpSwKB,MCHelpSwN,MCHelpSwNa,MCHelpSwNal, + MCHelpSwO,MCHelpSwOC,MCHelpSwOL,MCHelpSwOR,MCHelpSwOW,MCHelpSwP, + MCHelpSwPm,MCHelpSwR,MCHelpSwRI,MCHelpSwSC,MCHelpSwSL,MCHelpSwSM, + MCHelpSwTA,MCHelpSwTB,MCHelpSwTN,MCHelpSwTO,MCHelpSwTS,MCHelpSwU, + MCHelpSwVUnr,MCHelpSwVER,MCHelpSwVP,MCHelpSwX,MCHelpSwXa,MCHelpSwXal, + MCHelpSwY +#endif + }; + + for (uint I=0;IRewind(); + while (Args->GetString(CurMask,ASIZE(CurMask))) + { + wchar *LastMaskChar=PointToLastChar(CurMask); + bool DirMask=IsPathDiv(*LastMaskChar); // Mask for directories only. + + if (Dir) + { + // CheckName is a directory. + if (DirMask) + { + // We process the directory and have the directory exclusion mask. + // So let's convert "mask\" to "mask" and process it normally. + + *LastMaskChar=0; + } + else + { + // REMOVED, we want -npath\* to match empty folders too. + // If mask has wildcards in name part and does not have the trailing + // '\' character, we cannot use it for directories. + + // if (IsWildcard(PointToName(CurMask))) + // continue; + } + } + else + { + // If we process a file inside of directory excluded by "dirmask\". + // we want to exclude such file too. So we convert "dirmask\" to + // "dirmask\*". It is important for operations other than archiving + // with -x. When archiving with -x, directory matched by "dirmask\" + // is excluded from further scanning. + + if (DirMask) + wcsncatz(CurMask,L"*",ASIZE(CurMask)); + } + +#ifndef SFX_MODULE + if (CheckFullPath && IsFullPath(CurMask)) + { + // We do not need to do the special "*\" processing here, because + // unlike the "else" part of this "if", now we convert names to full + // format, so they all include the path, which is matched by "*\" + // correctly. Moreover, removing "*\" from mask would break + // the comparison, because now all names have the path. + + if (*FullName==0) + ConvertNameToFull(CheckName,FullName,ASIZE(FullName)); + if (CmpName(CurMask,FullName,MatchMode)) + return true; + } + else +#endif + { + wchar NewName[NM+2],*CurName=Name; + + // Important to convert before "*\" check below, so masks like + // d:*\something are processed properly. + wchar *CmpMask=ConvertPath(CurMask,NULL); + + if (CmpMask[0]=='*' && IsPathDiv(CmpMask[1])) + { + // We want "*\name" to match 'name' not only in subdirectories, + // but also in the current directory. We convert the name + // from 'name' to '.\name' to be matched by "*\" part even if it is + // in current directory. + NewName[0]='.'; + NewName[1]=CPATHDIVIDER; + wcsncpyz(NewName+2,Name,ASIZE(NewName)-2); + CurName=NewName; + } + + if (CmpName(CmpMask,CurName,MatchMode)) + return true; + } + } + return false; +} + + +#ifndef SFX_MODULE +// Now this function performs only one task and only in Windows version: +// it skips symlinks to directories if -e1024 switch is specified. +// Symlinks are skipped in ScanTree class, so their entire contents +// is skipped too. Without this function we would check the attribute +// only directly before archiving, so we would skip the symlink record, +// but not the contents of symlinked directory. +bool CommandData::ExclDirByAttr(uint FileAttr) +{ +#ifdef _WIN_ALL + if ((FileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0 && + (ExclFileAttr & FILE_ATTRIBUTE_REPARSE_POINT)!=0) + return true; +#endif + return false; +} +#endif + + + + +#ifndef SFX_MODULE +// Return 'true' if we need to exclude the file from processing. +bool CommandData::TimeCheck(RarTime &ft) +{ + if (FileTimeBefore.IsSet() && ft>=FileTimeBefore) + return true; + if (FileTimeAfter.IsSet() && ft<=FileTimeAfter) + return true; + return false; +} +#endif + + +#ifndef SFX_MODULE +// Return 'true' if we need to exclude the file from processing. +bool CommandData::SizeCheck(int64 Size) +{ + if (FileSizeLess!=INT64NDF && Size>=FileSizeLess) + return(true); + if (FileSizeMore!=INT64NDF && Size<=FileSizeMore) + return(true); + return(false); +} +#endif + + + + +int CommandData::IsProcessFile(FileHeader &FileHead,bool *ExactMatch,int MatchType, + wchar *MatchedArg,uint MatchedArgSize) +{ + if (MatchedArg!=NULL && MatchedArgSize>0) + *MatchedArg=0; +// if (wcslen(FileHead.FileName)>=NM) +// return 0; + bool Dir=FileHead.Dir; + if (ExclCheck(FileHead.FileName,Dir,false,true)) + return 0; +#ifndef SFX_MODULE + if (TimeCheck(FileHead.mtime)) + return 0; + if ((FileHead.FileAttr & ExclFileAttr)!=0 || InclAttrSet && (FileHead.FileAttr & InclFileAttr)==0) + return 0; + if (!Dir && SizeCheck(FileHead.UnpSize)) + return 0; +#endif + wchar *ArgName; + FileArgs.Rewind(); + for (int StringCount=1;(ArgName=FileArgs.GetString())!=NULL;StringCount++) + if (CmpName(ArgName,FileHead.FileName,MatchType)) + { + if (ExactMatch!=NULL) + *ExactMatch=wcsicompc(ArgName,FileHead.FileName)==0; + if (MatchedArg!=NULL) + wcsncpyz(MatchedArg,ArgName,MatchedArgSize); + return StringCount; + } + return 0; +} + + +void CommandData::ProcessCommand() +{ +#ifndef SFX_MODULE + + const wchar *SingleCharCommands=L"FUADPXETK"; + if (Command[0]!=0 && Command[1]!=0 && wcschr(SingleCharCommands,Command[0])!=NULL || *ArcName==0) + OutHelp(*Command==0 ? RARX_SUCCESS:RARX_USERERROR); // Return 'success' for 'rar' without parameters. + + const wchar *ArcExt=GetExt(ArcName); +#ifdef _UNIX + if (ArcExt==NULL && (!FileExist(ArcName) || IsDir(GetFileAttr(ArcName)))) + wcsncatz(ArcName,L".rar",ASIZE(ArcName)); +#else + if (ArcExt==NULL) + wcsncatz(ArcName,L".rar",ASIZE(ArcName)); +#endif + // Treat arcname.part1 as arcname.part1.rar. + if (ArcExt!=NULL && wcsnicomp(ArcExt,L".part",5)==0 && IsDigit(ArcExt[5]) && + !FileExist(ArcName)) + { + wchar Name[NM]; + wcsncpyz(Name,ArcName,ASIZE(Name)); + wcsncatz(Name,L".rar",ASIZE(Name)); + if (FileExist(Name)) + wcsncpyz(ArcName,Name,ASIZE(ArcName)); + } + + if (wcschr(L"AFUMD",*Command)==NULL) + { + if (GenerateArcName) + GenerateArchiveName(ArcName,ASIZE(ArcName),GenerateMask,false); + + StringList ArcMasks; + ArcMasks.AddString(ArcName); + ScanTree Scan(&ArcMasks,Recurse,SaveSymLinks,SCAN_SKIPDIRS); + FindData FindData; + while (Scan.GetNext(&FindData)==SCAN_SUCCESS) + AddArcName(FindData.Name); + } + else + AddArcName(ArcName); +#endif + + switch(Command[0]) + { + case 'P': + case 'X': + case 'E': + case 'T': + case 'I': + { + CmdExtract Extract(this); + Extract.DoExtract(); + } + break; +#ifndef SILENT + case 'V': + case 'L': + ListArchive(this); + break; + default: + OutHelp(RARX_USERERROR); +#endif + } + if (!BareOutput) + mprintf(L"\n"); +} + + +void CommandData::AddArcName(const wchar *Name) +{ + ArcNames.AddString(Name); +} + + +bool CommandData::GetArcName(wchar *Name,int MaxSize) +{ + return ArcNames.GetString(Name,MaxSize); +} + + +bool CommandData::IsSwitch(int Ch) +{ +#if defined(_WIN_ALL) || defined(_EMX) + return Ch=='-' || Ch=='/'; +#else + return Ch=='-'; +#endif +} + + +#ifndef SFX_MODULE +uint CommandData::GetExclAttr(const wchar *Str) +{ + if (IsDigit(*Str)) + return wcstol(Str,NULL,0); + + uint Attr=0; + while (*Str!=0) + { + switch(toupperw(*Str)) + { +#ifdef _UNIX + case 'D': + Attr|=S_IFDIR; + break; + case 'V': + Attr|=S_IFCHR; + break; +#elif defined(_WIN_ALL) || defined(_EMX) + case 'R': + Attr|=0x1; + break; + case 'H': + Attr|=0x2; + break; + case 'S': + Attr|=0x4; + break; + case 'D': + Attr|=0x10; + break; + case 'A': + Attr|=0x20; + break; +#endif + } + Str++; + } + return Attr; +} +#endif + + + + +#ifndef SFX_MODULE +bool CommandData::CheckWinSize() +{ + // Define 0x100000000 as macro to avoid troubles with older compilers. + const uint64 MaxDictSize=INT32TO64(1,0); + // Limit the dictionary size to 4 GB. + for (uint64 I=0x10000;I<=MaxDictSize;I*=2) + if (WinSize==I) + return true; + WinSize=0x400000; + return false; +} +#endif + + +#ifndef SFX_MODULE +void CommandData::ReportWrongSwitches(RARFORMAT Format) +{ + if (Format==RARFMT15) + { + if (HashType!=HASH_CRC32) + uiMsg(UIERROR_INCOMPATSWITCH,L"-ht",4); +#ifdef _WIN_ALL + if (SaveSymLinks) + uiMsg(UIERROR_INCOMPATSWITCH,L"-ol",4); +#endif + if (SaveHardLinks) + uiMsg(UIERROR_INCOMPATSWITCH,L"-oh",4); + +#ifdef _WIN_ALL + // Do not report a wrong dictionary size here, because we are not sure + // yet about archive format. We can switch to RAR5 mode later + // if we update RAR5 archive. + + +#endif + if (QOpenMode!=QOPEN_AUTO) + uiMsg(UIERROR_INCOMPATSWITCH,L"-qo",4); + } + if (Format==RARFMT50) + { + } +} +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/cmddata.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/cmddata.hpp new file mode 100644 index 0000000..e12d4fb --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/cmddata.hpp @@ -0,0 +1,64 @@ +#ifndef _RAR_CMDDATA_ +#define _RAR_CMDDATA_ + + +#define DefaultStoreList L"7z;ace;arj;bz2;cab;gz;jpeg;jpg;lha;lz;lzh;mp3;rar;taz;tgz;xz;z;zip;zipx" + +enum RAR_CMD_LIST_MODE {RCLM_AUTO,RCLM_REJECT_LISTS,RCLM_ACCEPT_LISTS}; + +class CommandData:public RAROptions +{ + private: + void ProcessSwitchesString(const wchar *Str); + void ProcessSwitch(const wchar *Switch); + void BadSwitch(const wchar *Switch); + uint GetExclAttr(const wchar *Str); + + bool FileLists; + bool NoMoreSwitches; + RAR_CMD_LIST_MODE ListMode; + bool BareOutput; + public: + CommandData(); + void Init(); + + void ParseCommandLine(bool Preprocess,int argc, char *argv[]); + void ParseArg(wchar *ArgW); + void ParseDone(); + void ParseEnvVar(); + void ReadConfig(); + void PreprocessArg(const wchar *Arg); + void OutTitle(); + void OutHelp(RAR_EXIT ExitCode); + bool IsSwitch(int Ch); + bool ExclCheck(const wchar *CheckName,bool Dir,bool CheckFullPath,bool CheckInclList); + static bool CheckArgs(StringList *Args,bool Dir,const wchar *CheckName,bool CheckFullPath,int MatchMode); + bool ExclDirByAttr(uint FileAttr); + bool TimeCheck(RarTime &ft); + bool SizeCheck(int64 Size); + bool AnyFiltersActive(); + int IsProcessFile(FileHeader &FileHead,bool *ExactMatch=NULL,int MatchType=MATCH_WILDSUBPATH, + wchar *MatchedArg=NULL,uint MatchedArgSize=0); + void ProcessCommand(); + void AddArcName(const wchar *Name); + bool GetArcName(wchar *Name,int MaxSize); + bool CheckWinSize(); + + int GetRecoverySize(const wchar *Str,int DefSize); + +#ifndef SFX_MODULE + void ReportWrongSwitches(RARFORMAT Format); +#endif + + wchar Command[NM+16]; + + wchar ArcName[NM]; + + StringList FileArgs; + StringList ExclArgs; + StringList InclArgs; + StringList ArcNames; + StringList StoreArgs; +}; + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/coder.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/coder.cpp new file mode 100644 index 0000000..9d971a8 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/coder.cpp @@ -0,0 +1,48 @@ + + +inline unsigned int RangeCoder::GetChar() +{ + return(UnpackRead->GetChar()); +} + + +void RangeCoder::InitDecoder(Unpack *UnpackRead) +{ + RangeCoder::UnpackRead=UnpackRead; + + low=code=0; + range=uint(-1); + for (int i=0;i < 4;i++) + code=(code << 8) | GetChar(); +} + + +// (int) cast before "low" added only to suppress compiler warnings. +#define ARI_DEC_NORMALIZE(code,low,range,read) \ +{ \ + while ((low^(low+range))GetChar(); \ + range <<= 8; \ + low <<= 8; \ + } \ +} + + +inline int RangeCoder::GetCurrentCount() +{ + return (code-low)/(range /= SubRange.scale); +} + + +inline uint RangeCoder::GetCurrentShiftCount(uint SHIFT) +{ + return (code-low)/(range >>= SHIFT); +} + + +inline void RangeCoder::Decode() +{ + low += range*SubRange.LowCount; + range *= SubRange.HighCount-SubRange.LowCount; +} diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/coder.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/coder.hpp new file mode 100644 index 0000000..7b36ff2 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/coder.hpp @@ -0,0 +1,23 @@ +/**************************************************************************** + * Contents: 'Carryless rangecoder' by Dmitry Subbotin * + ****************************************************************************/ + + +class RangeCoder +{ + public: + void InitDecoder(Unpack *UnpackRead); + inline int GetCurrentCount(); + inline uint GetCurrentShiftCount(uint SHIFT); + inline void Decode(); + inline void PutChar(unsigned int c); + inline unsigned int GetChar(); + + uint low, code, range; + struct SUBRANGE + { + uint LowCount, HighCount, scale; + } SubRange; + + Unpack *UnpackRead; +}; diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/compress.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/compress.hpp new file mode 100644 index 0000000..73f7ee4 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/compress.hpp @@ -0,0 +1,59 @@ +#ifndef _RAR_COMPRESS_ +#define _RAR_COMPRESS_ + +// Combine pack and unpack constants to class to avoid polluting global +// namespace with numerous short names. +class PackDef +{ + public: + // Maximum LZ match length we can encode even for short distances. + static const uint MAX_LZ_MATCH = 0x1001; + + // We increment LZ match length for longer distances, because shortest + // matches are not allowed for them. Maximum length increment is 3 + // for distances larger than 256KB (0x40000). Here we define the maximum + // incremented LZ match. Normally packer does not use it, but we must be + // ready to process it in corrupt archives. + static const uint MAX_INC_LZ_MATCH = MAX_LZ_MATCH + 3; + + static const uint MAX3_LZ_MATCH = 0x101; // Maximum match length for RAR v3. + static const uint LOW_DIST_REP_COUNT = 16; + + static const uint NC = 306; /* alphabet = {0, 1, 2, ..., NC - 1} */ + static const uint DC = 64; + static const uint LDC = 16; + static const uint RC = 44; + static const uint HUFF_TABLE_SIZE = NC + DC + RC + LDC; + static const uint BC = 20; + + static const uint NC30 = 299; /* alphabet = {0, 1, 2, ..., NC - 1} */ + static const uint DC30 = 60; + static const uint LDC30 = 17; + static const uint RC30 = 28; + static const uint BC30 = 20; + static const uint HUFF_TABLE_SIZE30 = NC30 + DC30 + RC30 + LDC30; + + static const uint NC20 = 298; /* alphabet = {0, 1, 2, ..., NC - 1} */ + static const uint DC20 = 48; + static const uint RC20 = 28; + static const uint BC20 = 19; + static const uint MC20 = 257; + + // Largest alphabet size among all values listed above. + static const uint LARGEST_TABLE_SIZE = 306; + + enum { + CODE_HUFFMAN, CODE_LZ, CODE_REPEATLZ, CODE_CACHELZ, CODE_STARTFILE, + CODE_ENDFILE, CODE_FILTER, CODE_FILTERDATA + }; +}; + + +enum FilterType { + // These values must not be changed, because we use them directly + // in RAR5 compression and decompression code. + FILTER_DELTA=0, FILTER_E8, FILTER_E8E9, FILTER_ARM, + FILTER_AUDIO, FILTER_RGB, FILTER_ITANIUM, FILTER_PPM, FILTER_NONE +}; + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/consio.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/consio.cpp new file mode 100644 index 0000000..196066e --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/consio.cpp @@ -0,0 +1,357 @@ +#include "rar.hpp" +#include "log.cpp" + +static MESSAGE_TYPE MsgStream=MSG_STDOUT; +static RAR_CHARSET RedirectCharset=RCH_DEFAULT; + +const int MaxMsgSize=2*NM+2048; + +static bool StdoutRedirected=false,StderrRedirected=false,StdinRedirected=false; + +#ifdef _WIN_ALL +static bool IsRedirected(DWORD nStdHandle) +{ + HANDLE hStd=GetStdHandle(nStdHandle); + DWORD Mode; + return GetFileType(hStd)!=FILE_TYPE_CHAR || GetConsoleMode(hStd,&Mode)==0; +} +#endif + + +void InitConsole() +{ +#ifdef _WIN_ALL + // We want messages like file names or progress percent to be printed + // immediately. Use only in Windows, in Unix they can cause wprintf %ls + // to fail with non-English strings. + setbuf(stdout,NULL); + setbuf(stderr,NULL); + + // Detect if output is redirected and set output mode properly. + // We do not want to send Unicode output to files and especially to pipes + // like '|more', which cannot handle them correctly in Windows. + // In Unix console output is UTF-8 and it is handled correctly + // when redirecting, so no need to perform any adjustments. + StdoutRedirected=IsRedirected(STD_OUTPUT_HANDLE); + StderrRedirected=IsRedirected(STD_ERROR_HANDLE); + StdinRedirected=IsRedirected(STD_INPUT_HANDLE); +#ifdef _MSC_VER + if (!StdoutRedirected) + _setmode(_fileno(stdout), _O_U16TEXT); + if (!StderrRedirected) + _setmode(_fileno(stderr), _O_U16TEXT); +#endif +#elif defined(_UNIX) + StdoutRedirected=!isatty(fileno(stdout)); + StderrRedirected=!isatty(fileno(stderr)); + StdinRedirected=!isatty(fileno(stdin)); +#endif +} + + +void SetConsoleMsgStream(MESSAGE_TYPE MsgStream) +{ + ::MsgStream=MsgStream; +} + + +void SetConsoleRedirectCharset(RAR_CHARSET RedirectCharset) +{ + ::RedirectCharset=RedirectCharset; +} + + +#ifndef SILENT +static void cvt_wprintf(FILE *dest,const wchar *fmt,va_list arglist) +{ + // This buffer is for format string only, not for entire output, + // so it can be short enough. + wchar fmtw[1024]; + PrintfPrepareFmt(fmt,fmtw,ASIZE(fmtw)); +#ifdef _WIN_ALL + safebuf wchar Msg[MaxMsgSize]; + if (dest==stdout && StdoutRedirected || dest==stderr && StderrRedirected) + { + HANDLE hOut=GetStdHandle(dest==stdout ? STD_OUTPUT_HANDLE:STD_ERROR_HANDLE); + vswprintf(Msg,ASIZE(Msg),fmtw,arglist); + DWORD Written; + if (RedirectCharset==RCH_UNICODE) + WriteFile(hOut,Msg,(DWORD)wcslen(Msg)*sizeof(*Msg),&Written,NULL); + else + { + // Avoid Unicode for redirect in Windows, it does not work with pipes. + safebuf char MsgA[MaxMsgSize]; + if (RedirectCharset==RCH_UTF8) + WideToUtf(Msg,MsgA,ASIZE(MsgA)); + else + WideToChar(Msg,MsgA,ASIZE(MsgA)); + if (RedirectCharset==RCH_DEFAULT || RedirectCharset==RCH_OEM) + CharToOemA(MsgA,MsgA); // Console tools like 'more' expect OEM encoding. + + // We already converted \n to \r\n above, so we use WriteFile instead + // of C library to avoid unnecessary additional conversion. + WriteFile(hOut,MsgA,(DWORD)strlen(MsgA),&Written,NULL); + } + return; + } + // MSVC2008 vfwprintf writes every character to console separately + // and it is too slow. We use direct WriteConsole call instead. + vswprintf(Msg,ASIZE(Msg),fmtw,arglist); + HANDLE hOut=GetStdHandle(dest==stderr ? STD_ERROR_HANDLE:STD_OUTPUT_HANDLE); + DWORD Written; + WriteConsole(hOut,Msg,(DWORD)wcslen(Msg),&Written,NULL); +#else + vfwprintf(dest,fmtw,arglist); + // We do not use setbuf(NULL) in Unix (see comments in InitConsole). + fflush(dest); +#endif +} + + +void mprintf(const wchar *fmt,...) +{ + if (MsgStream==MSG_NULL || MsgStream==MSG_ERRONLY) + return; + + fflush(stderr); // Ensure proper message order. + + va_list arglist; + va_start(arglist,fmt); + FILE *dest=MsgStream==MSG_STDERR ? stderr:stdout; + cvt_wprintf(dest,fmt,arglist); + va_end(arglist); +} +#endif + + +#ifndef SILENT +void eprintf(const wchar *fmt,...) +{ + if (MsgStream==MSG_NULL) + return; + + fflush(stdout); // Ensure proper message order. + + va_list arglist; + va_start(arglist,fmt); + cvt_wprintf(stderr,fmt,arglist); + va_end(arglist); +} +#endif + + +#ifndef SILENT +static void GetPasswordText(wchar *Str,uint MaxLength) +{ + if (MaxLength==0) + return; + if (StdinRedirected) + getwstr(Str,MaxLength); // Read from pipe or redirected file. + else + { +#ifdef _WIN_ALL + HANDLE hConIn=GetStdHandle(STD_INPUT_HANDLE); + HANDLE hConOut=GetStdHandle(STD_OUTPUT_HANDLE); + DWORD ConInMode,ConOutMode; + DWORD Read=0; + GetConsoleMode(hConIn,&ConInMode); + GetConsoleMode(hConOut,&ConOutMode); + SetConsoleMode(hConIn,ENABLE_LINE_INPUT); + SetConsoleMode(hConOut,ENABLE_PROCESSED_OUTPUT|ENABLE_WRAP_AT_EOL_OUTPUT); + + ReadConsole(hConIn,Str,MaxLength-1,&Read,NULL); + Str[Read]=0; + SetConsoleMode(hConIn,ConInMode); + SetConsoleMode(hConOut,ConOutMode); +#else + char StrA[MAXPASSWORD]; +#if defined(_EMX) || defined (__VMS) + fgets(StrA,ASIZE(StrA)-1,stdin); +#elif defined(__sun) + strncpyz(StrA,getpassphrase(""),ASIZE(StrA)); +#else + strncpyz(StrA,getpass(""),ASIZE(StrA)); +#endif + CharToWide(StrA,Str,MaxLength); + cleandata(StrA,sizeof(StrA)); +#endif + } + Str[MaxLength-1]=0; + RemoveLF(Str); +} +#endif + + +#ifndef SILENT +bool GetConsolePassword(UIPASSWORD_TYPE Type,const wchar *FileName,SecPassword *Password) +{ + if (!StdinRedirected) + uiAlarm(UIALARM_QUESTION); + + while (true) + { + if (!StdinRedirected) + if (Type==UIPASSWORD_GLOBAL) + eprintf(L"\n%s: ",St(MAskPsw)); + else + eprintf(St(MAskPswFor),FileName); + + wchar PlainPsw[MAXPASSWORD]; + GetPasswordText(PlainPsw,ASIZE(PlainPsw)); + if (*PlainPsw==0 && Type==UIPASSWORD_GLOBAL) + return false; + if (!StdinRedirected && Type==UIPASSWORD_GLOBAL) + { + eprintf(St(MReAskPsw)); + wchar CmpStr[MAXPASSWORD]; + GetPasswordText(CmpStr,ASIZE(CmpStr)); + if (*CmpStr==0 || wcscmp(PlainPsw,CmpStr)!=0) + { + eprintf(St(MNotMatchPsw)); + cleandata(PlainPsw,sizeof(PlainPsw)); + cleandata(CmpStr,sizeof(CmpStr)); + continue; + } + cleandata(CmpStr,sizeof(CmpStr)); + } + Password->Set(PlainPsw); + cleandata(PlainPsw,sizeof(PlainPsw)); + break; + } + return true; +} +#endif + + +#ifndef SILENT +bool getwstr(wchar *str,size_t n) +{ + // Print buffered prompt title function before waiting for input. + fflush(stderr); + + *str=0; +#if defined(_WIN_ALL) + // fgetws does not work well with non-English text in Windows, + // so we do not use it. + if (StdinRedirected) // ReadConsole does not work if redirected. + { + // fgets does not work well with pipes in Windows in our test. + // Let's use files. + Array StrA(n*4); // Up to 4 UTF-8 characters per wchar_t. + File SrcFile; + SrcFile.SetHandleType(FILE_HANDLESTD); + int ReadSize=SrcFile.Read(&StrA[0],StrA.Size()-1); + if (ReadSize<=0) + { + // Looks like stdin is a null device. We can enter to infinite loop + // calling Ask(), so let's better exit. + ErrHandler.Exit(RARX_USERBREAK); + } + StrA[ReadSize]=0; + CharToWide(&StrA[0],str,n); + cleandata(&StrA[0],StrA.Size()); // We can use this function to enter passwords. + } + else + { + DWORD ReadSize=0; + if (ReadConsole(GetStdHandle(STD_INPUT_HANDLE),str,DWORD(n-1),&ReadSize,NULL)==0) + return false; + str[ReadSize]=0; + } +#else + if (fgetws(str,n,stdin)==NULL) + ErrHandler.Exit(RARX_USERBREAK); // Avoid infinite Ask() loop. +#endif + RemoveLF(str); + return true; +} +#endif + + +#ifndef SILENT +// We allow this function to return 0 in case of invalid input, +// because it might be convenient to press Enter to some not dangerous +// prompts like "insert disk with next volume". We should call this function +// again in case of 0 in dangerous prompt such as overwriting file. +int Ask(const wchar *AskStr) +{ + uiAlarm(UIALARM_QUESTION); + + const int MaxItems=10; + wchar Item[MaxItems][40]; + int ItemKeyPos[MaxItems],NumItems=0; + + for (const wchar *NextItem=AskStr;NextItem!=NULL;NextItem=wcschr(NextItem+1,'_')) + { + wchar *CurItem=Item[NumItems]; + wcsncpyz(CurItem,NextItem+1,ASIZE(Item[0])); + wchar *EndItem=wcschr(CurItem,'_'); + if (EndItem!=NULL) + *EndItem=0; + int KeyPos=0,CurKey; + while ((CurKey=CurItem[KeyPos])!=0) + { + bool Found=false; + for (int I=0;I4 ? L"\n":L" "):L", "); + int KeyPos=ItemKeyPos[I]; + for (int J=0;J[{key};"{string}"p used to redefine + // a keyboard key on some terminals. + if (Data[J]=='\"') + return true; + if (!IsDigit(Data[J]) && Data[J]!=';') + break; + } + return false; +} + + +void OutComment(const wchar *Comment,size_t Size) +{ + if (IsCommentUnsafe(Comment,Size)) + return; + const size_t MaxOutSize=0x400; + for (size_t I=0;I>1)^0xEDB88320 : (C>>1); + CRCTab[I]=C; + } +} + + +static void InitTables() +{ + InitCRC32(crc_tables[0]); + + for (uint I=0;I<256;I++) // Build additional lookup tables. + { + uint C=crc_tables[0][I]; + for (uint J=1;J<8;J++) + { + C=crc_tables[0][(byte)C]^(C>>8); + crc_tables[J][I]=C; + } + } +} + + +struct CallInitCRC {CallInitCRC() {InitTables();}} static CallInit32; + +uint CRC32(uint StartCRC,const void *Addr,size_t Size) +{ + byte *Data=(byte *)Addr; + + // Align Data to 8 for better performance. + for (;Size>0 && ((size_t)Data & 7);Size--,Data++) + StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8); + + for (;Size>=8;Size-=8,Data+=8) + { +#ifdef BIG_ENDIAN + StartCRC ^= Data[0]|(Data[1] << 8)|(Data[2] << 16)|(Data[3] << 24); + uint NextData = Data[4]|(Data[5] << 8)|(Data[6] << 16)|(Data[7] << 24); +#else + StartCRC ^= *(uint32 *) Data; + uint NextData = *(uint32 *) (Data+4); +#endif + StartCRC = crc_tables[7][(byte) StartCRC ] ^ + crc_tables[6][(byte)(StartCRC >> 8) ] ^ + crc_tables[5][(byte)(StartCRC >> 16)] ^ + crc_tables[4][(byte)(StartCRC >> 24)] ^ + crc_tables[3][(byte) NextData ] ^ + crc_tables[2][(byte)(NextData >>8 ) ] ^ + crc_tables[1][(byte)(NextData >> 16)] ^ + crc_tables[0][(byte)(NextData >> 24)]; + } + + for (;Size>0;Size--,Data++) // Process left data. + StartCRC=crc_tables[0][(byte)(StartCRC^Data[0])]^(StartCRC>>8); + + return StartCRC; +} + + +#ifndef SFX_MODULE +// For RAR 1.4 archives in case somebody still has them. +ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size) +{ + byte *Data=(byte *)Addr; + for (size_t I=0;I>15))&0xffff; + } + return StartCRC; +} +#endif + + diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/crc.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/crc.hpp new file mode 100644 index 0000000..d8fea28 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/crc.hpp @@ -0,0 +1,15 @@ +#ifndef _RAR_CRC_ +#define _RAR_CRC_ + +// This function is only to intialize external CRC tables. We do not need to +// call it before calculating CRC32. +void InitCRC32(uint *CRCTab); + +uint CRC32(uint StartCRC,const void *Addr,size_t Size); + +#ifndef SFX_MODULE +ushort Checksum14(ushort StartCRC,const void *Addr,size_t Size); +#endif + + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/crypt.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/crypt.cpp new file mode 100644 index 0000000..fc2126d --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/crypt.cpp @@ -0,0 +1,134 @@ +#include "rar.hpp" + +#ifndef SFX_MODULE +#include "crypt1.cpp" +#include "crypt2.cpp" +#endif +#include "crypt3.cpp" +#include "crypt5.cpp" + + +CryptData::CryptData() +{ + Method=CRYPT_NONE; + memset(KDF3Cache,0,sizeof(KDF3Cache)); + memset(KDF5Cache,0,sizeof(KDF5Cache)); + KDF3CachePos=0; + KDF5CachePos=0; + memset(CRCTab,0,sizeof(CRCTab)); +} + + +CryptData::~CryptData() +{ + cleandata(KDF3Cache,sizeof(KDF3Cache)); + cleandata(KDF5Cache,sizeof(KDF5Cache)); +} + + + + +void CryptData::DecryptBlock(byte *Buf,size_t Size) +{ + switch(Method) + { +#ifndef SFX_MODULE + case CRYPT_RAR13: + Decrypt13(Buf,Size); + break; + case CRYPT_RAR15: + Crypt15(Buf,Size); + break; + case CRYPT_RAR20: + for (size_t I=0;IIsSet() || Method==CRYPT_NONE) + return false; + + CryptData::Method=Method; + + wchar PwdW[MAXPASSWORD]; + Password->Get(PwdW,ASIZE(PwdW)); + char PwdA[MAXPASSWORD]; + WideToChar(PwdW,PwdA,ASIZE(PwdA)); + + switch(Method) + { +#ifndef SFX_MODULE + case CRYPT_RAR13: + SetKey13(PwdA); + break; + case CRYPT_RAR15: + SetKey15(PwdA); + break; + case CRYPT_RAR20: + SetKey20(PwdA); + break; +#endif + case CRYPT_RAR30: + SetKey30(Encrypt,Password,PwdW,Salt); + break; + case CRYPT_RAR50: + SetKey50(Encrypt,Password,PwdW,Salt,InitV,Lg2Cnt,HashKey,PswCheck); + break; + } + cleandata(PwdA,sizeof(PwdA)); + cleandata(PwdW,sizeof(PwdW)); + return true; +} + + +// Use the current system time to additionally randomize data. +static void TimeRandomize(byte *RndBuf,size_t BufSize) +{ + static uint Count=0; + RarTime CurTime; + CurTime.SetCurrentTime(); + uint64 Random=CurTime.GetWin()+clock(); + for (size_t I=0;I> ( (I & 7) * 8 )); + RndBuf[I]=byte( (RndByte ^ I) + Count++); + } +} + + + + +// Fill buffer with random data. +void GetRnd(byte *RndBuf,size_t BufSize) +{ + bool Success=false; +#if defined(_WIN_ALL) + HCRYPTPROV hProvider = 0; + if (CryptAcquireContext(&hProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) + { + Success=CryptGenRandom(hProvider, (DWORD)BufSize, RndBuf) == TRUE; + CryptReleaseContext(hProvider, 0); + } +#elif defined(_UNIX) + FILE *rndf = fopen("/dev/urandom", "r"); + if (rndf!=NULL) + { + Success=fread(RndBuf, BufSize, 1, rndf) == BufSize; + fclose(rndf); + } +#endif + // We use this code only as the last resort if code above failed. + if (!Success) + TimeRandomize(RndBuf,BufSize); +} diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/crypt.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/crypt.hpp new file mode 100644 index 0000000..f6382ef --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/crypt.hpp @@ -0,0 +1,101 @@ +#ifndef _RAR_CRYPT_ +#define _RAR_CRYPT_ + + +enum CRYPT_METHOD { + CRYPT_NONE,CRYPT_RAR13,CRYPT_RAR15,CRYPT_RAR20,CRYPT_RAR30,CRYPT_RAR50 +}; + +#define SIZE_SALT50 16 +#define SIZE_SALT30 8 +#define SIZE_INITV 16 +#define SIZE_PSWCHECK 8 +#define SIZE_PSWCHECK_CSUM 4 + +#define CRYPT_BLOCK_SIZE 16 +#define CRYPT_BLOCK_MASK (CRYPT_BLOCK_SIZE-1) // 0xf + +#define CRYPT5_KDF_LG2_COUNT 15 // LOG2 of PDKDF2 iteration count. +#define CRYPT5_KDF_LG2_COUNT_MAX 24 // LOG2 of maximum accepted iteration count. +#define CRYPT_VERSION 0 // Supported encryption version. + + +class CryptData +{ + struct KDF5CacheItem + { + SecPassword Pwd; + byte Salt[SIZE_SALT50]; + byte Key[32]; + uint Lg2Count; // Log2 of PBKDF2 repetition count. + byte PswCheckValue[SHA256_DIGEST_SIZE]; + byte HashKeyValue[SHA256_DIGEST_SIZE]; + }; + + struct KDF3CacheItem + { + SecPassword Pwd; + byte Salt[SIZE_SALT30]; + byte Key[16]; + byte Init[16]; + bool SaltPresent; + }; + + + private: + void SetKey13(const char *Password); + void Decrypt13(byte *Data,size_t Count); + + void SetKey15(const char *Password); + void Crypt15(byte *Data,size_t Count); + + void SetKey20(const char *Password); + void Swap20(byte *Ch1,byte *Ch2); + void UpdKeys20(byte *Buf); + void EncryptBlock20(byte *Buf); + void DecryptBlock20(byte *Buf); + + void SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt); + void SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey,byte *PswCheck); + + KDF3CacheItem KDF3Cache[4]; + uint KDF3CachePos; + + KDF5CacheItem KDF5Cache[4]; + uint KDF5CachePos; + + CRYPT_METHOD Method; + + Rijndael rin; + + uint CRCTab[256]; // For RAR 1.5 and RAR 2.0 encryption. + + byte SubstTable20[256]; + uint Key20[4]; + + byte Key13[3]; + ushort Key15[4]; + public: + CryptData(); + ~CryptData(); + bool SetCryptKeys(bool Encrypt,CRYPT_METHOD Method,SecPassword *Password, + const byte *Salt,const byte *InitV,uint Lg2Cnt, + byte *HashKey,byte *PswCheck); + void SetAV15Encryption(); + void SetCmt13Encryption(); + void EncryptBlock(byte *Buf,size_t Size); + void DecryptBlock(byte *Buf,size_t Size); + static void SetSalt(byte *Salt,size_t SaltSize); +}; + +void GetRnd(byte *RndBuf,size_t BufSize); + +void hmac_sha256(const byte *Key,size_t KeyLength,const byte *Data, + size_t DataLength,byte *ResDigest); +void pbkdf2(const byte *pass, size_t pass_len, const byte *salt, + size_t salt_len,byte *key, byte *Value1, byte *Value2, + uint rounds); + +void ConvertHashToMAC(HashValue *Value,byte *Key); + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/crypt1.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/crypt1.cpp new file mode 100644 index 0000000..1426393 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/crypt1.cpp @@ -0,0 +1,79 @@ +extern uint CRCTab[256]; + +void CryptData::SetKey13(const char *Password) +{ + Key13[0]=Key13[1]=Key13[2]=0; + for (size_t I=0;Password[I]!=0;I++) + { + byte P=Password[I]; + Key13[0]+=P; + Key13[1]^=P; + Key13[2]+=P; + Key13[2]=(byte)rotls(Key13[2],1,8); + } +} + + +void CryptData::SetKey15(const char *Password) +{ + InitCRC32(CRCTab); + uint PswCRC=CRC32(0xffffffff,Password,strlen(Password)); + Key15[0]=PswCRC&0xffff; + Key15[1]=(PswCRC>>16)&0xffff; + Key15[2]=Key15[3]=0; + for (size_t I=0;Password[I]!=0;I++) + { + byte P=Password[I]; + Key15[2]^=P^CRCTab[P]; + Key15[3]+=P+(CRCTab[P]>>16); + } +} + + +void CryptData::SetAV15Encryption() +{ + InitCRC32(CRCTab); + Method=CRYPT_RAR15; + Key15[0]=0x4765; + Key15[1]=0x9021; + Key15[2]=0x7382; + Key15[3]=0x5215; +} + + +void CryptData::SetCmt13Encryption() +{ + Method=CRYPT_RAR13; + Key13[0]=0; + Key13[1]=7; + Key13[2]=77; +} + + +void CryptData::Decrypt13(byte *Data,size_t Count) +{ + while (Count--) + { + Key13[1]+=Key13[2]; + Key13[0]+=Key13[1]; + *Data-=Key13[0]; + Data++; + } +} + + +void CryptData::Crypt15(byte *Data,size_t Count) +{ + while (Count--) + { + Key15[0]+=0x1234; + Key15[1]^=CRCTab[(Key15[0] & 0x1fe)>>1]; + Key15[2]-=CRCTab[(Key15[0] & 0x1fe)>>1]>>16; + Key15[0]^=Key15[2]; + Key15[3]=rotrs(Key15[3]&0xffff,1,16)^Key15[1]; + Key15[3]=rotrs(Key15[3]&0xffff,1,16); + Key15[0]^=Key15[3]; + *Data^=(byte)(Key15[0]>>8); + Data++; + } +} diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/crypt2.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/crypt2.cpp new file mode 100644 index 0000000..5fa4a97 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/crypt2.cpp @@ -0,0 +1,133 @@ +#define NROUNDS 32 + +#define substLong(t) ( (uint)SubstTable20[(uint)t&255] | \ + ((uint)SubstTable20[(int)(t>> 8)&255]<< 8) | \ + ((uint)SubstTable20[(int)(t>>16)&255]<<16) | \ + ((uint)SubstTable20[(int)(t>>24)&255]<<24) ) + + +static byte InitSubstTable20[256]={ + 215, 19,149, 35, 73,197,192,205,249, 28, 16,119, 48,221, 2, 42, + 232, 1,177,233, 14, 88,219, 25,223,195,244, 90, 87,239,153,137, + 255,199,147, 70, 92, 66,246, 13,216, 40, 62, 29,217,230, 86, 6, + 71, 24,171,196,101,113,218,123, 93, 91,163,178,202, 67, 44,235, + 107,250, 75,234, 49,167,125,211, 83,114,157,144, 32,193,143, 36, + 158,124,247,187, 89,214,141, 47,121,228, 61,130,213,194,174,251, + 97,110, 54,229,115, 57,152, 94,105,243,212, 55,209,245, 63, 11, + 164,200, 31,156, 81,176,227, 21, 76, 99,139,188,127, 17,248, 51, + 207,120,189,210, 8,226, 41, 72,183,203,135,165,166, 60, 98, 7, + 122, 38,155,170, 69,172,252,238, 39,134, 59,128,236, 27,240, 80, + 131, 3, 85,206,145, 79,154,142,159,220,201,133, 74, 64, 20,129, + 224,185,138,103,173,182, 43, 34,254, 82,198,151,231,180, 58, 10, + 118, 26,102, 12, 50,132, 22,191,136,111,162,179, 45, 4,148,108, + 161, 56, 78,126,242,222, 15,175,146, 23, 33,241,181,190, 77,225, + 0, 46,169,186, 68, 95,237, 65, 53,208,253,168, 9, 18,100, 52, + 116,184,160, 96,109, 37, 30,106,140,104,150, 5,204,117,112, 84 +}; + + +void CryptData::SetKey20(const char *Password) +{ + InitCRC32(CRCTab); + + char Psw[MAXPASSWORD]; + strncpyz(Psw,Password,ASIZE(Psw)); // We'll need to modify it below. + size_t PswLength=strlen(Psw); + + Key20[0]=0xD3A3B879L; + Key20[1]=0x3F6D12F7L; + Key20[2]=0x7515A235L; + Key20[3]=0xA4E7F123L; + + memcpy(SubstTable20,InitSubstTable20,sizeof(SubstTable20)); + for (uint J=0;J<256;J++) + for (size_t I=0;I=0;I--) + { + T=((C+rotls(D,11,32))^Key20[I&3]); + TA=A^substLong(T); + T=((D^rotls(C,17,32))+Key20[I&3]); + TB=B^substLong(T); + A=C; + B=D; + C=TA; + D=TB; + } + RawPut4(C^Key20[0],Buf+0); + RawPut4(D^Key20[1],Buf+4); + RawPut4(A^Key20[2],Buf+8); + RawPut4(B^Key20[3],Buf+12); + UpdKeys20(InBuf); +} + + +void CryptData::UpdKeys20(byte *Buf) +{ + for (int I=0;I<16;I+=4) + { + Key20[0]^=CRCTab[Buf[I]]; + Key20[1]^=CRCTab[Buf[I+1]]; + Key20[2]^=CRCTab[Buf[I+2]]; + Key20[3]^=CRCTab[Buf[I+3]]; + } +} + + +void CryptData::Swap20(byte *Ch1,byte *Ch2) +{ + byte Ch=*Ch1; + *Ch1=*Ch2; + *Ch2=Ch; +} diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/crypt3.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/crypt3.cpp new file mode 100644 index 0000000..4840648 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/crypt3.cpp @@ -0,0 +1,68 @@ +void CryptData::SetKey30(bool Encrypt,SecPassword *Password,const wchar *PwdW,const byte *Salt) +{ + byte AESKey[16],AESInit[16]; + + bool Cached=false; + for (uint I=0;I>8); + PswNum[2]=(byte)(I>>16); + sha1_process(&c, PswNum, 3); + if (I%(HashRounds/16)==0) + { + sha1_context tempc=c; + uint32 digest[5]; + sha1_done( &tempc, digest ); + AESInit[I/(HashRounds/16)]=(byte)digest[4]; + } + } + uint32 digest[5]; + sha1_done( &c, digest ); + for (int I=0;I<4;I++) + for (int J=0;J<4;J++) + AESKey[I*4+J]=(byte)(digest[I]>>(J*8)); + + KDF3Cache[KDF3CachePos].Pwd=*Password; + if ((KDF3Cache[KDF3CachePos].SaltPresent=(Salt!=NULL))==true) + memcpy(KDF3Cache[KDF3CachePos].Salt,Salt,SIZE_SALT30); + memcpy(KDF3Cache[KDF3CachePos].Key,AESKey,sizeof(AESKey)); + SecHideData(KDF3Cache[KDF3CachePos].Key,sizeof(KDF3Cache[KDF3CachePos].Key),true,false); + memcpy(KDF3Cache[KDF3CachePos].Init,AESInit,sizeof(AESInit)); + KDF3CachePos=(KDF3CachePos+1)%ASIZE(KDF3Cache); + + cleandata(RawPsw,sizeof(RawPsw)); + } + rin.Init(Encrypt, AESKey, 128, AESInit); + cleandata(AESKey,sizeof(AESKey)); + cleandata(AESInit,sizeof(AESInit)); +} + diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/crypt5.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/crypt5.cpp new file mode 100644 index 0000000..7562469 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/crypt5.cpp @@ -0,0 +1,233 @@ +static void hmac_sha256(const byte *Key,size_t KeyLength,const byte *Data, + size_t DataLength,byte *ResDigest, + sha256_context *ICtxOpt,bool *SetIOpt, + sha256_context *RCtxOpt,bool *SetROpt) +{ + const size_t Sha256BlockSize=64; // As defined in RFC 4868. + + byte KeyHash[SHA256_DIGEST_SIZE]; + if (KeyLength > Sha256BlockSize) // Convert longer keys to key hash. + { + sha256_context KCtx; + sha256_init(&KCtx); + sha256_process(&KCtx, Key, KeyLength); + sha256_done(&KCtx, KeyHash); + + Key = KeyHash; + KeyLength = SHA256_DIGEST_SIZE; + } + + byte KeyBuf[Sha256BlockSize]; // Store the padded key here. + sha256_context ICtx; + + if (ICtxOpt!=NULL && *SetIOpt) + ICtx=*ICtxOpt; // Use already calculated first block context. + else + { + // This calculation is the same for all iterations with same password. + // So for PBKDF2 we can calculate it only for first block and then reuse + // to improve performance. + + for (size_t I = 0; I < KeyLength; I++) // Use 0x36 padding for inner digest. + KeyBuf[I] = Key[I] ^ 0x36; + for (size_t I = KeyLength; I < Sha256BlockSize; I++) + KeyBuf[I] = 0x36; + + sha256_init(&ICtx); + sha256_process(&ICtx, KeyBuf, Sha256BlockSize); // Hash padded key. + } + + if (ICtxOpt!=NULL && !*SetIOpt) // Store constant context for further reuse. + { + *ICtxOpt=ICtx; + *SetIOpt=true; + } + + sha256_process(&ICtx, Data, DataLength); // Hash data. + + byte IDig[SHA256_DIGEST_SIZE]; // Internal digest for padded key and data. + sha256_done(&ICtx, IDig); + + sha256_context RCtx; + + if (RCtxOpt!=NULL && *SetROpt) + RCtx=*RCtxOpt; // Use already calculated first block context. + else + { + // This calculation is the same for all iterations with same password. + // So for PBKDF2 we can calculate it only for first block and then reuse + // to improve performance. + + for (size_t I = 0; I < KeyLength; I++) // Use 0x5c for outer key padding. + KeyBuf[I] = Key[I] ^ 0x5c; + for (size_t I = KeyLength; I < Sha256BlockSize; I++) + KeyBuf[I] = 0x5c; + + sha256_init(&RCtx); + sha256_process(&RCtx, KeyBuf, Sha256BlockSize); // Hash padded key. + } + + if (RCtxOpt!=NULL && !*SetROpt) // Store constant context for further reuse. + { + *RCtxOpt=RCtx; + *SetROpt=true; + } + + sha256_process(&RCtx, IDig, SHA256_DIGEST_SIZE); // Hash internal digest. + + sha256_done(&RCtx, ResDigest); +} + + +// PBKDF2 for 32 byte key length. We generate the key for specified number +// of iteration count also as two supplementary values (key for checksums +// and password verification) for iterations+16 and iterations+32. +void pbkdf2(const byte *Pwd, size_t PwdLength, + const byte *Salt, size_t SaltLength, + byte *Key, byte *V1, byte *V2, uint Count) +{ + const size_t MaxSalt=64; + byte SaltData[MaxSalt+4]; + memcpy(SaltData, Salt, Min(SaltLength,MaxSalt)); + + SaltData[SaltLength + 0] = 0; // Salt concatenated to 1. + SaltData[SaltLength + 1] = 0; + SaltData[SaltLength + 2] = 0; + SaltData[SaltLength + 3] = 1; + + // First iteration: HMAC of password, salt and block index (1). + byte U1[SHA256_DIGEST_SIZE]; + hmac_sha256(Pwd, PwdLength, SaltData, SaltLength + 4, U1, NULL, NULL, NULL, NULL); + byte Fn[SHA256_DIGEST_SIZE]; // Current function value. + memcpy(Fn, U1, sizeof(Fn)); // Function at first iteration. + + uint CurCount[] = { Count-1, 16, 16 }; + byte *CurValue[] = { Key , V1, V2 }; + + sha256_context ICtxOpt,RCtxOpt; + bool SetIOpt=false,SetROpt=false; + + byte U2[SHA256_DIGEST_SIZE]; + for (uint I = 0; I < 3; I++) // For output key and 2 supplementary values. + { + for (uint J = 0; J < CurCount[I]; J++) + { + // U2 = PRF (P, U1). + hmac_sha256(Pwd, PwdLength, U1, sizeof(U1), U2, &ICtxOpt, &SetIOpt, &RCtxOpt, &SetROpt); + memcpy(U1, U2, sizeof(U1)); + for (uint K = 0; K < sizeof(Fn); K++) // Function ^= U. + Fn[K] ^= U1[K]; + } + memcpy(CurValue[I], Fn, SHA256_DIGEST_SIZE); + } + + cleandata(SaltData, sizeof(SaltData)); + cleandata(Fn, sizeof(Fn)); + cleandata(U1, sizeof(U1)); + cleandata(U2, sizeof(U2)); +} + + +void CryptData::SetKey50(bool Encrypt,SecPassword *Password,const wchar *PwdW, + const byte *Salt,const byte *InitV,uint Lg2Cnt,byte *HashKey, + byte *PswCheck) +{ + if (Lg2Cnt>CRYPT5_KDF_LG2_COUNT_MAX) + return; + + byte Key[32],PswCheckValue[SHA256_DIGEST_SIZE],HashKeyValue[SHA256_DIGEST_SIZE]; + bool Found=false; + for (uint I=0;ILg2Count==Lg2Cnt && Item->Pwd==*Password && + memcmp(Item->Salt,Salt,SIZE_SALT50)==0) + { + memcpy(Key,Item->Key,sizeof(Key)); + SecHideData(Key,sizeof(Key),false,false); + + memcpy(PswCheckValue,Item->PswCheckValue,sizeof(PswCheckValue)); + memcpy(HashKeyValue,Item->HashKeyValue,sizeof(HashKeyValue)); + Found=true; + break; + } + } + + if (!Found) + { + char PwdUtf[MAXPASSWORD*4]; + WideToUtf(PwdW,PwdUtf,ASIZE(PwdUtf)); + + pbkdf2((byte *)PwdUtf,strlen(PwdUtf),Salt,SIZE_SALT50,Key,HashKeyValue,PswCheckValue,(1<Lg2Count=Lg2Cnt; + Item->Pwd=*Password; + memcpy(Item->Salt,Salt,SIZE_SALT50); + memcpy(Item->Key,Key,sizeof(Item->Key)); + memcpy(Item->PswCheckValue,PswCheckValue,sizeof(PswCheckValue)); + memcpy(Item->HashKeyValue,HashKeyValue,sizeof(HashKeyValue)); + SecHideData(Item->Key,sizeof(Item->Key),true,false); + } + if (HashKey!=NULL) + memcpy(HashKey,HashKeyValue,SHA256_DIGEST_SIZE); + if (PswCheck!=NULL) + { + memset(PswCheck,0,SIZE_PSWCHECK); + for (uint I=0;IType==HASH_CRC32) + { + byte RawCRC[4]; + RawPut4(Value->CRC32,RawCRC); + byte Digest[SHA256_DIGEST_SIZE]; + hmac_sha256(Key,SHA256_DIGEST_SIZE,RawCRC,sizeof(RawCRC),Digest,NULL,NULL,NULL,NULL); + Value->CRC32=0; + for (uint I=0;ICRC32^=Digest[I] << ((I & 3) * 8); + } + if (Value->Type==HASH_BLAKE2) + { + byte Digest[BLAKE2_DIGEST_SIZE]; + hmac_sha256(Key,BLAKE2_DIGEST_SIZE,Value->Digest,sizeof(Value->Digest),Digest,NULL,NULL,NULL,NULL); + memcpy(Value->Digest,Digest,sizeof(Value->Digest)); + } +} + + +#if 0 +static void TestPBKDF2(); +struct TestKDF {TestKDF() {TestPBKDF2();exit(0);}} GlobalTestKDF; + +void TestPBKDF2() // Test PBKDF2 HMAC-SHA256 +{ + byte Key[32],V1[32],V2[32]; + + pbkdf2((byte *)"password", 8, (byte *)"salt", 4, Key, V1, V2, 1); + byte Res1[32]={0x12, 0x0f, 0xb6, 0xcf, 0xfc, 0xf8, 0xb3, 0x2c, 0x43, 0xe7, 0x22, 0x52, 0x56, 0xc4, 0xf8, 0x37, 0xa8, 0x65, 0x48, 0xc9, 0x2c, 0xcc, 0x35, 0x48, 0x08, 0x05, 0x98, 0x7c, 0xb7, 0x0b, 0xe1, 0x7b }; + mprintf(L"\nPBKDF2 test1: %s", memcmp(Key,Res1,32)==0 ? L"OK":L"Failed"); + + pbkdf2((byte *)"password", 8, (byte *)"salt", 4, Key, V1, V2, 4096); + byte Res2[32]={0xc5, 0xe4, 0x78, 0xd5, 0x92, 0x88, 0xc8, 0x41, 0xaa, 0x53, 0x0d, 0xb6, 0x84, 0x5c, 0x4c, 0x8d, 0x96, 0x28, 0x93, 0xa0, 0x01, 0xce, 0x4e, 0x11, 0xa4, 0x96, 0x38, 0x73, 0xaa, 0x98, 0x13, 0x4a }; + mprintf(L"\nPBKDF2 test2: %s", memcmp(Key,Res2,32)==0 ? L"OK":L"Failed"); + + pbkdf2((byte *)"just some long string pretending to be a password", 49, (byte *)"salt, salt, salt, a lot of salt", 31, Key, V1, V2, 65536); + byte Res3[32]={0x08, 0x0f, 0xa3, 0x1d, 0x42, 0x2d, 0xb0, 0x47, 0x83, 0x9b, 0xce, 0x3a, 0x3b, 0xce, 0x49, 0x51, 0xe2, 0x62, 0xb9, 0xff, 0x76, 0x2f, 0x57, 0xe9, 0xc4, 0x71, 0x96, 0xce, 0x4b, 0x6b, 0x6e, 0xbf}; + mprintf(L"\nPBKDF2 test3: %s", memcmp(Key,Res3,32)==0 ? L"OK":L"Failed"); +} +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/dll.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/dll.cpp new file mode 100644 index 0000000..b5eada5 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/dll.cpp @@ -0,0 +1,483 @@ +#include "rar.hpp" + +static int RarErrorToDll(RAR_EXIT ErrCode); + +struct DataSet +{ + CommandData Cmd; + Archive Arc; + CmdExtract Extract; + int OpenMode; + int HeaderSize; + + DataSet():Arc(&Cmd),Extract(&Cmd) {}; +}; + + +HANDLE PASCAL RAROpenArchive(struct RAROpenArchiveData *r) +{ + RAROpenArchiveDataEx rx; + memset(&rx,0,sizeof(rx)); + rx.ArcName=r->ArcName; + rx.OpenMode=r->OpenMode; + rx.CmtBuf=r->CmtBuf; + rx.CmtBufSize=r->CmtBufSize; + HANDLE hArc=RAROpenArchiveEx(&rx); + r->OpenResult=rx.OpenResult; + r->CmtSize=rx.CmtSize; + r->CmtState=rx.CmtState; + return hArc; +} + + +HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *r) +{ + DataSet *Data=NULL; + try + { + ErrHandler.Clean(); + + r->OpenResult=0; + Data=new DataSet; + Data->Cmd.DllError=0; + Data->OpenMode=r->OpenMode; + Data->Cmd.FileArgs.AddString(L"*"); + + char AnsiArcName[NM]; + *AnsiArcName=0; + if (r->ArcName!=NULL) + { + strncpyz(AnsiArcName,r->ArcName,ASIZE(AnsiArcName)); +#ifdef _WIN_ALL + if (!AreFileApisANSI()) + { + OemToCharBuffA(r->ArcName,AnsiArcName,ASIZE(AnsiArcName)); + AnsiArcName[ASIZE(AnsiArcName)-1]=0; + } +#endif + } + + wchar ArcName[NM]; + GetWideName(AnsiArcName,r->ArcNameW,ArcName,ASIZE(ArcName)); + + Data->Cmd.AddArcName(ArcName); + Data->Cmd.Overwrite=OVERWRITE_ALL; + Data->Cmd.VersionControl=1; + + Data->Cmd.Callback=r->Callback; + Data->Cmd.UserData=r->UserData; + + // Open shared mode is added by request of dll users, who need to + // browse and unpack archives while downloading. + Data->Cmd.OpenShared = true; + if (!Data->Arc.Open(ArcName,FMF_OPENSHARED)) + { + r->OpenResult=ERAR_EOPEN; + delete Data; + return NULL; + } + if (!Data->Arc.IsArchive(true)) + { + if (Data->Cmd.DllError!=0) + r->OpenResult=Data->Cmd.DllError; + else + { + RAR_EXIT ErrCode=ErrHandler.GetErrorCode(); + if (ErrCode!=RARX_SUCCESS && ErrCode!=RARX_WARNING) + r->OpenResult=RarErrorToDll(ErrCode); + else + r->OpenResult=ERAR_BAD_ARCHIVE; + } + delete Data; + return NULL; + } + r->Flags=0; + + if (Data->Arc.Volume) + r->Flags|=0x01; + if (Data->Arc.Locked) + r->Flags|=0x04; + if (Data->Arc.Solid) + r->Flags|=0x08; + if (Data->Arc.NewNumbering) + r->Flags|=0x10; + if (Data->Arc.Signed) + r->Flags|=0x20; + if (Data->Arc.Protected) + r->Flags|=0x40; + if (Data->Arc.Encrypted) + r->Flags|=0x80; + if (Data->Arc.FirstVolume) + r->Flags|=0x100; + + Array CmtDataW; + if (r->CmtBufSize!=0 && Data->Arc.GetComment(&CmtDataW)) + { + Array CmtData(CmtDataW.Size()*4+1); + memset(&CmtData[0],0,CmtData.Size()); + WideToChar(&CmtDataW[0],&CmtData[0],CmtData.Size()-1); + size_t Size=strlen(&CmtData[0])+1; + + r->Flags|=2; + r->CmtState=Size>r->CmtBufSize ? ERAR_SMALL_BUF:1; + r->CmtSize=(uint)Min(Size,r->CmtBufSize); + memcpy(r->CmtBuf,&CmtData[0],r->CmtSize-1); + if (Size<=r->CmtBufSize) + r->CmtBuf[r->CmtSize-1]=0; + } + else + r->CmtState=r->CmtSize=0; + Data->Extract.ExtractArchiveInit(Data->Arc); + return (HANDLE)Data; + } + catch (RAR_EXIT ErrCode) + { + if (Data!=NULL && Data->Cmd.DllError!=0) + r->OpenResult=Data->Cmd.DllError; + else + r->OpenResult=RarErrorToDll(ErrCode); + if (Data != NULL) + delete Data; + return NULL; + } + catch (std::bad_alloc&) // Catch 'new' exception. + { + r->OpenResult=ERAR_NO_MEMORY; + if (Data != NULL) + delete Data; + } + return NULL; // To make compilers happy. +} + + +int PASCAL RARCloseArchive(HANDLE hArcData) +{ + DataSet *Data=(DataSet *)hArcData; + try + { + bool Success=Data==NULL ? false:Data->Arc.Close(); + delete Data; + return Success ? ERAR_SUCCESS : ERAR_ECLOSE; + } + catch (RAR_EXIT ErrCode) + { + return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrCode); + } +} + + +int PASCAL RARReadHeader(HANDLE hArcData,struct RARHeaderData *D) +{ + struct RARHeaderDataEx X; + memset(&X,0,sizeof(X)); + + int Code=RARReadHeaderEx(hArcData,&X); + + strncpyz(D->ArcName,X.ArcName,ASIZE(D->ArcName)); + strncpyz(D->FileName,X.FileName,ASIZE(D->FileName)); + D->Flags=X.Flags; + D->PackSize=X.PackSize; + D->UnpSize=X.UnpSize; + D->HostOS=X.HostOS; + D->FileCRC=X.FileCRC; + D->FileTime=X.FileTime; + D->UnpVer=X.UnpVer; + D->Method=X.Method; + D->FileAttr=X.FileAttr; + D->CmtSize=0; + D->CmtState=0; + + return Code; +} + + +int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *D) +{ + DataSet *Data=(DataSet *)hArcData; + try + { + if ((Data->HeaderSize=(int)Data->Arc.SearchBlock(HEAD_FILE))<=0) + { + if (Data->Arc.Volume && Data->Arc.GetHeaderType()==HEAD_ENDARC && + Data->Arc.EndArcHead.NextVolume) + if (MergeArchive(Data->Arc,NULL,false,'L')) + { + Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET); + return RARReadHeaderEx(hArcData,D); + } + else + return ERAR_EOPEN; + + if (Data->Arc.BrokenHeader) + return ERAR_BAD_DATA; + + // Might be necessary if RARSetPassword is still called instead of + // open callback for RAR5 archives and if password is invalid. + if (Data->Arc.FailedHeaderDecryption) + return ERAR_BAD_PASSWORD; + + return ERAR_END_ARCHIVE; + } + FileHeader *hd=&Data->Arc.FileHead; + if (Data->OpenMode==RAR_OM_LIST && hd->SplitBefore) + { + int Code=RARProcessFile(hArcData,RAR_SKIP,NULL,NULL); + if (Code==0) + return RARReadHeaderEx(hArcData,D); + else + return Code; + } + wcsncpy(D->ArcNameW,Data->Arc.FileName,ASIZE(D->ArcNameW)); + WideToChar(D->ArcNameW,D->ArcName,ASIZE(D->ArcName)); + + wcsncpy(D->FileNameW,hd->FileName,ASIZE(D->FileNameW)); + WideToChar(D->FileNameW,D->FileName,ASIZE(D->FileName)); +#ifdef _WIN_ALL + CharToOemA(D->FileName,D->FileName); +#endif + + D->Flags=0; + if (hd->SplitBefore) + D->Flags|=RHDF_SPLITBEFORE; + if (hd->SplitAfter) + D->Flags|=RHDF_SPLITAFTER; + if (hd->Encrypted) + D->Flags|=RHDF_ENCRYPTED; + if (hd->Solid) + D->Flags|=RHDF_SOLID; + if (hd->Dir) + D->Flags|=RHDF_DIRECTORY; + + D->PackSize=uint(hd->PackSize & 0xffffffff); + D->PackSizeHigh=uint(hd->PackSize>>32); + D->UnpSize=uint(hd->UnpSize & 0xffffffff); + D->UnpSizeHigh=uint(hd->UnpSize>>32); + D->HostOS=hd->HSType==HSYS_WINDOWS ? HOST_WIN32:HOST_UNIX; + if (Data->Arc.Format==RARFMT50) + D->UnpVer=Data->Arc.FileHead.UnpVer==0 ? 50 : 200; // If it is not 0, just set it to something big. + else + D->UnpVer=Data->Arc.FileHead.UnpVer; + D->FileCRC=hd->FileHash.CRC32; + D->FileTime=hd->mtime.GetDos(); + + uint64 MRaw=hd->mtime.GetWin(); + D->MtimeLow=(uint)MRaw; + D->MtimeHigh=(uint)(MRaw>>32); + uint64 CRaw=hd->ctime.GetWin(); + D->CtimeLow=(uint)CRaw; + D->CtimeHigh=(uint)(CRaw>>32); + uint64 ARaw=hd->atime.GetWin(); + D->AtimeLow=(uint)ARaw; + D->AtimeHigh=(uint)(ARaw>>32); + + D->Method=hd->Method+0x30; + D->FileAttr=hd->FileAttr; + D->CmtSize=0; + D->CmtState=0; + + D->DictSize=uint(hd->WinSize/1024); + + switch (hd->FileHash.Type) + { + case HASH_RAR14: + case HASH_CRC32: + D->HashType=RAR_HASH_CRC32; + break; + case HASH_BLAKE2: + D->HashType=RAR_HASH_BLAKE2; + memcpy(D->Hash,hd->FileHash.Digest,BLAKE2_DIGEST_SIZE); + break; + default: + D->HashType=RAR_HASH_NONE; + break; + } + + D->RedirType=hd->RedirType; + // RedirNameSize sanity check is useful in case some developer + // did not initialize Reserved area with 0 as required in docs. + // We have taken 'Redir*' fields from Reserved area. We may remove + // this RedirNameSize check sometimes later. + if (hd->RedirType!=FSREDIR_NONE && D->RedirName!=NULL && + D->RedirNameSize>0 && D->RedirNameSize<100000) + wcsncpyz(D->RedirName,hd->RedirName,D->RedirNameSize); + D->DirTarget=hd->DirTarget; + } + catch (RAR_EXIT ErrCode) + { + return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrCode); + } + return ERAR_SUCCESS; +} + + +int PASCAL ProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName,wchar *DestPathW,wchar *DestNameW) +{ + DataSet *Data=(DataSet *)hArcData; + try + { + Data->Cmd.DllError=0; + if (Data->OpenMode==RAR_OM_LIST || Data->OpenMode==RAR_OM_LIST_INCSPLIT || + Operation==RAR_SKIP && !Data->Arc.Solid) + { + if (Data->Arc.Volume && Data->Arc.GetHeaderType()==HEAD_FILE && + Data->Arc.FileHead.SplitAfter) + if (MergeArchive(Data->Arc,NULL,false,'L')) + { + Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET); + return ERAR_SUCCESS; + } + else + return ERAR_EOPEN; + Data->Arc.SeekToNext(); + } + else + { + Data->Cmd.DllOpMode=Operation; + + *Data->Cmd.ExtrPath=0; + *Data->Cmd.DllDestName=0; + + if (DestPath!=NULL) + { + char ExtrPathA[NM]; + strncpyz(ExtrPathA,DestPath,ASIZE(ExtrPathA)-2); +#ifdef _WIN_ALL + // We must not apply OemToCharBuffA directly to DestPath, + // because we do not know DestPath length and OemToCharBuffA + // does not stop at 0. + OemToCharA(ExtrPathA,ExtrPathA); +#endif + CharToWide(ExtrPathA,Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath)); + AddEndSlash(Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath)); + } + if (DestName!=NULL) + { + char DestNameA[NM]; + strncpyz(DestNameA,DestName,ASIZE(DestNameA)-2); +#ifdef _WIN_ALL + // We must not apply OemToCharBuffA directly to DestName, + // because we do not know DestName length and OemToCharBuffA + // does not stop at 0. + OemToCharA(DestNameA,DestNameA); +#endif + CharToWide(DestNameA,Data->Cmd.DllDestName,ASIZE(Data->Cmd.DllDestName)); + } + + if (DestPathW!=NULL) + { + wcsncpy(Data->Cmd.ExtrPath,DestPathW,ASIZE(Data->Cmd.ExtrPath)); + AddEndSlash(Data->Cmd.ExtrPath,ASIZE(Data->Cmd.ExtrPath)); + } + + if (DestNameW!=NULL) + wcsncpyz(Data->Cmd.DllDestName,DestNameW,ASIZE(Data->Cmd.DllDestName)); + + wcscpy(Data->Cmd.Command,Operation==RAR_EXTRACT ? L"X":L"T"); + Data->Cmd.Test=Operation!=RAR_EXTRACT; + bool Repeat=false; + Data->Extract.ExtractCurrentFile(Data->Arc,Data->HeaderSize,Repeat); + + // Now we process extra file information if any. + // + // Archive can be closed if we process volumes, next volume is missing + // and current one is already removed or deleted. So we need to check + // if archive is still open to avoid calling file operations on + // the invalid file handle. Some of our file operations like Seek() + // process such invalid handle correctly, some not. + while (Data->Arc.IsOpened() && Data->Arc.ReadHeader()!=0 && + Data->Arc.GetHeaderType()==HEAD_SERVICE) + { + Data->Extract.ExtractCurrentFile(Data->Arc,Data->HeaderSize,Repeat); + Data->Arc.SeekToNext(); + } + Data->Arc.Seek(Data->Arc.CurBlockPos,SEEK_SET); + } + } + catch (std::bad_alloc&) + { + return ERAR_NO_MEMORY; + } + catch (RAR_EXIT ErrCode) + { + return Data->Cmd.DllError!=0 ? Data->Cmd.DllError : RarErrorToDll(ErrCode); + } + return Data->Cmd.DllError; +} + + +int PASCAL RARProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName) +{ + return ProcessFile(hArcData,Operation,DestPath,DestName,NULL,NULL); +} + + +int PASCAL RARProcessFileW(HANDLE hArcData,int Operation,wchar *DestPath,wchar *DestName) +{ + return ProcessFile(hArcData,Operation,NULL,NULL,DestPath,DestName); +} + + +void PASCAL RARSetChangeVolProc(HANDLE hArcData,CHANGEVOLPROC ChangeVolProc) +{ + DataSet *Data=(DataSet *)hArcData; + Data->Cmd.ChangeVolProc=ChangeVolProc; +} + + +void PASCAL RARSetCallback(HANDLE hArcData,UNRARCALLBACK Callback,LPARAM UserData) +{ + DataSet *Data=(DataSet *)hArcData; + Data->Cmd.Callback=Callback; + Data->Cmd.UserData=UserData; +} + + +void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataProc) +{ + DataSet *Data=(DataSet *)hArcData; + Data->Cmd.ProcessDataProc=ProcessDataProc; +} + + +#ifndef RAR_NOCRYPT +void PASCAL RARSetPassword(HANDLE hArcData,char *Password) +{ + DataSet *Data=(DataSet *)hArcData; + wchar PasswordW[MAXPASSWORD]; + GetWideName(Password,NULL,PasswordW,ASIZE(PasswordW)); + Data->Cmd.Password.Set(PasswordW); + cleandata(PasswordW,sizeof(PasswordW)); +} +#endif + + +int PASCAL RARGetDllVersion() +{ + return RAR_DLL_VERSION; +} + + +static int RarErrorToDll(RAR_EXIT ErrCode) +{ + switch(ErrCode) + { + case RARX_FATAL: + return ERAR_EREAD; + case RARX_CRC: + return ERAR_BAD_DATA; + case RARX_WRITE: + return ERAR_EWRITE; + case RARX_OPEN: + return ERAR_EOPEN; + case RARX_CREATE: + return ERAR_ECREATE; + case RARX_MEMORY: + return ERAR_NO_MEMORY; + case RARX_BADPWD: + return ERAR_BAD_PASSWORD; + case RARX_SUCCESS: + return ERAR_SUCCESS; // 0. + default: + return ERAR_UNKNOWN; + } +} diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/dll.def b/Carthage/Checkouts/UnrarKit/Libraries/unrar/dll.def new file mode 100644 index 0000000..660f69b --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/dll.def @@ -0,0 +1,12 @@ +EXPORTS + RAROpenArchive + RAROpenArchiveEx + RARCloseArchive + RARReadHeader + RARReadHeaderEx + RARProcessFile + RARSetCallback + RARSetChangeVolProc + RARSetProcessDataProc + RARSetPassword + RARGetDllVersion diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/dll.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/dll.hpp new file mode 100644 index 0000000..7f82906 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/dll.hpp @@ -0,0 +1,185 @@ +#ifndef _UNRAR_DLL_ +#define _UNRAR_DLL_ + +#pragma pack(1) + +#define ERAR_SUCCESS 0 +#define ERAR_END_ARCHIVE 10 +#define ERAR_NO_MEMORY 11 +#define ERAR_BAD_DATA 12 +#define ERAR_BAD_ARCHIVE 13 +#define ERAR_UNKNOWN_FORMAT 14 +#define ERAR_EOPEN 15 +#define ERAR_ECREATE 16 +#define ERAR_ECLOSE 17 +#define ERAR_EREAD 18 +#define ERAR_EWRITE 19 +#define ERAR_SMALL_BUF 20 +#define ERAR_UNKNOWN 21 +#define ERAR_MISSING_PASSWORD 22 +#define ERAR_EREFERENCE 23 +#define ERAR_BAD_PASSWORD 24 + +#define RAR_OM_LIST 0 +#define RAR_OM_EXTRACT 1 +#define RAR_OM_LIST_INCSPLIT 2 + +#define RAR_SKIP 0 +#define RAR_TEST 1 +#define RAR_EXTRACT 2 + +#define RAR_VOL_ASK 0 +#define RAR_VOL_NOTIFY 1 + +#define RAR_DLL_VERSION 8 + +#define RAR_HASH_NONE 0 +#define RAR_HASH_CRC32 1 +#define RAR_HASH_BLAKE2 2 + + +#ifdef _UNIX +#define CALLBACK +#define PASCAL +#define LONG long +#define HANDLE void * +#define LPARAM long +#define UINT unsigned int +#endif + +#define RHDF_SPLITBEFORE 0x01 +#define RHDF_SPLITAFTER 0x02 +#define RHDF_ENCRYPTED 0x04 +#define RHDF_SOLID 0x10 +#define RHDF_DIRECTORY 0x20 + + +struct RARHeaderData +{ + char ArcName[260]; + char FileName[260]; + unsigned int Flags; + unsigned int PackSize; + unsigned int UnpSize; + unsigned int HostOS; + unsigned int FileCRC; + unsigned int FileTime; + unsigned int UnpVer; + unsigned int Method; + unsigned int FileAttr; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; +}; + + +struct RARHeaderDataEx +{ + char ArcName[1024]; + wchar_t ArcNameW[1024]; + char FileName[1024]; + wchar_t FileNameW[1024]; + unsigned int Flags; + unsigned int PackSize; + unsigned int PackSizeHigh; + unsigned int UnpSize; + unsigned int UnpSizeHigh; + unsigned int HostOS; + unsigned int FileCRC; + unsigned int FileTime; + unsigned int UnpVer; + unsigned int Method; + unsigned int FileAttr; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; + unsigned int DictSize; + unsigned int HashType; + char Hash[32]; + unsigned int RedirType; + wchar_t *RedirName; + unsigned int RedirNameSize; + unsigned int DirTarget; + unsigned int MtimeLow; + unsigned int MtimeHigh; + unsigned int CtimeLow; + unsigned int CtimeHigh; + unsigned int AtimeLow; + unsigned int AtimeHigh; + unsigned int Reserved[988]; +}; + + +struct RAROpenArchiveData +{ + char *ArcName; + unsigned int OpenMode; + unsigned int OpenResult; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; +}; + +typedef int (CALLBACK *UNRARCALLBACK)(UINT msg,LPARAM UserData,LPARAM P1,LPARAM P2); + +#define ROADF_VOLUME 0x0001 +#define ROADF_COMMENT 0x0002 +#define ROADF_LOCK 0x0004 +#define ROADF_SOLID 0x0008 +#define ROADF_NEWNUMBERING 0x0010 +#define ROADF_SIGNED 0x0020 +#define ROADF_RECOVERY 0x0040 +#define ROADF_ENCHEADERS 0x0080 +#define ROADF_FIRSTVOLUME 0x0100 + +struct RAROpenArchiveDataEx +{ + char *ArcName; + wchar_t *ArcNameW; + unsigned int OpenMode; + unsigned int OpenResult; + char *CmtBuf; + unsigned int CmtBufSize; + unsigned int CmtSize; + unsigned int CmtState; + unsigned int Flags; + UNRARCALLBACK Callback; + LPARAM UserData; + unsigned int Reserved[28]; +}; + +enum UNRARCALLBACK_MESSAGES { + UCM_CHANGEVOLUME,UCM_PROCESSDATA,UCM_NEEDPASSWORD,UCM_CHANGEVOLUMEW, + UCM_NEEDPASSWORDW +}; + +typedef int (PASCAL *CHANGEVOLPROC)(char *ArcName,int Mode); +typedef int (PASCAL *PROCESSDATAPROC)(unsigned char *Addr,int Size); + +#ifdef __cplusplus +extern "C" { +#endif + +HANDLE PASCAL RAROpenArchive(struct RAROpenArchiveData *ArchiveData); +HANDLE PASCAL RAROpenArchiveEx(struct RAROpenArchiveDataEx *ArchiveData); +int PASCAL RARCloseArchive(HANDLE hArcData); +int PASCAL RARReadHeader(HANDLE hArcData,struct RARHeaderData *HeaderData); +int PASCAL RARReadHeaderEx(HANDLE hArcData,struct RARHeaderDataEx *HeaderData); +int PASCAL RARProcessFile(HANDLE hArcData,int Operation,char *DestPath,char *DestName); +int PASCAL RARProcessFileW(HANDLE hArcData,int Operation,wchar_t *DestPath,wchar_t *DestName); +void PASCAL RARSetCallback(HANDLE hArcData,UNRARCALLBACK Callback,LPARAM UserData); +void PASCAL RARSetChangeVolProc(HANDLE hArcData,CHANGEVOLPROC ChangeVolProc); +void PASCAL RARSetProcessDataProc(HANDLE hArcData,PROCESSDATAPROC ProcessDataProc); +void PASCAL RARSetPassword(HANDLE hArcData,char *Password); +int PASCAL RARGetDllVersion(); + +#ifdef __cplusplus +} +#endif + +#pragma pack() + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/dll.rc b/Carthage/Checkouts/UnrarKit/Libraries/unrar/dll.rc new file mode 100644 index 0000000..c28ecfb --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/dll.rc @@ -0,0 +1,28 @@ +#include +#include + +VS_VERSION_INFO VERSIONINFO +FILEVERSION 5, 60, 3, 2672 +PRODUCTVERSION 5, 60, 3, 2672 +FILEOS VOS__WINDOWS32 +FILETYPE VFT_APP +{ + BLOCK "StringFileInfo" + { + BLOCK "040904E4" + { + VALUE "CompanyName", "Alexander Roshal\0" + VALUE "ProductName", "RAR decompression library\0" + VALUE "FileDescription", "RAR decompression library\0" + VALUE "FileVersion", "5.60.3\0" + VALUE "ProductVersion", "5.60.3\0" + VALUE "LegalCopyright", "Copyright Alexander Roshal 1993-2018\0" + VALUE "OriginalFilename", "Unrar.dll\0" + } + } + BLOCK "VarFileInfo" + { + VALUE "Translation", 0x0409, 0x04E4 + } +} + diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/encname.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/encname.cpp new file mode 100644 index 0000000..84731a7 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/encname.cpp @@ -0,0 +1,69 @@ +#include "rar.hpp" + +EncodeFileName::EncodeFileName() +{ + Flags=0; + FlagBits=0; + FlagsPos=0; + DestSize=0; +} + + + + +void EncodeFileName::Decode(char *Name,size_t NameSize,byte *EncName,size_t EncSize, + wchar *NameW,size_t MaxDecSize) +{ + size_t EncPos=0,DecPos=0; + byte HighByte=EncPos=EncSize) + break; + Flags=EncName[EncPos++]; + FlagBits=8; + } + switch(Flags>>6) + { + case 0: + if (EncPos>=EncSize) + break; + NameW[DecPos++]=EncName[EncPos++]; + break; + case 1: + if (EncPos>=EncSize) + break; + NameW[DecPos++]=EncName[EncPos++]+(HighByte<<8); + break; + case 2: + if (EncPos+1>=EncSize) + break; + NameW[DecPos++]=EncName[EncPos]+(EncName[EncPos+1]<<8); + EncPos+=2; + break; + case 3: + { + if (EncPos>=EncSize) + break; + int Length=EncName[EncPos++]; + if ((Length & 0x80)!=0) + { + if (EncPos>=EncSize) + break; + byte Correction=EncName[EncPos++]; + for (Length=(Length&0x7f)+2;Length>0 && DecPos0 && DecPos1) + exit(RARX_USERBREAK); + // Otherwise return from signal handler and let Wait() function to close + // files and quit. We cannot use the same approach as in Windows, + // because Unix signal handler can block execution of our main code. +#endif + +#if defined(_WIN_ALL) && !defined(_MSC_VER) + // never reached, just to avoid a compiler warning + return TRUE; +#endif +} + + +void ErrorHandler::SetSignalHandlers(bool Enable) +{ + EnableBreak=Enable; +#ifdef _WIN_ALL + SetConsoleCtrlHandler(Enable ? ProcessSignal:NULL,TRUE); +#else + signal(SIGINT,Enable ? ProcessSignal:SIG_IGN); + signal(SIGTERM,Enable ? ProcessSignal:SIG_IGN); +#endif +} + + +void ErrorHandler::Throw(RAR_EXIT Code) +{ + if (Code==RARX_USERBREAK && !EnableBreak) + return; +#if !defined(SILENT) + // Do not write "aborted" when just displaying online help. + if (Code!=RARX_SUCCESS && Code!=RARX_USERERROR) + mprintf(L"\n%s\n",St(MProgAborted)); +#endif + SetErrorCode(Code); + throw Code; +} + + +bool ErrorHandler::GetSysErrMsg(wchar *Msg,size_t Size) +{ +#if !defined(SFX_MODULE) && !defined(SILENT) +#ifdef _WIN_ALL + int ErrType=GetLastError(); + if (ErrType!=0) + return FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, + NULL,ErrType,MAKELANGID(LANG_NEUTRAL,SUBLANG_DEFAULT), + Msg,(DWORD)Size,NULL)!=0; +#endif + +#if defined(_UNIX) || defined(_EMX) + if (errno!=0) + { + char *err=strerror(errno); + if (err!=NULL) + { + CharToWide(err,Msg,Size); + return true; + } + } +#endif +#endif + return false; +} + + +void ErrorHandler::SysErrMsg() +{ +#if !defined(SFX_MODULE) && !defined(SILENT) + wchar Msg[1024]; + if (!GetSysErrMsg(Msg,ASIZE(Msg))) + return; +#ifdef _WIN_ALL + wchar *CurMsg=Msg; + while (CurMsg!=NULL) + { + while (*CurMsg=='\r' || *CurMsg=='\n') + CurMsg++; + if (*CurMsg==0) + break; + wchar *EndMsg=wcschr(CurMsg,'\r'); + if (EndMsg==NULL) + EndMsg=wcschr(CurMsg,'\n'); + if (EndMsg!=NULL) + { + *EndMsg=0; + EndMsg++; + } + uiMsg(UIERROR_SYSERRMSG,CurMsg); + CurMsg=EndMsg; + } +#endif + +#if defined(_UNIX) || defined(_EMX) + uiMsg(UIERROR_SYSERRMSG,Msg); +#endif + +#endif +} + + +int ErrorHandler::GetSystemErrorCode() +{ +#ifdef _WIN_ALL + return GetLastError(); +#else + return errno; +#endif +} + + +void ErrorHandler::SetSystemErrorCode(int Code) +{ +#ifdef _WIN_ALL + SetLastError(Code); +#else + errno=Code; +#endif +} diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/errhnd.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/errhnd.hpp new file mode 100644 index 0000000..c360c6c --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/errhnd.hpp @@ -0,0 +1,71 @@ +#ifndef _RAR_ERRHANDLER_ +#define _RAR_ERRHANDLER_ + +enum RAR_EXIT // RAR exit code. +{ + RARX_SUCCESS = 0, + RARX_WARNING = 1, + RARX_FATAL = 2, + RARX_CRC = 3, + RARX_LOCK = 4, + RARX_WRITE = 5, + RARX_OPEN = 6, + RARX_USERERROR = 7, + RARX_MEMORY = 8, + RARX_CREATE = 9, + RARX_NOFILES = 10, + RARX_BADPWD = 11, + RARX_USERBREAK = 255 +}; + +class ErrorHandler +{ + private: + RAR_EXIT ExitCode; + uint ErrCount; + bool EnableBreak; + bool Silent; + bool DisableShutdown; // Shutdown is not suitable after last error. + public: + ErrorHandler(); + void Clean(); + void MemoryError(); + void OpenError(const wchar *FileName); + void CloseError(const wchar *FileName); + void ReadError(const wchar *FileName); + bool AskRepeatRead(const wchar *FileName); + void WriteError(const wchar *ArcName,const wchar *FileName); + void WriteErrorFAT(const wchar *FileName); + bool AskRepeatWrite(const wchar *FileName,bool DiskFull); + void SeekError(const wchar *FileName); + void GeneralErrMsg(const wchar *fmt,...); + void MemoryErrorMsg(); + void OpenErrorMsg(const wchar *FileName); + void OpenErrorMsg(const wchar *ArcName,const wchar *FileName); + void CreateErrorMsg(const wchar *FileName); + void CreateErrorMsg(const wchar *ArcName,const wchar *FileName); + void ReadErrorMsg(const wchar *FileName); + void ReadErrorMsg(const wchar *ArcName,const wchar *FileName); + void WriteErrorMsg(const wchar *ArcName,const wchar *FileName); + void ArcBrokenMsg(const wchar *ArcName); + void ChecksumFailedMsg(const wchar *ArcName,const wchar *FileName); + void UnknownMethodMsg(const wchar *ArcName,const wchar *FileName); + void Exit(RAR_EXIT ExitCode); + void SetErrorCode(RAR_EXIT Code); + RAR_EXIT GetErrorCode() {return ExitCode;} + uint GetErrorCount() {return ErrCount;} + void SetSignalHandlers(bool Enable); + void Throw(RAR_EXIT Code); + void SetSilent(bool Mode) {Silent=Mode;}; + bool GetSysErrMsg(wchar *Msg,size_t Size); + void SysErrMsg(); + int GetSystemErrorCode(); + void SetSystemErrorCode(int Code); + bool IsShutdownEnabled() {return !DisableShutdown;} + + bool UserBreak; // Ctrl+Break is pressed. + bool MainExit; // main() is completed. +}; + + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/extinfo.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/extinfo.cpp new file mode 100644 index 0000000..5cb90a4 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/extinfo.cpp @@ -0,0 +1,178 @@ +#include "rar.hpp" + +#include "hardlinks.cpp" +#include "win32stm.cpp" + +#ifdef _WIN_ALL +#include "win32acl.cpp" +#include "win32lnk.cpp" +#endif + +#ifdef _UNIX +#include "uowners.cpp" +#ifdef SAVE_LINKS +#include "ulinks.cpp" +#endif +#endif + + + +// RAR2 service header extra records. +#ifndef SFX_MODULE +void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name) +{ + if (Cmd->Test) + return; + switch(Arc.SubBlockHead.SubType) + { +#ifdef _UNIX + case UO_HEAD: + if (Cmd->ProcessOwners) + ExtractUnixOwner20(Arc,Name); + break; +#endif +#ifdef _WIN_ALL + case NTACL_HEAD: + if (Cmd->ProcessOwners) + ExtractACL20(Arc,Name); + break; + case STREAM_HEAD: + ExtractStreams20(Arc,Name); + break; +#endif + } +} +#endif + + +// RAR3 and RAR5 service header extra records. +void SetExtraInfo(CommandData *Cmd,Archive &Arc,wchar *Name) +{ +#ifdef _UNIX + if (!Cmd->Test && Cmd->ProcessOwners && Arc.Format==RARFMT15 && + Arc.SubHead.CmpName(SUBHEAD_TYPE_UOWNER)) + ExtractUnixOwner30(Arc,Name); +#endif +#ifdef _WIN_ALL + if (!Cmd->Test && Cmd->ProcessOwners && Arc.SubHead.CmpName(SUBHEAD_TYPE_ACL)) + ExtractACL(Arc,Name); + if (Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM)) + ExtractStreams(Arc,Name,Cmd->Test); +#endif +} + + +// Extra data stored directly in file header. +void SetFileHeaderExtra(CommandData *Cmd,Archive &Arc,wchar *Name) +{ +#ifdef _UNIX + if (Cmd->ProcessOwners && Arc.Format==RARFMT50 && Arc.FileHead.UnixOwnerSet) + SetUnixOwner(Arc,Name); +#endif +} + + + + +// Calculate a number of path components except \. and \.. +static int CalcAllowedDepth(const wchar *Name) +{ + int AllowedDepth=0; + while (*Name!=0) + { + if (IsPathDiv(Name[0]) && Name[1]!=0 && !IsPathDiv(Name[1])) + { + bool Dot=Name[1]=='.' && (IsPathDiv(Name[2]) || Name[2]==0); + bool Dot2=Name[1]=='.' && Name[2]=='.' && (IsPathDiv(Name[3]) || Name[3]==0); + if (!Dot && !Dot2) + AllowedDepth++; + } + Name++; + } + return AllowedDepth; +} + + +// Check if all existing path components are directories and not links. +static bool LinkInPath(const wchar *Name) +{ + wchar Path[NM]; + if (wcslen(Name)>=ASIZE(Path)) + return true; // It should not be that long, skip. + wcsncpyz(Path,Name,ASIZE(Path)); + for (wchar *s=Path+wcslen(Path)-1;s>Path;s--) + if (IsPathDiv(*s)) + { + *s=0; + FindData FD; + if (FindFile::FastFind(Path,&FD,true) && (FD.IsLink || !FD.IsDir)) + return true; + } + return false; +} + + +bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName) +{ + // Catch root dir based /path/file paths also as stuff like \\?\. + // Do not check PrepSrcName here, it can be root based if destination path + // is a root based. + if (IsFullRootPath(SrcName) || IsFullRootPath(TargetName)) + return false; + + // Number of ".." in link target. + int UpLevels=0; + for (int Pos=0;*TargetName!=0;Pos++) + { + bool Dot2=TargetName[0]=='.' && TargetName[1]=='.' && + (IsPathDiv(TargetName[2]) || TargetName[2]==0) && + (Pos==0 || IsPathDiv(*(TargetName-1))); + if (Dot2) + UpLevels++; + TargetName++; + } + // If link target includes "..", it must not have another links + // in the path, because they can bypass our safety check. For example, + // suppose we extracted "lnk1" -> "." first and "lnk1/lnk2" -> ".." next + // or "dir/lnk1" -> ".." first and "dir/lnk1/lnk2" -> ".." next. + if (UpLevels>0 && LinkInPath(PrepSrcName)) + return false; + + // We could check just prepared src name, but for extra safety + // we check both original (as from archive header) and prepared + // (after applying the destination path and -ep switches) names. + + int AllowedDepth=CalcAllowedDepth(SrcName); // Original name depth. + + // Remove the destination path from prepared name if any. We should not + // count the destination path depth, because the link target must point + // inside of this path, not outside of it. + size_t ExtrPathLength=wcslen(Cmd->ExtrPath); + if (ExtrPathLength>0 && wcsncmp(PrepSrcName,Cmd->ExtrPath,ExtrPathLength)==0) + { + PrepSrcName+=ExtrPathLength; + while (IsPathDiv(*PrepSrcName)) + PrepSrcName++; + } + int PrepAllowedDepth=CalcAllowedDepth(PrepSrcName); + + return AllowedDepth>=UpLevels && PrepAllowedDepth>=UpLevels; +} + + +bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName) +{ +#if defined(SAVE_LINKS) && defined(_UNIX) + // For RAR 3.x archives we process links even in test mode to skip link data. + if (Arc.Format==RARFMT15) + return ExtractUnixLink30(Cmd,DataIO,Arc,LinkName); + if (Arc.Format==RARFMT50) + return ExtractUnixLink50(Cmd,LinkName,&Arc.FileHead); +#elif defined _WIN_ALL + // RAR 5.0 archives store link information in file header, so there is + // no need to additionally test it if we do not create a file. + if (Arc.Format==RARFMT50) + return CreateReparsePoint(Cmd,LinkName,&Arc.FileHead); +#endif + return false; +} diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/extinfo.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/extinfo.hpp new file mode 100644 index 0000000..2b0005d --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/extinfo.hpp @@ -0,0 +1,23 @@ +#ifndef _RAR_EXTINFO_ +#define _RAR_EXTINFO_ + +bool IsRelativeSymlinkSafe(CommandData *Cmd,const wchar *SrcName,const wchar *PrepSrcName,const wchar *TargetName); +bool ExtractSymlink(CommandData *Cmd,ComprDataIO &DataIO,Archive &Arc,const wchar *LinkName); +#ifdef _UNIX +void SetUnixOwner(Archive &Arc,const wchar *FileName); +#endif + +bool ExtractHardlink(wchar *NameNew,wchar *NameExisting,size_t NameExistingSize); + +void GetStreamNameNTFS(Archive &Arc,wchar *StreamName,size_t MaxSize); + +#ifdef _WIN_ALL +bool SetPrivilege(LPCTSTR PrivName); +#endif + +void SetExtraInfo20(CommandData *Cmd,Archive &Arc,wchar *Name); +void SetExtraInfo(CommandData *Cmd,Archive &Arc,wchar *Name); +void SetFileHeaderExtra(CommandData *Cmd,Archive &Arc,wchar *Name); + + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/extract.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/extract.cpp new file mode 100644 index 0000000..99cca62 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/extract.cpp @@ -0,0 +1,1165 @@ +#include "rar.hpp" + +CmdExtract::CmdExtract(CommandData *Cmd) +{ + CmdExtract::Cmd=Cmd; + + *ArcName=0; + + *DestFileName=0; + + TotalFileCount=0; + Unp=new Unpack(&DataIO); +#ifdef RAR_SMP + Unp->SetThreads(Cmd->Threads); +#endif +} + + +CmdExtract::~CmdExtract() +{ + delete Unp; +} + + +void CmdExtract::DoExtract() +{ +#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT) + Fat32=NotFat32=false; +#endif + PasswordCancelled=false; + DataIO.SetCurrentCommand(Cmd->Command[0]); + + FindData FD; + while (Cmd->GetArcName(ArcName,ASIZE(ArcName))) + if (FindFile::FastFind(ArcName,&FD)) + DataIO.TotalArcSize+=FD.Size; + + Cmd->ArcNames.Rewind(); + while (Cmd->GetArcName(ArcName,ASIZE(ArcName))) + { + if (Cmd->ManualPassword) + Cmd->Password.Clean(); // Clean user entered password before processing next archive. + while (true) + { + EXTRACT_ARC_CODE Code=ExtractArchive(); + if (Code!=EXTRACT_ARC_REPEAT) + break; + } + if (FindFile::FastFind(ArcName,&FD)) + DataIO.ProcessedArcSize+=FD.Size; + } + + // Clean user entered password. Not really required, just for extra safety. + if (Cmd->ManualPassword) + Cmd->Password.Clean(); + + if (TotalFileCount==0 && Cmd->Command[0]!='I' && + ErrHandler.GetErrorCode()!=RARX_BADPWD) // Not in case of wrong archive password. + { + if (!PasswordCancelled) + uiMsg(UIERROR_NOFILESTOEXTRACT,ArcName); + ErrHandler.SetErrorCode(RARX_NOFILES); + } + else + if (!Cmd->DisableDone) + if (Cmd->Command[0]=='I') + mprintf(St(MDone)); + else + if (ErrHandler.GetErrorCount()==0) + mprintf(St(MExtrAllOk)); + else + mprintf(St(MExtrTotalErr),ErrHandler.GetErrorCount()); +} + + +void CmdExtract::ExtractArchiveInit(Archive &Arc) +{ + DataIO.UnpArcSize=Arc.FileLength(); + + FileCount=0; + MatchedArgs=0; +#ifndef SFX_MODULE + FirstFile=true; +#endif + + PasswordAll=(Cmd->Password.IsSet()); + + DataIO.UnpVolume=false; + + PrevProcessed=false; + AllMatchesExact=true; + ReconstructDone=false; + AnySolidDataUnpackedWell=false; + + StartTime.SetCurrentTime(); +} + + +EXTRACT_ARC_CODE CmdExtract::ExtractArchive() +{ + Archive Arc(Cmd); + if (!Arc.WOpen(ArcName)) + return EXTRACT_ARC_NEXT; + + if (!Arc.IsArchive(true)) + { +#if !defined(SFX_MODULE) && !defined(RARDLL) + if (CmpExt(ArcName,L"rev")) + { + wchar FirstVolName[NM]; + VolNameToFirstName(ArcName,FirstVolName,ASIZE(FirstVolName),true); + + // If several volume names from same volume set are specified + // and current volume is not first in set and first volume is present + // and specified too, let's skip the current volume. + if (wcsicomp(ArcName,FirstVolName)!=0 && FileExist(FirstVolName) && + Cmd->ArcNames.Search(FirstVolName,false)) + return EXTRACT_ARC_NEXT; + RecVolumesTest(Cmd,NULL,ArcName); + TotalFileCount++; // Suppress "No files to extract" message. + return EXTRACT_ARC_NEXT; + } +#endif + + mprintf(St(MNotRAR),ArcName); + +#ifndef SFX_MODULE + if (CmpExt(ArcName,L"rar")) +#endif + ErrHandler.SetErrorCode(RARX_WARNING); + return EXTRACT_ARC_NEXT; + } + + if (Arc.FailedHeaderDecryption) // Bad archive password. + return EXTRACT_ARC_NEXT; + +#ifndef SFX_MODULE + if (Arc.Volume && !Arc.FirstVolume) + { + wchar FirstVolName[NM]; + VolNameToFirstName(ArcName,FirstVolName,ASIZE(FirstVolName),Arc.NewNumbering); + + // If several volume names from same volume set are specified + // and current volume is not first in set and first volume is present + // and specified too, let's skip the current volume. + if (wcsicomp(ArcName,FirstVolName)!=0 && FileExist(FirstVolName) && + Cmd->ArcNames.Search(FirstVolName,false)) + return EXTRACT_ARC_NEXT; + } +#endif + + int64 VolumeSetSize=0; // Total size of volumes after the current volume. + + if (Arc.Volume) + { + // Calculate the total size of all accessible volumes. + // This size is necessary to display the correct total progress indicator. + + wchar NextName[NM]; + wcscpy(NextName,Arc.FileName); + + while (true) + { + // First volume is already added to DataIO.TotalArcSize + // in initial TotalArcSize calculation in DoExtract. + // So we skip it and start from second volume. + NextVolumeName(NextName,ASIZE(NextName),!Arc.NewNumbering); + FindData FD; + if (FindFile::FastFind(NextName,&FD)) + VolumeSetSize+=FD.Size; + else + break; + } + DataIO.TotalArcSize+=VolumeSetSize; + } + + ExtractArchiveInit(Arc); + + if (*Cmd->Command=='T' || *Cmd->Command=='I') + Cmd->Test=true; + + + if (*Cmd->Command=='I') + { + Cmd->DisablePercentage=true; + } + else + uiStartArchiveExtract(!Cmd->Test,ArcName); + + Arc.ViewComment(); + + + while (1) + { + size_t Size=Arc.ReadHeader(); + + + bool Repeat=false; + if (!ExtractCurrentFile(Arc,Size,Repeat)) + if (Repeat) + { + // If we started extraction from not first volume and need to + // restart it from first, we must correct DataIO.TotalArcSize + // for correct total progress display. We subtract the size + // of current volume and all volumes after it and add the size + // of new (first) volume. + FindData OldArc,NewArc; + if (FindFile::FastFind(Arc.FileName,&OldArc) && + FindFile::FastFind(ArcName,&NewArc)) + DataIO.TotalArcSize-=VolumeSetSize+OldArc.Size-NewArc.Size; + return EXTRACT_ARC_REPEAT; + } + else + break; + } + + +#if !defined(SFX_MODULE) && !defined(RARDLL) + if (Cmd->Test && Arc.Volume) + RecVolumesTest(Cmd,&Arc,ArcName); +#endif + + return EXTRACT_ARC_NEXT; +} + + +bool CmdExtract::ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat) +{ + wchar Command=Cmd->Command[0]; + if (HeaderSize==0) + if (DataIO.UnpVolume) + { +#ifdef NOVOLUME + return false; +#else + // Supposing we unpack an old RAR volume without the end of archive + // record and last file is not split between volumes. + if (!MergeArchive(Arc,&DataIO,false,Command)) + { + ErrHandler.SetErrorCode(RARX_WARNING); + return false; + } +#endif + } + else + return false; + + HEADER_TYPE HeaderType=Arc.GetHeaderType(); + if (HeaderType!=HEAD_FILE) + { +#ifndef SFX_MODULE + if (Arc.Format==RARFMT15 && HeaderType==HEAD3_OLDSERVICE && PrevProcessed) + SetExtraInfo20(Cmd,Arc,DestFileName); +#endif + if (HeaderType==HEAD_SERVICE && PrevProcessed) + SetExtraInfo(Cmd,Arc,DestFileName); + if (HeaderType==HEAD_ENDARC) + if (Arc.EndArcHead.NextVolume) + { +#ifndef NOVOLUME + if (!MergeArchive(Arc,&DataIO,false,Command)) + { + ErrHandler.SetErrorCode(RARX_WARNING); + return false; + } +#endif + Arc.Seek(Arc.CurBlockPos,SEEK_SET); + return true; + } + else + return false; + Arc.SeekToNext(); + return true; + } + PrevProcessed=false; + + // We can get negative sizes in corrupt archive and it is unacceptable + // for size comparisons in ComprDataIO::UnpRead, where we cast sizes + // to size_t and can exceed another read or available size. We could fix it + // when reading an archive. But we prefer to do it here, because this + // function is called directly in unrar.dll, so we fix bad parameters + // passed to dll. Also we want to see real negative sizes in the listing + // of corrupt archive. To prevent uninitialized data access perform + // these checks after rejecting zero length and non-file headers above. + if (Arc.FileHead.PackSize<0) + Arc.FileHead.PackSize=0; + if (Arc.FileHead.UnpSize<0) + Arc.FileHead.UnpSize=0; + + if (!Cmd->Recurse && MatchedArgs>=Cmd->FileArgs.ItemsCount() && AllMatchesExact) + return false; + + int MatchType=MATCH_WILDSUBPATH; + + bool EqualNames=false; + wchar MatchedArg[NM]; + int MatchNumber=Cmd->IsProcessFile(Arc.FileHead,&EqualNames,MatchType,MatchedArg,ASIZE(MatchedArg)); + bool MatchFound=MatchNumber!=0; +#ifndef SFX_MODULE + if (Cmd->ExclPath==EXCL_BASEPATH) + { + wcsncpyz(Cmd->ArcPath,MatchedArg,ASIZE(Cmd->ArcPath)); + *PointToName(Cmd->ArcPath)=0; + if (IsWildcard(Cmd->ArcPath)) // Cannot correctly process path*\* masks here. + *Cmd->ArcPath=0; + } +#endif + if (MatchFound && !EqualNames) + AllMatchesExact=false; + + Arc.ConvertAttributes(); + +#if !defined(SFX_MODULE) && !defined(RARDLL) + if (Arc.FileHead.SplitBefore && FirstFile) + { + wchar CurVolName[NM]; + wcsncpyz(CurVolName,ArcName,ASIZE(CurVolName)); + VolNameToFirstName(ArcName,ArcName,ASIZE(ArcName),Arc.NewNumbering); + + if (wcsicomp(ArcName,CurVolName)!=0 && FileExist(ArcName)) + { + // If first volume name does not match the current name and if such + // volume name really exists, let's unpack from this first volume. + Repeat=true; + return false; + } +#ifndef RARDLL + if (!ReconstructDone) + { + ReconstructDone=true; + if (RecVolumesRestore(Cmd,Arc.FileName,true)) + { + Repeat=true; + return false; + } + } +#endif + wcsncpyz(ArcName,CurVolName,ASIZE(ArcName)); + } +#endif + + wchar ArcFileName[NM]; + ConvertPath(Arc.FileHead.FileName,ArcFileName); + + if (Arc.FileHead.Version) + { + if (Cmd->VersionControl!=1 && !EqualNames) + { + if (Cmd->VersionControl==0) + MatchFound=false; + int Version=ParseVersionFileName(ArcFileName,false); + if (Cmd->VersionControl-1==Version) + ParseVersionFileName(ArcFileName,true); + else + MatchFound=false; + } + } + else + if (!Arc.IsArcDir() && Cmd->VersionControl>1) + MatchFound=false; + + DataIO.UnpVolume=Arc.FileHead.SplitAfter; + DataIO.NextVolumeMissing=false; + + Arc.Seek(Arc.NextBlockPos-Arc.FileHead.PackSize,SEEK_SET); + + bool ExtrFile=false; + bool SkipSolid=false; + +#ifndef SFX_MODULE + if (FirstFile && (MatchFound || Arc.Solid) && Arc.FileHead.SplitBefore) + { + if (MatchFound) + { + uiMsg(UIERROR_NEEDPREVVOL,Arc.FileName,ArcFileName); +#ifdef RARDLL + Cmd->DllError=ERAR_BAD_DATA; +#endif + ErrHandler.SetErrorCode(RARX_OPEN); + } + MatchFound=false; + } + + FirstFile=false; +#endif + + if (MatchFound || (SkipSolid=Arc.Solid)!=0) + { + // First common call of uiStartFileExtract. It is done before overwrite + // prompts, so if SkipSolid state is changed below, we'll need to make + // additional uiStartFileExtract calls with updated parameters. + if (!uiStartFileExtract(ArcFileName,!Cmd->Test,Cmd->Test && Command!='I',SkipSolid)) + return false; + + ExtrPrepareName(Arc,ArcFileName,DestFileName,ASIZE(DestFileName)); + + // DestFileName can be set empty in case of excessive -ap switch. + ExtrFile=!SkipSolid && *DestFileName!=0 && !Arc.FileHead.SplitBefore; + + if ((Cmd->FreshFiles || Cmd->UpdateFiles) && (Command=='E' || Command=='X')) + { + FindData FD; + if (FindFile::FastFind(DestFileName,&FD)) + { + if (FD.mtime >= Arc.FileHead.mtime) + { + // If directory already exists and its modification time is newer + // than start of extraction, it is likely it was created + // when creating a path to one of already extracted items. + // In such case we'll better update its time even if archived + // directory is older. + + if (!FD.IsDir || FD.mtimeFreshFiles) + ExtrFile=false; + } + + if (!CheckUnpVer(Arc,ArcFileName)) + { + ErrHandler.SetErrorCode(RARX_FATAL); +#ifdef RARDLL + Cmd->DllError=ERAR_UNKNOWN_FORMAT; +#endif + Arc.SeekToNext(); + return !Arc.Solid; // Can try extracting next file only in non-solid archive. + } + + while (true) // Repeat the password prompt for wrong and empty passwords. + { + if (Arc.FileHead.Encrypted) + { + // Stop archive extracting if user cancelled a password prompt. +#ifdef RARDLL + if (!ExtrDllGetPassword()) + { + Cmd->DllError=ERAR_MISSING_PASSWORD; + return false; + } +#else + if (!ExtrGetPassword(Arc,ArcFileName)) + { + PasswordCancelled=true; + return false; + } +#endif + } + + // Set a password before creating the file, so we can skip creating + // in case of wrong password. + SecPassword FilePassword=Cmd->Password; +#if defined(_WIN_ALL) && !defined(SFX_MODULE) + ConvertDosPassword(Arc,FilePassword); +#endif + + byte PswCheck[SIZE_PSWCHECK]; + DataIO.SetEncryption(false,Arc.FileHead.CryptMethod,&FilePassword, + Arc.FileHead.SaltSet ? Arc.FileHead.Salt:NULL, + Arc.FileHead.InitV,Arc.FileHead.Lg2Count, + Arc.FileHead.HashKey,PswCheck); + + // If header is damaged, we cannot rely on password check value, + // because it can be damaged too. + if (Arc.FileHead.Encrypted && Arc.FileHead.UsePswCheck && + memcmp(Arc.FileHead.PswCheck,PswCheck,SIZE_PSWCHECK)!=0 && + !Arc.BrokenHeader) + { + if (PasswordAll) // For -p or Ctrl+P. + { + // This message is used by Android GUI to reset cached passwords. + // Update appropriate code if changed. + uiMsg(UIERROR_BADPSW,ArcFileName); + } + else // For passwords entered manually. + { + // This message is used by Android GUI and Windows GUI and SFX to + // reset cached passwords. Update appropriate code if changed. + uiMsg(UIWAIT_BADPSW,ArcFileName); + Cmd->Password.Clean(); + + // Avoid new requests for unrar.dll to prevent the infinite loop + // if app always returns the same password. +#ifndef RARDLL + continue; // Request a password again. +#endif + } +#ifdef RARDLL + // If we already have ERAR_EOPEN as result of missing volume, + // we should not replace it with less precise ERAR_BAD_PASSWORD. + if (Cmd->DllError!=ERAR_EOPEN) + Cmd->DllError=ERAR_BAD_PASSWORD; +#endif + ErrHandler.SetErrorCode(RARX_BADPWD); + ExtrFile=false; + } + break; + } + +#ifdef RARDLL + if (*Cmd->DllDestName!=0) + wcsncpyz(DestFileName,Cmd->DllDestName,ASIZE(DestFileName)); +#endif + + File CurFile; + + bool LinkEntry=Arc.FileHead.RedirType!=FSREDIR_NONE; + if (LinkEntry && Arc.FileHead.RedirType!=FSREDIR_FILECOPY) + { + if (ExtrFile && Command!='P' && !Cmd->Test) + { + // Overwrite prompt for symbolic and hard links. + bool UserReject=false; + if (FileExist(DestFileName) && !UserReject) + FileCreate(Cmd,NULL,DestFileName,ASIZE(DestFileName),&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime); + if (UserReject) + ExtrFile=false; + } + } + else + if (Arc.IsArcDir()) + { + if (!ExtrFile || Command=='P' || Command=='I' || Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH) + return true; + TotalFileCount++; + ExtrCreateDir(Arc,ArcFileName); + // It is important to not increment MatchedArgs here, so we extract + // dir with its entire contents and not dir record only even if + // dir record precedes files. + return true; + } + else + if (ExtrFile) // Create files and file copies (FSREDIR_FILECOPY). + ExtrFile=ExtrCreateFile(Arc,CurFile); + + if (!ExtrFile && Arc.Solid) + { + SkipSolid=true; + ExtrFile=true; + + // We changed SkipSolid, so we need to call uiStartFileExtract + // with "Skip" parameter to change the operation status + // from "extracting" to "skipping". For example, it can be necessary + // if user answered "No" to overwrite prompt when unpacking + // a solid archive. + if (!uiStartFileExtract(ArcFileName,false,false,true)) + return false; + } + if (ExtrFile) + { + // Set it in test mode, so we also test subheaders such as NTFS streams + // after tested file. + if (Cmd->Test) + PrevProcessed=true; + + bool TestMode=Cmd->Test || SkipSolid; // Unpack to memory, not to disk. + + if (!SkipSolid) + { + if (!TestMode && Command!='P' && CurFile.IsDevice()) + { + uiMsg(UIERROR_INVALIDNAME,Arc.FileName,DestFileName); + ErrHandler.WriteError(Arc.FileName,DestFileName); + } + TotalFileCount++; + } + FileCount++; + if (Command!='I') + if (SkipSolid) + mprintf(St(MExtrSkipFile),ArcFileName); + else + switch(Cmd->Test ? 'T':Command) // "Test" can be also enabled by -t switch. + { + case 'T': + mprintf(St(MExtrTestFile),ArcFileName); + break; +#ifndef SFX_MODULE + case 'P': + mprintf(St(MExtrPrinting),ArcFileName); + break; +#endif + case 'X': + case 'E': + mprintf(St(MExtrFile),DestFileName); + break; + } + if (!Cmd->DisablePercentage) + mprintf(L" "); + + DataIO.CurUnpRead=0; + DataIO.CurUnpWrite=0; + DataIO.UnpHash.Init(Arc.FileHead.FileHash.Type,Cmd->Threads); + DataIO.PackedDataHash.Init(Arc.FileHead.FileHash.Type,Cmd->Threads); + DataIO.SetPackedSizeToRead(Arc.FileHead.PackSize); + DataIO.SetFiles(&Arc,&CurFile); + DataIO.SetTestMode(TestMode); + DataIO.SetSkipUnpCRC(SkipSolid); + +#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT) + if (!TestMode && !Arc.BrokenHeader && + Arc.FileHead.UnpSize>0xffffffff && (Fat32 || !NotFat32)) + { + if (!Fat32) // Not detected yet. + NotFat32=!(Fat32=IsFAT(Cmd->ExtrPath)); + if (Fat32) + uiMsg(UIMSG_FAT32SIZE); // Inform user about FAT32 size limit. + } +#endif + + if (!TestMode && !Arc.BrokenHeader && + (Arc.FileHead.PackSize<<11)>Arc.FileHead.UnpSize && + (Arc.FileHead.UnpSize<100000000 || Arc.FileLength()>Arc.FileHead.PackSize)) + CurFile.Prealloc(Arc.FileHead.UnpSize); + + CurFile.SetAllowDelete(!Cmd->KeepBroken); + + bool FileCreateMode=!TestMode && !SkipSolid && Command!='P'; + bool ShowChecksum=true; // Display checksum verification result. + + bool LinkSuccess=true; // Assume success for test mode. + if (LinkEntry) + { + FILE_SYSTEM_REDIRECT Type=Arc.FileHead.RedirType; + + if (Type==FSREDIR_HARDLINK || Type==FSREDIR_FILECOPY) + { + wchar NameExisting[NM]; + ExtrPrepareName(Arc,Arc.FileHead.RedirName,NameExisting,ASIZE(NameExisting)); + if (FileCreateMode && *NameExisting!=0) // *NameExisting can be 0 in case of excessive -ap switch. + if (Type==FSREDIR_HARDLINK) + LinkSuccess=ExtractHardlink(DestFileName,NameExisting,ASIZE(NameExisting)); + else + LinkSuccess=ExtractFileCopy(CurFile,Arc.FileName,DestFileName,NameExisting,ASIZE(NameExisting)); + } + else + if (Type==FSREDIR_UNIXSYMLINK || Type==FSREDIR_WINSYMLINK || Type==FSREDIR_JUNCTION) + { + if (FileCreateMode) + LinkSuccess=ExtractSymlink(Cmd,DataIO,Arc,DestFileName); + } + else + { + uiMsg(UIERROR_UNKNOWNEXTRA, Arc.FileName, DestFileName); + LinkSuccess=false; + } + + if (!LinkSuccess || Arc.Format==RARFMT15 && !FileCreateMode) + { + // RAR 5.x links have a valid data checksum even in case of + // failure, because they do not store any data. + // We do not want to display "OK" in this case. + // For 4.x symlinks we verify the checksum only when extracting, + // but not when testing an archive. + ShowChecksum=false; + } + PrevProcessed=FileCreateMode && LinkSuccess; + } + else + if (!Arc.FileHead.SplitBefore) + if (Arc.FileHead.Method==0) + UnstoreFile(DataIO,Arc.FileHead.UnpSize); + else + { + Unp->Init(Arc.FileHead.WinSize,Arc.FileHead.Solid); + Unp->SetDestSize(Arc.FileHead.UnpSize); +#ifndef SFX_MODULE + if (Arc.Format!=RARFMT50 && Arc.FileHead.UnpVer<=15) + Unp->DoUnpack(15,FileCount>1 && Arc.Solid); + else +#endif + Unp->DoUnpack(Arc.FileHead.UnpVer,Arc.FileHead.Solid); + } + + Arc.SeekToNext(); + + // We check for "split after" flag to detect partially extracted files + // from incomplete volume sets. For them file header contains packed + // data hash, which must not be compared against unpacked data hash + // to prevent accidental match. Moreover, for -m0 volumes packed data + // hash would match truncated unpacked data hash and lead to fake "OK" + // in incomplete volume set. + bool ValidCRC=!Arc.FileHead.SplitAfter && DataIO.UnpHash.Cmp(&Arc.FileHead.FileHash,Arc.FileHead.UseHashKey ? Arc.FileHead.HashKey:NULL); + + // We set AnySolidDataUnpackedWell to true if we found at least one + // valid non-zero solid file in preceding solid stream. If it is true + // and if current encrypted file is broken, we do not need to hint + // about a wrong password and can report CRC error only. + if (!Arc.FileHead.Solid) + AnySolidDataUnpackedWell=false; // Reset the flag, because non-solid file is found. + else + if (Arc.FileHead.Method!=0 && Arc.FileHead.UnpSize>0 && ValidCRC) + AnySolidDataUnpackedWell=true; + + bool BrokenFile=false; + + // Checksum is not calculated in skip solid mode for performance reason. + if (!SkipSolid && ShowChecksum) + { + if (ValidCRC) + { + if (Command!='P' && Command!='I') + mprintf(L"%s%s ",Cmd->DisablePercentage ? L" ":L"\b\b\b\b\b ", + Arc.FileHead.FileHash.Type==HASH_NONE ? L" ?":St(MOk)); + } + else + { + if (Arc.FileHead.Encrypted && (!Arc.FileHead.UsePswCheck || + Arc.BrokenHeader) && !AnySolidDataUnpackedWell) + uiMsg(UIERROR_CHECKSUMENC,Arc.FileName,ArcFileName); + else + uiMsg(UIERROR_CHECKSUM,Arc.FileName,ArcFileName); + BrokenFile=true; + ErrHandler.SetErrorCode(RARX_CRC); +#ifdef RARDLL + // If we already have ERAR_EOPEN as result of missing volume + // or ERAR_BAD_PASSWORD for RAR5 wrong password, + // we should not replace it with less precise ERAR_BAD_DATA. + if (Cmd->DllError!=ERAR_EOPEN && Cmd->DllError!=ERAR_BAD_PASSWORD) + Cmd->DllError=ERAR_BAD_DATA; +#endif + } + } + else + mprintf(L"\b\b\b\b\b "); + + if (!TestMode && (Command=='X' || Command=='E') && + (!LinkEntry || Arc.FileHead.RedirType==FSREDIR_FILECOPY && LinkSuccess) && + (!BrokenFile || Cmd->KeepBroken)) + { + // We could preallocate more space that really written to broken file. + if (BrokenFile) + CurFile.Truncate(); + +#if defined(_WIN_ALL) || defined(_EMX) + if (Cmd->ClearArc) + Arc.FileHead.FileAttr&=~FILE_ATTRIBUTE_ARCHIVE; +#endif + + + CurFile.SetOpenFileTime( + Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime, + Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.FileHead.ctime, + Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime); + CurFile.Close(); +#if defined(_WIN_ALL) && !defined(SFX_MODULE) + if (Cmd->SetCompressedAttr && + (Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0) + SetFileCompression(CurFile.FileName,true); +#endif + SetFileHeaderExtra(Cmd,Arc,CurFile.FileName); + + CurFile.SetCloseFileTime( + Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime, + Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime); + if (!Cmd->IgnoreGeneralAttr && !SetFileAttr(CurFile.FileName,Arc.FileHead.FileAttr)) + uiMsg(UIERROR_FILEATTR,Arc.FileName,CurFile.FileName); + + PrevProcessed=true; + } + } + } + // It is important to increment it for files, but not dirs. So we extract + // dir with its entire contents, not just dir record only even if dir + // record precedes files. + if (MatchFound) + MatchedArgs++; + if (DataIO.NextVolumeMissing) + return false; + if (!ExtrFile) + if (!Arc.Solid) + Arc.SeekToNext(); + else + if (!SkipSolid) + return false; + return true; +} + + +void CmdExtract::UnstoreFile(ComprDataIO &DataIO,int64 DestUnpSize) +{ + Array Buffer(File::CopyBufferSize()); + while (true) + { + int ReadSize=DataIO.UnpRead(&Buffer[0],Buffer.Size()); + if (ReadSize<=0) + break; + int WriteSize=ReadSize0) + { + DataIO.UnpWrite(&Buffer[0],WriteSize); + DestUnpSize-=WriteSize; + } + } +} + + +bool CmdExtract::ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize) +{ + SlashToNative(NameExisting,NameExisting,NameExistingSize); // Not needed for RAR 5.1+ archives. + + File Existing; + if (!Existing.WOpen(NameExisting)) + { + uiMsg(UIERROR_FILECOPY,ArcName,NameExisting,NameNew); + uiMsg(UIERROR_FILECOPYHINT,ArcName); +#ifdef RARDLL + Cmd->DllError=ERAR_EREFERENCE; +#endif + return false; + } + + Array Buffer(0x100000); + int64 CopySize=0; + + while (true) + { + Wait(); + int ReadSize=Existing.Read(&Buffer[0],Buffer.Size()); + if (ReadSize==0) + break; + New.Write(&Buffer[0],ReadSize); + CopySize+=ReadSize; + } + + return true; +} + + +void CmdExtract::ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize) +{ + wcsncpyz(DestName,Cmd->ExtrPath,DestSize); + + if (*Cmd->ExtrPath!=0) + { + wchar LastChar=*PointToLastChar(Cmd->ExtrPath); + // We need IsPathDiv check here to correctly handle Unix forward slash + // in the end of destination path in Windows: rar x arc dest/ + // IsDriveDiv is needed for current drive dir: rar x arc d: + if (!IsPathDiv(LastChar) && !IsDriveDiv(LastChar)) + { + // Destination path can be without trailing slash if it come from GUI shell. + AddEndSlash(DestName,DestSize); + } + } + +#ifndef SFX_MODULE + if (Cmd->AppendArcNameToPath) + { + wcsncatz(DestName,PointToName(Arc.FirstVolumeName),DestSize); + SetExt(DestName,NULL,DestSize); + AddEndSlash(DestName,DestSize); + } +#endif + +#ifndef SFX_MODULE + size_t ArcPathLength=wcslen(Cmd->ArcPath); + if (ArcPathLength>0) + { + size_t NameLength=wcslen(ArcFileName); + + // Earlier we compared lengths only here, but then noticed a cosmetic bug + // in WinRAR. When extracting a file reference from subfolder with + // "Extract relative paths", so WinRAR sets ArcPath, if reference target + // is missing, error message removed ArcPath both from reference and target + // names. If target was stored in another folder, its name looked wrong. + if (NameLength>=ArcPathLength && + wcsnicompc(Cmd->ArcPath,ArcFileName,ArcPathLength)==0 && + (IsPathDiv(Cmd->ArcPath[ArcPathLength-1]) || + IsPathDiv(ArcFileName[ArcPathLength]) || ArcFileName[ArcPathLength]==0)) + { + ArcFileName+=Min(ArcPathLength,NameLength); + while (IsPathDiv(*ArcFileName)) + ArcFileName++; + if (*ArcFileName==0) // Excessive -ap switch. + { + *DestName=0; + return; + } + } + } +#endif + + wchar Command=Cmd->Command[0]; + // Use -ep3 only in systems, where disk letters are exist, not in Unix. + bool AbsPaths=Cmd->ExclPath==EXCL_ABSPATH && Command=='X' && IsDriveDiv(':'); + + // We do not use any user specified destination paths when extracting + // absolute paths in -ep3 mode. + if (AbsPaths) + *DestName=0; + + if (Command=='E' || Cmd->ExclPath==EXCL_SKIPWHOLEPATH) + wcsncatz(DestName,PointToName(ArcFileName),DestSize); + else + wcsncatz(DestName,ArcFileName,DestSize); + +#ifdef _WIN_ALL + // Must do after Cmd->ArcPath processing above, so file name and arc path + // trailing spaces are in sync. + if (!Cmd->AllowIncompatNames) + MakeNameCompatible(DestName); +#endif + + wchar DiskLetter=toupperw(DestName[0]); + + if (AbsPaths) + { + if (DestName[1]=='_' && IsPathDiv(DestName[2]) && + DiskLetter>='A' && DiskLetter<='Z') + DestName[1]=':'; + else + if (DestName[0]=='_' && DestName[1]=='_') + { + // Convert __server\share to \\server\share. + DestName[0]=CPATHDIVIDER; + DestName[1]=CPATHDIVIDER; + } + } +} + + +#ifdef RARDLL +bool CmdExtract::ExtrDllGetPassword() +{ + if (!Cmd->Password.IsSet()) + { + if (Cmd->Callback!=NULL) + { + wchar PasswordW[MAXPASSWORD]; + *PasswordW=0; + if (Cmd->Callback(UCM_NEEDPASSWORDW,Cmd->UserData,(LPARAM)PasswordW,ASIZE(PasswordW))==-1) + *PasswordW=0; + if (*PasswordW==0) + { + char PasswordA[MAXPASSWORD]; + *PasswordA=0; + if (Cmd->Callback(UCM_NEEDPASSWORD,Cmd->UserData,(LPARAM)PasswordA,ASIZE(PasswordA))==-1) + *PasswordA=0; + GetWideName(PasswordA,NULL,PasswordW,ASIZE(PasswordW)); + cleandata(PasswordA,sizeof(PasswordA)); + } + Cmd->Password.Set(PasswordW); + cleandata(PasswordW,sizeof(PasswordW)); + Cmd->ManualPassword=true; + } + if (!Cmd->Password.IsSet()) + return false; + } + return true; +} +#endif + + +#ifndef RARDLL +bool CmdExtract::ExtrGetPassword(Archive &Arc,const wchar *ArcFileName) +{ + if (!Cmd->Password.IsSet()) + { + if (!uiGetPassword(UIPASSWORD_FILE,ArcFileName,&Cmd->Password)/* || !Cmd->Password.IsSet()*/) + { + // Suppress "test is ok" message if user cancelled the password prompt. + uiMsg(UIERROR_INCERRCOUNT); + return false; + } + Cmd->ManualPassword=true; + } +#if !defined(SILENT) + else + if (!PasswordAll && !Arc.FileHead.Solid) + { + eprintf(St(MUseCurPsw),ArcFileName); + switch(Cmd->AllYes ? 1 : Ask(St(MYesNoAll))) + { + case -1: + ErrHandler.Exit(RARX_USERBREAK); + case 2: + if (!uiGetPassword(UIPASSWORD_FILE,ArcFileName,&Cmd->Password)) + return false; + break; + case 3: + PasswordAll=true; + break; + } + } +#endif + return true; +} +#endif + + +#if defined(_WIN_ALL) && !defined(SFX_MODULE) +void CmdExtract::ConvertDosPassword(Archive &Arc,SecPassword &DestPwd) +{ + if (Arc.Format==RARFMT15 && Arc.FileHead.HostOS==HOST_MSDOS) + { + // We need the password in OEM encoding if file was encrypted by + // native RAR/DOS (not extender based). Let's make the conversion. + wchar PlainPsw[MAXPASSWORD]; + Cmd->Password.Get(PlainPsw,ASIZE(PlainPsw)); + char PswA[MAXPASSWORD]; + CharToOemBuffW(PlainPsw,PswA,ASIZE(PswA)); + PswA[ASIZE(PswA)-1]=0; + CharToWide(PswA,PlainPsw,ASIZE(PlainPsw)); + DestPwd.Set(PlainPsw); + cleandata(PlainPsw,sizeof(PlainPsw)); + cleandata(PswA,sizeof(PswA)); + } +} +#endif + + +void CmdExtract::ExtrCreateDir(Archive &Arc,const wchar *ArcFileName) +{ + if (Cmd->Test) + { + mprintf(St(MExtrTestFile),ArcFileName); + mprintf(L" %s",St(MOk)); + return; + } + + MKDIR_CODE MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr); + bool DirExist=false; + if (MDCode!=MKDIR_SUCCESS) + { + DirExist=FileExist(DestFileName); + if (DirExist && !IsDir(GetFileAttr(DestFileName))) + { + // File with name same as this directory exists. Propose user + // to overwrite it. + bool UserReject; + FileCreate(Cmd,NULL,DestFileName,ASIZE(DestFileName),&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime); + DirExist=false; + } + if (!DirExist) + { + CreatePath(DestFileName,true); + MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr); + if (MDCode!=MKDIR_SUCCESS) + { + wchar OrigName[ASIZE(DestFileName)]; + wcsncpyz(OrigName,DestFileName,ASIZE(OrigName)); + MakeNameUsable(DestFileName,true); + CreatePath(DestFileName,true); + MDCode=MakeDir(DestFileName,!Cmd->IgnoreGeneralAttr,Arc.FileHead.FileAttr); +#ifndef SFX_MODULE + if (MDCode==MKDIR_SUCCESS) + uiMsg(UIERROR_RENAMING,Arc.FileName,OrigName,DestFileName); +#endif + } + } + } + if (MDCode==MKDIR_SUCCESS) + { + mprintf(St(MCreatDir),DestFileName); + mprintf(L" %s",St(MOk)); + PrevProcessed=true; + } + else + if (DirExist) + { + if (!Cmd->IgnoreGeneralAttr) + SetFileAttr(DestFileName,Arc.FileHead.FileAttr); + PrevProcessed=true; + } + else + { + uiMsg(UIERROR_DIRCREATE,Arc.FileName,DestFileName); + ErrHandler.SysErrMsg(); +#ifdef RARDLL + Cmd->DllError=ERAR_ECREATE; +#endif + ErrHandler.SetErrorCode(RARX_CREATE); + } + if (PrevProcessed) + { +#if defined(_WIN_ALL) && !defined(SFX_MODULE) + if (Cmd->SetCompressedAttr && + (Arc.FileHead.FileAttr & FILE_ATTRIBUTE_COMPRESSED)!=0 && WinNT()) + SetFileCompression(DestFileName,true); +#endif + SetFileHeaderExtra(Cmd,Arc,DestFileName); + SetDirTime(DestFileName, + Cmd->xmtime==EXTTIME_NONE ? NULL:&Arc.FileHead.mtime, + Cmd->xctime==EXTTIME_NONE ? NULL:&Arc.FileHead.ctime, + Cmd->xatime==EXTTIME_NONE ? NULL:&Arc.FileHead.atime); + } +} + + +bool CmdExtract::ExtrCreateFile(Archive &Arc,File &CurFile) +{ + bool Success=true; + wchar Command=Cmd->Command[0]; +#if !defined(SFX_MODULE) + if (Command=='P') + CurFile.SetHandleType(FILE_HANDLESTD); +#endif + if ((Command=='E' || Command=='X') && !Cmd->Test) + { + bool UserReject; + // Specify "write only" mode to avoid OpenIndiana NAS problems + // with SetFileTime and read+write files. + if (!FileCreate(Cmd,&CurFile,DestFileName,ASIZE(DestFileName),&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime,true)) + { + Success=false; + if (!UserReject) + { + ErrHandler.CreateErrorMsg(Arc.FileName,DestFileName); +#ifdef RARDLL + Cmd->DllError=ERAR_ECREATE; +#endif + if (!IsNameUsable(DestFileName)) + { + uiMsg(UIMSG_CORRECTINGNAME,Arc.FileName); + + wchar OrigName[ASIZE(DestFileName)]; + wcsncpyz(OrigName,DestFileName,ASIZE(OrigName)); + + MakeNameUsable(DestFileName,true); + + CreatePath(DestFileName,true); + if (FileCreate(Cmd,&CurFile,DestFileName,ASIZE(DestFileName),&UserReject,Arc.FileHead.UnpSize,&Arc.FileHead.mtime,true)) + { +#ifndef SFX_MODULE + uiMsg(UIERROR_RENAMING,Arc.FileName,OrigName,DestFileName); +#endif + Success=true; + } + else + ErrHandler.CreateErrorMsg(Arc.FileName,DestFileName); + } + } + } + } + return Success; +} + + +bool CmdExtract::CheckUnpVer(Archive &Arc,const wchar *ArcFileName) +{ + bool WrongVer; + if (Arc.Format==RARFMT50) // Both SFX and RAR can unpack RAR 5.0 archives. + WrongVer=Arc.FileHead.UnpVer>VER_UNPACK5; + else + { +#ifdef SFX_MODULE // SFX can unpack only RAR 2.9 archives. + WrongVer=Arc.FileHead.UnpVer!=VER_UNPACK; +#else // All formats since 1.3 for RAR. + WrongVer=Arc.FileHead.UnpVer<13 || Arc.FileHead.UnpVer>VER_UNPACK; +#endif + } + + // We can unpack stored files regardless of compression version field. + if (Arc.FileHead.Method==0) + WrongVer=false; + + if (WrongVer) + { + ErrHandler.UnknownMethodMsg(Arc.FileName,ArcFileName); + uiMsg(UIERROR_NEWERRAR,Arc.FileName); + } + return !WrongVer; +} diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/extract.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/extract.hpp new file mode 100644 index 0000000..85a21f5 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/extract.hpp @@ -0,0 +1,62 @@ +#ifndef _RAR_EXTRACT_ +#define _RAR_EXTRACT_ + +enum EXTRACT_ARC_CODE {EXTRACT_ARC_NEXT,EXTRACT_ARC_REPEAT}; + +class CmdExtract +{ + private: + EXTRACT_ARC_CODE ExtractArchive(); + bool ExtractFileCopy(File &New,wchar *ArcName,wchar *NameNew,wchar *NameExisting,size_t NameExistingSize); + void ExtrPrepareName(Archive &Arc,const wchar *ArcFileName,wchar *DestName,size_t DestSize); +#ifdef RARDLL + bool ExtrDllGetPassword(); +#else + bool ExtrGetPassword(Archive &Arc,const wchar *ArcFileName); +#endif +#if defined(_WIN_ALL) && !defined(SFX_MODULE) + void ConvertDosPassword(Archive &Arc,SecPassword &DestPwd); +#endif + void ExtrCreateDir(Archive &Arc,const wchar *ArcFileName); + bool ExtrCreateFile(Archive &Arc,File &CurFile); + bool CheckUnpVer(Archive &Arc,const wchar *ArcFileName); + + RarTime StartTime; // time when extraction started + + CommandData *Cmd; + + ComprDataIO DataIO; + Unpack *Unp; + unsigned long TotalFileCount; + + unsigned long FileCount; + unsigned long MatchedArgs; + bool FirstFile; + bool AllMatchesExact; + bool ReconstructDone; + + // If any non-zero solid file was successfully unpacked before current. + // If true and if current encrypted file is broken, obviously + // the password is correct and we can report broken CRC without + // any wrong password hints. + bool AnySolidDataUnpackedWell; + + wchar ArcName[NM]; + + bool PasswordAll; + bool PrevProcessed; // If previous file was successfully extracted or tested. + wchar DestFileName[NM]; + bool PasswordCancelled; +#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT) + bool Fat32,NotFat32; +#endif + public: + CmdExtract(CommandData *Cmd); + ~CmdExtract(); + void DoExtract(); + void ExtractArchiveInit(Archive &Arc); + bool ExtractCurrentFile(Archive &Arc,size_t HeaderSize,bool &Repeat); + static void UnstoreFile(ComprDataIO &DataIO,int64 DestUnpSize); +}; + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/filcreat.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/filcreat.cpp new file mode 100644 index 0000000..a64a7d4 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/filcreat.cpp @@ -0,0 +1,163 @@ +#include "rar.hpp" + +// If NewFile==NULL, we delete created file after user confirmation. +// It is useful we we need to overwrite an existing folder or file, +// but need user confirmation for that. +bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize, + bool *UserReject,int64 FileSize,RarTime *FileTime,bool WriteOnly) +{ + if (UserReject!=NULL) + *UserReject=false; +#ifdef _WIN_ALL + bool ShortNameChanged=false; +#endif + while (FileExist(Name)) + { +#if defined(_WIN_ALL) + if (!ShortNameChanged) + { + // Avoid the infinite loop if UpdateExistingShortName returns + // the same name. + ShortNameChanged=true; + + // Maybe our long name matches the short name of existing file. + // Let's check if we can change the short name. + if (UpdateExistingShortName(Name)) + continue; + } + // Allow short name check again. It is necessary, because rename and + // autorename below can change the name, so we need to check it again. + ShortNameChanged=false; +#endif + UIASKREP_RESULT Choice=uiAskReplaceEx(Cmd,Name,MaxNameSize,FileSize,FileTime,(NewFile==NULL ? UIASKREP_F_NORENAME:0)); + + if (Choice==UIASKREP_R_REPLACE) + break; + if (Choice==UIASKREP_R_SKIP) + { + if (UserReject!=NULL) + *UserReject=true; + return false; + } + if (Choice==UIASKREP_R_CANCEL) + ErrHandler.Exit(RARX_USERBREAK); + } + + // Try to truncate the existing file first instead of delete, + // so we preserve existing file permissions such as NTFS permissions. + uint FileMode=WriteOnly ? FMF_WRITE|FMF_SHAREREAD:FMF_UPDATE|FMF_SHAREREAD; + if (NewFile!=NULL && NewFile->Create(Name,FileMode)) + return true; + + CreatePath(Name,true); + return NewFile!=NULL ? NewFile->Create(Name,FileMode):DelFile(Name); +} + + +bool GetAutoRenamedName(wchar *Name,size_t MaxNameSize) +{ + wchar NewName[NM]; + size_t NameLength=wcslen(Name); + wchar *Ext=GetExt(Name); + if (Ext==NULL) + Ext=Name+NameLength; + for (uint FileVer=1;;FileVer++) + { + swprintf(NewName,ASIZE(NewName),L"%.*ls(%u)%ls",uint(Ext-Name),Name,FileVer,Ext); + if (!FileExist(NewName)) + { + wcsncpyz(Name,NewName,MaxNameSize); + break; + } + if (FileVer>=1000000) + return false; + } + return true; +} + + +#if defined(_WIN_ALL) +// If we find a file, which short name is equal to 'Name', we try to change +// its short name, while preserving the long name. It helps when unpacking +// an archived file, which long name is equal to short name of already +// existing file. Otherwise we would overwrite the already existing file, +// even though its long name does not match the name of unpacking file. +bool UpdateExistingShortName(const wchar *Name) +{ + wchar LongPathName[NM]; + DWORD Res=GetLongPathName(Name,LongPathName,ASIZE(LongPathName)); + if (Res==0 || Res>=ASIZE(LongPathName)) + return false; + wchar ShortPathName[NM]; + Res=GetShortPathName(Name,ShortPathName,ASIZE(ShortPathName)); + if (Res==0 || Res>=ASIZE(ShortPathName)) + return false; + wchar *LongName=PointToName(LongPathName); + wchar *ShortName=PointToName(ShortPathName); + + // We continue only if file has a short name, which does not match its + // long name, and this short name is equal to name of file which we need + // to create. + if (*ShortName==0 || wcsicomp(LongName,ShortName)==0 || + wcsicomp(PointToName(Name),ShortName)!=0) + return false; + + // Generate the temporary new name for existing file. + wchar NewName[NM]; + *NewName=0; + for (int I=0;I<10000 && *NewName==0;I+=123) + { + // Here we copy the path part of file to create. We'll make the temporary + // file in the same folder. + wcsncpyz(NewName,Name,ASIZE(NewName)); + + // Here we set the random name part. + swprintf(PointToName(NewName),ASIZE(NewName),L"rtmp%d",I); + + // If such file is already exist, try next random name. + if (FileExist(NewName)) + *NewName=0; + } + + // If we could not generate the name not used by any other file, we return. + if (*NewName==0) + return false; + + // FastFind returns the name without path, but we need the fully qualified + // name for renaming, so we use the path from file to create and long name + // from existing file. + wchar FullName[NM]; + wcsncpyz(FullName,Name,ASIZE(FullName)); + SetName(FullName,LongName,ASIZE(FullName)); + + // Rename the existing file to randomly generated name. Normally it changes + // the short name too. + if (!MoveFile(FullName,NewName)) + return false; + + // Now we need to create the temporary empty file with same name as + // short name of our already existing file. We do it to occupy its previous + // short name and not allow to use it again when renaming the file back to + // its original long name. + File KeepShortFile; + bool Created=false; + if (!FileExist(Name)) + Created=KeepShortFile.Create(Name,FMF_WRITE|FMF_SHAREREAD); + + // Now we rename the existing file from temporary name to original long name. + // Since its previous short name is occupied by another file, it should + // get another short name. + MoveFile(NewName,FullName); + + if (Created) + { + // Delete the temporary zero length file occupying the short name, + KeepShortFile.Close(); + KeepShortFile.Delete(); + } + // We successfully changed the short name. Maybe sometimes we'll simplify + // this function by use of SetFileShortName Windows API call. + // But SetFileShortName is not available in older Windows. + return true; +} +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/filcreat.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/filcreat.hpp new file mode 100644 index 0000000..44f801d --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/filcreat.hpp @@ -0,0 +1,14 @@ +#ifndef _RAR_FILECREATE_ +#define _RAR_FILECREATE_ + +bool FileCreate(RAROptions *Cmd,File *NewFile,wchar *Name,size_t MaxNameSize, + bool *UserReject,int64 FileSize=INT64NDF, + RarTime *FileTime=NULL,bool WriteOnly=false); + +bool GetAutoRenamedName(wchar *Name,size_t MaxNameSize); + +#if defined(_WIN_ALL) +bool UpdateExistingShortName(const wchar *Name); +#endif + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/file.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/file.cpp new file mode 100644 index 0000000..e2bb42a --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/file.cpp @@ -0,0 +1,729 @@ +#include "rar.hpp" + +File::File() +{ + hFile=FILE_BAD_HANDLE; + *FileName=0; + NewFile=false; + LastWrite=false; + HandleType=FILE_HANDLENORMAL; + SkipClose=false; + IgnoreReadErrors=false; + ErrorType=FILE_SUCCESS; + OpenShared=false; + AllowDelete=true; + AllowExceptions=true; +#ifdef _WIN_ALL + NoSequentialRead=false; + CreateMode=FMF_UNDEFINED; +#endif +} + + +File::~File() +{ + if (hFile!=FILE_BAD_HANDLE && !SkipClose) + if (NewFile) + Delete(); + else + Close(); +} + + +void File::operator = (File &SrcFile) +{ + hFile=SrcFile.hFile; + NewFile=SrcFile.NewFile; + LastWrite=SrcFile.LastWrite; + HandleType=SrcFile.HandleType; + wcsncpyz(FileName,SrcFile.FileName,ASIZE(FileName)); + SrcFile.SkipClose=true; +} + + +bool File::Open(const wchar *Name,uint Mode) +{ + ErrorType=FILE_SUCCESS; + FileHandle hNewFile; + bool OpenShared=File::OpenShared || (Mode & FMF_OPENSHARED)!=0; + bool UpdateMode=(Mode & FMF_UPDATE)!=0; + bool WriteMode=(Mode & FMF_WRITE)!=0; +#ifdef _WIN_ALL + uint Access=WriteMode ? GENERIC_WRITE:GENERIC_READ; + if (UpdateMode) + Access|=GENERIC_WRITE; + uint ShareMode=(Mode & FMF_OPENEXCLUSIVE) ? 0 : FILE_SHARE_READ; + if (OpenShared) + ShareMode|=FILE_SHARE_WRITE; + uint Flags=NoSequentialRead ? 0:FILE_FLAG_SEQUENTIAL_SCAN; + hNewFile=CreateFile(Name,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL); + + DWORD LastError; + if (hNewFile==FILE_BAD_HANDLE) + { + LastError=GetLastError(); + + wchar LongName[NM]; + if (GetWinLongPath(Name,LongName,ASIZE(LongName))) + { + hNewFile=CreateFile(LongName,Access,ShareMode,NULL,OPEN_EXISTING,Flags,NULL); + + // For archive names longer than 260 characters first CreateFile + // (without \\?\) fails and sets LastError to 3 (access denied). + // We need the correct "file not found" error code to decide + // if we create a new archive or quit with "cannot create" error. + // So we need to check the error code after \\?\ CreateFile again, + // otherwise we'll fail to create new archives with long names. + // But we cannot simply assign the new code to LastError, + // because it would break "..\arcname.rar" relative names processing. + // First CreateFile returns the correct "file not found" code for such + // names, but "\\?\" CreateFile returns ERROR_INVALID_NAME treating + // dots as a directory name. So we check only for "file not found" + // error here and for other errors use the first CreateFile result. + if (GetLastError()==ERROR_FILE_NOT_FOUND) + LastError=ERROR_FILE_NOT_FOUND; + } + } + if (hNewFile==FILE_BAD_HANDLE && LastError==ERROR_FILE_NOT_FOUND) + ErrorType=FILE_NOTFOUND; + +#else + int flags=UpdateMode ? O_RDWR:(WriteMode ? O_WRONLY:O_RDONLY); +#ifdef O_BINARY + flags|=O_BINARY; +#if defined(_AIX) && defined(_LARGE_FILE_API) + flags|=O_LARGEFILE; +#endif +#endif + char NameA[NM]; + WideToChar(Name,NameA,ASIZE(NameA)); + + int handle=open(NameA,flags); +#ifdef LOCK_EX + +#ifdef _OSF_SOURCE + extern "C" int flock(int, int); +#endif + + if (!OpenShared && UpdateMode && handle>=0 && flock(handle,LOCK_EX|LOCK_NB)==-1) + { + close(handle); + return false; + } +#endif + if (handle==-1) + hNewFile=FILE_BAD_HANDLE; + else + { +#ifdef FILE_USE_OPEN + hNewFile=handle; +#else + hNewFile=fdopen(handle,UpdateMode ? UPDATEBINARY:READBINARY); +#endif + } + if (hNewFile==FILE_BAD_HANDLE && errno==ENOENT) + ErrorType=FILE_NOTFOUND; +#endif + NewFile=false; + HandleType=FILE_HANDLENORMAL; + SkipClose=false; + bool Success=hNewFile!=FILE_BAD_HANDLE; + if (Success) + { + hFile=hNewFile; + wcsncpyz(FileName,Name,ASIZE(FileName)); + } + return Success; +} + + +#if !defined(SFX_MODULE) +void File::TOpen(const wchar *Name) +{ + if (!WOpen(Name)) + ErrHandler.Exit(RARX_OPEN); +} +#endif + + +bool File::WOpen(const wchar *Name) +{ + if (Open(Name)) + return true; + ErrHandler.OpenErrorMsg(Name); + return false; +} + + +bool File::Create(const wchar *Name,uint Mode) +{ + // OpenIndiana based NAS and CIFS shares fail to set the file time if file + // was created in read+write mode and some data was written and not flushed + // before SetFileTime call. So we should use the write only mode if we plan + // SetFileTime call and do not need to read from file. + bool WriteMode=(Mode & FMF_WRITE)!=0; + bool ShareRead=(Mode & FMF_SHAREREAD)!=0 || File::OpenShared; +#ifdef _WIN_ALL + CreateMode=Mode; + uint Access=WriteMode ? GENERIC_WRITE:GENERIC_READ|GENERIC_WRITE; + DWORD ShareMode=ShareRead ? FILE_SHARE_READ:0; + + // Windows automatically removes dots and spaces in the end of file name, + // So we detect such names and process them with \\?\ prefix. + wchar *LastChar=PointToLastChar(Name); + bool Special=*LastChar=='.' || *LastChar==' '; + + if (Special && (Mode & FMF_STANDARDNAMES)==0) + hFile=FILE_BAD_HANDLE; + else + hFile=CreateFile(Name,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL); + + if (hFile==FILE_BAD_HANDLE) + { + wchar LongName[NM]; + if (GetWinLongPath(Name,LongName,ASIZE(LongName))) + hFile=CreateFile(LongName,Access,ShareMode,NULL,CREATE_ALWAYS,0,NULL); + } + +#else + char NameA[NM]; + WideToChar(Name,NameA,ASIZE(NameA)); +#ifdef FILE_USE_OPEN + hFile=open(NameA,(O_CREAT|O_TRUNC) | (WriteMode ? O_WRONLY : O_RDWR),0666); +#else + hFile=fopen(NameA,WriteMode ? WRITEBINARY:CREATEBINARY); +#endif +#endif + NewFile=true; + HandleType=FILE_HANDLENORMAL; + SkipClose=false; + wcsncpyz(FileName,Name,ASIZE(FileName)); + return hFile!=FILE_BAD_HANDLE; +} + + +#if !defined(SFX_MODULE) +void File::TCreate(const wchar *Name,uint Mode) +{ + if (!WCreate(Name,Mode)) + ErrHandler.Exit(RARX_FATAL); +} +#endif + + +bool File::WCreate(const wchar *Name,uint Mode) +{ + if (Create(Name,Mode)) + return true; + ErrHandler.CreateErrorMsg(Name); + return false; +} + + +bool File::Close() +{ + bool Success=true; + + if (hFile!=FILE_BAD_HANDLE) + { + if (!SkipClose) + { +#ifdef _WIN_ALL + // We use the standard system handle for stdout in Windows + // and it must not be closed here. + if (HandleType==FILE_HANDLENORMAL) + Success=CloseHandle(hFile)==TRUE; +#else +#ifdef FILE_USE_OPEN + Success=close(hFile)!=-1; +#else + Success=fclose(hFile)!=EOF; +#endif +#endif + } + hFile=FILE_BAD_HANDLE; + } + HandleType=FILE_HANDLENORMAL; + if (!Success && AllowExceptions) + ErrHandler.CloseError(FileName); + return Success; +} + + +bool File::Delete() +{ + if (HandleType!=FILE_HANDLENORMAL) + return false; + if (hFile!=FILE_BAD_HANDLE) + Close(); + if (!AllowDelete) + return false; + return DelFile(FileName); +} + + +bool File::Rename(const wchar *NewName) +{ + // No need to rename if names are already same. + bool Success=wcscmp(FileName,NewName)==0; + + if (!Success) + Success=RenameFile(FileName,NewName); + + if (Success) + wcscpy(FileName,NewName); + + return Success; +} + + +bool File::Write(const void *Data,size_t Size) +{ + if (Size==0) + return true; + if (HandleType==FILE_HANDLESTD) + { +#ifdef _WIN_ALL + hFile=GetStdHandle(STD_OUTPUT_HANDLE); +#else + // Cannot use the standard stdout here, because it already has wide orientation. + if (hFile==FILE_BAD_HANDLE) + { +#ifdef FILE_USE_OPEN + hFile=dup(STDOUT_FILENO); // Open new stdout stream. +#else + hFile=fdopen(dup(STDOUT_FILENO),"w"); // Open new stdout stream. +#endif + } +#endif + } + bool Success; + while (1) + { + Success=false; +#ifdef _WIN_ALL + DWORD Written=0; + if (HandleType!=FILE_HANDLENORMAL) + { + // writing to stdout can fail in old Windows if data block is too large + const size_t MaxSize=0x4000; + for (size_t I=0;ISize && FilePos-Size<=0xffffffff && FilePos+Size>0xffffffff) + ErrHandler.WriteErrorFAT(FileName); +#endif + if (ErrHandler.AskRepeatWrite(FileName,false)) + { +#if !defined(_WIN_ALL) && !defined(FILE_USE_OPEN) + clearerr(hFile); +#endif + if (Written0) + Seek(Tell()-Written,SEEK_SET); + continue; + } + ErrHandler.WriteError(NULL,FileName); + } + break; + } + LastWrite=true; + return Success; // It can return false only if AllowExceptions is disabled. +} + + +int File::Read(void *Data,size_t Size) +{ + int64 FilePos=0; // Initialized only to suppress some compilers warning. + + if (IgnoreReadErrors) + FilePos=Tell(); + int ReadSize; + while (true) + { + ReadSize=DirectRead(Data,Size); + if (ReadSize==-1) + { + ErrorType=FILE_READERROR; + if (AllowExceptions) + if (IgnoreReadErrors) + { + ReadSize=0; + for (size_t I=0;IMaxDeviceRead) +// Size=MaxDeviceRead; + hFile=GetStdHandle(STD_INPUT_HANDLE); +#else +#ifdef FILE_USE_OPEN + hFile=STDIN_FILENO; +#else + hFile=stdin; +#endif +#endif + } +#ifdef _WIN_ALL + // For pipes like 'type file.txt | rar -si arcname' ReadFile may return + // data in small ~4KB blocks. It may slightly reduce the compression ratio. + DWORD Read; + if (!ReadFile(hFile,Data,(DWORD)Size,&Read,NULL)) + { + if (IsDevice() && Size>MaxDeviceRead) + return DirectRead(Data,MaxDeviceRead); + if (HandleType==FILE_HANDLESTD && GetLastError()==ERROR_BROKEN_PIPE) + return 0; + + // We had a bug report about failure to archive 1C database lock file + // 1Cv8tmp.1CL, which is a zero length file with a region above 200 KB + // permanently locked. If our first read request uses too large buffer + // and if we are in -dh mode, so we were able to open the file, + // we'll fail with "Read error". So now we use try a smaller buffer size + // in case of lock error. + if (HandleType==FILE_HANDLENORMAL && Size>MaxLockedRead && + GetLastError()==ERROR_LOCK_VIOLATION) + return DirectRead(Data,MaxLockedRead); + + return -1; + } + return Read; +#else +#ifdef FILE_USE_OPEN + ssize_t ReadSize=read(hFile,Data,Size); + if (ReadSize==-1) + return -1; + return (int)ReadSize; +#else + if (LastWrite) + { + fflush(hFile); + LastWrite=false; + } + clearerr(hFile); + size_t ReadSize=fread(Data,1,Size,hFile); + if (ferror(hFile)) + return -1; + return (int)ReadSize; +#endif +#endif +} + + +void File::Seek(int64 Offset,int Method) +{ + if (!RawSeek(Offset,Method) && AllowExceptions) + ErrHandler.SeekError(FileName); +} + + +bool File::RawSeek(int64 Offset,int Method) +{ + if (hFile==FILE_BAD_HANDLE) + return true; + if (Offset<0 && Method!=SEEK_SET) + { + Offset=(Method==SEEK_CUR ? Tell():FileLength())+Offset; + Method=SEEK_SET; + } +#ifdef _WIN_ALL + LONG HighDist=(LONG)(Offset>>32); + if (SetFilePointer(hFile,(LONG)Offset,&HighDist,Method)==0xffffffff && + GetLastError()!=NO_ERROR) + return false; +#else + LastWrite=false; +#ifdef FILE_USE_OPEN + if (lseek(hFile,(off_t)Offset,Method)==-1) + return false; +#elif defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE) && !defined(__VMS) + if (fseeko(hFile,Offset,Method)!=0) + return false; +#else + if (fseek(hFile,(long)Offset,Method)!=0) + return false; +#endif +#endif + return true; +} + + +int64 File::Tell() +{ + if (hFile==FILE_BAD_HANDLE) + if (AllowExceptions) + ErrHandler.SeekError(FileName); + else + return -1; +#ifdef _WIN_ALL + LONG HighDist=0; + uint LowDist=SetFilePointer(hFile,0,&HighDist,FILE_CURRENT); + if (LowDist==0xffffffff && GetLastError()!=NO_ERROR) + if (AllowExceptions) + ErrHandler.SeekError(FileName); + else + return -1; + return INT32TO64(HighDist,LowDist); +#else +#ifdef FILE_USE_OPEN + return lseek(hFile,0,SEEK_CUR); +#elif defined(_LARGEFILE_SOURCE) && !defined(_OSF_SOURCE) + return ftello(hFile); +#else + return ftell(hFile); +#endif +#endif +} + + +void File::Prealloc(int64 Size) +{ +#ifdef _WIN_ALL + if (RawSeek(Size,SEEK_SET)) + { + Truncate(); + Seek(0,SEEK_SET); + } +#endif + +#if defined(_UNIX) && defined(USE_FALLOCATE) + // fallocate is rather new call. Only latest kernels support it. + // So we are not using it by default yet. + int fd = GetFD(); + if (fd >= 0) + fallocate(fd, 0, 0, Size); +#endif +} + + +byte File::GetByte() +{ + byte Byte=0; + Read(&Byte,1); + return Byte; +} + + +void File::PutByte(byte Byte) +{ + Write(&Byte,1); +} + + +bool File::Truncate() +{ +#ifdef _WIN_ALL + return SetEndOfFile(hFile)==TRUE; +#else + return ftruncate(GetFD(),(off_t)Tell())==0; +#endif +} + + +void File::Flush() +{ +#ifdef _WIN_ALL + FlushFileBuffers(hFile); +#else +#ifndef FILE_USE_OPEN + fflush(hFile); +#endif + fsync(GetFD()); +#endif +} + + +void File::SetOpenFileTime(RarTime *ftm,RarTime *ftc,RarTime *fta) +{ +#ifdef _WIN_ALL + // Workaround for OpenIndiana NAS time bug. If we cannot create a file + // in write only mode, we need to flush the write buffer before calling + // SetFileTime or file time will not be changed. + if (CreateMode!=FMF_UNDEFINED && (CreateMode & FMF_WRITE)==0) + FlushFileBuffers(hFile); + + bool sm=ftm!=NULL && ftm->IsSet(); + bool sc=ftc!=NULL && ftc->IsSet(); + bool sa=fta!=NULL && fta->IsSet(); + FILETIME fm,fc,fa; + if (sm) + ftm->GetWinFT(&fm); + if (sc) + ftc->GetWinFT(&fc); + if (sa) + fta->GetWinFT(&fa); + SetFileTime(hFile,sc ? &fc:NULL,sa ? &fa:NULL,sm ? &fm:NULL); +#endif +} + + +void File::SetCloseFileTime(RarTime *ftm,RarTime *fta) +{ +// Android APP_PLATFORM := android-14 does not support futimens and futimes. +// Newer platforms support futimens, but fail on Android 4.2. +// We have to use utime for Android. +// Also we noticed futimens fail to set timestamps on NTFS partition +// mounted to virtual Linux x86 machine, but utimensat worked correctly. +// So we set timestamps for already closed files in Unix. +#ifdef _UNIX + SetCloseFileTimeByName(FileName,ftm,fta); +#endif +} + + +void File::SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta) +{ +#ifdef _UNIX + bool setm=ftm!=NULL && ftm->IsSet(); + bool seta=fta!=NULL && fta->IsSet(); + if (setm || seta) + { + char NameA[NM]; + WideToChar(Name,NameA,ASIZE(NameA)); + +#ifdef UNIX_TIME_NS + timespec times[2]; + times[0].tv_sec=seta ? fta->GetUnix() : 0; + times[0].tv_nsec=seta ? long(fta->GetUnixNS()%1000000000) : UTIME_NOW; + times[1].tv_sec=setm ? ftm->GetUnix() : 0; + times[1].tv_nsec=setm ? long(ftm->GetUnixNS()%1000000000) : UTIME_NOW; + utimensat(AT_FDCWD,NameA,times,0); +#else + utimbuf ut; + if (setm) + ut.modtime=ftm->GetUnix(); + else + ut.modtime=fta->GetUnix(); // Need to set something, cannot left it 0. + if (seta) + ut.actime=fta->GetUnix(); + else + ut.actime=ut.modtime; // Need to set something, cannot left it 0. + utime(NameA,&ut); +#endif + } +#endif +} + + +void File::GetOpenFileTime(RarTime *ft) +{ +#ifdef _WIN_ALL + FILETIME FileTime; + GetFileTime(hFile,NULL,NULL,&FileTime); + ft->SetWinFT(&FileTime); +#endif +#if defined(_UNIX) || defined(_EMX) + struct stat st; + fstat(GetFD(),&st); + ft->SetUnix(st.st_mtime); +#endif +} + + +int64 File::FileLength() +{ + SaveFilePos SavePos(*this); + Seek(0,SEEK_END); + return Tell(); +} + + +bool File::IsDevice() +{ + if (hFile==FILE_BAD_HANDLE) + return false; +#ifdef _WIN_ALL + uint Type=GetFileType(hFile); + return Type==FILE_TYPE_CHAR || Type==FILE_TYPE_PIPE; +#else + return isatty(GetFD()); +#endif +} + + +#ifndef SFX_MODULE +int64 File::Copy(File &Dest,int64 Length) +{ + Array Buffer(File::CopyBufferSize()); + int64 CopySize=0; + bool CopyAll=(Length==INT64NDF); + + while (CopyAll || Length>0) + { + Wait(); + size_t SizeToRead=(!CopyAll && Length<(int64)Buffer.Size()) ? (size_t)Length:Buffer.Size(); + byte *Buf=&Buffer[0]; + int ReadSize=Read(Buf,SizeToRead); + if (ReadSize==0) + break; + size_t WriteSize=ReadSize; +#ifdef _WIN_ALL + // For FAT32 USB flash drives in Windows if first write is 4 KB or more, + // write caching is disabled and "write through" is enabled, resulting + // in bad performance, especially for many small files. It happens when + // we create SFX archive on USB drive, because SFX module is written first. + // So we split the first write to small 1 KB followed by rest of data. + if (CopySize==0 && WriteSize>=4096) + { + const size_t FirstWrite=1024; + Dest.Write(Buf,FirstWrite); + Buf+=FirstWrite; + WriteSize-=FirstWrite; + } +#endif + Dest.Write(Buf,WriteSize); + CopySize+=ReadSize; + if (!CopyAll) + Length-=ReadSize; + } + return CopySize; +} +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/file.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/file.hpp new file mode 100644 index 0000000..f99336a --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/file.hpp @@ -0,0 +1,140 @@ +#ifndef _RAR_FILE_ +#define _RAR_FILE_ + +#define FILE_USE_OPEN + +#ifdef _WIN_ALL + typedef HANDLE FileHandle; + #define FILE_BAD_HANDLE INVALID_HANDLE_VALUE +#elif defined(FILE_USE_OPEN) + typedef off_t FileHandle; + #define FILE_BAD_HANDLE -1 +#else + typedef FILE* FileHandle; + #define FILE_BAD_HANDLE NULL +#endif + +class RAROptions; + +enum FILE_HANDLETYPE {FILE_HANDLENORMAL,FILE_HANDLESTD}; + +enum FILE_ERRORTYPE {FILE_SUCCESS,FILE_NOTFOUND,FILE_READERROR}; + +enum FILE_MODE_FLAGS { + // Request read only access to file. Default for Open. + FMF_READ=0, + + // Request both read and write access to file. Default for Create. + FMF_UPDATE=1, + + // Request write only access to file. + FMF_WRITE=2, + + // Open files which are already opened for write by other programs. + FMF_OPENSHARED=4, + + // Open files only if no other program is opened it even in shared mode. + FMF_OPENEXCLUSIVE=8, + + // Provide read access to created file for other programs. + FMF_SHAREREAD=16, + + // Use standard NTFS names without trailing dots and spaces. + FMF_STANDARDNAMES=32, + + // Mode flags are not defined yet. + FMF_UNDEFINED=256 +}; + + +class File +{ + private: + FileHandle hFile; + bool LastWrite; + FILE_HANDLETYPE HandleType; + bool SkipClose; + bool IgnoreReadErrors; + bool NewFile; + bool AllowDelete; + bool AllowExceptions; +#ifdef _WIN_ALL + bool NoSequentialRead; + uint CreateMode; +#endif + protected: + bool OpenShared; // Set by 'Archive' class. + public: + wchar FileName[NM]; + + FILE_ERRORTYPE ErrorType; + public: + File(); + virtual ~File(); + void operator = (File &SrcFile); + + // Several functions below are 'virtual', because they are redefined + // by Archive for QOpen and by MultiFile for split files in WinRAR. + virtual bool Open(const wchar *Name,uint Mode=FMF_READ); + void TOpen(const wchar *Name); + bool WOpen(const wchar *Name); + bool Create(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD); + void TCreate(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD); + bool WCreate(const wchar *Name,uint Mode=FMF_UPDATE|FMF_SHAREREAD); + virtual bool Close(); // 'virtual' for MultiFile class. + bool Delete(); + bool Rename(const wchar *NewName); + bool Write(const void *Data,size_t Size); + virtual int Read(void *Data,size_t Size); + int DirectRead(void *Data,size_t Size); + virtual void Seek(int64 Offset,int Method); + bool RawSeek(int64 Offset,int Method); + virtual int64 Tell(); + void Prealloc(int64 Size); + byte GetByte(); + void PutByte(byte Byte); + bool Truncate(); + void Flush(); + void SetOpenFileTime(RarTime *ftm,RarTime *ftc=NULL,RarTime *fta=NULL); + void SetCloseFileTime(RarTime *ftm,RarTime *fta=NULL); + static void SetCloseFileTimeByName(const wchar *Name,RarTime *ftm,RarTime *fta); + void GetOpenFileTime(RarTime *ft); + virtual bool IsOpened() {return hFile!=FILE_BAD_HANDLE;}; // 'virtual' for MultiFile class. + int64 FileLength(); + void SetHandleType(FILE_HANDLETYPE Type) {HandleType=Type;} + FILE_HANDLETYPE GetHandleType() {return HandleType;} + bool IsDevice(); + static bool RemoveCreated(); + FileHandle GetHandle() {return hFile;} + void SetHandle(FileHandle Handle) {Close();hFile=Handle;} + void SetIgnoreReadErrors(bool Mode) {IgnoreReadErrors=Mode;} + int64 Copy(File &Dest,int64 Length=INT64NDF); + void SetAllowDelete(bool Allow) {AllowDelete=Allow;} + void SetExceptions(bool Allow) {AllowExceptions=Allow;} +#ifdef _WIN_ALL + void RemoveSequentialFlag() {NoSequentialRead=true;} +#endif +#ifdef _UNIX + int GetFD() + { +#ifdef FILE_USE_OPEN + return hFile; +#else + return fileno(hFile); +#endif + } +#endif + static size_t CopyBufferSize() + { +#ifdef _WIN_ALL + // USB flash performance is poor with 64 KB buffer, 256+ KB resolved it. + // For copying from HDD to same HDD the best performance was with 256 KB + // buffer in XP and with 1 MB buffer in Win10. + return WinNT()==WNT_WXP ? 0x40000:0x100000; +#else + return 0x100000; +#endif + } +}; + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/filefn.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/filefn.cpp new file mode 100644 index 0000000..4eb7b9b --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/filefn.cpp @@ -0,0 +1,510 @@ +#include "rar.hpp" + +MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr) +{ +#ifdef _WIN_ALL + // Windows automatically removes dots and spaces in the end of directory + // name. So we detect such names and process them with \\?\ prefix. + wchar *LastChar=PointToLastChar(Name); + bool Special=*LastChar=='.' || *LastChar==' '; + BOOL RetCode=Special ? FALSE : CreateDirectory(Name,NULL); + if (RetCode==0 && !FileExist(Name)) + { + wchar LongName[NM]; + if (GetWinLongPath(Name,LongName,ASIZE(LongName))) + RetCode=CreateDirectory(LongName,NULL); + } + if (RetCode!=0) // Non-zero return code means success for CreateDirectory. + { + if (SetAttr) + SetFileAttr(Name,Attr); + return MKDIR_SUCCESS; + } + int ErrCode=GetLastError(); + if (ErrCode==ERROR_FILE_NOT_FOUND || ErrCode==ERROR_PATH_NOT_FOUND) + return MKDIR_BADPATH; + return MKDIR_ERROR; +#elif defined(_UNIX) + char NameA[NM]; + WideToChar(Name,NameA,ASIZE(NameA)); + mode_t uattr=SetAttr ? (mode_t)Attr:0777; + int ErrCode=mkdir(NameA,uattr); + if (ErrCode==-1) + return errno==ENOENT ? MKDIR_BADPATH:MKDIR_ERROR; + return MKDIR_SUCCESS; +#else + return MKDIR_ERROR; +#endif +} + + +bool CreatePath(const wchar *Path,bool SkipLastName) +{ + if (Path==NULL || *Path==0) + return false; + +#if defined(_WIN_ALL) || defined(_EMX) + uint DirAttr=0; +#else + uint DirAttr=0777; +#endif + + bool Success=true; + + for (const wchar *s=Path;*s!=0;s++) + { + wchar DirName[NM]; + if (s-Path>=ASIZE(DirName)) + break; + + // Process all kinds of path separators, so user can enter Unix style + // path in Windows or Windows in Unix. s>Path check avoids attempting + // creating an empty directory for paths starting from path separator. + if (IsPathDiv(*s) && s>Path) + { +#ifdef _WIN_ALL + // We must not attempt to create "D:" directory, because first + // CreateDirectory will fail, so we'll use \\?\D:, which forces Wine + // to create "D:" directory. + if (s==Path+2 && Path[1]==':') + continue; +#endif + wcsncpy(DirName,Path,s-Path); + DirName[s-Path]=0; + + Success=MakeDir(DirName,true,DirAttr)==MKDIR_SUCCESS; + if (Success) + { + mprintf(St(MCreatDir),DirName); + mprintf(L" %s",St(MOk)); + } + } + } + if (!SkipLastName && !IsPathDiv(*PointToLastChar(Path))) + Success=MakeDir(Path,true,DirAttr)==MKDIR_SUCCESS; + return Success; +} + + +void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta) +{ +#if defined(_WIN_ALL) + bool sm=ftm!=NULL && ftm->IsSet(); + bool sc=ftc!=NULL && ftc->IsSet(); + bool sa=fta!=NULL && fta->IsSet(); + + uint DirAttr=GetFileAttr(Name); + bool ResetAttr=(DirAttr!=0xffffffff && (DirAttr & FILE_ATTRIBUTE_READONLY)!=0); + if (ResetAttr) + SetFileAttr(Name,0); + + HANDLE hFile=CreateFile(Name,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL); + if (hFile==INVALID_HANDLE_VALUE) + { + wchar LongName[NM]; + if (GetWinLongPath(Name,LongName,ASIZE(LongName))) + hFile=CreateFile(LongName,GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE, + NULL,OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,NULL); + } + + if (hFile==INVALID_HANDLE_VALUE) + return; + FILETIME fm,fc,fa; + if (sm) + ftm->GetWinFT(&fm); + if (sc) + ftc->GetWinFT(&fc); + if (sa) + fta->GetWinFT(&fa); + SetFileTime(hFile,sc ? &fc:NULL,sa ? &fa:NULL,sm ? &fm:NULL); + CloseHandle(hFile); + if (ResetAttr) + SetFileAttr(Name,DirAttr); +#endif +#if defined(_UNIX) || defined(_EMX) + File::SetCloseFileTimeByName(Name,ftm,fta); +#endif +} + + +bool IsRemovable(const wchar *Name) +{ +#if defined(_WIN_ALL) + wchar Root[NM]; + GetPathRoot(Name,Root,ASIZE(Root)); + int Type=GetDriveType(*Root!=0 ? Root:NULL); + return Type==DRIVE_REMOVABLE || Type==DRIVE_CDROM; +#else + return false; +#endif +} + + +#ifndef SFX_MODULE +int64 GetFreeDisk(const wchar *Name) +{ +#ifdef _WIN_ALL + wchar Root[NM]; + GetFilePath(Name,Root,ASIZE(Root)); + + ULARGE_INTEGER uiTotalSize,uiTotalFree,uiUserFree; + uiUserFree.u.LowPart=uiUserFree.u.HighPart=0; + if (GetDiskFreeSpaceEx(*Root!=0 ? Root:NULL,&uiUserFree,&uiTotalSize,&uiTotalFree) && + uiUserFree.u.HighPart<=uiTotalFree.u.HighPart) + return INT32TO64(uiUserFree.u.HighPart,uiUserFree.u.LowPart); + return 0; +#elif defined(_UNIX) + wchar Root[NM]; + GetFilePath(Name,Root,ASIZE(Root)); + char RootA[NM]; + WideToChar(Root,RootA,ASIZE(RootA)); + struct statvfs sfs; + if (statvfs(*RootA!=0 ? RootA:".",&sfs)!=0) + return 0; + int64 FreeSize=sfs.f_bsize; + FreeSize=FreeSize*sfs.f_bavail; + return FreeSize; +#else + return 0; +#endif +} +#endif + + +#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT) +// Return 'true' for FAT and FAT32, so we can adjust the maximum supported +// file size to 4 GB for these file systems. +bool IsFAT(const wchar *Name) +{ + wchar Root[NM]; + GetPathRoot(Name,Root,ASIZE(Root)); + wchar FileSystem[MAX_PATH+1]; + if (GetVolumeInformation(Root,NULL,0,NULL,NULL,NULL,FileSystem,ASIZE(FileSystem))) + return wcscmp(FileSystem,L"FAT")==0 || wcscmp(FileSystem,L"FAT32")==0; + return false; +} +#endif + + +bool FileExist(const wchar *Name) +{ +#ifdef _WIN_ALL + return GetFileAttr(Name)!=0xffffffff; +#elif defined(ENABLE_ACCESS) + char NameA[NM]; + WideToChar(Name,NameA,ASIZE(NameA)); + return access(NameA,0)==0; +#else + FindData FD; + return FindFile::FastFind(Name,&FD); +#endif +} + + +bool WildFileExist(const wchar *Name) +{ + if (IsWildcard(Name)) + { + FindFile Find; + Find.SetMask(Name); + FindData fd; + return Find.Next(&fd); + } + return FileExist(Name); +} + + +bool IsDir(uint Attr) +{ +#ifdef _WIN_ALL + return Attr!=0xffffffff && (Attr & FILE_ATTRIBUTE_DIRECTORY)!=0; +#endif +#if defined(_UNIX) + return (Attr & 0xF000)==0x4000; +#endif +} + + +bool IsUnreadable(uint Attr) +{ +#if defined(_UNIX) && defined(S_ISFIFO) && defined(S_ISSOCK) && defined(S_ISCHR) + return S_ISFIFO(Attr) || S_ISSOCK(Attr) || S_ISCHR(Attr); +#endif + return false; +} + + +bool IsLink(uint Attr) +{ +#ifdef _UNIX + return (Attr & 0xF000)==0xA000; +#elif defined(_WIN_ALL) + return (Attr & FILE_ATTRIBUTE_REPARSE_POINT)!=0; +#else + return false; +#endif +} + + + + + + +bool IsDeleteAllowed(uint FileAttr) +{ +#ifdef _WIN_ALL + return (FileAttr & (FILE_ATTRIBUTE_READONLY|FILE_ATTRIBUTE_SYSTEM|FILE_ATTRIBUTE_HIDDEN))==0; +#else + return (FileAttr & (S_IRUSR|S_IWUSR))==(S_IRUSR|S_IWUSR); +#endif +} + + +void PrepareToDelete(const wchar *Name) +{ +#if defined(_WIN_ALL) || defined(_EMX) + SetFileAttr(Name,0); +#endif +#ifdef _UNIX + if (Name!=NULL) + { + char NameA[NM]; + WideToChar(Name,NameA,ASIZE(NameA)); + chmod(NameA,S_IRUSR|S_IWUSR|S_IXUSR); + } +#endif +} + + +uint GetFileAttr(const wchar *Name) +{ +#ifdef _WIN_ALL + DWORD Attr=GetFileAttributes(Name); + if (Attr==0xffffffff) + { + wchar LongName[NM]; + if (GetWinLongPath(Name,LongName,ASIZE(LongName))) + Attr=GetFileAttributes(LongName); + } + return Attr; +#else + char NameA[NM]; + WideToChar(Name,NameA,ASIZE(NameA)); + struct stat st; + if (stat(NameA,&st)!=0) + return 0; + return st.st_mode; +#endif +} + + +bool SetFileAttr(const wchar *Name,uint Attr) +{ +#ifdef _WIN_ALL + bool Success=SetFileAttributes(Name,Attr)!=0; + if (!Success) + { + wchar LongName[NM]; + if (GetWinLongPath(Name,LongName,ASIZE(LongName))) + Success=SetFileAttributes(LongName,Attr)!=0; + } + return Success; +#elif defined(_UNIX) + char NameA[NM]; + WideToChar(Name,NameA,ASIZE(NameA)); + return chmod(NameA,(mode_t)Attr)==0; +#else + return false; +#endif +} + + +#if 0 +wchar *MkTemp(wchar *Name,size_t MaxSize) +{ + size_t Length=wcslen(Name); + + RarTime CurTime; + CurTime.SetCurrentTime(); + + // We cannot use CurTime.GetWin() as is, because its lowest bits can + // have low informational value, like being a zero or few fixed numbers. + uint Random=(uint)(CurTime.GetWin()/100000); + + // Using PID we guarantee that different RAR copies use different temp names + // even if started in exactly the same time. + uint PID=0; +#ifdef _WIN_ALL + PID=(uint)GetCurrentProcessId(); +#elif defined(_UNIX) + PID=(uint)getpid(); +#endif + + for (uint Attempt=0;;Attempt++) + { + uint Ext=Random%50000+Attempt; + wchar RndText[50]; + swprintf(RndText,ASIZE(RndText),L"%u.%03u",PID,Ext); + if (Length+wcslen(RndText)>=MaxSize || Attempt==1000) + return NULL; + wcscpy(Name+Length,RndText); + if (!FileExist(Name)) + break; + } + return Name; +} +#endif + + +#if !defined(SFX_MODULE) +void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size,uint Flags) +{ + SaveFilePos SavePos(*SrcFile); +#ifndef SILENT + int64 FileLength=Size==INT64NDF ? SrcFile->FileLength() : Size; +#endif + + if ((Flags & (CALCFSUM_SHOWTEXT|CALCFSUM_SHOWPERCENT))!=0) + uiMsg(UIEVENT_FILESUMSTART); + + if ((Flags & CALCFSUM_CURPOS)==0) + SrcFile->Seek(0,SEEK_SET); + + const size_t BufSize=0x100000; + Array Data(BufSize); + + + DataHash HashCRC,HashBlake2; + HashCRC.Init(HASH_CRC32,Threads); + HashBlake2.Init(HASH_BLAKE2,Threads); + + int64 BlockCount=0; + int64 TotalRead=0; + while (true) + { + size_t SizeToRead; + if (Size==INT64NDF) // If we process the entire file. + SizeToRead=BufSize; // Then always attempt to read the entire buffer. + else + SizeToRead=(size_t)Min((int64)BufSize,Size); + int ReadSize=SrcFile->Read(&Data[0],SizeToRead); + if (ReadSize==0) + break; + TotalRead+=ReadSize; + + if ((++BlockCount & 0xf)==0) + { +#ifndef SILENT + if ((Flags & CALCFSUM_SHOWPROGRESS)!=0) + uiExtractProgress(TotalRead,FileLength,TotalRead,FileLength); + else + { + if ((Flags & CALCFSUM_SHOWPERCENT)!=0) + uiMsg(UIEVENT_FILESUMPROGRESS,ToPercent(TotalRead,FileLength)); + } +#endif + Wait(); + } + + if (CRC32!=NULL) + HashCRC.Update(&Data[0],ReadSize); + if (Blake2!=NULL) + HashBlake2.Update(&Data[0],ReadSize); + + if (Size!=INT64NDF) + Size-=ReadSize; + } + if ((Flags & CALCFSUM_SHOWPERCENT)!=0) + uiMsg(UIEVENT_FILESUMEND); + + if (CRC32!=NULL) + *CRC32=HashCRC.GetCRC32(); + if (Blake2!=NULL) + { + HashValue Result; + HashBlake2.Result(&Result); + memcpy(Blake2,Result.Digest,sizeof(Result.Digest)); + } +} +#endif + + +bool RenameFile(const wchar *SrcName,const wchar *DestName) +{ +#ifdef _WIN_ALL + bool Success=MoveFile(SrcName,DestName)!=0; + if (!Success) + { + wchar LongName1[NM],LongName2[NM]; + if (GetWinLongPath(SrcName,LongName1,ASIZE(LongName1)) && + GetWinLongPath(DestName,LongName2,ASIZE(LongName2))) + Success=MoveFile(LongName1,LongName2)!=0; + } + return Success; +#else + char SrcNameA[NM],DestNameA[NM]; + WideToChar(SrcName,SrcNameA,ASIZE(SrcNameA)); + WideToChar(DestName,DestNameA,ASIZE(DestNameA)); + bool Success=rename(SrcNameA,DestNameA)==0; + return Success; +#endif +} + + +bool DelFile(const wchar *Name) +{ +#ifdef _WIN_ALL + bool Success=DeleteFile(Name)!=0; + if (!Success) + { + wchar LongName[NM]; + if (GetWinLongPath(Name,LongName,ASIZE(LongName))) + Success=DeleteFile(LongName)!=0; + } + return Success; +#else + char NameA[NM]; + WideToChar(Name,NameA,ASIZE(NameA)); + bool Success=remove(NameA)==0; + return Success; +#endif +} + + + + +#if defined(_WIN_ALL) && !defined(SFX_MODULE) +bool SetFileCompression(const wchar *Name,bool State) +{ + HANDLE hFile=CreateFile(Name,FILE_READ_DATA|FILE_WRITE_DATA, + FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN,NULL); + if (hFile==INVALID_HANDLE_VALUE) + { + wchar LongName[NM]; + if (GetWinLongPath(Name,LongName,ASIZE(LongName))) + hFile=CreateFile(LongName,FILE_READ_DATA|FILE_WRITE_DATA, + FILE_SHARE_READ|FILE_SHARE_WRITE,NULL,OPEN_EXISTING, + FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_SEQUENTIAL_SCAN,NULL); + } + if (hFile==INVALID_HANDLE_VALUE) + return false; + SHORT NewState=State ? COMPRESSION_FORMAT_DEFAULT:COMPRESSION_FORMAT_NONE; + DWORD Result; + int RetCode=DeviceIoControl(hFile,FSCTL_SET_COMPRESSION,&NewState, + sizeof(NewState),NULL,0,&Result,NULL); + CloseHandle(hFile); + return RetCode!=0; +} +#endif + + + + + + + + + + diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/filefn.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/filefn.hpp new file mode 100644 index 0000000..1bda9b5 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/filefn.hpp @@ -0,0 +1,50 @@ +#ifndef _RAR_FILEFN_ +#define _RAR_FILEFN_ + +enum MKDIR_CODE {MKDIR_SUCCESS,MKDIR_ERROR,MKDIR_BADPATH}; + +MKDIR_CODE MakeDir(const wchar *Name,bool SetAttr,uint Attr); +bool CreatePath(const wchar *Path,bool SkipLastName); +void SetDirTime(const wchar *Name,RarTime *ftm,RarTime *ftc,RarTime *fta); +bool IsRemovable(const wchar *Name); + +#ifndef SFX_MODULE +int64 GetFreeDisk(const wchar *Name); +#endif + +#if defined(_WIN_ALL) && !defined(SFX_MODULE) && !defined(SILENT) +bool IsFAT(const wchar *Root); +#endif + +bool FileExist(const wchar *Name); +bool WildFileExist(const wchar *Name); +bool IsDir(uint Attr); +bool IsUnreadable(uint Attr); +bool IsLink(uint Attr); +void SetSFXMode(const wchar *FileName); +void EraseDiskContents(const wchar *FileName); +bool IsDeleteAllowed(uint FileAttr); +void PrepareToDelete(const wchar *Name); +uint GetFileAttr(const wchar *Name); +bool SetFileAttr(const wchar *Name,uint Attr); +#if 0 +wchar* MkTemp(wchar *Name,size_t MaxSize); +#endif + +enum CALCFSUM_FLAGS {CALCFSUM_SHOWTEXT=1,CALCFSUM_SHOWPERCENT=2,CALCFSUM_SHOWPROGRESS=4,CALCFSUM_CURPOS=8}; + +void CalcFileSum(File *SrcFile,uint *CRC32,byte *Blake2,uint Threads,int64 Size=INT64NDF,uint Flags=0); + +bool RenameFile(const wchar *SrcName,const wchar *DestName); +bool DelFile(const wchar *Name); +bool DelDir(const wchar *Name); + +#if defined(_WIN_ALL) && !defined(SFX_MODULE) +bool SetFileCompression(const wchar *Name,bool State); +#endif + + + + + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/filestr.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/filestr.cpp new file mode 100644 index 0000000..a5d29d7 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/filestr.cpp @@ -0,0 +1,166 @@ +#include "rar.hpp" + +bool ReadTextFile( + const wchar *Name, + StringList *List, + bool Config, + bool AbortOnError, + RAR_CHARSET SrcCharset, + bool Unquote, + bool SkipComments, + bool ExpandEnvStr) +{ + wchar FileName[NM]; + *FileName=0; + + if (Name!=NULL) + if (Config) + GetConfigName(Name,FileName,ASIZE(FileName),true,false); + else + wcsncpyz(FileName,Name,ASIZE(FileName)); + + File SrcFile; + if (*FileName!=0) + { + bool OpenCode=AbortOnError ? SrcFile.WOpen(FileName):SrcFile.Open(FileName,0); + + if (!OpenCode) + { + if (AbortOnError) + ErrHandler.Exit(RARX_OPEN); + return false; + } + } + else + SrcFile.SetHandleType(FILE_HANDLESTD); + + uint DataSize=0,ReadSize; + const int ReadBlock=4096; + + Array Data(ReadBlock); + while ((ReadSize=SrcFile.Read(&Data[DataSize],ReadBlock))!=0) + { + DataSize+=ReadSize; + Data.Add(ReadSize); // Always have ReadBlock available for next data. + } + // Set to really read size, so we can zero terminate it correctly. + Data.Alloc(DataSize); + + int LittleEndian=DataSize>=2 && Data[0]==255 && Data[1]==254 ? 1:0; + int BigEndian=DataSize>=2 && Data[0]==254 && Data[1]==255 ? 1:0; + bool Utf8=DataSize>=3 && Data[0]==0xef && Data[1]==0xbb && Data[2]==0xbf; + + if (SrcCharset==RCH_DEFAULT) + SrcCharset=DetectTextEncoding(&Data[0],DataSize); + + Array DataW; + + if (SrcCharset==RCH_DEFAULT || SrcCharset==RCH_OEM || SrcCharset==RCH_ANSI) + { + Data.Push(0); // Zero terminate. +#if defined(_WIN_ALL) + if (SrcCharset==RCH_OEM) + OemToCharA((char *)&Data[0],(char *)&Data[0]); +#endif + DataW.Alloc(Data.Size()); + CharToWide((char *)&Data[0],&DataW[0],DataW.Size()); + } + + if (SrcCharset==RCH_UNICODE) + { + size_t Start=2; // Skip byte order mark. + if (!LittleEndian && !BigEndian) // No byte order mask. + { + Start=0; + LittleEndian=1; + } + + DataW.Alloc(Data.Size()/2+1); + size_t End=Data.Size() & ~1; // We need even bytes number for UTF-16. + for (size_t I=Start;I=CurStr;SpacePtr--) + { + if (*SpacePtr!=' ' && *SpacePtr!='\t') + break; + *SpacePtr=0; + } + + if (Unquote && *CurStr=='\"') + { + size_t Length=wcslen(CurStr); + if (CurStr[Length-1]=='\"') + { + CurStr[Length-1]=0; + CurStr++; + } + } + + bool Expanded=false; +#if defined(_WIN_ALL) + if (ExpandEnvStr && *CurStr=='%') // Expand environment variables in Windows. + { + wchar ExpName[NM]; + *ExpName=0; + DWORD Result=ExpandEnvironmentStrings(CurStr,ExpName,ASIZE(ExpName)); + Expanded=Result!=0 && ResultAddString(ExpName); + } +#endif + if (!Expanded && *CurStr!=0) + List->AddString(CurStr); + + if (Done) + break; + CurStr=NextStr+1; + while (*CurStr=='\r' || *CurStr=='\n') + CurStr++; + } + return true; +} + + +RAR_CHARSET DetectTextEncoding(const byte *Data,size_t DataSize) +{ + if (DataSize>3 && Data[0]==0xef && Data[1]==0xbb && Data[2]==0xbf && + IsTextUtf8(Data+3,DataSize-3)) + return RCH_UTF8; + + bool LittleEndian=DataSize>2 && Data[0]==255 && Data[1]==254; + bool BigEndian=DataSize>2 && Data[0]==254 && Data[1]==255; + + if (LittleEndian || BigEndian) + for (size_t I=LittleEndian ? 3 : 2;IError=false; + if (*FindMask==0) + return false; +#ifdef _WIN_ALL + if (FirstCall) + { + if ((hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,fd))==INVALID_HANDLE_VALUE) + return false; + } + else + if (Win32Find(hFind,FindMask,fd)==INVALID_HANDLE_VALUE) + return false; +#else + if (FirstCall) + { + wchar DirName[NM]; + wcsncpyz(DirName,FindMask,ASIZE(DirName)); + RemoveNameFromPath(DirName); + if (*DirName==0) + wcscpy(DirName,L"."); + char DirNameA[NM]; + WideToChar(DirName,DirNameA,ASIZE(DirNameA)); + if ((dirp=opendir(DirNameA))==NULL) + { + fd->Error=(errno!=ENOENT); + return false; + } + } + while (1) + { + struct dirent *ent=readdir(dirp); + if (ent==NULL) + return false; + if (strcmp(ent->d_name,".")==0 || strcmp(ent->d_name,"..")==0) + continue; + wchar Name[NM]; + if (!CharToWide(ent->d_name,Name,ASIZE(Name))) + uiMsg(UIERROR_INVALIDNAME,UINULL,Name); + + if (CmpName(FindMask,Name,MATCH_NAMES)) + { + wchar FullName[NM]; + wcscpy(FullName,FindMask); + *PointToName(FullName)=0; + if (wcslen(FullName)+wcslen(Name)>=ASIZE(FullName)-1) + { + uiMsg(UIERROR_PATHTOOLONG,FullName,L"",Name); + return false; + } + wcscat(FullName,Name); + if (!FastFind(FullName,fd,GetSymLink)) + { + ErrHandler.OpenErrorMsg(FullName); + continue; + } + wcscpy(fd->Name,FullName); + break; + } + } +#endif + fd->Flags=0; + fd->IsDir=IsDir(fd->FileAttr); + fd->IsLink=IsLink(fd->FileAttr); + + FirstCall=false; + wchar *NameOnly=PointToName(fd->Name); + if (wcscmp(NameOnly,L".")==0 || wcscmp(NameOnly,L"..")==0) + return Next(fd); + return true; +} + + +bool FindFile::FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink) +{ + fd->Error=false; +#ifndef _UNIX + if (IsWildcard(FindMask)) + return false; +#endif +#ifdef _WIN_ALL + HANDLE hFind=Win32Find(INVALID_HANDLE_VALUE,FindMask,fd); + if (hFind==INVALID_HANDLE_VALUE) + return false; + FindClose(hFind); +#else + char FindMaskA[NM]; + WideToChar(FindMask,FindMaskA,ASIZE(FindMaskA)); + + struct stat st; + if (GetSymLink) + { +#ifdef SAVE_LINKS + if (lstat(FindMaskA,&st)!=0) +#else + if (stat(FindMaskA,&st)!=0) +#endif + { + fd->Error=(errno!=ENOENT); + return false; + } + } + else + if (stat(FindMaskA,&st)!=0) + { + fd->Error=(errno!=ENOENT); + return false; + } + fd->FileAttr=st.st_mode; + fd->Size=st.st_size; + +#ifdef UNIX_TIME_NS + fd->mtime.SetUnixNS(st.st_mtim.tv_sec*(uint64)1000000000+st.st_mtim.tv_nsec); + fd->atime.SetUnixNS(st.st_atim.tv_sec*(uint64)1000000000+st.st_atim.tv_nsec); + fd->ctime.SetUnixNS(st.st_ctim.tv_sec*(uint64)1000000000+st.st_ctim.tv_nsec); +#else + fd->mtime.SetUnix(st.st_mtime); + fd->atime.SetUnix(st.st_atime); + fd->ctime.SetUnix(st.st_ctime); +#endif + + wcsncpyz(fd->Name,FindMask,ASIZE(fd->Name)); +#endif + fd->Flags=0; + fd->IsDir=IsDir(fd->FileAttr); + fd->IsLink=IsLink(fd->FileAttr); + + return true; +} + + +#ifdef _WIN_ALL +HANDLE FindFile::Win32Find(HANDLE hFind,const wchar *Mask,FindData *fd) +{ + WIN32_FIND_DATA FindData; + if (hFind==INVALID_HANDLE_VALUE) + { + hFind=FindFirstFile(Mask,&FindData); + if (hFind==INVALID_HANDLE_VALUE) + { + wchar LongMask[NM]; + if (GetWinLongPath(Mask,LongMask,ASIZE(LongMask))) + hFind=FindFirstFile(LongMask,&FindData); + } + if (hFind==INVALID_HANDLE_VALUE) + { + int SysErr=GetLastError(); + // We must not issue an error for "file not found" and "path not found", + // because it is normal to not find anything for wildcard mask when + // archiving. Also searching for non-existent file is normal in some + // other modules, like WinRAR scanning for winrar_theme_description.txt + // to check if any themes are available. + fd->Error=SysErr!=ERROR_FILE_NOT_FOUND && + SysErr!=ERROR_PATH_NOT_FOUND && + SysErr!=ERROR_NO_MORE_FILES; + } + } + else + if (!FindNextFile(hFind,&FindData)) + { + hFind=INVALID_HANDLE_VALUE; + fd->Error=GetLastError()!=ERROR_NO_MORE_FILES; + } + + if (hFind!=INVALID_HANDLE_VALUE) + { + wcsncpyz(fd->Name,Mask,ASIZE(fd->Name)); + SetName(fd->Name,FindData.cFileName,ASIZE(fd->Name)); + fd->Size=INT32TO64(FindData.nFileSizeHigh,FindData.nFileSizeLow); + fd->FileAttr=FindData.dwFileAttributes; + fd->ftCreationTime=FindData.ftCreationTime; + fd->ftLastAccessTime=FindData.ftLastAccessTime; + fd->ftLastWriteTime=FindData.ftLastWriteTime; + fd->mtime.SetWinFT(&FindData.ftLastWriteTime); + fd->ctime.SetWinFT(&FindData.ftCreationTime); + fd->atime.SetWinFT(&FindData.ftLastAccessTime); + + + } + fd->Flags=0; + return hFind; +} +#endif + diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/find.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/find.hpp new file mode 100644 index 0000000..250637f --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/find.hpp @@ -0,0 +1,49 @@ +#ifndef _RAR_FINDDATA_ +#define _RAR_FINDDATA_ + +enum FINDDATA_FLAGS { + FDDF_SECONDDIR=1 // Second encounter of same directory in SCAN_GETDIRSTWICE ScanTree mode. +}; + +struct FindData +{ + wchar Name[NM]; + uint64 Size; + uint FileAttr; + bool IsDir; + bool IsLink; + RarTime mtime; + RarTime ctime; + RarTime atime; +#ifdef _WIN_ALL + FILETIME ftCreationTime; + FILETIME ftLastAccessTime; + FILETIME ftLastWriteTime; +#endif + uint Flags; + bool Error; +}; + +class FindFile +{ + private: +#ifdef _WIN_ALL + static HANDLE Win32Find(HANDLE hFind,const wchar *Mask,FindData *fd); +#endif + + wchar FindMask[NM]; + bool FirstCall; +#ifdef _WIN_ALL + HANDLE hFind; +#else + DIR *dirp; +#endif + public: + FindFile(); + ~FindFile(); + void SetMask(const wchar *Mask); + bool Next(FindData *fd,bool GetSymLink=false); + static bool FastFind(const wchar *FindMask,FindData *fd,bool GetSymLink=false); +}; + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/getbits.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/getbits.cpp new file mode 100644 index 0000000..e4db269 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/getbits.cpp @@ -0,0 +1,52 @@ +#include "rar.hpp" + +BitInput::BitInput(bool AllocBuffer) +{ + ExternalBuffer=false; + if (AllocBuffer) + { + // getbits32 attempts to read data from InAddr, ... InAddr+3 positions. + // So let's allocate 3 additional bytes for situation, when we need to + // read only 1 byte from the last position of buffer and avoid a crash + // from access to next 3 bytes, which contents we do not need. + size_t BufSize=MAX_SIZE+3; + InBuf=new byte[BufSize]; + + // Ensure that we get predictable results when accessing bytes in area + // not filled with read data. + memset(InBuf,0,BufSize); + } + else + InBuf=NULL; +} + + +BitInput::~BitInput() +{ + if (!ExternalBuffer) + delete[] InBuf; +} + + +void BitInput::faddbits(uint Bits) +{ + // Function wrapped version of inline addbits to save code size. + addbits(Bits); +} + + +uint BitInput::fgetbits() +{ + // Function wrapped version of inline getbits to save code size. + return getbits(); +} + + +void BitInput::SetExternalBuffer(byte *Buf) +{ + if (InBuf!=NULL && !ExternalBuffer) + delete[] InBuf; + InBuf=Buf; + ExternalBuffer=true; +} + diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/getbits.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/getbits.hpp new file mode 100644 index 0000000..2e151da --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/getbits.hpp @@ -0,0 +1,68 @@ +#ifndef _RAR_GETBITS_ +#define _RAR_GETBITS_ + +class BitInput +{ + public: + enum BufferSize {MAX_SIZE=0x8000}; // Size of input buffer. + + int InAddr; // Curent byte position in the buffer. + int InBit; // Current bit position in the current byte. + + bool ExternalBuffer; + public: + BitInput(bool AllocBuffer); + ~BitInput(); + + byte *InBuf; // Dynamically allocated input buffer. + + void InitBitInput() + { + InAddr=InBit=0; + } + + // Move forward by 'Bits' bits. + void addbits(uint Bits) + { + Bits+=InBit; + InAddr+=Bits>>3; + InBit=Bits&7; + } + + // Return 16 bits from current position in the buffer. + // Bit at (InAddr,InBit) has the highest position in returning data. + uint getbits() + { + uint BitField=(uint)InBuf[InAddr] << 16; + BitField|=(uint)InBuf[InAddr+1] << 8; + BitField|=(uint)InBuf[InAddr+2]; + BitField >>= (8-InBit); + return BitField & 0xffff; + } + + // Return 32 bits from current position in the buffer. + // Bit at (InAddr,InBit) has the highest position in returning data. + uint getbits32() + { + uint BitField=(uint)InBuf[InAddr] << 24; + BitField|=(uint)InBuf[InAddr+1] << 16; + BitField|=(uint)InBuf[InAddr+2] << 8; + BitField|=(uint)InBuf[InAddr+3]; + BitField <<= InBit; + BitField|=(uint)InBuf[InAddr+4] >> (8-InBit); + return BitField & 0xffffffff; + } + + void faddbits(uint Bits); + uint fgetbits(); + + // Check if buffer has enough space for IncPtr bytes. Returns 'true' + // if buffer will be overflown. + bool Overflow(uint IncPtr) + { + return InAddr+IncPtr>=MAX_SIZE; + } + + void SetExternalBuffer(byte *Buf); +}; +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/global.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/global.cpp new file mode 100644 index 0000000..3975813 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/global.cpp @@ -0,0 +1,7 @@ +#define INCLUDEGLOBAL + +#if defined(__BORLANDC__) || defined(_MSC_VER) +#pragma hdrstop +#endif + +#include "rar.hpp" diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/global.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/global.hpp new file mode 100644 index 0000000..35c6cf9 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/global.hpp @@ -0,0 +1,14 @@ +#ifndef _RAR_GLOBAL_ +#define _RAR_GLOBAL_ + +#ifdef INCLUDEGLOBAL + #define EXTVAR +#else + #define EXTVAR extern +#endif + +EXTVAR ErrorHandler ErrHandler; + + + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/hardlinks.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/hardlinks.cpp new file mode 100644 index 0000000..cf0b25a --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/hardlinks.cpp @@ -0,0 +1,34 @@ +bool ExtractHardlink(wchar *NameNew,wchar *NameExisting,size_t NameExistingSize) +{ + SlashToNative(NameExisting,NameExisting,NameExistingSize); // Not needed for RAR 5.1+ archives. + + if (!FileExist(NameExisting)) + return false; + CreatePath(NameNew,true); + +#ifdef _WIN_ALL + bool Success=CreateHardLink(NameNew,NameExisting,NULL)!=0; + if (!Success) + { + uiMsg(UIERROR_HLINKCREATE,NameNew); + ErrHandler.SysErrMsg(); + ErrHandler.SetErrorCode(RARX_CREATE); + } + return Success; +#elif defined(_UNIX) + char NameExistingA[NM],NameNewA[NM]; + WideToChar(NameExisting,NameExistingA,ASIZE(NameExistingA)); + WideToChar(NameNew,NameNewA,ASIZE(NameNewA)); + bool Success=link(NameExistingA,NameNewA)==0; + if (!Success) + { + uiMsg(UIERROR_HLINKCREATE,NameNew); + ErrHandler.SysErrMsg(); + ErrHandler.SetErrorCode(RARX_CREATE); + } + return Success; +#else + return false; +#endif +} + diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/hash.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/hash.cpp new file mode 100644 index 0000000..42791f4 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/hash.cpp @@ -0,0 +1,135 @@ +#include "rar.hpp" + +void HashValue::Init(HASH_TYPE Type) +{ + HashValue::Type=Type; + + // Zero length data CRC32 is 0. It is important to set it when creating + // headers with no following data like directories or symlinks. + if (Type==HASH_RAR14 || Type==HASH_CRC32) + CRC32=0; + if (Type==HASH_BLAKE2) + { + // dd0e891776933f43c7d032b08a917e25741f8aa9a12c12e1cac8801500f2ca4f + // is BLAKE2sp hash of empty data. We init the structure to this value, + // so if we create a file or service header with no following data like + // "file copy" or "symlink", we set the checksum to proper value avoiding + // additional header type or size checks when extracting. + static byte EmptyHash[32]={ + 0xdd, 0x0e, 0x89, 0x17, 0x76, 0x93, 0x3f, 0x43, + 0xc7, 0xd0, 0x32, 0xb0, 0x8a, 0x91, 0x7e, 0x25, + 0x74, 0x1f, 0x8a, 0xa9, 0xa1, 0x2c, 0x12, 0xe1, + 0xca, 0xc8, 0x80, 0x15, 0x00, 0xf2, 0xca, 0x4f + }; + memcpy(Digest,EmptyHash,sizeof(Digest)); + } +} + + +bool HashValue::operator == (const HashValue &cmp) +{ + if (Type==HASH_NONE || cmp.Type==HASH_NONE) + return true; + if (Type==HASH_RAR14 && cmp.Type==HASH_RAR14 || + Type==HASH_CRC32 && cmp.Type==HASH_CRC32) + return CRC32==cmp.CRC32; + if (Type==HASH_BLAKE2 && cmp.Type==HASH_BLAKE2) + return memcmp(Digest,cmp.Digest,sizeof(Digest))==0; + return false; +} + + +DataHash::DataHash() +{ + blake2ctx=NULL; + HashType=HASH_NONE; +#ifdef RAR_SMP + ThPool=NULL; + MaxThreads=0; +#endif +} + + +DataHash::~DataHash() +{ +#ifdef RAR_SMP + DestroyThreadPool(ThPool); +#endif + cleandata(&CurCRC32, sizeof(CurCRC32)); + if (blake2ctx!=NULL) + { + cleandata(blake2ctx, sizeof(blake2sp_state)); + delete blake2ctx; + } +} + + +void DataHash::Init(HASH_TYPE Type,uint MaxThreads) +{ + if (blake2ctx==NULL) + blake2ctx=new blake2sp_state; + HashType=Type; + if (Type==HASH_RAR14) + CurCRC32=0; + if (Type==HASH_CRC32) + CurCRC32=0xffffffff; // Initial CRC32 value. + if (Type==HASH_BLAKE2) + blake2sp_init(blake2ctx); +#ifdef RAR_SMP + DataHash::MaxThreads=Min(MaxThreads,MaxHashThreads); +#endif +} + + +void DataHash::Update(const void *Data,size_t DataSize) +{ +#ifndef SFX_MODULE + if (HashType==HASH_RAR14) + CurCRC32=Checksum14((ushort)CurCRC32,Data,DataSize); +#endif + if (HashType==HASH_CRC32) + CurCRC32=CRC32(CurCRC32,Data,DataSize); + + if (HashType==HASH_BLAKE2) + { +#ifdef RAR_SMP + if (MaxThreads>1 && ThPool==NULL) + ThPool=CreateThreadPool(); + blake2ctx->ThPool=ThPool; + blake2ctx->MaxThreads=MaxThreads; +#endif + blake2sp_update( blake2ctx, (byte *)Data, DataSize); + } +} + + +void DataHash::Result(HashValue *Result) +{ + Result->Type=HashType; + if (HashType==HASH_RAR14) + Result->CRC32=CurCRC32; + if (HashType==HASH_CRC32) + Result->CRC32=CurCRC32^0xffffffff; + if (HashType==HASH_BLAKE2) + { + // Preserve the original context, so we can continue hashing if necessary. + blake2sp_state res=*blake2ctx; + blake2sp_final(&res,Result->Digest); + } +} + + +uint DataHash::GetCRC32() +{ + return HashType==HASH_CRC32 ? CurCRC32^0xffffffff : 0; +} + + +bool DataHash::Cmp(HashValue *CmpValue,byte *Key) +{ + HashValue Final; + Result(&Final); + if (Key!=NULL) + ConvertHashToMAC(&Final,Key); + return Final==*CmpValue; +} diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/hash.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/hash.hpp new file mode 100644 index 0000000..b7d879f --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/hash.hpp @@ -0,0 +1,52 @@ +#ifndef _RAR_DATAHASH_ +#define _RAR_DATAHASH_ + +enum HASH_TYPE {HASH_NONE,HASH_RAR14,HASH_CRC32,HASH_BLAKE2}; + +struct HashValue +{ + void Init(HASH_TYPE Type); + bool operator == (const HashValue &cmp); + bool operator != (const HashValue &cmp) {return !(*this==cmp);} + + HASH_TYPE Type; + union + { + uint CRC32; + byte Digest[SHA256_DIGEST_SIZE]; + }; +}; + + +#ifdef RAR_SMP +class ThreadPool; +class DataHash; +#endif + + +class DataHash +{ + private: + HASH_TYPE HashType; + uint CurCRC32; + blake2sp_state *blake2ctx; + +#ifdef RAR_SMP + ThreadPool *ThPool; + + uint MaxThreads; + // Upper limit for maximum threads to prevent wasting threads in pool. + static const uint MaxHashThreads=8; +#endif + public: + DataHash(); + ~DataHash(); + void Init(HASH_TYPE Type,uint MaxThreads); + void Update(const void *Data,size_t DataSize); + void Result(HashValue *Result); + uint GetCRC32(); + bool Cmp(HashValue *CmpValue,byte *Key); + HASH_TYPE Type() {return HashType;} +}; + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/headers.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/headers.cpp new file mode 100644 index 0000000..b042dc3 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/headers.cpp @@ -0,0 +1,61 @@ +#include "rar.hpp" + +void FileHeader::Reset(size_t SubDataSize) +{ + SubData.Alloc(SubDataSize); + BaseBlock::Reset(); + FileHash.Init(HASH_NONE); + mtime.Reset(); + atime.Reset(); + ctime.Reset(); + SplitBefore=false; + SplitAfter=false; + + UnknownUnpSize=0; + + SubFlags=0; // Important for RAR 3.0 subhead. + + CryptMethod=CRYPT_NONE; + Encrypted=false; + SaltSet=false; + UsePswCheck=false; + UseHashKey=false; + Lg2Count=0; + + Solid=false; + Dir=false; + WinSize=0; + Inherited=false; + SubBlock=false; + CommentInHeader=false; + Version=false; + LargeFile=false; + + RedirType=FSREDIR_NONE; + DirTarget=false; + UnixOwnerSet=false; +} + + +FileHeader& FileHeader::operator = (FileHeader &hd) +{ + SubData.Reset(); + memcpy(this,&hd,sizeof(*this)); + SubData.CleanData(); + SubData=hd.SubData; + return *this; +} + + +void MainHeader::Reset() +{ + HighPosAV=0; + PosAV=0; + CommentInHeader=false; + PackComment=false; + Locator=false; + QOpenOffset=0; + QOpenMaxSize=0; + RROffset=0; + RRMaxSize=0; +} diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/headers.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/headers.hpp new file mode 100644 index 0000000..488960a --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/headers.hpp @@ -0,0 +1,353 @@ +#ifndef _RAR_HEADERS_ +#define _RAR_HEADERS_ + +#define SIZEOF_MARKHEAD3 7 // Size of RAR 4.x archive mark header. +#define SIZEOF_MAINHEAD14 7 // Size of RAR 1.4 main archive header. +#define SIZEOF_MAINHEAD3 13 // Size of RAR 4.x main archive header. +#define SIZEOF_FILEHEAD14 21 // Size of RAR 1.4 file header. +#define SIZEOF_FILEHEAD3 32 // Size of RAR 3.0 file header. +#define SIZEOF_SHORTBLOCKHEAD 7 +#define SIZEOF_LONGBLOCKHEAD 11 +#define SIZEOF_SUBBLOCKHEAD 14 +#define SIZEOF_COMMHEAD 13 +#define SIZEOF_PROTECTHEAD 26 +#define SIZEOF_UOHEAD 18 +#define SIZEOF_STREAMHEAD 26 + +#define VER_PACK 29 +#define VER_PACK5 50 // It is stored as 0, but we subtract 50 when saving an archive. +#define VER_UNPACK 29 +#define VER_UNPACK5 50 // It is stored as 0, but we add 50 when reading an archive. + +#define MHD_VOLUME 0x0001U + +// Old style main archive comment embed into main archive header. Must not +// be used in new archives anymore. +#define MHD_COMMENT 0x0002U + +#define MHD_LOCK 0x0004U +#define MHD_SOLID 0x0008U +#define MHD_PACK_COMMENT 0x0010U +#define MHD_NEWNUMBERING 0x0010U +#define MHD_AV 0x0020U +#define MHD_PROTECT 0x0040U +#define MHD_PASSWORD 0x0080U +#define MHD_FIRSTVOLUME 0x0100U + +#define LHD_SPLIT_BEFORE 0x0001U +#define LHD_SPLIT_AFTER 0x0002U +#define LHD_PASSWORD 0x0004U + +// Old style file comment embed into file header. Must not be used +// in new archives anymore. +#define LHD_COMMENT 0x0008U + +// For non-file subheaders it denotes 'subblock having a parent file' flag. +#define LHD_SOLID 0x0010U + + +#define LHD_WINDOWMASK 0x00e0U +#define LHD_WINDOW64 0x0000U +#define LHD_WINDOW128 0x0020U +#define LHD_WINDOW256 0x0040U +#define LHD_WINDOW512 0x0060U +#define LHD_WINDOW1024 0x0080U +#define LHD_WINDOW2048 0x00a0U +#define LHD_WINDOW4096 0x00c0U +#define LHD_DIRECTORY 0x00e0U + +#define LHD_LARGE 0x0100U +#define LHD_UNICODE 0x0200U +#define LHD_SALT 0x0400U +#define LHD_VERSION 0x0800U +#define LHD_EXTTIME 0x1000U + +#define SKIP_IF_UNKNOWN 0x4000U +#define LONG_BLOCK 0x8000U + +#define EARC_NEXT_VOLUME 0x0001U // Not last volume. +#define EARC_DATACRC 0x0002U // Store CRC32 of RAR archive (now is used only in volumes). +#define EARC_REVSPACE 0x0004U // Reserve space for end of REV file 7 byte record. +#define EARC_VOLNUMBER 0x0008U // Store a number of current volume. + +enum HEADER_TYPE { + // RAR 5.0 header types. + HEAD_MARK=0x00, HEAD_MAIN=0x01, HEAD_FILE=0x02, HEAD_SERVICE=0x03, + HEAD_CRYPT=0x04, HEAD_ENDARC=0x05, HEAD_UNKNOWN=0xff, + + // RAR 1.5 - 4.x header types. + HEAD3_MARK=0x72,HEAD3_MAIN=0x73,HEAD3_FILE=0x74,HEAD3_CMT=0x75, + HEAD3_AV=0x76,HEAD3_OLDSERVICE=0x77,HEAD3_PROTECT=0x78,HEAD3_SIGN=0x79, + HEAD3_SERVICE=0x7a,HEAD3_ENDARC=0x7b +}; + + +// RAR 2.9 and earlier. +enum { EA_HEAD=0x100,UO_HEAD=0x101,MAC_HEAD=0x102,BEEA_HEAD=0x103, + NTACL_HEAD=0x104,STREAM_HEAD=0x105 }; + + +// Internal implementation, depends on archive format version. +enum HOST_SYSTEM { + // RAR 5.0 host OS + HOST5_WINDOWS=0,HOST5_UNIX=1, + + // RAR 3.0 host OS. + HOST_MSDOS=0,HOST_OS2=1,HOST_WIN32=2,HOST_UNIX=3,HOST_MACOS=4, + HOST_BEOS=5,HOST_MAX +}; + +// Unified archive format independent implementation. +enum HOST_SYSTEM_TYPE { + HSYS_WINDOWS, HSYS_UNIX, HSYS_UNKNOWN +}; + + +// We also use these values in extra field, so do not modify them. +enum FILE_SYSTEM_REDIRECT { + FSREDIR_NONE=0, FSREDIR_UNIXSYMLINK, FSREDIR_WINSYMLINK, FSREDIR_JUNCTION, + FSREDIR_HARDLINK, FSREDIR_FILECOPY +}; + + +#define SUBHEAD_TYPE_CMT L"CMT" +#define SUBHEAD_TYPE_QOPEN L"QO" +#define SUBHEAD_TYPE_ACL L"ACL" +#define SUBHEAD_TYPE_STREAM L"STM" +#define SUBHEAD_TYPE_UOWNER L"UOW" +#define SUBHEAD_TYPE_AV L"AV" +#define SUBHEAD_TYPE_RR L"RR" +#define SUBHEAD_TYPE_OS2EA L"EA2" + +/* new file inherits a subblock when updating a host file */ +#define SUBHEAD_FLAGS_INHERITED 0x80000000 + +#define SUBHEAD_FLAGS_CMT_UNICODE 0x00000001 + + +struct MarkHeader +{ + byte Mark[8]; + + // Following fields are virtual and not present in real blocks. + uint HeadSize; +}; + + +struct BaseBlock +{ + uint HeadCRC; // 'ushort' for RAR 1.5. + HEADER_TYPE HeaderType; // 1 byte for RAR 1.5. + uint Flags; // 'ushort' for RAR 1.5. + uint HeadSize; // 'ushort' for RAR 1.5, up to 2 MB for RAR 5.0. + + bool SkipIfUnknown; + + void Reset() + { + SkipIfUnknown=false; + } +}; + + +struct BlockHeader:BaseBlock +{ + uint DataSize; +}; + + +struct MainHeader:BaseBlock +{ + ushort HighPosAV; + uint PosAV; + bool CommentInHeader; + bool PackComment; // For RAR 1.4 archive format only. + bool Locator; + uint64 QOpenOffset; // Offset of quick list record. + uint64 QOpenMaxSize; // Maximum size of QOpen offset in locator extra field. + uint64 RROffset; // Offset of recovery record. + uint64 RRMaxSize; // Maximum size of RR offset in locator extra field. + void Reset(); +}; + + +struct FileHeader:BlockHeader +{ + byte HostOS; + byte UnpVer; + byte Method; + union { + uint FileAttr; + uint SubFlags; + }; + wchar FileName[NM]; + + Array SubData; + + RarTime mtime; + RarTime ctime; + RarTime atime; + + int64 PackSize; + int64 UnpSize; + int64 MaxSize; // Reserve size bytes for vint of this size. + + HashValue FileHash; + + uint FileFlags; + + bool SplitBefore; + bool SplitAfter; + + bool UnknownUnpSize; + + bool Encrypted; + CRYPT_METHOD CryptMethod; + bool SaltSet; + byte Salt[SIZE_SALT50]; + byte InitV[SIZE_INITV]; + bool UsePswCheck; + byte PswCheck[SIZE_PSWCHECK]; + + // Use HMAC calculated from HashKey and checksum instead of plain checksum. + bool UseHashKey; + + // Key to convert checksum to HMAC. Derived from password with PBKDF2 + // using additional iterations. + byte HashKey[SHA256_DIGEST_SIZE]; + + uint Lg2Count; // Log2 of PBKDF2 repetition count. + + bool Solid; + bool Dir; + bool CommentInHeader; // RAR 2.0 file comment. + bool Version; // name.ext;ver file name containing the version number. + size_t WinSize; + bool Inherited; // New file inherits a subblock when updating a host file (for subblocks only). + + // 'true' if file sizes use 8 bytes instead of 4. Not used in RAR 5.0. + bool LargeFile; + + // 'true' for HEAD_SERVICE block, which is a child of preceding file block. + // RAR 4.x uses 'solid' flag to indicate child subheader blocks in archives. + bool SubBlock; + + HOST_SYSTEM_TYPE HSType; + + FILE_SYSTEM_REDIRECT RedirType; + wchar RedirName[NM]; + bool DirTarget; + + bool UnixOwnerSet,UnixOwnerNumeric,UnixGroupNumeric; + char UnixOwnerName[256],UnixGroupName[256]; +#ifdef _UNIX + uid_t UnixOwnerID; + gid_t UnixGroupID; +#else // Need these Unix fields in Windows too for 'list' command. + uint UnixOwnerID; + uint UnixGroupID; +#endif + + void Reset(size_t SubDataSize=0); + + bool CmpName(const wchar *Name) + { + return(wcscmp(FileName,Name)==0); + } + + FileHeader& operator = (FileHeader &hd); +}; + + +struct EndArcHeader:BaseBlock +{ + // Optional CRC32 of entire archive up to start of EndArcHeader block. + // Present in RAR 4.x archives if EARC_DATACRC flag is set. + uint ArcDataCRC; + + uint VolNumber; // Optional number of current volume. + + // 7 additional zero bytes can be stored here if EARC_REVSPACE is set. + + bool NextVolume; // Not last volume. + bool DataCRC; + bool RevSpace; + bool StoreVolNumber; + void Reset() + { + BaseBlock::Reset(); + NextVolume=false; + DataCRC=false; + RevSpace=false; + StoreVolNumber=false; + } +}; + + +struct CryptHeader:BaseBlock +{ + bool UsePswCheck; + uint Lg2Count; // Log2 of PBKDF2 repetition count. + byte Salt[SIZE_SALT50]; + byte PswCheck[SIZE_PSWCHECK]; +}; + + +// SubBlockHeader and its successors were used in RAR 2.x format. +// RAR 4.x uses FileHeader with HEAD_SERVICE HeaderType for subblocks. +struct SubBlockHeader:BlockHeader +{ + ushort SubType; + byte Level; +}; + + +struct CommentHeader:BaseBlock +{ + ushort UnpSize; + byte UnpVer; + byte Method; + ushort CommCRC; +}; + + +struct ProtectHeader:BlockHeader +{ + byte Version; + ushort RecSectors; + uint TotalBlocks; + byte Mark[8]; +}; + + +struct UnixOwnersHeader:SubBlockHeader +{ + ushort OwnerNameSize; + ushort GroupNameSize; +/* dummy */ + char OwnerName[256]; + char GroupName[256]; +}; + + +struct EAHeader:SubBlockHeader +{ + uint UnpSize; + byte UnpVer; + byte Method; + uint EACRC; +}; + + +struct StreamHeader:SubBlockHeader +{ + uint UnpSize; + byte UnpVer; + byte Method; + uint StreamCRC; + ushort StreamNameSize; + char StreamName[260]; +}; + + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/headers5.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/headers5.hpp new file mode 100644 index 0000000..9ea8d97 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/headers5.hpp @@ -0,0 +1,100 @@ +#ifndef _RAR_HEADERS5_ +#define _RAR_HEADERS5_ + +#define SIZEOF_MARKHEAD5 8 // RAR 5.0 signature length. +#define SIZEOF_SHORTBLOCKHEAD5 7 // Smallest RAR 5.0 block size. + +// RAR 5.0 block flags common for all blocks. + +// Additional extra area is present in the end of block header. +#define HFL_EXTRA 0x0001 +// Additional data area is present in the end of block header. +#define HFL_DATA 0x0002 +// Unknown blocks with this flag must be skipped when updating an archive. +#define HFL_SKIPIFUNKNOWN 0x0004 +// Data area of this block is continuing from previous volume. +#define HFL_SPLITBEFORE 0x0008 +// Data area of this block is continuing in next volume. +#define HFL_SPLITAFTER 0x0010 +// Block depends on preceding file block. +#define HFL_CHILD 0x0020 +// Preserve a child block if host is modified. +#define HFL_INHERITED 0x0040 + +// RAR 5.0 main archive header specific flags. +#define MHFL_VOLUME 0x0001 // Volume. +#define MHFL_VOLNUMBER 0x0002 // Volume number field is present. True for all volumes except first. +#define MHFL_SOLID 0x0004 // Solid archive. +#define MHFL_PROTECT 0x0008 // Recovery record is present. +#define MHFL_LOCK 0x0010 // Locked archive. + +// RAR 5.0 file header specific flags. +#define FHFL_DIRECTORY 0x0001 // Directory. +#define FHFL_UTIME 0x0002 // Time field in Unix format is present. +#define FHFL_CRC32 0x0004 // CRC32 field is present. +#define FHFL_UNPUNKNOWN 0x0008 // Unknown unpacked size. + +// RAR 5.0 end of archive header specific flags. +#define EHFL_NEXTVOLUME 0x0001 // Not last volume. + +// RAR 5.0 archive encryption header specific flags. +#define CHFL_CRYPT_PSWCHECK 0x0001 // Password check data is present. + + +// RAR 5.0 file compression flags. +#define FCI_ALGO_BIT0 0x0001 // Version of compression algorithm. +#define FCI_ALGO_BIT1 0x0002 // 0 .. 63. +#define FCI_ALGO_BIT2 0x0004 +#define FCI_ALGO_BIT3 0x0008 +#define FCI_ALGO_BIT4 0x0010 +#define FCI_ALGO_BIT5 0x0020 +#define FCI_SOLID 0x0040 // Solid flag. +#define FCI_METHOD_BIT0 0x0080 // Compression method. +#define FCI_METHOD_BIT1 0x0100 // 0 .. 5 (6 and 7 are not used). +#define FCI_METHOD_BIT2 0x0200 +#define FCI_DICT_BIT0 0x0400 // Dictionary size. +#define FCI_DICT_BIT1 0x0800 // 128 KB .. 4 GB. +#define FCI_DICT_BIT2 0x1000 +#define FCI_DICT_BIT3 0x2000 + +// Main header extra field values. +#define MHEXTRA_LOCATOR 0x01 // Position of quick list and other blocks. + +// Flags for MHEXTRA_LOCATOR. +#define MHEXTRA_LOCATOR_QLIST 0x01 // Quick open offset is present. +#define MHEXTRA_LOCATOR_RR 0x02 // Recovery record offset is present. + +// File and service header extra field values. +#define FHEXTRA_CRYPT 0x01 // Encryption parameters. +#define FHEXTRA_HASH 0x02 // File hash. +#define FHEXTRA_HTIME 0x03 // High precision file time. +#define FHEXTRA_VERSION 0x04 // File version information. +#define FHEXTRA_REDIR 0x05 // File system redirection (links, etc.). +#define FHEXTRA_UOWNER 0x06 // Unix owner and group information. +#define FHEXTRA_SUBDATA 0x07 // Service header subdata array. + + +// Hash type values for FHEXTRA_HASH. +#define FHEXTRA_HASH_BLAKE2 0x00 + +// Flags for FHEXTRA_HTIME. +#define FHEXTRA_HTIME_UNIXTIME 0x01 // Use Unix time_t format. +#define FHEXTRA_HTIME_MTIME 0x02 // mtime is present. +#define FHEXTRA_HTIME_CTIME 0x04 // ctime is present. +#define FHEXTRA_HTIME_ATIME 0x08 // atime is present. +#define FHEXTRA_HTIME_UNIX_NS 0x10 // Unix format with nanosecond precision. + +// Flags for FHEXTRA_CRYPT. +#define FHEXTRA_CRYPT_PSWCHECK 0x01 // Store password check data. +#define FHEXTRA_CRYPT_HASHMAC 0x02 // Use MAC for unpacked data checksums. + +// Flags for FHEXTRA_REDIR. +#define FHEXTRA_REDIR_DIR 0x01 // Link target is directory. + +// Flags for FHEXTRA_UOWNER. +#define FHEXTRA_UOWNER_UNAME 0x01 // User name string is present. +#define FHEXTRA_UOWNER_GNAME 0x02 // Group name string is present. +#define FHEXTRA_UOWNER_NUMUID 0x04 // Numeric user ID is present. +#define FHEXTRA_UOWNER_NUMGID 0x08 // Numeric group ID is present. + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/isnt.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/isnt.cpp new file mode 100644 index 0000000..6fadec0 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/isnt.cpp @@ -0,0 +1,24 @@ +#include "rar.hpp" + +#ifdef _WIN_ALL +DWORD WinNT() +{ + static int dwPlatformId=-1; + static DWORD dwMajorVersion,dwMinorVersion; + if (dwPlatformId==-1) + { + OSVERSIONINFO WinVer; + WinVer.dwOSVersionInfoSize=sizeof(WinVer); + GetVersionEx(&WinVer); + dwPlatformId=WinVer.dwPlatformId; + dwMajorVersion=WinVer.dwMajorVersion; + dwMinorVersion=WinVer.dwMinorVersion; + } + DWORD Result=0; + if (dwPlatformId==VER_PLATFORM_WIN32_NT) + Result=dwMajorVersion*0x100+dwMinorVersion; + + + return Result; +} +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/isnt.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/isnt.hpp new file mode 100644 index 0000000..85790da --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/isnt.hpp @@ -0,0 +1,13 @@ +#ifndef _RAR_ISNT_ +#define _RAR_ISNT_ + +enum WINNT_VERSION { + WNT_NONE=0,WNT_NT351=0x0333,WNT_NT4=0x0400,WNT_W2000=0x0500, + WNT_WXP=0x0501,WNT_W2003=0x0502,WNT_VISTA=0x0600,WNT_W7=0x0601, + WNT_W8=0x0602,WNT_W81=0x0603,WNT_W10=0x0a00 +}; + +DWORD WinNT(); + + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/license.txt b/Carthage/Checkouts/UnrarKit/Libraries/unrar/license.txt new file mode 100644 index 0000000..0811276 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/license.txt @@ -0,0 +1,42 @@ + ****** ***** ****** UnRAR - free utility for RAR archives + ** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ****** ******* ****** License for use and distribution of + ** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + ** ** ** ** ** ** FREE portable version + ~~~~~~~~~~~~~~~~~~~~~ + + The source code of UnRAR utility is freeware. This means: + + 1. All copyrights to RAR and the utility UnRAR are exclusively + owned by the author - Alexander Roshal. + + 2. UnRAR source code may be used in any software to handle + RAR archives without limitations free of charge, but cannot be + used to develop RAR (WinRAR) compatible archiver and to + re-create RAR compression algorithm, which is proprietary. + Distribution of modified UnRAR source code in separate form + or as a part of other software is permitted, provided that + full text of this paragraph, starting from "UnRAR source code" + words, is included in license, or in documentation if license + is not available, and in source code comments of resulting package. + + 3. The UnRAR utility may be freely distributed. It is allowed + to distribute UnRAR inside of other software packages. + + 4. THE RAR ARCHIVER AND THE UnRAR UTILITY ARE DISTRIBUTED "AS IS". + NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED. YOU USE AT + YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS, + DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING + OR MISUSING THIS SOFTWARE. + + 5. Installing and using the UnRAR utility signifies acceptance of + these terms and conditions of the license. + + 6. If you don't agree with terms of the license you must remove + UnRAR files from your storage devices and cease to use the + utility. + + Thank you for your interest in RAR and UnRAR. + + + Alexander L. Roshal diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/list.cpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/list.cpp new file mode 100644 index 0000000..561122b --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/list.cpp @@ -0,0 +1,472 @@ +#include "rar.hpp" + +static void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare); +static void ListSymLink(Archive &Arc); +static void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize); +static void ListOldSubHeader(Archive &Arc); +static void ListNewSubHeader(CommandData *Cmd,Archive &Arc); + +void ListArchive(CommandData *Cmd) +{ + int64 SumPackSize=0,SumUnpSize=0; + uint ArcCount=0,SumFileCount=0; + bool Technical=(Cmd->Command[1]=='T'); + bool ShowService=Technical && Cmd->Command[2]=='A'; + bool Bare=(Cmd->Command[1]=='B'); + bool Verbose=(Cmd->Command[0]=='V'); + + wchar ArcName[NM]; + while (Cmd->GetArcName(ArcName,ASIZE(ArcName))) + { + if (Cmd->ManualPassword) + Cmd->Password.Clean(); // Clean user entered password before processing next archive. + + Archive Arc(Cmd); +#ifdef _WIN_ALL + Arc.RemoveSequentialFlag(); +#endif + if (!Arc.WOpen(ArcName)) + continue; + bool FileMatched=true; + while (1) + { + int64 TotalPackSize=0,TotalUnpSize=0; + uint FileCount=0; + if (Arc.IsArchive(true)) + { + bool TitleShown=false; + if (!Bare) + { + Arc.ViewComment(); + mprintf(L"\n%s: %s",St(MListArchive),Arc.FileName); + mprintf(L"\n%s: ",St(MListDetails)); + uint SetCount=0; + const wchar *Fmt=Arc.Format==RARFMT14 ? L"RAR 1.4":(Arc.Format==RARFMT15 ? L"RAR 4":L"RAR 5"); + mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", Fmt); + if (Arc.Solid) + mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSolid)); + if (Arc.SFXSize>0) + mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListSFX)); + if (Arc.Volume) + if (Arc.Format==RARFMT50) + { + // RAR 5.0 archives store the volume number in main header, + // so it is already available now. + if (SetCount++ > 0) + mprintf(L", "); + mprintf(St(MVolumeNumber),Arc.VolNumber+1); + } + else + mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListVolume)); + if (Arc.Protected) + mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListRR)); + if (Arc.Locked) + mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListLock)); + if (Arc.Encrypted) + mprintf(L"%s%s", SetCount++ > 0 ? L", ":L"", St(MListEncHead)); + mprintf(L"\n"); + } + + wchar VolNumText[50]; + *VolNumText=0; + while(Arc.ReadHeader()>0) + { + HEADER_TYPE HeaderType=Arc.GetHeaderType(); + if (HeaderType==HEAD_ENDARC) + { +#ifndef SFX_MODULE + // Only RAR 1.5 archives store the volume number in end record. + if (Arc.EndArcHead.StoreVolNumber && Arc.Format==RARFMT15) + swprintf(VolNumText,ASIZE(VolNumText),L"%.10ls %u",St(MListVolume),Arc.VolNumber+1); +#endif + if (Technical && ShowService) + { + mprintf(L"\n%12ls: %ls",St(MListService),L"EOF"); + if (*VolNumText!=0) + mprintf(L"\n%12ls: %ls",St(MListFlags),VolNumText); + mprintf(L"\n"); + } + break; + } + switch(HeaderType) + { + case HEAD_FILE: + FileMatched=Cmd->IsProcessFile(Arc.FileHead)!=0; + if (FileMatched) + { + ListFileHeader(Arc,Arc.FileHead,TitleShown,Verbose,Technical,Bare); + if (!Arc.FileHead.SplitBefore) + { + TotalUnpSize+=Arc.FileHead.UnpSize; + FileCount++; + } + TotalPackSize+=Arc.FileHead.PackSize; + } + break; + case HEAD_SERVICE: + if (FileMatched && !Bare) + { + if (Technical && ShowService) + ListFileHeader(Arc,Arc.SubHead,TitleShown,Verbose,true,false); + } + break; + } + Arc.SeekToNext(); + } + if (!Bare && !Technical) + if (TitleShown) + { + wchar UnpSizeText[20]; + itoa(TotalUnpSize,UnpSizeText,ASIZE(UnpSizeText)); + + wchar PackSizeText[20]; + itoa(TotalPackSize,PackSizeText,ASIZE(PackSizeText)); + + if (Verbose) + { + mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----"); + mprintf(L"\n%21ls %9ls %3d%% %-27ls %u",UnpSizeText, + PackSizeText,ToPercentUnlim(TotalPackSize,TotalUnpSize), + VolNumText,FileCount); + } + else + { + mprintf(L"\n----------- --------- ---------- ----- ----"); + mprintf(L"\n%21ls %-16ls %u",UnpSizeText,VolNumText,FileCount); + } + + SumFileCount+=FileCount; + SumUnpSize+=TotalUnpSize; + SumPackSize+=TotalPackSize; + mprintf(L"\n"); + } + else + mprintf(St(MListNoFiles)); + + ArcCount++; + +#ifndef NOVOLUME + if (Cmd->VolSize!=0 && (Arc.FileHead.SplitAfter || + Arc.GetHeaderType()==HEAD_ENDARC && Arc.EndArcHead.NextVolume) && + MergeArchive(Arc,NULL,false,Cmd->Command[0])) + Arc.Seek(0,SEEK_SET); + else +#endif + break; + } + else + { + if (Cmd->ArcNames.ItemsCount()<2 && !Bare) + mprintf(St(MNotRAR),Arc.FileName); + break; + } + } + } + + // Clean user entered password. Not really required, just for extra safety. + if (Cmd->ManualPassword) + Cmd->Password.Clean(); + + if (ArcCount>1 && !Bare && !Technical) + { + wchar UnpSizeText[20],PackSizeText[20]; + itoa(SumUnpSize,UnpSizeText,ASIZE(UnpSizeText)); + itoa(SumPackSize,PackSizeText,ASIZE(PackSizeText)); + + if (Verbose) + mprintf(L"%21ls %9ls %3d%% %28ls %u",UnpSizeText,PackSizeText, + ToPercentUnlim(SumPackSize,SumUnpSize),L"",SumFileCount); + else + mprintf(L"%21ls %18s %lu",UnpSizeText,L"",SumFileCount); + } +} + + +enum LISTCOL_TYPE { + LCOL_NAME,LCOL_ATTR,LCOL_SIZE,LCOL_PACKED,LCOL_RATIO,LCOL_CSUM,LCOL_ENCR +}; + + +void ListFileHeader(Archive &Arc,FileHeader &hd,bool &TitleShown,bool Verbose,bool Technical,bool Bare) +{ + wchar *Name=hd.FileName; + RARFORMAT Format=Arc.Format; + + if (Bare) + { + mprintf(L"%s\n",Name); + return; + } + + if (!TitleShown && !Technical) + { + if (Verbose) + { + mprintf(L"\n%ls",St(MListTitleV)); + mprintf(L"\n----------- --------- -------- ----- ---------- ----- -------- ----"); + } + else + { + mprintf(L"\n%ls",St(MListTitleL)); + mprintf(L"\n----------- --------- ---------- ----- ----"); + } + TitleShown=true; + } + + wchar UnpSizeText[30],PackSizeText[30]; + if (hd.UnpSize==INT64NDF) + wcscpy(UnpSizeText,L"?"); + else + itoa(hd.UnpSize,UnpSizeText,ASIZE(UnpSizeText)); + itoa(hd.PackSize,PackSizeText,ASIZE(PackSizeText)); + + wchar AttrStr[30]; + if (hd.HeaderType==HEAD_SERVICE) + swprintf(AttrStr,ASIZE(AttrStr),L"%cB",hd.Inherited ? 'I' : '.'); + else + ListFileAttr(hd.FileAttr,hd.HSType,AttrStr,ASIZE(AttrStr)); + + wchar RatioStr[10]; + + if (hd.SplitBefore && hd.SplitAfter) + wcscpy(RatioStr,L"<->"); + else + if (hd.SplitBefore) + wcscpy(RatioStr,L"<--"); + else + if (hd.SplitAfter) + wcscpy(RatioStr,L"-->"); + else + swprintf(RatioStr,ASIZE(RatioStr),L"%d%%",ToPercentUnlim(hd.PackSize,hd.UnpSize)); + + wchar DateStr[50]; + hd.mtime.GetText(DateStr,ASIZE(DateStr),Technical); + + if (Technical) + { + mprintf(L"\n%12s: %s",St(MListName),Name); + + bool FileBlock=hd.HeaderType==HEAD_FILE; + + if (!FileBlock && Arc.SubHead.CmpName(SUBHEAD_TYPE_STREAM)) + { + mprintf(L"\n%12ls: %ls",St(MListType),St(MListStream)); + wchar StreamName[NM]; + GetStreamNameNTFS(Arc,StreamName,ASIZE(StreamName)); + mprintf(L"\n%12ls: %ls",St(MListTarget),StreamName); + } + else + { + const wchar *Type=St(FileBlock ? (hd.Dir ? MListDir:MListFile):MListService); + + if (hd.RedirType!=FSREDIR_NONE) + switch(hd.RedirType) + { + case FSREDIR_UNIXSYMLINK: + Type=St(MListUSymlink); break; + case FSREDIR_WINSYMLINK: + Type=St(MListWSymlink); break; + case FSREDIR_JUNCTION: + Type=St(MListJunction); break; + case FSREDIR_HARDLINK: + Type=St(MListHardlink); break; + case FSREDIR_FILECOPY: + Type=St(MListCopy); break; + } + mprintf(L"\n%12ls: %ls",St(MListType),Type); + if (hd.RedirType!=FSREDIR_NONE) + if (Format==RARFMT15) + { + char LinkTargetA[NM]; + if (Arc.FileHead.Encrypted) + { + // Link data are encrypted. We would need to ask for password + // and initialize decryption routine to display the link target. + strncpyz(LinkTargetA,"*<-?->",ASIZE(LinkTargetA)); + } + else + { + int DataSize=(int)Min(hd.PackSize,ASIZE(LinkTargetA)-1); + Arc.Read(LinkTargetA,DataSize); + LinkTargetA[DataSize > 0 ? DataSize : 0] = 0; + } + wchar LinkTarget[NM]; + CharToWide(LinkTargetA,LinkTarget,ASIZE(LinkTarget)); + mprintf(L"\n%12ls: %ls",St(MListTarget),LinkTarget); + } + else + mprintf(L"\n%12ls: %ls",St(MListTarget),hd.RedirName); + } + if (!hd.Dir) + { + mprintf(L"\n%12ls: %ls",St(MListSize),UnpSizeText); + mprintf(L"\n%12ls: %ls",St(MListPacked),PackSizeText); + mprintf(L"\n%12ls: %ls",St(MListRatio),RatioStr); + } + if (hd.mtime.IsSet()) + mprintf(L"\n%12ls: %ls",St(MListMtime),DateStr); + if (hd.ctime.IsSet()) + { + hd.ctime.GetText(DateStr,ASIZE(DateStr),true); + mprintf(L"\n%12ls: %ls",St(MListCtime),DateStr); + } + if (hd.atime.IsSet()) + { + hd.atime.GetText(DateStr,ASIZE(DateStr),true); + mprintf(L"\n%12ls: %ls",St(MListAtime),DateStr); + } + mprintf(L"\n%12ls: %ls",St(MListAttr),AttrStr); + if (hd.FileHash.Type==HASH_CRC32) + mprintf(L"\n%12ls: %8.8X", + hd.UseHashKey ? L"CRC32 MAC":hd.SplitAfter ? L"Pack-CRC32":L"CRC32", + hd.FileHash.CRC32); + if (hd.FileHash.Type==HASH_BLAKE2) + { + wchar BlakeStr[BLAKE2_DIGEST_SIZE*2+1]; + BinToHex(hd.FileHash.Digest,BLAKE2_DIGEST_SIZE,NULL,BlakeStr,ASIZE(BlakeStr)); + mprintf(L"\n%12ls: %ls", + hd.UseHashKey ? L"BLAKE2 MAC":hd.SplitAfter ? L"Pack-BLAKE2":L"BLAKE2", + BlakeStr); + } + + const wchar *HostOS=L""; + if (Format==RARFMT50 && hd.HSType!=HSYS_UNKNOWN) + HostOS=hd.HSType==HSYS_WINDOWS ? L"Windows":L"Unix"; + if (Format==RARFMT15) + { + static const wchar *RarOS[]={ + L"DOS",L"OS/2",L"Windows",L"Unix",L"Mac OS",L"BeOS",L"WinCE",L"",L"",L"" + }; + if (hd.HostOS=0x100000 ? hd.WinSize/0x100000:hd.WinSize/0x400, + hd.WinSize>=0x100000 ? L"M":L"K"); + + if (hd.Solid || hd.Encrypted) + { + mprintf(L"\n%12ls: ",St(MListFlags)); + if (hd.Solid) + mprintf(L"%ls ",St(MListSolid)); + if (hd.Encrypted) + mprintf(L"%ls ",St(MListEnc)); + } + + if (hd.Version) + { + uint Version=ParseVersionFileName(Name,false); + if (Version!=0) + mprintf(L"\n%12ls: %u",St(MListFileVer),Version); + } + + if (hd.UnixOwnerSet) + { + mprintf(L"\n%12ls: ",L"Unix owner"); + if (*hd.UnixOwnerName!=0) + mprintf(L"%ls:",GetWide(hd.UnixOwnerName)); + if (*hd.UnixGroupName!=0) + mprintf(L"%ls",GetWide(hd.UnixGroupName)); + if ((*hd.UnixOwnerName!=0 || *hd.UnixGroupName!=0) && (hd.UnixOwnerNumeric || hd.UnixGroupNumeric)) + mprintf(L" "); + if (hd.UnixOwnerNumeric) + mprintf(L"#%d:",hd.UnixOwnerID); + if (hd.UnixGroupNumeric) + mprintf(L"#%d:",hd.UnixGroupID); + } + + mprintf(L"\n"); + return; + } + + mprintf(L"\n%c%10ls %9ls ",hd.Encrypted ? '*' : ' ',AttrStr,UnpSizeText); + + if (Verbose) + mprintf(L"%9ls %4ls ",PackSizeText,RatioStr); + + mprintf(L" %ls ",DateStr); + + if (Verbose) + { + if (hd.FileHash.Type==HASH_CRC32) + mprintf(L"%8.8X ",hd.FileHash.CRC32); + else + if (hd.FileHash.Type==HASH_BLAKE2) + { + byte *S=hd.FileHash.Digest; + mprintf(L"%02x%02x..%02x ",S[0],S[1],S[31]); + } + else + mprintf(L"???????? "); + } + mprintf(L"%ls",Name); +} + +/* +void ListSymLink(Archive &Arc) +{ + if (Arc.FileHead.HSType==HSYS_UNIX && (Arc.FileHead.FileAttr & 0xF000)==0xA000) + if (Arc.FileHead.Encrypted) + { + // Link data are encrypted. We would need to ask for password + // and initialize decryption routine to display the link target. + mprintf(L"\n%22ls %ls",L"-->",L"*<-?->"); + } + else + { + char FileName[NM]; + uint DataSize=(uint)Min(Arc.FileHead.PackSize,sizeof(FileName)-1); + Arc.Read(FileName,DataSize); + FileName[DataSize]=0; + mprintf(L"\n%22ls %ls",L"-->",GetWide(FileName)); + } +} +*/ + +void ListFileAttr(uint A,HOST_SYSTEM_TYPE HostType,wchar *AttrStr,size_t AttrSize) +{ + switch(HostType) + { + case HSYS_WINDOWS: + swprintf(AttrStr,AttrSize,L"%c%c%c%c%c%c%c", + (A & 0x2000)!=0 ? 'I' : '.', // Not content indexed. + (A & 0x0800)!=0 ? 'C' : '.', // Compressed. + (A & 0x0020)!=0 ? 'A' : '.', // Archive. + (A & 0x0010)!=0 ? 'D' : '.', // Directory. + (A & 0x0004)!=0 ? 'S' : '.', // System. + (A & 0x0002)!=0 ? 'H' : '.', // Hidden. + (A & 0x0001)!=0 ? 'R' : '.'); // Read-only. + break; + case HSYS_UNIX: + switch (A & 0xF000) + { + case 0x4000: + AttrStr[0]='d'; + break; + case 0xA000: + AttrStr[0]='l'; + break; + default: + AttrStr[0]='-'; + break; + } + swprintf(AttrStr+1,AttrSize-1,L"%c%c%c%c%c%c%c%c%c", + (A & 0x0100) ? 'r' : '-', + (A & 0x0080) ? 'w' : '-', + (A & 0x0040) ? ((A & 0x0800)!=0 ? 's':'x'):((A & 0x0800)!=0 ? 'S':'-'), + (A & 0x0020) ? 'r' : '-', + (A & 0x0010) ? 'w' : '-', + (A & 0x0008) ? ((A & 0x0400)!=0 ? 's':'x'):((A & 0x0400)!=0 ? 'S':'-'), + (A & 0x0004) ? 'r' : '-', + (A & 0x0002) ? 'w' : '-', + (A & 0x0001) ? ((A & 0x200)!=0 ? 't' : 'x') : '-'); + break; + case HSYS_UNKNOWN: + wcscpy(AttrStr,L"?"); + break; + } +} diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/list.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/list.hpp new file mode 100644 index 0000000..7721ae5 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/list.hpp @@ -0,0 +1,6 @@ +#ifndef _RAR_LIST_ +#define _RAR_LIST_ + +void ListArchive(CommandData *Cmd); + +#endif diff --git a/Carthage/Checkouts/UnrarKit/Libraries/unrar/loclang.hpp b/Carthage/Checkouts/UnrarKit/Libraries/unrar/loclang.hpp new file mode 100644 index 0000000..87499bb --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Libraries/unrar/loclang.hpp @@ -0,0 +1,380 @@ +#define MYesNo L"_Yes_No" +#define MYesNoAll L"_Yes_No_All" +#define MYesNoAllQ L"_Yes_No_All_nEver_Quit" +#define MYesNoAllRenQ L"_Yes_No_All_nEver_Rename_Quit" +#define MContinueQuit L"_Continue_Quit" +#define MRetryAbort L"_Retry_Abort" +#define MCopyright L"\nRAR %s Copyright (c) 1993-%d Alexander Roshal %d %s %d" +#define MRegTo L"\nRegistered to %s\n" +#define MShare L"\nTrial version Type 'rar -?' for help\n" +#define MRegKeyWarning L"\nAvailable license key is valid only for %s\n" +#define MUCopyright L"\nUNRAR %s freeware Copyright (c) 1993-%d Alexander Roshal\n" +#define MBeta L"beta" +#define Mx86 L"x86" +#define Mx64 L"x64" +#define MMonthJan L"Jan" +#define MMonthFeb L"Feb" +#define MMonthMar L"Mar" +#define MMonthApr L"Apr" +#define MMonthMay L"May" +#define MMonthJun L"Jun" +#define MMonthJul L"Jul" +#define MMonthAug L"Aug" +#define MMonthSep L"Sep" +#define MMonthOct L"Oct" +#define MMonthNov L"Nov" +#define MMonthDec L"Dec" +#define MRARTitle1 L"\nUsage: rar - - " +#define MUNRARTitle1 L"\nUsage: unrar - - " +#define MRARTitle2 L"\n <@listfiles...> " +#define MCHelpCmd L"\n\n" +#define MCHelpCmdA L"\n a Add files to archive" +#define MCHelpCmdC L"\n c Add archive comment" +#define MCHelpCmdCH L"\n ch Change archive parameters" +#define MCHelpCmdCW L"\n cw Write archive comment to file" +#define MCHelpCmdD L"\n d Delete files from archive" +#define MCHelpCmdE L"\n e Extract files without archived paths" +#define MCHelpCmdF L"\n f Freshen files in archive" +#define MCHelpCmdI L"\n i[par]= Find string in archives" +#define MCHelpCmdK L"\n k Lock archive" +#define MCHelpCmdL L"\n l[t[a],b] List archive contents [technical[all], bare]" +#define MCHelpCmdM L"\n m[f] Move to archive [files only]" +#define MCHelpCmdP L"\n p Print file to stdout" +#define MCHelpCmdR L"\n r Repair archive" +#define MCHelpCmdRC L"\n rc Reconstruct missing volumes" +#define MCHelpCmdRN L"\n rn Rename archived files" +#define MCHelpCmdRR L"\n rr[N] Add data recovery record" +#define MCHelpCmdRV L"\n rv[N] Create recovery volumes" +#define MCHelpCmdS L"\n s[name|-] Convert archive to or from SFX" +#define MCHelpCmdT L"\n t Test archive files" +#define MCHelpCmdU L"\n u Update files in archive" +#define MCHelpCmdV L"\n v[t[a],b] Verbosely list archive contents [technical[all],bare]" +#define MCHelpCmdX L"\n x Extract files with full path" +#define MCHelpSw L"\n\n" +#define MCHelpSwm L"\n - Stop switches scanning" +#define MCHelpSwAT L"\n @[+] Disable [enable] file lists" +#define MCHelpSwAC L"\n ac Clear Archive attribute after compression or extraction" +#define MCHelpSwAD L"\n ad Append archive name to destination path" +#define MCHelpSwAG L"\n ag[format] Generate archive name using the current date" +#define MCHelpSwAI L"\n ai Ignore file attributes" +#define MCHelpSwAO L"\n ao Add files with Archive attribute set" +#define MCHelpSwAP L"\n ap Set path inside archive" +#define MCHelpSwAS L"\n as Synchronize archive contents" +#define MCHelpSwCm L"\n c- Disable comments show" +#define MCHelpSwCFGm L"\n cfg- Disable read configuration" +#define MCHelpSwCL L"\n cl Convert names to lower case" +#define MCHelpSwCU L"\n cu Convert names to upper case" +#define MCHelpSwDF L"\n df Delete files after archiving" +#define MCHelpSwDH L"\n dh Open shared files" +#define MCHelpSwDR L"\n dr Delete files to Recycle Bin" +#define MCHelpSwDS L"\n ds Disable name sort for solid archive" +#define MCHelpSwDW L"\n dw Wipe files after archiving" +#define MCHelpSwEa L"\n e[+] Set file exclude and include attributes" +#define MCHelpSwED L"\n ed Do not add empty directories" +#define MCHelpSwEN L"\n en Do not put 'end of archive' block" +#define MCHelpSwEP L"\n ep Exclude paths from names" +#define MCHelpSwEP1 L"\n ep1 Exclude base directory from names" +#define MCHelpSwEP2 L"\n ep2 Expand paths to full" +#define MCHelpSwEP3 L"\n ep3 Expand paths to full including the drive letter" +#define MCHelpSwF L"\n f Freshen files" +#define MCHelpSwHP L"\n hp[password] Encrypt both file data and headers" +#define MCHelpSwHT L"\n ht[b|c] Select hash type [BLAKE2,CRC32] for file checksum" +#define MCHelpSwIDP L"\n id[c,d,p,q] Disable messages" +#define MCHelpSwIEML L"\n ieml[addr] Send archive by email" +#define MCHelpSwIERR L"\n ierr Send all messages to stderr" +#define MCHelpSwILOG L"\n ilog[name] Log errors to file" +#define MCHelpSwINUL L"\n inul Disable all messages" +#define MCHelpSwIOFF L"\n ioff[n] Turn PC off after completing an operation" +#define MCHelpSwISND L"\n isnd Enable sound" +#define MCHelpSwIVER L"\n iver Display the version number" +#define MCHelpSwK L"\n k Lock archive" +#define MCHelpSwKB L"\n kb Keep broken extracted files" +#define MCHelpSwLog L"\n log[f][=name] Write names to log file" +#define MCHelpSwMn L"\n m<0..5> Set compression level (0-store...3-default...5-maximal)" +#define MCHelpSwMA L"\n ma[4|5] Specify a version of archiving format" +#define MCHelpSwMC L"\n mc Set advanced compression parameters" +#define MCHelpSwMD L"\n md[k,m,g] Dictionary size in KB, MB or GB" +#define MCHelpSwMS L"\n ms[ext;ext] Specify file types to store" +#define MCHelpSwMT L"\n mt Set the number of threads" +#define MCHelpSwN L"\n n Additionally filter included files" +#define MCHelpSwNa L"\n n@ Read additional filter masks from stdin" +#define MCHelpSwNal L"\n n@ Read additional filter masks from list file" +#define MCHelpSwO L"\n o[+|-] Set the overwrite mode" +#define MCHelpSwOC L"\n oc Set NTFS Compressed attribute" +#define MCHelpSwOH L"\n oh Save hard links as the link instead of the file" +#define MCHelpSwOI L"\n oi[0-4][:min] Save identical files as references" +#define MCHelpSwOL L"\n ol[a] Process symbolic links as the link [absolute paths]" +#define MCHelpSwONI L"\n oni Allow potentially incompatible names" +#define MCHelpSwOR L"\n or Rename files automatically" +#define MCHelpSwOS L"\n os Save NTFS streams" +#define MCHelpSwOW L"\n ow Save or restore file owner and group" +#define MCHelpSwP L"\n p[password] Set password" +#define MCHelpSwPm L"\n p- Do not query password" +#define MCHelpSwQO L"\n qo[-|+] Add quick open information [none|force]" +#define MCHelpSwR L"\n r Recurse subdirectories" +#define MCHelpSwRm L"\n r- Disable recursion" +#define MCHelpSwR0 L"\n r0 Recurse subdirectories for wildcard names only" +#define MCHelpSwRI L"\n ri

[:] Set priority (0-default,1-min..15-max) and sleep time in ms" +#define MCHelpSwRR L"\n rr[N] Add data recovery record" +#define MCHelpSwRV L"\n rv[N] Create recovery volumes" +#define MCHelpSwS L"\n s[,v[-],e] Create solid archive" +#define MCHelpSwSm L"\n s- Disable solid archiving" +#define MCHelpSwSC L"\n sc[obj] Specify the character set" +#define MCHelpSwSFX L"\n sfx[name] Create SFX archive" +#define MCHelpSwSI L"\n si[name] Read data from standard input (stdin)" +#define MCHelpSwSL L"\n sl Process files with size less than specified" +#define MCHelpSwSM L"\n sm Process files with size more than specified" +#define MCHelpSwT L"\n t Test files after archiving" +#define MCHelpSwTK L"\n tk Keep original archive time" +#define MCHelpSwTL L"\n tl Set archive time to latest file" +#define MCHelpSwTN L"\n tn


+ +1: Or set `followTags = true` in your git config to always get this behavior: + + git config --global push.followTags true + +[↩](#a1) \ No newline at end of file diff --git a/Carthage/Checkouts/UnrarKit/Resources/UnrarKit-Info.plist b/Carthage/Checkouts/UnrarKit/Resources/UnrarKit-Info.plist new file mode 100644 index 0000000..ef347dc --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Resources/UnrarKit-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleExecutable + ${EXECUTABLE_NAME} + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + ${PRODUCT_NAME} + CFBundlePackageType + FMWK + CFBundleShortVersionString + 2.9 + CFBundleSignature + ???? + CFBundleVersion + 2.9 + + diff --git a/Carthage/Checkouts/UnrarKit/Resources/UnrarKitResources-Info.plist b/Carthage/Checkouts/UnrarKit/Resources/UnrarKitResources-Info.plist new file mode 100644 index 0000000..2340392 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Resources/UnrarKitResources-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + English + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 2.9 + CFBundleSignature + ???? + CFBundleVersion + 2.9 + NSHumanReadableCopyright + Copyright © 2017 Abbey Code. All rights reserved. + + diff --git a/Carthage/Checkouts/UnrarKit/Resources/en.lproj/UnrarKit.strings b/Carthage/Checkouts/UnrarKit/Resources/en.lproj/UnrarKit.strings new file mode 100644 index 0000000..1fe673d --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Resources/en.lproj/UnrarKit.strings @@ -0,0 +1,45 @@ +/* Error detail string */ +"An unknown error occurred" = "An unknown error occurred"; + +/* Error detail string */ +"Archive has a corrupt header" = "Archive has a corrupt header"; + +/* Error detail string */ +"Buffer too small to contain entire comments" = "Buffer too small to contain entire comments"; + +/* Error detail string */ +"Error encountered while closing the archive" = "Error encountered while closing the archive"; + +/* Error detail string */ +"Error encountered while reading the archive" = "Error encountered while reading the archive"; + +/* Error detail string */ +"Error encountered while writing a file to disk" = "Error encountered while writing a file to disk"; + +/* Error detail string */ +"Failed to create the target directory for extraction" = "Failed to create the target directory for extraction"; + +/* Error detail string */ +"Failed to open a reference to the file" = "Failed to open a reference to the file"; + +/* Error detail string */ +"File is not a valid RAR archive" = "File is not a valid RAR archive"; + +/* Error detail string */ +"No password given to unlock a protected archive" = "No password given to unlock a protected archive"; + +/* Error detail string */ +"Ran out of memory while reading archive" = "Ran out of memory while reading archive"; + +/* Error detail string */ +"RAR headers encrypted in unknown format" = "RAR headers encrypted in unknown format"; + +/* Error detail string */ +"Unable to find the archive" = "Unable to find the archive"; + +/* Error detail string */ +"Unknown error encountered (code %ld)" = "Unknown error encountered (code %ld)"; + +/* Error detail string */ +"User cancelled the operation in progress" = "User cancelled the operation in progress"; + diff --git a/Carthage/Checkouts/UnrarKit/Scripts/add-github-release.py b/Carthage/Checkouts/UnrarKit/Scripts/add-github-release.py new file mode 100755 index 0000000..9f6e0fe --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Scripts/add-github-release.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +# Usage: add-github-release.py +# +# Creates a release in GitHub for the given tag +# + +import json +import os +import urllib2 +import sys + +def add_release(token, repo, tag, archive_path, notes): + ''' + Creates a release on GitHub for the given arguments + ''' + print('token: "{}", repo: "{}", tag: "{}", archive: "{}" notes: "{}"'.format('SECURE' if token else '', repo, tag, archive_path, notes)) + + assert token, 'No API token given' + assert repo, 'No repo given' + assert '/' in repo, "Repo doesn't look like a valid GitHub repo (e.g. abbeycode/UnrarKit)" + assert tag, 'No tag given' + assert archive_path, 'No archive path given' + assert notes, 'No notes given' + + is_beta = tag_is_beta(tag) + + url = 'https://api.github.com/repos/{}/releases?access_token={}'.format(repo, token) + values = { + 'tag_name': tag, + 'name': 'v{}'.format(tag), + 'body': notes, + 'prerelease': True if is_beta else False + } + + data = json.dumps(values) + request = urllib2.Request(url, data) + response = urllib2.urlopen(request) + the_page = response.read() + + response_dict = json.loads(the_page) + upload_url = response_dict['upload_url'] + release_url = response_dict['url'] + + upload_carthage_archive(token, upload_url, archive_path) + + print('Release added: {}'.format(release_url)) + return True + +def tag_is_beta(tag): + ''' + Returns True if the tag contains a label indicating it's a beta build + + >>> tag_is_beta('1.2.3') + False + >>> tag_is_beta('1.2.3-beta') + True + >>> tag_is_beta('1.2.3-beta2') + True + >>> tag_is_beta('1.2.3-RC') + True + >>> tag_is_beta('1.2.3-RC1') + True + >>> tag_is_beta('1.2.3-prerelease') + True + >>> tag_is_beta('1.2.3-prerelease2') + True + >>> tag_is_beta('1.2.3-alpha') + True + >>> tag_is_beta('1.2.3-alpha2') + True + ''' + + return 'beta' in tag or 'RC' in tag or 'prerelease' in tag or 'alpha' in tag + +def upload_carthage_archive(token, upload_url, archive_path): + ''' + Uploads the archive at the given path to GitHub for the release specified + ''' + + upload_url = upload_url.split('{')[0] + url = '{}?access_token={}&name={}'.format(upload_url, token, archive_path) + header = {'Content-Type': 'application/zip'} + + with FileWithLen(archive_path, 'r') as f: + request = urllib2.Request(url, f, header) + response = urllib2.urlopen(request) + + page = response.read() + response_dict = json.loads(page) + return True + +class FileWithLen(file): + def __init__(self, *args, **keyws): + file.__init__(self, *args, **keyws) + + def __len__(self): + return int(os.fstat(self.fileno())[6]) + +if __name__ == '__main__': + # Allow script to be called with 'test' argument + if len(sys.argv) == 2 and sys.argv[1].lower() == 'test': + import doctest + result = doctest.testmod() + sys.exit(0 if result.failed == 0 else 1) + + expected_arg_count = 6 + + if len(sys.argv) != expected_arg_count: + print('\nadd-github-release given {} arguments ({}). Expecting {}\n'.format(len(sys.argv) - 1, sys.argv[1:], expected_arg_count - 1)) + sys.exit(1) + + exit_code = 0 if add_release(*sys.argv[1:]) else 1 + sys.exit(exit_code) \ No newline at end of file diff --git a/Carthage/Checkouts/UnrarKit/Scripts/archive-carthage.sh b/Carthage/Checkouts/UnrarKit/Scripts/archive-carthage.sh new file mode 100755 index 0000000..6afb08e --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Scripts/archive-carthage.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -ev + +# Archives the Carthage packages, and prints the name of the archive + +carthage build --no-skip-current +carthage archive + +export ARCHIVE_PATH="UnrarKit.framework.zip" \ No newline at end of file diff --git a/Carthage/Checkouts/UnrarKit/Scripts/carthage-validate.sh b/Carthage/Checkouts/UnrarKit/Scripts/carthage-validate.sh new file mode 100755 index 0000000..76d4775 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Scripts/carthage-validate.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +REPO="github \"$TRAVIS_REPO_SLUG\"" +COMMIT=$TRAVIS_COMMIT + +if [ -z ${TRAVIS+x} ]; then + REPO="git \"`pwd`\"" + COMMIT=`git log -1 --oneline | cut -f1 -d' '` + echo "Not running in Travis. Setting REPO ($REPO) and COMMIT ($COMMIT)" +fi + +if [ -n "$TRAVIS" ] && [ "$TRAVIS_PULL_REQUEST" != "false" ]; then + REPO="github \"$TRAVIS_PULL_REQUEST_SLUG\"" + COMMIT=$TRAVIS_PULL_REQUEST_SHA + echo "Build is for a Pull Request. Overriding REPO ($REPO) and COMMIT ($COMMIT)" +fi + +if [ ! -d "CarthageValidation" ]; then + mkdir "CarthageValidation" +fi + +echo "Validating commit '$COMMIT'" + +pushd CarthageValidation > /dev/null + +rm Cartfile +rm Cartfile.resolved +rm -rf Carthage + +echo "$REPO \"$COMMIT\"" > Cartfile + +carthage bootstrap --configuration Debug --verbose +EXIT_CODE=$? + +echo "Checking for build products..." + +if [ ! -d "Carthage/Build/Mac/UnrarKit.framework" ]; then + echo "No Mac library built" + EXIT_CODE=1 +fi + +if [ ! -d "Carthage/Build/iOS/UnrarKit.framework" ]; then + echo "No iOS library built" + EXIT_CODE=1 +fi + +popd > /dev/null + +exit $EXIT_CODE \ No newline at end of file diff --git a/Carthage/Checkouts/UnrarKit/Scripts/cocoapod-validate.sh b/Carthage/Checkouts/UnrarKit/Scripts/cocoapod-validate.sh new file mode 100755 index 0000000..9922f12 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Scripts/cocoapod-validate.sh @@ -0,0 +1,28 @@ +#!/bin/bash + +set -ev + +git fetch --tags + +if [ -z "$TRAVIS_TAG" ]; then + TRAVIS_TAG_SUBSTITUTED=1 + export TRAVIS_TAG="$(git tag -l | tail -1)" + echo "Not a tagged build. Using last tag ($TRAVIS_TAG) for pod lib lint..." +fi + +# For linting purposes, fix the error in dll.hpp +sed -i .original 's/RARGetDllVersion();/RARGetDllVersion(void);/' Libraries/unrar/dll.hpp + +# Lint the podspec to check for errors. Don't call `pod spec lint`, because we want it to evaluate locally + +# 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' + +# Put back the original dll.hpp +mv Libraries/unrar/dll.hpp.original Libraries/unrar/dll.hpp + +if [ -n "$TRAVIS_TAG_SUBSTITUTED" ]; then + echo "Unsetting TRAVIS_TAG..." + unset TRAVIS_TAG +fi diff --git a/Carthage/Checkouts/UnrarKit/Scripts/get-release-notes.py b/Carthage/Checkouts/UnrarKit/Scripts/get-release-notes.py new file mode 100755 index 0000000..d789595 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Scripts/get-release-notes.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- + +# Usage: get-release-notes.py +# +# Prints the release notes for a given version of the library, ignoring any +# beta marking on the tag. For beta releases, retrieves the beta notes and +# prepends them +# +# Retrieves release notes from CHANGELOG.mc +# Retrieves beta notes from beta-notes.md +# + +import os.path +import re +import subprocess +import sys + +CHANGELOG_FILEPATH = 'CHANGELOG.md' +BETANOTES_FILEPATH = 'beta-notes.md' + + +def print_release_notes(version): + version_num, beta_tag, beta_num = get_version_parts(version) + change_notes = get_changelog_notes(version_num) + + if beta_tag is None: + print(change_notes) + return True + + beta_notes = get_beta_notes(beta_num, change_notes) + + if not beta_notes is None: + print(beta_notes) + return True + + return False + +def get_version_parts(version): + ''' + Splits out the main part of the version number from any beta tags, and the beta number + + >>> get_version_parts('1.0') + ('1.0', None, None) + + >>> get_version_parts('1.0.1') + ('1.0.1', None, None) + + >>> get_version_parts('1.0-beta') + ('1.0', 'beta', 1) + + >>> get_version_parts('1.0.1-beta') + ('1.0.1', 'beta', 1) + + >>> get_version_parts('1.0-beta1') + ('1.0', 'beta', 1) + + >>> get_version_parts('1.0.2-beta1') + ('1.0.2', 'beta', 1) + + ''' + + matches = re.match(r'(?P[\d\.]+)\-?(?P\D+)?(?P\d+)?', version) + version_num = matches.group('version_num') + beta_tag = matches.group('beta') + beta_num = matches.group('beta_num') + + beta_num = (int(beta_num or 1)) if beta_tag else None + + return (version_num, beta_tag, beta_num) + +def get_version_notes(version_num, changes): + r''' + Returns the portion of the given changelog that corresponds to the changes for the given + version number. version_num is expected to be stripped of any beta info + + This won't work for the last version number in a file, but that's fine + + >>> get_version_notes('1.2', '# UnrarKit CHANGELOG\n\n## 1.2\n\nList of changes\n\n## 1.1\n\nMore changes\n\n## 1.0') + 'List of changes' + + >>> get_version_notes('1.1', '# UnrarKit CHANGELOG\n\n## 1.2\n\nList of changes\n\n## 1.1\n\nMore changes\n\n## 1.0') + 'More changes' + ''' + + notes_regex = r'##\s+{}\s+(.+?)\s+(?:##\s+[\d\.]+).*'.format(version_num.replace('.', '\.')) + matches = re.search(notes_regex, changes, re.DOTALL) + + return matches[1].strip() + +def get_changelog_notes(version_num): + with open(CHANGELOG_FILEPATH, 'r') as changelog: + changes = changelog.read() + + return get_version_notes(version_num, changes) + +def have_beta_notes_been_updated(version): + ''' + Returns True if the beta notes have been updated since the last tag, or if the version + isn't a beta, or if it's the first beta + ''' + + version_num, beta_tag, beta_num = get_version_parts(version) + if not beta_tag or beta_num == 1: + return True + + all_tags = subprocess.check_output(['git', 'tag', '--sort=-taggerdate'], universal_newlines=True) + last_tag = all_tags.split('\n')[0] + + diff_output = subprocess.check_output(['git', 'diff', '--name-only', last_tag, 'HEAD', + '--', BETANOTES_FILEPATH]) + + # Will be 'beta-notes.md' if it has changed, blank otherwise + return bool(diff_output) + +def get_beta_notes(beta_num, change_notes): + ''' + Returns the release's change notes, taking the beta notes into account. If it's + the first beta release, then it doesn't bother. Also checks if the release notes + have been updated since the last beta + ''' + + if beta_num == 1: + return change_notes + + with open(BETANOTES_FILEPATH, 'r') as beta_notes_file: + beta_notes = beta_notes_file.read() + + return '''Updates in this beta: + +{} + +------- +Changes for main release: +{} +'''.format(beta_notes, change_notes) + + +if __name__ == '__main__': + import doctest + doctest.testmod() + + CHECK_BETA_NOTES_FLAG = '--beta-notes-check' + + if len(sys.argv) < 2: + print('\nNo argument given. Pass the version number, optionally with {}\n'.format( + CHECK_BETA_NOTES_FLAG), file=sys.stderr) + sys.exit(1) + + version = sys.argv[1] + + if not version: + print("Empty version number passed", file=sys.stderr) + sys.exit(1) + + if len(sys.argv) >= 3 and sys.argv[2] == CHECK_BETA_NOTES_FLAG: + if not have_beta_notes_been_updated(version): + print("Beta notes haven't been updated since since last release", file=sys.stderr) + sys.exit(1) + + sys.exit(0) + + if not os.path.exists(CHANGELOG_FILEPATH): + CHANGELOG_FILEPATH = os.path.join('..', CHANGELOG_FILEPATH) + BETANOTES_FILEPATH = os.path.join('..', BETANOTES_FILEPATH) + + exit_code = 0 if print_release_notes(version) else 1 + sys.exit(exit_code) \ No newline at end of file diff --git a/Carthage/Checkouts/UnrarKit/Scripts/localize.sh b/Carthage/Checkouts/UnrarKit/Scripts/localize.sh new file mode 100755 index 0000000..73462c6 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Scripts/localize.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# Generate Localizable.strings +find -E . -iregex '.*\.(m|h|mm)$' \ + -not -path "./Tests*" \ + -print0 \ +| xargs -0 genstrings -o Resources/en.lproj + +# Define file and temp file +LOCALIZE=./Resources/en.lproj/UnrarKit.strings +UTF8=./Resources/en.lproj/UnrarKitUTF8.txt + +# Convert file encoding from UTF-16 to UTF-8 +iconv -f UTF-16LE -t UTF-8 $LOCALIZE >$UTF8 +mv $UTF8 $LOCALIZE + +# Replace all \\n tokens in the file with a newline (used in comments) +sed -i "" 's_\\\\n_\ +_g' $LOCALIZE + +# Check for missing comments in the UTF8 file, showing the violating lines +MISSING=$(grep -A 1 'engineer' $LOCALIZE | sed '/*\/$/ s_.*__') + +# If there were missing comments +if [ -n "$MISSING" ]; then + echo "Comments are missing for:" + + #Print output, putting line breaks back in and indenting each line + echo $MISSING | sed 's:-- :\ +:' | sed 's/^/& /g' + + # Return non-zero to signal an error + exit 1 +fi \ No newline at end of file diff --git a/Carthage/Checkouts/UnrarKit/Scripts/push-output.sh b/Carthage/Checkouts/UnrarKit/Scripts/push-output.sh new file mode 100755 index 0000000..5edccb7 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Scripts/push-output.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +set -ev + +# Only potentially push to CocoaPods when it's a tagged build +if [ -z "$TRAVIS_TAG" ]; then + echo -e "\nBuild is not tagged" + exit 0 +fi + +# Make sure tag name looks like a version number +if ! [[ $TRAVIS_TAG =~ ^[0-9\.]+(\-beta[0-9]*)?$ ]]; then + echo -e "\nBranch build not a valid version number: $TRAVIS_TAG" + exit 1 +else + echo -e "\nTag looks like a version number: $TRAVIS_TAG" +fi + +# Skip tests because they're assumed to have passed during the cocoapod-validate script or else +# this script wouldn't run. Allow warnings, because prior validation doesn't (and it patches) +# around the one warning in the UnRAR library I can't silence +echo -e "\nLinting podspec..." +pod spec lint --fail-fast --skip-tests --allow-warnings + +if [ $? -ne 0 ]; then + echo -e "\nPodspec failed lint. Run again with --verbose to troubleshoot" + exit 1 +fi + +echo -e "\nExporting Carthage archive...\n" +# Exports ARCHIVE_PATH, used below +source ./Scripts/archive-carthage.sh + +# Skip tests and allow warnings for reasons stated above +echo -e "\nPushing to CocoaPods...\n" +pod trunk push --skip-tests --allow-warnings + +# If push is successful, add release to GitHub +if [ $? -ne 0 ]; then + echo -e "\nPush to CocoaPods failed" + exit 1 +fi + +RELEASE_NOTES=$(./Scripts/get-release-notes.py "$TRAVIS_TAG") +./Scripts/add-github-release.py $GITHUB_RELEASE_API_TOKEN $TRAVIS_REPO_SLUG $TRAVIS_TAG "$ARCHIVE_PATH" "$RELEASE_NOTES" \ No newline at end of file diff --git a/Carthage/Checkouts/UnrarKit/Scripts/set-version.sh b/Carthage/Checkouts/UnrarKit/Scripts/set-version.sh new file mode 100755 index 0000000..47675a4 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Scripts/set-version.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +# Usage: set-version.sh +# +# Updates the main plist file, then tags the build in Git, using the release notes from CHANGELOG.md + +# Colors +COLOR_OFF='\033[0m' +RED='\033[0;31m' +GREEN='\033[0;32m' +BOLD_YELLOW='\033[1;33m' + +# Did this script change since the last commit? +THIS_FILE_REGEX='.*Scripts/set-version\.sh.*' +THIS_FILE_CHANGED=$(git status --porcelain --untracked-files=no | grep $THIS_FILE_REGEX | wc -l) + +# Only continue if the repo has no changes (excluding this script) +CHANGED_FILE_COUNT=$(git status --porcelain --untracked-files=no | grep -v $THIS_FILE_REGEX | wc -l) +if [ $CHANGED_FILE_COUNT -gt 0 ]; then + echo -e "${RED}Please commit or discard any changes before continuing$COLOR_OFF" + exit 1 +fi + +# Require a single argument to be passed in +if [ "$#" -ne 1 ]; then + echo -e "${RED}Please pass the desired version number as an argument$COLOR_OFF" + exit 1 +fi + +./Scripts/get-release-notes.py $1 --beta-notes-check + +# Check whether beta notes have been updated. The check passes for first- or non-beta releases +if [ ! $? -eq 0 ]; then + exit 1 +fi + +RELEASE_NOTES=$(./Scripts/get-release-notes.py $1) +if [ -z "$RELEASE_NOTES" ]; then + echo -e "${RED}Please add release notes for v$1 into CHANGELOG.md$COLOR_OFF" + exit 1 +fi + +# Require agvtool for updating the plist versions. Exit if not installed +if ! [ -x "$(command -v agvtool)" ]; then + echo -e "${RED}agvtool not found. Are you running on a Mac?$COLOR_OFF" + exit 2 +fi + +echo -e "${GREEN}Updating version numbers in plist to '$1'..$COLOR_OFF" +agvtool new-version -all "$1" # CFBundleVersion +agvtool new-marketing-version "$1" # CFBundleShortVersionString + +if [ "$THIS_FILE_CHANGED" -gt 0 ]; then + echo -e "${BOLD_YELLOW}Not committing to Git, as this script isn't final. Commit it to continue$COLOR_OFF" + exit 2 +fi + +echo -e "${GREEN}Committing updated plist...$COLOR_OFF" +git commit -m "Updated plist to v$1" Resources + +# Revert changes to other plist files +git checkout . + +echo -e "${GREEN}Tagging build...$COLOR_OFF" +git tag $1 -m "$RELEASE_NOTES" \ No newline at end of file diff --git a/Carthage/Checkouts/UnrarKit/Tests/CheckDataTests.m b/Carthage/Checkouts/UnrarKit/Tests/CheckDataTests.m new file mode 100644 index 0000000..6228c67 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Tests/CheckDataTests.m @@ -0,0 +1,94 @@ +// +// CheckDataTests.m +// UnrarKit +// +// Created by Dov Frankel on 10/6/17. +// + +#import "URKArchiveTestCase.h" + +@interface CheckDataTests : URKArchiveTestCase @end + +@implementation CheckDataTests + +#pragma mark - checkDataIntegrity + +- (void)testCheckDataIntegrity { + NSArray *testArchives = @[@"Test Archive.rar", + @"Test Archive (Password).rar", + @"Test Archive (Header Password).rar"]; + + for (NSString *testArchiveName in testArchives) { + NSLog(@"Testing data integrity of archive %@", testArchiveName); + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *password = ([testArchiveName rangeOfString:@"Password"].location != NSNotFound + ? @"password" + : nil); + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL password:password error:nil]; + + BOOL success = [archive checkDataIntegrity]; + XCTAssertTrue(success, @"Data integrity check failed for %@", testArchiveName); + } +} + +- (void)testCheckDataIntegrity_NotAnArchive { + NSURL *testArchiveURL = self.testFileURLs[@"Test File B.jpg"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + BOOL success = [archive checkDataIntegrity]; + XCTAssertFalse(success, @"Data integrity check passed for non-archive"); +} + +- (void)testCheckDataIntegrity_ModifiedCRC { + NSURL *testArchiveURL = self.testFileURLs[@"Modified CRC Archive.rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + BOOL success = [archive checkDataIntegrity]; + XCTAssertFalse(success, @"Data integrity check passed for archive with a modified CRC"); +} + +#pragma mark - checkDataIntegrityOfFile + +- (void)testCheckDataIntegrityForFile { + NSArray *testArchives = @[@"Test Archive.rar", + @"Test Archive (Password).rar", + @"Test Archive (Header Password).rar"]; + + for (NSString *testArchiveName in testArchives) { + NSLog(@"Testing data integrity of file in archive %@", testArchiveName); + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *password = ([testArchiveName rangeOfString:@"Password"].location != NSNotFound + ? @"password" + : nil); + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL password:password error:nil]; + + NSError *listFilenamesError = nil; + NSArray *filenames = [archive listFilenames:&listFilenamesError]; + + XCTAssertNotNil(filenames, @"No file info returned for %@", testArchiveName); + XCTAssertNil(listFilenamesError, @"Error returned for %@: %@", testArchiveName, listFilenamesError); + + NSString *firstFilename = filenames.firstObject; + BOOL success = [archive checkDataIntegrityOfFile:firstFilename]; + + XCTAssertTrue(success, @"Data integrity check failed for %@ in %@", firstFilename, testArchiveName); + } +} + +- (void)testCheckDataIntegrityForFile_NotAnArchive { + NSURL *testArchiveURL = self.testFileURLs[@"Test File B.jpg"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + BOOL success = [archive checkDataIntegrityOfFile:@"README.md"]; + XCTAssertFalse(success, @"Data integrity check passed for non-archive"); +} + +- (void)testCheckDataIntegrityForFile_ModifiedCRC { + NSURL *testArchiveURL = self.testFileURLs[@"Modified CRC Archive.rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + BOOL success = [archive checkDataIntegrityOfFile:@"README.md"]; + XCTAssertFalse(success, @"Data integrity check passed for archive with modified CRC"); +} + +@end diff --git a/Carthage/Checkouts/UnrarKit/Tests/ExtractFilesTests.m b/Carthage/Checkouts/UnrarKit/Tests/ExtractFilesTests.m new file mode 100644 index 0000000..2f2bde7 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Tests/ExtractFilesTests.m @@ -0,0 +1,243 @@ +// +// ExtractFilesTests.m +// UnrarKit +// +// Created by Dov Frankel on 6/22/15. +// +// + +#import "URKArchiveTestCase.h" + +@interface ExtractFilesTests : URKArchiveTestCase + +@end + +@implementation ExtractFilesTests + +- (void)testExtractFiles +{ + NSArray *testArchives = @[@"Test Archive.rar", + @"Test Archive (Password).rar", + @"Test Archive (Header Password).rar"]; + + NSSet *expectedFileSet = [self.testFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) { + return ![key hasSuffix:@"rar"]; + }]; + + NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)]; + + NSFileManager *fm = [NSFileManager defaultManager]; + + for (NSString *testArchiveName in testArchives) { + NSLog(@"Testing extraction of archive %@", testArchiveName); + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *extractDirectory = [self randomDirectoryWithPrefix: + [testArchiveName stringByDeletingPathExtension]]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + NSString *password = ([testArchiveName rangeOfString:@"Password"].location != NSNotFound + ? @"password" + : nil); + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL password:password error:nil]; + + NSError *error = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&error]; + + XCTAssertNil(error, @"Error returned by unrarFileTo:overWrite:error:"); + XCTAssertTrue(success, @"Unrar failed to extract %@ to %@", testArchiveName, extractURL); + + error = nil; + NSArray *extractedFiles = [[fm contentsOfDirectoryAtPath:extractURL.path + error:&error] + sortedArrayUsingSelector:@selector(compare:)]; + + XCTAssertNil(error, @"Failed to list contents of extract directory: %@", extractURL); + + XCTAssertNotNil(extractedFiles, @"No list of files returned"); + XCTAssertEqual(extractedFiles.count, expectedFileSet.count, + @"Incorrect number of files listed in archive"); + + for (NSInteger i = 0; i < extractedFiles.count; i++) { + NSString *extractedFilename = extractedFiles[i]; + NSString *expectedFilename = expectedFiles[i]; + + XCTAssertEqualObjects(extractedFilename, expectedFilename, @"Incorrect filename listed"); + + NSURL *extractedFileURL = [extractURL URLByAppendingPathComponent:extractedFilename]; + NSURL *expectedFileURL = self.testFileURLs[expectedFilename]; + + NSData *extractedFileData = [NSData dataWithContentsOfURL:extractedFileURL]; + NSData *expectedFileData = [NSData dataWithContentsOfURL:expectedFileURL]; + + XCTAssertTrue([expectedFileData isEqualToData:extractedFileData], @"Data in file doesn't match source"); + } + } +} + +- (void)testExtractFiles_RAR5 +{ + NSFileManager *fm = [NSFileManager defaultManager]; + +#if !TARGET_OS_IPHONE + NSURL *extractRootDirectory = self.tempDirectory; +#else + NSURL *extractRootDirectory = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory + inDomains:NSUserDomainMask] firstObject]; + extractRootDirectory = [extractRootDirectory URLByAppendingPathComponent:@"testExtractFiles_RAR5"]; + NSLog(@"Documents directory: %@", extractRootDirectory.path); + + if ([fm fileExistsAtPath:extractRootDirectory.path]) { + NSError *clearDirError = nil; + XCTAssertTrue([fm removeItemAtURL:extractRootDirectory error:&clearDirError], @"Failed to clear out documents directory"); + XCTAssertNil(clearDirError, @"Error while clearing out documents directory"); + } + +#endif + NSArray *expectedFiles = @[@"nopw.txt", + @"yohoho_ws.txt"]; + + NSString *testArchiveName = @"Test Archive (RAR5).rar"; + + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + + for (NSInteger i = 0; i < 10; i++) { + NSString *extractDir = [NSString stringWithFormat:@"%ld_%@", (long)i, testArchiveName.stringByDeletingPathExtension]; + NSURL *extractURL = [extractRootDirectory URLByAppendingPathComponent:extractDir]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *error = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&error]; + + XCTAssertNil(error, @"Error returned by unrarFileTo:overWrite:error:"); + XCTAssertTrue(success, @"Unrar failed to extract %@ to %@", testArchiveName, extractURL); + + error = nil; + NSArray *extractedFiles = [[fm contentsOfDirectoryAtPath:extractURL.path + error:&error] + sortedArrayUsingSelector:@selector(compare:)]; + + XCTAssertNil(error, @"Failed to list contents of extract directory: %@", extractURL); + + XCTAssertNotNil(extractedFiles, @"No list of files returned"); + XCTAssertEqual(extractedFiles.count, expectedFiles.count, + @"Incorrect number of files listed in archive"); + + for (NSInteger x = 0; x < extractedFiles.count; x++) { + NSString *extractedFilename = extractedFiles[x]; + NSString *expectedFilename = expectedFiles[x]; + + XCTAssertEqualObjects(extractedFilename, expectedFilename, @"Incorrect filename listed"); + + NSURL *extractedFileURL = [extractURL URLByAppendingPathComponent:extractedFilename]; + XCTAssertTrue([fm fileExistsAtPath:extractedFileURL.path], @"No file extracted"); + } + } +} + +- (void)testExtractFiles_Unicode +{ + NSSet *expectedFileSet = [self.unicodeFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) { + return ![key hasSuffix:@"rar"]; + }]; + + NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)]; + + NSFileManager *fm = [NSFileManager defaultManager]; + + NSString *testArchiveName = @"Ⓣest Ⓐrchive.rar"; + NSURL *testArchiveURL = self.unicodeFileURLs[testArchiveName]; + NSString *extractDirectory = [self randomDirectoryWithPrefix: + [testArchiveName stringByDeletingPathExtension]]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *error = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&error]; + + XCTAssertNil(error, @"Error returned by unrarFileTo:overWrite:error:"); + XCTAssertTrue(success, @"Unrar failed to extract %@ to %@", testArchiveName, extractURL); + + error = nil; + NSArray *extractedFiles = [[fm contentsOfDirectoryAtPath:extractURL.path + error:&error] + sortedArrayUsingSelector:@selector(compare:)]; + + XCTAssertNil(error, @"Failed to list contents of extract directory: %@", extractURL); + + XCTAssertNotNil(extractedFiles, @"No list of files returned"); + XCTAssertEqual(extractedFiles.count, expectedFileSet.count, + @"Incorrect number of files listed in archive"); + + for (NSInteger i = 0; i < extractedFiles.count; i++) { + NSString *extractedFilename = extractedFiles[i]; + NSString *expectedFilename = expectedFiles[i]; + + XCTAssertEqualObjects(extractedFilename, expectedFilename, @"Incorrect filename listed"); + + NSURL *extractedFileURL = [extractURL URLByAppendingPathComponent:extractedFilename]; + NSURL *expectedFileURL = self.unicodeFileURLs[expectedFilename]; + + NSData *extractedFileData = [NSData dataWithContentsOfURL:extractedFileURL]; + NSData *expectedFileData = [NSData dataWithContentsOfURL:expectedFileURL]; + + XCTAssertTrue([expectedFileData isEqualToData:extractedFileData], @"Data in file doesn't match source"); + } +} + +- (void)testExtractFiles_NoPasswordGiven +{ + NSArray *testArchives = @[@"Test Archive (Password).rar", + @"Test Archive (Header Password).rar"]; + + NSFileManager *fm = [NSFileManager defaultManager]; + + for (NSString *testArchiveName in testArchives) { + NSLog(@"Testing extraction archive (no password given): %@", testArchiveName); + URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[testArchiveName] error:nil]; + + NSString *extractDirectory = [self randomDirectoryWithPrefix: + [testArchiveName stringByDeletingPathExtension]]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + + NSError *error = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&error]; + BOOL dirExists = [fm fileExistsAtPath:extractURL.path]; + + XCTAssertFalse(success, @"Extract without password succeeded"); + XCTAssertEqual(error.code, URKErrorCodeMissingPassword, @"Unexpected error code returned"); + XCTAssertFalse(dirExists, @"Directory successfully created without password"); + } +} + +- (void)testExtractFiles_InvalidArchive +{ + NSFileManager *fm = [NSFileManager defaultManager]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Test File A.txt"] error:nil]; + + NSString *extractDirectory = [self randomDirectoryWithPrefix:@"ExtractInvalidArchive"]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + NSError *error = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&error]; + BOOL dirExists = [fm fileExistsAtPath:extractURL.path]; + + XCTAssertFalse(success, @"Extract invalid archive succeeded"); + XCTAssertEqual(error.code, URKErrorCodeBadArchive, @"Unexpected error code returned"); + XCTAssertFalse(dirExists, @"Directory successfully created for invalid archive"); +} + +@end diff --git a/Carthage/Checkouts/UnrarKit/Tests/FirstVolumeTests.m b/Carthage/Checkouts/UnrarKit/Tests/FirstVolumeTests.m new file mode 100644 index 0000000..cdd25fb --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Tests/FirstVolumeTests.m @@ -0,0 +1,109 @@ +// +// FirstVolumeTests.m +// UnrarKit +// +// Created by Dov Frankel on 2/9/17. +// +// + +#import "URKArchiveTestCase.h" + +@interface FirstVolumeTests : URKArchiveTestCase @end + +@interface URKArchive (Tests) + +// It's a private class method ++ (NSURL *)firstVolumeURL:(NSURL *)volumeURL; + +@end + +@implementation FirstVolumeTests + +- (void)testSingleVolume { + NSURL *onlyVolumeArchiveURL = self.testFileURLs[@"Test Archive.rar"]; + NSURL *returnedFirstVolumeURL = [URKArchive firstVolumeURL:onlyVolumeArchiveURL]; + + XCTAssertNotNil(returnedFirstVolumeURL, @"No URL returned"); + XCTAssertEqualObjects(returnedFirstVolumeURL, onlyVolumeArchiveURL, @"URL changed even though it's a single volume archive"); +} + + +#if !TARGET_OS_IPHONE +- (void)testMultipleVolume_UseFirstVolume { + NSArray *volumeURLs = [self multiPartArchiveWithName:@"FirstVolumeTests-testMultipleVolume_UseFirstVolume.rar"]; + NSURL *firstVolumeURL = volumeURLs.firstObject; + NSURL *returnedFirstVolumeURL = [URKArchive firstVolumeURL:firstVolumeURL]; + + XCTAssertNotNil(returnedFirstVolumeURL, @"No URL returned"); + XCTAssertEqualObjects(returnedFirstVolumeURL, firstVolumeURL, @"URL changed even though it was initialized with the first volume"); +} +#endif + +#if !TARGET_OS_IPHONE +- (void)testMultipleVolume_UseMiddleVolume { + NSArray *volumeURLs = [self multiPartArchiveWithName:@"ListVolumesTests-testMultipleVolume_UseFirstVolume.rar"]; + NSURL *firstVolumeURL = volumeURLs.firstObject; + NSURL *thirdVolumeURL = volumeURLs[2]; + + NSURL *returnedFirstVolumeURL = [URKArchive firstVolumeURL:thirdVolumeURL]; + + XCTAssertNotNil(returnedFirstVolumeURL, @"No URL returned"); + XCTAssertEqualObjects(returnedFirstVolumeURL.absoluteString, firstVolumeURL.absoluteString, @"Incorrect URL returned as first volume"); +} +#endif + +#if !TARGET_OS_IPHONE +- (void)testMultipleVolume_UseMiddleVolume_OneHundredParts { + NSArray *volumeURLs = [self multiPartArchiveWithName:@"ListVolumesTests-testMultipleVolume_UseFirstVolume.rar" fileSize:2500000]; + + NSURL *firstVolumeURL = volumeURLs.firstObject; + NSURL *hundredthVolumeURL = volumeURLs[100]; + + NSURL *returnedFirstVolumeURL = [URKArchive firstVolumeURL:hundredthVolumeURL]; + + XCTAssertNotNil(returnedFirstVolumeURL, @"No URL returned"); + XCTAssertEqualObjects(returnedFirstVolumeURL.absoluteString, firstVolumeURL.absoluteString, @"Incorrect URL returned as first volume"); +} +#endif + +#if !TARGET_OS_IPHONE +- (void)testMultipleVolume_UseFirstVolume_OldNamingScheme { + NSArray *volumeURLs = [self multiPartArchiveOldSchemeWithName:@"FirstVolumeTests-testMultipleVolume_UseFirstVolume_OldNamingScheme.rar"]; + NSURL *firstVolumeURL = volumeURLs.firstObject; + NSURL *returnedFirstVolumeURL = [URKArchive firstVolumeURL:firstVolumeURL]; + + XCTAssertNotNil(returnedFirstVolumeURL, @"No URL returned"); + XCTAssertEqualObjects(returnedFirstVolumeURL, firstVolumeURL, @"URL changed even though it was initialized with the first volume"); +} +#endif + +#if !TARGET_OS_IPHONE +- (void)testMultipleVolume_UseMiddleVolume_OldNamingScheme { + NSArray *volumeURLs = [self multiPartArchiveOldSchemeWithName:@"FirstVolumeTests-testMultipleVolume_UseMiddleVolume_OldNamingScheme.rar"]; + NSURL *firstVolumeURL = volumeURLs.firstObject; + NSURL *thirdVolumeURL = volumeURLs[2]; + + NSURL *returnedFirstVolumeURL = [URKArchive firstVolumeURL:thirdVolumeURL]; + + XCTAssertNotNil(returnedFirstVolumeURL, @"No URL returned"); + XCTAssertEqualObjects(returnedFirstVolumeURL.absoluteString, firstVolumeURL.absoluteString, @"Incorrect URL returned as first volume"); +} +#endif + +#if !TARGET_OS_IPHONE +- (void)testMultipleVolume_FirstVolumeMissing { + NSArray *volumeURLs = [self multiPartArchiveWithName:@"ListVolumesTests-testMultipleVolume_FirstVolumeMissing.rar"]; + + NSError *deleteError = nil; + [[NSFileManager defaultManager] removeItemAtURL:volumeURLs.firstObject + error:&deleteError]; + XCTAssertNil(deleteError, @"Error deleting first volume of archive"); + + NSURL *firstVolumeURL = volumeURLs.firstObject; + NSURL *returnedFirstVolumeURL = [URKArchive firstVolumeURL:firstVolumeURL]; + + XCTAssertNil(returnedFirstVolumeURL, @"First volume URL returned when it does not exist"); +} +#endif + +@end diff --git a/Carthage/Checkouts/UnrarKit/Tests/HasMultipleVolumesTests.m b/Carthage/Checkouts/UnrarKit/Tests/HasMultipleVolumesTests.m new file mode 100644 index 0000000..02bf2df --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Tests/HasMultipleVolumesTests.m @@ -0,0 +1,73 @@ +// +// HasMultipleVolumesTests.m +// UnrarKit +// +// Created by Dov Frankel on 2/9/17. +// +// + +#import "URKArchiveTestCase.h" + +@interface HasMultipleVolumesTests : URKArchiveTestCase + +@end + +@implementation HasMultipleVolumesTests + +- (void)testSingleVolume { + NSURL *testArchiveURL = self.testFileURLs[@"Test Archive.rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + BOOL hasMultipleParts = archive.hasMultipleVolumes; + + XCTAssertFalse(hasMultipleParts, @"Single-volume archive reported to have multiple parts"); +} + +#if !TARGET_OS_IPHONE +- (void)testMultipleVolume_UseFirstVolume { + NSArray *volumeURLs = [self multiPartArchiveWithName:@"HasMultipleVolumesTests-testMultipleVolume_UseFirstVolume.rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:volumeURLs.firstObject error:nil]; + + BOOL hasMultipleParts = archive.hasMultipleVolumes; + XCTAssertTrue(hasMultipleParts, @"Multi-volume archive's first part not reported to have multiple volumes"); +} +#endif + +#if !TARGET_OS_IPHONE +- (void)testMultipleVolume_UseMiddleVolume { + NSArray *volumeURLs = [self multiPartArchiveWithName:@"HasMultipleVolumesTests-testMultipleVolume_UseMiddleVolume.rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:volumeURLs[2] error:nil]; + + BOOL hasMultipleParts = archive.hasMultipleVolumes; + XCTAssertTrue(hasMultipleParts, @"Multi-volume archive's middle part not reported to have multiple volumes"); +} +#endif + +#if !TARGET_OS_IPHONE +- (void)testMultipleVolume_UseFirstVolume_OldNamingScheme { + NSArray *volumeURLs = [self multiPartArchiveOldSchemeWithName:@"HasMultipleVolumesTests-testMultipleVolume_UseFirstVolume_OldNamingScheme.rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:volumeURLs.firstObject error:nil]; + + BOOL hasMultipleParts = archive.hasMultipleVolumes; + XCTAssertTrue(hasMultipleParts, @"Multi-volume archive's first part not reported to have multiple volumes"); +} +#endif + +#if !TARGET_OS_IPHONE +- (void)testMultipleVolume_UseMiddleVolume_OldNamingScheme { + NSArray *volumeURLs = [self multiPartArchiveOldSchemeWithName:@"HasMultipleVolumesTests-testMultipleVolume_UseMiddleVolume_OldNamingScheme.rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:volumeURLs[2] error:nil]; + + BOOL hasMultipleParts = archive.hasMultipleVolumes; + XCTAssertTrue(hasMultipleParts, @"Multi-volume archive's middle part not reported to have multiple volumes"); +} +#endif + +- (void)testInvalidArchive { + URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Test File A.txt"] error:nil]; + + BOOL hasMultipleParts = archive.hasMultipleVolumes; + XCTAssertFalse(hasMultipleParts, @"Invalid archive reported to have multiple volumes"); +} + +@end diff --git a/Carthage/Checkouts/UnrarKit/Tests/IsPasswordProtectedTests.m b/Carthage/Checkouts/UnrarKit/Tests/IsPasswordProtectedTests.m new file mode 100644 index 0000000..b9be514 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Tests/IsPasswordProtectedTests.m @@ -0,0 +1,53 @@ +// +// IsPasswordProtectedTests.m +// UnrarKit +// +// Created by Dov Frankel on 6/22/15. +// +// + +#import "URKArchiveTestCase.h" + +@interface IsPasswordProtectedTests : URKArchiveTestCase + +@end + +@implementation IsPasswordProtectedTests + +- (void)testIsPasswordProtected_PasswordRequired +{ + NSURL *archiveURL = self.testFileURLs[@"Test Archive (Password).rar"]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:archiveURL error:nil]; + + XCTAssertTrue(archive.isPasswordProtected, @"isPasswordProtected = NO for password-protected archive"); +} + +- (void)testIsPasswordProtected_PasswordRequired_RAR5 +{ + NSURL *archiveURL = self.testFileURLs[@"Test Archive (RAR5, Password).rar"]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:archiveURL error:nil]; + + XCTAssertTrue(archive.isPasswordProtected, @"isPasswordProtected = NO for password-protected RAR5 archive"); +} + +- (void)testIsPasswordProtected_HeaderPasswordRequired +{ + NSURL *archiveURL = self.testFileURLs[@"Test Archive (Header Password).rar"]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:archiveURL error:nil]; + + XCTAssertTrue(archive.isPasswordProtected, @"isPasswordProtected = NO for password-protected archive"); +} + +- (void)testIsPasswordProtected_PasswordNotRequired +{ + NSURL *archiveURL = self.testFileURLs[@"Test Archive.rar"]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:archiveURL error:nil]; + + XCTAssertFalse(archive.isPasswordProtected, @"isPasswordProtected = YES for password-protected archive"); +} + +@end diff --git a/Carthage/Checkouts/UnrarKit/Tests/IterateFileInfoTests.m b/Carthage/Checkouts/UnrarKit/Tests/IterateFileInfoTests.m new file mode 100644 index 0000000..a3238a9 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Tests/IterateFileInfoTests.m @@ -0,0 +1,214 @@ +// +// IterateFileInfoTests.m +// UnrarKit +// +// Created by Dov Frankel on 5/22/18. +// +// + +#import "URKArchiveTestCase.h" + +@interface IterateFileInfoTests : URKArchiveTestCase + +@end + +@implementation IterateFileInfoTests + + +- (void)testIterateFileInfo +{ + NSArray *testArchives = @[@"Test Archive.rar", @"Test Archive (Password).rar"]; + + NSSet *expectedFileSet = [self.testFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) { + return ![key hasSuffix:@"rar"]; + }]; + + NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)]; + + for (NSString *testArchiveName in testArchives) { + NSLog(@"Testing list files of archive %@", testArchiveName); + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *error = nil; + NSMutableArray *iteratedFiles = [NSMutableArray array]; + BOOL success = [archive iterateFileInfo:^(URKFileInfo * _Nonnull fileInfo, BOOL * _Nonnull stop) { + [iteratedFiles addObject:fileInfo.filename]; + } + error:&error]; + + XCTAssertTrue(success, @"Error returned by iterateFileInfo"); + XCTAssertNil(error, @"Error returned by iterateFileInfo"); + XCTAssertEqual(iteratedFiles.count, expectedFileSet.count, + @"Incorrect number of files listed in archive"); + + for (NSInteger i = 0; i < iteratedFiles.count; i++) { + NSString *archiveFilename = iteratedFiles[i]; + NSString *expectedFilename = expectedFiles[i]; + + NSLog(@"Testing for file %@", expectedFilename); + + XCTAssertEqualObjects(archiveFilename, expectedFilename, @"Incorrect filename listed"); + } + } +} + +- (void)testIterateFileInfo_Unicode +{ + NSSet *expectedFileSet = [self.unicodeFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) { + return ![key hasSuffix:@"rar"]; + }]; + + NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)]; + + NSURL *testArchiveURL = self.unicodeFileURLs[@"Ⓣest Ⓐrchive.rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *error = nil; + NSMutableArray *iteratedFiles = [NSMutableArray array]; + BOOL success = [archive iterateFileInfo:^(URKFileInfo * _Nonnull fileInfo, BOOL * _Nonnull stop) { + [iteratedFiles addObject:fileInfo.filename]; + } + error:&error]; + + XCTAssertTrue(success, @"Error returned by iterateFileInfo"); + XCTAssertNil(error, @"Error returned by iterateFileInfo"); + XCTAssertEqual(iteratedFiles.count, expectedFileSet.count, + @"Incorrect number of files listed in archive"); + + for (NSInteger i = 0; i < iteratedFiles.count; i++) { + NSString *archiveFilename = iteratedFiles[i]; + NSString *expectedFilename = expectedFiles[i]; + + XCTAssertEqualObjects(archiveFilename, expectedFilename, @"Incorrect filename listed"); + } +} + +- (void)testIterateFileInfo_RAR5 +{ + NSArray *expectedFiles = @[@"yohoho_ws.txt", + @"nopw.txt"]; + + NSURL *testArchiveURL = self.testFileURLs[@"Test Archive (RAR5).rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *error = nil; + NSMutableArray *iteratedFiles = [NSMutableArray array]; + BOOL success = [archive iterateFileInfo:^(URKFileInfo * _Nonnull fileInfo, BOOL * _Nonnull stop) { + [iteratedFiles addObject:fileInfo.filename]; + } + error:&error]; + + XCTAssertTrue(success, @"Error returned by iterateFileInfo"); + XCTAssertNil(error, @"Error returned by iterateFileInfo"); + XCTAssertEqual(iteratedFiles.count, expectedFiles.count, + @"Incorrect number of files listed in archive"); + + for (NSInteger i = 0; i < iteratedFiles.count; i++) { + NSString *archiveFilename = iteratedFiles[i]; + NSString *expectedFilename = expectedFiles[i]; + + XCTAssertEqualObjects(archiveFilename, expectedFilename, @"Incorrect filename listed"); + } +} + +- (void)testIterateFileInfo_HeaderPassword +{ + NSArray *testArchives = @[@"Test Archive (Header Password).rar"]; + + NSSet *expectedFileSet = [self.testFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) { + return ![key hasSuffix:@"rar"]; + }]; + + NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)]; + + for (NSString *testArchiveName in testArchives) { + NSLog(@"Testing list files of archive %@", testArchiveName); + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + + URKArchive *archiveNoPassword = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *passwordError = nil; + NSArray *filesInArchive = [archiveNoPassword listFilenames:&passwordError]; + + XCTAssertNotNil(passwordError, @"No error returned by listFilenames (no password given)"); + XCTAssertNil(filesInArchive, @"List of files returned (no password given)"); + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL password:@"password" error:nil]; + + NSError *error = nil; + NSMutableArray *iteratedFiles = [NSMutableArray array]; + BOOL success = [archive iterateFileInfo:^(URKFileInfo * _Nonnull fileInfo, BOOL * _Nonnull stop) { + [iteratedFiles addObject:fileInfo.filename]; + } + error:&error]; + + XCTAssertTrue(success, @"Error returned by iterateFileInfo"); + XCTAssertNil(error, @"Error returned by iterateFileInfo"); + XCTAssertEqual(iteratedFiles.count, expectedFiles.count, + @"Incorrect number of files listed in archive"); + + for (NSInteger i = 0; i < iteratedFiles.count; i++) { + NSString *archiveFilename = iteratedFiles[i]; + NSString *expectedFilename = expectedFiles[i]; + + NSLog(@"Testing for file %@", expectedFilename); + + XCTAssertEqualObjects(archiveFilename, expectedFilename, @"Incorrect filename listed"); + } + } +} + +- (void)testIterateFileInfo_NoHeaderPasswordGiven +{ + URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Test Archive (Header Password).rar"] error:nil]; + + NSError *error = nil; + __block BOOL called = NO; + BOOL success = [archive iterateFileInfo:^(URKFileInfo * _Nonnull fileInfo, BOOL * _Nonnull stop) { + called = YES; + } + error:&error]; + + XCTAssertNotNil(error, @"Iteration without password returned no error"); + XCTAssertFalse(success, @"Iteration without password succeeded"); + XCTAssertFalse(called, @"Iteration without password called action block"); + XCTAssertEqual(error.code, URKErrorCodeMissingPassword, @"Unexpected error code returned"); +} + +- (void)testIterateFileInfo_NoFilePasswordGiven +{ + URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Test Archive (Password).rar"] error:nil]; + + NSError *error = nil; + __block BOOL called = NO; + BOOL success = [archive iterateFileInfo:^(URKFileInfo * _Nonnull fileInfo, BOOL * _Nonnull stop) { + called = YES; + } + error:&error]; + + XCTAssertNil(error, @"Iteration without file password failed"); + XCTAssertTrue(success, @"Iteration without file password failed"); + XCTAssertTrue(called, @"Iteration without file password didn't call action block"); +} + +- (void)testIterateFileInfo_InvalidArchive +{ + URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Test File A.txt"] error:nil]; + + NSError *error = nil; + __block BOOL called = NO; + BOOL success = [archive iterateFileInfo:^(URKFileInfo * _Nonnull fileInfo, BOOL * _Nonnull stop) { + called = YES; + } + error:&error]; + + XCTAssertNotNil(error, @"Iteration of invalid archive succeeded"); + XCTAssertFalse(success, @"Iteration for invalid archive succeeded"); + XCTAssertFalse(called, @"Iteration for invalid archive called action block"); + XCTAssertEqual(error.code, URKErrorCodeBadArchive, @"Unexpected error code returned"); +} + + +@end diff --git a/Carthage/Checkouts/UnrarKit/Tests/ListFilenamesTests.m b/Carthage/Checkouts/UnrarKit/Tests/ListFilenamesTests.m new file mode 100644 index 0000000..4c94e11 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Tests/ListFilenamesTests.m @@ -0,0 +1,183 @@ +// +// ListFilenamesTests.m +// UnrarKit +// +// Created by Dov Frankel on 6/22/15. +// +// + +#import "URKArchiveTestCase.h" + +@interface ListFilenamesTests : URKArchiveTestCase + +@end + +@implementation ListFilenamesTests + + +- (void)testListFilenames +{ + NSArray *testArchives = @[@"Test Archive.rar", @"Test Archive (Password).rar"]; + + NSSet *expectedFileSet = [self.testFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) { + return ![key hasSuffix:@"rar"]; + }]; + + NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)]; + + for (NSString *testArchiveName in testArchives) { + NSLog(@"Testing list files of archive %@", testArchiveName); + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *error = nil; + NSArray *filesInArchive = [archive listFilenames:&error]; + + XCTAssertNil(error, @"Error returned by listFilenames"); + XCTAssertNotNil(filesInArchive, @"No list of files returned"); + XCTAssertEqual(filesInArchive.count, expectedFileSet.count, + @"Incorrect number of files listed in archive"); + + for (NSInteger i = 0; i < filesInArchive.count; i++) { + NSString *archiveFilename = filesInArchive[i]; + NSString *expectedFilename = expectedFiles[i]; + + NSLog(@"Testing for file %@", expectedFilename); + + XCTAssertEqualObjects(archiveFilename, expectedFilename, @"Incorrect filename listed"); + } + } +} + +- (void)testListFilenames_Unicode +{ + NSSet *expectedFileSet = [self.unicodeFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) { + return ![key hasSuffix:@"rar"]; + }]; + + NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)]; + + NSURL *testArchiveURL = self.unicodeFileURLs[@"Ⓣest Ⓐrchive.rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *error = nil; + NSArray *filesInArchive = [archive listFilenames:&error]; + + XCTAssertNil(error, @"Error returned by listFilenames"); + XCTAssertNotNil(filesInArchive, @"No list of files returned"); + XCTAssertEqual(filesInArchive.count, expectedFileSet.count, + @"Incorrect number of files listed in archive"); + + for (NSInteger i = 0; i < filesInArchive.count; i++) { + NSString *archiveFilename = filesInArchive[i]; + NSString *expectedFilename = expectedFiles[i]; + + XCTAssertEqualObjects(archiveFilename, expectedFilename, @"Incorrect filename listed"); + } +} + +- (void)testListFilenames_RAR5 +{ + NSArray *expectedFiles = @[@"yohoho_ws.txt", + @"nopw.txt"]; + + NSURL *testArchiveURL = self.testFileURLs[@"Test Archive (RAR5).rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *error = nil; + NSArray *filesInArchive = [archive listFilenames:&error]; + + XCTAssertNil(error, @"Error returned by listFilenames"); + XCTAssertNotNil(filesInArchive, @"No list of files returned"); + XCTAssertEqual(filesInArchive.count, expectedFiles.count, + @"Incorrect number of files listed in archive"); + + for (NSInteger i = 0; i < filesInArchive.count; i++) { + NSString *archiveFilename = filesInArchive[i]; + NSString *expectedFilename = expectedFiles[i]; + + XCTAssertEqualObjects(archiveFilename, expectedFilename, @"Incorrect filename listed"); + } +} + +- (void)testListFilenames_HeaderPassword +{ + NSArray *testArchives = @[@"Test Archive (Header Password).rar"]; + + NSSet *expectedFileSet = [self.testFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) { + return ![key hasSuffix:@"rar"]; + }]; + + NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)]; + + for (NSString *testArchiveName in testArchives) { + NSLog(@"Testing list files of archive %@", testArchiveName); + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + + URKArchive *archiveNoPassword = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *error = nil; + NSArray *filesInArchive = [archiveNoPassword listFilenames:&error]; + + XCTAssertNotNil(error, @"No error returned by listFilenames (no password given)"); + XCTAssertNil(filesInArchive, @"List of files returned (no password given)"); + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL password:@"password" error:nil]; + + filesInArchive = nil; + error = nil; + filesInArchive = [archive listFilenames:&error]; + + XCTAssertNil(error, @"Error returned by listFilenames"); + XCTAssertEqual(filesInArchive.count, expectedFileSet.count, + @"Incorrect number of files listed in archive"); + + for (NSInteger i = 0; i < filesInArchive.count; i++) { + NSString *archiveFilename = filesInArchive[i]; + NSString *expectedFilename = expectedFiles[i]; + + NSLog(@"Testing for file %@", expectedFilename); + + XCTAssertEqualObjects(archiveFilename, expectedFilename, @"Incorrect filename listed"); + } + } +} + +- (void)testListFilenames_NoHeaderPasswordGiven +{ + URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Test Archive (Header Password).rar"] error:nil]; + + NSError *error = nil; + NSArray *files = [archive listFilenames:&error]; + + XCTAssertNotNil(error, @"List without password succeeded"); + XCTAssertNil(files, @"List returned without password"); + XCTAssertEqual(error.code, URKErrorCodeMissingPassword, @"Unexpected error code returned"); +} + +- (void)testListFilenames_NoFilePasswordGiven +{ + URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Test Archive (Password).rar"] error:nil]; + + NSError *error = nil; + NSArray *files = [archive listFilenames:&error]; + + XCTAssertNil(error, @"List without password succeeded"); + XCTAssertNotNil(files, @"List returned without password"); +} + +- (void)testListFilenames_InvalidArchive +{ + URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Test File A.txt"] error:nil]; + + NSError *error = nil; + NSArray *files = [archive listFilenames:&error]; + + XCTAssertNotNil(error, @"List files of invalid archive succeeded"); + XCTAssertNil(files, @"List returned for invalid archive"); + XCTAssertEqual(error.code, URKErrorCodeBadArchive, @"Unexpected error code returned"); +} + + +@end diff --git a/Carthage/Checkouts/UnrarKit/Tests/ListVolumesTests.m b/Carthage/Checkouts/UnrarKit/Tests/ListVolumesTests.m new file mode 100644 index 0000000..c30e902 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Tests/ListVolumesTests.m @@ -0,0 +1,82 @@ +// +// ListVolumesTests.m +// UnrarKit +// +// Created by Dov Frankel on 12/9/16. +// +// + +#import "URKArchiveTestCase.h" + +@interface ListVolumesTests : URKArchiveTestCase + +@end + +@implementation ListVolumesTests + +- (void)testSingleVolume { + NSURL *testArchiveURL = self.testFileURLs[@"Test Archive.rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *listVolumesError = nil; + NSArray *volumeURLs = [archive listVolumeURLs:&listVolumesError]; + + XCTAssertNil(listVolumesError, @"Error listing volume URLs"); + XCTAssertNotNil(volumeURLs, @"No URLs returned"); + XCTAssertEqual(volumeURLs.count, 1, @"Wrong number of volume URLs listed"); + + XCTAssertEqualObjects(volumeURLs[0].lastPathComponent, testArchiveURL.path.lastPathComponent, + @"Wrong URL returned"); +} + +#if !TARGET_OS_IPHONE +- (void)testMultipleVolume_UseFirstVolume { + NSArray *generatedVolumeURLs = [self multiPartArchiveWithName:@"ListVolumesTests-testMultipleVolume_UseFirstVolume.rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:generatedVolumeURLs.firstObject error:nil]; + + NSMutableArray *expectedVolumeURLs = [NSMutableArray array]; + + // NSTemporaryDirectory() returns '/var', which maps to '/private/var' + for (NSURL *volumeURL in generatedVolumeURLs) { + NSString *originalPath = volumeURL.path; + NSString *privatePath = [@"/private" stringByAppendingString:originalPath]; + [expectedVolumeURLs addObject:[NSURL fileURLWithPath:privatePath]]; + } + + NSError *listVolumesError = nil; + NSArray *volumeURLs = [archive listVolumeURLs:&listVolumesError]; + + XCTAssertNil(listVolumesError, @"Error listing volume URLs"); + XCTAssertNotNil(volumeURLs, @"No URLs returned"); + XCTAssertEqual(volumeURLs.count, 5, @"Wrong number of volume URLs listed"); + XCTAssertTrue([expectedVolumeURLs isEqualToArray:volumeURLs], + @"Expected these URL:\n%@\n\nGot these:\n%@", expectedVolumeURLs, volumeURLs); +} +#endif + +#if !TARGET_OS_IPHONE +- (void)testMultipleVolume_UseMiddleVolume { + NSArray *generatedVolumeURLs = [self multiPartArchiveWithName:@"ListVolumesTests-testMultipleVolume_UseMiddleVolume.rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:generatedVolumeURLs[2] error:nil]; + + NSMutableArray *expectedVolumeURLs = [NSMutableArray array]; + + // NSTemporaryDirectory() returns '/var', which maps to '/private/var' + for (NSURL *volumeURL in generatedVolumeURLs) { + NSString *originalPath = volumeURL.path; + NSString *privatePath = [@"/private" stringByAppendingString:originalPath]; + [expectedVolumeURLs addObject:[NSURL fileURLWithPath:privatePath]]; + } + + NSError *listVolumesError = nil; + NSArray *volumeURLs = [archive listVolumeURLs:&listVolumesError]; + + XCTAssertNil(listVolumesError, @"Error listing volume URLs"); + XCTAssertNotNil(volumeURLs, @"No URLs returned"); + XCTAssertEqual(volumeURLs.count, 5, @"Wrong number of volume URLs listed"); + XCTAssertTrue([expectedVolumeURLs isEqualToArray:volumeURLs], + @"Expected these URL:\n%@\n\nGot these:\n%@", expectedVolumeURLs, volumeURLs); +} +#endif + +@end diff --git a/Carthage/Checkouts/UnrarKit/Tests/ProgressReportingTests.m b/Carthage/Checkouts/UnrarKit/Tests/ProgressReportingTests.m new file mode 100644 index 0000000..9bb8072 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Tests/ProgressReportingTests.m @@ -0,0 +1,597 @@ +// +// ProgressReportingTests.m +// UnrarKit +// +// Created by Dov Frankel on 9/19/17. +// +// + +#import +#import "URKArchiveTestCase.h" + + +@interface ProgressReportingTests : URKArchiveTestCase + +@property (retain) NSMutableArray *fractionsCompletedReported; +@property (retain) NSMutableArray *descriptionsReported; +@property (retain) NSMutableArray *additionalDescriptionsReported; +@property (retain) NSMutableArray *fileInfosReported; + +@end + +static void *ExtractFilesContext = &ExtractFilesContext; +static void *OtherContext = &OtherContext; +static void *CancelContext = &CancelContext; + +static NSUInteger observerCallCount; + +@implementation ProgressReportingTests + + +- (void)setUp { + [super setUp]; + + self.fractionsCompletedReported = [NSMutableArray array]; + self.descriptionsReported = [NSMutableArray array]; + self.additionalDescriptionsReported = [NSMutableArray array]; + self.fileInfosReported = [NSMutableArray array]; + + observerCallCount = 0; +} + +- (void)testProgressReporting_ExtractFiles_FractionCompleted +{ + NSString *testArchiveName = @"Test Archive.rar"; + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *extractDirectory = [self randomDirectoryWithPrefix: + [testArchiveName stringByDeletingPathExtension]]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSProgress *extractFilesProgress = [NSProgress progressWithTotalUnitCount:1]; + [extractFilesProgress becomeCurrentWithPendingUnitCount:1]; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [extractFilesProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:ExtractFilesContext]; + + NSError *extractError = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&extractError]; + + XCTAssertNil(extractError, @"Error returned by extractFilesTo:overwrite:error:"); + XCTAssertTrue(success, @"Unrar failed to extract %@ to %@", testArchiveName, extractURL); + + [extractFilesProgress resignCurrent]; + [extractFilesProgress removeObserver:self forKeyPath:observedSelector]; + + XCTAssertEqual(extractFilesProgress.fractionCompleted, 1.00, @"Progress never reported as completed"); + + NSUInteger expectedProgressUpdates = 4; + NSArray *expectedProgresses = @[@0, + @0.000315, + @0.533568, + @1.0]; + + XCTAssertEqual(self.fractionsCompletedReported.count, expectedProgressUpdates, @"Incorrect number of progress updates"); + for (NSInteger i = 0; i < expectedProgressUpdates; i++) { + float expectedProgress = expectedProgresses[i].floatValue; + float actualProgress = self.fractionsCompletedReported[i].floatValue; + + XCTAssertEqualWithAccuracy(actualProgress, expectedProgress, 0.00001f, @"Incorrect progress reported at index %ld", (long)i); + } +} + +- (void)testProgressReporting_ExtractFiles_Description +{ + NSString *testArchiveName = @"Test Archive.rar"; + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *extractDirectory = [self randomDirectoryWithPrefix: + [testArchiveName stringByDeletingPathExtension]]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSProgress *extractFilesProgress = [NSProgress progressWithTotalUnitCount:1]; + archive.progress = extractFilesProgress; + + NSString *observedSelector = NSStringFromSelector(@selector(localizedDescription)); + + [self.descriptionsReported removeAllObjects]; + [extractFilesProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:ExtractFilesContext]; + + NSError *extractError = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&extractError]; + + XCTAssertNil(extractError, @"Error returned by extractFilesTo:overwrite:error:"); + XCTAssertTrue(success, @"Unrar failed to extract %@ to %@", testArchiveName, extractURL); + + [extractFilesProgress removeObserver:self forKeyPath:observedSelector]; + + NSArray*expectedDescriptions = @[@"Processing “Test File A.txt”…", + @"Processing “Test File B.jpg”…", + @"Processing “Test File C.m4a”…"]; + + for (NSString *expectedDescription in expectedDescriptions) { + BOOL descriptionFound = [self.descriptionsReported containsObject:expectedDescription]; + XCTAssertTrue(descriptionFound, @"Expected progress updates to contain '%@', but they didn't", expectedDescription); + } +} + +- (void)testProgressReporting_ExtractFiles_AdditionalDescription +{ + NSString *testArchiveName = @"Test Archive.rar"; + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *extractDirectory = [self randomDirectoryWithPrefix: + [testArchiveName stringByDeletingPathExtension]]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSProgress *extractFilesProgress = [NSProgress progressWithTotalUnitCount:1]; + archive.progress = extractFilesProgress; + + NSString *observedSelector = NSStringFromSelector(@selector(localizedAdditionalDescription)); + + [extractFilesProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:ExtractFilesContext]; + + NSError *extractError = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&extractError]; + + XCTAssertNil(extractError, @"Error returned by extractFilesTo:overwrite:error:"); + XCTAssertTrue(success, @"Unrar failed to extract %@ to %@", testArchiveName, extractURL); + + [extractFilesProgress removeObserver:self forKeyPath:observedSelector]; + + NSArray*expectedAdditionalDescriptions = @[@"Zero KB of 105 KB", + @"33 bytes of 105 KB", + @"56 KB of 105 KB", + @"105 KB of 105 KB"]; + + for (NSString *expectedDescription in expectedAdditionalDescriptions) { + BOOL descriptionFound = [self.additionalDescriptionsReported containsObject:expectedDescription]; + XCTAssertTrue(descriptionFound, @"Expected progress updates to contain '%@', but they didn't", expectedDescription); + } +} + +- (void)testProgressReporting_ExtractFiles_FileInfo +{ + NSString *testArchiveName = @"Test Archive.rar"; + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *extractDirectory = [self randomDirectoryWithPrefix: + [testArchiveName stringByDeletingPathExtension]]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSProgress *extractFilesProgress = [NSProgress progressWithTotalUnitCount:1]; + archive.progress = extractFilesProgress; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [extractFilesProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:ExtractFilesContext]; + + NSError *extractError = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&extractError]; + + XCTAssertNil(extractError, @"Error returned by extractFilesTo:overwrite:error:"); + XCTAssertTrue(success, @"Unrar failed to extract %@ to %@", testArchiveName, extractURL); + + [extractFilesProgress removeObserver:self forKeyPath:observedSelector]; + + NSUInteger expectedFileInfos = 3; + NSArray *expectedFileNames = @[@"Test File A.txt", + @"Test File B.jpg", + @"Test File C.m4a"]; + + NSArray *actualFilenames = [self.fileInfosReported valueForKeyPath:NSStringFromSelector(@selector(filename))]; + + XCTAssertEqual(self.fileInfosReported.count, expectedFileInfos, @"Incorrect number of progress updates"); + XCTAssertTrue([expectedFileNames isEqualToArray:actualFilenames], @"Incorrect filenames returned: %@", actualFilenames); +} + +- (void)testProgressReporting_PerformOnFiles { + NSString *testArchiveName = @"Test Archive.rar"; + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSProgress *performProgress = [NSProgress progressWithTotalUnitCount:1]; + [performProgress becomeCurrentWithPendingUnitCount:1]; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [performProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:OtherContext]; + + NSError *performError = nil; + BOOL success = [archive performOnFilesInArchive: + ^(URKFileInfo * _Nonnull fileInfo, BOOL * _Nonnull stop) {} error:&performError]; + + XCTAssertNil(performError, @"Error returned by performOnFilesInArchive:error:"); + XCTAssertTrue(success, @"Unrar failed to perform operation on files of archive"); + + [performProgress resignCurrent]; + [performProgress removeObserver:self forKeyPath:observedSelector]; + + XCTAssertEqual(performProgress.fractionCompleted, 1.00, @"Progress never reported as completed"); + + NSUInteger expectedProgressUpdates = 4; + NSArray *expectedProgresses = @[@0, + @0.333333, + @0.666666, + @1.0]; + + XCTAssertEqual(self.fractionsCompletedReported.count, expectedProgressUpdates, @"Incorrect number of progress updates"); + for (NSInteger i = 0; i < expectedProgressUpdates; i++) { + float expectedProgress = expectedProgresses[i].floatValue; + float actualProgress = self.fractionsCompletedReported[i].floatValue; + + XCTAssertEqualWithAccuracy(actualProgress, expectedProgress, 0.000001f, @"Incorrect progress reported at index %ld", (long)i); + } +} + +- (void)testProgressReporting_PerformOnData { + NSString *testArchiveName = @"Test Archive.rar"; + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSProgress *performProgress = [NSProgress progressWithTotalUnitCount:1]; + [performProgress becomeCurrentWithPendingUnitCount:1]; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [performProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:OtherContext]; + + NSError *performError = nil; + BOOL success = [archive performOnDataInArchive: + ^(URKFileInfo * _Nonnull fileInfo, NSData * _Nonnull fileData, BOOL * _Nonnull stop) {} + error:&performError]; + + XCTAssertNil(performError, @"Error returned by performOnDataInArchive:error:"); + XCTAssertTrue(success, @"Unrar failed to perform operation on data of archive"); + + [performProgress resignCurrent]; + [performProgress removeObserver:self forKeyPath:observedSelector]; + + XCTAssertEqual(performProgress.fractionCompleted, 1.00, @"Progress never reported as completed"); + + NSUInteger expectedProgressUpdates = 4; + NSArray *expectedProgresses = @[@0, + @0.000315, + @0.533568, + @1.0]; + + XCTAssertEqual(self.fractionsCompletedReported.count, expectedProgressUpdates, @"Incorrect number of progress updates"); + for (NSInteger i = 0; i < expectedProgressUpdates; i++) { + float expectedProgress = expectedProgresses[i].floatValue; + float actualProgress = self.fractionsCompletedReported[i].floatValue; + + XCTAssertEqualWithAccuracy(actualProgress, expectedProgress, 0.000001f, @"Incorrect progress reported at index %ld", (long)i); + } +} + +- (void)testProgressCancellation_ExtractFiles { + NSString *testArchiveName = @"Test Archive.rar"; + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *extractDirectory = [self randomDirectoryWithPrefix: + [testArchiveName stringByDeletingPathExtension]]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSProgress *extractFilesProgress = [NSProgress progressWithTotalUnitCount:1]; + [extractFilesProgress becomeCurrentWithPendingUnitCount:1]; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [extractFilesProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:CancelContext]; + + NSError *extractError = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&extractError]; + + XCTAssertNotNil(extractError, @"Error not returned by extractFilesTo:overwrite:error:"); + XCTAssertEqual(extractError.code, URKErrorCodeUserCancelled, @"Incorrect error code returned from user cancellation"); + XCTAssertFalse(success, @"Unrar didn't cancel extraction"); + + [extractFilesProgress resignCurrent]; + [extractFilesProgress removeObserver:self forKeyPath:observedSelector]; + + + NSUInteger expectedProgressUpdates = 2; + XCTAssertEqual(self.fractionsCompletedReported.count, expectedProgressUpdates, @"Incorrect number of progress updates"); + + NSError *listContentsError = nil; + NSFileManager *fm = [NSFileManager defaultManager]; + NSArray *extractedFiles = [fm contentsOfDirectoryAtPath:extractURL.path + error:&listContentsError]; + + XCTAssertNil(listContentsError, @"Error listing contents of extraction directory"); + XCTAssertEqual(extractedFiles.count, 1, @"Cancellation didn't occur in as timely a fashion as expected"); +} + + + +#pragma mark - Mac-only tests + + +#if !TARGET_OS_IPHONE +- (void)testProgressReporting_ExtractData { + NSURL *largeArchiveURL = [self largeArchiveURL]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:largeArchiveURL error:nil]; + NSString *firstFile = [[archive listFilenames:nil] firstObject]; + + NSProgress *extractFileProgress = [NSProgress progressWithTotalUnitCount:1]; + [extractFileProgress becomeCurrentWithPendingUnitCount:1]; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [extractFileProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:OtherContext]; + + NSError *extractError = nil; + NSData *data = [archive extractDataFromFile:firstFile error:&extractError]; + + XCTAssertNil(extractError, @"Error returned by extractDataFromFile:error:"); + XCTAssertNotNil(data, @"Unrar failed to extract large archive"); + + [extractFileProgress resignCurrent]; + [extractFileProgress removeObserver:self forKeyPath:observedSelector]; + + XCTAssertEqual(extractFileProgress.fractionCompleted, 1.00, @"Progress never reported as completed"); + + NSUInteger expectedProgressUpdates = 4; + NSArray *expectedProgresses = @[@0, + @0.6990074, + @0.6990504, + @1.0]; + + XCTAssertEqual(self.fractionsCompletedReported.count, expectedProgressUpdates, @"Incorrect number of progress updates"); + for (NSInteger i = 0; i < expectedProgressUpdates; i++) { + float expectedProgress = expectedProgresses[i].floatValue; + float actualProgress = self.fractionsCompletedReported[i].floatValue; + + XCTAssertEqualWithAccuracy(actualProgress, expectedProgress, 0.000001f, @"Incorrect progress reported at index %ld", (long)i); + } +} + +- (void)testProgressReporting_ExtractBufferedData { + NSURL *largeArchiveURL = [self largeArchiveURL]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:largeArchiveURL error:nil]; + NSString *firstFile = [[archive listFilenames:nil] firstObject]; + + NSProgress *extractFileProgress = [NSProgress progressWithTotalUnitCount:1]; + [extractFileProgress becomeCurrentWithPendingUnitCount:1]; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [extractFileProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:OtherContext]; + + NSError *extractError = nil; + BOOL success = [archive extractBufferedDataFromFile:firstFile + error:&extractError + action:^(NSData * _Nonnull dataChunk, CGFloat percentDecompressed) {}]; + + XCTAssertNil(extractError, @"Error returned by extractDataFromFile:error:"); + XCTAssertTrue(success, @"Unrar failed to extract large archive into buffer"); + + [extractFileProgress resignCurrent]; + [extractFileProgress removeObserver:self forKeyPath:observedSelector]; + + XCTAssertEqual(extractFileProgress.fractionCompleted, 1.00, @"Progress never reported as completed"); + + NSUInteger expectedProgressUpdates = 4; + NSArray *expectedProgresses = @[@0, + @0.6990074, + @0.6990504, + @1.0]; + + XCTAssertEqual(self.fractionsCompletedReported.count, expectedProgressUpdates, @"Incorrect number of progress updates"); + for (NSInteger i = 0; i < expectedProgressUpdates; i++) { + float expectedProgress = expectedProgresses[i].floatValue; + float actualProgress = self.fractionsCompletedReported[i].floatValue; + + XCTAssertEqualWithAccuracy(actualProgress, expectedProgress, 0.000001f, @"Incorrect progress reported at index %ld", (long)i); + } +} + +- (void)testProgressCancellation_ExtractData { + NSURL *largeArchiveURL = [self largeArchiveURL]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:largeArchiveURL error:nil]; + NSString *firstFile = [[archive listFilenames:nil] firstObject]; + + NSProgress *extractFileProgress = [NSProgress progressWithTotalUnitCount:1]; + [extractFileProgress becomeCurrentWithPendingUnitCount:1]; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [extractFileProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:CancelContext]; + + NSError *extractError = nil; + NSData *data = [archive extractDataFromFile:firstFile error:&extractError]; + + XCTAssertNotNil(extractError, @"No error returned by cancelled extractDataFromFile:error:"); + XCTAssertEqual(extractError.code, URKErrorCodeUserCancelled, @"Incorrect error code returned from user cancellation"); + XCTAssertNil(data, @"extractData didn't return nil when cancelled"); + + [extractFileProgress resignCurrent]; + [extractFileProgress removeObserver:self forKeyPath:observedSelector]; + + NSUInteger expectedProgressUpdates = 2; + XCTAssertEqual(self.fractionsCompletedReported.count, expectedProgressUpdates, @"Incorrect number of progress updates"); +} + +- (void)testProgressCancellation_ExtractBufferedData { + NSURL *largeArchiveURL = [self largeArchiveURL]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:largeArchiveURL error:nil]; + NSString *firstFile = [[archive listFilenames:nil] firstObject]; + + NSProgress *extractFileProgress = [NSProgress progressWithTotalUnitCount:1]; + [extractFileProgress becomeCurrentWithPendingUnitCount:1]; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [extractFileProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:CancelContext]; + + __block NSUInteger blockCallCount = 0; + + NSError *extractError = nil; + BOOL success = [archive extractBufferedDataFromFile:firstFile + error:&extractError + action:^(NSData * _Nonnull dataChunk, CGFloat percentDecompressed) { + blockCallCount++; + }]; + + XCTAssertNotNil(extractError, @"No error returned by cancelled extractDataFromFile:error:"); + XCTAssertEqual(extractError.code, URKErrorCodeUserCancelled, @"Incorrect error code returned from user cancellation"); + XCTAssertFalse(success, @"extractBufferedData didn't return false when cancelled"); + + [extractFileProgress resignCurrent]; + [extractFileProgress removeObserver:self forKeyPath:observedSelector]; + + NSUInteger expectedProgressUpdates = 2; + XCTAssertEqual(self.fractionsCompletedReported.count, expectedProgressUpdates, @"Incorrect number of progress updates"); + XCTAssertEqual(blockCallCount, 1, @"Action block called incorrect number of times after cancellation"); +} + +- (void)testProgressCancellation_ExtractFiles_MiddleOfFile { + NSURL *largeTextFile = [self randomTextFileOfLength:50000000]; // Increase for a more dramatic test + XCTAssertNotNil(largeTextFile, @"No large text file URL returned"); + NSURL *testArchiveURL = [self archiveWithFiles:@[largeTextFile]]; + + NSString *extractDirectory = [self randomDirectoryWithPrefix:@"CancelExtractInMiddle"]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSProgress *extractFilesProgress = [NSProgress progressWithTotalUnitCount:1]; + [extractFilesProgress becomeCurrentWithPendingUnitCount:1]; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [extractFilesProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:ExtractFilesContext]; + + // Half a second later, cancel progress + dispatch_queue_t cancellationQueue = dispatch_queue_create("Extract Files Cancellation", 0); + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), cancellationQueue, ^{ + URKLogInfo("Cancelling extraction in progress"); + [extractFilesProgress cancel]; + }); + + NSDate *extractStart = [NSDate date]; + + NSError *extractError = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&extractError]; + + NSDate *extractFinish = [NSDate date]; + + NSTimeInterval executionTime = [extractFinish timeIntervalSinceDate:extractStart]; + XCTAssertLessThan(executionTime, 1.0, @"Asynchronous file extraction cancel didn't stop in the middle of a file"); + + XCTAssertNotNil(extractError, @"Error not returned by extractFilesTo:overwrite:error:"); + XCTAssertEqual(extractError.code, URKErrorCodeUserCancelled, @"Incorrect error code returned from user cancellation"); + XCTAssertFalse(success, @"Unrar didn't cancel extraction"); + + [extractFilesProgress resignCurrent]; + [extractFilesProgress removeObserver:self forKeyPath:observedSelector]; + + + NSUInteger expectedProgressUpdates = 1; + XCTAssertEqual(self.fractionsCompletedReported.count, expectedProgressUpdates, @"Incorrect number of progress updates"); + + NSError *listContentsError = nil; + NSFileManager *fm = [NSFileManager defaultManager]; + NSArray *extractedFiles = [fm contentsOfDirectoryAtPath:extractURL.path + error:&listContentsError]; + + XCTAssertNil(listContentsError, @"Error listing contents of extraction directory"); + XCTAssertEqual(extractedFiles.count, 0, @"Partial file produced in spite of cancellation"); +} +#endif + + +#pragma mark - Private methods + + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context +{ + observerCallCount++; + + NSProgress *progress; + + if ([object isKindOfClass:[NSProgress class]]) { + progress = object; + [self.fractionsCompletedReported addObject:@(progress.fractionCompleted)]; + } else { + return; + } + + if (context == ExtractFilesContext) { + [self.descriptionsReported addObject:progress.localizedDescription]; + [self.additionalDescriptionsReported addObject:progress.localizedAdditionalDescription]; + + URKFileInfo *fileInfo = progress.userInfo[URKProgressInfoKeyFileInfoExtracting]; + if (fileInfo) [self.fileInfosReported addObject:fileInfo]; + } + + if (context == CancelContext && observerCallCount == 2) { + NSLog(@"Cancelling progress in -[ProgressReportingTests observeValueForKeyPath:ofObject:change:context:]"); + [progress cancel]; + } +} + +@end diff --git a/Carthage/Checkouts/UnrarKit/Tests/Test Data/Folder Archive.rar b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Folder Archive.rar new file mode 100644 index 0000000..0e62e60 Binary files /dev/null and b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Folder Archive.rar differ diff --git a/Carthage/Checkouts/UnrarKit/Tests/Test Data/Good CRC Archive.rar b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Good CRC Archive.rar new file mode 100644 index 0000000..1c4a52e Binary files /dev/null and b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Good CRC Archive.rar differ diff --git a/Carthage/Checkouts/UnrarKit/Tests/Test Data/Modified CRC Archive.rar b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Modified CRC Archive.rar new file mode 100644 index 0000000..472fa44 Binary files /dev/null and b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Modified CRC Archive.rar differ diff --git a/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test Archive (Header Password).rar b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test Archive (Header Password).rar new file mode 100644 index 0000000..b02a0ae Binary files /dev/null and b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test Archive (Header Password).rar differ diff --git a/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test Archive (Password).rar b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test Archive (Password).rar new file mode 100644 index 0000000..5a5f7cb Binary files /dev/null and b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test Archive (Password).rar differ diff --git a/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test Archive (RAR5).rar b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test Archive (RAR5).rar new file mode 100644 index 0000000..101ccc2 Binary files /dev/null and b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test Archive (RAR5).rar differ diff --git a/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test Archive (RAR5, Password).rar b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test Archive (RAR5, Password).rar new file mode 100644 index 0000000..a5d29a1 Binary files /dev/null and b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test Archive (RAR5, Password).rar differ diff --git a/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test Archive.rar b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test Archive.rar new file mode 100644 index 0000000..c910e1e Binary files /dev/null and b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test Archive.rar differ diff --git a/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test File A.txt b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test File A.txt new file mode 100644 index 0000000..2a3321e --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test File A.txt @@ -0,0 +1 @@ +Test File A (secret message here) \ No newline at end of file diff --git a/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test File B.jpg b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test File B.jpg new file mode 100644 index 0000000..42caa84 Binary files /dev/null and b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test File B.jpg differ diff --git a/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test File C.m4a b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test File C.m4a new file mode 100644 index 0000000..090b5be Binary files /dev/null and b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test File C.m4a differ diff --git a/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test File Ⓐ.txt b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test File Ⓐ.txt new file mode 100644 index 0000000..2a3321e --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test File Ⓐ.txt @@ -0,0 +1 @@ +Test File A (secret message here) \ No newline at end of file diff --git a/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test File Ⓑ.jpg b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test File Ⓑ.jpg new file mode 100644 index 0000000..42caa84 Binary files /dev/null and b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test File Ⓑ.jpg differ diff --git a/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test File Ⓒ.m4a b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test File Ⓒ.m4a new file mode 100644 index 0000000..090b5be Binary files /dev/null and b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Test File Ⓒ.m4a differ diff --git a/Carthage/Checkouts/UnrarKit/Tests/Test Data/bin/rar b/Carthage/Checkouts/UnrarKit/Tests/Test Data/bin/rar new file mode 100755 index 0000000..0cc0542 Binary files /dev/null and b/Carthage/Checkouts/UnrarKit/Tests/Test Data/bin/rar differ diff --git a/Carthage/Checkouts/UnrarKit/Tests/Test Data/bin/rar-license.txt b/Carthage/Checkouts/UnrarKit/Tests/Test Data/bin/rar-license.txt new file mode 100644 index 0000000..82af4af --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Tests/Test Data/bin/rar-license.txt @@ -0,0 +1,127 @@ + END USER LICENSE AGREEMENT + + The following agreement regarding RAR (and its Windows version - WinRAR) + archiver - referred to as "software" - is made between win.rar GmbH - + referred to as "licensor" - and anyone who is installing, accessing + or in any other way using the software - referred to as "user". + + 1. The author and holder of the copyright of the software is + Alexander L. Roshal. The licensor and as such issuer of the license + and bearer of the worldwide exclusive usage rights including the rights + to reproduce, distribute and make the software available to the public + in any form is win.rar GmbH, Marienstr. 12, 10117 Berlin, Germany. + + 2. The software is distributed as try before you buy. This means that + anyone may use the software during a test period of a maximum of 40 days + at no charge. Following this test period, the user must purchase + a license to continue using the software. + + 3. The software's trial version may be freely distributed, with exceptions + noted below, provided the distribution package is not modified in any way. + + a. Nobody may distribute separate parts of the package, with the exception + of the UnRAR components, without written permission. + + b. The software's unlicensed trial version may not be distributed + inside of any other software package without written permission. + The software must remain in the original unmodified installation + file for download without any barrier and conditions to the user + such as collecting fees for the download or making the download + conditional on the user giving his contact data. + + c. The unmodified installation file of WinRAR must be provided pure + and unpaired. Any bundling is interdicted. In particular the use + of any install or download software which is providing any kind + of download bundles is prohibited unless granted by win.rar GmbH + in written form. + + d. Hacks/cracks, keys or key generators may not be included, pointed to + or referred to by the distributor of the trial version. + + e. In case of violation of the precedent conditions the allowance + lapses immediately and automatically. + + 4. The trial version of the software can display a registration reminder + dialog. Depending on the software version and configuration such dialog + can contain either a predefined text and links loaded locally + or a web page loaded from the internet. Such web page can contain + licensing instructions or other materials according to the licensor's + choice, including advertisement. When opening a web page, the software + transfers only those parameters which are technically required + by HTTP protocol to successfully open a web page in a browser. + + 5. The software is distributed "as is". No warranty of any kind is expressed + or implied. You use at your own risk. Neither the author, the licensor + nor the agents of the licensor will be liable for data loss, damages, + loss of profits or any other kind of loss while using or misusing + this software. + + 6. There are 2 basic types of licenses issued for the software. These are: + + a. A single computer usage license. The user purchases one license to + use the software on one computer. + + Home users may use their single computer usage license on all + computers and mobile devices (USB drive, external hard drive, etc.) + which are property of the license owner. + + Business users require one license per computer or mobile device + on which the software is installed. + + b. A multiple usage license. The user purchases a number of usage + licenses for use, by the purchaser or the purchaser's employees + on the same number of computers. + + In a network (server/client) environment the user must purchase + a license copy for each separate client (workstation) on which + the software is installed, used or accessed. A separate license copy + for each client (workstation) is needed regardless of whether + the clients (workstations) will use the software simultaneously + or at different times. If for example you wish to have 9 different + clients (workstations) in your network with access to RAR, + you must purchase 9 license copies. + + A user who purchased a license, is granted a non-exclusive right to use + the software on as many computers as defined by the licensing terms above + according to the number of licenses purchased, for any legal purpose. + + 7. There are no additional license fees, apart from the cost of the license, + associated with the creation and distribution of RAR archives, + volumes, self-extracting archives or self-extracting volumes. + Owners of a license may use their copies of the software to produce + archives and self-extracting archives and to distribute those archives + free of any additional royalties. + + 8. The licensed software may not be rented or leased but may be permanently + transferred, in its entirety, if the recipient agrees to the terms of + this license. + + 9. To buy a license, please read the file order.htm provided with + the software for details. + + 10. You may not use, copy, emulate, clone, rent, lease, sell, modify, + decompile, disassemble, otherwise reverse engineer, or transfer + the licensed software, or any subset of the licensed software, + except as provided for in this agreement. Any such unauthorized use + shall result in immediate and automatic termination of this license + and may result in criminal and/or civil prosecution. + + Neither RAR binary code, WinRAR binary code, UnRAR source + or UnRAR binary code may be used or reverse engineered to re-create + the RAR compression algorithm, which is proprietary, without written + permission. + + The software may be using components developed and/or copyrighted + by third parties. Please read "Acknowledgments" help file topic + for WinRAR or acknow.txt text file for other RAR versions for details. + + 11. This License Agreement is construed solely and exclusively under + German law. If you are a merchant, the courts at the registered office + of win.rar GmbH in Berlin/Germany shall have exclusive jurisdiction + for any and all disputes arising in connection with this License + Agreement or its validity. + + 12. Installing and using the software signifies acceptance of these terms + and conditions of the license. If you do not agree with the terms of this + license, you must remove all software files from your storage devices + and cease to use the software. diff --git a/Carthage/Checkouts/UnrarKit/Tests/Test Data/Ⓣest Ⓐrchive.rar b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Ⓣest Ⓐrchive.rar new file mode 100644 index 0000000..c325151 Binary files /dev/null and b/Carthage/Checkouts/UnrarKit/Tests/Test Data/Ⓣest Ⓐrchive.rar differ diff --git a/Carthage/Checkouts/UnrarKit/Tests/URKArchiveTestCase.h b/Carthage/Checkouts/UnrarKit/Tests/URKArchiveTestCase.h new file mode 100644 index 0000000..8f7606f --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Tests/URKArchiveTestCase.h @@ -0,0 +1,67 @@ +// +// URKArchiveTestCase.h +// UnrarKit +// +// Created by Dov Frankel on 6/22/15. +// +// + +#import "TargetConditionals.h" + +#if TARGET_OS_IPHONE +#import +#else +#import +#endif + +@import XCTest; +@import UnrarKit; + + +@interface URKArchiveTestCase : XCTestCase + +@property BOOL testFailed; + +@property NSURL *tempDirectory; +@property NSMutableDictionary *testFileURLs; +@property NSMutableDictionary *unicodeFileURLs; +@property NSURL *corruptArchive; + + +- (NSURL *)urlOfTestFile:(NSString *)filename; +- (NSString *)randomDirectoryName; +- (NSString *)randomDirectoryWithPrefix:(NSString *)prefix; +- (NSURL *)randomTextFileOfLength:(NSUInteger)numberOfCharacters; +- (NSUInteger)crcOfTestFile:(NSString *)filename; + +// Mac Only + +#if !TARGET_OS_IPHONE +- (NSURL *)largeArchiveURL; +- (NSInteger)numberOfOpenFileHandles; +- (NSURL *)archiveWithFiles:(NSArray *)fileURLs; + +- (NSURL *)archiveWithFiles:(NSArray *)fileURLs arguments:(NSArray *)customArgs; +- (NSURL *)archiveWithFiles:(NSArray *)fileURLs arguments:(NSArray *)customArgs commandOutput:(NSString **)commandOutput; + +- (NSURL *)archiveWithFiles:(NSArray *)fileURLs name:(NSString *)archiveName; +- (NSURL *)archiveWithFiles:(NSArray *)fileURLs name:(NSString *)archiveName arguments:(NSArray *)customArgs; +- (NSURL *)archiveWithFiles:(NSArray *)fileURLs name:(NSString *)archiveName arguments:(NSArray *)customArgs commandOutput:(NSString **)commandOutput; + +- (NSArray *)multiPartArchiveWithName:(NSString *)baseName; +- (NSArray *)multiPartArchiveWithName:(NSString *)baseName fileSize:(NSUInteger)fileSize; +- (NSArray *)multiPartArchiveOldSchemeWithName:(NSString *)baseName; +#endif + +@end + +@interface NSString (URKArchiveTestCaseExtensions) + +/** + * Returns all of the regex matches in the given string + * + * @param expression The regex expression to match. Must contain exactly one capture group + */ +- (NSArray *)regexMatches:(NSString *)expression; + +@end diff --git a/Carthage/Checkouts/UnrarKit/Tests/URKArchiveTestCase.m b/Carthage/Checkouts/UnrarKit/Tests/URKArchiveTestCase.m new file mode 100644 index 0000000..c3d9a0e --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Tests/URKArchiveTestCase.m @@ -0,0 +1,405 @@ +// +// URKArchiveTestCase.m +// UnrarKit +// +// Created by Dov Frankel on 6/22/15. +// +// + +#import "URKArchiveTestCase.h" + +#import + + + +static NSURL *originalLargeArchiveURL; + + +@implementation URKArchiveTestCase + + +#pragma mark - Test Management + + +- (void)setUp +{ + [super setUp]; + + NSFileManager *fm = [NSFileManager defaultManager]; + NSString *uniqueName = [self randomDirectoryName]; + NSError *error = nil; + + NSArray *testFiles = @[@"Test Archive.rar", + @"Test Archive (Password).rar", + @"Test Archive (Header Password).rar", + @"Test Archive (RAR5, Password).rar", + @"Test Archive (RAR5).rar", + @"Folder Archive.rar", + @"Modified CRC Archive.rar", + @"Test File A.txt", + @"Test File B.jpg", + @"Test File C.m4a", + @"bin/rar"]; + + NSArray *unicodeFiles = @[@"Ⓣest Ⓐrchive.rar", + @"Test File Ⓐ.txt", + @"Test File Ⓑ.jpg", + @"Test File Ⓒ.m4a"]; + + NSString *tempDirSubtree = [@"UnrarKitTest" stringByAppendingPathComponent:uniqueName]; + + self.testFailed = NO; + self.testFileURLs = [[NSMutableDictionary alloc] init]; + self.unicodeFileURLs = [[NSMutableDictionary alloc] init]; + self.tempDirectory = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:tempDirSubtree] + isDirectory:YES]; + + NSLog(@"Temp directory: %@", self.tempDirectory); + + [fm createDirectoryAtURL:self.tempDirectory + withIntermediateDirectories:YES + attributes:nil + error:&error]; + + XCTAssertNil(error, @"Failed to create temp directory: %@", self.tempDirectory); + + NSMutableArray *filesToCopy = [NSMutableArray arrayWithArray:testFiles]; + [filesToCopy addObjectsFromArray:unicodeFiles]; + + for (NSString *file in filesToCopy) { + NSURL *testFileURL = [self urlOfTestFile:file]; + BOOL testFileExists = [fm fileExistsAtPath:testFileURL.path]; + XCTAssertTrue(testFileExists, @"%@ not found", file); + + NSURL *destinationURL = [self.tempDirectory URLByAppendingPathComponent:file isDirectory:NO]; + + NSError *error = nil; + if (file.pathComponents.count > 1) { + [fm createDirectoryAtPath:destinationURL.URLByDeletingLastPathComponent.path + withIntermediateDirectories:YES + attributes:nil + error:&error]; + XCTAssertNil(error, @"Failed to create directories for file %@", file); + } + + [fm copyItemAtURL:testFileURL + toURL:destinationURL + error:&error]; + + XCTAssertNil(error, @"Failed to copy temp file %@ from %@ to %@", + file, testFileURL, destinationURL); + + if ([testFiles containsObject:file]) { + [self.testFileURLs setObject:destinationURL forKey:file]; + } + else if ([unicodeFiles containsObject:file]) { + [self.unicodeFileURLs setObject:destinationURL forKey:file]; + } + } + + + // Make a "corrupt" rar file + NSURL *m4aFileURL = [self urlOfTestFile:@"Test File C.m4a"]; + self.corruptArchive = [self.tempDirectory URLByAppendingPathComponent:@"corrupt.rar"]; + [fm copyItemAtURL:m4aFileURL + toURL:self.corruptArchive + error:&error]; + + XCTAssertNil(error, @"Failed to create corrupt archive (copy from %@ to %@)", m4aFileURL, self.corruptArchive); +} + +- (void)tearDown +{ + NSString *largeArchiveDirectory = originalLargeArchiveURL.path.stringByDeletingLastPathComponent; + BOOL tempDirContainsLargeArchive = [largeArchiveDirectory isEqualToString:self.tempDirectory.path]; + if (!self.testFailed && !tempDirContainsLargeArchive) { + __block NSError *error = nil; + + dispatch_semaphore_t sem = dispatch_semaphore_create(1); + + dispatch_async(dispatch_get_main_queue(), ^{ + [[NSFileManager defaultManager] removeItemAtURL:self.tempDirectory error:&error]; + dispatch_semaphore_signal(sem); + }); + + dispatch_semaphore_wait(sem, dispatch_time(DISPATCH_TIME_NOW, 5000)); + XCTAssertNil(error, @"Error deleting temp directory"); + } + + [super tearDown]; +} + +- (void) recordFailureWithDescription:(NSString *) description inFile:(NSString *) filename atLine:(NSUInteger) lineNumber expected:(BOOL) expected; +{ + self.testFailed = YES; + [super recordFailureWithDescription:description inFile:filename atLine:lineNumber expected:expected]; +} + + + +#pragma mark - Helper Methods + + +- (NSURL *)urlOfTestFile:(NSString *)filename +{ + NSString *baseDirectory = @"Test Data"; + NSString *subPath = filename.stringByDeletingLastPathComponent; + NSString *bundleSubdir = [baseDirectory stringByAppendingPathComponent:subPath]; + + return [[NSBundle bundleForClass:[self class]] URLForResource:filename.lastPathComponent + withExtension:nil + subdirectory:bundleSubdir]; +} + +- (NSString *)randomDirectoryName +{ + NSString *globallyUnique = [[NSProcessInfo processInfo] globallyUniqueString]; + NSRange firstHyphen = [globallyUnique rangeOfString:@"-"]; + return [globallyUnique substringToIndex:firstHyphen.location]; +} + +- (NSString *)randomDirectoryWithPrefix:(NSString *)prefix +{ + return [NSString stringWithFormat:@"%@ %@", prefix, [self randomDirectoryName]]; +} + +- (NSURL *)randomTextFileOfLength:(NSUInteger)numberOfCharacters { + NSString *letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 .,?!\n"; + NSUInteger letterCount = letters.length; + + NSMutableString *randomString = [NSMutableString stringWithCapacity:numberOfCharacters]; + + for (NSUInteger i = 0; i < numberOfCharacters; i++) { + uint32_t charIndex = arc4random_uniform((uint32_t)letterCount); + [randomString appendFormat:@"%C", [letters characterAtIndex:charIndex]]; + } + + NSURL *resultURL = [self.tempDirectory URLByAppendingPathComponent: + [NSString stringWithFormat:@"%@.txt", [[NSProcessInfo processInfo] globallyUniqueString]]]; + + NSError *error = nil; + [randomString writeToURL:resultURL atomically:YES encoding:NSUTF16StringEncoding error:&error]; + XCTAssertNil(error, @"Error opening file handle for text file creation: %@", error); + + return resultURL; +} + +- (NSUInteger)crcOfTestFile:(NSString *)filename { + NSURL *fileURL = [self urlOfTestFile:filename]; + NSData *fileContents = [[NSFileManager defaultManager] contentsAtPath:[fileURL path]]; + return crc32(0, fileContents.bytes, (uint)fileContents.length); +} + + + +#pragma mark - Mac Only + + +#if !TARGET_OS_IPHONE +- (NSURL *)largeArchiveURL { + NSFileManager *fm = [NSFileManager defaultManager]; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSMutableArray *largeTextFiles = [NSMutableArray array]; + for (NSInteger i = 0; i < 20; i++) { + [largeTextFiles addObject:[self randomTextFileOfLength:3000000]]; + } + + NSError *largeArchiveError = nil; + + NSURL *largeArchiveURLRandomName = [self archiveWithFiles:largeTextFiles]; + originalLargeArchiveURL = [largeArchiveURLRandomName.URLByDeletingLastPathComponent URLByAppendingPathComponent:@"Large Archive (Original).rar"]; + [fm moveItemAtURL:largeArchiveURLRandomName toURL:originalLargeArchiveURL error:&largeArchiveError]; + + XCTAssertNil(largeArchiveError, @"Error renaming original large archive: %@", largeArchiveError); + }); + + NSString *largeArchiveName = @"Large Archive.rar"; + NSURL *destinationURL = [self.tempDirectory URLByAppendingPathComponent:largeArchiveName isDirectory:NO]; + NSError *fileCopyError = nil; + [fm copyItemAtURL:originalLargeArchiveURL toURL:destinationURL error:&fileCopyError]; + XCTAssertNil(fileCopyError, @"Failed to copy the Large Archive"); + + return destinationURL; +} + +- (NSInteger)numberOfOpenFileHandles { + int pid = [[NSProcessInfo processInfo] processIdentifier]; + NSPipe *pipe = [NSPipe pipe]; + NSFileHandle *file = pipe.fileHandleForReading; + + NSTask *task = [[NSTask alloc] init]; + task.launchPath = @"/usr/sbin/lsof"; + task.arguments = @[@"-P", @"-n", @"-p", [NSString stringWithFormat:@"%d", pid]]; + task.standardOutput = pipe; + + [task launch]; + + NSData *data = [file readDataToEndOfFile]; + [file closeFile]; + + NSString *lsofOutput = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]; + + // NSLog(@"LSOF:\n%@", lsofOutput); + + return [lsofOutput componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]].count; +} + +- (NSURL *)archiveWithFiles:(NSArray *)fileURLs { + return [self archiveWithFiles:fileURLs arguments:nil]; +} + +- (NSURL *)archiveWithFiles:(NSArray *)fileURLs arguments:(NSArray *)customArgs { + return [self archiveWithFiles:fileURLs arguments:customArgs commandOutput:NULL]; +} + +- (NSURL *)archiveWithFiles:(NSArray *)fileURLs arguments:(NSArray *)customArgs commandOutput:(NSString **)commandOutput { + return [self archiveWithFiles:fileURLs name:nil arguments:customArgs commandOutput:commandOutput]; +} + +- (NSURL *)archiveWithFiles:(NSArray *)fileURLs name:(NSString *)archiveName { + return [self archiveWithFiles:fileURLs name:archiveName arguments:nil]; +} + +- (NSURL *)archiveWithFiles:(NSArray *)fileURLs name:(NSString *)archiveName arguments:(NSArray *)customArgs { + return [self archiveWithFiles:fileURLs name:archiveName arguments:customArgs commandOutput:NULL]; +} + +- (NSURL *)archiveWithFiles:(NSArray *)fileURLs name:(NSString *)archiveName arguments:(NSArray *)customArgs commandOutput:(NSString **)commandOutput { + NSString *archiveFileName = archiveName; + if (![archiveFileName length]) { + NSString *uniqueString = [[NSProcessInfo processInfo] globallyUniqueString]; + archiveFileName = [uniqueString stringByAppendingPathExtension:@"rar"]; + } + + NSURL *rarExec = [[self.tempDirectory URLByAppendingPathComponent:@"bin"] + URLByAppendingPathComponent:@"rar"]; + NSURL *archiveURL = [self.tempDirectory URLByAppendingPathComponent:archiveFileName]; + + NSMutableArray *rarArguments = [NSMutableArray arrayWithArray:@[@"a", @"-ep", archiveURL.path]]; + if (customArgs) { + [rarArguments addObjectsFromArray:customArgs]; + } + [rarArguments addObjectsFromArray:[fileURLs valueForKeyPath:@"path"]]; + + NSPipe *pipe = [NSPipe pipe]; + NSFileHandle *file = pipe.fileHandleForReading; + + NSTask *task = [[NSTask alloc] init]; + task.launchPath = rarExec.path; + task.arguments = rarArguments; + task.standardOutput = pipe; + + [task launch]; + [task waitUntilExit]; + + NSData *data = [file readDataToEndOfFile]; + [file closeFile]; + + if (commandOutput) { + *commandOutput = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + } + + if (task.terminationStatus != 0) { + NSLog(@"Failed to create RAR archive"); + return nil; + } + + return archiveURL; +} + +- (NSArray *)multiPartArchiveWithName:(NSString *)baseName +{ + return [self multiPartArchiveWithName:baseName fileSize:100000]; +} + +- (NSArray *)multiPartArchiveWithName:(NSString *)baseName fileSize:(NSUInteger)fileSize +{ + NSURL *textFile = [self randomTextFileOfLength:fileSize]; + + // Generate multi-volume archive, with parts no larger than 20 KB in size + NSString *commandOutputString = nil; + [self archiveWithFiles:@[textFile] + name:baseName + arguments:@[@"-v20k"] + commandOutput:&commandOutputString]; + + NSMutableArray *volumePaths = [NSMutableArray arrayWithArray: + [commandOutputString regexMatches:@"Creating archive (.+)"]]; + NSString *intendedFirstVolumePath = volumePaths.firstObject; + + // Fill in leading zeroes according to number of parts (no fewer than 2 digits) + int numDigits = MAX(2, floor(log10(volumePaths.count)) + 1); + NSString *zeroPadding = [@"" stringByPaddingToLength:numDigits - 1 withString:@"0" startingAtIndex:0]; + NSString *actualExtension = [NSString stringWithFormat:@"part%@1.rar", zeroPadding]; + + NSString *firstVolumeDir = [intendedFirstVolumePath stringByDeletingLastPathComponent]; + NSString *actualFirstVolumePath = [firstVolumeDir stringByAppendingPathComponent: + [baseName stringByReplacingOccurrencesOfString:@"rar" + withString:actualExtension]]; + [volumePaths replaceObjectAtIndex:0 withObject:actualFirstVolumePath]; + + NSMutableArray *result = [NSMutableArray array]; + for (NSString *path in volumePaths) { + [result addObject:[NSURL fileURLWithPath:path]]; + } + + return result; +} + +- (NSArray *)multiPartArchiveOldSchemeWithName:(NSString *)baseName +{ + NSURL *textFile = [self randomTextFileOfLength:100000]; + + // Generate multi-volume archive, with parts no larger than 20 KB in size + NSString *commandOutputString = nil; + [self archiveWithFiles:@[textFile] + name:baseName + arguments:@[@"-v20k", @"-vn"] + commandOutput:&commandOutputString]; + + NSArray *volumePaths = [commandOutputString regexMatches:@"Creating archive (.+)"]; + + NSMutableArray *result = [NSMutableArray array]; + for (NSString *path in volumePaths) { + [result addObject:[NSURL fileURLWithPath:path]]; + } + + return result; +} +#endif + + + +@end + + +@implementation NSString (URKArchiveTestCaseExtensions) + +- (NSArray *)regexMatches:(NSString *)expression +{ + NSError *regexCreationError = nil; + + NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:expression + options:0 + error:®exCreationError]; + + if (!regex) { + NSLog(@"Failed to create regex with pattern '%@': %@", expression, regexCreationError); + return @[]; + } + + NSMutableArray *results = [NSMutableArray array]; + + [regex enumerateMatchesInString:self + options:0 + range:NSMakeRange(0, self.length) + usingBlock:^(NSTextCheckingResult * _Nullable result, NSMatchingFlags flags, BOOL * _Nonnull stop) { + [results addObject:[self substringWithRange:[result rangeAtIndex:1]]]; + }]; + + return results; +} + +@end diff --git a/Carthage/Checkouts/UnrarKit/Tests/URKArchiveTests.m b/Carthage/Checkouts/UnrarKit/Tests/URKArchiveTests.m new file mode 100644 index 0000000..db4894d --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Tests/URKArchiveTests.m @@ -0,0 +1,1201 @@ +// +// URKArchiveTests.m +// UnrarKit Tests +// +// + +#import "URKArchiveTestCase.h" + + +#import +enum SignPostCode: uint { // Use to reference in Instruments (http://stackoverflow.com/a/39416673/105717) + SignPostCodeCreateTextFile = 0, + SignPostCodeArchiveData = 1, + SignPostCodeExtractData = 2, +}; + +enum SignPostColor: uint { // standard color scheme for signposts in Instruments + SignPostColorBlue = 0, + SignPostColorGreen = 1, + SignPostColorPurple = 2, + SignPostColorOrange = 3, + SignPostColorRed = 4, +}; + + + +@interface URKArchiveTests : URKArchiveTestCase @end + + +@implementation URKArchiveTests + + + +#pragma mark - Test Cases + + +#pragma mark Archive File + + +#if !TARGET_OS_IPHONE +- (void)testFileURL { + NSArray *testArchives = @[@"Large", + @"Test Archive.rar", + @"Test Archive (Password).rar", + @"Test Archive (Header Password).rar"]; + + for (NSString *testArchiveName in testArchives) { + NSLog(@"Testing fileURL of archive %@", testArchiveName); + NSURL *testArchiveURL = ([testArchiveName isEqualToString:@"Large"] + ? [self largeArchiveURL] + : self.testFileURLs[testArchiveName]); + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSURL *resolvedURL = archive.fileURL.URLByResolvingSymlinksInPath; + XCTAssertNotNil(resolvedURL, @"Nil URL returned for valid archive"); + XCTAssertTrue([testArchiveURL isEqual:resolvedURL], @"Resolved URL doesn't match original"); + } +} +#endif + +#if !TARGET_OS_IPHONE +- (void)testFilename { + NSArray *testArchives = @[@"Large", + @"Test Archive.rar", + @"Test Archive (Password).rar", + @"Test Archive (Header Password).rar"]; + + for (NSString *testArchiveName in testArchives) { + NSLog(@"Testing filename of archive %@", testArchiveName); + NSURL *testArchiveURL = ([testArchiveName isEqualToString:@"Large"] + ? [self largeArchiveURL] + : self.testFileURLs[testArchiveName]); + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSString *resolvedFilename = archive.filename; + XCTAssertNotNil(resolvedFilename, @"Nil filename returned for valid archive"); + + // Testing by suffix, since the original points to /private/var, but the resolved one + // points straight to /var. They're equivalent, but not character-for-character equal + XCTAssertTrue([resolvedFilename hasSuffix:testArchiveURL.path], + @"Resolved filename doesn't match original"); + } +} +#endif + +- (void)testUncompressedSize { + NSURL *testArchiveURL = self.testFileURLs[@"Test Archive.rar"]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + NSNumber *size = archive.uncompressedSize; + + XCTAssertNotNil(size, @"Nil size returned"); + XCTAssertEqual(size.integerValue, 104714, @"Wrong uncompressed size returned"); +} + +- (void)testUncompressedSize_InvalidArchive { + NSURL *testArchiveURL = self.testFileURLs[@"Test File A.txt"]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + NSNumber *size = archive.uncompressedSize; + + XCTAssertNil(size, @"Uncompressed size of invalid archive should be nil"); +} + +- (void)testCompressedSize { + NSURL *testArchiveURL = self.testFileURLs[@"Test Archive.rar"]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + NSNumber *size = archive.compressedSize; + + XCTAssertNotNil(size, @"Nil size returned"); + XCTAssertEqual(size.integerValue, 89069, @"Wrong uncompressed size returned"); +} + +- (void)testCompressedSize_ArchiveMissing { + NSURL *testArchiveURL = self.testFileURLs[@"Test Archive.rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + [[NSFileManager defaultManager] removeItemAtURL:testArchiveURL error:nil]; + + NSNumber *size = archive.compressedSize; + + XCTAssertNil(size, @"Compressed size of an archive with no path should be nil"); +} + + +#pragma mark - RAR file Detection + +#pragma By Path + +- (void)testPathIsARAR +{ + NSURL *url = self.testFileURLs[@"Test Archive.rar"]; + NSString *path = url.path; + BOOL pathIsRAR = [URKArchive pathIsARAR:path]; + XCTAssertTrue(pathIsRAR, @"RAR file is not reported as a RAR"); +} + +- (void)testPathIsARAR_NotARAR +{ + NSURL *url = self.testFileURLs[@"Test File B.jpg"]; + NSString *path = url.path; + BOOL pathIsRAR = [URKArchive pathIsARAR:path]; + XCTAssertFalse(pathIsRAR, @"JPG file is reported as a RAR"); +} + +- (void)testPathIsARAR_SmallFile +{ + NSURL *url = [self randomTextFileOfLength:1]; + NSString *path = url.path; + BOOL pathIsRAR = [URKArchive pathIsARAR:path]; + XCTAssertFalse(pathIsRAR, @"Small non-RAR file is reported as a RAR"); +} + +- (void)testPathIsARAR_MissingFile +{ + NSURL *url = [self.testFileURLs[@"Test Archive.rar"] URLByAppendingPathExtension:@"missing"]; + NSString *path = url.path; + BOOL pathIsRAR = [URKArchive pathIsARAR:path]; + XCTAssertFalse(pathIsRAR, @"Missing file is reported as a RAR"); +} + +#if !TARGET_OS_IPHONE +- (void)testPathIsARAR_FileHandleLeaks +{ + NSURL *smallFileURL = [self randomTextFileOfLength:1]; + NSURL *jpgURL = self.testFileURLs[@"Test File B.jpg"]; + + NSInteger initialFileCount = [self numberOfOpenFileHandles]; + + for (NSInteger i = 0; i < 10000; i++) { + BOOL smallFileIsZip = [URKArchive pathIsARAR:smallFileURL.path]; + XCTAssertFalse(smallFileIsZip, @"Small non-RAR file is reported as a RAR"); + + BOOL jpgIsZip = [URKArchive pathIsARAR:jpgURL.path]; + XCTAssertFalse(jpgIsZip, @"JPG file is reported as a RAR"); + + NSURL *zipURL = self.testFileURLs[@"Test Archive.rar"]; + BOOL zipFileIsZip = [URKArchive pathIsARAR:zipURL.path]; + XCTAssertTrue(zipFileIsZip, @"RAR file is not reported as a RAR"); + } + + NSInteger finalFileCount = [self numberOfOpenFileHandles]; + + XCTAssertEqualWithAccuracy(initialFileCount, finalFileCount, 5, @"File descriptors were left open"); +} +#endif + +#pragma By URL + +- (void)testurlIsARAR +{ + NSURL *url = self.testFileURLs[@"Test Archive.rar"]; + BOOL urlIsRAR = [URKArchive urlIsARAR:url]; + XCTAssertTrue(urlIsRAR, @"RAR file is not reported as a RAR"); +} + +- (void)testurlIsARAR_NotARAR +{ + NSURL *url = self.testFileURLs[@"Test File B.jpg"]; + BOOL urlIsRAR = [URKArchive urlIsARAR:url]; + XCTAssertFalse(urlIsRAR, @"JPG file is reported as a RAR"); +} + +- (void)testurlIsARAR_SmallFile +{ + NSURL *url = [self randomTextFileOfLength:1]; + BOOL urlIsRAR = [URKArchive urlIsARAR:url]; + XCTAssertFalse(urlIsRAR, @"Small non-RAR file is reported as a RAR"); +} + +- (void)testurlIsARAR_MissingFile +{ + NSURL *url = [self.testFileURLs[@"Test Archive.rar"] URLByAppendingPathExtension:@"missing"]; + BOOL urlIsRAR = [URKArchive urlIsARAR:url]; + XCTAssertFalse(urlIsRAR, @"Missing file is reported as a RAR"); +} + +#if !TARGET_OS_IPHONE +- (void)testurlIsARAR_FileHandleLeaks +{ + NSURL *smallFileURL = [self randomTextFileOfLength:1]; + NSURL *jpgURL = self.testFileURLs[@"Test File B.jpg"]; + + NSInteger initialFileCount = [self numberOfOpenFileHandles]; + + for (NSInteger i = 0; i < 10000; i++) { + BOOL smallFileIsZip = [URKArchive urlIsARAR:smallFileURL]; + XCTAssertFalse(smallFileIsZip, @"Small non-RAR file is reported as a RAR"); + + BOOL jpgIsZip = [URKArchive urlIsARAR:jpgURL]; + XCTAssertFalse(jpgIsZip, @"JPG file is reported as a RAR"); + + NSURL *zipURL = self.testFileURLs[@"Test Archive.rar"]; + BOOL zipFileIsZip = [URKArchive urlIsARAR:zipURL]; + XCTAssertTrue(zipFileIsZip, @"RAR file is not reported as a RAR"); + } + + NSInteger finalFileCount = [self numberOfOpenFileHandles]; + + XCTAssertEqualWithAccuracy(initialFileCount, finalFileCount, 5, @"File descriptors were left open"); +} +#endif + + + +#pragma mark List File Info + + +- (void)testListFileInfo { + URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Test Archive.rar"] error:nil]; + + NSSet *expectedFileSet = [self.testFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) { + return ![key hasSuffix:@"rar"]; + }]; + + NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)]; + + static NSDateFormatter *testFileInfoDateFormatter; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + testFileInfoDateFormatter = [[NSDateFormatter alloc] init]; + testFileInfoDateFormatter.dateFormat = @"M/dd/yyyy h:mm a"; + testFileInfoDateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US"]; + }); + + NSDictionary *expectedTimestamps = @{@"Test File A.txt": [testFileInfoDateFormatter dateFromString:@"3/13/2014 8:02 PM"], + @"Test File B.jpg": [testFileInfoDateFormatter dateFromString:@"3/13/2014 8:04 PM"], + @"Test File C.m4a": [testFileInfoDateFormatter dateFromString:@"3/13/2014 8:05 PM"],}; + + NSError *error = nil; + NSArray *filesInArchive = [archive listFileInfo:&error]; + + XCTAssertNil(error, @"Error returned by listFileInfo"); + XCTAssertNotNil(filesInArchive, @"No list of files returned"); + XCTAssertEqual(filesInArchive.count, expectedFileSet.count, @"Incorrect number of files listed in archive"); + + NSFileManager *fm = [NSFileManager defaultManager]; + + for (NSInteger i = 0; i < filesInArchive.count; i++) { + URKFileInfo *fileInfo = filesInArchive[i]; + + // Test Archive Name + NSString *expectedArchiveName = archive.filename; + XCTAssertEqualObjects(fileInfo.archiveName, expectedArchiveName, @"Incorrect archive name"); + + // Test Filename + NSString *expectedFilename = expectedFiles[i]; + XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Incorrect filename"); + + // Test CRC + NSUInteger expectedFileCRC = [self crcOfTestFile:expectedFilename]; + XCTAssertEqual(fileInfo.CRC, expectedFileCRC, @"Incorrect CRC checksum"); + + // Test Last Modify Date + NSTimeInterval archiveFileTimeInterval = [fileInfo.timestamp timeIntervalSinceReferenceDate]; + NSTimeInterval expectedFileTimeInterval = [expectedTimestamps[fileInfo.filename] timeIntervalSinceReferenceDate]; + XCTAssertEqualWithAccuracy(archiveFileTimeInterval, expectedFileTimeInterval, 60, @"Incorrect file timestamp (more than 60 seconds off)"); + + // Test Uncompressed Size + NSError *attributesError = nil; + NSString *expectedFilePath = [[self urlOfTestFile:expectedFilename] path]; + NSDictionary *expectedFileAttributes = [fm attributesOfItemAtPath:expectedFilePath + error:&attributesError]; + XCTAssertNil(attributesError, @"Error getting file attributes of %@", expectedFilename); + + long long expectedFileSize = expectedFileAttributes.fileSize; + XCTAssertEqual(fileInfo.uncompressedSize, expectedFileSize, @"Incorrect uncompressed file size"); + + // Test Compression method + XCTAssertEqual(fileInfo.compressionMethod, URKCompressionMethodNormal, @"Incorrect compression method"); + + // Test Host OS + XCTAssertEqual(fileInfo.hostOS, URKHostOSUnix, @"Incorrect host OS"); + } +} + +- (void)testListFileInfo_Unicode +{ + NSSet *expectedFileSet = [self.unicodeFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) { + return ![key hasSuffix:@"rar"]; + }]; + + NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)]; + + NSURL *testArchiveURL = self.unicodeFileURLs[@"Ⓣest Ⓐrchive.rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *error = nil; + NSArray *filesInArchive = [archive listFileInfo:&error]; + + XCTAssertNil(error, @"Error returned by listFileInfo"); + XCTAssertNotNil(filesInArchive, @"No list of files returned"); + XCTAssertEqual(filesInArchive.count, expectedFileSet.count, + @"Incorrect number of files listed in archive"); + + for (NSInteger i = 0; i < filesInArchive.count; i++) { + URKFileInfo *fileInfo = (URKFileInfo *)filesInArchive[i]; + + XCTAssertEqualObjects(fileInfo.filename, expectedFiles[i], @"Incorrect filename listed"); + XCTAssertEqualObjects(fileInfo.archiveName, archive.filename, @"Incorrect archiveName listed"); + } +} + +#if !TARGET_OS_IPHONE +- (void)testListFileInfo_MultivolumeArchive { + NSArray *generatedVolumeURLs = [self multiPartArchiveWithName:@"ListFileInfoTests_MultivolumeArchive.rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:generatedVolumeURLs.firstObject error:nil]; + + NSError *error = nil; + NSArray *files = [archive listFileInfo:&error]; + + XCTAssertNil(error, @"Error returned when listing file info for multivolume archive"); + XCTAssertEqual(files.count, 1, @"Incorrect number of file info items returned for multivolume archive"); +} +#endif + +- (void)testListFileInfo_HeaderPassword +{ + NSArray *testArchives = @[@"Test Archive (Header Password).rar"]; + + NSSet *expectedFileSet = [self.testFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) { + return ![key hasSuffix:@"rar"]; + }]; + + NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)]; + + for (NSString *testArchiveName in testArchives) { + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + + URKArchive *archiveNoPassword = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *error = nil; + NSArray *filesInArchive = [archiveNoPassword listFileInfo:&error]; + + XCTAssertNotNil(error, @"No error returned by listFileInfo (no password given)"); + XCTAssertNil(filesInArchive, @"List of files returned (no password given)"); + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL password:@"password" error:nil]; + + filesInArchive = nil; + error = nil; + filesInArchive = [archive listFileInfo:&error]; + + XCTAssertNil(error, @"Error returned by listFileInfo"); + XCTAssertEqual(filesInArchive.count, expectedFileSet.count, + @"Incorrect number of files listed in archive"); + + for (NSInteger i = 0; i < filesInArchive.count; i++) { + URKFileInfo *archiveFileInfo = filesInArchive[i]; + NSString *archiveFilename = archiveFileInfo.filename; + NSString *expectedFilename = expectedFiles[i]; + + XCTAssertEqualObjects(archiveFilename, expectedFilename, @"Incorrect filename listed"); + } + } +} + +- (void)testListFileInfo_NoHeaderPasswordGiven { + URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Test Archive (Header Password).rar"] error:nil]; + + NSError *error = nil; + NSArray *files = [archive listFileInfo:&error]; + + XCTAssertNotNil(error, @"List without password succeeded"); + XCTAssertNil(files, @"List returned without password"); + XCTAssertEqual(error.code, URKErrorCodeMissingPassword, @"Unexpected error code returned"); +} + +- (void)testListFileInfo_InvalidArchive +{ + URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Test File A.txt"] error:nil]; + + NSError *error = nil; + NSArray *files = [archive listFileInfo:&error]; + + XCTAssertNotNil(error, @"List files of invalid archive succeeded"); + XCTAssertNil(files, @"List returned for invalid archive"); + XCTAssertEqual(error.code, URKErrorCodeBadArchive, @"Unexpected error code returned"); +} + + +#pragma mark Extract Data + + +- (void)testExtractData +{ + NSArray *testArchives = @[@"Test Archive.rar", + @"Test Archive (Password).rar", + @"Test Archive (Header Password).rar"]; + + NSSet *expectedFileSet = [self.testFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) { + return ![key hasSuffix:@"rar"]; + }]; + + NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)]; + + for (NSString *testArchiveName in testArchives) { + + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *password = ([testArchiveName rangeOfString:@"Password"].location != NSNotFound + ? @"password" + : nil); + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL password:password error:nil]; + + NSError *error = nil; + NSArray *fileInfos = [archive listFileInfo:&error]; + XCTAssertNil(error, @"Error reading file info"); + + for (NSInteger i = 0; i < expectedFiles.count; i++) { + NSString *expectedFilename = expectedFiles[i]; + + NSError *error = nil; + NSData *extractedData = [archive extractDataFromFile:expectedFilename error:&error]; + + XCTAssertNil(error, @"Error in extractData:error:"); + + NSData *expectedFileData = [NSData dataWithContentsOfURL:self.testFileURLs[expectedFilename]]; + + XCTAssertNotNil(extractedData, @"No data extracted"); + XCTAssertTrue([expectedFileData isEqualToData:extractedData], @"Extracted data doesn't match original file"); + + error = nil; + NSData *dataFromFileInfo = [archive extractData:fileInfos[i] error:&error]; + XCTAssertNil(error, @"Error extracting data by file info"); + XCTAssertTrue([expectedFileData isEqualToData:dataFromFileInfo], @"Extracted data from file info doesn't match original file"); + } + } +} + +- (void)testExtractData_Unicode +{ + NSSet *expectedFileSet = [self.unicodeFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) { + return ![key hasSuffix:@"rar"]; + }]; + + NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)]; + + NSURL *testArchiveURL = self.unicodeFileURLs[@"Ⓣest Ⓐrchive.rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *error = nil; + NSArray *fileInfos = [archive listFileInfo:&error]; + XCTAssertNil(error, @"Error reading file info"); + + for (NSInteger i = 0; i < expectedFiles.count; i++) { + NSString *expectedFilename = expectedFiles[i]; + + NSError *error = nil; + NSData *extractedData = [archive extractDataFromFile:expectedFilename error:&error]; + + XCTAssertNil(error, @"Error in extractData:error:"); + + NSData *expectedFileData = [NSData dataWithContentsOfURL:self.unicodeFileURLs[expectedFilename]]; + + XCTAssertNotNil(extractedData, @"No data extracted"); + XCTAssertTrue([expectedFileData isEqualToData:extractedData], @"Extracted data doesn't match original file"); + + error = nil; + NSData *dataFromFileInfo = [archive extractData:fileInfos[i] error:&error]; + XCTAssertNil(error, @"Error extracting data by file info"); + XCTAssertTrue([expectedFileData isEqualToData:dataFromFileInfo], @"Extracted data from file info doesn't match original file"); + } +} + +- (void)testExtractData_NoPassword +{ + NSArray *testArchives = @[@"Test Archive (Password).rar", + @"Test Archive (Header Password).rar"]; + + for (NSString *testArchiveName in testArchives) { + URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[testArchiveName] error:nil]; + + NSError *error = nil; + NSData *data = [archive extractDataFromFile:@"Test File A.txt" error:&error]; + + XCTAssertNotNil(error, @"Extract data without password succeeded"); + XCTAssertNil(data, @"Data returned without password"); + XCTAssertEqual(error.code, URKErrorCodeMissingPassword, @"Unexpected error code returned"); + } +} + +- (void)testExtractData_InvalidArchive +{ + URKArchive *archive = [[URKArchive alloc] initWithURL:self.testFileURLs[@"Test File A.txt"] error:nil]; + + NSError *error = nil; + NSData *data = [archive extractDataFromFile:@"Any file.txt" error:&error]; + + XCTAssertNotNil(error, @"Extract data for invalid archive succeeded"); + XCTAssertNil(data, @"Data returned for invalid archive"); + XCTAssertEqual(error.code, URKErrorCodeBadArchive, @"Unexpected error code returned"); +} + + +#pragma mark Perform on Files + + +- (void)testPerformOnFiles +{ + NSArray *testArchives = @[@"Test Archive.rar", + @"Test Archive (Password).rar", + @"Test Archive (Header Password).rar"]; + + NSSet *expectedFileSet = [self.testFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) { + return ![key hasSuffix:@"rar"]; + }]; + + NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)]; + + for (NSString *testArchiveName in testArchives) { + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *password = ([testArchiveName rangeOfString:@"Password"].location != NSNotFound + ? @"password" + : nil); + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL password:password error:nil]; + + __block NSUInteger fileIndex = 0; + NSError *error = nil; + + [archive performOnFilesInArchive: + ^(URKFileInfo *fileInfo, BOOL *stop) { + NSString *expectedFilename = expectedFiles[fileIndex++]; + XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Unexpected filename encountered"); + } error:&error]; + + XCTAssertNil(error, @"Error iterating through files"); + XCTAssertEqual(fileIndex, expectedFiles.count, @"Incorrect number of files encountered"); + } +} + +- (void)testPerformOnFiles_Unicode +{ + NSSet *expectedFileSet = [self.unicodeFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) { + return ![key hasSuffix:@"rar"]; + }]; + + NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)]; + + NSURL *testArchiveURL = self.unicodeFileURLs[@"Ⓣest Ⓐrchive.rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + __block NSUInteger fileIndex = 0; + NSError *error = nil; + + [archive performOnFilesInArchive: + ^(URKFileInfo *fileInfo, BOOL *stop) { + NSString *expectedFilename = expectedFiles[fileIndex++]; + XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Unexpected filename encountered"); + } error:&error]; + + XCTAssertNil(error, @"Error iterating through files"); + XCTAssertEqual(fileIndex, expectedFiles.count, @"Incorrect number of files encountered"); +} + +#if !TARGET_OS_IPHONE +- (void)testPerformOnFiles_Ordering +{ + NSArray *testFilenames = @[@"AAA.txt", + @"BBB.txt", + @"CCC.txt"]; + + NSFileManager *fm = [NSFileManager defaultManager]; + + NSMutableArray *testFileURLs = [NSMutableArray array]; + + // Touch test files + [testFilenames enumerateObjectsUsingBlock:^(NSString *filename, NSUInteger idx, BOOL *stop) { + NSURL *outputURL = [self.tempDirectory URLByAppendingPathComponent:filename]; + XCTAssertTrue([fm createFileAtPath:outputURL.path contents:nil attributes:nil], @"Failed to create test file: %@", filename); + [testFileURLs addObject:outputURL]; + }]; + + // Create RAR archive with test files, reversed + NSURL *reversedArchiveURL = [self archiveWithFiles:testFileURLs.reverseObjectEnumerator.allObjects]; + + NSError *error = nil; + __block NSUInteger index = 0; + + URKArchive *archive = [[URKArchive alloc] initWithURL:reversedArchiveURL error:nil]; + [archive performOnFilesInArchive:^(URKFileInfo *fileInfo, BOOL *stop) { + NSString *expectedFilename = testFilenames[index++]; + XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Archive files not iterated through in correct order"); + } error:&error]; +} +#endif + + +#pragma mark Perform on Data + + +- (void)testPerformOnData +{ + NSArray *testArchives = @[@"Test Archive.rar", + @"Test Archive (Password).rar", + @"Test Archive (Header Password).rar"]; + + NSSet *expectedFileSet = [self.testFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) { + return ![key hasSuffix:@"rar"]; + }]; + + NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)]; + + for (NSString *testArchiveName in testArchives) { + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *password = ([testArchiveName rangeOfString:@"Password"].location != NSNotFound + ? @"password" + : nil); + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL password:password error:nil]; + + __block NSUInteger fileIndex = 0; + NSError *error = nil; + + [archive performOnDataInArchive: + ^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + NSString *expectedFilename = expectedFiles[fileIndex++]; + XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Unexpected filename encountered"); + + NSData *expectedFileData = [NSData dataWithContentsOfURL:self.testFileURLs[expectedFilename]]; + + XCTAssertNotNil(fileData, @"No data extracted"); + XCTAssertTrue([expectedFileData isEqualToData:fileData], @"File data doesn't match original file"); + } error:&error]; + + XCTAssertNil(error, @"Error iterating through files"); + XCTAssertEqual(fileIndex, expectedFiles.count, @"Incorrect number of files encountered"); + } +} + +- (void)testPerformOnData_Unicode +{ + NSSet *expectedFileSet = [self.unicodeFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) { + return ![key hasSuffix:@"rar"]; + }]; + + NSArray *expectedFiles = [[expectedFileSet allObjects] sortedArrayUsingSelector:@selector(compare:)]; + + NSURL *testArchiveURL = self.unicodeFileURLs[@"Ⓣest Ⓐrchive.rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + __block NSUInteger fileIndex = 0; + NSError *error = nil; + + [archive performOnDataInArchive: + ^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + NSString *expectedFilename = expectedFiles[fileIndex++]; + XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Unexpected filename encountered"); + + NSData *expectedFileData = [NSData dataWithContentsOfURL:self.unicodeFileURLs[expectedFilename]]; + + XCTAssertNotNil(fileData, @"No data extracted"); + XCTAssertTrue([expectedFileData isEqualToData:fileData], @"File data doesn't match original file"); + } error:&error]; + + XCTAssertNil(error, @"Error iterating through files"); + XCTAssertEqual(fileIndex, expectedFiles.count, @"Incorrect number of files encountered"); +} + +#if !TARGET_OS_IPHONE +- (void)testPerformOnData_FileMoved +{ + NSURL *largeArchiveURL = [self largeArchiveURL]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:largeArchiveURL error:nil]; + + NSError *error = nil; + NSArray *archiveFiles = [archive listFilenames:&error]; + + XCTAssertNotNil(archiveFiles, @"No filenames listed from test archive"); + XCTAssertNil(error, @"Error listing files in test archive: %@", error); + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [NSThread sleepForTimeInterval:1]; + + NSURL *movedURL = [largeArchiveURL URLByAppendingPathExtension:@"FileMoved"]; + + NSError *renameError = nil; + NSFileManager *fm = [NSFileManager defaultManager]; + [fm moveItemAtURL:largeArchiveURL toURL:movedURL error:&renameError]; + XCTAssertNil(renameError, @"Error renaming file: %@", renameError); + }); + + __block NSUInteger fileCount = 0; + + error = nil; + BOOL success = [archive performOnDataInArchive:^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + XCTAssertNotNil(fileData, @"Extracted file is nil: %@", fileInfo.filename); + + if (!fileInfo.isDirectory) { + fileCount++; + XCTAssertGreaterThan(fileData.length, 0, @"Extracted file is empty: %@", fileInfo.filename); + } + } error:&error]; + + XCTAssertEqual(fileCount, 20, @"Not all files read"); + XCTAssertTrue(success, @"Failed to read files"); + XCTAssertNil(error, @"Error reading files: %@", error); +} +#endif + +#if !TARGET_OS_IPHONE +- (void)testPerformOnData_FileDeleted +{ + NSURL *largeArchiveURL = [self largeArchiveURL]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:largeArchiveURL error:nil]; + + NSError *error = nil; + NSArray *archiveFiles = [archive listFilenames:&error]; + + XCTAssertNotNil(archiveFiles, @"No filenames listed from test archive"); + XCTAssertNil(error, @"Error listing files in test archive: %@", error); + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + [NSThread sleepForTimeInterval:1]; + + NSError *removeError = nil; + NSFileManager *fm = [NSFileManager defaultManager]; + [fm removeItemAtURL:largeArchiveURL error:&removeError]; + XCTAssertNil(removeError, @"Error removing file: %@", removeError); + }); + + __block NSUInteger fileCount = 0; + + error = nil; + BOOL success = [archive performOnDataInArchive:^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + XCTAssertNotNil(fileData, @"Extracted file is nil: %@", fileInfo.filename); + + if (!fileInfo.isDirectory) { + fileCount++; + XCTAssertGreaterThan(fileData.length, 0, @"Extracted file is empty: %@", fileInfo.filename); + } + } error:&error]; + + XCTAssertEqual(fileCount, 20, @"Not all files read"); + XCTAssertTrue(success, @"Failed to read files"); + XCTAssertNil(error, @"Error reading files: %@", error); +} +#endif + +#if !TARGET_OS_IPHONE +- (void)testPerformOnData_FileMovedBeforeBegin +{ + NSURL *largeArchiveURL = [self largeArchiveURL]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:largeArchiveURL error:nil]; + + NSError *error = nil; + NSArray *archiveFiles = [archive listFilenames:&error]; + + XCTAssertNotNil(archiveFiles, @"No filenames listed from test archive"); + XCTAssertNil(error, @"Error listing files in test archive: %@", error); + + NSURL *movedURL = [largeArchiveURL URLByAppendingPathExtension:@"FileMovedBeforeBegin"]; + + NSError *renameError = nil; + NSFileManager *fm = [NSFileManager defaultManager]; + [fm moveItemAtURL:largeArchiveURL toURL:movedURL error:&renameError]; + XCTAssertNil(renameError, @"Error renaming file: %@", renameError); + + __block NSUInteger fileCount = 0; + + error = nil; + BOOL success = [archive performOnDataInArchive:^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + XCTAssertNotNil(fileData, @"Extracted file is nil: %@", fileInfo.filename); + + if (!fileInfo.isDirectory) { + fileCount++; + XCTAssertGreaterThan(fileData.length, 0, @"Extracted file is empty: %@", fileInfo.filename); + } + } error:&error]; + + XCTAssertEqual(fileCount, 20, @"Not all files read"); + XCTAssertTrue(success, @"Failed to read files"); + XCTAssertNil(error, @"Error reading files: %@", error); +} +#endif + +- (void)testPerformOnData_Folder +{ + NSURL *testArchiveURL = self.testFileURLs[@"Folder Archive.rar"]; + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSArray *expectedFiles = @[@"G070-Cliff", @"G070-Cliff/image.jpg"]; + + __block NSUInteger fileIndex = 0; + NSError *error = nil; + + [archive performOnDataInArchive: + ^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + NSString *expectedFilename = expectedFiles[fileIndex++]; + XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Unexpected filename encountered"); + } error:&error]; + + XCTAssertNil(error, @"Error iterating through files"); + XCTAssertEqual(fileIndex, expectedFiles.count, @"Incorrect number of files encountered"); +} + + +#pragma mark Extract Buffered Data + + +- (void)testExtractBufferedData +{ + NSURL *archiveURL = self.testFileURLs[@"Test Archive.rar"]; + NSString *extractedFile = @"Test File B.jpg"; + URKArchive *archive = [[URKArchive alloc] initWithURL:archiveURL error:nil]; + + NSError *error = nil; + NSMutableData *reconstructedFile = [NSMutableData data]; + BOOL success = [archive extractBufferedDataFromFile:extractedFile + error:&error + action: + ^(NSData *dataChunk, CGFloat percentDecompressed) { + NSLog(@"Decompressed: %f%%", percentDecompressed); + [reconstructedFile appendBytes:dataChunk.bytes + length:dataChunk.length]; + }]; + + XCTAssertTrue(success, @"Failed to read buffered data"); + XCTAssertNil(error, @"Error reading buffered data"); + XCTAssertGreaterThan(reconstructedFile.length, 0, @"No data returned"); + + NSData *originalFile = [NSData dataWithContentsOfURL:self.testFileURLs[extractedFile]]; + XCTAssertTrue([originalFile isEqualToData:reconstructedFile], + @"File extracted in buffer not returned correctly"); +} + +#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200 +- (void)testExtractBufferedData_VeryLarge +{ + kdebug_signpost_start(SignPostCodeCreateTextFile, 0, 0, 0, SignPostColorBlue); + NSURL *largeTextFile = [self randomTextFileOfLength:1000000]; // Increase for a more dramatic test + XCTAssertNotNil(largeTextFile, @"No large text file URL returned"); + kdebug_signpost_end(SignPostCodeCreateTextFile, 0, 0, 0, SignPostColorBlue); + + kdebug_signpost_start(SignPostCodeArchiveData, 0, 0, 0, SignPostColorGreen); + NSURL *archiveURL = [self archiveWithFiles:@[largeTextFile]]; + XCTAssertNotNil(archiveURL, @"No archived large text file URL returned"); + kdebug_signpost_end(SignPostCodeArchiveData, 0, 0, 0, SignPostColorGreen); + + NSURL *deflatedFileURL = [self.tempDirectory URLByAppendingPathComponent:@"DeflatedTextFile.txt"]; + BOOL createSuccess = [[NSFileManager defaultManager] createFileAtPath:deflatedFileURL.path + contents:nil + attributes:nil]; + XCTAssertTrue(createSuccess, @"Failed to create empty deflate file"); + + NSError *handleError = nil; + NSFileHandle *deflated = [NSFileHandle fileHandleForWritingToURL:deflatedFileURL + error:&handleError]; + XCTAssertNil(handleError, @"Error creating a file handle"); + + URKArchive *archive = [[URKArchive alloc] initWithURL:archiveURL error:nil]; + + kdebug_signpost_start(SignPostCodeExtractData, 0, 0, 0, SignPostColorPurple); + + NSError *error = nil; + BOOL success = [archive extractBufferedDataFromFile:largeTextFile.lastPathComponent + error:&error + action: + ^(NSData *dataChunk, CGFloat percentDecompressed) { + NSLog(@"Decompressed: %f%%", percentDecompressed); + [deflated writeData:dataChunk]; + }]; + + kdebug_signpost_end(SignPostCodeExtractData, 0, 0, 0, SignPostColorPurple); + + XCTAssertTrue(success, @"Failed to read buffered data"); + XCTAssertNil(error, @"Error reading buffered data"); + + [deflated closeFile]; + + NSData *deflatedData = [NSData dataWithContentsOfURL:deflatedFileURL]; + NSData *fileData = [NSData dataWithContentsOfURL:largeTextFile]; + + XCTAssertTrue([fileData isEqualToData:deflatedData], @"Data didn't restore correctly"); +} +#endif + + + +#pragma mark Various + + +#if !TARGET_OS_IPHONE +- (void)testFileDescriptorUsage +{ + NSInteger initialFileCount = [self numberOfOpenFileHandles]; + + NSString *testArchiveName = @"Test Archive.rar"; + NSURL *testArchiveOriginalURL = self.testFileURLs[testArchiveName]; + NSFileManager *fm = [NSFileManager defaultManager]; + + for (NSInteger i = 0; i < 1000; 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); + + URKArchive *archive = [[URKArchive alloc] initWithURL:testArchiveCopyURL error:nil]; + + NSArray *fileList = [archive listFilenames:&error]; + XCTAssertNotNil(fileList); + + for (NSString *fileName in fileList) { + NSData *fileData = [archive extractDataFromFile:fileName error:&error]; + XCTAssertNotNil(fileData); + XCTAssertNil(error); + } + } + + NSInteger finalFileCount = [self numberOfOpenFileHandles]; + + XCTAssertEqualWithAccuracy(initialFileCount, finalFileCount, 5, @"File descriptors were left open"); +} +#endif + +#if !TARGET_OS_IPHONE +- (void)testMultiThreading { + NSURL *largeArchiveURL_A = [self largeArchiveURL]; + NSURL *largeArchiveURL_B = [largeArchiveURL_A.URLByDeletingLastPathComponent URLByAppendingPathComponent:@"Large Archive 2.rar"]; + NSURL *largeArchiveURL_C = [largeArchiveURL_A.URLByDeletingLastPathComponent URLByAppendingPathComponent:@"Large Archive 3.rar"]; + + NSFileManager *fm = [NSFileManager defaultManager]; + + NSError *archiveBCopyError = nil; + XCTAssertTrue([fm copyItemAtURL:largeArchiveURL_A toURL:largeArchiveURL_B error:&archiveBCopyError], @"Failed to copy archive B"); + XCTAssertNil(archiveBCopyError, @"Error copying archive B"); + + NSError *archiveCCopyError = nil; + XCTAssertTrue([fm copyItemAtURL:largeArchiveURL_A toURL:largeArchiveURL_C error:&archiveCCopyError], @"Failed to copy archive C"); + XCTAssertNil(archiveCCopyError, @"Error copying archive C"); + + URKArchive *largeArchiveA = [[URKArchive alloc] initWithURL:largeArchiveURL_A error:nil]; + URKArchive *largeArchiveB = [[URKArchive alloc] initWithURL:largeArchiveURL_B error:nil]; + URKArchive *largeArchiveC = [[URKArchive alloc] initWithURL:largeArchiveURL_C error:nil]; + + XCTestExpectation *expectationA = [self expectationWithDescription:@"A finished"]; + XCTestExpectation *expectationB = [self expectationWithDescription:@"B finished"]; + XCTestExpectation *expectationC = [self expectationWithDescription:@"C finished"]; + + NSBlockOperation *enumerateA = [NSBlockOperation blockOperationWithBlock:^{ + NSError *error = nil; + [largeArchiveA performOnDataInArchive:^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + NSLog(@"File name: %@", fileInfo.filename); + } error:&error]; + + XCTAssertNil(error); + [expectationA fulfill]; + }]; + + NSBlockOperation *enumerateB = [NSBlockOperation blockOperationWithBlock:^{ + NSError *error = nil; + [largeArchiveB performOnDataInArchive:^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + NSLog(@"File name: %@", fileInfo.filename); + } error:&error]; + + XCTAssertNil(error); + [expectationB fulfill]; + }]; + + NSBlockOperation *enumerateC = [NSBlockOperation blockOperationWithBlock:^{ + NSError *error = nil; + [largeArchiveC performOnDataInArchive:^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + NSLog(@"File name: %@", fileInfo.filename); + } error:&error]; + + XCTAssertNil(error); + [expectationC fulfill]; + }]; + + NSOperationQueue *queue = [[NSOperationQueue alloc] init]; + queue.maxConcurrentOperationCount = 3; + queue.suspended = YES; + + [queue addOperation:enumerateA]; + [queue addOperation:enumerateB]; + [queue addOperation:enumerateC]; + + queue.suspended = NO; + + [self waitForExpectationsWithTimeout:30 handler:^(NSError *error) { + if (error) { + NSLog(@"Error while waiting for expectations: %@", error); + } + }]; +} +#endif + +#if !TARGET_OS_IPHONE +- (void)testMultiThreading_SingleFile { + NSURL *largeArchiveURL = [self largeArchiveURL]; + + URKArchive *largeArchiveA = [[URKArchive alloc] initWithURL:largeArchiveURL error:nil]; + URKArchive *largeArchiveB = [[URKArchive alloc] initWithURL:largeArchiveURL error:nil]; + URKArchive *largeArchiveC = [[URKArchive alloc] initWithURL:largeArchiveURL error:nil]; + + XCTestExpectation *expectationA = [self expectationWithDescription:@"A finished"]; + XCTestExpectation *expectationB = [self expectationWithDescription:@"B finished"]; + XCTestExpectation *expectationC = [self expectationWithDescription:@"C finished"]; + + NSBlockOperation *enumerateA = [NSBlockOperation blockOperationWithBlock:^{ + NSError *error = nil; + [largeArchiveA performOnDataInArchive:^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + NSLog(@"File name: %@", fileInfo.filename); + } error:&error]; + + XCTAssertNil(error); + [expectationA fulfill]; + }]; + + NSBlockOperation *enumerateB = [NSBlockOperation blockOperationWithBlock:^{ + NSError *error = nil; + [largeArchiveB performOnDataInArchive:^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + NSLog(@"File name: %@", fileInfo.filename); + } error:&error]; + + XCTAssertNil(error); + [expectationB fulfill]; + }]; + + NSBlockOperation *enumerateC = [NSBlockOperation blockOperationWithBlock:^{ + NSError *error = nil; + [largeArchiveC performOnDataInArchive:^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + NSLog(@"File name: %@", fileInfo.filename); + } error:&error]; + + XCTAssertNil(error); + [expectationC fulfill]; + }]; + + NSOperationQueue *queue = [[NSOperationQueue alloc] init]; + queue.maxConcurrentOperationCount = 3; + queue.suspended = YES; + + [queue addOperation:enumerateA]; + [queue addOperation:enumerateB]; + [queue addOperation:enumerateC]; + + queue.suspended = NO; + + [self waitForExpectationsWithTimeout:30 handler:^(NSError *error) { + if (error) { + NSLog(@"Error while waiting for expectations: %@", error); + } + }]; +} +#endif + +#if !TARGET_OS_IPHONE +- (void)testMultiThreading_SingleArchiveObject { + NSURL *largeArchiveURL = [self largeArchiveURL]; + + URKArchive *largeArchive = [[URKArchive alloc] initWithURL:largeArchiveURL error:nil]; + + XCTestExpectation *expectationA = [self expectationWithDescription:@"A finished"]; + XCTestExpectation *expectationB = [self expectationWithDescription:@"B finished"]; + XCTestExpectation *expectationC = [self expectationWithDescription:@"C finished"]; + + NSBlockOperation *enumerateA = [NSBlockOperation blockOperationWithBlock:^{ + NSError *error = nil; + [largeArchive performOnDataInArchive:^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + NSLog(@"File name: %@", fileInfo.filename); + } error:&error]; + + XCTAssertNil(error); + [expectationA fulfill]; + }]; + + NSBlockOperation *enumerateB = [NSBlockOperation blockOperationWithBlock:^{ + NSError *error = nil; + [largeArchive performOnDataInArchive:^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + NSLog(@"File name: %@", fileInfo.filename); + } error:&error]; + + XCTAssertNil(error); + [expectationB fulfill]; + }]; + + NSBlockOperation *enumerateC = [NSBlockOperation blockOperationWithBlock:^{ + NSError *error = nil; + [largeArchive performOnDataInArchive:^(URKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + NSLog(@"File name: %@", fileInfo.filename); + } error:&error]; + + XCTAssertNil(error); + [expectationC fulfill]; + }]; + + NSOperationQueue *queue = [[NSOperationQueue alloc] init]; + queue.maxConcurrentOperationCount = 3; + queue.suspended = YES; + + [queue addOperation:enumerateA]; + [queue addOperation:enumerateB]; + [queue addOperation:enumerateC]; + + queue.suspended = NO; + + [self waitForExpectationsWithTimeout:30 handler:^(NSError *error) { + if (error) { + NSLog(@"Error while waiting for expectations: %@", error); + } + }]; +} +#endif + +- (void)testErrorIsCorrect +{ + NSError *error = nil; + URKArchive *archive = [[URKArchive alloc] initWithURL:self.corruptArchive error:nil]; + XCTAssertNil([archive listFilenames:&error], "Listing filenames in corrupt archive should return nil"); + XCTAssertNotNil(error, @"An error should be returned when listing filenames in a corrupt archive"); + XCTAssertNotNil(error.description, @"Error's description is nil"); +} + +- (void)testUnicodeArchiveName +{ + NSURL *originalArchiveURL = self.testFileURLs[@"Test Archive.rar"]; + + NSString *newArchiveName = @" ♔ ♕ ♖ ♗ ♘ ♙ ♚ ♛ ♜ ♝ ♞ ♟.rar"; + + NSURL *newArchiveURL = [[originalArchiveURL URLByDeletingLastPathComponent] + URLByAppendingPathComponent:newArchiveName]; + + NSError *error = nil; + BOOL moveSuccess = [[NSFileManager defaultManager] moveItemAtURL:originalArchiveURL + toURL:newArchiveURL + error:&error]; + XCTAssertTrue(moveSuccess, @"Failed to rename Test Archive to unicode name"); + XCTAssertNil(error, @"Error renaming Test Archive to unicode name: %@", error); + + NSString *extractDirectory = [self randomDirectoryWithPrefix: + [@"Unicode contents" stringByDeletingPathExtension]]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + NSError *extractFilesError = nil; + URKArchive *unicodeNamedArchive = [[URKArchive alloc] initWithURL:newArchiveURL error:nil]; + BOOL extractSuccess = [unicodeNamedArchive extractFilesTo:extractURL.path + overwrite:NO + error:&error]; + + XCTAssertTrue(extractSuccess, @"Failed to extract archive"); + XCTAssertNil(extractFilesError, @"Error extracting archive: %@", extractFilesError); +} + + + +@end diff --git a/Carthage/Checkouts/UnrarKit/Tests/UnrarKit Tests-Info.plist b/Carthage/Checkouts/UnrarKit/Tests/UnrarKit Tests-Info.plist new file mode 100644 index 0000000..ba72822 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Tests/UnrarKit Tests-Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/Carthage/Checkouts/UnrarKit/Tests/ValidatePasswordTests.m b/Carthage/Checkouts/UnrarKit/Tests/ValidatePasswordTests.m new file mode 100644 index 0000000..71c8fb5 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Tests/ValidatePasswordTests.m @@ -0,0 +1,73 @@ +// +// ValidatePasswordTests.m +// UnrarKit +// +// Created by Dov Frankel on 6/22/15. +// +// + +#import "URKArchiveTestCase.h" + +@interface ValidatePasswordTests : URKArchiveTestCase @end + +@implementation ValidatePasswordTests + +- (void)testValidatePassword_PasswordRequired +{ + NSURL *archiveURL = self.testFileURLs[@"Test Archive (Password).rar"]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:archiveURL error:nil]; + + XCTAssertFalse(archive.validatePassword, @"validatePassword = YES when no password supplied"); + + archive.password = @"wrong"; + XCTAssertFalse(archive.validatePassword, @"validatePassword = YES when wrong password supplied"); + + archive.password = @"password"; + XCTAssertTrue(archive.validatePassword, @"validatePassword = NO when correct password supplied"); +} + +- (void)testValidatePassword_HeaderPasswordRequired +{ + NSURL *archiveURL = self.testFileURLs[@"Test Archive (Header Password).rar"]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:archiveURL error:nil]; + + XCTAssertFalse(archive.validatePassword, @"validatePassword = YES when no password supplied"); + + archive.password = @"wrong"; + XCTAssertFalse(archive.validatePassword, @"validatePassword = YES when wrong password supplied"); + + archive.password = @"password"; + XCTAssertTrue(archive.validatePassword, @"validatePassword = NO when correct password supplied"); +} + +- (void)testValidatePassword_PasswordNotRequired +{ + NSURL *archiveURL = self.testFileURLs[@"Test Archive.rar"]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:archiveURL error:nil]; + + XCTAssertTrue(archive.validatePassword, @"validatePassword = NO when no password supplied"); + + archive.password = @"password"; + XCTAssertTrue(archive.validatePassword, @"validatePassword = NO when password supplied"); +} + +- (void)testValidatePassword_RAR5 +{ + NSURL *archiveURL = self.testFileURLs[@"Test Archive (RAR5, Password).rar"]; + + URKArchive *archive = [[URKArchive alloc] initWithURL:archiveURL error:nil]; + + XCTAssertFalse(archive.validatePassword, @"validatePassword = YES when no password supplied"); + + archive.password = @"wrong"; + XCTAssertFalse(archive.validatePassword, @"validatePassword = YES when wrong password supplied"); + + archive.password = @"123"; + XCTAssertTrue(archive.validatePassword, @"validatePassword = NO when correct password supplied"); +} + + +@end diff --git a/Carthage/Checkouts/UnrarKit/Tests/en.lproj/InfoPlist.strings b/Carthage/Checkouts/UnrarKit/Tests/en.lproj/InfoPlist.strings new file mode 100644 index 0000000..477b28f --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/Tests/en.lproj/InfoPlist.strings @@ -0,0 +1,2 @@ +/* Localized versions of Info.plist keys */ + diff --git a/Carthage/Checkouts/UnrarKit/UnrarKit.podspec b/Carthage/Checkouts/UnrarKit/UnrarKit.podspec new file mode 100644 index 0000000..ccfd144 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/UnrarKit.podspec @@ -0,0 +1,111 @@ +Pod::Spec.new do |s| + s.name = "UnrarKit" + s.version = ENV["TRAVIS_TAG"] + s.summary = "UnrarKit is here to enable Mac and iOS Cocoa apps to easily work with RAR files for read-only operations" + s.license = "BSD" + s.homepage = "https://github.com/abbeycode/UnrarKit" + s.author = { "Dov Frankel" => "dov@abbey-code.com" } + s.social_media_url = "https://twitter.com/dovfrankel" + s.source = { :git => "https://github.com/abbeycode/UnrarKit.git", :tag => "#{s.version}" } + s.ios.deployment_target = "9.0" + s.osx.deployment_target = "10.9" + s.requires_arc = "Classes/**/*" + s.source_files = "Classes/**/*.{mm,m,h}" + s.public_header_files = "Classes/*.h" + s.resource_bundles = { + 'UnrarKitResources' => ['Resources/**/*'] + } + s.library = "z" + + s.test_spec 'Tests' do |test_spec| + test_spec.requires_arc = "Tests/**/*" + test_spec.source_files = "Tests/*.{h,m}" + test_spec.resources = ["Tests/Test Data"] + end + + s.subspec "unrar-lib" do |ss| + ss.public_header_files = "Libraries/unrar/raros.hpp", + "Libraries/unrar/dll.hpp" + ss.source_files = "Libraries/unrar/*.hpp", + "Libraries/unrar/rar.cpp", + "Libraries/unrar/strlist.cpp", + "Libraries/unrar/strfn.cpp", + "Libraries/unrar/pathfn.cpp", + "Libraries/unrar/smallfn.cpp", + "Libraries/unrar/global.cpp", + "Libraries/unrar/file.cpp", + "Libraries/unrar/filefn.cpp", + "Libraries/unrar/filcreat.cpp", + "Libraries/unrar/archive.cpp", + "Libraries/unrar/arcread.cpp", + "Libraries/unrar/unicode.cpp", + "Libraries/unrar/system.cpp", + "Libraries/unrar/isnt.cpp", + "Libraries/unrar/crypt.cpp", + "Libraries/unrar/crc.cpp", + "Libraries/unrar/rawread.cpp", + "Libraries/unrar/encname.cpp", + "Libraries/unrar/resource.cpp", + "Libraries/unrar/match.cpp", + "Libraries/unrar/timefn.cpp", + "Libraries/unrar/rdwrfn.cpp", + "Libraries/unrar/consio.cpp", + "Libraries/unrar/options.cpp", + "Libraries/unrar/errhnd.cpp", + "Libraries/unrar/rarvm.cpp", + "Libraries/unrar/secpassword.cpp", + "Libraries/unrar/rijndael.cpp", + "Libraries/unrar/getbits.cpp", + "Libraries/unrar/sha1.cpp", + "Libraries/unrar/sha256.cpp", + "Libraries/unrar/blake2s.cpp", + "Libraries/unrar/hash.cpp", + "Libraries/unrar/extinfo.cpp", + "Libraries/unrar/extract.cpp", + "Libraries/unrar/volume.cpp", + "Libraries/unrar/list.cpp", + "Libraries/unrar/find.cpp", + "Libraries/unrar/unpack.cpp", + "Libraries/unrar/headers.cpp", + "Libraries/unrar/threadpool.cpp", + "Libraries/unrar/rs16.cpp", + "Libraries/unrar/cmddata.cpp", + "Libraries/unrar/ui.cpp", + "Libraries/unrar/filestr.cpp", + "Libraries/unrar/recvol.cpp", + "Libraries/unrar/rs.cpp", + "Libraries/unrar/scantree.cpp", + "Libraries/unrar/qopen.cpp", + "Libraries/unrar/dll.cpp" + # These files are built implicitly as dependencies + ss.preserve_paths = "Libraries/unrar/arccmt.cpp", + "Libraries/unrar/blake2sp.cpp", + "Libraries/unrar/coder.cpp", + "Libraries/unrar/crypt1.cpp", + "Libraries/unrar/crypt2.cpp", + "Libraries/unrar/crypt3.cpp", + "Libraries/unrar/crypt5.cpp", + "Libraries/unrar/hardlinks.cpp", + "Libraries/unrar/log.cpp", + "Libraries/unrar/model.cpp", + "Libraries/unrar/rarvmtbl.cpp", + "Libraries/unrar/recvol3.cpp", + "Libraries/unrar/recvol5.cpp", + "Libraries/unrar/suballoc.cpp", + "Libraries/unrar/uicommon.cpp", + "Libraries/unrar/uisilent.cpp", + "Libraries/unrar/ulinks.cpp", + "Libraries/unrar/unpack15.cpp", + "Libraries/unrar/unpack20.cpp", + "Libraries/unrar/unpack30.cpp", + "Libraries/unrar/unpack50.cpp", + "Libraries/unrar/unpack50frag.cpp", + "Libraries/unrar/unpackinline.cpp", + "Libraries/unrar/uowners.cpp", + "Libraries/unrar/win32stm.cpp" + ss.pod_target_xcconfig = { "OTHER_LDFLAGS" => "$(inherited) -lc++", + "OTHER_CFLAGS" => "$(inherited) -Wno-return-type -Wno-logical-op-parentheses -Wno-conversion -Wno-parentheses -Wno-unused-function -Wno-unused-variable -Wno-switch -Wno-unused-command-line-argument -Wno-strict-prototypes -Wno-conditional-uninitialized", + "OTHER_CPLUSPLUSFLAGS" => "$(inherited) -DSILENT -DRARDLL $(OTHER_CFLAGS)" } + ss.compiler_flags = "-Xanalyzer -analyzer-disable-all-checks" + end +end diff --git a/Carthage/Checkouts/UnrarKit/UnrarKit.xcodeproj/.gitignore b/Carthage/Checkouts/UnrarKit/UnrarKit.xcodeproj/.gitignore new file mode 100644 index 0000000..2af29df --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/UnrarKit.xcodeproj/.gitignore @@ -0,0 +1,2 @@ +/rogerio.mode1v3 +/rogerio.pbxuser diff --git a/Carthage/Checkouts/UnrarKit/UnrarKit.xcodeproj/project.pbxproj b/Carthage/Checkouts/UnrarKit/UnrarKit.xcodeproj/project.pbxproj new file mode 100644 index 0000000..d7e70bb --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/UnrarKit.xcodeproj/project.pbxproj @@ -0,0 +1,1463 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 7A22B1F81F60A2D3004B8050 /* UnrarKit.strings in Resources */ = {isa = PBXBuildFile; fileRef = 7A22B1FA1F60A2D3004B8050 /* UnrarKit.strings */; }; + 7A22B1FB1F60A39E004B8050 /* UnrarKitResources.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 7A22B1EA1F60A05F004B8050 /* UnrarKitResources.bundle */; }; + 7A267F6E1F713B970004EAA6 /* ProgressReportingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A267F6D1F713B970004EAA6 /* ProgressReportingTests.m */; }; + 7A66082B20B4BE2000FE68D6 /* IterateFileInfoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7A66082A20B4BE2000FE68D6 /* IterateFileInfoTests.m */; }; + 7AC29A611F83C0D600DA4DE6 /* rar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F4A18DB722E00B5651B /* rar.cpp */; }; + 7AC29A621F83C0DD00DA4DE6 /* strlist.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F6D18DB722E00B5651B /* strlist.cpp */; }; + 7AC29A631F83C0E200DA4DE6 /* strfn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F6B18DB722E00B5651B /* strfn.cpp */; }; + 7AC29A641F83C0F000DA4DE6 /* pathfn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F4818DB722E00B5651B /* pathfn.cpp */; }; + 7AC29A651F83C10200DA4DE6 /* smallfn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F6918DB722E00B5651B /* smallfn.cpp */; }; + 7AC29A661F83C11400DA4DE6 /* global.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F3018DB722E00B5651B /* global.cpp */; }; + 7AC29A671F83C12200DA4DE6 /* file.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F2618DB722E00B5651B /* file.cpp */; }; + 7AC29A681F83C12D00DA4DE6 /* filefn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F2818DB722E00B5651B /* filefn.cpp */; }; + 7AC29A691F83C13600DA4DE6 /* filcreat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F2418DB722E00B5651B /* filcreat.cpp */; }; + 7AC29A6A1F83C13D00DA4DE6 /* archive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F0818DB722E00B5651B /* archive.cpp */; }; + 7AC29A6B1F83C14200DA4DE6 /* arcread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F0A18DB722E00B5651B /* arcread.cpp */; }; + 7AC29A6C1F83C14D00DA4DE6 /* unicode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F7718DB722E00B5651B /* unicode.cpp */; }; + 7AC29A6D1F83C15400DA4DE6 /* system.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F7118DB722E00B5651B /* system.cpp */; }; + 7AC29A6E1F83C16500DA4DE6 /* isnt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F3318DB722E00B5651B /* isnt.cpp */; }; + 7AC29A6F1F83C16D00DA4DE6 /* crypt.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F1618DB722E00B5651B /* crypt.cpp */; }; + 7AC29A701F83C17300DA4DE6 /* crc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F1418DB722E00B5651B /* crc.cpp */; }; + 7AC29A711F83C17900DA4DE6 /* rawread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F5418DB722E00B5651B /* rawread.cpp */; }; + 7AC29A721F83C1CD00DA4DE6 /* consio.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F1218DB722E00B5651B /* consio.cpp */; }; + 7AC29A731F83C1CD00DA4DE6 /* encname.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F1C18DB722E00B5651B /* encname.cpp */; }; + 7AC29A741F83C1CD00DA4DE6 /* errhnd.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F1E18DB722E00B5651B /* errhnd.cpp */; }; + 7AC29A751F83C1CD00DA4DE6 /* getbits.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F2E18DB722E00B5651B /* getbits.cpp */; }; + 7AC29A761F83C1CD00DA4DE6 /* match.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F3F18DB722E00B5651B /* match.cpp */; }; + 7AC29A771F83C1CD00DA4DE6 /* options.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F4418DB722E00B5651B /* options.cpp */; }; + 7AC29A781F83C1CD00DA4DE6 /* rarvm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F5118DB722E00B5651B /* rarvm.cpp */; }; + 7AC29A791F83C1CD00DA4DE6 /* rdwrfn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F5618DB722E00B5651B /* rdwrfn.cpp */; }; + 7AC29A7A1F83C1CD00DA4DE6 /* resource.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F5B18DB722E00B5651B /* resource.cpp */; }; + 7AC29A7B1F83C1CD00DA4DE6 /* rijndael.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F5D18DB722E00B5651B /* rijndael.cpp */; }; + 7AC29A7C1F83C1CD00DA4DE6 /* secpassword.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F6518DB722E00B5651B /* secpassword.cpp */; }; + 7AC29A7D1F83C1CD00DA4DE6 /* timefn.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F7318DB722E00B5651B /* timefn.cpp */; }; + 7AC29A7E1F83C21700DA4DE6 /* blake2s.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96370FB419ED8A8200DAF8F1 /* blake2s.cpp */; }; + 7AC29A7F1F83C21700DA4DE6 /* cmddata.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F0D18DB722E00B5651B /* cmddata.cpp */; }; + 7AC29A801F83C21700DA4DE6 /* dll.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F1818DB722E00B5651B /* dll.cpp */; }; + 7AC29A811F83C21700DA4DE6 /* extinfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F2018DB722E00B5651B /* extinfo.cpp */; }; + 7AC29A821F83C21700DA4DE6 /* extract.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F2218DB722E00B5651B /* extract.cpp */; }; + 7AC29A831F83C21700DA4DE6 /* filestr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F2A18DB722E00B5651B /* filestr.cpp */; }; + 7AC29A841F83C21700DA4DE6 /* find.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F2C18DB722E00B5651B /* find.cpp */; }; + 7AC29A851F83C21700DA4DE6 /* hash.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96370FC419ED8B0400DAF8F1 /* hash.cpp */; }; + 7AC29A861F83C21700DA4DE6 /* headers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96370FC619ED8B1F00DAF8F1 /* headers.cpp */; }; + 7AC29A871F83C21700DA4DE6 /* list.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F3618DB722E00B5651B /* list.cpp */; }; + 7AC29A881F83C21700DA4DE6 /* qopen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96370FC919ED8B4E00DAF8F1 /* qopen.cpp */; }; + 7AC29A891F83C21700DA4DE6 /* recvol.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F5918DB722E00B5651B /* recvol.cpp */; }; + 7AC29A8A1F83C21700DA4DE6 /* rs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F5F18DB722E00B5651B /* rs.cpp */; }; + 7AC29A8B1F83C21700DA4DE6 /* rs16.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96370FCD19ED8B9700DAF8F1 /* rs16.cpp */; }; + 7AC29A8C1F83C21700DA4DE6 /* scantree.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F6318DB722E00B5651B /* scantree.cpp */; }; + 7AC29A8D1F83C21700DA4DE6 /* sha1.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F6718DB722E00B5651B /* sha1.cpp */; }; + 7AC29A8E1F83C21700DA4DE6 /* sha256.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96370FCF19ED8BB200DAF8F1 /* sha256.cpp */; }; + 7AC29A8F1F83C21700DA4DE6 /* threadpool.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96370FD219ED8C6100DAF8F1 /* threadpool.cpp */; }; + 7AC29A901F83C21700DA4DE6 /* ui.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96370FD419ED8C8000DAF8F1 /* ui.cpp */; }; + 7AC29A911F83C21700DA4DE6 /* unpack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F7A18DB722E00B5651B /* unpack.cpp */; }; + 7AC29A921F83C21700DA4DE6 /* volume.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 96853F8218DB722F00B5651B /* volume.cpp */; }; + 7AC29A931F83C2A200DA4DE6 /* dll.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F1A18DB722E00B5651B /* dll.hpp */; }; + 7AC29A941F83C2A200DA4DE6 /* raros.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F4E18DB722E00B5651B /* raros.hpp */; }; + 7AC29A951F83C36900DA4DE6 /* archive.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F0918DB722E00B5651B /* archive.hpp */; }; + 7AC29A961F83C36900DA4DE6 /* array.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F0B18DB722E00B5651B /* array.hpp */; }; + 7AC29A971F83C36900DA4DE6 /* cmddata.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F0E18DB722E00B5651B /* cmddata.hpp */; }; + 7AC29A981F83C36900DA4DE6 /* coder.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F1018DB722E00B5651B /* coder.hpp */; }; + 7AC29A991F83C36900DA4DE6 /* compress.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F1118DB722E00B5651B /* compress.hpp */; }; + 7AC29A9A1F83C36900DA4DE6 /* consio.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F1318DB722E00B5651B /* consio.hpp */; }; + 7AC29A9B1F83C36900DA4DE6 /* crc.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F1518DB722E00B5651B /* crc.hpp */; }; + 7AC29A9C1F83C36900DA4DE6 /* crypt.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F1718DB722E00B5651B /* crypt.hpp */; }; + 7AC29A9D1F83C36900DA4DE6 /* encname.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F1D18DB722E00B5651B /* encname.hpp */; }; + 7AC29A9E1F83C36900DA4DE6 /* errhnd.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F1F18DB722E00B5651B /* errhnd.hpp */; }; + 7AC29A9F1F83C36900DA4DE6 /* extinfo.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F2118DB722E00B5651B /* extinfo.hpp */; }; + 7AC29AA01F83C36900DA4DE6 /* extract.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F2318DB722E00B5651B /* extract.hpp */; }; + 7AC29AA11F83C36900DA4DE6 /* filcreat.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F2518DB722E00B5651B /* filcreat.hpp */; }; + 7AC29AA21F83C36900DA4DE6 /* file.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F2718DB722E00B5651B /* file.hpp */; }; + 7AC29AA31F83C36900DA4DE6 /* filefn.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F2918DB722E00B5651B /* filefn.hpp */; }; + 7AC29AA41F83C36900DA4DE6 /* filestr.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F2B18DB722E00B5651B /* filestr.hpp */; }; + 7AC29AA51F83C36900DA4DE6 /* find.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F2D18DB722E00B5651B /* find.hpp */; }; + 7AC29AA61F83C36900DA4DE6 /* getbits.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F2F18DB722E00B5651B /* getbits.hpp */; }; + 7AC29AA71F83C36900DA4DE6 /* global.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F3118DB722E00B5651B /* global.hpp */; }; + 7AC29AA81F83C36900DA4DE6 /* headers.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F3218DB722E00B5651B /* headers.hpp */; }; + 7AC29AA91F83C36900DA4DE6 /* isnt.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F3418DB722E00B5651B /* isnt.hpp */; }; + 7AC29AAA1F83C36900DA4DE6 /* list.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F3718DB722E00B5651B /* list.hpp */; }; + 7AC29AAB1F83C36900DA4DE6 /* loclang.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F3818DB722E00B5651B /* loclang.hpp */; }; + 7AC29AAC1F83C36900DA4DE6 /* log.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F3A18DB722E00B5651B /* log.hpp */; }; + 7AC29AAD1F83C36900DA4DE6 /* match.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F4018DB722E00B5651B /* match.hpp */; }; + 7AC29AAE1F83C36900DA4DE6 /* model.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F4218DB722E00B5651B /* model.hpp */; }; + 7AC29AAF1F83C36900DA4DE6 /* options.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F4518DB722E00B5651B /* options.hpp */; }; + 7AC29AB01F83C36900DA4DE6 /* os.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F4618DB722E00B5651B /* os.hpp */; }; + 7AC29AB11F83C36900DA4DE6 /* pathfn.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F4918DB722E00B5651B /* pathfn.hpp */; }; + 7AC29AB21F83C36900DA4DE6 /* rar.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F4B18DB722E00B5651B /* rar.hpp */; }; + 7AC29AB31F83C36900DA4DE6 /* rardefs.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F4C18DB722E00B5651B /* rardefs.hpp */; }; + 7AC29AB41F83C36900DA4DE6 /* rarlang.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F4D18DB722E00B5651B /* rarlang.hpp */; }; + 7AC29AB51F83C36900DA4DE6 /* rartypes.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F5018DB722E00B5651B /* rartypes.hpp */; }; + 7AC29AB61F83C36900DA4DE6 /* rarvm.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F5218DB722E00B5651B /* rarvm.hpp */; }; + 7AC29AB71F83C36900DA4DE6 /* rawread.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F5518DB722E00B5651B /* rawread.hpp */; }; + 7AC29AB81F83C36900DA4DE6 /* rdwrfn.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F5718DB722E00B5651B /* rdwrfn.hpp */; }; + 7AC29AB91F83C36900DA4DE6 /* recvol.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F5A18DB722E00B5651B /* recvol.hpp */; }; + 7AC29ABA1F83C36900DA4DE6 /* resource.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F5C18DB722E00B5651B /* resource.hpp */; }; + 7AC29ABB1F83C36900DA4DE6 /* rijndael.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F5E18DB722E00B5651B /* rijndael.hpp */; }; + 7AC29ABC1F83C36900DA4DE6 /* rs.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F6018DB722E00B5651B /* rs.hpp */; }; + 7AC29ABD1F83C36900DA4DE6 /* savepos.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F6218DB722E00B5651B /* savepos.hpp */; }; + 7AC29ABE1F83C36900DA4DE6 /* scantree.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F6418DB722E00B5651B /* scantree.hpp */; }; + 7AC29ABF1F83C36900DA4DE6 /* secpassword.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F6618DB722E00B5651B /* secpassword.hpp */; }; + 7AC29AC01F83C36900DA4DE6 /* sha1.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F6818DB722E00B5651B /* sha1.hpp */; }; + 7AC29AC11F83C36900DA4DE6 /* smallfn.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F6A18DB722E00B5651B /* smallfn.hpp */; }; + 7AC29AC21F83C36900DA4DE6 /* strfn.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F6C18DB722E00B5651B /* strfn.hpp */; }; + 7AC29AC31F83C36900DA4DE6 /* strlist.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F6E18DB722E00B5651B /* strlist.hpp */; }; + 7AC29AC41F83C36900DA4DE6 /* suballoc.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F7018DB722E00B5651B /* suballoc.hpp */; }; + 7AC29AC51F83C36900DA4DE6 /* system.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F7218DB722E00B5651B /* system.hpp */; }; + 7AC29AC61F83C36900DA4DE6 /* timefn.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F7418DB722E00B5651B /* timefn.hpp */; }; + 7AC29AC71F83C36900DA4DE6 /* unicode.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F7818DB722E00B5651B /* unicode.hpp */; }; + 7AC29AC81F83C36900DA4DE6 /* unpack.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F7B18DB722E00B5651B /* unpack.hpp */; }; + 7AC29AC91F83C36900DA4DE6 /* version.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F8118DB722F00B5651B /* version.hpp */; }; + 7AC29ACA1F83C36900DA4DE6 /* volume.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F8318DB722F00B5651B /* volume.hpp */; }; + 7AC29ACB1F83C3E700DA4DE6 /* libunrar.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7AC29A5D1F83C08200DA4DE6 /* libunrar.a */; }; + 7AC29ACD1F83DB0400DA4DE6 /* dll.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F1A18DB722E00B5651B /* dll.hpp */; settings = {ATTRIBUTES = (Public, ); }; }; + 7AC29ACE1F83DB1000DA4DE6 /* raros.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 96853F4E18DB722E00B5651B /* raros.hpp */; settings = {ATTRIBUTES = (Public, ); }; }; + 7AC29AD01F850A6A00DA4DE6 /* UnrarKitMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 96BF58BA1F3A487100BC24E1 /* UnrarKitMacros.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 7ADC7A091F8831BC00023C2E /* CheckDataTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 7ADC7A081F8831BC00023C2E /* CheckDataTests.m */; }; + 964C8AC718D28EE000AD7321 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 964C8AC518D28EE000AD7321 /* InfoPlist.strings */; }; + 9660D7AF1A3F4FF90059AC1E /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 9660D7AE1A3F4FF90059AC1E /* libz.dylib */; }; + 967872741E460FA70048A54C /* ListVolumesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 967872731E460FA70048A54C /* ListVolumesTests.m */; }; + 9699F91D1B3CB4D000B6D373 /* URKArchive.h in Headers */ = {isa = PBXBuildFile; fileRef = 489CFA0E128B5169005DCC2A /* URKArchive.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9699F91E1B3CB4D000B6D373 /* URKFileInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = F3FCD4691A3262E5003612BF /* URKFileInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9699F91F1B3CB4D000B6D373 /* UnrarKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 969F17361A60297700665453 /* UnrarKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 9699FA6A1B3CE95D00B6D373 /* UnrarKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96EA535B1B3CB04300F79DC6 /* UnrarKit.framework */; }; + 9699FA891B3D9B5700B6D373 /* URKArchiveTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 964C8AC818D28EE000AD7321 /* URKArchiveTests.m */; }; + 9699FA8A1B3D9B6F00B6D373 /* URKArchiveTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 964547D11B384F7D00202B28 /* URKArchiveTestCase.m */; }; + 9699FA8B1B3D9B6F00B6D373 /* ExtractFilesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 96F4507A1B385BCD00679597 /* ExtractFilesTests.m */; }; + 9699FA8C1B3D9B6F00B6D373 /* IsPasswordProtectedTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 96F450761B38552200679597 /* IsPasswordProtectedTests.m */; }; + 9699FA8D1B3D9B6F00B6D373 /* ListFilenamesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 96F450781B385AF800679597 /* ListFilenamesTests.m */; }; + 9699FA8E1B3D9B6F00B6D373 /* ValidatePasswordTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 96F450741B38527100679597 /* ValidatePasswordTests.m */; }; + 96A043DE1E4CC8D500BD7013 /* FirstVolumeTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 96A043DD1E4CC8D500BD7013 /* FirstVolumeTests.m */; }; + 96A043E01E4D232F00BD7013 /* HasMultipleVolumesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 96A043DF1E4D232F00BD7013 /* HasMultipleVolumesTests.m */; }; + 96E5D345198B333200A74340 /* Test Data in Resources */ = {isa = PBXBuildFile; fileRef = 964C8AD018D28F1600AD7321 /* Test Data */; }; + 96EA537E1B3CB2C700F79DC6 /* URKFileInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = F3FCD46A1A3262E5003612BF /* URKFileInfo.m */; }; + 96EA53961B3CB2C700F79DC6 /* NSString+UnrarKit.mm in Sources */ = {isa = PBXBuildFile; fileRef = 96DBF7F81A3F72800033B759 /* NSString+UnrarKit.mm */; }; + 96EA53AC1B3CB2C700F79DC6 /* URKArchive.mm in Sources */ = {isa = PBXBuildFile; fileRef = 489CFA0F128B5169005DCC2A /* URKArchive.mm */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 7ACC4CC81F7EF00F001A07F6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0867D690FE84028FC02AAC07 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 7A22B1E91F60A05F004B8050; + remoteInfo = UnrarKitResources; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 964C8AD118D28F2900AD7321 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 1; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 489CFA0E128B5169005DCC2A /* URKArchive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = URKArchive.h; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objcpp; }; + 489CFA0F128B5169005DCC2A /* URKArchive.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = URKArchive.mm; sourceTree = ""; }; + 7A0668ED1FBBAABB00437F5F /* UnrarKitResources-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "UnrarKitResources-Info.plist"; sourceTree = ""; }; + 7A22B1EA1F60A05F004B8050 /* UnrarKitResources.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnrarKitResources.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 7A22B1F91F60A2D3004B8050 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/UnrarKit.strings; sourceTree = ""; }; + 7A267F6D1F713B970004EAA6 /* ProgressReportingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProgressReportingTests.m; sourceTree = ""; }; + 7A66082A20B4BE2000FE68D6 /* IterateFileInfoTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IterateFileInfoTests.m; sourceTree = ""; }; + 7AC29A5D1F83C08200DA4DE6 /* libunrar.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libunrar.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 7ADC7A081F8831BC00023C2E /* CheckDataTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = CheckDataTests.m; sourceTree = ""; }; + 96370FB319ED8A8200DAF8F1 /* blake2s_sse.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = blake2s_sse.cpp; sourceTree = ""; }; + 96370FB419ED8A8200DAF8F1 /* blake2s.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = blake2s.cpp; sourceTree = ""; }; + 96370FB519ED8A8200DAF8F1 /* blake2s.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = blake2s.hpp; sourceTree = ""; }; + 96370FB619ED8A8200DAF8F1 /* blake2sp.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = blake2sp.cpp; sourceTree = ""; }; + 96370FBB19ED8AAC00DAF8F1 /* crypt1.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = crypt1.cpp; sourceTree = ""; }; + 96370FBC19ED8AAC00DAF8F1 /* crypt2.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = crypt2.cpp; sourceTree = ""; }; + 96370FBD19ED8AAC00DAF8F1 /* crypt3.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = crypt3.cpp; sourceTree = ""; }; + 96370FBE19ED8AAC00DAF8F1 /* crypt5.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = crypt5.cpp; sourceTree = ""; }; + 96370FC319ED8ACF00DAF8F1 /* hardlinks.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = hardlinks.cpp; sourceTree = ""; }; + 96370FC419ED8B0400DAF8F1 /* hash.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = hash.cpp; sourceTree = ""; }; + 96370FC519ED8B0400DAF8F1 /* hash.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = hash.hpp; sourceTree = ""; }; + 96370FC619ED8B1F00DAF8F1 /* headers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = headers.cpp; sourceTree = ""; }; + 96370FC819ED8B2B00DAF8F1 /* headers5.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = headers5.hpp; sourceTree = ""; }; + 96370FC919ED8B4E00DAF8F1 /* qopen.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = qopen.cpp; sourceTree = ""; }; + 96370FCA19ED8B4E00DAF8F1 /* qopen.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = qopen.hpp; sourceTree = ""; }; + 96370FCB19ED8B7900DAF8F1 /* recvol3.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = recvol3.cpp; sourceTree = ""; }; + 96370FCC19ED8B7900DAF8F1 /* recvol5.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = recvol5.cpp; sourceTree = ""; }; + 96370FCD19ED8B9700DAF8F1 /* rs16.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = rs16.cpp; sourceTree = ""; }; + 96370FCE19ED8B9700DAF8F1 /* rs16.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = rs16.hpp; sourceTree = ""; }; + 96370FCF19ED8BB200DAF8F1 /* sha256.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = sha256.cpp; sourceTree = ""; }; + 96370FD019ED8BB200DAF8F1 /* sha256.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = sha256.hpp; sourceTree = ""; }; + 96370FD119ED8BC800DAF8F1 /* threadmisc.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = threadmisc.cpp; sourceTree = ""; }; + 96370FD219ED8C6100DAF8F1 /* threadpool.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = threadpool.cpp; sourceTree = ""; }; + 96370FD319ED8C6100DAF8F1 /* threadpool.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = threadpool.hpp; sourceTree = ""; }; + 96370FD419ED8C8000DAF8F1 /* ui.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ui.cpp; sourceTree = ""; }; + 96370FD519ED8C8000DAF8F1 /* ui.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ui.hpp; sourceTree = ""; }; + 96370FD619ED8C8000DAF8F1 /* uicommon.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = uicommon.cpp; sourceTree = ""; }; + 96370FD719ED8C8000DAF8F1 /* uiconsole.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = uiconsole.cpp; sourceTree = ""; }; + 96370FD819ED8C8000DAF8F1 /* uisilent.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = uisilent.cpp; sourceTree = ""; }; + 96370FD919ED8CAE00DAF8F1 /* unpack30.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = unpack30.cpp; sourceTree = ""; }; + 96370FDA19ED8CAE00DAF8F1 /* unpack50.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = unpack50.cpp; sourceTree = ""; }; + 96370FDB19ED8CAE00DAF8F1 /* unpack50frag.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = unpack50frag.cpp; sourceTree = ""; }; + 96370FDC19ED8CAE00DAF8F1 /* unpack50mt.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = unpack50mt.cpp; sourceTree = ""; }; + 96370FDD19ED8CAE00DAF8F1 /* unpackinline.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = unpackinline.cpp; sourceTree = ""; }; + 96370FDE19ED8CBF00DAF8F1 /* win32lnk.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = win32lnk.cpp; sourceTree = ""; }; + 964547D01B384F7D00202B28 /* URKArchiveTestCase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = URKArchiveTestCase.h; sourceTree = ""; }; + 964547D11B384F7D00202B28 /* URKArchiveTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = URKArchiveTestCase.m; sourceTree = ""; }; + 964C8ABB18D28EE000AD7321 /* UnrarKit Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "UnrarKit Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; + 964C8AC418D28EE000AD7321 /* UnrarKit Tests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "UnrarKit Tests-Info.plist"; sourceTree = ""; }; + 964C8AC618D28EE000AD7321 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; + 964C8AC818D28EE000AD7321 /* URKArchiveTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = URKArchiveTests.m; sourceTree = ""; }; + 964C8AD018D28F1600AD7321 /* Test Data */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "Test Data"; sourceTree = ""; }; + 9660D7AE1A3F4FF90059AC1E /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; + 967872731E460FA70048A54C /* ListVolumesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ListVolumesTests.m; sourceTree = ""; }; + 96853ED418DB707000B5651B /* UnrarKit-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = "UnrarKit-Info.plist"; path = "../Resources/UnrarKit-Info.plist"; sourceTree = ""; }; + 96853F0718DB722E00B5651B /* arccmt.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = arccmt.cpp; sourceTree = ""; }; + 96853F0818DB722E00B5651B /* archive.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = archive.cpp; sourceTree = ""; }; + 96853F0918DB722E00B5651B /* archive.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = archive.hpp; sourceTree = ""; }; + 96853F0A18DB722E00B5651B /* arcread.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = arcread.cpp; sourceTree = ""; }; + 96853F0B18DB722E00B5651B /* array.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = array.hpp; sourceTree = ""; }; + 96853F0D18DB722E00B5651B /* cmddata.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = cmddata.cpp; sourceTree = ""; }; + 96853F0E18DB722E00B5651B /* cmddata.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = cmddata.hpp; sourceTree = ""; }; + 96853F0F18DB722E00B5651B /* coder.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = coder.cpp; sourceTree = ""; }; + 96853F1018DB722E00B5651B /* coder.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = coder.hpp; sourceTree = ""; }; + 96853F1118DB722E00B5651B /* compress.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = compress.hpp; sourceTree = ""; }; + 96853F1218DB722E00B5651B /* consio.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = consio.cpp; sourceTree = ""; }; + 96853F1318DB722E00B5651B /* consio.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = consio.hpp; sourceTree = ""; }; + 96853F1418DB722E00B5651B /* crc.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = crc.cpp; sourceTree = ""; }; + 96853F1518DB722E00B5651B /* crc.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = crc.hpp; sourceTree = ""; }; + 96853F1618DB722E00B5651B /* crypt.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = crypt.cpp; sourceTree = ""; }; + 96853F1718DB722E00B5651B /* crypt.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = crypt.hpp; sourceTree = ""; }; + 96853F1818DB722E00B5651B /* dll.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = dll.cpp; sourceTree = ""; }; + 96853F1918DB722E00B5651B /* dll.def */ = {isa = PBXFileReference; lastKnownFileType = text; path = dll.def; sourceTree = ""; }; + 96853F1A18DB722E00B5651B /* dll.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = dll.hpp; sourceTree = ""; }; + 96853F1B18DB722E00B5651B /* dll.rc */ = {isa = PBXFileReference; lastKnownFileType = text; path = dll.rc; sourceTree = ""; }; + 96853F1C18DB722E00B5651B /* encname.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = encname.cpp; sourceTree = ""; }; + 96853F1D18DB722E00B5651B /* encname.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = encname.hpp; sourceTree = ""; }; + 96853F1E18DB722E00B5651B /* errhnd.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = errhnd.cpp; sourceTree = ""; }; + 96853F1F18DB722E00B5651B /* errhnd.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = errhnd.hpp; sourceTree = ""; }; + 96853F2018DB722E00B5651B /* extinfo.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = extinfo.cpp; sourceTree = ""; }; + 96853F2118DB722E00B5651B /* extinfo.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = extinfo.hpp; sourceTree = ""; }; + 96853F2218DB722E00B5651B /* extract.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = extract.cpp; sourceTree = ""; }; + 96853F2318DB722E00B5651B /* extract.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = extract.hpp; sourceTree = ""; }; + 96853F2418DB722E00B5651B /* filcreat.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = filcreat.cpp; sourceTree = ""; }; + 96853F2518DB722E00B5651B /* filcreat.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = filcreat.hpp; sourceTree = ""; }; + 96853F2618DB722E00B5651B /* file.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = file.cpp; sourceTree = ""; }; + 96853F2718DB722E00B5651B /* file.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = file.hpp; sourceTree = ""; }; + 96853F2818DB722E00B5651B /* filefn.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = filefn.cpp; sourceTree = ""; }; + 96853F2918DB722E00B5651B /* filefn.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = filefn.hpp; sourceTree = ""; }; + 96853F2A18DB722E00B5651B /* filestr.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = filestr.cpp; sourceTree = ""; }; + 96853F2B18DB722E00B5651B /* filestr.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = filestr.hpp; sourceTree = ""; }; + 96853F2C18DB722E00B5651B /* find.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = find.cpp; sourceTree = ""; }; + 96853F2D18DB722E00B5651B /* find.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = find.hpp; sourceTree = ""; }; + 96853F2E18DB722E00B5651B /* getbits.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = getbits.cpp; sourceTree = ""; }; + 96853F2F18DB722E00B5651B /* getbits.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = getbits.hpp; sourceTree = ""; }; + 96853F3018DB722E00B5651B /* global.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = global.cpp; sourceTree = ""; }; + 96853F3118DB722E00B5651B /* global.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = global.hpp; sourceTree = ""; }; + 96853F3218DB722E00B5651B /* headers.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = headers.hpp; sourceTree = ""; }; + 96853F3318DB722E00B5651B /* isnt.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = isnt.cpp; sourceTree = ""; }; + 96853F3418DB722E00B5651B /* isnt.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = isnt.hpp; sourceTree = ""; }; + 96853F3618DB722E00B5651B /* list.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = list.cpp; sourceTree = ""; }; + 96853F3718DB722E00B5651B /* list.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = list.hpp; sourceTree = ""; }; + 96853F3818DB722E00B5651B /* loclang.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = loclang.hpp; sourceTree = ""; }; + 96853F3918DB722E00B5651B /* log.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = log.cpp; sourceTree = ""; }; + 96853F3A18DB722E00B5651B /* log.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = log.hpp; sourceTree = ""; }; + 96853F3F18DB722E00B5651B /* match.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = match.cpp; sourceTree = ""; }; + 96853F4018DB722E00B5651B /* match.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = match.hpp; sourceTree = ""; }; + 96853F4118DB722E00B5651B /* model.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = model.cpp; sourceTree = ""; }; + 96853F4218DB722E00B5651B /* model.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = model.hpp; sourceTree = ""; }; + 96853F4418DB722E00B5651B /* options.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = options.cpp; sourceTree = ""; }; + 96853F4518DB722E00B5651B /* options.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = options.hpp; sourceTree = ""; }; + 96853F4618DB722E00B5651B /* os.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = os.hpp; sourceTree = ""; }; + 96853F4818DB722E00B5651B /* pathfn.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = pathfn.cpp; sourceTree = ""; }; + 96853F4918DB722E00B5651B /* pathfn.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = pathfn.hpp; sourceTree = ""; }; + 96853F4A18DB722E00B5651B /* rar.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = rar.cpp; sourceTree = ""; }; + 96853F4B18DB722E00B5651B /* rar.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = rar.hpp; sourceTree = ""; }; + 96853F4C18DB722E00B5651B /* rardefs.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = rardefs.hpp; sourceTree = ""; }; + 96853F4D18DB722E00B5651B /* rarlang.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = rarlang.hpp; sourceTree = ""; }; + 96853F4E18DB722E00B5651B /* raros.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = raros.hpp; sourceTree = ""; }; + 96853F4F18DB722E00B5651B /* rarpch.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = rarpch.cpp; sourceTree = ""; }; + 96853F5018DB722E00B5651B /* rartypes.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = rartypes.hpp; sourceTree = ""; }; + 96853F5118DB722E00B5651B /* rarvm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = rarvm.cpp; sourceTree = ""; }; + 96853F5218DB722E00B5651B /* rarvm.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = rarvm.hpp; sourceTree = ""; }; + 96853F5418DB722E00B5651B /* rawread.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = rawread.cpp; sourceTree = ""; }; + 96853F5518DB722E00B5651B /* rawread.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = rawread.hpp; sourceTree = ""; }; + 96853F5618DB722E00B5651B /* rdwrfn.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = rdwrfn.cpp; sourceTree = ""; }; + 96853F5718DB722E00B5651B /* rdwrfn.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = rdwrfn.hpp; sourceTree = ""; }; + 96853F5918DB722E00B5651B /* recvol.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = recvol.cpp; sourceTree = ""; }; + 96853F5A18DB722E00B5651B /* recvol.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = recvol.hpp; sourceTree = ""; }; + 96853F5B18DB722E00B5651B /* resource.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = resource.cpp; sourceTree = ""; }; + 96853F5C18DB722E00B5651B /* resource.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = resource.hpp; sourceTree = ""; }; + 96853F5D18DB722E00B5651B /* rijndael.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = rijndael.cpp; sourceTree = ""; }; + 96853F5E18DB722E00B5651B /* rijndael.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = rijndael.hpp; sourceTree = ""; }; + 96853F5F18DB722E00B5651B /* rs.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = rs.cpp; sourceTree = ""; }; + 96853F6018DB722E00B5651B /* rs.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = rs.hpp; sourceTree = ""; }; + 96853F6218DB722E00B5651B /* savepos.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = savepos.hpp; sourceTree = ""; }; + 96853F6318DB722E00B5651B /* scantree.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = scantree.cpp; sourceTree = ""; }; + 96853F6418DB722E00B5651B /* scantree.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = scantree.hpp; sourceTree = ""; }; + 96853F6518DB722E00B5651B /* secpassword.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = secpassword.cpp; sourceTree = ""; }; + 96853F6618DB722E00B5651B /* secpassword.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = secpassword.hpp; sourceTree = ""; }; + 96853F6718DB722E00B5651B /* sha1.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = sha1.cpp; sourceTree = ""; }; + 96853F6818DB722E00B5651B /* sha1.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = sha1.hpp; sourceTree = ""; }; + 96853F6918DB722E00B5651B /* smallfn.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = smallfn.cpp; sourceTree = ""; }; + 96853F6A18DB722E00B5651B /* smallfn.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = smallfn.hpp; sourceTree = ""; }; + 96853F6B18DB722E00B5651B /* strfn.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = strfn.cpp; sourceTree = ""; }; + 96853F6C18DB722E00B5651B /* strfn.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = strfn.hpp; sourceTree = ""; }; + 96853F6D18DB722E00B5651B /* strlist.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = strlist.cpp; sourceTree = ""; }; + 96853F6E18DB722E00B5651B /* strlist.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = strlist.hpp; sourceTree = ""; }; + 96853F6F18DB722E00B5651B /* suballoc.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = suballoc.cpp; sourceTree = ""; }; + 96853F7018DB722E00B5651B /* suballoc.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = suballoc.hpp; sourceTree = ""; }; + 96853F7118DB722E00B5651B /* system.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = system.cpp; sourceTree = ""; }; + 96853F7218DB722E00B5651B /* system.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = system.hpp; sourceTree = ""; }; + 96853F7318DB722E00B5651B /* timefn.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = timefn.cpp; sourceTree = ""; }; + 96853F7418DB722E00B5651B /* timefn.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = timefn.hpp; sourceTree = ""; }; + 96853F7518DB722E00B5651B /* ulinks.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ulinks.cpp; sourceTree = ""; }; + 96853F7718DB722E00B5651B /* unicode.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = unicode.cpp; sourceTree = ""; }; + 96853F7818DB722E00B5651B /* unicode.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = unicode.hpp; sourceTree = ""; }; + 96853F7A18DB722E00B5651B /* unpack.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = unpack.cpp; sourceTree = ""; }; + 96853F7B18DB722E00B5651B /* unpack.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = unpack.hpp; sourceTree = ""; }; + 96853F7C18DB722E00B5651B /* unpack15.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = unpack15.cpp; sourceTree = ""; }; + 96853F7D18DB722E00B5651B /* unpack20.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = unpack20.cpp; sourceTree = ""; }; + 96853F8018DB722F00B5651B /* uowners.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = uowners.cpp; sourceTree = ""; }; + 96853F8118DB722F00B5651B /* version.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = version.hpp; sourceTree = ""; }; + 96853F8218DB722F00B5651B /* volume.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = volume.cpp; sourceTree = ""; }; + 96853F8318DB722F00B5651B /* volume.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = volume.hpp; sourceTree = ""; }; + 96853F8418DB722F00B5651B /* win32acl.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = win32acl.cpp; sourceTree = ""; }; + 96853F8518DB722F00B5651B /* win32stm.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = win32stm.cpp; sourceTree = ""; }; + 969F17361A60297700665453 /* UnrarKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UnrarKit.h; sourceTree = ""; }; + 96A043DD1E4CC8D500BD7013 /* FirstVolumeTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FirstVolumeTests.m; sourceTree = ""; }; + 96A043DF1E4D232F00BD7013 /* HasMultipleVolumesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HasMultipleVolumesTests.m; sourceTree = ""; }; + 96BF58BA1F3A487100BC24E1 /* UnrarKitMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnrarKitMacros.h; sourceTree = ""; }; + 96DBF7F71A3F72800033B759 /* NSString+UnrarKit.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "NSString+UnrarKit.h"; path = "Categories/NSString+UnrarKit.h"; sourceTree = ""; }; + 96DBF7F81A3F72800033B759 /* NSString+UnrarKit.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = "NSString+UnrarKit.mm"; path = "Categories/NSString+UnrarKit.mm"; sourceTree = ""; }; + 96EA535B1B3CB04300F79DC6 /* UnrarKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = UnrarKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 96F450741B38527100679597 /* ValidatePasswordTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ValidatePasswordTests.m; sourceTree = ""; }; + 96F450761B38552200679597 /* IsPasswordProtectedTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IsPasswordProtectedTests.m; sourceTree = ""; }; + 96F450781B385AF800679597 /* ListFilenamesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ListFilenamesTests.m; sourceTree = ""; }; + 96F4507A1B385BCD00679597 /* ExtractFilesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExtractFilesTests.m; sourceTree = ""; }; + F3FCD4691A3262E5003612BF /* URKFileInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = URKFileInfo.h; sourceTree = ""; }; + F3FCD46A1A3262E5003612BF /* URKFileInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = URKFileInfo.m; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 7A22B1E71F60A05F004B8050 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7AC29A5A1F83C08200DA4DE6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 964C8AB818D28EE000AD7321 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9660D7AF1A3F4FF90059AC1E /* libz.dylib in Frameworks */, + 9699FA6A1B3CE95D00B6D373 /* UnrarKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 96EA53571B3CB04300F79DC6 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 7AC29ACB1F83C3E700DA4DE6 /* libunrar.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 034768DFFF38A50411DB9C8B /* Products */ = { + isa = PBXGroup; + children = ( + 96EA535B1B3CB04300F79DC6 /* UnrarKit.framework */, + 964C8ABB18D28EE000AD7321 /* UnrarKit Tests.xctest */, + 7A22B1EA1F60A05F004B8050 /* UnrarKitResources.bundle */, + 7AC29A5D1F83C08200DA4DE6 /* libunrar.a */, + ); + name = Products; + sourceTree = ""; + }; + 0867D691FE84028FC02AAC07 /* UnrarKit */ = { + isa = PBXGroup; + children = ( + 08FB77AEFE84172EC02AAC07 /* Classes */, + 964C8AC218D28EE000AD7321 /* Tests */, + 7A22B1EB1F60A05F004B8050 /* UnrarKitResources */, + 0867D69AFE84028FC02AAC07 /* Frameworks */, + 034768DFFF38A50411DB9C8B /* Products */, + 96853F0418DB722E00B5651B /* Libraries */, + ); + name = UnrarKit; + sourceTree = ""; + }; + 0867D69AFE84028FC02AAC07 /* Frameworks */ = { + isa = PBXGroup; + children = ( + 9660D7AE1A3F4FF90059AC1E /* libz.dylib */, + ); + name = Frameworks; + sourceTree = ""; + }; + 08FB77AEFE84172EC02AAC07 /* Classes */ = { + isa = PBXGroup; + children = ( + 96DBF7F61A3F72370033B759 /* Categories */, + 969F17361A60297700665453 /* UnrarKit.h */, + 489CFA0E128B5169005DCC2A /* URKArchive.h */, + 489CFA0F128B5169005DCC2A /* URKArchive.mm */, + F3FCD4691A3262E5003612BF /* URKFileInfo.h */, + F3FCD46A1A3262E5003612BF /* URKFileInfo.m */, + 96BF58BA1F3A487100BC24E1 /* UnrarKitMacros.h */, + 7A0668EC1FBBAA3100437F5F /* Supporting Files */, + ); + path = Classes; + sourceTree = SOURCE_ROOT; + }; + 7A0668EC1FBBAA3100437F5F /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 96853ED418DB707000B5651B /* UnrarKit-Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 7A22B1EB1F60A05F004B8050 /* UnrarKitResources */ = { + isa = PBXGroup; + children = ( + 7A22B1FA1F60A2D3004B8050 /* UnrarKit.strings */, + 7A0668ED1FBBAABB00437F5F /* UnrarKitResources-Info.plist */, + ); + name = UnrarKitResources; + path = Resources; + sourceTree = ""; + }; + 964C8AC218D28EE000AD7321 /* Tests */ = { + isa = PBXGroup; + children = ( + 964C8AD018D28F1600AD7321 /* Test Data */, + 964547D01B384F7D00202B28 /* URKArchiveTestCase.h */, + 964547D11B384F7D00202B28 /* URKArchiveTestCase.m */, + 964C8AC818D28EE000AD7321 /* URKArchiveTests.m */, + 7ADC7A081F8831BC00023C2E /* CheckDataTests.m */, + 96F4507A1B385BCD00679597 /* ExtractFilesTests.m */, + 96A043DD1E4CC8D500BD7013 /* FirstVolumeTests.m */, + 96A043DF1E4D232F00BD7013 /* HasMultipleVolumesTests.m */, + 96F450761B38552200679597 /* IsPasswordProtectedTests.m */, + 7A66082A20B4BE2000FE68D6 /* IterateFileInfoTests.m */, + 96F450781B385AF800679597 /* ListFilenamesTests.m */, + 967872731E460FA70048A54C /* ListVolumesTests.m */, + 7A267F6D1F713B970004EAA6 /* ProgressReportingTests.m */, + 96F450741B38527100679597 /* ValidatePasswordTests.m */, + 964C8AC318D28EE000AD7321 /* Supporting Files */, + ); + path = Tests; + sourceTree = SOURCE_ROOT; + }; + 964C8AC318D28EE000AD7321 /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 964C8AC418D28EE000AD7321 /* UnrarKit Tests-Info.plist */, + 964C8AC518D28EE000AD7321 /* InfoPlist.strings */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 96853F0418DB722E00B5651B /* Libraries */ = { + isa = PBXGroup; + children = ( + 96853F0518DB722E00B5651B /* unrar */, + ); + path = Libraries; + sourceTree = SOURCE_ROOT; + }; + 96853F0518DB722E00B5651B /* unrar */ = { + isa = PBXGroup; + children = ( + 96853F0718DB722E00B5651B /* arccmt.cpp */, + 96853F0818DB722E00B5651B /* archive.cpp */, + 96853F0918DB722E00B5651B /* archive.hpp */, + 96853F0A18DB722E00B5651B /* arcread.cpp */, + 96853F0B18DB722E00B5651B /* array.hpp */, + 96370FB319ED8A8200DAF8F1 /* blake2s_sse.cpp */, + 96370FB419ED8A8200DAF8F1 /* blake2s.cpp */, + 96370FB519ED8A8200DAF8F1 /* blake2s.hpp */, + 96370FB619ED8A8200DAF8F1 /* blake2sp.cpp */, + 96853F0D18DB722E00B5651B /* cmddata.cpp */, + 96853F0E18DB722E00B5651B /* cmddata.hpp */, + 96853F0F18DB722E00B5651B /* coder.cpp */, + 96853F1018DB722E00B5651B /* coder.hpp */, + 96853F1118DB722E00B5651B /* compress.hpp */, + 96853F1218DB722E00B5651B /* consio.cpp */, + 96853F1318DB722E00B5651B /* consio.hpp */, + 96853F1418DB722E00B5651B /* crc.cpp */, + 96853F1518DB722E00B5651B /* crc.hpp */, + 96853F1618DB722E00B5651B /* crypt.cpp */, + 96853F1718DB722E00B5651B /* crypt.hpp */, + 96370FBB19ED8AAC00DAF8F1 /* crypt1.cpp */, + 96370FBC19ED8AAC00DAF8F1 /* crypt2.cpp */, + 96370FBD19ED8AAC00DAF8F1 /* crypt3.cpp */, + 96370FBE19ED8AAC00DAF8F1 /* crypt5.cpp */, + 96853F1818DB722E00B5651B /* dll.cpp */, + 96853F1918DB722E00B5651B /* dll.def */, + 96853F1A18DB722E00B5651B /* dll.hpp */, + 96853F1B18DB722E00B5651B /* dll.rc */, + 96853F1C18DB722E00B5651B /* encname.cpp */, + 96853F1D18DB722E00B5651B /* encname.hpp */, + 96853F1E18DB722E00B5651B /* errhnd.cpp */, + 96853F1F18DB722E00B5651B /* errhnd.hpp */, + 96853F2018DB722E00B5651B /* extinfo.cpp */, + 96853F2118DB722E00B5651B /* extinfo.hpp */, + 96853F2218DB722E00B5651B /* extract.cpp */, + 96853F2318DB722E00B5651B /* extract.hpp */, + 96853F2418DB722E00B5651B /* filcreat.cpp */, + 96853F2518DB722E00B5651B /* filcreat.hpp */, + 96853F2618DB722E00B5651B /* file.cpp */, + 96853F2718DB722E00B5651B /* file.hpp */, + 96853F2818DB722E00B5651B /* filefn.cpp */, + 96853F2918DB722E00B5651B /* filefn.hpp */, + 96853F2A18DB722E00B5651B /* filestr.cpp */, + 96853F2B18DB722E00B5651B /* filestr.hpp */, + 96853F2C18DB722E00B5651B /* find.cpp */, + 96853F2D18DB722E00B5651B /* find.hpp */, + 96853F2E18DB722E00B5651B /* getbits.cpp */, + 96853F2F18DB722E00B5651B /* getbits.hpp */, + 96853F3018DB722E00B5651B /* global.cpp */, + 96853F3118DB722E00B5651B /* global.hpp */, + 96370FC319ED8ACF00DAF8F1 /* hardlinks.cpp */, + 96370FC419ED8B0400DAF8F1 /* hash.cpp */, + 96370FC519ED8B0400DAF8F1 /* hash.hpp */, + 96370FC619ED8B1F00DAF8F1 /* headers.cpp */, + 96853F3218DB722E00B5651B /* headers.hpp */, + 96370FC819ED8B2B00DAF8F1 /* headers5.hpp */, + 96853F3318DB722E00B5651B /* isnt.cpp */, + 96853F3418DB722E00B5651B /* isnt.hpp */, + 96853F3618DB722E00B5651B /* list.cpp */, + 96853F3718DB722E00B5651B /* list.hpp */, + 96853F3818DB722E00B5651B /* loclang.hpp */, + 96853F3918DB722E00B5651B /* log.cpp */, + 96853F3A18DB722E00B5651B /* log.hpp */, + 96853F3F18DB722E00B5651B /* match.cpp */, + 96853F4018DB722E00B5651B /* match.hpp */, + 96853F4118DB722E00B5651B /* model.cpp */, + 96853F4218DB722E00B5651B /* model.hpp */, + 96853F4418DB722E00B5651B /* options.cpp */, + 96853F4518DB722E00B5651B /* options.hpp */, + 96853F4618DB722E00B5651B /* os.hpp */, + 96853F4818DB722E00B5651B /* pathfn.cpp */, + 96853F4918DB722E00B5651B /* pathfn.hpp */, + 96370FC919ED8B4E00DAF8F1 /* qopen.cpp */, + 96370FCA19ED8B4E00DAF8F1 /* qopen.hpp */, + 96853F4A18DB722E00B5651B /* rar.cpp */, + 96853F4B18DB722E00B5651B /* rar.hpp */, + 96853F4C18DB722E00B5651B /* rardefs.hpp */, + 96853F4D18DB722E00B5651B /* rarlang.hpp */, + 96853F4E18DB722E00B5651B /* raros.hpp */, + 96853F4F18DB722E00B5651B /* rarpch.cpp */, + 96853F5018DB722E00B5651B /* rartypes.hpp */, + 96853F5118DB722E00B5651B /* rarvm.cpp */, + 96853F5218DB722E00B5651B /* rarvm.hpp */, + 96853F5418DB722E00B5651B /* rawread.cpp */, + 96853F5518DB722E00B5651B /* rawread.hpp */, + 96853F5618DB722E00B5651B /* rdwrfn.cpp */, + 96853F5718DB722E00B5651B /* rdwrfn.hpp */, + 96853F5918DB722E00B5651B /* recvol.cpp */, + 96853F5A18DB722E00B5651B /* recvol.hpp */, + 96370FCB19ED8B7900DAF8F1 /* recvol3.cpp */, + 96370FCC19ED8B7900DAF8F1 /* recvol5.cpp */, + 96853F5B18DB722E00B5651B /* resource.cpp */, + 96853F5C18DB722E00B5651B /* resource.hpp */, + 96853F5D18DB722E00B5651B /* rijndael.cpp */, + 96853F5E18DB722E00B5651B /* rijndael.hpp */, + 96853F5F18DB722E00B5651B /* rs.cpp */, + 96853F6018DB722E00B5651B /* rs.hpp */, + 96370FCD19ED8B9700DAF8F1 /* rs16.cpp */, + 96370FCE19ED8B9700DAF8F1 /* rs16.hpp */, + 96853F6218DB722E00B5651B /* savepos.hpp */, + 96853F6318DB722E00B5651B /* scantree.cpp */, + 96853F6418DB722E00B5651B /* scantree.hpp */, + 96853F6518DB722E00B5651B /* secpassword.cpp */, + 96853F6618DB722E00B5651B /* secpassword.hpp */, + 96853F6718DB722E00B5651B /* sha1.cpp */, + 96853F6818DB722E00B5651B /* sha1.hpp */, + 96370FCF19ED8BB200DAF8F1 /* sha256.cpp */, + 96370FD019ED8BB200DAF8F1 /* sha256.hpp */, + 96853F6918DB722E00B5651B /* smallfn.cpp */, + 96853F6A18DB722E00B5651B /* smallfn.hpp */, + 96853F6B18DB722E00B5651B /* strfn.cpp */, + 96853F6C18DB722E00B5651B /* strfn.hpp */, + 96853F6D18DB722E00B5651B /* strlist.cpp */, + 96853F6E18DB722E00B5651B /* strlist.hpp */, + 96853F6F18DB722E00B5651B /* suballoc.cpp */, + 96853F7018DB722E00B5651B /* suballoc.hpp */, + 96853F7118DB722E00B5651B /* system.cpp */, + 96853F7218DB722E00B5651B /* system.hpp */, + 96370FD119ED8BC800DAF8F1 /* threadmisc.cpp */, + 96370FD219ED8C6100DAF8F1 /* threadpool.cpp */, + 96370FD319ED8C6100DAF8F1 /* threadpool.hpp */, + 96853F7318DB722E00B5651B /* timefn.cpp */, + 96853F7418DB722E00B5651B /* timefn.hpp */, + 96370FD419ED8C8000DAF8F1 /* ui.cpp */, + 96370FD519ED8C8000DAF8F1 /* ui.hpp */, + 96370FD619ED8C8000DAF8F1 /* uicommon.cpp */, + 96370FD719ED8C8000DAF8F1 /* uiconsole.cpp */, + 96370FD819ED8C8000DAF8F1 /* uisilent.cpp */, + 96853F7518DB722E00B5651B /* ulinks.cpp */, + 96853F7718DB722E00B5651B /* unicode.cpp */, + 96853F7818DB722E00B5651B /* unicode.hpp */, + 96853F7A18DB722E00B5651B /* unpack.cpp */, + 96853F7B18DB722E00B5651B /* unpack.hpp */, + 96853F7C18DB722E00B5651B /* unpack15.cpp */, + 96853F7D18DB722E00B5651B /* unpack20.cpp */, + 96370FD919ED8CAE00DAF8F1 /* unpack30.cpp */, + 96370FDA19ED8CAE00DAF8F1 /* unpack50.cpp */, + 96370FDB19ED8CAE00DAF8F1 /* unpack50frag.cpp */, + 96370FDC19ED8CAE00DAF8F1 /* unpack50mt.cpp */, + 96370FDD19ED8CAE00DAF8F1 /* unpackinline.cpp */, + 96853F8018DB722F00B5651B /* uowners.cpp */, + 96853F8118DB722F00B5651B /* version.hpp */, + 96853F8218DB722F00B5651B /* volume.cpp */, + 96853F8318DB722F00B5651B /* volume.hpp */, + 96853F8418DB722F00B5651B /* win32acl.cpp */, + 96370FDE19ED8CBF00DAF8F1 /* win32lnk.cpp */, + 96853F8518DB722F00B5651B /* win32stm.cpp */, + ); + path = unrar; + sourceTree = ""; + }; + 96DBF7F61A3F72370033B759 /* Categories */ = { + isa = PBXGroup; + children = ( + 96DBF7F71A3F72800033B759 /* NSString+UnrarKit.h */, + 96DBF7F81A3F72800033B759 /* NSString+UnrarKit.mm */, + ); + name = Categories; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 7AC29A5B1F83C08200DA4DE6 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 7AC29A931F83C2A200DA4DE6 /* dll.hpp in Headers */, + 7AC29A941F83C2A200DA4DE6 /* raros.hpp in Headers */, + 7AC29A951F83C36900DA4DE6 /* archive.hpp in Headers */, + 7AC29A961F83C36900DA4DE6 /* array.hpp in Headers */, + 7AC29A971F83C36900DA4DE6 /* cmddata.hpp in Headers */, + 7AC29A981F83C36900DA4DE6 /* coder.hpp in Headers */, + 7AC29A991F83C36900DA4DE6 /* compress.hpp in Headers */, + 7AC29A9A1F83C36900DA4DE6 /* consio.hpp in Headers */, + 7AC29A9B1F83C36900DA4DE6 /* crc.hpp in Headers */, + 7AC29A9C1F83C36900DA4DE6 /* crypt.hpp in Headers */, + 7AC29A9D1F83C36900DA4DE6 /* encname.hpp in Headers */, + 7AC29A9E1F83C36900DA4DE6 /* errhnd.hpp in Headers */, + 7AC29A9F1F83C36900DA4DE6 /* extinfo.hpp in Headers */, + 7AC29AA01F83C36900DA4DE6 /* extract.hpp in Headers */, + 7AC29AA11F83C36900DA4DE6 /* filcreat.hpp in Headers */, + 7AC29AA21F83C36900DA4DE6 /* file.hpp in Headers */, + 7AC29AA31F83C36900DA4DE6 /* filefn.hpp in Headers */, + 7AC29AA41F83C36900DA4DE6 /* filestr.hpp in Headers */, + 7AC29AA51F83C36900DA4DE6 /* find.hpp in Headers */, + 7AC29AA61F83C36900DA4DE6 /* getbits.hpp in Headers */, + 7AC29AA71F83C36900DA4DE6 /* global.hpp in Headers */, + 7AC29AA81F83C36900DA4DE6 /* headers.hpp in Headers */, + 7AC29AA91F83C36900DA4DE6 /* isnt.hpp in Headers */, + 7AC29AAA1F83C36900DA4DE6 /* list.hpp in Headers */, + 7AC29AAB1F83C36900DA4DE6 /* loclang.hpp in Headers */, + 7AC29AAC1F83C36900DA4DE6 /* log.hpp in Headers */, + 7AC29AAD1F83C36900DA4DE6 /* match.hpp in Headers */, + 7AC29AAE1F83C36900DA4DE6 /* model.hpp in Headers */, + 7AC29AAF1F83C36900DA4DE6 /* options.hpp in Headers */, + 7AC29AB01F83C36900DA4DE6 /* os.hpp in Headers */, + 7AC29AB11F83C36900DA4DE6 /* pathfn.hpp in Headers */, + 7AC29AB21F83C36900DA4DE6 /* rar.hpp in Headers */, + 7AC29AB31F83C36900DA4DE6 /* rardefs.hpp in Headers */, + 7AC29AB41F83C36900DA4DE6 /* rarlang.hpp in Headers */, + 7AC29AB51F83C36900DA4DE6 /* rartypes.hpp in Headers */, + 7AC29AB61F83C36900DA4DE6 /* rarvm.hpp in Headers */, + 7AC29AB71F83C36900DA4DE6 /* rawread.hpp in Headers */, + 7AC29AB81F83C36900DA4DE6 /* rdwrfn.hpp in Headers */, + 7AC29AB91F83C36900DA4DE6 /* recvol.hpp in Headers */, + 7AC29ABA1F83C36900DA4DE6 /* resource.hpp in Headers */, + 7AC29ABB1F83C36900DA4DE6 /* rijndael.hpp in Headers */, + 7AC29ABC1F83C36900DA4DE6 /* rs.hpp in Headers */, + 7AC29ABD1F83C36900DA4DE6 /* savepos.hpp in Headers */, + 7AC29ABE1F83C36900DA4DE6 /* scantree.hpp in Headers */, + 7AC29ABF1F83C36900DA4DE6 /* secpassword.hpp in Headers */, + 7AC29AC01F83C36900DA4DE6 /* sha1.hpp in Headers */, + 7AC29AC11F83C36900DA4DE6 /* smallfn.hpp in Headers */, + 7AC29AC21F83C36900DA4DE6 /* strfn.hpp in Headers */, + 7AC29AC31F83C36900DA4DE6 /* strlist.hpp in Headers */, + 7AC29AC41F83C36900DA4DE6 /* suballoc.hpp in Headers */, + 7AC29AC51F83C36900DA4DE6 /* system.hpp in Headers */, + 7AC29AC61F83C36900DA4DE6 /* timefn.hpp in Headers */, + 7AC29AC71F83C36900DA4DE6 /* unicode.hpp in Headers */, + 7AC29AC81F83C36900DA4DE6 /* unpack.hpp in Headers */, + 7AC29AC91F83C36900DA4DE6 /* version.hpp in Headers */, + 7AC29ACA1F83C36900DA4DE6 /* volume.hpp in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 96EA53581B3CB04300F79DC6 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 9699F91D1B3CB4D000B6D373 /* URKArchive.h in Headers */, + 9699F91E1B3CB4D000B6D373 /* URKFileInfo.h in Headers */, + 9699F91F1B3CB4D000B6D373 /* UnrarKit.h in Headers */, + 7AC29AD01F850A6A00DA4DE6 /* UnrarKitMacros.h in Headers */, + 7AC29ACD1F83DB0400DA4DE6 /* dll.hpp in Headers */, + 7AC29ACE1F83DB1000DA4DE6 /* raros.hpp in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 7A22B1E91F60A05F004B8050 /* UnrarKitResources */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7A22B1EF1F60A05F004B8050 /* Build configuration list for PBXNativeTarget "UnrarKitResources" */; + buildPhases = ( + 7A22B1E61F60A05F004B8050 /* Sources */, + 7A22B1E71F60A05F004B8050 /* Frameworks */, + 7A22B1E81F60A05F004B8050 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = UnrarKitResources; + productName = UnrarKitResources; + productReference = 7A22B1EA1F60A05F004B8050 /* UnrarKitResources.bundle */; + productType = "com.apple.product-type.bundle"; + }; + 7AC29A5C1F83C08200DA4DE6 /* unrar */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7AC29A601F83C08200DA4DE6 /* Build configuration list for PBXNativeTarget "unrar" */; + buildPhases = ( + 7AC29A591F83C08200DA4DE6 /* Sources */, + 7AC29A5A1F83C08200DA4DE6 /* Frameworks */, + 7AC29A5B1F83C08200DA4DE6 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = unrar; + productName = unrar; + productReference = 7AC29A5D1F83C08200DA4DE6 /* libunrar.a */; + productType = "com.apple.product-type.library.static"; + }; + 964C8ABA18D28EE000AD7321 /* UnrarKit Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 964C8ACF18D28EE000AD7321 /* Build configuration list for PBXNativeTarget "UnrarKit Tests" */; + buildPhases = ( + 964C8AB718D28EE000AD7321 /* Sources */, + 964C8AB818D28EE000AD7321 /* Frameworks */, + 964C8AB918D28EE000AD7321 /* Resources */, + 964C8AD118D28F2900AD7321 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "UnrarKit Tests"; + productName = "UnrarKit Tests"; + productReference = 964C8ABB18D28EE000AD7321 /* UnrarKit Tests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 96EA535A1B3CB04300F79DC6 /* UnrarKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = 96EA53721B3CB04300F79DC6 /* Build configuration list for PBXNativeTarget "UnrarKit" */; + buildPhases = ( + 96EA53561B3CB04300F79DC6 /* Sources */, + 96EA53571B3CB04300F79DC6 /* Frameworks */, + 96EA53581B3CB04300F79DC6 /* Headers */, + 96EA53591B3CB04300F79DC6 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 7ACC4CC91F7EF00F001A07F6 /* PBXTargetDependency */, + ); + name = UnrarKit; + productName = UnrarKit; + productReference = 96EA535B1B3CB04300F79DC6 /* UnrarKit.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0867D690FE84028FC02AAC07 /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0700; + LastUpgradeCheck = 0930; + TargetAttributes = { + 7A22B1E91F60A05F004B8050 = { + CreatedOnToolsVersion = 8.3.3; + ProvisioningStyle = Automatic; + }; + 7AC29A5C1F83C08200DA4DE6 = { + CreatedOnToolsVersion = 9.0; + ProvisioningStyle = Automatic; + }; + 964C8ABA18D28EE000AD7321 = { + LastSwiftMigration = 0820; + TestTargetID = 96853EDA18DB71CD00B5651B; + }; + 96EA535A1B3CB04300F79DC6 = { + CreatedOnToolsVersion = 6.3.2; + LastSwiftMigration = 0820; + }; + }; + }; + buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "UnrarKit" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + en, + Base, + ); + mainGroup = 0867D691FE84028FC02AAC07 /* UnrarKit */; + productRefGroup = 034768DFFF38A50411DB9C8B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 96EA535A1B3CB04300F79DC6 /* UnrarKit */, + 964C8ABA18D28EE000AD7321 /* UnrarKit Tests */, + 7A22B1E91F60A05F004B8050 /* UnrarKitResources */, + 7AC29A5C1F83C08200DA4DE6 /* unrar */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 7A22B1E81F60A05F004B8050 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 7A22B1F81F60A2D3004B8050 /* UnrarKit.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 964C8AB918D28EE000AD7321 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 964C8AC718D28EE000AD7321 /* InfoPlist.strings in Resources */, + 96E5D345198B333200A74340 /* Test Data in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 96EA53591B3CB04300F79DC6 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 7A22B1FB1F60A39E004B8050 /* UnrarKitResources.bundle in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 7A22B1E61F60A05F004B8050 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 7AC29A591F83C08200DA4DE6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 7AC29A611F83C0D600DA4DE6 /* rar.cpp in Sources */, + 7AC29A621F83C0DD00DA4DE6 /* strlist.cpp in Sources */, + 7AC29A631F83C0E200DA4DE6 /* strfn.cpp in Sources */, + 7AC29A641F83C0F000DA4DE6 /* pathfn.cpp in Sources */, + 7AC29A651F83C10200DA4DE6 /* smallfn.cpp in Sources */, + 7AC29A661F83C11400DA4DE6 /* global.cpp in Sources */, + 7AC29A671F83C12200DA4DE6 /* file.cpp in Sources */, + 7AC29A681F83C12D00DA4DE6 /* filefn.cpp in Sources */, + 7AC29A691F83C13600DA4DE6 /* filcreat.cpp in Sources */, + 7AC29A6A1F83C13D00DA4DE6 /* archive.cpp in Sources */, + 7AC29A6B1F83C14200DA4DE6 /* arcread.cpp in Sources */, + 7AC29A6C1F83C14D00DA4DE6 /* unicode.cpp in Sources */, + 7AC29A6D1F83C15400DA4DE6 /* system.cpp in Sources */, + 7AC29A6E1F83C16500DA4DE6 /* isnt.cpp in Sources */, + 7AC29A6F1F83C16D00DA4DE6 /* crypt.cpp in Sources */, + 7AC29A701F83C17300DA4DE6 /* crc.cpp in Sources */, + 7AC29A711F83C17900DA4DE6 /* rawread.cpp in Sources */, + 7AC29A731F83C1CD00DA4DE6 /* encname.cpp in Sources */, + 7AC29A7A1F83C1CD00DA4DE6 /* resource.cpp in Sources */, + 7AC29A761F83C1CD00DA4DE6 /* match.cpp in Sources */, + 7AC29A7D1F83C1CD00DA4DE6 /* timefn.cpp in Sources */, + 7AC29A791F83C1CD00DA4DE6 /* rdwrfn.cpp in Sources */, + 7AC29A721F83C1CD00DA4DE6 /* consio.cpp in Sources */, + 7AC29A771F83C1CD00DA4DE6 /* options.cpp in Sources */, + 7AC29A741F83C1CD00DA4DE6 /* errhnd.cpp in Sources */, + 7AC29A781F83C1CD00DA4DE6 /* rarvm.cpp in Sources */, + 7AC29A7C1F83C1CD00DA4DE6 /* secpassword.cpp in Sources */, + 7AC29A7B1F83C1CD00DA4DE6 /* rijndael.cpp in Sources */, + 7AC29A751F83C1CD00DA4DE6 /* getbits.cpp in Sources */, + 7AC29A8D1F83C21700DA4DE6 /* sha1.cpp in Sources */, + 7AC29A8E1F83C21700DA4DE6 /* sha256.cpp in Sources */, + 7AC29A7E1F83C21700DA4DE6 /* blake2s.cpp in Sources */, + 7AC29A851F83C21700DA4DE6 /* hash.cpp in Sources */, + 7AC29A811F83C21700DA4DE6 /* extinfo.cpp in Sources */, + 7AC29A821F83C21700DA4DE6 /* extract.cpp in Sources */, + 7AC29A921F83C21700DA4DE6 /* volume.cpp in Sources */, + 7AC29A871F83C21700DA4DE6 /* list.cpp in Sources */, + 7AC29A841F83C21700DA4DE6 /* find.cpp in Sources */, + 7AC29A911F83C21700DA4DE6 /* unpack.cpp in Sources */, + 7AC29A861F83C21700DA4DE6 /* headers.cpp in Sources */, + 7AC29A8F1F83C21700DA4DE6 /* threadpool.cpp in Sources */, + 7AC29A8B1F83C21700DA4DE6 /* rs16.cpp in Sources */, + 7AC29A7F1F83C21700DA4DE6 /* cmddata.cpp in Sources */, + 7AC29A901F83C21700DA4DE6 /* ui.cpp in Sources */, + 7AC29A831F83C21700DA4DE6 /* filestr.cpp in Sources */, + 7AC29A891F83C21700DA4DE6 /* recvol.cpp in Sources */, + 7AC29A8A1F83C21700DA4DE6 /* rs.cpp in Sources */, + 7AC29A8C1F83C21700DA4DE6 /* scantree.cpp in Sources */, + 7AC29A881F83C21700DA4DE6 /* qopen.cpp in Sources */, + 7AC29A801F83C21700DA4DE6 /* dll.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 964C8AB718D28EE000AD7321 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 96A043DE1E4CC8D500BD7013 /* FirstVolumeTests.m in Sources */, + 9699FA891B3D9B5700B6D373 /* URKArchiveTests.m in Sources */, + 9699FA8C1B3D9B6F00B6D373 /* IsPasswordProtectedTests.m in Sources */, + 9699FA8E1B3D9B6F00B6D373 /* ValidatePasswordTests.m in Sources */, + 967872741E460FA70048A54C /* ListVolumesTests.m in Sources */, + 9699FA8B1B3D9B6F00B6D373 /* ExtractFilesTests.m in Sources */, + 7A267F6E1F713B970004EAA6 /* ProgressReportingTests.m in Sources */, + 9699FA8A1B3D9B6F00B6D373 /* URKArchiveTestCase.m in Sources */, + 96A043E01E4D232F00BD7013 /* HasMultipleVolumesTests.m in Sources */, + 9699FA8D1B3D9B6F00B6D373 /* ListFilenamesTests.m in Sources */, + 7A66082B20B4BE2000FE68D6 /* IterateFileInfoTests.m in Sources */, + 7ADC7A091F8831BC00023C2E /* CheckDataTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 96EA53561B3CB04300F79DC6 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 96EA537E1B3CB2C700F79DC6 /* URKFileInfo.m in Sources */, + 96EA53961B3CB2C700F79DC6 /* NSString+UnrarKit.mm in Sources */, + 96EA53AC1B3CB2C700F79DC6 /* URKArchive.mm in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 7ACC4CC91F7EF00F001A07F6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 7A22B1E91F60A05F004B8050 /* UnrarKitResources */; + targetProxy = 7ACC4CC81F7EF00F001A07F6 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 7A22B1FA1F60A2D3004B8050 /* UnrarKit.strings */ = { + isa = PBXVariantGroup; + children = ( + 7A22B1F91F60A2D3004B8050 /* en */, + ); + name = UnrarKit.strings; + path = Resources; + sourceTree = SOURCE_ROOT; + }; + 964C8AC518D28EE000AD7321 /* InfoPlist.strings */ = { + isa = PBXVariantGroup; + children = ( + 964C8AC618D28EE000AD7321 /* en */, + ); + name = InfoPlist.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 1DEB922308733DC00010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_THUMB_SUPPORT = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MACOSX_DEPLOYMENT_TARGET = 10.12; + ONLY_ACTIVE_ARCH = YES; + OTHER_CPLUSPLUSFLAGS = ( + "-DSILENT", + "-DRARDLL", + "$(OTHER_CFLAGS)", + ); + OTHER_LDFLAGS = ""; + SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos"; + SWIFT_VERSION = 4.0; + }; + name = Debug; + }; + 1DEB922408733DC00010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_NO_COMMON_BLOCKS = YES; + GCC_THUMB_SUPPORT = NO; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MACOSX_DEPLOYMENT_TARGET = 10.12; + OTHER_CPLUSPLUSFLAGS = ( + "-DSILENT", + "-DRARDLL", + "$(OTHER_CFLAGS)", + ); + OTHER_LDFLAGS = "-ObjC"; + SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.0; + }; + name = Release; + }; + 7A22B1ED1F60A05F004B8050 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + INFOPLIST_FILE = "Resources/UnrarKitResources-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; + MTL_ENABLE_DEBUG_INFO = YES; + PRODUCT_BUNDLE_IDENTIFIER = "com.abbey-code.UnrarKitResources"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 7A22B1EE1F60A05F004B8050 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + INFOPLIST_FILE = "Resources/UnrarKitResources-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; + MTL_ENABLE_DEBUG_INFO = NO; + PRODUCT_BUNDLE_IDENTIFIER = "com.abbey-code.UnrarKitResources"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 7AC29A5E1F83C08200DA4DE6 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = NO; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + EXECUTABLE_PREFIX = lib; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_INHIBIT_ALL_WARNINGS = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_CFLAGS = ( + "-Qunused-arguments", + "-Xanalyzer", + "-analyzer-disable-all-checks", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + 7AC29A5F1F83C08200DA4DE6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = NO; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + EXECUTABLE_PREFIX = lib; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_TREAT_WARNINGS_AS_ERRORS = NO; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_INHIBIT_ALL_WARNINGS = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_CFLAGS = ( + "-Qunused-arguments", + "-Xanalyzer", + "-analyzer-disable-all-checks", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 964C8ACD18D28EE000AD7321 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(DEVELOPER_FRAMEWORKS_DIR)", + "$(inherited)", + ); + GCC_DYNAMIC_NO_PIC = NO; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(BUILT_PRODUCTS_DIR)/../../Headers", + ); + INFOPLIST_FILE = "Tests/UnrarKit Tests-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.abbey-code.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUNDLE_LOADER)"; + WRAPPER_EXTENSION = xctest; + }; + name = Debug; + }; + 964C8ACE18D28EE000AD7321 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + FRAMEWORK_SEARCH_PATHS = ( + "$(DEVELOPER_FRAMEWORKS_DIR)", + "$(inherited)", + ); + GCC_PRECOMPILE_PREFIX_HEADER = YES; + HEADER_SEARCH_PATHS = ( + "$(inherited)", + /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include, + "$(BUILT_PRODUCTS_DIR)/../../Headers", + ); + INFOPLIST_FILE = "Tests/UnrarKit Tests-Info.plist"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.abbey-code.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + TEST_HOST = "$(BUNDLE_LOADER)"; + WRAPPER_EXTENSION = xctest; + }; + name = Release; + }; + 96EA536E1B3CB04300F79DC6 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_VERSION = A; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = "Resources/UnrarKit-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = YES; + OTHER_LDFLAGS = ( + "-ObjC", + "-lz", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.abbey-code.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + WARNING_CFLAGS = ( + "-Weverything", + "-Wno-auto-import", + "-Wno-objc-missing-property-synthesis", + "-Wno-variadic-macros", + "-Wno-old-style-cast", + ); + }; + name = Debug; + }; + 96EA536F1B3CB04300F79DC6 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_MODULES = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + FRAMEWORK_VERSION = A; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + INFOPLIST_FILE = "Resources/UnrarKit-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + MTL_ENABLE_DEBUG_INFO = NO; + OTHER_LDFLAGS = ( + "-ObjC", + "-lz", + ); + PRODUCT_BUNDLE_IDENTIFIER = "com.abbey-code.${PRODUCT_NAME:rfc1034identifier}"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + VALIDATE_PRODUCT = YES; + WARNING_CFLAGS = ( + "-Weverything", + "-Wno-auto-import", + "-Wno-objc-missing-property-synthesis", + "-Wno-variadic-macros", + "-Wno-old-style-cast", + ); + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "UnrarKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB922308733DC00010E9CD /* Debug */, + 1DEB922408733DC00010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 7A22B1EF1F60A05F004B8050 /* Build configuration list for PBXNativeTarget "UnrarKitResources" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7A22B1ED1F60A05F004B8050 /* Debug */, + 7A22B1EE1F60A05F004B8050 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 7AC29A601F83C08200DA4DE6 /* Build configuration list for PBXNativeTarget "unrar" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7AC29A5E1F83C08200DA4DE6 /* Debug */, + 7AC29A5F1F83C08200DA4DE6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 964C8ACF18D28EE000AD7321 /* Build configuration list for PBXNativeTarget "UnrarKit Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 964C8ACD18D28EE000AD7321 /* Debug */, + 964C8ACE18D28EE000AD7321 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 96EA53721B3CB04300F79DC6 /* Build configuration list for PBXNativeTarget "UnrarKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 96EA536E1B3CB04300F79DC6 /* Debug */, + 96EA536F1B3CB04300F79DC6 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0867D690FE84028FC02AAC07 /* Project object */; +} diff --git a/Carthage/Checkouts/UnrarKit/UnrarKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Carthage/Checkouts/UnrarKit/UnrarKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..b015816 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/UnrarKit.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Carthage/Checkouts/UnrarKit/UnrarKit.xcodeproj/xcshareddata/xcschemes/UnrarKit.xcscheme b/Carthage/Checkouts/UnrarKit/UnrarKit.xcodeproj/xcshareddata/xcschemes/UnrarKit.xcscheme new file mode 100644 index 0000000..b5d0fe3 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/UnrarKit.xcodeproj/xcshareddata/xcschemes/UnrarKit.xcscheme @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Carthage/Checkouts/UnrarKit/UnrarKit.xcworkspace/contents.xcworkspacedata b/Carthage/Checkouts/UnrarKit/UnrarKit.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..be5fcb1 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/UnrarKit.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/Carthage/Checkouts/UnrarKit/UnrarKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Carthage/Checkouts/UnrarKit/UnrarKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/UnrarKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Carthage/Checkouts/UnrarKit/UnrarKit.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Carthage/Checkouts/UnrarKit/UnrarKit.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..08de0be --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/UnrarKit.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + diff --git a/Carthage/Checkouts/UnrarKit/beta-notes.md b/Carthage/Checkouts/UnrarKit/beta-notes.md new file mode 100644 index 0000000..e62fb45 --- /dev/null +++ b/Carthage/Checkouts/UnrarKit/beta-notes.md @@ -0,0 +1 @@ +* Added new method `-iterateFileInfo:error:` that takes a block, allowing for lazy iteration of file info, without building up an in-memory array (Issue #73 - Thanks to [@yanex](https://github.com/yanex) for the suggestion!) diff --git a/Carthage/Checkouts/UnzipKit/.github/ISSUE_TEMPLATE.MD b/Carthage/Checkouts/UnzipKit/.github/ISSUE_TEMPLATE.MD new file mode 100644 index 0000000..3453922 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/.github/ISSUE_TEMPLATE.MD @@ -0,0 +1,28 @@ +Thanks for making a contribution to UnzipKit! I greatly value issue reports, which help make the library better, and more useful to more people. To help me address your issue, please follow the steps below. + +_Delete from this line up_ + +- [ ] Provide a brief, descriptive issue title +- [ ] Fill out the template below +- [ ] **Option A** is the easier, more traditional way of reporting a bug +- [ ] **Option B** gets you bonus points (redeemable in the form of me looking at your issue more quickly). Create a failing unit test that would pass if the issue were resolved. When I go to fix your issue, it's one of the first things I would do anyway. There is a pretty complete set already there, so you can use those as a guide to creating new ones. + +## Option A + +### Steps to reproduce issue (Detailed enough for me to reproduce): + + +### What you expect to happen: + + +### What actually happened: + + +### (_Optional_) A stack trace or crash report, if you have one: + + +## Option B + +### Brief summary of issue: + +### Link to your branch where you've created automated tests to demonstrate the issue (and the name of the unit test(s) you created): \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/.gitignore b/Carthage/Checkouts/UnzipKit/.gitignore new file mode 100644 index 0000000..3ee5ebb --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/.gitignore @@ -0,0 +1,15 @@ +build +*.mode* +*.pbxuser +*.perspective* +.DS_Store +*.swp +**/*.xccheckout +**/xcuserdata/* +analyzer-output/** + +UnzipKitDemo/Pods/* +UnzipKitDemo/Podfile.lock +UnzipKitDemo/Carthage/* +UnzipKitDemo/Cartfile +UnzipKitDemo/Cartfile.resolved \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/.travis.yml b/Carthage/Checkouts/UnzipKit/.travis.yml new file mode 100644 index 0000000..3434eee --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/.travis.yml @@ -0,0 +1,41 @@ +language: + - objective-c + +osx_image: xcode9.3 + +before_script: + # Make log level less verbose. Temporarily undo if more info is needed + - sudo log config --mode "level:default" + +matrix: + include: + - stage: Test + env: Name=Mac + # The CLANG arguments and find command fail the build on analyzer errors + script: xcodebuild -workspace UnzipKit.xcworkspace -scheme UnzipKit -sdk macosx -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: Test + env: Name=iOS + # The CLANG arguments and find command fail the build on analyzer errors + script: xcodebuild -workspace UnzipKit.xcworkspace -scheme UnzipKit -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: Test + env: Name=DemoAppBuild + # The CLANG arguments and find command fail the build on analyzer errors + 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 + script: ./Scripts/cocoapod-validate.sh + + - stage: Validate + env: Name=Carthage + script: ./Scripts/carthage-validate.sh + + - stage: Release + if: tag IS present + before_install: brew upgrade python # Needs Python 3 + script: ./Scripts/push-output.sh + +# Turn on Docker, container-based infrastructure +sudo: false diff --git a/Carthage/Checkouts/UnzipKit/CHANGELOG.md b/Carthage/Checkouts/UnzipKit/CHANGELOG.md new file mode 100644 index 0000000..371e61c --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/CHANGELOG.md @@ -0,0 +1,153 @@ +# UnzipKit CHANGELOG + +## 1.9 + +* Added support for `NSProgress` and `NSProgressReporting` in all extraction and iteration methods (Issue #32) +* Added detailed logging using new unified logging framework. See [the readme](README.md) for more details (Issue #47) +* Added support for archiving and restoring files' POSIX permissions (PRs #84, #86, #87 - Thanks, [@MartinLau7](https://github.com/MartinLau7)!) +* Added methods to check data integrity of an individual archived file, or the entire archive (Issue #63) +* Fixed a crasher in `extractBufferedDataFromFile:error:action:`, which also manifested in other methods that use it, like `validatePassword` (Issue #51 - Thanks, [@amosavian](https://github.com/amosavian), [@monobono](https://github.com/monobono), and [@segunlee](https://github.com/segunlee)!) +* Upgraded project to Xcode 9 and to the macOS 10.13 and iOS 11 SDKs (Issue #61) +* Consolidated targets so they're shared between iOS and macOS (Issue #62) +* Added a CocoaPods test spec (Issue #59) +* Improved the way warnings are ignored to be more consistent, and so they're only ignored in `minizip`, and not the UnzipKit sources (Issue #68) + +## 1.8.5 + +* Fixed issues with localization (again, again) (Issue #42). Thanks, @stevenp! + +## 1.8.4 + +* Updated to Xcode 8 (Issue #50) +* Fixed issues with localization (again) (Issue #42). Thanks, @ConfusedVorlon and @tomjpsun! + +## 1.8.3 + +* Fixed bug in iOS framework target causing a framework bundle not to be produced (Issue #48 – Thanks, @amosavian!) +* Added CI automation to release tagged successful builds to CocoaPods from Travis (Issue #49) + +## 1.8.2 + +Fixed issues with localization, that could affect submission through iTunes Connect (Issue #42) + +## 1.8.1 + +* Added checking whether a file is compressed with the Deflate64 method, and returning a specific error code for that unsupported format (Issue #37) +* Fixed internationalization, laying the groundwork for non-US-English localization in the future. If you use UnzipKit from Carthage or CocoaPods, and run your app using the "Show non-localized strings" option, UnzipKit's strings should no longer display as all-cap (Issue #38) + +## 1.8 + +Fixed a bug causing delete operations (including writing updated data with the `overwrite` flag set to true) to fail when the archive resides on an external volume (Issue #36) + +## 1.7.2 + +Fixed the nullability attributes of the 'password' argument in the UZKArchive intitializers (Issue #34 - Thanks, Mohammad!) + +## 1.7.1 + +Fixed a bug causing the UZKErrorDomain constant not to be visible from client projects using Swift 2.2 (Xcode 7.3) or greater (Issue #33) + +## 1.7 + +* Reduced memory footprint while using `extractFilesTo:overwrite:progress:error` to extract an archive. This method now uses a buffer to read and write the archived file, rather than reading it into memory up front (Issue #27, PR #28). Thanks, @brendand! +* Added `nullable` attribute to the return types of the `extractData...` methods, so they play more nicely with Swift's error handling (PR #29). Thanks, @amosavian! +* Fixed a compiler warning that started showing up in Xcode 7.3 (Issue #26). Thanks again, @brendand! + +## 1.6.2 + +Fixed some issues when extracting files from an archive: + +* Extracting the first file past the 4 GB mark in an archive would fail, due to a bug in the Zip64 implementation (Issue #25) +* Memory would grow as each file was extracted, potentially consuming multiple gigabytes for large archives +* Improved error messages when there's an error extracting a file (the underlying error is no longer hidden) + +Thanks @brendand! + +## 1.6.1 + +Fixed issue that can cause a crash when writing to Zip files across multiple threads (Issue #23). Thanks again, @iblacksun! + +## 1.6 + +Added support for using UnzipKit from a Swift dynamic framework target (Issue #21, PR #22). Thanks @iblacksun! + +## 1.5 + +* Added full support for Carthage (Issue #11) +* Added annotations for nullability, improving compatibility with Xcode 7 and Swift + +## 1.4.2 + +Fixed a bug causing global comments not to get written to disk (Issue #19) + +## 1.4.1 + +* Added the ability to password protect a file over the streaming API (`-writeInfoBuffer:...`), if the CRC of the file is known up front (Issue #16) +* Fixed a memory consumption bug, causing a crash on iOS when creating an archive with many files when `overwrite =- YES` (Issue #18) +* Quieted the warning logged every time a `UZKArchive` is created for an as-yet uncreated file (Issue #17) + +Fixed a bug causing file-specific passwords never to be written to an archive (Issue #15) + +## 1.4 + +* Fixed file encryption (Issue #12) + + _Due to Zip format requirements (the CRC needs to be known before a file write begins), passwords can no longer be used with the block-based file writing methods (`-writeIntobuffer...`). This is checked with an assertion, since the `password` property could be set already before starting the buffered write_ + +* Updated the implementation of `isPasswordProtected` to check all files, not just the first (Issue #13) + +## 1.3.2 + +Fixed a bug causing file-specific passwords never to be written to an archive (Issue #15) + +## 1.3.1 + +Fixed a bug, in which `password` was passed through as `nil` for the overload of `-writeData...` that doesn't take the `overwrite` argument (Issue #14) + +## 1.3 + +Improved buffered writing API, no longer requiring a CRC, and allowing for error handling in the action block (Issue #9) + +## 1.2.2 + +Silenced some 32-bit iOS warnings (Thanks, Clint!) + +## 1.2.1 + +Added iOS 7 compatibility (Issue #8), and an iOS (Swift!) demo project + +## 1.2 + +Added methods to easily detect whether a file is a Zip archive or not (Issue #7) + +## 1.1.3 + +Fixed a bug introduced in the last version that would cause errors when writing a file for whom the comment had not first been read or written + +## 1.1.2 + +Exposed a "comment" property on UZKArchive for reading and writing an archive's global comment (Issue #6) + +## 1.1.1 + +Fixed a file handle leak that could lead to random file access errors (Issue #5) + +## 1.1 + +Improved error handling, providing more detail in the NSSError objects returned (Issue #3) + +## 1.0.3 + +Added synchronization, so accessing the same archive across threads doesn't cause errors (Issue #4) + +## 1.0.2 + +Fixed bug causing file extraction to fail when an archive contains directories (Issue #2) + +## 1.0.1 + +Fixed bug causing the library not to build for the 10.9 target SDK + +## 1.0 + +Initial release diff --git a/Carthage/Checkouts/UnzipKit/LICENSE b/Carthage/Checkouts/UnzipKit/LICENSE new file mode 100644 index 0000000..8fd672d --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/LICENSE @@ -0,0 +1,5 @@ +© Dov Frankel, All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/Lib/MiniZip/crypt.h b/Carthage/Checkouts/UnzipKit/Lib/MiniZip/crypt.h new file mode 100755 index 0000000..a01d08d --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Lib/MiniZip/crypt.h @@ -0,0 +1,131 @@ +/* crypt.h -- base code for crypt/uncrypt ZIPfile + + + Version 1.01e, February 12th, 2005 + + Copyright (C) 1998-2005 Gilles Vollant + + This code is a modified version of crypting code in Infozip distribution + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + If you don't need crypting in your application, just define symbols + NOCRYPT and NOUNCRYPT. + + This code support the "Traditional PKWARE Encryption". + + The new AES encryption added on Zip format by Winzip (see the page + http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong + Encryption is not supported. +*/ + +#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8)) + +/*********************************************************************** + * Return the next byte in the pseudo-random sequence + */ +static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab) +{ + unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an + * unpredictable manner on 16-bit systems; not a problem + * with any known compiler so far, though */ + + temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2; + return (int)(((temp * (temp ^ 1)) >> 8) & 0xff); +} + +/*********************************************************************** + * Update the encryption keys with the next byte of plain text + */ +static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c) +{ + (*(pkeys+0)) = CRC32((*(pkeys+0)), c); + (*(pkeys+1)) += (*(pkeys+0)) & 0xff; + (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1; + { + register int keyshift = (int)((*(pkeys+1)) >> 24); + (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift); + } + return c; +} + + +/*********************************************************************** + * Initialize the encryption keys and the random header according to + * the given password. + */ +static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab) +{ + *(pkeys+0) = 305419896L; + *(pkeys+1) = 591751049L; + *(pkeys+2) = 878082192L; + while (*passwd != '\0') { + update_keys(pkeys,pcrc_32_tab,(int)*passwd); + passwd++; + } +} + +#define zdecode(pkeys,pcrc_32_tab,c) \ + (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab))) + +#define zencode(pkeys,pcrc_32_tab,c,t) \ + (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c)) + +#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED + +#define RAND_HEAD_LEN 12 + /* "last resort" source for second part of crypt seed pattern */ +# ifndef ZCR_SEED2 +# define ZCR_SEED2 3141592654UL /* use PI as default pattern */ +# endif + +static int crypthead(const char* passwd, /* password string */ + unsigned char* buf, /* where to write header */ + int bufSize, + unsigned long* pkeys, + const unsigned long* pcrc_32_tab, + unsigned long crcForCrypting) +{ + int n; /* index in random header */ + int t; /* temporary */ + int c; /* random byte */ + unsigned char header[RAND_HEAD_LEN-2]; /* random header */ + static unsigned calls = 0; /* ensure different random header each time */ + + if (bufSize> 7) & 0xff; + header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t); + } + /* Encrypt random header (last two bytes is high word of crc) */ + init_keys(passwd, pkeys, pcrc_32_tab); + for (n = 0; n < RAND_HEAD_LEN-2; n++) + { + buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t); + } + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t); + buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t); + return n; +} + +#endif diff --git a/Carthage/Checkouts/UnzipKit/Lib/MiniZip/ioapi.c b/Carthage/Checkouts/UnzipKit/Lib/MiniZip/ioapi.c new file mode 100755 index 0000000..0ec2557 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Lib/MiniZip/ioapi.c @@ -0,0 +1,235 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + +*/ + +#if (defined(_WIN32)) + #define _CRT_SECURE_NO_WARNINGS +#endif + +#include "ioapi.h" + +voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode) +{ + if (pfilefunc->zfile_func64.zopen64_file != NULL) + return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode); + else + { + return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode); + } +} + +long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin); + else + { + uLong offsetTruncated = (uLong)offset; + if (offsetTruncated != offset) + return -1; + else + return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin); + } +} + +ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream) +{ + if (pfilefunc->zfile_func64.zseek64_file != NULL) + return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream); + else + { + uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream); + if ((tell_uLong) == ((uLong)-1)) + return (ZPOS64_T)-1; + else + return tell_uLong; + } +} + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32) +{ + p_filefunc64_32->zfile_func64.zopen64_file = NULL; + p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file; + p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file; + p_filefunc64_32->zfile_func64.ztell64_file = NULL; + p_filefunc64_32->zfile_func64.zseek64_file = NULL; + p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file; + p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file; + p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque; + p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file; + p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file; +} + + + +static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode)); +static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size)); +static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream)); +static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream)); +static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream)); + +static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen(filename, mode_fopen); + return file; +} + +static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode) +{ + FILE* file = NULL; + const char* mode_fopen = NULL; + if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ) + mode_fopen = "rb"; + else + if (mode & ZLIB_FILEFUNC_MODE_EXISTING) + mode_fopen = "r+b"; + else + if (mode & ZLIB_FILEFUNC_MODE_CREATE) + mode_fopen = "wb"; + + if ((filename!=NULL) && (mode_fopen != NULL)) + file = fopen((const char*)filename, mode_fopen); + return file; +} + + +static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size) +{ + uLong ret; + ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream); + return ret; +} + +static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream) +{ + long ret; + ret = ftell((FILE *)stream); + return ret; +} + + +static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream) +{ + ZPOS64_T ret; + ret = ftello((FILE *)stream); + return ret; +} + +static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + if (fseek((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + return ret; +} + +static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin) +{ + int fseek_origin=0; + long ret; + switch (origin) + { + case ZLIB_FILEFUNC_SEEK_CUR : + fseek_origin = SEEK_CUR; + break; + case ZLIB_FILEFUNC_SEEK_END : + fseek_origin = SEEK_END; + break; + case ZLIB_FILEFUNC_SEEK_SET : + fseek_origin = SEEK_SET; + break; + default: return -1; + } + ret = 0; + + if(fseeko((FILE *)stream, offset, fseek_origin) != 0) + ret = -1; + + return ret; +} + + +static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = fclose((FILE *)stream); + return ret; +} + +static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream) +{ + int ret; + ret = ferror((FILE *)stream); + return ret; +} + +void fill_fopen_filefunc (pzlib_filefunc_def) + zlib_filefunc_def* pzlib_filefunc_def; +{ + pzlib_filefunc_def->zopen_file = fopen_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell_file = ftell_file_func; + pzlib_filefunc_def->zseek_file = fseek_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} + +void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def) +{ + pzlib_filefunc_def->zopen64_file = fopen64_file_func; + pzlib_filefunc_def->zread_file = fread_file_func; + pzlib_filefunc_def->zwrite_file = fwrite_file_func; + pzlib_filefunc_def->ztell64_file = ftell64_file_func; + pzlib_filefunc_def->zseek64_file = fseek64_file_func; + pzlib_filefunc_def->zclose_file = fclose_file_func; + pzlib_filefunc_def->zerror_file = ferror_file_func; + pzlib_filefunc_def->opaque = NULL; +} diff --git a/Carthage/Checkouts/UnzipKit/Lib/MiniZip/ioapi.h b/Carthage/Checkouts/UnzipKit/Lib/MiniZip/ioapi.h new file mode 100755 index 0000000..cbb6dd1 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Lib/MiniZip/ioapi.h @@ -0,0 +1,206 @@ +/* ioapi.h -- IO base function header for compress/uncompress .zip + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + + Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this) + Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux. + More if/def section may be needed to support other platforms + Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows. + (but you should use iowin32.c for windows instead) + +*/ + +// Modification to silence "Macro name is a reserved identifier" warning +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wreserved-id-macro" + +#ifndef _ZLIBIOAPI64_H +#define _ZLIBIOAPI64_H + +#if (!defined(_WIN32)) && (!defined(WIN32)) + + // Linux needs this to support file operation on files larger then 4+GB + // But might need better if/def to select just the platforms that needs them. + + #ifndef __USE_FILE_OFFSET64 + #define __USE_FILE_OFFSET64 + #endif + #ifndef __USE_LARGEFILE64 + #define __USE_LARGEFILE64 + #endif + #ifndef _LARGEFILE64_SOURCE + #define _LARGEFILE64_SOURCE + #endif + #ifndef _FILE_OFFSET_BIT + #define _FILE_OFFSET_BIT 64 + #endif +#endif + +#pragma clang diagnostic pop + +#include +#include +#include "zlib.h" + +#if defined(USE_FILE32API) +#define fopen64 fopen +#define ftello64 ftell +#define fseeko64 fseek +#else +#ifdef _MSC_VER + #define fopen64 fopen + #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC))) + #define ftello64 _ftelli64 + #define fseeko64 _fseeki64 + #else // old MSC + #define ftello64 ftell + #define fseeko64 fseek + #endif +#endif +#endif + +/* +#ifndef ZPOS64_T + #ifdef _WIN32 + #define ZPOS64_T fpos_t + #else + #include + #define ZPOS64_T uint64_t + #endif +#endif +*/ + +#ifdef HAVE_MINIZIP64_CONF_H +#include "mz64conf.h" +#endif + +/* a type choosen by DEFINE */ +#ifdef HAVE_64BIT_INT_CUSTOM +typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T; +#else +#ifdef HAS_STDINT_H +#include "stdint.h" +typedef uint64_t ZPOS64_T; +#else + + +#if defined(_MSC_VER) || defined(__BORLANDC__) +typedef unsigned __int64 ZPOS64_T; +#else +typedef unsigned long long int ZPOS64_T; +#endif +#endif +#endif + + + +#ifdef __cplusplus +extern "C" { +#endif + + +#define ZLIB_FILEFUNC_SEEK_CUR (1) +#define ZLIB_FILEFUNC_SEEK_END (2) +#define ZLIB_FILEFUNC_SEEK_SET (0) + +#define ZLIB_FILEFUNC_MODE_READ (1) +#define ZLIB_FILEFUNC_MODE_WRITE (2) +#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3) + +#define ZLIB_FILEFUNC_MODE_EXISTING (4) +#define ZLIB_FILEFUNC_MODE_CREATE (8) + + +#ifndef ZCALLBACK + #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK) + #define ZCALLBACK CALLBACK + #else + #define ZCALLBACK + #endif +#endif + + + + +typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode)); +typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size)); +typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size)); +typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream)); +typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream)); + +typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin)); + + +/* here is the "old" 32 bits structure structure */ +typedef struct zlib_filefunc_def_s +{ + open_file_func zopen_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell_file_func ztell_file; + seek_file_func zseek_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc_def; + +typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream)); +typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)); +typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode)); + +typedef struct zlib_filefunc64_def_s +{ + open64_file_func zopen64_file; + read_file_func zread_file; + write_file_func zwrite_file; + tell64_file_func ztell64_file; + seek64_file_func zseek64_file; + close_file_func zclose_file; + testerror_file_func zerror_file; + voidpf opaque; +} zlib_filefunc64_def; + +void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def)); +void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def)); + +/* now internal definition, only for zip.c and unzip.h */ +typedef struct zlib_filefunc64_32_def_s +{ + zlib_filefunc64_def zfile_func64; + open_file_func zopen32_file; + tell_file_func ztell32_file; + seek_file_func zseek32_file; +} zlib_filefunc64_32_def; + + +#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size)) +//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream)) +//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode)) +#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream)) +#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream)) + +voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)); +long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)); +ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)); + +void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32); + +#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode))) +#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream))) +#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode))) + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Carthage/Checkouts/UnzipKit/Lib/MiniZip/mztools.c b/Carthage/Checkouts/UnzipKit/Lib/MiniZip/mztools.c new file mode 100755 index 0000000..f9092e6 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Lib/MiniZip/mztools.c @@ -0,0 +1,281 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +/* Code */ +#include +#include +#include +#include "zlib.h" +#include "unzip.h" + +#define READ_8(adr) ((unsigned char)*(adr)) +#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) ) +#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) ) + +#define WRITE_8(buff, n) do { \ + *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \ +} while(0) +#define WRITE_16(buff, n) do { \ + WRITE_8((unsigned char*)(buff), n); \ + WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \ +} while(0) +#define WRITE_32(buff, n) do { \ + WRITE_16((unsigned char*)(buff), (n) & 0xffff); \ + WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \ +} while(0) + +extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered) +const char* file; +const char* fileOut; +const char* fileOutTmp; +uLong* nRecovered; +uLong* bytesRecovered; +{ + int err = Z_OK; + FILE* fpZip = fopen(file, "rb"); + FILE* fpOut = fopen(fileOut, "wb"); + FILE* fpOutCD = fopen(fileOutTmp, "wb"); + if (fpZip != NULL && fpOut != NULL) { + int entries = 0; + uLong totalBytes = 0; + char header[30]; + char filename[256]; + char extra[1024]; + int offset = 0; + int offsetCD = 0; + while ( fread(header, 1, 30, fpZip) == 30 ) { + int currentOffset = offset; + + /* File entry */ + if (READ_32(header) == 0x04034b50) { + unsigned int version = READ_16(header + 4); + unsigned int gpflag = READ_16(header + 6); + unsigned int method = READ_16(header + 8); + unsigned int filetime = READ_16(header + 10); + unsigned int filedate = READ_16(header + 12); + unsigned int crc = READ_32(header + 14); /* crc */ + unsigned int cpsize = READ_32(header + 18); /* compressed size */ + unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */ + unsigned int fnsize = READ_16(header + 26); /* file name length */ + unsigned int extsize = READ_16(header + 28); /* extra field length */ + filename[0] = extra[0] = '\0'; + + /* Header */ + if (fwrite(header, 1, 30, fpOut) == 30) { + offset += 30; + } else { + err = Z_ERRNO; + break; + } + + /* Filename */ + if (fnsize > 0) { + if (fread(filename, 1, fnsize, fpZip) == fnsize) { + if (fwrite(filename, 1, fnsize, fpOut) == fnsize) { + offset += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (fread(extra, 1, extsize, fpZip) == extsize) { + if (fwrite(extra, 1, extsize, fpOut) == extsize) { + offset += extsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_ERRNO; + break; + } + } + + /* Data */ + { + int dataSize = cpsize; + if (dataSize == 0) { + dataSize = uncpsize; + } + if (dataSize > 0) { + char* data = malloc(dataSize); + if (data != NULL) { + if ((int)fread(data, 1, dataSize, fpZip) == dataSize) { + if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) { + offset += dataSize; + totalBytes += dataSize; + } else { + err = Z_ERRNO; + } + } else { + err = Z_ERRNO; + } + free(data); + if (err != Z_OK) { + break; + } + } else { + err = Z_MEM_ERROR; + break; + } + } + } + + /* Central directory entry */ + { + char header[46]; + char* comment = ""; + int comsize = (int) strlen(comment); + WRITE_32(header, 0x02014b50); + WRITE_16(header + 4, version); + WRITE_16(header + 6, version); + WRITE_16(header + 8, gpflag); + WRITE_16(header + 10, method); + WRITE_16(header + 12, filetime); + WRITE_16(header + 14, filedate); + WRITE_32(header + 16, crc); + WRITE_32(header + 20, cpsize); + WRITE_32(header + 24, uncpsize); + WRITE_16(header + 28, fnsize); + WRITE_16(header + 30, extsize); + WRITE_16(header + 32, comsize); + WRITE_16(header + 34, 0); /* disk # */ + WRITE_16(header + 36, 0); /* int attrb */ + WRITE_32(header + 38, 0); /* ext attrb */ + WRITE_32(header + 42, currentOffset); + /* Header */ + if (fwrite(header, 1, 46, fpOutCD) == 46) { + offsetCD += 46; + + /* Filename */ + if (fnsize > 0) { + if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) { + offsetCD += fnsize; + } else { + err = Z_ERRNO; + break; + } + } else { + err = Z_STREAM_ERROR; + break; + } + + /* Extra field */ + if (extsize > 0) { + if (fwrite(extra, 1, extsize, fpOutCD) == extsize) { + offsetCD += extsize; + } else { + err = Z_ERRNO; + break; + } + } + + /* Comment field */ + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) { + offsetCD += comsize; + } else { + err = Z_ERRNO; + break; + } + } + + + } else { + err = Z_ERRNO; + break; + } + } + + /* Success */ + entries++; + + } else { + break; + } + } + + /* Final central directory */ + { + int entriesZip = entries; + char header[22]; + char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools"; + int comsize = (int) strlen(comment); + if (entriesZip > 0xffff) { + entriesZip = 0xffff; + } + WRITE_32(header, 0x06054b50); + WRITE_16(header + 4, 0); /* disk # */ + WRITE_16(header + 6, 0); /* disk # */ + WRITE_16(header + 8, entriesZip); /* hack */ + WRITE_16(header + 10, entriesZip); /* hack */ + WRITE_32(header + 12, offsetCD); /* size of CD */ + WRITE_32(header + 16, offset); /* offset to CD */ + WRITE_16(header + 20, comsize); /* comment */ + + /* Header */ + if (fwrite(header, 1, 22, fpOutCD) == 22) { + + /* Comment field */ + if (comsize > 0) { + if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) { + err = Z_ERRNO; + } + } + + } else { + err = Z_ERRNO; + } + } + + /* Final merge (file + central directory) */ + fclose(fpOutCD); + if (err == Z_OK) { + fpOutCD = fopen(fileOutTmp, "rb"); + if (fpOutCD != NULL) { + int nRead; + char buffer[8192]; + while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) { + if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) { + err = Z_ERRNO; + break; + } + } + fclose(fpOutCD); + } + } + + /* Close */ + fclose(fpZip); + fclose(fpOut); + + /* Wipe temporary file */ + (void)remove(fileOutTmp); + + /* Number of recovered entries */ + if (err == Z_OK) { + if (nRecovered != NULL) { + *nRecovered = entries; + } + if (bytesRecovered != NULL) { + *bytesRecovered = totalBytes; + } + } + } else { + err = Z_STREAM_ERROR; + } + return err; +} diff --git a/Carthage/Checkouts/UnzipKit/Lib/MiniZip/mztools.h b/Carthage/Checkouts/UnzipKit/Lib/MiniZip/mztools.h new file mode 100755 index 0000000..88b3459 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Lib/MiniZip/mztools.h @@ -0,0 +1,31 @@ +/* + Additional tools for Minizip + Code: Xavier Roche '2004 + License: Same as ZLIB (www.gzip.org) +*/ + +#ifndef _zip_tools_H +#define _zip_tools_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#include "unzip.h" + +/* Repair a ZIP file (missing central directory) + file: file to recover + fileOut: output file after recovery + fileOutTmp: temporary file name used for recovery +*/ +extern int ZEXPORT unzRepair(const char* file, + const char* fileOut, + const char* fileOutTmp, + uLong* nRecovered, + uLong* bytesRecovered); + +#endif diff --git a/Carthage/Checkouts/UnzipKit/Lib/MiniZip/unzip.c b/Carthage/Checkouts/UnzipKit/Lib/MiniZip/unzip.c new file mode 100755 index 0000000..b254abb --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Lib/MiniZip/unzip.c @@ -0,0 +1,2129 @@ +/* unzip.c -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + + ------------------------------------------------------------------------------------ + Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of + compatibility with older software. The following is from the original crypt.c. + Code woven in by Terry Thorsen 1/2003. + + Copyright (c) 1990-2000 Info-ZIP. All rights reserved. + + See the accompanying file LICENSE, version 2000-Apr-09 or later + (the contents of which are also included in zip.h) for terms of use. + If, for some reason, all these files are missing, the Info-ZIP license + also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html + + crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h] + + The encryption/decryption parts of this source code (as opposed to the + non-echoing password parts) were originally written in Europe. The + whole source package can be freely distributed, including from the USA. + (Prior to January 2000, re-export from the US was a violation of US law.) + + This encryption code is a direct transcription of the algorithm from + Roger Schlafly, described by Phil Katz in the file appnote.txt. This + file (appnote.txt) is distributed with the PKZIP program (even in the + version without encryption capabilities). + + ------------------------------------------------------------------------------------ + + Changes in unzip.c + + 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos + 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz* + 2007-2008 - Even Rouault - Remove old C style function prototypes + 2007-2008 - Even Rouault - Add unzip support for ZIP64 + + Copyright (C) 2007-2008 Even Rouault + + + Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again). + Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G + should only read the compressed/uncompressed size from the Zip64 format if + the size from normal header was 0xFFFFFFFF + Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant + Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required) + Patch created by Daniel Borca + + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + + Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson + +*/ + + +#include +#include +#include + +// Matt Connolly 2013-09-12: this was defined in minizip 1.1. +// @see http://www.winimage.com/zLibDll/minizip.html +// Defining it defeats the ability to unzip password protected zip files, so this +// is commented out so that existing tests pass. + +//#ifndef NOUNCRYPT +// #define NOUNCRYPT +//#endif + +#include "zlib.h" +#include "unzip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + + +#ifndef CASESENSITIVITYDEFAULT_NO +# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) +# define CASESENSITIVITYDEFAULT_NO +# endif +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (16384) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + +const char unz_copyright[] = + " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info64_internal_s +{ + ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */ +} unz_file_info64_internal; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/ + uLong stream_initialised; /* flag set if stream structure is initialised*/ + + ZPOS64_T offset_local_extrafield;/* offset of the local extra field */ + uInt size_local_extrafield;/* size of the local extra field */ + ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/ + ZPOS64_T total_out_64; + + uLong crc32; /* crc32 of all data uncompressed */ + uLong crc32_wait; /* crc32 we must obtain after decompress all */ + ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */ + ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + uLong compression_method; /* compression method (0==store) */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + int raw; +} file_in_zip64_read_info_s; + + +/* unz64_s contain internal information about the zipfile +*/ +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + int is64bitOpenFunction; + voidpf filestream; /* io structore of the zipfile */ + unz_global_info64 gi; /* public global information */ + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + ZPOS64_T num_file; /* number of the current file in the zipfile*/ + ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/ + ZPOS64_T current_file_ok; /* flag about the usability of the current file*/ + ZPOS64_T central_pos; /* position of the beginning of the central dir*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info64 cur_file_info; /* public info about the current file in zip*/ + unz_file_info64_internal cur_file_info_internal; /* private info about it*/ + file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ + int encrypted; + + int isZip64; + +# ifndef NOUNCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; +# endif +} unz64_s; + + +#ifndef NOUNCRYPT +#include "crypt.h" +#endif + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + + +local int unz64local_getByte OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + int *pi)); + +local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int unz64local_getShort OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX)); + +local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + uLong *pX) +{ + uLong x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int unz64local_getLong64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX)); + + +local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream, + ZPOS64_T *pX) +{ + ZPOS64_T x ; + int i = 0; + int err; + + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<8; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<16; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<24; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<32; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<40; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<48; + + if (err==UNZ_OK) + err = unz64local_getByte(pzlib_filefunc_def,filestream,&i); + x |= ((ZPOS64_T)i)<<56; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +} + +/* My own strcmpi / strcasecmp */ +local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int ZEXPORT unzStringFileNameCompare (const char* fileName1, + const char* fileName2, + int iCaseSensitivity) + +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); +local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + + +/* + Locate the Central directory 64 of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T unz64local_SearchCentralDir64 OF(( + const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream)); + +local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, + voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK) + return 0; + + /* total number of disks */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK) + return 0; + + if (uL != 0x06064b50) + return 0; + + return relativeOffset; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer + "zlib/zlib114.zip". + If the zipfile cannot be opened (file doesn't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +local unzFile unzOpenInternal (const void *path, + zlib_filefunc64_32_def* pzlib_filefunc64_32_def, + int is64bitOpenFunction) +{ + unz64_s us; + unz64_s *s; + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + if (unz_copyright[0]!=' ') + return NULL; + + us.z_filefunc.zseek32_file = NULL; + us.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&us.z_filefunc.zfile_func64); + else + us.z_filefunc = *pzlib_filefunc64_32_def; + us.is64bitOpenFunction = is64bitOpenFunction; + + + + us.filestream = ZOPEN64(us.z_filefunc, + path, + ZLIB_FILEFUNC_MODE_READ | + ZLIB_FILEFUNC_MODE_EXISTING); + if (us.filestream==NULL) + return NULL; + + central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream); + if (central_pos) + { + uLong uS; + ZPOS64_T uL64; + + us.isZip64 = 1; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* size of zip64 end of central directory record */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version made by */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* version needed to extract */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + us.gi.size_comment = 0; + } + else + { + central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream); + if (central_pos==0) + err=UNZ_ERRNO; + + us.isZip64 = 0; + + if (ZSEEK64(us.z_filefunc, us.filestream, + central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.gi.number_entry = uL; + + /* total number of entries in the central dir */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + number_entry_CD = uL; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.size_central_dir = uL; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + us.offset_central_dir = uL; + + /* zipfile comment length */ + if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + } + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + ZCLOSE64(s->z_filefunc, s->filestream); + TRYFREE(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + +extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32) +{ + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + /* to do : check if number_entry is not truncated */ + pglobal_info32->number_entry = (uLong)s->gi.number_entry; + pglobal_info32->size_comment = s->gi.size_comment; + return UNZ_OK; +} +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm) +{ + ZPOS64_T uDate; + uDate = (ZPOS64_T)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +local int unz64local_GetCurrentFileInfoInternal OF((unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +local int unz64local_GetCurrentFileInfoInternal (unzFile file, + unz_file_info64 *pfile_info, + unz_file_info64_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz64_s* s; + unz_file_info64 file_info; + unz_file_info64_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + uLong uL; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pos_in_central_dir+s->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.compressed_size = uL; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info.uncompressed_size = uL; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + // relative offset of local header + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + file_info_internal.offset_curfile = uL; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + // Read extrafield + if ((err==UNZ_OK) && (extraField!=NULL)) + { + ZPOS64_T uSizeRead ; + if (file_info.size_file_extraz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + + lSeek += file_info.size_file_extra - (uLong)uSizeRead; + } + else + lSeek += file_info.size_file_extra; + + + if ((err==UNZ_OK) && (file_info.size_file_extra != 0)) + { + uLong acc = 0; + + // since lSeek now points to after the extra field we need to move back + lSeek -= file_info.size_file_extra; + + if (lSeek!=0) + { + if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + while(acc < file_info.size_file_extra) + { + uLong headerId; + uLong dataSize; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK) + err=UNZ_ERRNO; + + /* ZIP64 extra fields */ + if (headerId == 0x0001) + { + uLong uL; + + if(file_info.uncompressed_size == 0xFFFFFFFF) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.compressed_size == 0xFFFFFFFF) + { + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info_internal.offset_curfile == 0xFFFFFFFF) + { + /* Relative Header offset */ + if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + } + + if(file_info.disk_num_start == 0xFFFFFFFF) + { + /* Disk Start Number */ + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK) + err=UNZ_ERRNO; + } + + } + else + { + if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0) + err=UNZ_ERRNO; + } + + acc += 2 + 2 + dataSize; + } + } + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentz_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + } + + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file, + unz_file_info64 * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +extern int ZEXPORT unzGetCurrentFileInfo (unzFile file, + unz_file_info * pfile_info, + char * szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char* szComment, uLong commentBufferSize) +{ + int err; + unz_file_info64 file_info64; + err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); + if (err==UNZ_OK) + { + pfile_info->version = file_info64.version; + pfile_info->version_needed = file_info64.version_needed; + pfile_info->flag = file_info64.flag; + pfile_info->compression_method = file_info64.compression_method; + pfile_info->dosDate = file_info64.dosDate; + pfile_info->crc = file_info64.crc; + + pfile_info->size_filename = file_info64.size_filename; + pfile_info->size_file_extra = file_info64.size_file_extra; + pfile_info->size_file_comment = file_info64.size_file_comment; + + pfile_info->disk_num_start = file_info64.disk_num_start; + pfile_info->internal_fa = file_info64.internal_fa; + pfile_info->external_fa = file_info64.external_fa; + + pfile_info->tmu_date = file_info64.tmu_date, + + + pfile_info->compressed_size = (uLong)file_info64.compressed_size; + pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size; + + } + return err; +} +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int ZEXPORT unzGoToFirstFile (unzFile file) +{ + int err=UNZ_OK; + unz64_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int ZEXPORT unzGoToNextFile (unzFile file) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */ + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz64_s* s; + int err; + + /* We remember the 'current' position in the file so that we can jump + * back there if we fail. + */ + unz_file_info64 cur_file_infoSaved; + unz_file_info64_internal cur_file_info_internalSaved; + ZPOS64_T num_fileSaved; + ZPOS64_T pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + /* Save the current state */ + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + cur_file_infoSaved = s->cur_file_info; + cur_file_info_internalSaved = s->cur_file_info_internal; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + err = unzGetCurrentFileInfo64(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (err == UNZ_OK) + { + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + } + + /* We failed, so restore the state of the 'current file' to where we + * were. + */ + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + s->cur_file_info = cur_file_infoSaved; + s->cur_file_info_internal = cur_file_info_internalSaved; + return err; +} + + +/* +/////////////////////////////////////////// +// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net) +// I need random access +// +// Further optimization could be realized by adding an ability +// to cache the directory in memory. The goal being a single +// comprehensive file read to put the file I need in a memory. +*/ + +/* +typedef struct unz_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; // offset in file + ZPOS64_T num_of_file; // # of file +} unz_file_pos; +*/ + +extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos) +{ + unz64_s* s; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + file_pos->pos_in_zip_directory = s->pos_in_central_dir; + file_pos->num_of_file = s->num_file; + + return UNZ_OK; +} + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + int err = unzGetFilePos64(file,&file_pos64); + if (err==UNZ_OK) + { + file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory; + file_pos->num_of_file = (uLong)file_pos64.num_of_file; + } + return err; +} + +extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos) +{ + unz64_s* s; + int err; + + if (file==NULL || file_pos==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + /* jump to the right spot */ + s->pos_in_central_dir = file_pos->pos_in_zip_directory; + s->num_file = file_pos->num_of_file; + + /* set the current file */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + /* return results */ + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos) +{ + unz64_file_pos file_pos64; + if (file_pos == NULL) + return UNZ_PARAMERROR; + + file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory; + file_pos64.num_of_file = file_pos->num_of_file; + return unzGoToFilePos64(file,&file_pos64); +} + +/* +// Unzip Helper Functions - should be here? +/////////////////////////////////////////// +*/ + +/* + Read the local header of the current zipfile + Check the coherency of the local header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in local header + (filename and size of extra field data) +*/ +local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar, + ZPOS64_T * poffset_local_extrafield, + uInt * psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + { + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + } + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method, + int* level, int raw, const char* password) +{ + int err=UNZ_OK; + uInt iSizeVar; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + ZPOS64_T offset_local_extrafield; /* offset of the local extra field */ + uInt size_local_extrafield; /* size of the local extra field */ +# ifndef NOUNCRYPT + char source[12]; +# else + if (password != NULL) + return UNZ_PARAMERROR; +# endif + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + pfile_in_zip_read_info->raw=raw; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + TRYFREE(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if (method!=NULL) + *method = (int)s->cur_file_info.compression_method; + + if (level!=NULL) + { + *level = 6; + switch (s->cur_file_info.flag & 0x06) + { + case 6 : *level = 1; break; + case 4 : *level = 2; break; + case 2 : *level = 9; break; + } + } + + if ((s->cur_file_info.compression_method!=0) && +/* #ifdef HAVE_BZIP2 */ + (s->cur_file_info.compression_method!=Z_BZIP2ED) && +/* #endif */ + (s->cur_file_info.compression_method!=Z_DEFLATED)) + + err=UNZ_BADZIPFILE; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->total_out_64=0; + pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method; + pfile_in_zip_read_info->filestream=s->filestream; + pfile_in_zip_read_info->z_filefunc=s->z_filefunc; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw)) + { +#ifdef HAVE_BZIP2 + pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0; + pfile_in_zip_read_info->bstream.bzfree = (free_func)0; + pfile_in_zip_read_info->bstream.opaque = (voidpf)0; + pfile_in_zip_read_info->bstream.state = (voidpf)0; + + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = (voidpf)0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } +#else + pfile_in_zip_read_info->raw=1; +#endif + } + else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw)) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidpf)0; + pfile_in_zip_read_info->stream.next_in = 0; + pfile_in_zip_read_info->stream.avail_in = 0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=Z_DEFLATED; + else + { + TRYFREE(pfile_in_zip_read_info); + return err; + } + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + s->pfile_in_zip_read = pfile_in_zip_read_info; + s->encrypted = 0; + +# ifndef NOUNCRYPT + if (password != NULL) + { + int i; + s->pcrc_32_tab = get_crc_table(); + init_keys(password,s->keys,s->pcrc_32_tab); + if (ZSEEK64(s->z_filefunc, s->filestream, + s->pfile_in_zip_read->pos_in_zipfile + + s->pfile_in_zip_read->byte_before_the_zipfile, + SEEK_SET)!=0) + return UNZ_INTERNALERROR; + if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12) + return UNZ_INTERNALERROR; + + for (i = 0; i<12; i++) + zdecode(s->keys,s->pcrc_32_tab,source[i]); + + s->pfile_in_zip_read->pos_in_zipfile+=12; + s->encrypted=1; + } +# endif + + + return UNZ_OK; +} + +extern int ZEXPORT unzOpenCurrentFile (unzFile file) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL); +} + +extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password) +{ + return unzOpenCurrentFile3(file, NULL, NULL, 0, password); +} + +extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw) +{ + return unzOpenCurrentFile3(file, method, level, raw, NULL); +} + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + s=(unz64_s*)file; + if (file==NULL) + return 0; //UNZ_PARAMERROR; + pfile_in_zip_read_info=s->pfile_in_zip_read; + if (pfile_in_zip_read_info==NULL) + return 0; //UNZ_PARAMERROR; + return pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile; +} + +/** Addition for GDAL : END */ + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->read_buffer == NULL) return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Bytef*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if ((len>pfile_in_zip_read_info->rest_read_uncompressed) && + (!(pfile_in_zip_read_info->raw))) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + if ((len>pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in) && + (pfile_in_zip_read_info->raw)) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_compressed+ + pfile_in_zip_read_info->stream.avail_in; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->read_buffer, + uReadThis)!=uReadThis) + return UNZ_ERRNO; + + +# ifndef NOUNCRYPT + if(s->encrypted) + { + uInt i; + for(i=0;iread_buffer[i] = + zdecode(s->keys,s->pcrc_32_tab, + pfile_in_zip_read_info->read_buffer[i]); + } +# endif + + + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Bytef*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw)) + { + uInt uDoCopy,i ; + + if ((pfile_in_zip_read_info->stream.avail_in == 0) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + return (iRead==0) ? UNZ_EOF : iRead; + + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + uLong uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + uLong uOutThis; + + pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in; + pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in; + pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in; + pfile_in_zip_read_info->bstream.total_in_hi32 = 0; + pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out; + pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out; + pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out; + pfile_in_zip_read_info->bstream.total_out_hi32 = 0; + + uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32; + bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out; + + err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream); + + uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis)); + pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis; + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in; + pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in; + pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32; + pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out; + pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out; + pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32; + + if (err==BZ_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=BZ_OK) + break; +#endif + } // end Z_BZIP2ED + else + { + ZPOS64_T uTotalOutBefore,uTotalOutAfter; + const Bytef *bufBefore; + ZPOS64_T uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL)) + err = Z_DATA_ERROR; + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern z_off_t ZEXPORT unztell (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (z_off_t)pfile_in_zip_read_info->stream.total_out; +} + +extern ZPOS64_T ZEXPORT unztell64 (unzFile file) +{ + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return (ZPOS64_T)-1; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return (ZPOS64_T)-1; + + return pfile_in_zip_read_info->total_out_64; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int ZEXPORT unzeof (unzFile file) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* +Read extra field from the current file (opened by unzOpenCurrentFile) +This is the local-header version of the extra field (sometimes, there is +more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len) +{ + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + uInt read_now; + ZPOS64_T size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (ZSEEK64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield, + ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (ZREAD64(pfile_in_zip_read_info->z_filefunc, + pfile_in_zip_read_info->filestream, + buf,read_now)!=read_now) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int ZEXPORT unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz64_s* s; + file_in_zip64_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) && + (!pfile_in_zip_read_info->raw)) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + TRYFREE(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED) + inflateEnd(&pfile_in_zip_read_info->stream); +#ifdef HAVE_BZIP2 + else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED) + BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream); +#endif + + + pfile_in_zip_read_info->stream_initialised = 0; + TRYFREE(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf) +{ + unz64_s* s; + uLong uReadThis ; + if (file==NULL) + return (int)UNZ_PARAMERROR; + s=(unz64_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* Additions by RX '2004 */ +extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file) +{ + unz64_s* s; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + s=(unz64_s*)file; + if (!s->current_file_ok) + return 0; + if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff) + if (s->num_file==s->gi.number_entry) + return 0; + return s->pos_in_central_dir; +} + +extern uLong ZEXPORT unzGetOffset (unzFile file) +{ + ZPOS64_T offset64; + + if (file==NULL) + return 0; //UNZ_PARAMERROR; + offset64 = unzGetOffset64(file); + return (uLong)offset64; +} + +extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos) +{ + unz64_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz64_s*)file; + + s->pos_in_central_dir = pos; + s->num_file = s->gi.number_entry; /* hack */ + err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos) +{ + return unzSetOffset64(file,pos); +} diff --git a/Carthage/Checkouts/UnzipKit/Lib/MiniZip/unzip.h b/Carthage/Checkouts/UnzipKit/Lib/MiniZip/unzip.h new file mode 100755 index 0000000..3183968 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Lib/MiniZip/unzip.h @@ -0,0 +1,437 @@ +/* unzip.h -- IO for uncompress .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications of Unzip for Zip64 + Copyright (C) 2007-2008 Even Rouault + + Modifications for Zip64 support on both zip and unzip + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------------- + + Changes + + See header of unzip64.c + +*/ + +#ifndef _unz64_H +#define _unz64_H + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef voidp unzFile; +#endif + + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info64_s +{ + ZPOS64_T number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info64; + +typedef struct unz_global_info_s +{ + uLong number_entry; /* total number of entries in + the central dir on this disk */ + uLong size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info64_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + ZPOS64_T compressed_size; /* compressed size 8 bytes */ + ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info64; + +typedef struct unz_file_info_s +{ + uLong version; /* version made by 2 bytes */ + uLong version_needed; /* version needed to extract 2 bytes */ + uLong flag; /* general purpose bit flag 2 bytes */ + uLong compression_method; /* compression method 2 bytes */ + uLong dosDate; /* last mod file date in Dos fmt 4 bytes */ + uLong crc; /* crc-32 4 bytes */ + uLong compressed_size; /* compressed size 4 bytes */ + uLong uncompressed_size; /* uncompressed size 4 bytes */ + uLong size_filename; /* filename length 2 bytes */ + uLong size_file_extra; /* extra field length 2 bytes */ + uLong size_file_comment; /* file comment length 2 bytes */ + + uLong disk_num_start; /* disk number start 2 bytes */ + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ + + tm_unz tmu_date; +} unz_file_info; + +extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1, + const char* fileName2, + int iCaseSensitivity)); +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + + +extern unzFile ZEXPORT unzOpen OF((const char *path)); +extern unzFile ZEXPORT unzOpen64 OF((const void *path)); +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer + "zlib/zlib113.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. + the "64" function take a const void* pointer, because the path is just the + value passed to the open64_file_func callback. + Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path + is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char* + does not describe the reality +*/ + + +extern unzFile ZEXPORT unzOpen2 OF((const char *path, + zlib_filefunc_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unzOpen, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern unzFile ZEXPORT unzOpen2_64 OF((const void *path, + zlib_filefunc64_def* pzlib_filefunc_def)); +/* + Open a Zip file, like unz64Open, but provide a set of file low level API + for read/write the zip file (see ioapi.h) +*/ + +extern int ZEXPORT unzClose OF((unzFile file)); +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int ZEXPORT unzGetGlobalInfo OF((unzFile file, + unz_global_info *pglobal_info)); + +extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file, + unz_global_info64 *pglobal_info)); +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int ZEXPORT unzGetGlobalComment OF((unzFile file, + char *szComment, + uLong uSizeBuf)); +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int ZEXPORT unzGoToFirstFile OF((unzFile file)); +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int ZEXPORT unzGoToNextFile OF((unzFile file)); +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int ZEXPORT unzLocateFile OF((unzFile file, + const char *szFileName, + int iCaseSensitivity)); +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +/* ****************************************** */ +/* Ryan supplied functions */ +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_pos_s +{ + uLong pos_in_zip_directory; /* offset in zip file directory */ + uLong num_of_file; /* # of file */ +} unz_file_pos; + +extern int ZEXPORT unzGetFilePos( + unzFile file, + unz_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos( + unzFile file, + unz_file_pos* file_pos); + +typedef struct unz64_file_pos_s +{ + ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */ + ZPOS64_T num_of_file; /* # of file */ +} unz64_file_pos; + +extern int ZEXPORT unzGetFilePos64( + unzFile file, + unz64_file_pos* file_pos); + +extern int ZEXPORT unzGoToFilePos64( + unzFile file, + const unz64_file_pos* file_pos); + +/* ****************************************** */ + +extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file, + unz_file_info64 *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); + +extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file, + unz_file_info *pfile_info, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize)); +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + + +/** Addition for GDAL : START */ + +extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file)); + +/** Addition for GDAL : END */ + + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int ZEXPORT unzOpenCurrentFile OF((unzFile file)); +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file, + const char* password)); +/* + Open for reading data the current file in the zipfile. + password is a crypting password + If there is no error, the return value is UNZ_OK. +*/ + +extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file, + int* method, + int* level, + int raw)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + +extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file, + int* method, + int* level, + int raw, + const char* password)); +/* + Same than unzOpenCurrentFile, but open for read raw the file (not uncompress) + if raw==1 + *method will receive method of compression, *level will receive level of + compression + note : you can set level parameter as NULL (if you did not want known level, + but you CANNOT set method parameter as NULL +*/ + + +extern int ZEXPORT unzCloseCurrentFile OF((unzFile file)); +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + +extern int ZEXPORT unzReadCurrentFile OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read bytes from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern z_off_t ZEXPORT unztell OF((unzFile file)); + +extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file)); +/* + Give the current position in uncompressed data +*/ + +extern int ZEXPORT unzeof OF((unzFile file)); +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file, + voidp buf, + unsigned len)); +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ + +/***************************************************************************/ + +/* Get the current file offset */ +extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file); +extern uLong ZEXPORT unzGetOffset (unzFile file); + +/* Set the current file offset */ +extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos); +extern int ZEXPORT unzSetOffset (unzFile file, uLong pos); + + + +#ifdef __cplusplus +} +#endif + +#endif /* _unz64_H */ diff --git a/Carthage/Checkouts/UnzipKit/Lib/MiniZip/zip.c b/Carthage/Checkouts/UnzipKit/Lib/MiniZip/zip.c new file mode 100755 index 0000000..7ce4068 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Lib/MiniZip/zip.c @@ -0,0 +1,2004 @@ +/* zip.c -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + Changes + Oct-2009 - Mathias Svensson - Remove old C style function prototypes + Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives + Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions. + Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data + It is used when recreting zip archive with RAW when deleting items from a zip. + ZIP64 data is automaticly added to items that needs it, and existing ZIP64 data need to be removed. + Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required) + Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer + +*/ + + +#include +#include +#include +#include +#include "zlib.h" +#include "zip.h" + +#ifdef STDC +# include +# include +# include +#endif +#ifdef NO_ERRNO_H + extern int errno; +#else +# include +#endif + + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +#ifndef VERSIONMADEBY +# define VERSIONMADEBY (0x0) /* platform depedent */ +#endif + +#ifndef Z_BUFSIZE +#define Z_BUFSIZE (64*1024) //(16384) +#endif + +#ifndef Z_MAXFILENAMEINZIP +#define Z_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +/* +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) +*/ + +/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */ + + +// NOT sure that this work on ALL platform +#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32)) + +#ifndef SEEK_CUR +#define SEEK_CUR 1 +#endif + +#ifndef SEEK_END +#define SEEK_END 2 +#endif + +#ifndef SEEK_SET +#define SEEK_SET 0 +#endif + +#ifndef DEF_MEM_LEVEL +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +#endif +const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll"; + + +#define SIZEDATA_INDATABLOCK (4096-(4*4)) + +#define LOCALHEADERMAGIC (0x04034b50) +#define CENTRALHEADERMAGIC (0x02014b50) +#define ENDHEADERMAGIC (0x06054b50) +#define ZIP64ENDHEADERMAGIC (0x6064b50) +#define ZIP64ENDLOCHEADERMAGIC (0x7064b50) + +#define FLAG_LOCALHEADER_OFFSET (0x06) +#define CRC_LOCALHEADER_OFFSET (0x0e) + +#define SIZECENTRALHEADER (0x2e) /* 46 */ + +typedef struct linkedlist_datablock_internal_s +{ + struct linkedlist_datablock_internal_s* next_datablock; + uLong avail_in_this_block; + uLong filled_in_this_block; + uLong unused; /* for future use and alignement */ + unsigned char data[SIZEDATA_INDATABLOCK]; +} linkedlist_datablock_internal; + +typedef struct linkedlist_data_s +{ + linkedlist_datablock_internal* first_block; + linkedlist_datablock_internal* last_block; +} linkedlist_data; + + +typedef struct +{ + z_stream stream; /* zLib stream structure for inflate */ +#ifdef HAVE_BZIP2 + bz_stream bstream; /* bzLib stream structure for bziped */ +#endif + + int stream_initialised; /* 1 is stream is initialised */ + uInt pos_in_buffered_data; /* last written byte in buffered_data */ + + ZPOS64_T pos_local_header; /* offset of the local header of the file + currenty writing */ + char* central_header; /* central header data for the current file */ + uLong size_centralExtra; + uLong size_centralheader; /* size of the central header for cur file */ + uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */ + uLong flag; /* flag of the file currently writing */ + + int method; /* compression method of file currenty wr.*/ + int raw; /* 1 for directly writing raw data */ + Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/ + uLong dosDate; + uLong crc32; + int encrypt; + int zip64; /* Add ZIP64 extened information in the extra field */ + ZPOS64_T pos_zip64extrainfo; + ZPOS64_T totalCompressedData; + ZPOS64_T totalUncompressedData; +#ifndef NOCRYPT + unsigned long keys[3]; /* keys defining the pseudo-random sequence */ + const unsigned long* pcrc_32_tab; + int crypt_header_size; +#endif +} curfile64_info; + +typedef struct +{ + zlib_filefunc64_32_def z_filefunc; + voidpf filestream; /* io structore of the zipfile */ + linkedlist_data central_dir;/* datablock with central dir in construction*/ + int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/ + curfile64_info ci; /* info on the file curretly writing */ + + ZPOS64_T begin_pos; /* position of the beginning of the zipfile */ + ZPOS64_T add_position_when_writting_offset; + ZPOS64_T number_entry; + +#ifndef NO_ADDFILEINEXISTINGZIP + char *globalcomment; +#endif + +} zip64_internal; + + +#ifndef NOCRYPT +#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED +#include "crypt.h" +#endif + +local linkedlist_datablock_internal* allocate_new_datablock() +{ + linkedlist_datablock_internal* ldi; + ldi = (linkedlist_datablock_internal*) + ALLOC(sizeof(linkedlist_datablock_internal)); + if (ldi!=NULL) + { + ldi->next_datablock = NULL ; + ldi->filled_in_this_block = 0 ; + ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ; + } + return ldi; +} + +local void free_datablock(linkedlist_datablock_internal* ldi) +{ + while (ldi!=NULL) + { + linkedlist_datablock_internal* ldinext = ldi->next_datablock; + TRYFREE(ldi); + ldi = ldinext; + } +} + +local void init_linkedlist(linkedlist_data* ll) +{ + ll->first_block = ll->last_block = NULL; +} + +local void free_linkedlist(linkedlist_data* ll) +{ + free_datablock(ll->first_block); + ll->first_block = ll->last_block = NULL; +} + + +local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len) +{ + linkedlist_datablock_internal* ldi; + const unsigned char* from_copy; + + if (ll==NULL) + return ZIP_INTERNALERROR; + + if (ll->last_block == NULL) + { + ll->first_block = ll->last_block = allocate_new_datablock(); + if (ll->first_block == NULL) + return ZIP_INTERNALERROR; + } + + ldi = ll->last_block; + from_copy = (unsigned char*)buf; + + while (len>0) + { + uInt copy_this; + uInt i; + unsigned char* to_copy; + + if (ldi->avail_in_this_block==0) + { + ldi->next_datablock = allocate_new_datablock(); + if (ldi->next_datablock == NULL) + return ZIP_INTERNALERROR; + ldi = ldi->next_datablock ; + ll->last_block = ldi; + } + + if (ldi->avail_in_this_block < len) + copy_this = (uInt)ldi->avail_in_this_block; + else + copy_this = (uInt)len; + + to_copy = &(ldi->data[ldi->filled_in_this_block]); + + for (i=0;ifilled_in_this_block += copy_this; + ldi->avail_in_this_block -= copy_this; + from_copy += copy_this ; + len -= copy_this; + } + return ZIP_OK; +} + + + +/****************************************************************************/ + +#ifndef NO_ADDFILEINEXISTINGZIP +/* =========================================================================== + Inputs a long in LSB order to the given file + nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T) +*/ + +local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)); +local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte) +{ + unsigned char buf[8]; + int n; + for (n = 0; n < nbByte; n++) + { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + if (x != 0) + { /* data overflow - hack for ZIP64 (X Roche) */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } + + if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte) + return ZIP_ERRNO; + else + return ZIP_OK; +} + +local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte)); +local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte) +{ + unsigned char* buf=(unsigned char*)dest; + int n; + for (n = 0; n < nbByte; n++) { + buf[n] = (unsigned char)(x & 0xff); + x >>= 8; + } + + if (x != 0) + { /* data overflow - hack for ZIP64 */ + for (n = 0; n < nbByte; n++) + { + buf[n] = 0xff; + } + } +} + +/****************************************************************************/ + + +local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm) +{ + uLong year = (uLong)ptm->tm_year; + if (year>=1980) + year-=1980; + else if (year>=80) + year-=80; + return + (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) | + ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour)); +} + + +/****************************************************************************/ + +local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)); + +local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi) +{ + unsigned char c; + int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1); + if (err==1) + { + *pi = (int)c; + return ZIP_OK; + } + else + { + if (ZERROR64(*pzlib_filefunc_def,filestream)) + return ZIP_ERRNO; + else + return ZIP_EOF; + } +} + + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); + +local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x ; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX)); + +local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX) +{ + uLong x ; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (uLong)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((uLong)i)<<24; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + return err; +} + +local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)); + + +local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX) +{ + ZPOS64_T x; + int i = 0; + int err; + + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x = (ZPOS64_T)i; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<8; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<16; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<24; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<32; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<40; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<48; + + if (err==ZIP_OK) + err = zip64local_getByte(pzlib_filefunc_def,filestream,&i); + x += ((ZPOS64_T)i)<<56; + + if (err==ZIP_OK) + *pX = x; + else + *pX = 0; + + return err; +} + +#ifndef BUFREADCOMMENT +#define BUFREADCOMMENT (0x400) +#endif +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); + +local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + TRYFREE(buf); + return uPosFound; +} + +/* +Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before +the global comment) +*/ +local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)); + +local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream) +{ + unsigned char* buf; + ZPOS64_T uSizeFile; + ZPOS64_T uBackRead; + ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */ + ZPOS64_T uPosFound=0; + uLong uL; + ZPOS64_T relativeOffset; + + if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0) + return 0; + + uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos); + if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0) + break; + + if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + { + // Signature "0x07064b50" Zip64 end of central directory locater + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07)) + { + uPosFound = uReadPos+i; + break; + } + } + + if (uPosFound!=0) + break; + } + + TRYFREE(buf); + if (uPosFound == 0) + return 0; + + /* Zip64 end of central directory locator */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature, already checked */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + /* number of the disk with the start of the zip64 end of central directory */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 0) + return 0; + + /* relative offset of the zip64 end of central directory record */ + if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK) + return 0; + + /* total number of disks */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + if (uL != 1) + return 0; + + /* Goto Zip64 end of central directory record */ + if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0) + return 0; + + /* the signature */ + if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK) + return 0; + + if (uL != 0x06064b50) // signature of 'Zip64 end of central directory' + return 0; + + return relativeOffset; +} + +int LoadCentralDirectoryRecord(zip64_internal* pziinit) +{ + int err=ZIP_OK; + ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/ + + ZPOS64_T size_central_dir; /* size of the central directory */ + ZPOS64_T offset_central_dir; /* offset of start of central directory */ + ZPOS64_T central_pos; + uLong uL; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + ZPOS64_T number_entry; + ZPOS64_T number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + uLong VersionMadeBy; + uLong VersionNeeded; + uLong size_comment; + + int hasZIP64Record = 0; + + // check first if we find a ZIP64 record + central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream); + if(central_pos > 0) + { + hasZIP64Record = 1; + } + else if(central_pos == 0) + { + central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream); + } + +/* disable to allow appending to empty ZIP archive + if (central_pos==0) + err=ZIP_ERRNO; +*/ + + if(hasZIP64Record) + { + ZPOS64_T sizeEndOfCentralDirectory; + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* size of zip64 end of central directory record */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version made by */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK) + err=ZIP_ERRNO; + + /* version needed to extract */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory on this disk */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central directory */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK) + err=ZIP_ERRNO; + + // TODO.. + // read the comment from the standard central header. + size_comment = 0; + } + else + { + // Read End of central Directory info + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0) + err=ZIP_ERRNO; + + /* the signature, already checked */ + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of this disk */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK) + err=ZIP_ERRNO; + + /* number of the disk with the start of the central directory */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK) + err=ZIP_ERRNO; + + /* total number of entries in the central dir on this disk */ + number_entry = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry = uL; + + /* total number of entries in the central dir */ + number_entry_CD = 0; + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + number_entry_CD = uL; + + if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0)) + err=ZIP_BADZIPFILE; + + /* size of the central directory */ + size_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + size_central_dir = uL; + + /* offset of start of central directory with respect to the starting disk number */ + offset_central_dir = 0; + if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK) + err=ZIP_ERRNO; + else + offset_central_dir = uL; + + + /* zipfile global comment length */ + if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK) + err=ZIP_ERRNO; + } + + if ((central_posz_filefunc, pziinit->filestream); + return ZIP_ERRNO; + } + + if (size_comment>0) + { + pziinit->globalcomment = (char*)ALLOC(size_comment+1); + if (pziinit->globalcomment) + { + size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment); + pziinit->globalcomment[size_comment]=0; + } + } + + byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir); + pziinit->add_position_when_writting_offset = byte_before_the_zipfile; + + { + ZPOS64_T size_central_dir_to_read = size_central_dir; + size_t buf_size = SIZEDATA_INDATABLOCK; + void* buf_read = (void*)ALLOC(buf_size); + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + while ((size_central_dir_to_read>0) && (err==ZIP_OK)) + { + ZPOS64_T read_this = SIZEDATA_INDATABLOCK; + if (read_this > size_central_dir_to_read) + read_this = size_central_dir_to_read; + + if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this) + err=ZIP_ERRNO; + + if (err==ZIP_OK) + err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this); + + size_central_dir_to_read-=read_this; + } + TRYFREE(buf_read); + } + pziinit->begin_pos = byte_before_the_zipfile; + pziinit->number_entry = number_entry_CD; + + if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0) + err=ZIP_ERRNO; + + return err; +} + + +#endif /* !NO_ADDFILEINEXISTINGZIP*/ + + +/************************************************************/ +extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def) +{ + zip64_internal ziinit; + zip64_internal* zi; + int err=ZIP_OK; + + ziinit.z_filefunc.zseek32_file = NULL; + ziinit.z_filefunc.ztell32_file = NULL; + if (pzlib_filefunc64_32_def==NULL) + fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64); + else + ziinit.z_filefunc = *pzlib_filefunc64_32_def; + + ziinit.filestream = ZOPEN64(ziinit.z_filefunc, + pathname, + (append == APPEND_STATUS_CREATE) ? + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) : + (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING)); + + if (ziinit.filestream == NULL) + return NULL; + + if (append == APPEND_STATUS_CREATEAFTER) + ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END); + + ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream); + ziinit.in_opened_file_inzip = 0; + ziinit.ci.stream_initialised = 0; + ziinit.number_entry = 0; + ziinit.add_position_when_writting_offset = 0; + init_linkedlist(&(ziinit.central_dir)); + + + + zi = (zip64_internal*)ALLOC(sizeof(zip64_internal)); + if (zi==NULL) + { + ZCLOSE64(ziinit.z_filefunc,ziinit.filestream); + return NULL; + } + + /* now we add file in a zipfile */ +# ifndef NO_ADDFILEINEXISTINGZIP + ziinit.globalcomment = NULL; + if (append == APPEND_STATUS_ADDINZIP) + { + // Read and Cache Central Directory Records + err = LoadCentralDirectoryRecord(&ziinit); + } + + if (globalcomment) + { + *globalcomment = ziinit.globalcomment; + } +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + + if (err != ZIP_OK) + { +# ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(ziinit.globalcomment); +# endif /* !NO_ADDFILEINEXISTINGZIP*/ + TRYFREE(zi); + return NULL; + } + else + { + *zi = ziinit; + return (zipFile)zi; + } +} + +extern zipFile ZEXPORT zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def) +{ + if (pzlib_filefunc32_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def); + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + +extern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def) +{ + if (pzlib_filefunc_def != NULL) + { + zlib_filefunc64_32_def zlib_filefunc64_32_def_fill; + zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def; + zlib_filefunc64_32_def_fill.ztell32_file = NULL; + zlib_filefunc64_32_def_fill.zseek32_file = NULL; + return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill); + } + else + return zipOpen3(pathname, append, globalcomment, NULL); +} + + + +extern zipFile ZEXPORT zipOpen (const char* pathname, int append) +{ + return zipOpen3((const void*)pathname,append,NULL,NULL); +} + +extern zipFile ZEXPORT zipOpen64 (const void* pathname, int append) +{ + return zipOpen3(pathname,append,NULL,NULL); +} + +int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local) +{ + /* write the local header */ + int err; + uInt size_filename = (uInt)strlen(filename); + uInt size_extrafield = size_extrafield_local; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4); + + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2); + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4); + + // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */ + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */ + } + if (err==ZIP_OK) + { + if(zi->ci.zip64) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */ + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */ + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2); + + if(zi->ci.zip64) + { + size_extrafield += 20; + } + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2); + + if ((err==ZIP_OK) && (size_filename > 0)) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename) + err = ZIP_ERRNO; + } + + if ((err==ZIP_OK) && (size_extrafield_local > 0)) + { + if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local) + err = ZIP_ERRNO; + } + + + if ((err==ZIP_OK) && (zi->ci.zip64)) + { + // write the Zip64 extended info + short HeaderID = 1; + short DataSize = 16; + ZPOS64_T CompressedSize = 0; + ZPOS64_T UncompressedSize = 0; + + // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file) + zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2); + + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8); + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8); + } + + return err; +} + +/* + NOTE. + When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped + before calling this function it can be done with zipRemoveExtraInfoBlock + + It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize + unnecessary allocations. + */ +extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase, int zip64) +{ + zip64_internal* zi; + uInt size_filename; + uInt size_comment; + uInt i; + int err = ZIP_OK; + +# ifdef NOCRYPT + if (password != NULL) + return ZIP_PARAMERROR; +# endif + + if (file == NULL) + return ZIP_PARAMERROR; + +#ifdef HAVE_BZIP2 + if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED)) + return ZIP_PARAMERROR; +#else + if ((method!=0) && (method!=Z_DEFLATED)) + return ZIP_PARAMERROR; +#endif + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + if (err != ZIP_OK) + return err; + } + + if (filename==NULL) + filename="-"; + + if (comment==NULL) + size_comment = 0; + else + size_comment = (uInt)strlen(comment); + + size_filename = (uInt)strlen(filename); + + if (zipfi == NULL) + zi->ci.dosDate = 0; + else + { + if (zipfi->dosDate != 0) + zi->ci.dosDate = zipfi->dosDate; + else + zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date); + } + + zi->ci.flag = flagBase; + if ((level==8) || (level==9)) + zi->ci.flag |= 2; + if (level==2) + zi->ci.flag |= 4; + if (level==1) + zi->ci.flag |= 6; + if (password != NULL) + zi->ci.flag |= 1; + + zi->ci.crc32 = 0; + zi->ci.method = method; + zi->ci.encrypt = 0; + zi->ci.stream_initialised = 0; + zi->ci.pos_in_buffered_data = 0; + zi->ci.raw = raw; + zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream); + + zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment; + zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data + + zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree); + + zi->ci.size_centralExtra = size_extrafield_global; + zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4); + /* version info */ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2); + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2); + zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2); + zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2); + zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4); + zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/ + zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/ + zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2); + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2); + zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2); + zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/ + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2); + else + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2); + + if (zipfi==NULL) + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4); + else + zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4); + + if(zi->ci.pos_local_header >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4); + else + zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset,4); + + for (i=0;ici.central_header+SIZECENTRALHEADER+i) = *(filename+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+i) = + *(((const char*)extrafield_global)+i); + + for (i=0;ici.central_header+SIZECENTRALHEADER+size_filename+ + size_extrafield_global+i) = *(comment+i); + if (zi->ci.central_header == NULL) + return ZIP_INTERNALERROR; + + zi->ci.zip64 = zip64; + zi->ci.totalCompressedData = 0; + zi->ci.totalUncompressedData = 0; + zi->ci.pos_zip64extrainfo = 0; + + err = Write_LocalFileHeader(zi, filename, size_extrafield_local, extrafield_local); + +#ifdef HAVE_BZIP2 + zi->ci.bstream.avail_in = (uInt)0; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + zi->ci.bstream.total_in_hi32 = 0; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_out_hi32 = 0; + zi->ci.bstream.total_out_lo32 = 0; +#endif + + zi->ci.stream.avail_in = (uInt)0; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + zi->ci.stream.total_in = 0; + zi->ci.stream.total_out = 0; + zi->ci.stream.data_type = Z_BINARY; + +#ifdef HAVE_BZIP2 + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) +#else + if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) +#endif + { + if(zi->ci.method == Z_DEFLATED) + { + zi->ci.stream.zalloc = (alloc_func)0; + zi->ci.stream.zfree = (free_func)0; + zi->ci.stream.opaque = (voidpf)0; + + if (windowBits>0) + windowBits = -windowBits; + + err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy); + + if (err==Z_OK) + zi->ci.stream_initialised = Z_DEFLATED; + } + else if(zi->ci.method == Z_BZIP2ED) + { +#ifdef HAVE_BZIP2 + // Init BZip stuff here + zi->ci.bstream.bzalloc = 0; + zi->ci.bstream.bzfree = 0; + zi->ci.bstream.opaque = (voidpf)0; + + err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35); + if(err == BZ_OK) + zi->ci.stream_initialised = Z_BZIP2ED; +#endif + } + + } + +# ifndef NOCRYPT + zi->ci.crypt_header_size = 0; + if ((err==Z_OK) && (password != NULL)) + { + unsigned char bufHead[RAND_HEAD_LEN]; + unsigned int sizeHead; + zi->ci.encrypt = 1; + zi->ci.pcrc_32_tab = get_crc_table(); + /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/ + + sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting); + zi->ci.crypt_header_size = sizeHead; + + if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead) + err = ZIP_ERRNO; + } +# endif + + if (err==Z_OK) + zi->in_opened_file_inzip = 1; + return err; +} + +extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, + uLong versionMadeBy, uLong flagBase) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, versionMadeBy, flagBase, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, + int windowBits,int memLevel, int strategy, + const char* password, uLong crcForCrypting, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + windowBits, memLevel, strategy, + password, crcForCrypting, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); +} + +extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void* extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int raw, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, raw, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level, int zip64) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, zip64); +} + +extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi, + const void* extrafield_local, uInt size_extrafield_local, + const void*extrafield_global, uInt size_extrafield_global, + const char* comment, int method, int level) +{ + return zipOpenNewFileInZip4_64 (file, filename, zipfi, + extrafield_local, size_extrafield_local, + extrafield_global, size_extrafield_global, + comment, method, level, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + NULL, 0, VERSIONMADEBY, 0, 0); +} + +local int zip64FlushWriteBuffer(zip64_internal* zi) +{ + int err=ZIP_OK; + + if (zi->ci.encrypt != 0) + { +#ifndef NOCRYPT + uInt i; + int t; + for (i=0;ici.pos_in_buffered_data;i++) + zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t); +#endif + } + + if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data) + err = ZIP_ERRNO; + + zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data; + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED) + { + zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32; + zi->ci.bstream.total_in_lo32 = 0; + zi->ci.bstream.total_in_hi32 = 0; + } + else +#endif + { + zi->ci.totalUncompressedData += zi->ci.stream.total_in; + zi->ci.stream.total_in = 0; + } + + + zi->ci.pos_in_buffered_data = 0; + + return err; +} + +extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len) +{ + zip64_internal* zi; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + + zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len); + +#ifdef HAVE_BZIP2 + if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw)) + { + zi->ci.bstream.next_in = (void*)buf; + zi->ci.bstream.avail_in = len; + err = BZ_RUN_OK; + + while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0)) + { + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + + + if(err != BZ_RUN_OK) + break; + + if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32; +// uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_RUN); + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ; + } + } + + if(err == BZ_RUN_OK) + err = ZIP_OK; + } + else +#endif + { + zi->ci.stream.next_in = (Bytef*)buf; + zi->ci.stream.avail_in = len; + + while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0)) + { + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + + + if(err != ZIP_OK) + break; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + uLong uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_NO_FLUSH); + if(uTotalOutBefore > zi->ci.stream.total_out) + { + int bBreak = 0; + bBreak++; + } + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + else + { + uInt copy_this,i; + if (zi->ci.stream.avail_in < zi->ci.stream.avail_out) + copy_this = zi->ci.stream.avail_in; + else + copy_this = zi->ci.stream.avail_out; + + for (i = 0; i < copy_this; i++) + *(((char*)zi->ci.stream.next_out)+i) = + *(((const char*)zi->ci.stream.next_in)+i); + { + zi->ci.stream.avail_in -= copy_this; + zi->ci.stream.avail_out-= copy_this; + zi->ci.stream.next_in+= copy_this; + zi->ci.stream.next_out+= copy_this; + zi->ci.stream.total_in+= copy_this; + zi->ci.stream.total_out+= copy_this; + zi->ci.pos_in_buffered_data += copy_this; + } + } + }// while(...) + } + + return err; +} + +extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32) +{ + return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32); +} + +extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32) +{ + zip64_internal* zi; + ZPOS64_T compressed_size; + uLong invalidValue = 0xffffffff; + short datasize = 0; + int err=ZIP_OK; + + if (file == NULL) + return ZIP_PARAMERROR; + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 0) + return ZIP_PARAMERROR; + zi->ci.stream.avail_in = 0; + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + while (err==ZIP_OK) + { + uLong uTotalOutBefore; + if (zi->ci.stream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.stream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.stream.next_out = zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.stream.total_out; + err=deflate(&zi->ci.stream, Z_FINISH); + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ; + } + } + else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { +#ifdef HAVE_BZIP2 + err = BZ_FINISH_OK; + while (err==BZ_FINISH_OK) + { + uLong uTotalOutBefore; + if (zi->ci.bstream.avail_out == 0) + { + if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO) + err = ZIP_ERRNO; + zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE; + zi->ci.bstream.next_out = (char*)zi->ci.buffered_data; + } + uTotalOutBefore = zi->ci.bstream.total_out_lo32; + err=BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH); + if(err == BZ_STREAM_END) + err = Z_STREAM_END; + + zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore); + } + + if(err == BZ_FINISH_OK) + err = ZIP_OK; +#endif + } + + if (err==Z_STREAM_END) + err=ZIP_OK; /* this is normal */ + + if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK)) + { + if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO) + err = ZIP_ERRNO; + } + + if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw)) + { + int tmp_err = deflateEnd(&zi->ci.stream); + if (err == ZIP_OK) + err = tmp_err; + zi->ci.stream_initialised = 0; + } +#ifdef HAVE_BZIP2 + else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw)) + { + int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream); + if (err==ZIP_OK) + err = tmperr; + zi->ci.stream_initialised = 0; + } +#endif + + if (!zi->ci.raw) + { + crc32 = (uLong)zi->ci.crc32; + uncompressed_size = zi->ci.totalUncompressedData; + } + compressed_size = zi->ci.totalCompressedData; + +# ifndef NOCRYPT + compressed_size += zi->ci.crypt_header_size; +# endif + + // update Current Item crc and sizes, + if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff) + { + /*version Made by*/ + zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2); + /*version needed*/ + zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2); + + } + + zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/ + + + if(compressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/ + + /// set internal file attributes field + if (zi->ci.stream.data_type == Z_ASCII) + zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2); + + if(uncompressed_size >= 0xffffffff) + zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/ + else + zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/ + + // Add ZIP64 extra info field for uncompressed size + if(uncompressed_size >= 0xffffffff) + datasize += 8; + + // Add ZIP64 extra info field for compressed size + if(compressed_size >= 0xffffffff) + datasize += 8; + + // Add ZIP64 extra info field for relative offset to local file header of current file + if(zi->ci.pos_local_header >= 0xffffffff) + datasize += 8; + + if(datasize > 0) + { + char* p = NULL; + + if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree) + { + // we can not write more data to the buffer that we have room for. + return ZIP_BADZIPFILE; + } + + p = zi->ci.central_header + zi->ci.size_centralheader; + + // Add Extra Information Header for 'ZIP64 information' + zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID + p += 2; + zip64local_putValue_inmemory(p, datasize, 2); // DataSize + p += 2; + + if(uncompressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, uncompressed_size, 8); + p += 8; + } + + if(compressed_size >= 0xffffffff) + { + zip64local_putValue_inmemory(p, compressed_size, 8); + p += 8; + } + + if(zi->ci.pos_local_header >= 0xffffffff) + { + zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8); + p += 8; + } + + // Update how much extra free space we got in the memory buffer + // and increase the centralheader size so the new ZIP64 fields are included + // ( 4 below is the size of HeaderID and DataSize field ) + zi->ci.size_centralExtraFree -= datasize + 4; + zi->ci.size_centralheader += datasize + 4; + + // Update the extra info size field + zi->ci.size_centralExtra += datasize + 4; + zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2); + } + + if (err==ZIP_OK) + err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader); + + free(zi->ci.central_header); + + if (err==ZIP_OK) + { + // Update the LocalFileHeader with the new values. + + ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); + + if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */ + + if(uncompressed_size >= 0xffffffff) + { + if(zi->ci.pos_zip64extrainfo > 0) + { + // Update the size in the ZIP64 extended field. + if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8); + } + } + else + { + if (err==ZIP_OK) /* compressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4); + + if (err==ZIP_OK) /* uncompressed size, unknown */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4); + } + + if (ZSEEK64(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0) + err = ZIP_ERRNO; + } + + zi->number_entry ++; + zi->in_opened_file_inzip = 0; + + return err; +} + +extern int ZEXPORT zipCloseFileInZip (zipFile file) +{ + return zipCloseFileInZipRaw (file,0,0); +} + +int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip) +{ + int err = ZIP_OK; + ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4); + + /*num disks*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + /*relative offset*/ + if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8); + + /*total disks*/ /* Do not support spawning of disk so always say 1 here*/ + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4); + + return err; +} + +int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + uLong Zip64DataSize = 44; + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ? + + if (err==ZIP_OK) /* version made by */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* version needed */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* total number of entries in the central dir */ + err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8); + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8); + } + return err; +} +int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip) +{ + int err = ZIP_OK; + + /*signature*/ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4); + + if (err==ZIP_OK) /* number of this disk */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* number of the disk with the start of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2); + + if (err==ZIP_OK) /* total number of entries in the central dir on this disk */ + { + { + if(zi->number_entry >= 0xFFFF) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + } + } + + if (err==ZIP_OK) /* total number of entries in the central dir */ + { + if(zi->number_entry >= 0xFFFF) + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2); + } + + if (err==ZIP_OK) /* size of the central directory */ + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4); + + if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */ + { + ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + if(pos >= 0xffffffff) + { + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4); + } + else + err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4); + } + + return err; +} + +int Write_GlobalComment(zip64_internal* zi, const char* global_comment) +{ + int err = ZIP_OK; + uInt size_global_comment = 0; + + if(global_comment != NULL) + size_global_comment = (uInt)strlen(global_comment); + + err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2); + + if (err == ZIP_OK && size_global_comment > 0) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment) + err = ZIP_ERRNO; + } + return err; +} + +extern int ZEXPORT zipClose (zipFile file, const char* global_comment) +{ + zip64_internal* zi; + int err = 0; + uLong size_centraldir = 0; + ZPOS64_T centraldir_pos_inzip; + ZPOS64_T pos; + + if (file == NULL) + return ZIP_PARAMERROR; + + zi = (zip64_internal*)file; + + if (zi->in_opened_file_inzip == 1) + { + err = zipCloseFileInZip (file); + } + +#ifndef NO_ADDFILEINEXISTINGZIP + if (global_comment==NULL) + global_comment = zi->globalcomment; +#endif + + centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream); + + if (err==ZIP_OK) + { + linkedlist_datablock_internal* ldi = zi->central_dir.first_block; + while (ldi!=NULL) + { + if ((err==ZIP_OK) && (ldi->filled_in_this_block>0)) + { + if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block) + err = ZIP_ERRNO; + } + + size_centraldir += ldi->filled_in_this_block; + ldi = ldi->next_datablock; + } + } + free_linkedlist(&(zi->central_dir)); + + pos = centraldir_pos_inzip - zi->add_position_when_writting_offset; + if(pos >= 0xffffffff) + { + ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream); + Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos); + } + + if (err==ZIP_OK) + err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip); + + if(err == ZIP_OK) + err = Write_GlobalComment(zi, global_comment); + + if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0) + if (err == ZIP_OK) + err = ZIP_ERRNO; + +#ifndef NO_ADDFILEINEXISTINGZIP + TRYFREE(zi->globalcomment); +#endif + TRYFREE(zi); + + return err; +} + +extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader) +{ + char* p = pData; + int size = 0; + char* pNewHeader; + char* pTmp; + short header; + short dataSize; + + int retVal = ZIP_OK; + + if(pData == NULL || *dataLen < 4) + return ZIP_PARAMERROR; + + pNewHeader = (char*)ALLOC(*dataLen); + pTmp = pNewHeader; + + while(p < (pData + *dataLen)) + { + header = *(short*)p; + dataSize = *(((short*)p)+1); + + if( header == sHeader ) // Header found. + { + p += dataSize + 4; // skip it. do not copy to temp buffer + } + else + { + // Extra Info block should not be removed, So copy it to the temp buffer. + memcpy(pTmp, p, dataSize + 4); + p += dataSize + 4; + size += dataSize + 4; + } + + } + + if(size < *dataLen) + { + // clean old extra info block. + memset(pData,0, *dataLen); + + // copy the new extra info block over the old + if(size > 0) + memcpy(pData, pNewHeader, size); + + // set the new extra info size + *dataLen = size; + + retVal = ZIP_OK; + } + else + retVal = ZIP_ERRNO; + + TRYFREE(pNewHeader); + + return retVal; +} diff --git a/Carthage/Checkouts/UnzipKit/Lib/MiniZip/zip.h b/Carthage/Checkouts/UnzipKit/Lib/MiniZip/zip.h new file mode 100755 index 0000000..8aaebb6 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Lib/MiniZip/zip.h @@ -0,0 +1,362 @@ +/* zip.h -- IO on .zip files using zlib + Version 1.1, February 14h, 2010 + part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html ) + + Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html ) + + Modifications for Zip64 support + Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com ) + + For more info read MiniZip_info.txt + + --------------------------------------------------------------------------- + + Condition of use and distribution are the same than zlib : + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + --------------------------------------------------------------------------- + + Changes + + See header of zip.h + +*/ + +#ifndef _zip12_H +#define _zip12_H + +#ifdef __cplusplus +extern "C" { +#endif + +//#define HAVE_BZIP2 + +#ifndef _ZLIB_H +#include "zlib.h" +#endif + +#ifndef _ZLIBIOAPI_H +#include "ioapi.h" +#endif + +#ifdef HAVE_BZIP2 +#include "bzlib.h" +#endif + +#define Z_BZIP2ED 12 + +#if defined(STRICTZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagzipFile__ { int unused; } zipFile__; +typedef zipFile__ *zipFile; +#else +typedef voidp zipFile; +#endif + +#define ZIP_OK (0) +#define ZIP_EOF (0) +#define ZIP_ERRNO (Z_ERRNO) +#define ZIP_PARAMERROR (-102) +#define ZIP_BADZIPFILE (-103) +#define ZIP_INTERNALERROR (-104) + +#ifndef DEF_MEM_LEVEL +# if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +# else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +# endif +#endif +/* default memLevel */ + +/* tm_zip contain date/time info */ +typedef struct tm_zip_s +{ + uInt tm_sec; /* seconds after the minute - [0,59] */ + uInt tm_min; /* minutes after the hour - [0,59] */ + uInt tm_hour; /* hours since midnight - [0,23] */ + uInt tm_mday; /* day of the month - [1,31] */ + uInt tm_mon; /* months since January - [0,11] */ + uInt tm_year; /* years - [1980..2044] */ +} tm_zip; + +typedef struct +{ + tm_zip tmz_date; /* date in understandable format */ + uLong dosDate; /* if dos_date == 0, tmu_date is used */ +/* uLong flag; */ /* general purpose bit flag 2 bytes */ + + uLong internal_fa; /* internal file attributes 2 bytes */ + uLong external_fa; /* external file attributes 4 bytes */ +} zip_fileinfo; + +typedef const char* zipcharpc; + + +#define APPEND_STATUS_CREATE (0) +#define APPEND_STATUS_CREATEAFTER (1) +#define APPEND_STATUS_ADDINZIP (2) + +extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append)); +extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append)); +/* + Create a zipfile. + pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on + an Unix computer "zlib/zlib113.zip". + if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip + will be created at the end of the file. + (useful if the file contain a self extractor code) + if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will + add files in existing zip (be sure you don't add file that doesn't exist) + If the zipfile cannot be opened, the return value is NULL. + Else, the return value is a zipFile Handle, usable with other function + of this zip package. +*/ + +/* Note : there is no delete function into a zipfile. + If you want delete file into a zipfile, you must open a zipfile, and create another + Of couse, you can use RAW reading and writing to copy the file you did not want delte +*/ + +extern zipFile ZEXPORT zipOpen2 OF((const char *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc_def* pzlib_filefunc_def)); + +extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname, + int append, + zipcharpc* globalcomment, + zlib_filefunc64_def* pzlib_filefunc_def)); + +extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level)); + +extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int zip64)); + +/* + Open a file in the ZIP for writing. + filename : the filename in zip (if NULL, '-' without quote will be used + *zipfi contain supplemental information + if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local + contains the extrafield data the the local header + if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global + contains the extrafield data the the local header + if comment != NULL, comment contain the comment string + method contain the compression method (0 for store, Z_DEFLATED for deflate) + level contain the level of compression (can be Z_DEFAULT_COMPRESSION) + zip64 is set to 1 if a zip64 extended information block should be added to the local file header. + this MUST be '1' if the uncompressed size is >= 0xffffffff. + +*/ + + +extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw)); + + +extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int zip64)); +/* + Same than zipOpenNewFileInZip, except if raw=1, we write raw file + */ + +extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting)); + +extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + int zip64 + )); + +/* + Same than zipOpenNewFileInZip2, except + windowBits,memLevel,,strategy : see parameter strategy in deflateInit2 + password : crypting password (NULL for no crypting) + crcForCrypting : crc of file to compress (needed for crypting) + */ + +extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase + )); + + +extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file, + const char* filename, + const zip_fileinfo* zipfi, + const void* extrafield_local, + uInt size_extrafield_local, + const void* extrafield_global, + uInt size_extrafield_global, + const char* comment, + int method, + int level, + int raw, + int windowBits, + int memLevel, + int strategy, + const char* password, + uLong crcForCrypting, + uLong versionMadeBy, + uLong flagBase, + int zip64 + )); +/* + Same than zipOpenNewFileInZip4, except + versionMadeBy : value for Version made by field + flag : value for flag field (compression level info will be added) + */ + + +extern int ZEXPORT zipWriteInFileInZip OF((zipFile file, + const void* buf, + unsigned len)); +/* + Write data in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZip OF((zipFile file)); +/* + Close the current file in the zipfile +*/ + +extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file, + uLong uncompressed_size, + uLong crc32)); + +extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file, + ZPOS64_T uncompressed_size, + uLong crc32)); + +/* + Close the current file in the zipfile, for file opened with + parameter raw=1 in zipOpenNewFileInZip2 + uncompressed_size and crc32 are value for the uncompressed size +*/ + +extern int ZEXPORT zipClose OF((zipFile file, + const char* global_comment)); +/* + Close the zipfile +*/ + + +extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader)); +/* + zipRemoveExtraInfoBlock - Added by Mathias Svensson + + Remove extra information block from a extra information data for the local file header or central directory header + + It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode. + + 0x0001 is the signature header for the ZIP64 extra information blocks + + usage. + Remove ZIP64 Extra information from a central director extra field data + zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001); + + Remove ZIP64 Extra information from a Local File Header extra field data + zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001); +*/ + +#ifdef __cplusplus +} +#endif + +#endif /* _zip64_H */ diff --git a/Carthage/Checkouts/UnzipKit/README.md b/Carthage/Checkouts/UnzipKit/README.md new file mode 100644 index 0000000..89de8d5 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/README.md @@ -0,0 +1,313 @@ +[![Build Status](https://travis-ci.org/abbeycode/UnzipKit.svg?branch=master)](https://travis-ci.org/abbeycode/UnzipKit) +[![Documentation Coverage](https://img.shields.io/cocoapods/metrics/doc-percent/UnzipKit.svg)](http://cocoadocs.org/docsets/UnzipKit) + +# About + +UnzipKit is an Objective-C `zlib` wrapper for compressing and decompressing Zip files on OS X and iOS. It's based on the [AgileBits fork](https://github.com/AgileBits/objective-zip) of [Objective-Zip](http://code.google.com/p/objective-zip/), developed by [Flying Dolphin Studio](http://www.flyingdolphinstudio.com). + +It provides the following over Objective-Zip: + +* A simpler API, with only a handful of methods, and no incantations to remember +* The ability to delete files in an archive, including overwriting an existing file +* Pervasive use of blocks, making iteration simple +* Full documentation for all methods +* Pervasive use of `NSError`, instead of throwing exceptions + +# Installation + +UnzipKit supports both [CocoaPods](https://cocoapods.org/) and [Carthage](https://github.com/Carthage/Carthage). CocoaPods does not support dynamic framework targets (as of v0.39.0), so in that case, please use Carthage. + +Cartfile: + + github "abbeycode/UnzipKit" + +Podfile: + + pod "UnzipKit" + +# Deleting files + +Using the method `-deleteFile:error:` currently creates a new copy of the archive in a temporary location, without the deleted file, then replaces the original archive. By default, all methods to write data perform a delete on the file name they write before archiving the new data. You can turn this off by calling the overload with an `overwrite` argument, setting it to `NO`. This will not remove the original copy of that file, though, causing the archive to grow with each write of the same file name. + +If that's not a concern, such as when creating a new archive from scratch, it would improve performance, particularly for archives with a large number of files. + +```Objective-C +NSError *archiveError = nil; +UZKArchive *archive = [UZKArchive zipArchiveAtPath:@"An Archive.zip" error:&archiveError]; +BOOL deleteSuccessful = [archive deleteFile:@"dir/anotherFilename.jpg" + error:&error]; +``` + +# Detecting Zip files + +You can quickly and efficiently check whether a file at a given path or URL is a Zip archive: + +```Objective-C +BOOL fileAtPathIsArchive = [UZKArchive pathIsAZip:@"some/file.zip"]; + +NSURL *url = [NSURL fileURLWithPath:@"some/file.zip"]; +BOOL fileAtURLIsArchive = [UZKArchive urlIsAZip:url]; +``` + +# Reading Zip contents + +```Objective-C +NSError *archiveError = nil; +UZKArchive *archive = [UZKArchive zipArchiveAtPath:@"An Archive.zip" error:&archiveError]; +NSError *error = nil; +``` + +You can use UnzipKit to perform these read-only operations: + +* List the contents of the archive + ```Objective-C + NSArray *filesInArchive = [archive listFilenames:&error]; + ``` + +* Extract all files to disk + + ```Objective-C + BOOL extractFilesSuccessful = [archive extractFilesTo:@"some/directory" + overWrite:NO + error:&error]; + ``` + +* Extract each archived file into memory + + ```Objective-C + NSData *extractedData = [archive extractDataFromFile:@"a file in the archive.jpg" + error:&error]; + ``` + +# Modifying archives + +```Objective-C +NSError *archiveError = nil; +UZKArchive *archive = [UZKArchive zipArchiveAtPath:@"An Archive.zip" error:&archiveError]; +NSError *error = nil; +NSData *someFile = // Some data to write +``` + +You can also modify Zip archives: + +* Write an in-memory `NSData` into the archive + + ```Objective-C + BOOL success = [archive writeData:someFile + filePath:@"dir/filename.jpg" + error:&error]; + ``` +* 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(BOOL(^writeData)(const void *bytes, unsigned int length), NSError**(actionError)) { + for (NSUInteger i = 0; i <= someFile.length; i += bufferSize) { + const void *bytes = // some data + unsigned int length = // length of data + + if (/* Some error occurred reading the data */) { + *actionError = // Any error that was produced, or make your own + return NO; + } + + if (!writeData(&bytes, length)) { + return NO; + } + } + + return YES; + }]; + ``` +* Delete files from the archive + + ```Objective-C + BOOL success = [archive deleteFile:@"No-good-file.txt" error:&error]; + ``` + + +# Progress Reporting + +The following methods support `NSProgress` and `NSProgressReporting`: + +* `extractFilesTo:overwrite:error:` +* `extractData:error:` +* `extractDataFromFile:error:` +* `performOnFilesInArchive:error:` +* `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:`* + +_* the `writeData...` methods don't support cancellation like the read-only methods do + +## Using implicit `NSProgress` hierarchy + +You can create your own instance of `NSProgress` and observe its `fractionCompleted` property with KVO to monitor progress like so: + +```Objective-C + static void *ExtractDataContext = &ExtractDataContext; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:aFileURL error:nil]; + + NSProgress *extractDataProgress = [NSProgress progressWithTotalUnitCount:1]; + [extractDataProgress becomeCurrentWithPendingUnitCount:1]; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [extractDataProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:ExtractDataContext]; + + NSError *extractError = nil; + NSData *data = [archive extractDataFromFile:firstFile error:&extractError]; + + [extractDataProgress resignCurrent]; + [extractDataProgress removeObserver:self forKeyPath:observedSelector]; +``` + +## Using your own explicit `NSProgress` instance + +If you don't have a hierarchy of `NSProgress` instances, or if you want to observe more details during progress updates in `extractFilesTo:overwrite:error:`, you can create your own instance of `NSProgress` and set the `UZKArchive` instance's `progress` property, like so: + +```Objective-C + static void *ExtractFilesContext = &ExtractFilesContext; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:aFileURL error:nil]; + + NSProgress *extractFilesProgress = [NSProgress progressWithTotalUnitCount:1]; + archive.progress = extractFilesProgress; + + NSString *observedSelector = NSStringFromSelector(@selector(localizedDescription)); + + [self.descriptionsReported removeAllObjects]; + [extractFilesProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:ExtractFilesContext]; + + NSError *extractError = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&extractError]; + + [extractFilesProgress removeObserver:self forKeyPath:observedSelector]; +``` + +## Cancellation with `NSProgress` + +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. + + +# Documentation + +Full documentation for the project is available on [CocoaDocs](http://cocoadocs.org/docsets/UnzipKit). + +# Logging + +For all OS versions from 2016 onward (macOS 10.12, iOS 10, tvOS 10, watchOS 3), UnzipKit uses the new [Unified Logging framework](https://developer.apple.com/documentation/os/logging) for logging and Activity Tracing. You can view messages at the Info or Debug level to view more details of how UnzipKit is working, and use Activity Tracing to help pinpoint the code path that's causing a particular error. + +As a fallback, regular `NSLog` is used on older OSes, with all messages logged at the same level. + +When debugging your own code, if you'd like to decrease the verbosity of the UnzipKit framework, you can run the following command: + + sudo log config --mode "level:default" --subsystem com.abbey-code.UnzipKit + +The available levels, in order of increasing verbosity, are `default`, `info`, `debug`, with `debug` being the default. + +## Logging guidelines + +These are the general rules governing the particulars of how activities and log messages are classified and written. They were written after the initial round of log messages were, so there may be some inconsistencies (such as an incorrect log level). If you think you spot one, open an issue or a pull request! + +### Logging + +Log messages should follow these conventions. + +1. Log messages don't have final punctuation (like these list items) +1. Messages that note a C function is about to be called, rather than a higher level UnzipKit or Cocoa method, end with "...", since it's not expected for them to log any details of their own + +#### Default log level + +There should be no messages at this level, so that it's possible for a consumer of the API to turn off _all_ diagnostic logging from it, as detailed above. It's only possible to `log config --mode "level:off"` for a process, not a subsystem. + +#### Info log level + +Info level log statements serve the following specific purposes. + +1. Major action is taken, such as initializing an archive object, or deleting a file from an archive +1. Noting each public method has been called, and the arguments with which it was called +1. Signposting the major actions a public method takes +1. Notifying that an atypical condition has occurred (such as an action causing an early stop in a block or a NO return value) +1. Noting that a loop is about to occur, which will contain debug-level messages for each iteration + +#### Debug log level + +Most messages fall into this category, making it extremely verbose. All non-error messages that don't fall into either of the other two categories should be debug-level, with some examples of specific cases below. + +1. Any log message in a private method +1. Noting variable and argument values in a method +1. Indicating that everything is working as expected +1. Indicating what happens during each iteration of a loop (or documenting that an iteration has happened at all) + +#### Error log level + +1. Every `NSError` generated should get logged with the same detail message as the `NSError` object itself +1. `NSError` log messages should contain the string of the error code's enumeration value (e.g. `"UZKErrorCodeArchiveNotFound"`) when it is known at design time +1. Errors should reported everywhere they're encountered, making it easier to trace their flows through the call stack +1. Early exits that result in desired work not being performed + +#### Fault log level + +So far, there is only one case that gets logged at Fault-level: when a Cocoa framework methods that come back with an error + +### Activities +1. Public methods have English activity names with spaces, and are title-case +1. Private methods each have an activity with the method's name +1. Sub-activities are created for significant scope changes, such as when inside an action block, but not if no significant work is done before entering that action +1. Top-level activities within a method have variables named `activity`, with more specific labels given to sub-activities +1. If a method is strictly an overload that calls out to another overload without doing anything else, it should not define its own activity + +# Pushing a new CocoaPods version + +New tagged builds (in any branch) get pushed to CocoaPods automatically, provided they meet the following criteria: + +1. All builds and tests succeed +2. The library builds successfully for CocoaPods and for Carthage +3. The build is tagged with something resembling a version number (`#.#.#(-beta#)`, e.g. **2.9** or **2.9-beta5**) +4. `pod spec lint` passes, making sure the CocoaPod is 100% valid + +Before pushing a build, you must: + +1. Add the release notes to the [CHANGELOG.md](CHANGELOG.md), and commit +2. Run [set-version](Scripts/set-version.sh), like so: + + `./Scripts/set-version.sh ` + + This does the following: + + 1. Updates the various Info.plist files to indicate the new version number, and commits them + 2. Makes an annotated tag whose message contains the release notes entered in Step 1 + +Once that's done, you can call `git push --follow-tags` [1](#f1), and let [Travis CI](https://travis-ci.org/abbeycode/UnzipKit/builds) take care of the rest. + +# License + +* UnzipKit: [See LICENSE (BSD)](LICENSE) +* MiniZip: [See MiniZip website](http://www.winimage.com/zLibDll/minizip.html) + + + +
+ +1: Or set `followTags = true` in your git config to always get this behavior: + + git config --global push.followTags true + +[↩](#a1) diff --git a/Carthage/Checkouts/UnzipKit/Resources/UnzipKitResources-Info.plist b/Carthage/Checkouts/UnzipKit/Resources/UnzipKitResources-Info.plist new file mode 100644 index 0000000..c04e70c --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Resources/UnzipKitResources-Info.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.9 + CFBundleSignature + ???? + CFBundleVersion + 1.9 + NSHumanReadableCopyright + Copyright © 2019 Abbey Code. All rights reserved. + NSPrincipalClass + + + diff --git a/Carthage/Checkouts/UnzipKit/Resources/en.lproj/UnzipKit.strings b/Carthage/Checkouts/UnzipKit/Resources/en.lproj/UnzipKit.strings new file mode 100644 index 0000000..ce47516 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Resources/en.lproj/UnzipKit.strings @@ -0,0 +1,267 @@ +/* UZKErrorCodeOutputErrorPathIsAFile */ +"Attempted to extract the archive to a path that is a file, not a directory" = "Attempted to extract the archive to a path that is a file, not a directory"; + +/* UZKErrorCodeMixedModeAccess */ +"Attempted to read before all writes have completed, or vise-versa" = "Attempted to read before all writes have completed, or vise-versa"; + +/* Detailed error string */ +"Attempted to write to the archive while another write operation is already in progress" = "Attempted to write to the archive while another write operation is already in progress"; + +/* UZKErrorCodeBadZipFile */ +"Bad zip file" = "Bad zip file"; + +/* UZKErrorCodeFileNotFoundInArchive */ +"Can't find a file in the archive" = "Can't find a file in the archive"; + +/* UZKErrorCodeArchiveNotFound */ +"Can't open archive" = "Can't open archive"; + +/* Error message */ +"Cannot open archive, since it was compressed using the Deflate64 algorithm (method ID 9)" = "Cannot open archive, since it was compressed using the Deflate64 algorithm (method ID 9)"; + +/* Detailed error string */ +"Error allocating buffer for file %@ while deleting %@" = "Error allocating buffer for file %1$@ while deleting %2$@"; + +/* Detailed error string */ +"Error allocating buffer for file %@ while deleting %@. Is it too large?" = "Error allocating buffer for file %1$@ while deleting %2$@. Is it too large?"; + +/* Detailed error string */ +"Error allocating commentary info of %@ while deleting %@" = "Error allocating commentary info of %1$@ while deleting %2$@"; + +/* Detailed error string */ +"Error allocating extra_field info of %@ while deleting %@" = "Error allocating extra_field info of %1$@ while deleting %2$@"; + +/* Detailed error string */ +"Error allocating extrafield info of %@ while deleting %@" = "Error allocating extrafield info of %1$@ while deleting %2$@"; + +/* Detailed error string */ +"Error allocating local_extra for file %@ while deleting %@" = "Error allocating local_extra for file %1$@ while deleting %2$@"; + +/* Detailed error string */ +"Error allocating the global comment during comment read" = "Error allocating the global comment during comment read"; + +/* UZKErrorCodeFileCloseWriting */ +"Error clonsing a file in the archive after writing it" = "Error clonsing a file in the archive after writing it"; + +/* Detailed error string */ +"Error closing %@ in destination zip while deleting %@ (%d)" = "Error closing %1$@ in destination zip while deleting %2$@ (%3$d)"; + +/* Detailed error string */ +"Error closing %@ in source zip while deleting %@ (%d)" = "Error closing %1$@ in source zip while deleting %2$@ (%3$d)"; + +/* Detailed error string */ +"Error closing current file during buffered read" = "Error closing current file during buffered read"; + +/* Detailed error string */ +"Error closing file '%@' for write (%d)" = "Error closing file '%1$@' for write (%2$d)"; + +/* Detailed error string */ +"Error closing file in archive after append (%d)" = "Error closing file in archive after append (%d)"; + +/* Detailed error string */ +"Error closing file in archive after create (%d)" = "Error closing file in archive after create (%d)"; + +/* Detailed error string */ +"Error closing file in archive after read (%d)" = "Error closing file in archive after read (%d)"; + +/* Detailed error string */ +"Error closing file in archive in write mode %lu (%d)" = "Error closing file in archive in write mode %1$lu (%2$d)"; + +/* Detailed error string */ +"Error creating bookmark to new archive file: %@" = "Error creating bookmark to new archive file: %@"; + +/* Detailed error string */ +"Error creating current file (%d) '%@'" = "Error creating current file (%1$d) '%2$@'"; + +/* UZKErrorCodeDeleteFile */ +"Error deleting a file in the archive" = "Error deleting a file in the archive"; + +/* UZKErrorCodeOutputError */ +"Error extracting files from the archive" = "Error extracting files from the archive"; + +/* Detailed error string */ +"Error getting current file info (%d)" = "Error getting current file info (%d)"; + +/* Detailed error string */ +"Error getting current file info for archive (%d)" = "Error getting current file info for archive (%d)"; + +/* Detailed error string */ +"Error getting file info of file while deleting %@ (%d)" = "Error getting file info of file while deleting %1$@ (%2$d)"; + +/* Detailed error string */ +"Error getting global info (%d)" = "Error getting global info (%d)"; + +/* Detailed error string */ +"Error getting global info of archive during comment read: %d" = "Error getting global info of archive during comment read: %d"; + +/* Detailed error string */ +"Error getting local_extra for file %@ while deleting %@" = "Error getting local_extra for file %1$@ while deleting %2$@"; + +/* Detailed error string */ +"Error getting size_local_extra for file while deleting %@" = "Error getting size_local_extra for file while deleting %@"; + +/* Detailed error string */ +"Error getting the global info of the source file while deleting %@ (%d)" = "Error getting the global info of the source file while deleting %1$@ (%2$d)"; + +/* Detailed error string */ +"Error going to first file in archive (%d)" = "Error going to first file in archive (%d)"; + +/* Detailed error string */ +"Error locating file '%@' in archive" = "Error locating file '%@' in archive"; + +/* UZKErrorCodeFileNavigationError */ +"Error navigating through the archive" = "Error navigating through the archive"; + +/* Detailed error string */ +"Error navigating to next file (%d)" = "Error navigating to next file (%d)"; + +/* Detailed error string */ +"Error opening %@ for raw reading while deleting %@ (%d)" = "Error opening %1$@ for raw reading while deleting %2$@ (%3$d)"; + +/* Detailed error string */ +"Error opening %@ in destination zip while deleting %@ (%d)" = "Error opening %1$@ in destination zip while deleting %2$@ (%3$d)"; + +/* UZKErrorCodeFileOpenForWrite */ +"Error opening a file in the archive to write it" = "Error opening a file in the archive to write it"; + +/* Detailed error string */ +"Error opening archive (%d)" = "Error opening archive (%d)"; + +/* Detailed error string */ +"Error opening file '%@' for write (%d)" = "Error opening file '%1$@' for write (%2$d)"; + +/* Detailed error string */ +"Error opening the destination file while deleting %@" = "Error opening the destination file while deleting %@"; + +/* Detailed error string */ +"Error opening the source file while deleting %@" = "Error opening the source file while deleting %@"; + +/* Detailed error string */ +"Error opening zip file %@" = "Error opening zip file %@"; + +/* Detailed error string */ +"Error opening zip file for write: %@" = "Error opening zip file for write: %@"; + +/* Detailed error string */ +"Error reading %@ into buffer while deleting %@" = "Error reading %1$@ into buffer while deleting %2$@"; + +/* UZKErrorCodeFileRead */ +"Error reading a file in the archive" = "Error reading a file in the archive"; + +/* Detailed error string */ +"Error reading data from '%@' in archive" = "Error reading data from '%@' in archive"; + +/* Detailed error string */ +"Error reading extra_field and commentary info of %@ while deleting %@ (%d)" = "Error reading extra_field and commentary info of %1$@ while deleting %2$@ (%3$d)"; + +/* Detailed error string */ +"Error reading extrafield and commentary info of %@ while deleting %@ (%d)" = "Error reading extrafield and commentary info of %1$@ while deleting %2$@ (%3$d)"; + +/* Detailed error string */ +"Error reading the comment (readGlobalComment)" = "Error reading the comment (readGlobalComment)"; + +/* Detailed error string */ +"Error reading the global comment of the source file while deleting %@" = "Error reading the global comment of the source file while deleting %@"; + +/* Detailed error string */ +"Error reading the global comment of the source file while deleting %@ (wrong size)" = "Error reading the global comment of the source file while deleting %@ (wrong size)"; + +/* UZKErrorCodeZLibError */ +"Error reading/writing file" = "Error reading/writing file"; + +/* Detailed error string */ +"Error seeking to file position (%d)" = "Error seeking to file position (%d)"; + +/* Detailed error string */ +"Error writing %@ to destination zip while deleting %@ (%d)" = "Error writing %1$@ to destination zip while deleting %2$@ (%3$d)"; + +/* UZKErrorCodeFileWrite */ +"Error writing a file in the archive" = "Error writing a file in the archive"; + +/* Detailed error string */ +"Error writing to file '%@' (%d)" = "Error writing to file '%1$@' (%2$d)"; + +/* Detailed error string */ +"Error writing to file: %@" = "Error writing to file: %@"; + +/* Detailed error string */ +"Extract path exists, but is not a directory: %@" = "Extract path exists, but is not a directory: %@"; + +/* Detailed error string */ +"Failed to copy archive to external volume '%@', after deleting '%@' from it" = "Failed to copy archive to external volume '%1$@', after deleting '%2$@' from it"; + +/* Detailed error string */ +"Failed to copy archive to external volume '%@', after deleting '%@' from it (%@)" = "Failed to copy archive to external volume '%1$@', after deleting '%2$@' from it (%3$@)"; + +/* Detailed error string */ +"Failed to create destination directory: %@" = "Failed to create destination directory: %@"; + +/* Detailed error string */ +"Failed to create new file for archive: %@" = "Failed to create new file for archive: %@"; + +/* Detailed error string */ +"Failed to locate '%@' in archive during buffered read" = "Failed to locate '%@' in archive during buffered read"; + +/* Detailed error string */ +"Failed to locate '%@' in archive during-perform on-data operation" = "Failed to locate '%@' in archive during-perform on-data operation"; + +/* Detailed error string */ +"Failed to read file %@ in zip" = "Failed to read file %@ in zip"; + +/* Detailed error string */ +"Failed to remove archive from external volume '%@', after deleting '%@' from a new version to replace it" = "Failed to remove archive from external volume '%1$@', after deleting '%2$@' from a new version to replace it"; + +/* Detailed error string */ +"Failed to remove original archive from external volume '%@', after deleting '%@' from a new version to replace it (%@)" = "Failed to remove original archive from external volume '%1$@', after deleting '%2$@' from a new version to replace it (%3$@)"; + +/* Detailed error string */ +"Failed to replace the old archive with the new one, after deleting '%@' from it" = "Failed to replace the old archive with the new one, after deleting '%@' from it"; + +/* Detailed error string */ +"Failed to replace the old archive with the new one, after deleting '%@' from it (%@)" = "Failed to replace the old archive with the new one, after deleting '%1$@' from it (%2$@)"; + +/* Detailed error string */ +"Failed to seek to the next file, while deleting %@ from the archive" = "Failed to seek to the next file, while deleting %@ from the archive"; + +/* Detailed error string */ +"Failed to store the new file bookmark to the archive after deleting '%@' from it: %@" = "Failed to store the new file bookmark to the archive after deleting '%1$@' from it: %2$@"; + +/* Detailed error string */ +"File '%@' not found in archive" = "File '%@' not found in archive"; + +/* CRC mismatch error detail */ +"Incorrect CRC provided\n%@ given\n%@ calculated" = "Incorrect CRC provided\n%1$@ given\n%2$@ calculated"; + +/* UZKErrorCodeInvalidPassword */ +"Incorrect password provided" = "Incorrect password provided"; + +/* UZKErrorCodeInternalError */ +"Internal error" = "Internal error"; + +/* Detailed error string */ +"No file found at path %@" = "No file found at path %@"; + +/* Detailed error string */ +"No file position found for '%@'" = "No file position found for '%@'"; + +/* UZKErrorCodeParameterError */ +"Parameter error" = "Parameter error"; + +/* UZKErrorCodeDeflate64 */ +"The archive was compressed with the Deflate64 method, which isn't supported" = "The archive was compressed with the Deflate64 method, which isn't supported"; + +/* UZKErrorCodePreCRCMismatch */ +"The CRC given up front doesn't match the calculated CRC" = "The CRC given up front doesn't match the calculated CRC"; + +/* UZKErrorCodeCRCError */ +"The data got corrupted during decompression" = "The data got corrupted during decompression"; + +/* Detailed error string */ +"Unable to begin reading from the archive until all write operations have completed" = "Unable to begin reading from the archive until all write operations have completed"; + +/* Detailed error string */ +"Unable to begin writing to the archive until all read operations have completed" = "Unable to begin writing to the archive until all read operations have completed"; + +/* UnknownErrorCode */ +"Unknown error code: %ld" = "Unknown error code: %ld"; + diff --git a/Carthage/Checkouts/UnzipKit/Scripts/add-github-release.py b/Carthage/Checkouts/UnzipKit/Scripts/add-github-release.py new file mode 100755 index 0000000..0e0142f --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Scripts/add-github-release.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python +# -*- coding: UTF-8 -*- + +# Usage: add-github-release.py +# +# Creates a release in GitHub for the given tag +# + +import json +import os +import urllib2 +import sys + +def add_release(token, repo, tag, archive_path, notes): + ''' + Creates a release on GitHub for the given arguments + ''' + print('token: "{}", repo: "{}", tag: "{}", archive: "{}" notes: "{}"'.format('SECURE' if token else '', repo, tag, archive_path, notes)) + + assert token, 'No API token given' + assert repo, 'No repo given' + assert '/' in repo, "Repo doesn't look like a valid GitHub repo (e.g. abbeycode/UnrarKit)" + assert tag, 'No tag given' + assert archive_path, 'No archive path given' + assert notes, 'No notes given' + + is_beta = tag_is_beta(tag) + + url = 'https://api.github.com/repos/{}/releases?access_token={}'.format(repo, token) + values = { + 'tag_name': tag, + 'name': 'v{}'.format(tag), + 'body': notes, + 'prerelease': True if is_beta else False + } + + data = json.dumps(values) + request = urllib2.Request(url, data) + response = urllib2.urlopen(request) + the_page = response.read() + + response_dict = json.loads(the_page) + upload_url = response_dict['upload_url'] + release_url = response_dict['url'] + + upload_carthage_archive(token, upload_url, archive_path) + + print('Release added: {}'.format(release_url)) + return True + +def tag_is_beta(tag): + ''' + Returns True if the tag contains a label indicating it's a beta build + + >>> tag_is_beta('1.2.3') + False + >>> tag_is_beta('1.2.3-beta') + True + >>> tag_is_beta('1.2.3-beta2') + True + >>> tag_is_beta('1.2.3-RC') + True + >>> tag_is_beta('1.2.3-RC1') + True + >>> tag_is_beta('1.2.3-prerelease') + True + >>> tag_is_beta('1.2.3-prerelease2') + True + >>> tag_is_beta('1.2.3-alpha') + True + >>> tag_is_beta('1.2.3-alpha2') + True + ''' + + return 'beta' in tag or 'RC' in tag or 'prerelease' in tag or 'alpha' in tag + +def upload_carthage_archive(token, upload_url, archive_path): + ''' + Uploads the archive at the given path to GitHub for the release specified + ''' + + upload_url = upload_url.split('{')[0] + url = '{}?access_token={}&name={}'.format(upload_url, token, archive_path) + header = {'Content-Type': 'application/zip'} + + with FileWithLen(archive_path, 'r') as f: + request = urllib2.Request(url, f, header) + response = urllib2.urlopen(request) + + page = response.read() + response_dict = json.loads(page) + return True + +class FileWithLen(file): + def __init__(self, *args, **keyws): + file.__init__(self, *args, **keyws) + + def __len__(self): + return int(os.fstat(self.fileno())[6]) + + +if __name__ == '__main__': + # Allow script to be called with 'test' argument + if len(sys.argv) == 2 and sys.argv[1].lower() == 'test': + import doctest + result = doctest.testmod() + sys.exit(0 if result.failed == 0 else 1) + + expected_arg_count = 6 + + if len(sys.argv) != expected_arg_count: + print('\nadd-github-release given {} arguments ({}). Expecting {}\n'.format(len(sys.argv) - 1, sys.argv[1:], expected_arg_count - 1)) + sys.exit(1) + + exit_code = 0 if add_release(*sys.argv[1:]) else 1 + sys.exit(exit_code) \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/Scripts/archive-carthage.sh b/Carthage/Checkouts/UnzipKit/Scripts/archive-carthage.sh new file mode 100755 index 0000000..de22a0c --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Scripts/archive-carthage.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +set -ev + +# Archives the Carthage packages, and prints the name of the archive + +carthage build --no-skip-current +carthage archive + +export ARCHIVE_PATH="UnzipKit.framework.zip" \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/Scripts/carthage-validate.sh b/Carthage/Checkouts/UnzipKit/Scripts/carthage-validate.sh new file mode 100755 index 0000000..cce38af --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Scripts/carthage-validate.sh @@ -0,0 +1,50 @@ +#!/bin/bash + +REPO="github \"$TRAVIS_REPO_SLUG\"" +COMMIT=$TRAVIS_COMMIT + +if [ -z ${TRAVIS+x} ]; then + REPO="git \"`pwd`\"" + COMMIT=`git log -1 --oneline | cut -f1 -d' '` + TRAVIS_BUILD_DIR="/Users/Dov/Source Code/UnzipKit" + echo "Not running in Travis. Setting REPO ($REPO) and COMMIT ($COMMIT)" +fi + +if [ -n "$TRAVIS" ] && [ "$TRAVIS_PULL_REQUEST" != "false" ]; then + REPO="github \"$TRAVIS_PULL_REQUEST_SLUG\"" + COMMIT=$TRAVIS_PULL_REQUEST_SHA + echo "Build is for a Pull Request. Overriding REPO ($REPO) and COMMIT ($COMMIT)" +fi + +if [ ! -d "CarthageValidation" ]; then + mkdir "CarthageValidation" +fi + +brew install carthage + +rm UnzipKitDemo/Cartfile +rm UnzipKitDemo/Cartfile.resolved +rm -rf UnzipKitDemo/Carthage + +echo "$REPO \"$COMMIT\"" > UnzipKitDemo/Cartfile + +pushd UnzipKitDemo > /dev/null + +carthage bootstrap --configuration Debug --verbose +EXIT_CODE=$? + +echo "Checking for build products..." + +if [ ! -d "Carthage/Build/Mac/UnzipKit.framework" ]; then + echo "No Mac library built" + EXIT_CODE=1 +fi + +if [ ! -d "Carthage/Build/iOS/UnzipKit.framework" ]; then + echo "No iOS library built" + EXIT_CODE=1 +fi + +popd > /dev/null + +exit $EXIT_CODE \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/Scripts/cocoapod-validate.sh b/Carthage/Checkouts/UnzipKit/Scripts/cocoapod-validate.sh new file mode 100755 index 0000000..57fcc73 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Scripts/cocoapod-validate.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +set -ev +set -o pipefail + +. Scripts/set-travis-tag-to-latest.sh + +pod env + +# Lint the podspec to check for errors. Don't call `pod spec lint`, because we want it to evaluate locally + +# 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' + +. Scripts/unset-travis-tag.sh \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/Scripts/get-release-notes.py b/Carthage/Checkouts/UnzipKit/Scripts/get-release-notes.py new file mode 100755 index 0000000..0bf7ef2 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Scripts/get-release-notes.py @@ -0,0 +1,168 @@ +#!/usr/bin/env python3 +# -*- coding: UTF-8 -*- + +# Usage: get-release-notes.py +# +# Prints the release notes for a given version of the library, ignoring any +# beta marking on the tag. For beta releases, retrieves the beta notes and +# prepends them +# +# Retrieves release notes from CHANGELOG.mc +# Retrieves beta notes from beta-notes.md +# + +import os.path +import re +import subprocess +import sys + +CHANGELOG_FILEPATH = 'CHANGELOG.md' +BETANOTES_FILEPATH = 'beta-notes.md' + + +def print_release_notes(version): + version_num, beta_tag, beta_num = get_version_parts(version) + change_notes = get_changelog_notes(version_num) + + if beta_tag is None: + print(change_notes) + return True + + beta_notes = get_beta_notes(beta_num, change_notes) + + if not beta_notes is None: + print(beta_notes) + return True + + return False + +def get_version_parts(version): + ''' + Splits out the main part of the version number from any beta tags, and the beta number + + >>> get_version_parts('1.0') + ('1.0', None, None) + + >>> get_version_parts('1.0.1') + ('1.0.1', None, None) + + >>> get_version_parts('1.0-beta') + ('1.0', 'beta', 1) + + >>> get_version_parts('1.0.1-beta') + ('1.0.1', 'beta', 1) + + >>> get_version_parts('1.0-beta1') + ('1.0', 'beta', 1) + + >>> get_version_parts('1.0.2-beta1') + ('1.0.2', 'beta', 1) + + ''' + + matches = re.match(r'(?P[\d\.]+)\-?(?P\D+)?(?P\d+)?', version) + version_num = matches.group('version_num') + beta_tag = matches.group('beta') + beta_num = matches.group('beta_num') + + beta_num = (int(beta_num or 1)) if beta_tag else None + + return (version_num, beta_tag, beta_num) + +def get_version_notes(version_num, changes): + r''' + Returns the portion of the given changelog that corresponds to the changes for the given + version number. version_num is expected to be stripped of any beta info + + This won't work for the last version number in a file, but that's fine + + >>> get_version_notes('1.2', '# UnzipKit CHANGELOG\n\n## 1.2\n\nList of changes\n\n## 1.1\n\nMore changes\n\n## 1.0') + 'List of changes' + + >>> get_version_notes('1.1', '# UnzipKit CHANGELOG\n\n## 1.2\n\nList of changes\n\n## 1.1\n\nMore changes\n\n## 1.0') + 'More changes' + ''' + + notes_regex = r'##\s+{}\s+(.+?)\s+(?:##\s+[\d\.]+).*'.format(version_num.replace('.', '\.')) + matches = re.search(notes_regex, changes, re.DOTALL) + + return matches[1].strip() + +def get_changelog_notes(version_num): + with open(CHANGELOG_FILEPATH, 'r') as changelog: + changes = changelog.read() + + return get_version_notes(version_num, changes) + +def have_beta_notes_been_updated(version): + ''' + Returns True if the beta notes have been updated since the last tag, or if the version + isn't a beta, or if it's the first beta + ''' + + version_num, beta_tag, beta_num = get_version_parts(version) + if not beta_tag or beta_num == 1: + return True + + all_tags = subprocess.check_output(['git', 'tag', '--sort=-taggerdate'], universal_newlines=True) + last_tag = all_tags.split('\n')[0] + + diff_output = subprocess.check_output(['git', 'diff', '--name-only', last_tag, 'HEAD', + '--', BETANOTES_FILEPATH]) + + # Will be 'beta-notes.md' if it has changed, blank otherwise + return bool(diff_output) + +def get_beta_notes(beta_num, change_notes): + ''' + Returns the release's change notes, taking the beta notes into account. If it's + the first beta release, then it doesn't bother. Also checks if the release notes + have been updated since the last beta + ''' + + if beta_num == 1: + return change_notes + + with open(BETANOTES_FILEPATH, 'r') as beta_notes_file: + beta_notes = beta_notes_file.read() + + return '''Addressed in this beta: + +{} + +------- +Changes to main release: +{} +'''.format(beta_notes, change_notes) + + +if __name__ == '__main__': + import doctest + doctest.testmod() + + CHECK_BETA_NOTES_FLAG = '--beta-notes-check' + + if len(sys.argv) < 2: + print('\nNo argument given. Pass the version number, optionally with {}\n'.format( + CHECK_BETA_NOTES_FLAG), file=sys.stderr) + sys.exit(1) + + version = sys.argv[1] + + if not version: + print("Empty version number passed", file=sys.stderr) + sys.exit(1) + + if len(sys.argv) >= 3 and sys.argv[2] == CHECK_BETA_NOTES_FLAG: + if not have_beta_notes_been_updated(version): + print("Beta notes haven't been updated since since last release", file=sys.stderr) + sys.exit(1) + + sys.exit(0) + + if not os.path.exists(CHANGELOG_FILEPATH): + CHANGELOG_FILEPATH = os.path.join('..', CHANGELOG_FILEPATH) + BETANOTES_FILEPATH = os.path.join('..', BETANOTES_FILEPATH) + + exit_code = 0 if print_release_notes(version) else 1 + sys.exit(exit_code) \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/Scripts/install-demo-libs.sh b/Carthage/Checkouts/UnzipKit/Scripts/install-demo-libs.sh new file mode 100755 index 0000000..64982a0 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Scripts/install-demo-libs.sh @@ -0,0 +1,12 @@ +#!/bin/bash + +set -ev + +. Scripts/set-travis-tag-to-latest.sh + +pushd UnzipKitDemo +pod --version +pod update +popd + +. Scripts/unset-travis-tag.sh \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/Scripts/localize.sh b/Carthage/Checkouts/UnzipKit/Scripts/localize.sh new file mode 100755 index 0000000..b758837 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Scripts/localize.sh @@ -0,0 +1,34 @@ +#!/bin/bash + +# Generate Localizable.strings +find -E . -iregex '.*\.(m|h|mm)$' \ + -not -path "./UnzipKitTests*" \ + -print0 \ +| xargs -0 genstrings -o Resources/en.lproj + +# Define file and temp file +LOCALIZE=./Resources/en.lproj/UnzipKit.strings +UTF8=./Resources/en.lproj/UnzipKitUTF8.txt + +# Convert file encoding from UTF-16 to UTF-8 +iconv -f UTF-16LE -t UTF-8 $LOCALIZE >$UTF8 +mv $UTF8 $LOCALIZE + +# Replace all \\n tokens in the file with a newline (used in comments) +sed -i "" 's_\\\\n_\ +_g' $LOCALIZE + +# Check for missing comments in the UTF8 file, showing the violating lines +MISSING=$(grep -A 1 'engineer' $LOCALIZE | sed '/*\/$/ s_.*__') + +# If there were missing comments +if [ -n "$MISSING" ]; then + echo "Comments are missing for:" + + #Print output, putting line breaks back in and indenting each line + echo $MISSING | sed 's:-- :\ +:' | sed 's/^/& /g' + + # Return non-zero to signal an error + exit 1 +fi \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/Scripts/push-output.sh b/Carthage/Checkouts/UnzipKit/Scripts/push-output.sh new file mode 100755 index 0000000..a0a8104 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Scripts/push-output.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +echo + +# Only potentially push to CocoaPods when it's a tagged build +if [ -z "$TRAVIS_TAG" ]; then + echo -e "\nBuild is not tagged" + exit 0 +fi + +# Make sure tag name looks like a version number +if ! [[ $TRAVIS_TAG =~ ^[0-9\.]+(\-beta[0-9]*)?$ ]]; then + echo -e "\nBranch build not a valid version number: $TRAVIS_TAG" + exit 1 +else + echo -e "\nTag looks like a version number: $TRAVIS_TAG" +fi + +# Skip tests because they're assumed to have passed during the cocoapod-validate script or else +# this script wouldn't run +echo -e "\nLinting podspec..." +pod spec lint --fail-fast --skip-tests + +if [ $? -ne 0 ]; then + echo -e "\nPodspec failed lint. Run again with --verbose to troubleshoot" + exit 1 +fi + +echo -e "\nExporting Carthage archive...\n" +# Exports ARCHIVE_PATH, used below +source ./Scripts/archive-carthage.sh + +# Skip tests for reason stated above +echo -e "\nPushing to CocoaPods...\n" +pod trunk push --skip-tests + +# If push is successful, add release to GitHub +if [ $? -ne 0 ]; then + echo -e "\nPush to CocoaPods failed" + exit 1 +fi + +RELEASE_NOTES=$(./Scripts/get-release-notes.py "$TRAVIS_TAG") +./Scripts/add-github-release.py $GITHUB_RELEASE_API_TOKEN $TRAVIS_REPO_SLUG $TRAVIS_TAG "$ARCHIVE_PATH" "$RELEASE_NOTES" \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/Scripts/set-travis-tag-to-latest.sh b/Carthage/Checkouts/UnzipKit/Scripts/set-travis-tag-to-latest.sh new file mode 100755 index 0000000..0d47e54 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Scripts/set-travis-tag-to-latest.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +git fetch --tags + +if [ -z "$TRAVIS_TAG" ]; then + TRAVIS_TAG_SUBSTITUTED=1 + export TRAVIS_TAG="$(git tag -l | tail -1)" + echo "Not a tagged build. Using last tag ($TRAVIS_TAG)..." +fi diff --git a/Carthage/Checkouts/UnzipKit/Scripts/set-version.sh b/Carthage/Checkouts/UnzipKit/Scripts/set-version.sh new file mode 100755 index 0000000..4f65eb2 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Scripts/set-version.sh @@ -0,0 +1,59 @@ +#!/bin/bash + +# Usage: set-version.sh +# +# Updates the main plist file, then tags the build in Git, using the release notes from CHANGELOG.md + +# Colors +COLOR_OFF='\033[0m' +RED='\033[0;31m' +GREEN='\033[0;32m' +BOLD_YELLOW='\033[1;33m' + +# Did this script change since the last commit? +THIS_FILE_REGEX='.*Scripts/set-version\.sh.*' +THIS_FILE_CHANGED=$(git status --porcelain --untracked-files=no | grep $THIS_FILE_REGEX | wc -l) + +# Only continue if the repo has no changes (excluding this script) +CHANGED_FILE_COUNT=$(git status --porcelain --untracked-files=no | grep -v $THIS_FILE_REGEX | wc -l) +if [ $CHANGED_FILE_COUNT -gt 0 ]; then + echo -e "${RED}Please commit or discard any changes before continuing$COLOR_OFF" + exit 1 +fi + +# Require a single argument to be passed in +if [ "$#" -ne 1 ]; then + echo -e "${RED}Please pass the desired version number as an argument$COLOR_OFF" + exit 1 +fi + +./Scripts/get-release-notes.py $1 --beta-notes-check + +# Check whether beta notes have been updated. The check passes for first- or non-beta releases +if [ ! $? -eq 0 ]; then + exit 1 +fi + +RELEASE_NOTES=$(./Scripts/get-release-notes.py $1) +if [ -z "$RELEASE_NOTES" ]; then + echo -e "${RED}Please add release notes for v$1 into CHANGELOG.md$COLOR_OFF" + exit 1 +fi + +echo -e "${GREEN}Updating version numbers in plist to '$1'..$COLOR_OFF" +agvtool new-version -all "$1" # CFBundleVersion +agvtool new-marketing-version "$1" # CFBundleShortVersionString + +if [ "$THIS_FILE_CHANGED" -gt 0 ]; then + echo -e "${BOLD_YELLOW}Not committing to Git, as this script isn't final. Commit it to continue$COLOR_OFF" + exit 2 +fi + +echo -e "${GREEN}Committing updated plist...$COLOR_OFF" +git commit -m "Updated version to v$1" Source Resources + +# Revert changes to other plist files +git checkout . + +echo -e "${GREEN}Tagging build...$COLOR_OFF" +git tag $1 -m "$RELEASE_NOTES" \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/Scripts/unset-travis-tag.sh b/Carthage/Checkouts/UnzipKit/Scripts/unset-travis-tag.sh new file mode 100755 index 0000000..4b03586 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Scripts/unset-travis-tag.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +if [ -n "$TRAVIS_TAG_SUBSTITUTED" ]; then + echo "Unsetting TRAVIS_TAG..." + unset TRAVIS_TAG +fi \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/Source/Extensions/NSURL+UnzipKitExtensions.h b/Carthage/Checkouts/UnzipKit/Source/Extensions/NSURL+UnzipKitExtensions.h new file mode 100644 index 0000000..b0abcf5 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Source/Extensions/NSURL+UnzipKitExtensions.h @@ -0,0 +1,15 @@ +// +// NSURL+UnzipKitExtensions.h +// UnzipKit +// +// Created by Dov Frankel on 6/29/16. +// Copyright © 2016 Abbey Code. All rights reserved. +// + +#import + +@interface NSURL (UnzipKitExtensions) + +- (nullable NSString *)volumeName; + +@end diff --git a/Carthage/Checkouts/UnzipKit/Source/Extensions/NSURL+UnzipKitExtensions.m b/Carthage/Checkouts/UnzipKit/Source/Extensions/NSURL+UnzipKitExtensions.m new file mode 100644 index 0000000..b948ed9 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Source/Extensions/NSURL+UnzipKitExtensions.m @@ -0,0 +1,33 @@ +// +// NSURL+UnzipKitExtensions.m +// UnzipKit +// +// Created by Dov Frankel on 6/29/16. +// Copyright © 2016 Abbey Code. All rights reserved. +// + +#import "NSURL+UnzipKitExtensions.h" + +#import "UnzipKitMacros.h" + +@implementation NSURL (UnzipKitExtensions) + +- (NSString *)volumeName { + + if (!self.isFileURL) { + return nil; + } + + NSError *error = nil; + NSString *result = nil; + + [self getResourceValue:&result forKey:NSURLVolumeNameKey error:&error]; + + if (!result && error) { + UZKLogError("Error retrieving volume name of %{public}@: %{public}@", self.path, error); + } + + return result; +} + +@end diff --git a/Carthage/Checkouts/UnzipKit/Source/Info.plist b/Carthage/Checkouts/UnzipKit/Source/Info.plist new file mode 100644 index 0000000..1e28140 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Source/Info.plist @@ -0,0 +1,28 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.9 + CFBundleSignature + ???? + CFBundleVersion + 1.9 + NSHumanReadableCopyright + © 2017 Abbey Code. All rights reserved. + NSPrincipalClass + + + diff --git a/Carthage/Checkouts/UnzipKit/Source/UZKArchive.h b/Carthage/Checkouts/UnzipKit/Source/UZKArchive.h new file mode 100644 index 0000000..ce99538 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Source/UZKArchive.h @@ -0,0 +1,949 @@ +// +// UZKArchive.h +// UnzipKit +// +// + +#import +#import + +#import "UZKFileInfo.h" + +/** + * Defines the various error codes that the listing and extraction methods return. + * These are returned in NSError's [code]([NSError code]) field. + */ +typedef NS_ENUM(NSInteger, UZKErrorCode) { + + /** + * An error from zlib reading or writing the file (UNZ_ERRNO/ZIP_ERRNO) + */ + UZKErrorCodeZLibError = -1, + + /** + * An error with a parameter, usually the file name (UNZ_PARAMERROR/ZIP_PARAMERROR) + */ + UZKErrorCodeParameterError = -102, + + /** + * The Zip file appears to be corrupted, or invalid (UNZ_BADZIPFILE/ZIP_BADZIPFILE) + */ + UZKErrorCodeBadZipFile = -103, + + /** + * An error internal to MiniZip (UNZ_INTERNALERROR/ZIP_INTERNALERROR) + */ + UZKErrorCodeInternalError = -104, + + /** + * The decompressed file's CRC doesn't match the original file's CRC (UNZ_CRCERROR) + */ + UZKErrorCodeCRCError = -105, + + /** + * Failure to find/open the archive + */ + UZKErrorCodeArchiveNotFound = 101, + + /** + * Error reading or advancing through the archive + */ + UZKErrorCodeFileNavigationError = 102, + + /** + * Error finding a file in the archive + */ + UZKErrorCodeFileNotFoundInArchive = 103, + + /** + * Error writing an extracted file to disk + */ + UZKErrorCodeOutputError = 104, + + /** + * The destination directory is a file. Not used anymore + */ + UZKErrorCodeOutputErrorPathIsAFile = 105, + + /** + * Password given doesn't decrypt the archive + */ + UZKErrorCodeInvalidPassword = 106, + + /** + * Error reading a file in the archive + */ + UZKErrorCodeFileRead = 107, + + /** + * Error opening a file in the archive for writing + */ + UZKErrorCodeFileOpenForWrite = 108, + + /** + * Error writing a file in the archive + */ + UZKErrorCodeFileWrite = 109, + + /** + * Error closing the file in the archive + */ + UZKErrorCodeFileCloseWriting = 110, + + /** + * Error deleting a file in the archive + */ + UZKErrorCodeDeleteFile = 111, + + /** + * Tried to read before all writes have completed, or vise-versa + */ + UZKErrorCodeMixedModeAccess = 112, + + /** + * Error reading the global comment of the archive + */ + UZKErrorCodeReadComment = 113, + + /** + * The CRC given up front doesn't match the calculated CRC + */ + UZKErrorCodePreCRCMismatch = 114, + + /** + * The zip is compressed using Deflate64 (compression method 9), which isn't supported + */ + UZKErrorCodeDeflate64 = 115, + + /** + * User cancelled the operation + */ + UZKErrorCodeUserCancelled = 116, +}; + + +typedef NSString *const UZKProgressInfoKey; + +/** + * Defines the keys passed in `-[NSProgress userInfo]` for certain methods + */ +static UZKProgressInfoKey _Nonnull +/** + * For `extractFilesTo:overwrite:error:`, this key contains an instance of URKFileInfo with the file currently being extracted + */ +UZKProgressInfoKeyFileInfoExtracting = @"UZKProgressInfoKeyFileInfoExtracting"; + +NS_ASSUME_NONNULL_BEGIN + +extern NSString *UZKErrorDomain; + +@interface UZKArchive : NSObject +// Minimum of iOS 9, macOS 10.11 SDKs +#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED > 90000) || (defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED > 101100) + +#endif + +/** + * The URL of the archive. Returns nil if the URL becomes unreachable + */ +@property(weak, nonatomic, readonly, nullable) NSURL *fileURL; + +/** + * The filename of the archive. Returns nil if the archive file becomes unreachable + */ +@property(weak, nonatomic, readonly, nullable) NSString *filename; + +/** + * The password of the archive + */ +@property(strong, nullable) NSString *password; + +/** + * The global comment inside the archive + * + * Comments are written in UTF-8, and read in UTF-8 and Windows/CP-1252, falling back to defaultCStringEncoding + */ +@property(retain, atomic, nullable) NSString *comment; + +/** + * Can be used for progress reporting, but it's not necessary. You can also use + * implicit progress reporting. If you don't use it, one will still be created, + * which will become a child progress of whichever one is the current NSProgress + * instance. + * + * To use this, assign it before beginning an operation that reports progress. Once + * the method you're calling has a reference to it, it will nil it out. Please check + * for nil before assigning it to avoid concurrency conflicts. + */ +@property(nullable, strong) NSProgress *progress; + + +/** + * DEPRECATED: Creates and returns an archive at the given path + * + * @param filePath A path to the archive file + * + * @return Returns a UZKArchive object, or nil if the path isn't reachable + */ ++ (nullable instancetype)zipArchiveAtPath:(NSString *)filePath __deprecated_msg("Use -initWithPath:error: instead"); + +/** + * DEPRECATED: Creates and returns an archive at the given URL + * + * @param fileURL The URL of the archive file + * + * @return Returns a UZKArchive object, or nil if the URL isn't reachable + */ ++ (nullable instancetype)zipArchiveAtURL:(NSURL *)fileURL __deprecated_msg("Use -initWithURL:error: instead"); + +/** + * DEPRECATED: Creates and returns an archive at the given path, with a given password + * + * @param filePath A path to the archive file + * @param password The password of the given archive + * + * @return Returns a UZKArchive object, or nil if the path isn't reachable + */ ++ (nullable instancetype)zipArchiveAtPath:(NSString *)filePath password:(nullable NSString *)password __deprecated_msg("Use -initWithPath:password:error: instead"); + +/** + * DEPRECATED: Creates and returns an archive at the given URL, with a given password + * + * @param fileURL The URL of the archive file + * @param password The password of the given archive + * + * @return Returns a UZKArchive object, or nil if the URL isn't reachable + */ ++ (nullable instancetype)zipArchiveAtURL:(NSURL *)fileURL password:(nullable NSString *)password __deprecated_msg("Use -initWithURL:password:error: instead");; + + +/** + * Creates and returns an archive at the given path + * + * @param filePath A path to the archive file + * @param error Returns an error code if the object can't be initialized + * + * @return Returns a UZKArchive object, or nil if the path isn't reachable + */ +- (nullable instancetype)initWithPath:(NSString *)filePath error:(NSError **)error; + +/** + * Creates and returns an archive at the given URL + * + * @param fileURL The URL of the archive file + * @param error Returns an error code if the object can't be initialized + * + * @return Returns a UZKArchive object, or nil if the URL isn't reachable + */ +- (nullable instancetype)initWithURL:(NSURL *)fileURL error:(NSError **)error; + +/** + * Creates and returns an archive at the given path, with a given password + * + * @param filePath A path to the archive file + * @param password The password of the given archive + * @param error Returns an error code if the object can't be initialized + * + * @return Returns a UZKArchive object, or nil if the path isn't reachable + */ +- (nullable instancetype)initWithPath:(NSString *)filePath password:(nullable NSString *)password error:(NSError **)error; + +/** + * Creates and returns an archive at the given URL, with a given password + * + * @param fileURL The URL of the archive file + * @param password The password of the given archive + * @param error Returns an error code if the object can't be initialized + * + * @return Returns a UZKArchive object, or nil if the URL isn't reachable + */ +- (nullable instancetype)initWithURL:(NSURL *)fileURL password:(nullable NSString *)password error:(NSError **)error; + + + +#pragma mark - Read Methods + + +/** + * Determines whether a file is a Zip file by reading the header + * + * @param filePath Path to the file being checked + * + * @return YES if the file exists and contains a signature indicating it is a Zip file + */ ++ (BOOL)pathIsAZip:(NSString *)filePath; + +/** + * Determines whether a file is a Zip file by reading the header + * + * @param fileURL URL of the file being checked + * + * @return YES if the file exists and contains a signature indicating it is a Zip file + */ ++ (BOOL)urlIsAZip:(NSURL *)fileURL; + + +/** + * Lists the names of the files in the archive + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return Returns a list of NSString containing the paths within the archive's contents, or nil if an error was encountered + */ +- (nullable NSArray *)listFilenames:(NSError **)error; + +/** + * Lists the various attributes of each file in the archive + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return Returns a list of UZKFileInfo objects, which contain metadata about the archive's files, or nil if an error was encountered + */ +- (nullable NSArray *)listFileInfo:(NSError **)error; + +/** + * Writes all files in the archive to the given path. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction. Use the progress property (as explained in the README) to + * retrieve more detailed information, such as the current file being extracted, number of files extracted, + * and the URKFileInfo instance being extracted + * + * @param destinationDirectory The destination path of the unarchived files + * @param overwrite YES to overwrite files in the destination directory, NO otherwise + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return YES on successful extraction, NO if an error was encountered + */ +- (BOOL)extractFilesTo:(NSString *)destinationDirectory + overwrite:(BOOL)overwrite + error:(NSError **)error; + +/** + * **DEPRECATED:** Writes all files in the archive to the given path + * + * @param destinationDirectory The destination path of the unarchived files + * @param overwrite YES to overwrite files in the destination directory, NO otherwise + * @param progress Called every so often to report the progress of the extraction + * + * - *currentFile* The info about the file that's being extracted + * - *percentArchiveDecompressed* The percentage of the archive that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return YES on successful extraction, NO if an error was encountered + */ +- (BOOL)extractFilesTo:(NSString *)destinationDirectory + overwrite:(BOOL)overwrite + progress:(nullable void (^)(UZKFileInfo *currentFile, CGFloat percentArchiveDecompressed))progress + error:(NSError **)error __deprecated_msg("Use -extractFilesTo:overwrite:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * Unarchive a single file from the archive into memory. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction + * + * @param fileInfo The info of the file within the archive to be expanded. Only the filename property is used + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractData:(UZKFileInfo *)fileInfo + error:(NSError **)error; + +/** + * **DEPRECATED:** Unarchive a single file from the archive into memory + * + * @param fileInfo The info of the file within the archive to be expanded. Only the filename property is used + * @param progress Called every so often to report the progress of the extraction + * + * - *percentDecompressed* The percentage of the archive that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractData:(UZKFileInfo *)fileInfo + progress:(nullable void (^)(CGFloat percentDecompressed))progress + error:(NSError **)error __deprecated_msg("Use -extractData:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * Unarchive a single file from the archive into memory. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction + * + * @param filePath The path of the file within the archive to be expanded + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractDataFromFile:(NSString *)filePath + error:(NSError **)error; + +/** + * **DEPRECATED:** Unarchive a single file from the archive into memory + * + * @param filePath The path of the file within the archive to be expanded + * @param progress Called every so often to report the progress of the extraction + * + * - *percentDecompressed* The percentage of the file that has been decompressed + * + * @param error Contains an NSError object when there was an error reading the archive + * + * @return An NSData object containing the bytes of the file, or nil if an error was encountered + */ +- (nullable NSData *)extractDataFromFile:(NSString *)filePath + progress:(nullable void (^)(CGFloat percentDecompressed))progress + error:(NSError **)error __deprecated_msg("Use -extractDataFromFile:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * Loops through each file in the archive into memory, allowing you to perform an action + * using its info. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of the operation + * + * @param action The action to perform using the data + * + * - *fileInfo* The metadata of the file within the archive + * - *stop* Set to YES to stop reading the archive + * + * @param error Contains an error if any was returned + * + * @return YES if no errors were encountered, NO otherwise + */ +- (BOOL)performOnFilesInArchive:(void(^)(UZKFileInfo *fileInfo, BOOL *stop))action + error:(NSError **)error; + +/** + * Extracts each file in the archive into memory, allowing you to perform an action + * on it. Supports NSProgress for progress reporting, which also allows cancellation + * in the middle of the operation + * + * @param action The action to perform using the data + * + * - *fileInfo* The metadata of the file within the archive + * - *fileData* The full data of the file in the archive + * - *stop* Set to YES to stop reading the archive + * + * @param error Contains an error if any was returned + * + * @return YES if no errors were encountered, NO otherwise + */ +- (BOOL)performOnDataInArchive:(void(^)(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop))action + error:(NSError **)error; + +/** + * Unarchive a single file from the archive into memory. Supports NSProgress for progress reporting, which also + * allows cancellation in the middle of extraction + * + * @param filePath The path of the file within the archive to be expanded + * @param error Contains an NSError object when there was an error reading the archive + * @param action The block to run for each chunk of data, each of size <= bufferSize + * + * - *dataChunk* The data read from the archived file. Read bytes and length to write the data + * - *percentDecompressed* The percentage of the file that has been decompressed + * + * @return YES if all data was read successfully, NO if an error was encountered + */ +- (BOOL)extractBufferedDataFromFile:(NSString *)filePath + error:(NSError **)error + action:(void(^)(NSData *dataChunk, CGFloat percentDecompressed))action; + +/** + * YES if archive protected with a password, NO otherwise + */ +- (BOOL)isPasswordProtected; + +/** + * Tests whether the provided password unlocks the archive + * + * @return YES if correct password or archive is not password protected, NO if password is wrong + */ +- (BOOL)validatePassword; + +/** + Extract each file in the archive, checking whether the data matches the CRC checksum + stored at the time it was written + + @return YES if the data is all correct, false if any check failed + */ +- (BOOL)checkDataIntegrity; + +/** + Extract a particular file, to determine if its data matches the CRC + checksum stored at the time it written + + @param filePath The file in the archive to check + + @return YES if the data is correct, false if any check failed + */ +- (BOOL)checkDataIntegrityOfFile:(NSString *)filePath; + + + +#pragma mark - Write Methods + + +/** + * 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 filePath The full path to the target file in the archive + * @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 + filePath:(NSString *)filePath + 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 + * @param progress Called every so often to report the progress of the compression + * + * - *percentCompressed* The percentage of the file that has been compressed + * + * @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 + filePath:(NSString *)filePath + progress:(nullable void (^)(CGFloat percentCompressed))progress + error:(NSError **)error __deprecated_msg("Use -writeData:filePath:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * 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 + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + 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 + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param progress Called every so often to report the progress of the compression + * + * - *percentCompressed* The percentage of the file that has been compressed + * + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + progress:(nullable void (^)(CGFloat percentCompressed))progress + error:(NSError **)error __deprecated_msg("Use -writeData:filePath:fileDate:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * 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 + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + 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 + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @param progress Called every so often to report the progress of the compression + * + * - *percentCompressed* The percentage of the file that has been compressed + * + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + progress:(nullable void (^)(CGFloat percentCompressed))progress + error:(NSError **)error __deprecated_msg("Use -writeData:filePath:fileDate:compressionMethod:password:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * 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. + * + * @param data Data to write into the archive + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + error:(NSError **)error; + +/** + * 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. + * + * @param data Data to write into the archive + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param permissions The desired POSIX permissions of the file in the archive + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + posixPermissions:(short)permissions +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + error:(NSError **)error; + +/** + * **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. + * + * @param data Data to write into the archive + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param progress Called every so often to report the progress of the compression + * + * - *percentCompressed* The percentage of the file that has been compressed + * + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + progress:(nullable void (^)(CGFloat percentCompressed))progress + error:(NSError **)error __deprecated_msg("Use -writeData:filePath:fileDate:compressionMethod:password:overwrite:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * **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. + * + * @param data Data to write into the archive + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param permissions The desired POSIX permissions of the file in the archive + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param password Override the password associated with the archive (not recommended) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param progress Called every so often to report the progress of the compression + * + * - *percentCompressed* The percentage of the file that has been compressed + * + * @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 + filePath:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + posixPermissions:(short)permissions +compressionMethod:(UZKCompressionMethod)method + password:(nullable NSString *)password + overwrite:(BOOL)overwrite + progress:(nullable void (^)(CGFloat percentCompressed))progress + error:(NSError **)error __deprecated_msg("Use -writeData:filePath:fileDate:permissions:compressionMethod:password:overwrite:error: instead, and if using the progress block, replace with NSProgress as described in the README"); + +/** + * 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 + * @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:(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 filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @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:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + 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 filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @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:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + compressionMethod:(UZKCompressionMethod)method + 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, 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. + * + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @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:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + compressionMethod:(UZKCompressionMethod)method + overwrite:(BOOL)overwrite + 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, 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. + * + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param preCRC The CRC-32 for the data being sent. Only necessary if encrypting the file. + Pass 0 otherwise + * @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:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + 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; + +/** + * 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 + * be slow. On the other hand, when not overwriting, the size of the archive will grow each time + * the file is written. + * + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param preCRC The CRC-32 for the data being sent. Only necessary if encrypting the file. + * Pass 0 otherwise + * @param password Override the password associated with the archive (not recommended) + * @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:(NSString *)filePath + fileDate:(nullable NSDate *)fileDate + 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; + + +/** + * 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 + * be slow. On the other hand, when not overwriting, the size of the archive will grow each time + * the file is written. + * + * @param filePath The full path to the target file in the archive + * @param fileDate The timestamp of the file in the archive. Uses the current time if nil + * @param permissions The desired POSIX permissions of the file in the archive + * @param method The UZKCompressionMethod to use (Default, None, Fastest, Best) + * @param overwrite If YES, and the file exists, delete it before writing. If NO, append + * the data into the archive without removing it first (legacy Objective-Zip + * behavior) + * @param preCRC The CRC-32 for the data being sent. Only necessary if encrypting the file. + * Pass 0 otherwise + * @param password Override the password associated with the archive (not recommended) + * @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:(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; + +/** + * Removes the given file from the archive + * + * @param filePath The file in the archive you wish to delete + * @param error Contains an NSError object when there was an error writing to the archive + * + * @return YES if the file was successfully deleted, NO otherwise + */ +- (BOOL)deleteFile:(NSString *)filePath error:(NSError **)error; + + +@end +NS_ASSUME_NONNULL_END diff --git a/Carthage/Checkouts/UnzipKit/Source/UZKArchive.m b/Carthage/Checkouts/UnzipKit/Source/UZKArchive.m new file mode 100644 index 0000000..a8ac32a --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Source/UZKArchive.m @@ -0,0 +1,2827 @@ +// +// UZKArchive.m +// UnzipKit +// +// + +#import "UZKArchive.h" + +#import "zip.h" + +#import "UZKFileInfo.h" +#import "UZKFileInfo_Private.h" +#import "UnzipKitMacros.h" +#import "NSURL+UnzipKitExtensions.h" + + +NSString *UZKErrorDomain = @"UZKErrorDomain"; + +#define FILE_IN_ZIP_MAX_NAME_LENGTH (512) + + +typedef NS_ENUM(NSUInteger, UZKFileMode) { + UZKFileModeUnassigned = -1, + UZKFileModeUnzip = 0, + UZKFileModeCreate, + UZKFileModeAppend +}; + +static NSBundle *_resources = nil; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundef" +#if UNIFIED_LOGGING_SUPPORTED +os_log_t unzipkit_log; +BOOL unzipkitIsAtLeast10_13SDK; +#endif +#pragma clang diagnostic pop + + +@interface UZKArchive () + +- (instancetype)init NS_UNAVAILABLE; + +- (instancetype)initWithFile:(NSURL *)fileURL password:(NSString*)password error:(NSError * __autoreleasing*)error +#if (TARGET_OS_IPHONE && __IPHONE_OS_VERSION_MIN_REQUIRED > __IPHONE_7_0) || MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_9 +NS_DESIGNATED_INITIALIZER +#endif +; + +@property (strong) NSData *fileBookmark; +@property (strong) NSURL *fallbackURL; + +@property (assign) NSInteger openCount; + +@property (assign) UZKFileMode mode; +@property (assign) zipFile zipFile; +@property (assign) unzFile unzFile; +@property (strong) NSDictionary *archiveContents; + +@property (strong) NSObject *threadLock; + +@property (assign) BOOL commentRetrieved; + +@end + + +@implementation UZKArchive + +@synthesize comment = _comment; + + +#pragma mark - Deprecated Convenience Methods + + ++ (UZKArchive *)zipArchiveAtPath:(NSString *)filePath +{ + return [[UZKArchive alloc] initWithPath:filePath error:nil]; +} + ++ (UZKArchive *)zipArchiveAtURL:(NSURL *)fileURL +{ + return [[UZKArchive alloc] initWithURL:fileURL error:nil]; +} + ++ (UZKArchive *)zipArchiveAtPath:(NSString *)filePath password:(NSString *)password +{ + return [[UZKArchive alloc] initWithPath:filePath password:password error:nil]; +} + ++ (UZKArchive *)zipArchiveAtURL:(NSURL *)fileURL password:(NSString *)password +{ + return [[UZKArchive alloc] initWithURL:fileURL password:password error:nil]; +} + + + +#pragma mark - Initializers + ++ (void)initialize { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + NSBundle *mainBundle = [NSBundle mainBundle]; + NSURL *resourcesURL = [mainBundle URLForResource:@"UnzipKitResources" withExtension:@"bundle"]; + + _resources = (resourcesURL + ? [NSBundle bundleWithURL:resourcesURL] + : mainBundle); + + UZKLogInit(); + }); +} + +- (instancetype)init { + NSAssert(NO, @"Do not use -init. Use one of the -initWithPath or -initWithURL variants", nil); + @throw nil; +} + +- (instancetype)initWithPath:(NSString *)filePath error:(NSError * __autoreleasing*)error +{ + return [self initWithFile:[NSURL fileURLWithPath:filePath] error:error]; +} + +- (instancetype)initWithURL:(NSURL *)fileURL error:(NSError * __autoreleasing*)error +{ + return [self initWithFile:fileURL error:error]; +} + +- (instancetype)initWithPath:(NSString *)filePath password:(NSString *)password error:(NSError * __autoreleasing*)error +{ + return [self initWithFile:[NSURL fileURLWithPath:filePath] + password:password + error:error]; +} + +- (instancetype)initWithURL:(NSURL *)fileURL password:(NSString *)password error:(NSError * __autoreleasing*)error +{ + return [self initWithFile:fileURL password:password error:error]; +} + +- (instancetype)initWithFile:(NSURL *)fileURL error:(NSError * __autoreleasing*)error +{ + return [self initWithFile:fileURL password:nil error:error]; +} + +- (instancetype)initWithFile:(NSURL *)fileURL password:(NSString*)password error:(NSError * __autoreleasing*)error +{ + if ((self = [super init])) { + UZKCreateActivity("Init Archive"); + + if (!fileURL) { + UZKLogError("Nil fileURL passed to UZKArchive initializer") + return nil; + } + + UZKLogInfo("Initializing archive with URL %{public}@, path %{public}@, password %{public}@", fileURL, fileURL.path, [password length] != 0 ? @"given" : @"not given"); + + if ([fileURL checkResourceIsReachableAndReturnError:NULL]) { + NSError *bookmarkError = nil; + if (![self storeFileBookmark:fileURL error:&bookmarkError]) { + UZKLogError("Error creating bookmark to ZIP archive: %{public}@", bookmarkError); + + if (error) { + *error = bookmarkError; + } + + return nil; + } + } else { + UZKLogInfo("URL %{public}@ doesn't yet exist", fileURL) + } + + UZKLogDebug("Initializing private fields"); + + _openCount = 0; + _mode = UZKFileModeUnassigned; + + _fallbackURL = fileURL; + _password = password; + _threadLock = [[NSObject alloc] init]; + + _commentRetrieved = NO; + } + + return self; +} + + + +#pragma mark - Properties + + +- (NSURL *)fileURL +{ + UZKCreateActivity("Read Archive URL"); + + NSError *checkExistsError = nil; + + if (!self.fileBookmark + || (self.fallbackURL && [self.fallbackURL checkResourceIsReachableAndReturnError:&checkExistsError])) + { + UZKLogDebug("checkResourceIsReachableAndReturnError returned false with error: %{public}@", checkExistsError); + UZKLogInfo("Returning fallback URL for archive"); + return self.fallbackURL; + } + + UZKLogInfo("Resolving archive bookmark (base64):\n%{public}@", [self.fileBookmark base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]); + + BOOL bookmarkIsStale = NO; + NSError *error = nil; + + NSURL *result = [NSURL URLByResolvingBookmarkData:self.fileBookmark + options:(NSURLBookmarkResolutionOptions)0 + relativeToURL:nil + bookmarkDataIsStale:&bookmarkIsStale + error:&error]; + + + if (!result) { + UZKLogFault("Error resolving bookmark to ZIP archive: %{public}@", error); + return nil; + } + + UZKLogDebug("Resolved bookmark. URL: %{public}@, isStale: %{public}@", result, bookmarkIsStale ? @"YES" : @"NO"); + + if (bookmarkIsStale) { + UZKLogDebug("Refreshing stale bookmark"); + self.fallbackURL = result; + + if (![self storeFileBookmark:result + error:&error]) { + UZKLogFault("Error creating fresh bookmark to ZIP archive: %{public}@", error); + } + } + + return result; +} + +- (NSString *)filename +{ + UZKCreateActivity("Read Archive Filename"); + + NSURL *url = self.fileURL; + + if (!url) { + return nil; + } + + return url.path; +} + +- (NSString *)comment +{ + UZKCreateActivity("Read Archive Comment"); + + if (self.commentRetrieved) { + UZKLogDebug("Returning cached comment"); + return _comment; + } + + _comment = [self readGlobalComment]; + return _comment; +} + +- (void)setComment:(NSString *)comment +{ + UZKCreateActivity("Write Archive Comment"); + + _comment = comment; + self.commentRetrieved = YES; + + UZKLogInfo("Opening archive in Append mode with comment set to write it"); + + NSError *error = nil; + BOOL success = [self performActionWithArchiveOpen:nil + inMode:UZKFileModeAppend + error:&error]; + + if (!success) { + UZKLogError("Failed to write comment to archive: %{public}@", error); + } +} + + + +#pragma mark - Zip file detection + + ++ (BOOL)pathIsAZip:(NSString *)filePath +{ + UZKCreateActivity("Determining File Type (Path)"); + + NSFileHandle *handle = [NSFileHandle fileHandleForReadingAtPath:filePath]; + + if (!handle) { + UZKLogError("No file handle returned for path: %{public}@", filePath); + return NO; + } + + @try { + NSData *fileData = [handle readDataOfLength:4]; + + if (fileData.length < 4) { + UZKLogDebug("File is not a ZIP. Less than 4 bytes of data"); + return NO; + } + + const unsigned char *dataBytes = fileData.bytes; + + // First two bytes must equal 'PK' + if (dataBytes[0] != 0x50 || dataBytes[1] != 0x4b) { + UZKLogDebug("File is not a ZIP. First two bytes are not PK"); + return NO; + } + + // Check for standard Zip + if (dataBytes[2] == 0x03 && + dataBytes[3] == 0x04) { + UZKLogDebug("File is a standard ZIP"); + return YES; + } + + // Check for empty Zip + if (dataBytes[2] == 0x05 && + dataBytes[3] == 0x06) { + UZKLogDebug("File is an empty ZIP"); + return YES; + } + + // Check for spanning Zip + if (dataBytes[2] == 0x07 && + dataBytes[3] == 0x08) { + UZKLogDebug("File is a spanning ZIP"); + return YES; + } + + UZKLogDebug("File is not a ZIP. Unknown contents in 3rd and 4th bytes (%02X %02X)", dataBytes[2], dataBytes[3]); + } + @finally { + [handle closeFile]; + } + + return NO; +} + ++ (BOOL)urlIsAZip:(NSURL *)fileURL +{ + UZKCreateActivity("Determining File Type (URL)"); + + if (!fileURL || !fileURL.path) { + UZKLogDebug("File is not a ZIP: nil URL or path"); + return NO; + } + + return [UZKArchive pathIsAZip:(NSString* _Nonnull)fileURL.path]; +} + + + +#pragma mark - Read Methods + + +- (NSArray *)listFilenames:(NSError * __autoreleasing*)error +{ + UZKCreateActivity("Listing Filenames"); + + NSArray *zipInfos = [self listFileInfo:error]; + + if (!zipInfos) { + UZKLogDebug("No file info returned"); + return nil; + } + + return (NSArray* _Nonnull)[zipInfos valueForKeyPath:@"filename"]; +} + +- (NSArray *)listFileInfo:(NSError * __autoreleasing*)error +{ + UZKCreateActivity("Listing File Info"); + + if (error) { + *error = nil; + } + + NSError *checkExistsError = nil; + if (![self.fileURL checkResourceIsReachableAndReturnError:&checkExistsError]) { + UZKLogError("File %{public}@ doesn't exist: %{public}@", self.fileURL, checkExistsError); + return @[]; + } + + NSError *unzipError; + + __weak UZKArchive *welf = self; + NSMutableArray *zipInfos = [NSMutableArray array]; + + BOOL success = [self performActionWithArchiveOpen:^(NSError * __autoreleasing*innerError) { + UZKCreateActivity("Finding File Info Items"); + + UZKLogInfo("Getting global info..."); + unzGoToNextFile(welf.unzFile); + + unz_global_info gi; + int err = unzGetGlobalInfo(welf.unzFile, &gi); + if (err != UNZ_OK) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error getting global info (%d)", @"UnzipKit", _resources, @"Detailed error string"), + err]; + UZKLogError("UZKErrorCodeArchiveNotFound: %{public}@", detail); + [welf assignError:innerError code:UZKErrorCodeArchiveNotFound + detail:detail]; + return; + } + + NSUInteger fileCount = gi.number_entry; + UZKLogDebug("fileCount: %lu", (unsigned long)fileCount); + + UZKLogInfo("Going to first file..."); + err = unzGoToFirstFile(welf.unzFile); + + if (err != UNZ_OK) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error going to first file in archive (%d)", @"UnzipKit", _resources, @"Detailed error string"), + err]; + UZKLogError("UZKErrorCodeFileNavigationError: %{public}@", detail); + [welf assignError:innerError code:UZKErrorCodeFileNavigationError + detail:detail]; + return; + } + + for (NSUInteger i = 0; i < fileCount; i++) { + UZKLogDebug("Iterating through file info (iteration #%lu)", (unsigned long)i+1); + UZKFileInfo *info = [welf currentFileInZipInfo:innerError]; + + if (info) { + UZKLogDebug("Info found: %{public}@", info.filename); + [zipInfos addObject:info]; + } else { + UZKLogDebug("Info not found"); + return; + } + + UZKLogDebug("Going to next file..."); + err = unzGoToNextFile(welf.unzFile); + if (err == UNZ_END_OF_LIST_OF_FILE) { + UZKLogInfo("End of file found"); + return; + } + + if (err != UNZ_OK) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error navigating to next file (%d)", @"UnzipKit", _resources, @"Detailed error string"), + err]; + UZKLogError("UZKErrorCodeFileNavigationError: %{public}@", detail); + [welf assignError:innerError code:UZKErrorCodeFileNavigationError + detail:detail]; + return; + } + } + } inMode:UZKFileModeUnzip error:&unzipError]; + + if (!success) { + if (error) { + *error = unzipError; + } + + return nil; + } + + return [zipInfos copy]; +} + +- (BOOL)extractFilesTo:(NSString *)destinationDirectory + overwrite:(BOOL)overwrite + error:(NSError * __autoreleasing*)error +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return [self extractFilesTo:destinationDirectory + overwrite:overwrite + progress:nil + error:error]; +#pragma clang diagnostic pop +} + +- (BOOL)extractFilesTo:(NSString *)destinationDirectory + overwrite:(BOOL)overwrite + progress:(void (^)(UZKFileInfo *currentFile, CGFloat percentArchiveDecompressed))progressBlock + error:(NSError * __autoreleasing*)error +{ + UZKCreateActivity("Extracting Files to Directory"); + + NSError *listError = nil; + NSArray *fileInfo = [self listFileInfo:&listError]; + + if (!fileInfo || listError) { + UZKLogError("Error listing contents of archive: %{public}@", listError); + + if (error) { + *error = listError; + } + + return NO; + } + + NSFileManager *fm = [[NSFileManager alloc] init]; + + NSNumber *totalSize = [fileInfo valueForKeyPath:@"@sum.uncompressedSize"]; + UZKLogDebug("totalSize: %lld", totalSize.longLongValue); + __block long long bytesDecompressed = 0; + __block NSInteger filesExtracted = 0; + + NSProgress *progress = [self beginProgressOperation:totalSize.longLongValue]; + progress.kind = NSProgressKindFile; + + __weak UZKArchive *welf = self; + NSError *extractError = nil; + + BOOL success = [self performActionWithArchiveOpen:^(NSError * __autoreleasing*innerError) { + UZKCreateActivity("Performing Extraction"); + + NSError *strongError = nil; + + @try { + for (UZKFileInfo *info in fileInfo) { + UZKLogDebug("Extracting %{public}@ to disk", info.filename); + + if (progress.isCancelled) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error locating file '%@' in archive", @"UnzipKit", _resources, @"Detailed error string"), + info.filename]; + UZKLogError("Halted file extraction due to user cancellation: %{public}@", detail); + [welf assignError:&strongError code:UZKErrorCodeUserCancelled + detail:detail]; + return; + } + + @autoreleasepool { + if (progressBlock) { + progressBlock(info, bytesDecompressed / totalSize.doubleValue); + } + + if (![self locateFileInZip:info.filename error:&strongError]) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error locating file '%@' in archive", @"UnzipKit", _resources, @"Detailed error string"), + info.filename]; + UZKLogError("UZKErrorCodeFileNotFoundInArchive: %{public}@", detail); + [welf assignError:&strongError code:UZKErrorCodeFileNotFoundInArchive + detail:detail]; + return; + } + + NSString *extractPath = [destinationDirectory stringByAppendingPathComponent:info.filename]; + UZKLogDebug("Extracting to %{public}@", extractPath); + if ([fm fileExistsAtPath:extractPath] && !overwrite) { + UZKLogDebug("File exists and overwrite==NO. Skipping file"); + return; + } + + NSString *extractDir = (info.isDirectory + ? extractPath + : extractPath.stringByDeletingLastPathComponent); + if (![fm fileExistsAtPath:extractDir]) { + UZKLogDebug("Creating directories for path %{public}@", extractDir); + BOOL directoriesCreated = [fm createDirectoryAtPath:extractDir + withIntermediateDirectories:YES + attributes:nil + error:error]; + if (!directoriesCreated) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Failed to create destination directory: %@", @"UnzipKit", _resources, @"Detailed error string"), + extractDir]; + UZKLogError("UZKErrorCodeOutputError: %{public}@", detail); + [welf assignError:&strongError code:UZKErrorCodeOutputError + detail:detail]; + return; + } + } + + if (info.isDirectory) { + UZKLogDebug("Created empty directory") + continue; + } + + NSURL *deflatedDirectoryURL = [NSURL fileURLWithPath:destinationDirectory]; + NSURL *deflatedFileURL = [deflatedDirectoryURL URLByAppendingPathComponent:info.filename]; + [progress setUserInfoObject:deflatedFileURL + forKey:NSProgressFileURLKey]; + [progress setUserInfoObject:info + forKey:UZKProgressInfoKeyFileInfoExtracting]; + NSString *path = deflatedFileURL.path; + + UZKLogDebug("Creating empty file at path %{public}@", path); + BOOL createSuccess = [fm createFileAtPath:path + contents:nil + attributes:nil]; + + if (!createSuccess) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error creating current file (%d) '%@'", @"UnzipKit", _resources, @"Detailed error string"), + strongError, info.filename]; + UZKLogError("UZKErrorCodeOutputError: %{public}@", detail); + [welf assignError:&strongError code:UZKErrorCodeOutputError + detail:detail]; + return; + } + + UZKLogDebug("Opening file handle for URL %{public}@", deflatedFileURL); + NSFileHandle *deflatedFileHandle = [NSFileHandle fileHandleForWritingToURL:deflatedFileURL + error:&strongError]; + + + if (!deflatedFileHandle) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error writing to file: %@", @"UnzipKit", _resources, @"Detailed error string"), + deflatedFileURL]; + UZKLogError("UZKErrorCodeOutputError: %{public}@", detail); + [welf assignError:&strongError code:UZKErrorCodeOutputError + detail:detail]; + return; + } + + UZKLogDebug("Extracting buffered data"); + BOOL extractSuccess = [welf extractBufferedDataFromFile:info.filename + error:&strongError + action: + ^(NSData *dataChunk, CGFloat percentDecompressed) { + UZKLogDebug("Writing data chunk of size %lu (%lld total so far)", (unsigned long)dataChunk.length, bytesDecompressed); + bytesDecompressed += dataChunk.length; + [deflatedFileHandle writeData:dataChunk]; + if (progressBlock) { + progressBlock(info, (double)bytesDecompressed / totalSize.doubleValue); + } + }]; + + UZKLogDebug("Closing file handle"); + [deflatedFileHandle closeFile]; + + // Restore the timestamp and permission attributes of the file + NSDictionary* attribs = @{NSFileModificationDate: info.timestamp, + NSFilePosixPermissions: @(info.posixPermissions)}; + [[NSFileManager defaultManager] setAttributes:attribs ofItemAtPath:path error:nil]; + + if (!extractSuccess) { + UZKLogError("Error extracting file (%ld): %{public}@", (long)strongError.code, strongError.localizedDescription); + + UZKLogInfo("Cleaning up target directory after failure: %{public}@", deflatedFileURL); + // Remove the directory we were going to unzip to if it fails. + [fm removeItemAtURL:deflatedDirectoryURL + error:nil]; + return; + } + + [progress setUserInfoObject:@(++filesExtracted) + forKey:NSProgressFileCompletedCountKey]; + [progress setUserInfoObject:@(fileInfo.count) + forKey:NSProgressFileTotalCountKey]; + progress.completedUnitCount = bytesDecompressed; + } + } + } + @finally { + if (strongError && innerError) { + *innerError = strongError; + } + } + } inMode:UZKFileModeUnzip error:&extractError]; + + if (error) { + *error = extractError ? extractError : nil; + } + + return success; +} + +- (nullable NSData *)extractData:(UZKFileInfo *)fileInfo + error:(NSError * __autoreleasing*)error +{ + return [self extractDataFromFile:fileInfo.filename + error:error]; +} + +- (nullable NSData *)extractData:(UZKFileInfo *)fileInfo + progress:(void (^)(CGFloat))progress + error:(NSError * __autoreleasing*)error +{ + return [self extractDataFromFile:fileInfo.filename + progress:progress + error:error]; +} + +- (nullable NSData *)extractDataFromFile:(NSString *)filePath + error:(NSError * __autoreleasing *)error +{ +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdeprecated-declarations" + return [self extractDataFromFile:filePath + progress:nil + error:error]; +#pragma clang diagnostic pop +} + +- (nullable NSData *)extractDataFromFile:(NSString *)filePath + progress:(void (^)(CGFloat))progressBlock + error:(NSError * __autoreleasing*)error +{ + UZKCreateActivity("Extracting Data from File"); + + NSMutableData *result = [NSMutableData data]; + + UZKLogInfo("Extracting buffered data from file %{public}@", filePath); + + NSError *extractError = nil; + BOOL success = [self extractBufferedDataFromFile:filePath + error:&extractError + action:^(NSData *dataChunk, CGFloat percentDecompressed) { + UZKLogDebug("Appending data chunk of size %lu (%.3f%% complete)", (unsigned long)dataChunk.length, (double)percentDecompressed * 100); + + if (progressBlock) { + progressBlock(percentDecompressed); + } + + [result appendData:dataChunk]; + }]; + + if (progressBlock) { + UZKLogDebug("Declaring extraction progress as completed"); + progressBlock(1.0); + } + + if (success) { + return [NSData dataWithData:result]; + } + + UZKLogError("Error extracting file (%ld): %{public}@", (long)extractError.code, extractError.localizedDescription); + + if (error) { + *error = extractError; + } + + return nil; +} + +- (BOOL)performOnFilesInArchive:(void (^)(UZKFileInfo *, BOOL *))action + error:(NSError * __autoreleasing*)error +{ + UZKCreateActivity("Performing Action on Each File"); + + UZKLogInfo("Listing file info"); + + NSError *listError = nil; + NSArray *fileInfo = [self listFileInfo:&listError]; + + if (listError || !fileInfo) { + UZKLogError("Failed to list the files in the archive: %{public}@", listError); + + if (error) { + *error = listError; + } + + return NO; + } + + NSProgress *progress = [self beginProgressOperation:fileInfo.count]; + + UZKLogInfo("Sorting file info by name/path"); + + NSArray *sortedFileInfo = [fileInfo sortedArrayUsingDescriptors:@[[NSSortDescriptor sortDescriptorWithKey:@"filename" ascending:YES]]]; + + BOOL success = [self performActionWithArchiveOpen:^(NSError * __autoreleasing*innerError) { + UZKCreateActivity("Iterating Each File Info"); + + BOOL stop = NO; + + for (UZKFileInfo *info in sortedFileInfo) { + if (progress.isCancelled) { + UZKLogInfo("File info iteration was cancelled"); + break; + } + UZKLogDebug("Performing action on %{public}@", info.filename); + action(info, &stop); + progress.completedUnitCount += 1; + + if (stop) { + UZKLogInfo("Action dictated an early stop"); + progress.completedUnitCount = progress.totalUnitCount; + break; + } + } + } inMode:UZKFileModeUnzip error:error]; + + if (progress.isCancelled) { + NSString *detail = NSLocalizedStringFromTableInBundle(@"User cancelled operation", @"UnzipKit", _resources, @"Detailed error string"); + UZKLogError("UZKErrorCodeUserCancelled: %{public}@", detail); + [self assignError:error code:UZKErrorCodeUserCancelled + detail:detail]; + return NO; + } + + return success; +} + +- (BOOL)performOnDataInArchive:(void (^)(UZKFileInfo *, NSData *, BOOL *))action + error:(NSError * __autoreleasing*)error +{ + UZKCreateActivity("Performing Action on Each File's Data"); + + __weak UZKArchive *welf = self; + + return [self performOnFilesInArchive:^(UZKFileInfo *fileInfo, BOOL *stop) { + UZKLogInfo("Locating file %{public}@", fileInfo.filename); + + if (![welf locateFileInZip:fileInfo.filename error:error]) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Failed to locate '%@' in archive during-perform on-data operation", @"UnzipKit", _resources, @"Detailed error string"), + fileInfo.filename]; + UZKLogError("UZKErrorCodeFileNotFoundInArchive: %{public}@", detail); + [welf assignError:error code:UZKErrorCodeFileNotFoundInArchive + detail:detail]; + return; + } + + UZKLogInfo("Reading file from archive"); + + NSData *fileData = [welf readFile:fileInfo.filename + length:fileInfo.uncompressedSize + error:error]; + + if (!fileData) { + UZKLogError("Error reading file %{public}@ in archive", fileInfo.filename); + return; + } + + UZKLogInfo("Performing action on file data"); + action(fileInfo, fileData, stop); + } error:error]; +} + +- (BOOL)extractBufferedDataFromFile:(NSString *)filePath + error:(NSError * __autoreleasing*)error + action:(void (^)(NSData *, CGFloat))action +{ + UZKCreateActivity("Extracting Data into Buffer"); + + NSProgress *progress = [self beginProgressOperation:0]; + + __weak UZKArchive *welf = self; + NSUInteger bufferSize = 1024 * 256; // 256 kb, arbitrary + + BOOL success = [self performActionWithArchiveOpen:^(NSError * __autoreleasing*innerError) { + if (![welf locateFileInZip:filePath error:innerError]) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Failed to locate '%@' in archive during buffered read", @"UnzipKit", _resources, @"Detailed error string"), + filePath]; + UZKLogError("UZKErrorCodeFileNotFoundInArchive: %{public}@", detail); + [welf assignError:innerError code:UZKErrorCodeFileNotFoundInArchive + detail:detail]; + return; + } + + UZKLogInfo("Getting file info"); + UZKFileInfo *info = [welf currentFileInZipInfo:innerError]; + + if (!info) { + UZKLogError("Failed to get info of file %{public}@ in archive", filePath); + return; + } + + progress.totalUnitCount = info.uncompressedSize; + + UZKLogInfo("Opening file"); + if (![welf openFile:innerError]) { + UZKLogError("Failed to open file %{public}@ in archive", filePath); + return; + } + + long long bytesDecompressed = 0; + + NSError *strongInnerError = nil; + + for (;;) + { + if (progress.isCancelled) { + UZKLogInfo("Buffered data read cancelled"); + return; + } + + @autoreleasepool { + UZKLogDebug("Reading file data"); + NSMutableData *data = [NSMutableData dataWithLength:bufferSize]; + int bytesRead = unzReadCurrentFile(welf.unzFile, data.mutableBytes, (unsigned)bufferSize); + + if (bytesRead < 0) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Failed to read file %@ in zip", @"UnzipKit", _resources, @"Detailed error string"), + info.filename]; + UZKLogError("Error reading data (code %d): %{public}@", bytesRead, detail); + [welf assignError:&strongInnerError code:bytesRead + detail:detail]; + break; + } + else if (bytesRead == 0) { + UZKLogDebug("Done reading file"); + break; + } + + UZKLogDebug("bytesRead: %{iec-bytes}d (%d bytes)", bytesRead, bytesRead); + + data.length = bytesRead; + bytesDecompressed += bytesRead; + + if (action) { + UZKLogDebug("Performing action on chunk of data"); + action([data copy], bytesDecompressed / (CGFloat)info.uncompressedSize); + } + + progress.completedUnitCount = bytesDecompressed; + } + } + + if (strongInnerError) { + *innerError = strongInnerError; + return; + } + + UZKLogInfo("Closing file..."); + int err = unzCloseCurrentFile(welf.unzFile); + if (err != UNZ_OK) { + if (err == UZKErrorCodeCRCError) { + err = UZKErrorCodeInvalidPassword; + } + + NSString *detail = NSLocalizedStringFromTableInBundle(@"Error closing current file during buffered read", @"UnzipKit", _resources, @"Detailed error string"); + UZKLogError("Error closing file (code %d): %{public}@", err, detail); + [welf assignError:innerError code:err + detail:detail]; + return; + } + + } inMode:UZKFileModeUnzip error:error]; + + if (progress.isCancelled) { + UZKLogError("User cancelled data extraction"); + NSString *detail = NSLocalizedStringFromTableInBundle(@"User cancelled data read", @"UnzipKit", _resources, @"Detailed error string"); + [self assignError:error code:UZKErrorCodeUserCancelled + detail:detail]; + return NO; + } + + return success; +} + +- (BOOL)isPasswordProtected +{ + UZKCreateActivity("Checking Password Protection"); + + NSError *error = nil; + NSArray *fileInfos = [self listFileInfo:&error]; + + if (error) { + UZKLogError("Error checking whether file is password protected: %{public}@", error); + return NO; + } + + for (UZKFileInfo *fileInfo in fileInfos) { + if (fileInfo.isEncryptedWithPassword) { + UZKLogDebug("File %{public}@ is encrypted. Not checking any others", fileInfo.filename); + return YES; + } + + UZKLogDebug("File %{public}@ is NOT encrypted. Checking remaining files", fileInfo.filename); + } + + return NO; +} + +- (BOOL)validatePassword +{ + UZKCreateActivity("Validating Password"); + + if (!self.isPasswordProtected) { + UZKLogInfo("Archive is not password protected. There is no password to validate"); + return YES; + } + + NSError *error = nil; + NSArray *fileInfos = [self listFileInfo:&error]; + + if (error) { + UZKLogError("Error checking whether file is password protected: %{public}@", error); + return NO; + } + + if (!fileInfos || fileInfos.count == 0) { + UZKLogInfo("There are no files in the archive"); + return NO; + } + + UZKFileInfo *smallest = [fileInfos sortedArrayUsingComparator:^NSComparisonResult(UZKFileInfo *file1, UZKFileInfo *file2) { + if (file1.uncompressedSize < file2.uncompressedSize) + return NSOrderedAscending; + if (file1.uncompressedSize > file2.uncompressedSize) + return NSOrderedDescending; + return NSOrderedSame; + }].firstObject; + + UZKLogDebug("Decrypting smallest file in archive: %{public}@", smallest.filename); + + NSData *smallestData = [self extractData:(UZKFileInfo* _Nonnull)smallest + error:&error]; + + if (error || !smallestData) { + UZKLogInfo("Error while checking password: %{public}@", error); + return NO; + } + + return YES; +} + +- (BOOL)checkDataIntegrity +{ + return [self checkDataIntegrityOfFile:(NSString * _Nonnull)nil]; +} + +- (BOOL)checkDataIntegrityOfFile:(NSString *)filePath +{ + UZKCreateActivity("Checking data integrity"); + + UZKLogInfo("Checking integrity of %{public}@", filePath ? filePath : @"all files in archive"); + + NSError *performOnDataError = nil; + __block BOOL dataIsValid = NO; + + BOOL success = [self performOnDataInArchive: + ^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + // Only set this once we've reached this point, validating the archive's structures + dataIsValid = YES; + + if (filePath && ![filePath isEqualToString:fileInfo.filename]) { + UZKLogDebug("Skipping '%{public}@' != %{public}@", fileInfo.filename, filePath); + return; + } + + uLong extractedCRC = crc32(0, fileData.bytes, (uInt)fileData.length); + + if (extractedCRC != fileInfo.CRC) { + UZKLogError("CRC mismatch in '%{public}@': expected %010lu, found %010lu", + fileInfo.filename, (unsigned long)fileInfo.CRC, extractedCRC) + dataIsValid = NO; + } + + if (!dataIsValid || filePath) { + *stop = YES; + } + } + error:&performOnDataError]; + + if (!success) { + UZKLogError("Failed to iterate through data: %{public}@", performOnDataError); + } + + return success && dataIsValid; +} + + +#pragma mark - Write Methods + + +- (BOOL)writeData:(NSData *)data + filePath:(NSString *)filePath + error:(NSError * __autoreleasing*)error +{ + return [self writeData:data + filePath:filePath + fileDate:nil + compressionMethod:UZKCompressionMethodDefault + password:nil + overwrite:YES + error:error]; +} + +- (BOOL)writeData:(NSData *)data + filePath:(NSString *)filePath + progress:(void (^)(CGFloat percentCompressed))progress + error:(NSError * __autoreleasing*)error +{ + return [self writeData:data + filePath:filePath + fileDate:nil + compressionMethod:UZKCompressionMethodDefault + password:nil + overwrite:YES + progress:progress + error:error]; +} + +- (BOOL)writeData:(NSData *)data + filePath:(NSString *)filePath + fileDate:(NSDate *)fileDate + error:(NSError * __autoreleasing*)error +{ + return [self writeData:data + filePath:filePath + fileDate:fileDate + compressionMethod:UZKCompressionMethodDefault + password:nil + overwrite:YES + error:error]; +} + +- (BOOL)writeData:(NSData *)data + filePath:(NSString *)filePath + fileDate:(NSDate *)fileDate + progress:(void (^)(CGFloat percentCompressed))progress + error:(NSError * __autoreleasing*)error +{ + return [self writeData:data + filePath:filePath + fileDate:fileDate + compressionMethod:UZKCompressionMethodDefault + password:nil + overwrite:YES + progress:progress + error:error]; +} + +- (BOOL)writeData:(NSData *)data + filePath:(NSString *)filePath + fileDate:(NSDate *)fileDate +compressionMethod:(UZKCompressionMethod)method + password:(NSString *)password + error:(NSError * __autoreleasing*)error +{ + return [self writeData:data + filePath:filePath + fileDate:fileDate + compressionMethod:method + password:password + overwrite:YES + error:error]; +} + +- (BOOL)writeData:(NSData *)data + filePath:(NSString *)filePath + fileDate:(NSDate *)fileDate +compressionMethod:(UZKCompressionMethod)method + password:(NSString *)password + progress:(void (^)(CGFloat percentCompressed))progress + error:(NSError * __autoreleasing*)error +{ + return [self writeData:data + filePath:filePath + fileDate:fileDate + compressionMethod:method + password:password + overwrite:YES + progress:progress + error:error]; +} + +- (BOOL)writeData:(NSData *)data + filePath:(NSString *)filePath + fileDate:(NSDate *)fileDate +compressionMethod:(UZKCompressionMethod)method + password:(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 + progress:nil + error:error]; +#pragma clang diagnostic pop +} + +- (BOOL)writeData:(NSData *)data + filePath:(NSString *)filePath + fileDate:(NSDate *)fileDate +compressionMethod:(UZKCompressionMethod)method + password:(NSString *)password + overwrite:(BOOL)overwrite + progress:(void (^)(CGFloat percentCompressed))progressBlock + error:(NSError * __autoreleasing*)error +{ + return [self writeData:data + filePath:filePath + fileDate:fileDate + posixPermissions:0 + compressionMethod:method + password:password + overwrite:overwrite + progress:progressBlock + error:error]; +} + +- (BOOL)writeData:(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 + progress:nil + error:error]; +#pragma clang diagnostic pop +} + +- (BOOL)writeData:(NSData *)data + filePath:(NSString *)filePath + fileDate:(NSDate *)fileDate + posixPermissions:(short)permissions +compressionMethod:(UZKCompressionMethod)method + password:(NSString *)password + overwrite:(BOOL)overwrite + progress:(void (^)(CGFloat percentCompressed))progressBlock + error:(NSError * __autoreleasing*)error +{ + UZKCreateActivity("Writing Data"); + + UZKLogInfo("Writing data to archive. filePath: %{public}@, fileDate: %{time_t}ld, compressionMethod: %ld, password: %{public}@, " + "overwrite: %{public}@, progress block specified: %{public}@, error pointer specified: %{public}@", + filePath, lrint(fileDate.timeIntervalSince1970), (long)method, password != nil ? @"" : @"(null)", overwrite ? @"YES" : @"NO", + progressBlock ? @"YES" : @"NO", error ? @"YES" : @"NO"); + + const NSUInteger bufferSize = 4096; //Arbitrary + const void *bytes = data.bytes; + + NSProgress *progress = [self beginProgressOperation:data.length]; + progress.cancellable = NO; + + if (progressBlock) { + UZKLogDebug("Calling progress block with zero"); + progressBlock(0); + } + + __weak UZKArchive *welf = self; + uLong calculatedCRC = crc32(0, data.bytes, (uInt)data.length); + UZKLogDebug("Calculated CRC: %010lu", calculatedCRC); + + BOOL success = [self performWriteAction:^int(uLong *crc, NSError * __autoreleasing*innerError) { + UZKCreateActivity("Performing File Write"); + + NSAssert(crc, @"No CRC reference passed", nil); + *crc = calculatedCRC; + + UZKLogInfo("Iterating through all data, in %lu chunks", (unsigned long)bufferSize); + + for (NSUInteger i = 0; i <= data.length; i += bufferSize) { + UZKLogDebug("Writing chunk starting at byte %lu", (unsigned long)i); + + unsigned int dataRemaining = (unsigned int)(data.length - i); + unsigned int size = (unsigned int)(dataRemaining < bufferSize ? dataRemaining : bufferSize); + int err = zipWriteInFileInZip(welf.zipFile, (const char *)bytes + i, size); + + if (err != ZIP_OK) { + UZKLogError("Error writing data: %d", err); + return err; + } + + progress.completedUnitCount += size; + + if (progressBlock) { + double percentComplete = i / (double)data.length; + UZKLogDebug("Calling progress block at %.3f%%", percentComplete * 100); + progressBlock(percentComplete); + } + } + + return ZIP_OK; + } + filePath:filePath + fileDate:fileDate + posixPermissions:permissions + compressionMethod:method + password:password + overwrite:overwrite + CRC:calculatedCRC + 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 +{ + return [self writeIntoBuffer:filePath + fileDate:nil + posixPermissions:0 + compressionMethod:UZKCompressionMethodDefault + overwrite:YES + CRC:0 + password:nil + error:error + block:action]; +} + +- (BOOL)writeIntoBuffer:(NSString *)filePath + fileDate:(NSDate *)fileDate + 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]; +} + +- (BOOL)writeIntoBuffer:(NSString *)filePath + fileDate:(NSDate *)fileDate + compressionMethod:(UZKCompressionMethod)method + 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]; +} + +- (BOOL)writeIntoBuffer:(NSString *)filePath + fileDate:(NSDate *)fileDate + compressionMethod:(UZKCompressionMethod)method + overwrite:(BOOL)overwrite + 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]; +} + +- (BOOL)writeIntoBuffer:(NSString *)filePath + fileDate:(NSDate *)fileDate + compressionMethod:(UZKCompressionMethod)method + overwrite:(BOOL)overwrite + CRC:(uLong)preCRC + 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]; +} + +- (BOOL)writeIntoBuffer:(NSString *)filePath + fileDate:(NSDate *)fileDate + compressionMethod:(UZKCompressionMethod)method + overwrite:(BOOL)overwrite + CRC:(uLong)preCRC + password:(NSString *)password + 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]; +} + +- (BOOL)writeIntoBuffer:(NSString *)filePath + fileDate:(NSDate *)fileDate + posixPermissions:(short)permissions + compressionMethod:(UZKCompressionMethod)method + overwrite:(BOOL)overwrite + CRC:(uLong)preCRC + password:(NSString *)password + 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"); + + NSAssert(preCRC != 0 || ([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); + + __weak UZKArchive *welf = self; + + BOOL success = [self performWriteAction:^int(uLong *crc, NSError * __autoreleasing*innerError) { + UZKCreateActivity("Performing File Write"); + + NSAssert(crc, @"No CRC reference passed", nil); + + if (!action) { + UZKLogInfo("No write action specified. This is unusual, but not fatal"); + return ZIP_OK; + } + + BOOL result = action(^BOOL(const void *bytes, unsigned int length) { + UZKLogInfo("Writing %{iec-bytes}u (%u bytes) into archive from buffer", length, length); + int writeErr = zipWriteInFileInZip(self.zipFile, bytes, length); + if (writeErr != ZIP_OK) { + UZKLogError("Error writing data from buffer: %d", writeErr); + return NO; + } + + uLong oldCRC = *crc; + *crc = crc32(oldCRC, bytes, (uInt)length); + UZKLogDebug("Calculated new CRC: %010lu from old CRC: %010lu", *crc, oldCRC); + + return YES; + }, innerError); + + if (preCRC != 0 && *crc != preCRC) { + uLong calculatedCRC = *crc; + NSString *preCRCStr = [NSString stringWithFormat:@"%010lu", preCRC]; + NSString *calculatedCRCStr = [NSString stringWithFormat:@"%010lu", calculatedCRC]; + NSString *detail = [NSString stringWithFormat: + NSLocalizedStringFromTableInBundle(@"Incorrect CRC provided\n%@ given\n%@ calculated", @"UnzipKit", _resources, @"CRC mismatch error detail"), + preCRCStr, calculatedCRCStr]; + UZKLogError("UZKErrorCodePreCRCMismatch: %{public}@", detail); + return [welf assignError:innerError code:UZKErrorCodePreCRCMismatch + detail:detail]; + } + + return result; + } + filePath:filePath + fileDate:fileDate + posixPermissions:permissions + compressionMethod:method + password:password + overwrite:overwrite + CRC:preCRC + error:error]; + + return success; +} + +- (BOOL)deleteFile:(NSString *)filePath error:(NSError * __autoreleasing*)error +{ + UZKCreateActivity("Deleting File"); + + // Thanks to Ivan A. Krestinin for much of the code below: http://www.winimage.com/zLibDll/del.cpp + + UZKLogInfo("Deleting file %{public}@ from archive", filePath); + + NSFileManager *fm = [NSFileManager defaultManager]; + + if (!self.filename || ![fm fileExistsAtPath:(NSString* _Nonnull)self.filename]) { + UZKLogError("No archive exists at path %{public}@, when trying to delete %{public}@", self.filename, filePath); + return YES; + } + + NSString *randomString = [NSString stringWithFormat:@"%@.zip", [[NSProcessInfo processInfo] globallyUniqueString]]; + NSURL *temporaryURL = [[NSURL fileURLWithPath:NSTemporaryDirectory()] URLByAppendingPathComponent:randomString]; + + UZKLogInfo("Writing new archive without deleted file to %{public}@", temporaryURL.path); + + const char *original_filename = self.filename.UTF8String; + const char *del_file = filePath.UTF8String; + const char *temp_filename = temporaryURL.path.UTF8String; + + // Open source and destination files + + UZKLogInfo("Opening original archive at %{public}s", original_filename); + zipFile source_zip = unzOpen(original_filename); + if (source_zip == NULL) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error opening the source file while deleting %@", @"UnzipKit", _resources, @"Detailed error string"), + filePath]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + + UZKLogInfo("Opening temporary archive at %{public}s", temp_filename); + zipFile dest_zip = zipOpen(temp_filename, APPEND_STATUS_CREATE); + if (dest_zip == NULL) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error opening the destination file while deleting %@", @"UnzipKit", _resources, @"Detailed error string"), + filePath]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + UZKLogDebug("Closing source_zip"); + unzClose(source_zip); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + + // Get global commentary + + UZKLogInfo("Getting global info from source zip"); + unz_global_info global_info; + int err = unzGetGlobalInfo(source_zip, &global_info); + if (err != UNZ_OK) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error getting the global info of the source file while deleting %@ (%d)", @"UnzipKit", _resources, @"Detailed error string"), + filePath, err]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + UZKLogDebug("Closing source_zip, dest_zip"); + zipClose(dest_zip, NULL); + unzClose(source_zip); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + + char *global_comment = NULL; + + if (global_info.size_comment > 0) + { + UZKLogInfo("Getting global comment from source zip"); + global_comment = (char*)malloc(global_info.size_comment+1); + if ((global_comment == NULL) && (global_info.size_comment != 0)) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error reading the global comment of the source file while deleting %@", @"UnzipKit", _resources, @"Detailed error string"), + filePath]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + UZKLogDebug("Closing source_zip, dest_zip"); + zipClose(dest_zip, NULL); + unzClose(source_zip); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + + if ((unsigned int)unzGetGlobalComment(source_zip, global_comment, global_info.size_comment + 1) != global_info.size_comment) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error reading the global comment of the source file while deleting %@ (wrong size)", @"UnzipKit", _resources, @"Detailed error string"), + filePath]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + UZKLogDebug("Closing source_zip, dest_zip, freeing global_comment"); + zipClose(dest_zip, NULL); + unzClose(source_zip); + free(global_comment); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + } + + BOOL noFilesDeleted = YES; + int filesCopied = 0; + + NSString *filenameToDelete = [UZKArchive figureOutCString:del_file]; + + UZKLogInfo("Navigating to first file in source archive"); + int nextFileReturnValue = unzGoToFirstFile(source_zip); + + while (nextFileReturnValue == UNZ_OK) + { + // Get zipped file info + char filename_inzip[FILE_IN_ZIP_MAX_NAME_LENGTH]; + unz_file_info64 unzipInfo; + + UZKLogDebug("Getting file info"); + err = unzGetCurrentFileInfo64(source_zip, &unzipInfo, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0); + if (err != UNZ_OK) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error getting file info of file while deleting %@ (%d)", @"UnzipKit", _resources, @"Detailed error string"), + filePath, err]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + UZKLogDebug("Closing source_zip, dest_zip, freeing global_comment"); + zipClose(dest_zip, NULL); + unzClose(source_zip); + free(global_comment); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + + NSString *currentFileName = [UZKArchive figureOutCString:filename_inzip]; + UZKLogDebug("Current file is %{public}@", currentFileName); + + // If this is the file to delete + if ([filenameToDelete isEqualToString:currentFileName.decomposedStringWithCanonicalMapping]) { + UZKLogDebug("This file is the one we're deleting"); + noFilesDeleted = NO; + } else { + UZKLogDebug("Allocating extra field"); + char *extra_field = (char*)malloc(unzipInfo.size_file_extra); + if ((extra_field == NULL) && (unzipInfo.size_file_extra != 0)) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error allocating extra_field info of %@ while deleting %@", @"UnzipKit", _resources, @"Detailed error string"), + currentFileName, filePath]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + UZKLogDebug("Closing source_zip, dest_zip, freeing global_comment"); + zipClose(dest_zip, NULL); + unzClose(source_zip); + free(global_comment); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + + UZKLogDebug("Allocating commentary"); + char *commentary = (char*)malloc(unzipInfo.size_file_comment); + if ((commentary == NULL) && (unzipInfo.size_file_comment != 0)) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error allocating commentary info of %@ while deleting %@", @"UnzipKit", _resources, @"Detailed error string"), + currentFileName, filePath]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + UZKLogDebug("Closing source_zip, dest_zip, freeing global_comment, extra_field"); + zipClose(dest_zip, NULL); + unzClose(source_zip); + free(global_comment); + free(extra_field); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + + UZKLogDebug("Getting file info"); + err = unzGetCurrentFileInfo64(source_zip, &unzipInfo, filename_inzip, FILE_IN_ZIP_MAX_NAME_LENGTH, extra_field, unzipInfo.size_file_extra, commentary, unzipInfo.size_file_comment); + if (err != UNZ_OK) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error reading extra_field and commentary info of %@ while deleting %@ (%d)", @"UnzipKit", _resources, @"Detailed error string"), + currentFileName, filePath, err]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + UZKLogDebug("Closing source_zip, dest_zip, freeing global_comment, extra_field, commentary"); + free(extra_field); + free(commentary); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + + // Open source archive for raw reading + + int method; + int level; + UZKLogDebug("Opening file in source archive"); + err = unzOpenCurrentFile2(source_zip, &method, &level, 1); + if (err != UNZ_OK) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error opening %@ for raw reading while deleting %@ (%d)", @"UnzipKit", _resources, @"Detailed error string"), + currentFileName, filePath, err]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + UZKLogDebug("Closing source_zip, dest_zip, freeing global_comment, extra_field, commentary"); + zipClose(dest_zip, NULL); + unzClose(source_zip); + free(global_comment); + free(extra_field); + free(commentary); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + + UZKLogDebug("Getting local extra field size"); + int size_local_extra = unzGetLocalExtrafield(source_zip, NULL, 0); + if (size_local_extra < 0) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error getting size_local_extra for file while deleting %@", @"UnzipKit", _resources, @"Detailed error string"), + currentFileName, filePath]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + UZKLogDebug("Closing source_zip, dest_zip, freeing global_comment, extra_field, commentary"); + zipClose(dest_zip, NULL); + unzClose(source_zip); + free(global_comment); + free(extra_field); + free(commentary); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + + UZKLogDebug("Allocating local extra field"); + void *local_extra = malloc(size_local_extra); + if ((local_extra == NULL) && (size_local_extra != 0)) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error allocating local_extra for file %@ while deleting %@", @"UnzipKit", _resources, @"Detailed error string"), + currentFileName, filePath]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + UZKLogDebug("Closing source_zip, dest_zip, freeing global_comment, extra_field, commentary"); + zipClose(dest_zip, NULL); + unzClose(source_zip); + free(global_comment); + free(extra_field); + free(commentary); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + + UZKLogDebug("Getting local extra field"); + if (unzGetLocalExtrafield(source_zip, local_extra, size_local_extra) < 0) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error getting local_extra for file %@ while deleting %@", @"UnzipKit", _resources, @"Detailed error string"), + currentFileName, filePath]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + UZKLogDebug("Closing source_zip, dest_zip, freeing global_comment, extra_field, commentary, local_extra"); + zipClose(dest_zip, NULL); + unzClose(source_zip); + free(global_comment); + free(extra_field); + free(commentary); + free(local_extra); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + + // This malloc may fail if the file is very large + UZKLogDebug("Allocating data read buffer"); + void *buf = malloc((unsigned long)unzipInfo.compressed_size); + if ((buf == NULL) && (unzipInfo.compressed_size != 0)) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error allocating buffer for file %@ while deleting %@. Is it too large?", @"UnzipKit", _resources, @"Detailed error string"), + currentFileName, filePath]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + UZKLogDebug("Closing source_zip, dest_zip, freeing global_comment, extra_field, commentary, local_extra"); + zipClose(dest_zip, NULL); + unzClose(source_zip); + free(global_comment); + free(extra_field); + free(commentary); + free(local_extra); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + + // Read file + UZKLogDebug("Reading data into buffer"); + int size = unzReadCurrentFile(source_zip, buf, (uInt)unzipInfo.compressed_size); + if ((unsigned int)size != unzipInfo.compressed_size) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error reading %@ into buffer while deleting %@", @"UnzipKit", _resources, @"Detailed error string"), + currentFileName, filePath]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + UZKLogDebug("Closing source_zip, dest_zip, freeing global_comment, extra_field, commentary, local_extra, buf"); + zipClose(dest_zip, NULL); + unzClose(source_zip); + free(global_comment); + free(extra_field); + free(commentary); + free(local_extra); + free(buf); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + + // Open destination archive + + UZKLogDebug("Filling zip_fileinfo struct"); + zip_fileinfo zipInfo; + memcpy (&zipInfo.tmz_date, &unzipInfo.tmu_date, sizeof(tm_unz)); + zipInfo.dosDate = unzipInfo.dosDate; + zipInfo.internal_fa = unzipInfo.internal_fa; + zipInfo.external_fa = unzipInfo.external_fa; + + UZKLogDebug("Opening file in destination archive"); + err = zipOpenNewFileInZip2(dest_zip, filename_inzip, &zipInfo, + local_extra, size_local_extra, extra_field, (uInt)unzipInfo.size_file_extra, commentary, + method, level, 1); + if (err != UNZ_OK) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error opening %@ in destination zip while deleting %@ (%d)", @"UnzipKit", _resources, @"Detailed error string"), + currentFileName, filePath, err]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + UZKLogDebug("Closing source_zip, dest_zip, freeing global_comment, extra_field, commentary, local_extra, buf"); + zipClose(dest_zip, NULL); + unzClose(source_zip); + free(global_comment); + free(extra_field); + free(commentary); + free(local_extra); + free(buf); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + + // Write file + UZKLogDebug("Writing file in destination archive"); + err = zipWriteInFileInZip(dest_zip, buf, (uInt)unzipInfo.compressed_size); + if (err != UNZ_OK) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error writing %@ to destination zip while deleting %@ (%d)", @"UnzipKit", _resources, @"Detailed error string"), + currentFileName, filePath, err]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + UZKLogDebug("Closing source_zip, dest_zip, freeing global_comment, extra_field, commentary, local_extra, buf"); + zipClose(dest_zip, NULL); + unzClose(source_zip); + free(global_comment); + free(extra_field); + free(commentary); + free(local_extra); + free(buf); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + + // Close destination archive + UZKLogDebug("Closing file in destination archive"); + err = zipCloseFileInZipRaw64(dest_zip, unzipInfo.uncompressed_size, 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]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + UZKLogDebug("Closing source_zip, dest_zip, freeing global_comment, extra_field, commentary, local_extra, buf"); + zipClose(dest_zip, NULL); + unzClose(source_zip); + free(global_comment); + free(extra_field); + free(commentary); + free(local_extra); + free(buf); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + + // Close source archive + UZKLogDebug("Closing source archive"); + err = unzCloseCurrentFile(source_zip); + if (err != UNZ_OK) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error closing %@ in source zip while deleting %@ (%d)", @"UnzipKit", _resources, @"Detailed error string"), + currentFileName, filePath, err]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + UZKLogDebug("Closing source_zip, dest_zip, freeing global_comment, extra_field, commentary, local_extra, buf"); + zipClose(dest_zip, NULL); + unzClose(source_zip); + free(global_comment); + free(extra_field); + free(commentary); + free(local_extra); + free(buf); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + + UZKLogDebug("Freeing extra_field, commentary, local_extra, buf"); + free(extra_field); + free(commentary); + free(local_extra); + free(buf); + + ++filesCopied; + } + + UZKLogDebug("Going to next file"); + nextFileReturnValue = unzGoToNextFile(source_zip); + } + + UZKLogDebug("Closing source_zip, dest_zip (writing global comment)"); + zipClose(dest_zip, global_comment); + unzClose(source_zip); + + UZKLogDebug("Freeing global_comment"); + free(global_comment); + + // Don't swap the files + if (noFilesDeleted) { + UZKLogInfo("No files deleted. Not replacing the original archive with the copy"); + return YES; + } + + // Failure + if (nextFileReturnValue != UNZ_END_OF_LIST_OF_FILE) + { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Failed to seek to the next file, while deleting %@ from the archive", @"UnzipKit", _resources, @"Detailed error string"), + filenameToDelete]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + UZKLogDebug("Removing temp_filename"); + remove(temp_filename); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail]; + } + + // Replace old file with the new (trimmed) one + NSURL *newURL; + + NSString *temporaryVolume = temporaryURL.volumeName; + NSString *destinationVolume = self.fileURL.volumeName; + + if ([temporaryVolume isEqualToString:destinationVolume]) { + UZKLogInfo("Temporary file URL and destination URL share a volume. Replacing one file with another"); + NSError *replaceError = nil; + BOOL result = [fm replaceItemAtURL:(NSURL* _Nonnull)self.fileURL + withItemAtURL:temporaryURL + backupItemName:nil + options:NSFileManagerItemReplacementWithoutDeletingBackupItem + resultingItemURL:&newURL + error:&replaceError]; + + if (!result) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Failed to replace the old archive with the new one, after deleting '%@' from it (%@)", @"UnzipKit", _resources, @"Detailed error string"), + filenameToDelete, replaceError.localizedDescription]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail + underlyer:replaceError]; + } + } else { + UZKLogInfo("Temporary file URL and destination URL reside on different volumes. Will remove original archive and copy over the replacement"); + newURL = self.fileURL; + + UZKLogDebug("Removing original archive: %{public}@", newURL); + NSError *deleteError = nil; + if (![fm removeItemAtURL:(NSURL* _Nonnull)newURL + error:&deleteError]) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Failed to remove original archive from external volume '%@', after deleting '%@' from a new version to replace it (%@)", @"UnzipKit", _resources, @"Detailed error string"), + destinationVolume, filenameToDelete, deleteError.localizedDescription]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail + underlyer:deleteError]; + } + + UZKLogDebug("Copying temporary archive from %{public}@ to destination %{public}@", temporaryURL, newURL); + NSError *copyError = nil; + if (![fm copyItemAtURL:temporaryURL + toURL:(NSURL* _Nonnull)newURL + error:©Error]) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Failed to copy archive to external volume '%@', after deleting '%@' from it (%@)", @"UnzipKit", _resources, @"Detailed error string"), + destinationVolume, filenameToDelete, copyError.localizedDescription]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail + underlyer:copyError]; + } + } + + UZKLogInfo("Updating archive bookmark"); + NSError *bookmarkError = nil; + if (![self storeFileBookmark:newURL + error:&bookmarkError]) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Failed to store the new file bookmark to the archive after deleting '%@' from it: %@", @"UnzipKit", _resources, @"Detailed error string"), + filenameToDelete, bookmarkError.localizedDescription]; + UZKLogError("UZKErrorCodeDeleteFile: %{public}@", detail); + return [self assignError:error code:UZKErrorCodeDeleteFile + detail:detail + underlyer:bookmarkError]; + } + + return YES; +} + + + +#pragma mark - Private Methods + + +- (BOOL)performActionWithArchiveOpen:(void(^)(NSError * __autoreleasing*innerError))action + inMode:(UZKFileMode)mode + error:(NSError * __autoreleasing*)error +{ + UZKCreateActivity("Performing Action With Archive Open"); + + @synchronized(self.threadLock) { + if (error) { + *error = nil; + } + + NSError *openError = nil; + NSError *actionError = nil; + + @try { + if (![self openFile:self.filename + inMode:mode + withPassword:self.password + error:&openError]) + { + UZKLogDebug("Archive failed to open. Reporting error"); + + if (error) { + *error = openError; + } + + return NO; + } + + if (action) { + UZKLogDebug("Performing action"); + action(&actionError); + } + } + @finally { + NSError *closeError = nil; + if (![self closeFile:&closeError inMode:mode]) { + UZKLogDebug("Archive failed to close"); + + if (error && !actionError && !openError) { + *error = closeError; + } + + return NO; + } + } + + if (error && actionError && !openError) { + *error = actionError; + } + + return !actionError; + } +} + +- (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 + error:(NSError * __autoreleasing*)error +{ + UZKCreateActivity("Performing Write"); + + if (overwrite) { + UZKLogInfo("Overwriting %{public}@ if it already exists. Will look for existing file to delete", filePath); + + NSError *listFilesError = nil; + NSArray *existingFiles; + + @autoreleasepool { + UZKLogDebug("Listing file info"); + existingFiles = [self listFileInfo:&listFilesError]; + } + + if (existingFiles) { + UZKLogDebug("Existing files found. Looking for matches to filePath %{public}@", filePath); + NSIndexSet *matchingFiles = [existingFiles indexesOfObjectsPassingTest: + ^BOOL(UZKFileInfo *info, NSUInteger idx, BOOL *stop) { + if ([info.filename isEqualToString:filePath]) { + *stop = YES; + return YES; + } + + return NO; + }]; + + if (matchingFiles.count > 0 && ![self deleteFile:filePath error:error]) { + UZKLogError("Failed to delete %{public}@ before writing new data for it", filePath); + return NO; + } + } + } + + if (!password) { + UZKLogDebug("No password specified for file. Using archive's password: %{public}@", password != nil ? @"" : @"(null)"); + password = self.password; + } + + __weak UZKArchive *welf = self; + + 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]; + + const char *passwordStr = NULL; + + if (password) { + UZKLogDebug("Converting password to NSISOLatin1StringEncoding"); + passwordStr = [password cStringUsingEncoding:NSISOLatin1StringEncoding]; + } + + UZKLogDebug("Opening new file..."); + int err = zipOpenNewFileInZip3(welf.zipFile, + filePath.UTF8String, + &zi, + NULL, 0, NULL, 0, NULL, + (method != UZKCompressionMethodNone) ? Z_DEFLATED : 0, + method, + 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, + passwordStr, + crc); + + if (err != ZIP_OK) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error opening file '%@' for write (%d)", @"UnzipKit", _resources, @"Detailed error string"), + filePath, err]; + UZKLogError("UZKErrorCodeFileOpenForWrite: %{public}@", detail); + [welf assignError:innerError code:UZKErrorCodeFileOpenForWrite + detail:detail]; + return; + } + + UZKLogDebug("Writing file"); + uLong outCRC = 0; + err = write(&outCRC, innerError); + if (err < 0) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error writing to file '%@' (%d)", @"UnzipKit", _resources, @"Detailed error string"), + filePath, err]; + UZKLogError("UZKErrorCodeFileOpenForWrite: %{public}@", detail); + [welf assignError:innerError code:UZKErrorCodeFileWrite + detail:detail]; + return; + } + + UZKLogDebug("Closing file..."); + 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]; + UZKLogError("UZKErrorCodeFileOpenForWrite: %{public}@", detail); + [welf assignError:innerError code:UZKErrorCodeFileWrite + detail:detail]; + return; + } + + } inMode:UZKFileModeAppend error:error]; + + return success; +} + +- (BOOL)openFile:(NSString *)zipFile + inMode:(UZKFileMode)mode + withPassword:(NSString *)aPassword + error:(NSError * __autoreleasing*)error +{ + UZKCreateActivity("Opening File"); + + UZKLogDebug("Opening file in mode %lu", (unsigned long)mode); + + if (error) { + *error = nil; + } + + if (self.mode != UZKFileModeUnassigned && self.mode != mode) { + NSString *message; + + if (self.mode == UZKFileModeUnzip) { + message = NSLocalizedStringFromTableInBundle(@"Unable to begin writing to the archive until all read operations have completed", @"UnzipKit", _resources, @"Detailed error string"); + } else { + message = NSLocalizedStringFromTableInBundle(@"Unable to begin reading from the archive until all write operations have completed", @"UnzipKit", _resources, @"Detailed error string"); + } + + UZKLogError("UZKErrorCodeMixedModeAccess: %{public}@", message); + return [self assignError:error code:UZKErrorCodeMixedModeAccess detail:message]; + } + + if (mode != UZKFileModeUnzip && self.openCount > 0) { + NSString *detail = NSLocalizedStringFromTableInBundle(@"Attempted to write to the archive while another write operation is already in progress", @"UnzipKit", _resources, @"Detailed error string"); + UZKLogError("UZKErrorCodeFileWrite: %{public}@", detail); + return [self assignError:error code:UZKErrorCodeFileWrite + detail:detail]; + } + + // Always initialize comment, so it can be read when the file is closed +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wdirect-ivar-access" + if (!self.commentRetrieved) { + UZKLogDebug("Retrieving comment"); + self.commentRetrieved = YES; + _comment = [self readGlobalComment]; + } +#pragma clang diagnostic pop + + if (self.openCount++ > 0) { + UZKLogDebug("File is already open. Not going any further"); + return YES; + } + + self.mode = mode; + + NSFileManager *fm = [NSFileManager defaultManager]; + + switch (mode) { + case UZKFileModeUnzip: { + if (![fm fileExistsAtPath:zipFile]) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"No file found at path %@", @"UnzipKit", _resources, @"Detailed error string"), + zipFile]; + UZKLogError("UZKErrorCodeArchiveNotFound: %{public}@", detail); + [self assignError:error code:UZKErrorCodeArchiveNotFound + detail:detail]; + return NO; + } + + UZKLogDebug("Opening file for read..."); + self.unzFile = unzOpen(self.filename.UTF8String); + if (self.unzFile == NULL) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error opening zip file %@", @"UnzipKit", _resources, @"Detailed error string"), + zipFile]; + UZKLogError("UZKErrorCodeBadZipFile: %{public}@", detail); + [self assignError:error code:UZKErrorCodeBadZipFile + detail:detail]; + return NO; + } + + UZKLogDebug("Seeking to first file..."); + int err = unzGoToFirstFile(self.unzFile); + if (err != UNZ_OK) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error going to first file in archive (%d)", @"UnzipKit", _resources, @"Detailed error string"), + err]; + UZKLogError("UZKErrorCodeFileNavigationError: %{public}@", detail); + [self assignError:error code:UZKErrorCodeFileNavigationError + detail:detail]; + return NO; + } + + NSMutableDictionary *dic = [NSMutableDictionary dictionary]; + + UZKLogInfo("Reading file info to cache file positions"); + + do { + @autoreleasepool { + UZKLogDebug("Reading file info for current file in zip"); + UZKFileInfo *info = [self currentFileInZipInfo:error]; + + if (!info) { + UZKLogDebug("No info returned. Exiting loop"); + return NO; + } + + UZKLogDebug("Got info for %{public}@", info.filename); + + unz_file_pos pos; + int err = unzGetFilePos(self.unzFile, &pos); + if (err == UNZ_OK && info.filename) { + NSValue *dictValue = [NSValue valueWithBytes:&pos + objCType:@encode(unz_file_pos)]; + dic[info.filename.decomposedStringWithCanonicalMapping] = dictValue; + } + } + } while (unzGoToNextFile (self.unzFile) != UNZ_END_OF_LIST_OF_FILE); + + self.archiveContents = [dic copy]; + break; + } + case UZKFileModeCreate: + case UZKFileModeAppend: + if (![fm fileExistsAtPath:zipFile]) { + NSError *createFileError = nil; + + UZKLogDebug("Creating empty file, since it doesn't exist yet"); + if (![[NSData data] writeToFile:zipFile options:NSDataWritingAtomic error:&createFileError]) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Failed to create new file for archive: %@", @"UnzipKit", _resources, @"Detailed error string"), + createFileError.localizedDescription]; + UZKLogError("UZKErrorCodeFileOpenForWrite: %{public}@", detail); + return [self assignError:error code:UZKErrorCodeFileOpenForWrite + detail:detail + underlyer:createFileError]; + } + + UZKLogDebug("Storing bookmark for newly created file"); + NSError *bookmarkError = nil; + if (![self storeFileBookmark:[NSURL fileURLWithPath:zipFile] + error:&bookmarkError]) + { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error creating bookmark to new archive file: %@", @"UnzipKit", _resources, @"Detailed error string"), + bookmarkError.localizedDescription]; + UZKLogError("UZKErrorCodeFileOpenForWrite: %{public}@", detail); + return [self assignError:error code:UZKErrorCodeFileOpenForWrite + detail:detail + underlyer:bookmarkError]; + } + } + + int appendStatus = mode == UZKFileModeCreate ? APPEND_STATUS_CREATE : APPEND_STATUS_ADDINZIP; + + UZKLogDebug("Opening archive for write"); + self.zipFile = zipOpen(self.filename.UTF8String, appendStatus); + if (self.zipFile == NULL) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error opening zip file for write: %@", @"UnzipKit", _resources, @"Detailed error string"), + zipFile]; + UZKLogError("UZKErrorCodeArchiveNotFound: %{public}@", detail); + [self assignError:error code:UZKErrorCodeArchiveNotFound + detail:detail]; + return NO; + } + break; + + case UZKFileModeUnassigned: + NSAssert(NO, @"Cannot call -openFile:inMode:withPassword:error: with a mode of UZKFileModeUnassigned (%lu)", (unsigned long)mode); + break; + } + + return YES; +} + +- (BOOL)closeFile:(NSError * __autoreleasing*)error + inMode:(UZKFileMode)mode +{ + UZKCreateActivity("Closing File"); + + if (mode != self.mode) { + UZKLogInfo("Closing archive for mode %lu, but archive is currently in mode %lu", (unsigned long)mode, (unsigned long)self.mode); + return NO; + } + + if (--self.openCount > 0) { + UZKLogDebug("Not closing file, as there have been more calls to open it than to close it"); + return YES; + } + + int err; + const char *cmt; + const char *logverb; + + BOOL closeSucceeded = YES; + + switch (self.mode) { + case UZKFileModeUnzip: + if (!self.unzFile) { + UZKLogDebug("self.unzFile is nil. File already closed?"); + break; + } + UZKLogDebug("Closing file in read mode..."); + err = unzClose(self.unzFile); + if (err != UNZ_OK) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error closing file in archive after read (%d)", @"UnzipKit", _resources, @"Detailed error string"), + err]; + UZKLogError("UZKErrorCodeZLibError: %{public}@", detail); + [self assignError:error code:UZKErrorCodeZLibError + detail:detail]; + closeSucceeded = NO; + } + break; + + case UZKFileModeCreate: + case UZKFileModeAppend: + logverb = self.mode == UZKFileModeCreate ? "create" : "append"; + + if (!self.zipFile) { + UZKLogDebug("self.zipFile is nil. File already closed?"); + break; + } + cmt = self.comment.UTF8String; + UZKLogDebug("Closing file in %{public}s mode with comment %{public}s...", logverb, cmt); + err = zipClose(self.zipFile, cmt); + if (err != ZIP_OK) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error closing file in archive in write mode %lu (%d)", @"UnzipKit", _resources, @"Detailed error string"), + self.mode, err]; + UZKLogError("UZKErrorCodeZLibError: %{public}@", detail); + [self assignError:error code:UZKErrorCodeZLibError + detail:detail]; + closeSucceeded = NO; + } + break; + + case UZKFileModeUnassigned: + NSAssert(NO, @"Unbalanced call to -closeFile:, openCount == %ld", (long)self.openCount); + break; + } + + if (self.openCount == 0) { + self.mode = UZKFileModeUnassigned; + } + + return closeSucceeded; +} + + + +#pragma mark - Zip File Navigation + + +- (UZKFileInfo *)currentFileInZipInfo:(NSError * __autoreleasing*)error { + UZKCreateActivity("currentFileInZipInfo"); + + char filename_inzip[FILE_IN_ZIP_MAX_NAME_LENGTH]; + unz_file_info64 file_info; + + UZKLogDebug("Getting file info..."); + int err = unzGetCurrentFileInfo64(self.unzFile, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0); + if (err != UNZ_OK) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error getting current file info (%d)", @"UnzipKit", _resources, @"Detailed error string"), + err]; + UZKLogError("UZKErrorCodeArchiveNotFound: %{public}@", detail); + [self assignError:error code:UZKErrorCodeArchiveNotFound + detail:detail]; + return nil; + } + + NSString *filename = [UZKArchive figureOutCString:filename_inzip]; + return [UZKFileInfo fileInfo:&file_info filename:filename]; +} + +- (BOOL)locateFileInZip:(NSString *)fileNameInZip error:(NSError * __autoreleasing*)error { + UZKCreateActivity("locateFileInZip"); + + UZKLogDebug("Looking up file position"); + NSValue *filePosValue = self.archiveContents[fileNameInZip.decomposedStringWithCanonicalMapping]; + + if (!filePosValue) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"No file position found for '%@'", @"UnzipKit", _resources, @"Detailed error string"), + fileNameInZip]; + UZKLogError("UZKErrorCodeFileNotFoundInArchive: %{public}@", detail); + return [self assignError:error code:UZKErrorCodeFileNotFoundInArchive + detail:detail]; + } + + unz_file_pos pos; + [filePosValue getValue:&pos]; + + UZKLogDebug("Going to file position"); + int err = unzGoToFilePos(self.unzFile, &pos); + + if (err == UNZ_END_OF_LIST_OF_FILE) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"File '%@' not found in archive", @"UnzipKit", _resources, @"Detailed error string"), + fileNameInZip]; + UZKLogError("UZKErrorCodeFileNotFoundInArchive: %{public}@", detail); + return [self assignError:error code:UZKErrorCodeFileNotFoundInArchive + detail:detail]; + } + + if (err != UNZ_OK) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error seeking to file position (%d)", @"UnzipKit", _resources, @"Detailed error string"), + err]; + UZKLogError("%{public}@", detail); + return [self assignError:error code:err + detail:detail]; + } + + return YES; +} + + + +#pragma mark - Zip File Operations + + +- (BOOL)openFile:(NSError * __autoreleasing*)error +{ + UZKCreateActivity("openFile"); + + char filename_inzip[FILE_IN_ZIP_MAX_NAME_LENGTH]; + unz_file_info64 file_info; + + UZKLogDebug("Getting file info"); + int err = unzGetCurrentFileInfo64(self.unzFile, &file_info, filename_inzip, sizeof(filename_inzip), NULL, 0, NULL, 0); + if (err != UNZ_OK) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error getting current file info for archive (%d)", @"UnzipKit", _resources, @"Detailed error string"), + err]; + UZKLogError("UZKErrorCodeInternalError: %{public}@", detail); + return [self assignError:error code:UZKErrorCodeInternalError + detail:detail]; + } + + const char *passwordStr = NULL; + + if (self.password) { + UZKLogDebug("Encoding password in NSISOLatin1StringEncoding"); + passwordStr = [self.password cStringUsingEncoding:NSISOLatin1StringEncoding]; + } + + if ([self isDeflate64:file_info]) { + NSString *detail = NSLocalizedStringFromTableInBundle(@"Cannot open archive, since it was compressed using the Deflate64 algorithm (method ID 9)", @"UnzipKit", _resources, @"Error message"); + UZKLogError("UZKErrorCodeDeflate64: %{public}@", detail); + return [self assignError:error code:UZKErrorCodeDeflate64 + detail:detail]; + } + + UZKLogDebug("Opening file..."); + err = unzOpenCurrentFilePassword(self.unzFile, passwordStr); + if (err != UNZ_OK) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error opening archive (%d)", @"UnzipKit", _resources, @"Detailed error string"), + err]; + UZKLogError("%{public}@", detail); + return [self assignError:error code:err + detail:detail]; + } + + return YES; +} + + +- (NSData *)readFile:(NSString *)filePath length:(unsigned long long int)length error:(NSError * __autoreleasing*)error { + UZKCreateActivity("readFile"); + + UZKLogDebug("Opening file"); + if (![self openFile:error]) { + return nil; + } + + UZKLogDebug("Reading data..."); + NSMutableData *data = [NSMutableData dataWithLength:(NSUInteger)length]; + int bytes = unzReadCurrentFile(self.unzFile, data.mutableBytes, (unsigned)length); + + if (bytes < 0) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error reading data from '%@' in archive", @"UnzipKit", _resources, @"Detailed error string"), + filePath]; + UZKLogError("Error code %d: %{public}@", bytes, detail); + [self assignError:error code:bytes + detail:detail]; + return nil; + } + + UZKLogDebug("%{iec-bytes}d (%d bytes) read", bytes, bytes); + data.length = bytes; + return data; +} + +- (NSString *)readGlobalComment { + UZKCreateActivity("readGlobalComment"); + + UZKLogDebug("Checking archive exists"); + + NSError *checkExistsError = nil; + if (![self.fileURL checkResourceIsReachableAndReturnError:&checkExistsError]) { + UZKLogDebug("Archive not found"); + return nil; + } + + __weak UZKArchive *welf = self; + __block NSString *comment = nil; + NSError *error = nil; + + BOOL success = [self performActionWithArchiveOpen:^(NSError * __autoreleasing*innerError) { + UZKCreateActivity("Perform Action"); + + UZKLogDebug("Getting global info..."); + unz_global_info global_info; + int err = unzGetGlobalInfo(welf.unzFile, &global_info); + if (err != UNZ_OK) { + NSString *detail = [NSString localizedStringWithFormat:NSLocalizedStringFromTableInBundle(@"Error getting global info of archive during comment read: %d", @"UnzipKit", _resources, @"Detailed error string"), + err]; + UZKLogError("UZKErrorCodeReadComment: %{public}@", detail); + UZKLogDebug("Closing archive..."); + unzClose(welf.unzFile); + + [welf assignError:innerError code:UZKErrorCodeReadComment detail:detail]; + return; + } + + char *global_comment = NULL; + + if (global_info.size_comment > 0) + { + UZKLogDebug("Allocating global comment..."); + global_comment = (char*)malloc(global_info.size_comment+1); + if ((global_comment == NULL) && (global_info.size_comment != 0)) { + NSString *detail = NSLocalizedStringFromTableInBundle(@"Error allocating the global comment during comment read", @"UnzipKit", _resources, @"Detailed error string"); + UZKLogError("UZKErrorCodeReadComment: %{public}@", detail); + UZKLogDebug("Closing archive..."); + unzClose(welf.unzFile); + + [welf assignError:innerError code:UZKErrorCodeReadComment detail:detail]; + return; + } + + UZKLogDebug("Reading global comment..."); + if ((unsigned int)unzGetGlobalComment(welf.unzFile, global_comment, global_info.size_comment + 1) != global_info.size_comment) { + NSString *detail = NSLocalizedStringFromTableInBundle(@"Error reading the comment (readGlobalComment)", @"UnzipKit", _resources, @"Detailed error string"); + UZKLogError("UZKErrorCodeReadComment: %{public}@", detail); + UZKLogDebug("Closing archive and freeing global_comment..."); + unzClose(welf.unzFile); + free(global_comment); + + [welf assignError:innerError code:UZKErrorCodeReadComment detail:@"Error reading global comment (unzGetGlobalComment)"]; + return; + } + + UZKLogDebug("Turning C string into NSString"); + comment = [UZKArchive figureOutCString:global_comment]; + free(global_comment); + } + } inMode:UZKFileModeUnzip error:&error]; + + self.commentRetrieved = YES; + + if (!success) { + return nil; + } + + return comment; +} + + + +#pragma mark - Misc. Private Methods + + +- (BOOL)storeFileBookmark:(NSURL *)fileURL error:(NSError * __autoreleasing*)error +{ + UZKCreateActivity("storeFileBookmark"); + + UZKLogDebug("Creating bookmark"); + NSError *bookmarkError = nil; + self.fileBookmark = [fileURL bookmarkDataWithOptions:(NSURLBookmarkCreationOptions)0 + includingResourceValuesForKeys:@[] + relativeToURL:nil + error:&bookmarkError]; + + if (bookmarkError) { + UZKLogFault("Error creating bookmark for URL %{public}@: %{public}@", fileURL, bookmarkError); + } + + if (error) { + *error = bookmarkError ? bookmarkError : nil; + } + + return bookmarkError == nil; +} + ++ (NSString *)figureOutCString:(const char *)filenameBytes +{ + UZKCreateActivity("figureOutCString"); + + UZKLogDebug("Trying out UTF-8"); + NSString *stringValue = [NSString stringWithUTF8String:filenameBytes]; + + if (!stringValue) { + UZKLogDebug("Trying out NSWindowsCP1252StringEncoding"); + stringValue = [NSString stringWithCString:filenameBytes + encoding:NSWindowsCP1252StringEncoding]; + } + + if (!stringValue) { + UZKLogDebug("Trying out defaultCStringEncoding"); + stringValue = [NSString stringWithCString:filenameBytes + encoding:[NSString defaultCStringEncoding]]; + } + + UZKLogDebug("Returning decomposedStringWithCanonicalMapping"); + return [stringValue decomposedStringWithCanonicalMapping]; +} + ++ (NSString *)errorNameForErrorCode:(NSInteger)errorCode +{ + NSString *errorName; + + switch (errorCode) { + case UZKErrorCodeZLibError: + errorName = NSLocalizedStringFromTableInBundle(@"Error reading/writing file", @"UnzipKit", _resources, @"UZKErrorCodeZLibError"); + break; + + case UZKErrorCodeParameterError: + errorName = NSLocalizedStringFromTableInBundle(@"Parameter error", @"UnzipKit", _resources, @"UZKErrorCodeParameterError"); + break; + + case UZKErrorCodeBadZipFile: + errorName = NSLocalizedStringFromTableInBundle(@"Bad zip file", @"UnzipKit", _resources, @"UZKErrorCodeBadZipFile"); + break; + + case UZKErrorCodeInternalError: + errorName = NSLocalizedStringFromTableInBundle(@"Internal error", @"UnzipKit", _resources, @"UZKErrorCodeInternalError"); + break; + + case UZKErrorCodeCRCError: + errorName = NSLocalizedStringFromTableInBundle(@"The data got corrupted during decompression", @"UnzipKit", _resources, @"UZKErrorCodeCRCError"); + break; + + case UZKErrorCodeArchiveNotFound: + errorName = NSLocalizedStringFromTableInBundle(@"Can't open archive", @"UnzipKit", _resources, @"UZKErrorCodeArchiveNotFound"); + break; + + case UZKErrorCodeFileNavigationError: + errorName = NSLocalizedStringFromTableInBundle(@"Error navigating through the archive", @"UnzipKit", _resources, @"UZKErrorCodeFileNavigationError"); + break; + + case UZKErrorCodeFileNotFoundInArchive: + errorName = NSLocalizedStringFromTableInBundle(@"Can't find a file in the archive", @"UnzipKit", _resources, @"UZKErrorCodeFileNotFoundInArchive"); + break; + + case UZKErrorCodeOutputError: + errorName = NSLocalizedStringFromTableInBundle(@"Error extracting files from the archive", @"UnzipKit", _resources, @"UZKErrorCodeOutputError"); + break; + + case UZKErrorCodeOutputErrorPathIsAFile: + errorName = NSLocalizedStringFromTableInBundle(@"Attempted to extract the archive to a path that is a file, not a directory", @"UnzipKit", _resources, @"UZKErrorCodeOutputErrorPathIsAFile"); + break; + + case UZKErrorCodeInvalidPassword: + errorName = NSLocalizedStringFromTableInBundle(@"Incorrect password provided", @"UnzipKit", _resources, @"UZKErrorCodeInvalidPassword"); + break; + + case UZKErrorCodeFileRead: + errorName = NSLocalizedStringFromTableInBundle(@"Error reading a file in the archive", @"UnzipKit", _resources, @"UZKErrorCodeFileRead"); + break; + + case UZKErrorCodeFileOpenForWrite: + errorName = NSLocalizedStringFromTableInBundle(@"Error opening a file in the archive to write it", @"UnzipKit", _resources, @"UZKErrorCodeFileOpenForWrite"); + break; + + case UZKErrorCodeFileWrite: + errorName = NSLocalizedStringFromTableInBundle(@"Error writing a file in the archive", @"UnzipKit", _resources, @"UZKErrorCodeFileWrite"); + break; + + case UZKErrorCodeFileCloseWriting: + errorName = NSLocalizedStringFromTableInBundle(@"Error clonsing a file in the archive after writing it", @"UnzipKit", _resources, @"UZKErrorCodeFileCloseWriting"); + break; + + case UZKErrorCodeDeleteFile: + errorName = NSLocalizedStringFromTableInBundle(@"Error deleting a file in the archive", @"UnzipKit", _resources, @"UZKErrorCodeDeleteFile"); + break; + + case UZKErrorCodeMixedModeAccess: + errorName = NSLocalizedStringFromTableInBundle(@"Attempted to read before all writes have completed, or vise-versa", @"UnzipKit", _resources, @"UZKErrorCodeMixedModeAccess"); + break; + + case UZKErrorCodePreCRCMismatch: + errorName = NSLocalizedStringFromTableInBundle(@"The CRC given up front doesn't match the calculated CRC", @"UnzipKit", _resources, @"UZKErrorCodePreCRCMismatch"); + break; + + case UZKErrorCodeDeflate64: + errorName = NSLocalizedStringFromTableInBundle(@"The archive was compressed with the Deflate64 method, which isn't supported", @"UnzipKit", _resources, @"UZKErrorCodeDeflate64"); + break; + + default: + errorName = [NSString localizedStringWithFormat: + NSLocalizedStringFromTableInBundle(@"Unknown error code: %ld", @"UnzipKit", _resources, @"UnknownErrorCode"), errorCode]; + break; + } + + return errorName; +} + ++ (zip_fileinfo)zipFileInfoForDate:(NSDate *)fileDate + posixPermissions:(short)permissions +{ + NSCalendar *calendar = [NSCalendar calendarWithIdentifier:NSCalendarIdentifierGregorian]; + + // Use "now" if no date given + if (!fileDate) { + fileDate = [NSDate date]; + } + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wassign-enum" + + NSDateComponents *date = [calendar components:(NSCalendarUnitSecond | + NSCalendarUnitMinute | + NSCalendarUnitHour | + NSCalendarUnitDay | + NSCalendarUnitMonth | + NSCalendarUnitYear) + fromDate:fileDate]; + +#pragma clang diagnostic pop + + zip_fileinfo zi; + zi.tmz_date.tm_sec = (uInt)date.second; + zi.tmz_date.tm_min = (uInt)date.minute; + zi.tmz_date.tm_hour = (uInt)date.hour; + zi.tmz_date.tm_mday = (uInt)date.day; + zi.tmz_date.tm_mon = (uInt)date.month - 1; // 0-indexed + zi.tmz_date.tm_year = (uInt)date.year; + zi.internal_fa = 0; + zi.external_fa = 0; + zi.dosDate = 0; + + if (permissions > 0) { + unsigned long permissionsMask = (permissions & 0777) << 16; + zi.external_fa |= permissionsMask; + } + + return zi; +} + +/** + * @return Always returns NO + */ +- (BOOL)assignError:(NSError * __autoreleasing*)error + code:(NSInteger)errorCode + detail:(NSString *)errorDetail +{ + return [self assignError:error + code:errorCode + detail:errorDetail + underlyer:nil]; +} + +/** + * @return Always returns NO + */ +- (BOOL)assignError:(NSError * __autoreleasing*)error + code:(NSInteger)errorCode + detail:(NSString *)errorDetail + underlyer:(NSError *)underlyingError +{ + if (error) { + NSString *errorName = [UZKArchive errorNameForErrorCode:errorCode]; + + // If this error is being re-wrapped, include the original error + if (!underlyingError && *error && [*error isKindOfClass:[NSError class]]) { + underlyingError = *error; + } + + NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithDictionary: + @{NSLocalizedFailureReasonErrorKey: errorName, + NSLocalizedDescriptionKey: errorName, + NSLocalizedRecoverySuggestionErrorKey: errorDetail}]; + + if (self.fileURL) { + userInfo[NSURLErrorKey] = self.fileURL; + } + + if (underlyingError) { + userInfo[NSUnderlyingErrorKey] = underlyingError; + } + + *error = [NSError errorWithDomain:UZKErrorDomain + code:errorCode + userInfo:[NSDictionary dictionaryWithDictionary:userInfo]]; + } + + return NO; +} + +- (BOOL)isDeflate64:(unz_file_info64)file_info +{ + UZKCreateActivity("isDeflate64"); + + UZKLogDebug("Compression method: %lu", file_info.compression_method); + return file_info.compression_method == 9; +} + +- (NSProgress *)beginProgressOperation:(unsigned long long)totalUnitCount +{ + UZKCreateActivity("-beginProgressOperation:"); + + NSProgress *progress; + progress = self.progress; + self.progress = nil; + + if (!progress) { + progress = [[NSProgress alloc] initWithParent:[NSProgress currentProgress] + userInfo:nil]; + } + + if (totalUnitCount > 0) { + progress.totalUnitCount = totalUnitCount; + } + + progress.cancellable = YES; + progress.pausable = NO; + + return progress; +} + + +@end + + diff --git a/Carthage/Checkouts/UnzipKit/Source/UZKFileInfo.h b/Carthage/Checkouts/UnzipKit/Source/UZKFileInfo.h new file mode 100644 index 0000000..e14248e --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Source/UZKFileInfo.h @@ -0,0 +1,90 @@ +// +// UZKFileInfo.h +// UnzipKit +// +// + +#import + + + +@class UZKArchive; + +/** + * Defines the various compression levels that can be applied to a file + */ +typedef NS_ENUM(NSInteger, UZKCompressionMethod) { + /** + * Default level + */ + UZKCompressionMethodDefault= -1, + + /** + * No compression + */ + UZKCompressionMethodNone= 0, + + /** + * Fastest compression + */ + UZKCompressionMethodFastest= 1, + + /** + * Best (slowest) compression + */ + UZKCompressionMethodBest= 9 +}; + + +@interface UZKFileInfo : NSObject + +/** + * The name of the file + */ +@property (readonly, strong) NSString *filename; + +/** + * The timestamp of the file + */ +@property (readonly, nonatomic) NSDate *timestamp; + +/** + * The CRC checksum of the file + */ +@property (readonly) NSUInteger CRC; + +/** + * Size of the uncompressed file + */ +@property (readonly) unsigned long long int uncompressedSize; + +/** + * Size of the compressed file + */ +@property (readonly) unsigned long long int compressedSize; + +/** + * YES if the file will be continued of the next volume + */ +@property (readonly) BOOL isEncryptedWithPassword; + +/** + * YES if the file is a directory + */ +@property (readonly) BOOL isDirectory; + +/** + * The type of compression + */ +@property (readonly) UZKCompressionMethod compressionMethod; + +/** + * The POSIX permissions of the file, like you would get by retrieving the `NSFilePosixPermissions` + * key from the attributes NSFileManager returns. Assign in octal form, like 0777 in Objective-C or + * 0o777 in Swift + */ +@property (nonatomic, readonly) short posixPermissions; + + + +@end diff --git a/Carthage/Checkouts/UnzipKit/Source/UZKFileInfo.m b/Carthage/Checkouts/UnzipKit/Source/UZKFileInfo.m new file mode 100644 index 0000000..050adf6 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Source/UZKFileInfo.m @@ -0,0 +1,108 @@ +// +// UZKFileInfo.m +// UnzipKit +// +// + +#import "UZKFileInfo.h" +#import "unzip.h" + +@interface UZKFileInfo () + +@property (readwrite) tm_unz zipTMUDate; + +@end + + +@implementation UZKFileInfo + +@synthesize timestamp = _timestamp; + + +#pragma mark - Initialization + + ++ (instancetype) fileInfo:(unz_file_info64 *)fileInfo filename:(NSString *)filename { + return [[UZKFileInfo alloc] initWithFileInfo:fileInfo filename:filename]; +} + +- (instancetype)initWithFileInfo:(unz_file_info64 *)fileInfo filename:(NSString *)filename +{ + if ((self = [super init])) { + _filename = filename; + _uncompressedSize = fileInfo->uncompressed_size; + _compressedSize = fileInfo->compressed_size; + _zipTMUDate = fileInfo->tmu_date; + _CRC = fileInfo->crc; + _isEncryptedWithPassword = (fileInfo->flag & 1) != 0; + _isDirectory = [filename hasSuffix:@"/"]; + + if (_isDirectory) { + _filename = [_filename substringToIndex:_filename.length - 1]; + } + + _compressionMethod = [self readCompressionMethod:fileInfo->compression_method + flag:fileInfo->flag]; + + uLong permissions = (fileInfo->external_fa >> 16) & 0777U; + _posixPermissions = permissions ? permissions : 0644U; + } + return self; +} + + + +#pragma mark - Properties + + +- (NSDate *)timestamp { + if (!_timestamp) { + _timestamp = [self readDate:self.zipTMUDate]; + } + + return _timestamp; +} + + + +#pragma mark - Private Methods + + +- (UZKCompressionMethod)readCompressionMethod:(uLong)compressionMethod + flag:(uLong)flag +{ + UZKCompressionMethod level = UZKCompressionMethodNone; + if (compressionMethod != 0) { + switch ((flag & 0x6) / 2) { + case 0: + level = UZKCompressionMethodDefault; + break; + + case 1: + level = UZKCompressionMethodBest; + break; + + default: + level = UZKCompressionMethodFastest; + break; + } + } + + return level; +} + +- (NSDate *)readDate:(tm_unz)date +{ + NSDateComponents *components = [[NSDateComponents alloc] init]; + components.day = date.tm_mday; + components.month = date.tm_mon + 1; + components.year = date.tm_year; + components.hour = date.tm_hour; + components.minute = date.tm_min; + components.second = date.tm_sec; + NSCalendar *calendar = [NSCalendar currentCalendar]; + + return [calendar dateFromComponents:components]; +} + +@end diff --git a/Carthage/Checkouts/UnzipKit/Source/UZKFileInfo_Private.h b/Carthage/Checkouts/UnzipKit/Source/UZKFileInfo_Private.h new file mode 100644 index 0000000..bcce4fb --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Source/UZKFileInfo_Private.h @@ -0,0 +1,23 @@ +// +// UZKFileInfo_Private.h +// UnzipKit +// +// + +@import Foundation; + +#import "unzip.h" + +@interface UZKFileInfo (Private) + +/** + * Returns a UZKFileInfo instance for the given extended header data + * + * @param fileInfo The header data for a Zip file + * @param filename The archive that contains the file + * + * @return an instance of UZKFileInfo + */ ++ (instancetype) fileInfo:(unz_file_info64 *)fileInfo filename:(NSString *)filename; + +@end \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/Source/UnzipKit.h b/Carthage/Checkouts/UnzipKit/Source/UnzipKit.h new file mode 100644 index 0000000..d390a9d --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Source/UnzipKit.h @@ -0,0 +1,19 @@ +// +// UnzipKit.h +// UnzipKit +// +// Created by Dov Frankel on 12/16/14. +// Copyright (c) 2014 Abbey Code. All rights reserved. +// + +#import + +//! Project version number for UnzipKit. +FOUNDATION_EXPORT double UnzipKitVersionNumber; + +//! Project version string for UnzipKit. +FOUNDATION_EXPORT const unsigned char UnzipKitVersionString[]; + + +#import "UZKArchive.h" +#import "UZKFileInfo.h" diff --git a/Carthage/Checkouts/UnzipKit/Source/UnzipKitMacros.h b/Carthage/Checkouts/UnzipKit/Source/UnzipKitMacros.h new file mode 100644 index 0000000..c68438d --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Source/UnzipKitMacros.h @@ -0,0 +1,106 @@ +// +// UnzipKitMacros.h +// UnzipKit +// +// Created by Dov Frankel on 7/10/17. +// Copyright © 2017 Abbey Code. All rights reserved. +// + +#ifndef UnzipKitMacros_h +#define UnzipKitMacros_h + +#import "TargetConditionals.h" + +//#import "Availability.h" +//#import "AvailabilityInternal.h" + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundef" +#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" + + +#if TARGET_OS_IPHONE +#define SDK_10_13_MAJOR 11 +#define SDK_10_13_MINOR 0 +#else +#define SDK_10_13_MAJOR 10 +#define SDK_10_13_MINOR 13 +#endif + +// iOS 10, macOS 10.12, tvOS 10.0, watchOS 3.0 +#define UNIFIED_LOGGING_SUPPORTED \ + __IPHONE_OS_VERSION_MIN_REQUIRED >= 100000 \ + || __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200 \ + || __TV_OS_VERSION_MIN_REQUIRED >= 100000 \ + || __WATCH_OS_VERSION_MIN_REQUIRED >= 30000 + +#if UNIFIED_LOGGING_SUPPORTED +@import os.log; +@import os.activity; + +// Called from +[UnzipKit initialize] and +[UZKArchiveTestCase setUp] +extern os_log_t unzipkit_log; // Declared in UZKArchive.m +extern BOOL unzipkitIsAtLeast10_13SDK; // Declared in UZKArchive.m +#define UZKLogInit() unzipkit_log = os_log_create("com.abbey-code.UnzipKit", "General"); \ + \ + NSOperatingSystemVersion minVersion; \ + minVersion.majorVersion = SDK_10_13_MAJOR; \ + minVersion.minorVersion = SDK_10_13_MINOR; \ + minVersion.patchVersion = 0; \ + unzipkitIsAtLeast10_13SDK = [[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:minVersion]; \ + UZKLogDebug("Is >= 10.13 (or iOS 11): %@", unzipkitIsAtLeast10_13SDK ? @"YES" : @"NO"); + +#define UZKLog(format, ...) os_log(unzipkit_log, format, ##__VA_ARGS__); +#define UZKLogInfo(format, ...) os_log_info(unzipkit_log, format, ##__VA_ARGS__); +#define UZKLogDebug(format, ...) os_log_debug(unzipkit_log, format, ##__VA_ARGS__); + + +#define UZKLogError(format, ...) \ + if (unzipkitIsAtLeast10_13SDK) os_log_error(unzipkit_log, format, ##__VA_ARGS__); \ + else os_log_with_type(unzipkit_log, OS_LOG_TYPE_ERROR, format, ##__VA_ARGS__); + +#define UZKLogFault(format, ...) \ + if (unzipkitIsAtLeast10_13SDK) os_log_fault(unzipkit_log, format, ##__VA_ARGS__); \ + else os_log_with_type(unzipkit_log, OS_LOG_TYPE_FAULT, format, ##__VA_ARGS__); + + +#define UZKCreateActivity(name) \ + os_activity_t activity = os_activity_create(name, OS_ACTIVITY_CURRENT, OS_ACTIVITY_FLAG_DEFAULT); \ + os_activity_scope(activity); + + +#else // Fall back to regular NSLog + +// No-op, as nothing needs to be initialized +#define UZKLogInit() (void)0 + + +// Only used below +#define _removeLogFormatTokens(format) [[[@format \ + stringByReplacingOccurrencesOfString:@"{public}" withString:@""] \ + stringByReplacingOccurrencesOfString:@"{time_t}" withString:@""] \ + stringByReplacingOccurrencesOfString:@"{iec-bytes}" withString:@""] +#define _stringify(a) #a +#define _nsLogWithoutWarnings(format, ...) \ + _Pragma( _stringify( clang diagnostic push ) ) \ + _Pragma( _stringify( clang diagnostic ignored "-Wformat-nonliteral" ) ) \ + _Pragma( _stringify( clang diagnostic ignored "-Wformat-security" ) ) \ + NSLog(_removeLogFormatTokens(format), ##__VA_ARGS__); \ + _Pragma( _stringify( clang diagnostic pop ) ) + +// All levels do the same thing +#define UZKLog(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); +#define UZKLogInfo(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); +#define UZKLogDebug(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); +#define UZKLogError(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); +#define UZKLogFault(format, ...) _nsLogWithoutWarnings(format, ##__VA_ARGS__); + +// No-op, as no equivalent to Activities exists +#define UZKCreateActivity(name) (void)0 + +#endif + + +#pragma clang diagnostic pop + +#endif /* UnzipKitMacros_h */ diff --git a/Carthage/Checkouts/UnzipKit/Tests/CheckDataTests.m b/Carthage/Checkouts/UnzipKit/Tests/CheckDataTests.m new file mode 100644 index 0000000..fe1f748 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/CheckDataTests.m @@ -0,0 +1,97 @@ +// +// CheckDataTests.m +// UnzipKit +// +// Created by Dov Frankel on 10/13/17. +// Copyright (c) 2017 Abbey Code. All rights reserved. +// + +#import "UZKArchiveTestCase.h" +#import "UnzipKit.h" + +@interface CheckDataTests : UZKArchiveTestCase +@end + +@implementation CheckDataTests + + +#pragma mark - checkDataIntegrity + +- (void)testCheckDataIntegrity { + NSArray *testArchives = @[@"Test Archive.zip", + @"Test Archive (Password).zip"]; + + for (NSString *testArchiveName in testArchives) { + NSLog(@"Testing data integrity of archive %@", testArchiveName); + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *password = ([testArchiveName rangeOfString:@"Password"].location != NSNotFound + ? @"password" + : nil); + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL password:password error:nil]; + + BOOL success = [archive checkDataIntegrity]; + XCTAssertTrue(success, @"Data integrity check failed for %@", testArchiveName); + } +} + +- (void)testCheckDataIntegrity_NotAnArchive { + NSURL *testArchiveURL = self.testFileURLs[@"Test File B.jpg"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + BOOL success = [archive checkDataIntegrity]; + XCTAssertFalse(success, @"Data integrity check passed for non-archive"); +} + +- (void)testCheckDataIntegrity_ModifiedCRC { + NSURL *testArchiveURL = self.testFileURLs[@"Modified CRC Archive.zip"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + BOOL success = [archive checkDataIntegrity]; + XCTAssertFalse(success, @"Data integrity check passed for archive with a modified CRC"); +} + +#pragma mark - checkDataIntegrityOfFile + +- (void)testCheckDataIntegrityForFile { + NSArray *testArchives = @[@"Test Archive.zip", + @"Test Archive (Password).zip"]; + + for (NSString *testArchiveName in testArchives) { + NSLog(@"Testing data integrity of file in archive %@", testArchiveName); + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *password = ([testArchiveName rangeOfString:@"Password"].location != NSNotFound + ? @"password" + : nil); + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL password:password error:nil]; + + NSError *listFilenamesError = nil; + NSArray *filenames = [archive listFilenames:&listFilenamesError]; + + XCTAssertNotNil(filenames, @"No file info returned for %@", testArchiveName); + XCTAssertNil(listFilenamesError, @"Error returned for %@: %@", testArchiveName, listFilenamesError); + + NSString *firstFilename = filenames.firstObject; + BOOL success = [archive checkDataIntegrityOfFile:firstFilename]; + + XCTAssertTrue(success, @"Data integrity check failed for %@ in %@", firstFilename, testArchiveName); + } +} + +- (void)testCheckDataIntegrityForFile_NotAnArchive { + NSURL *testArchiveURL = self.testFileURLs[@"Test File B.jpg"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + BOOL success = [archive checkDataIntegrityOfFile:@"README.md"]; + XCTAssertFalse(success, @"Data integrity check passed for non-archive"); +} + +- (void)testCheckDataIntegrityForFile_ModifiedCRC { + NSURL *testArchiveURL = self.testFileURLs[@"Modified CRC Archive.zip"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + BOOL success = [archive checkDataIntegrityOfFile:@"README.md"]; + XCTAssertFalse(success, @"Data integrity check passed for archive with modified CRC"); +} + + +@end diff --git a/Carthage/Checkouts/UnzipKit/Tests/CommentsTests.m b/Carthage/Checkouts/UnzipKit/Tests/CommentsTests.m new file mode 100644 index 0000000..3a26b7e --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/CommentsTests.m @@ -0,0 +1,53 @@ +// +// CommentsTests.m +// UnzipKit +// +// Created by Dov Frankel on 7/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "UZKArchiveTestCase.h" +#import "UnzipKit.h" + +@interface CommentsTests : UZKArchiveTestCase +@end + +@implementation CommentsTests + + +- (void)testGlobalComment_Read +{ + UZKArchive *commentArchive = [[UZKArchive alloc] initWithURL:self.testFileURLs[@"Comments Archive.zip"] error:nil]; + + NSString *comment = commentArchive.comment; + XCTAssertNotNil(comment, @"No comment returned from archive"); + XCTAssertGreaterThan(comment.length, (NSUInteger)0, @"Comment has no content"); +} + +- (void)testGlobalComment_ReadWhenNonePresent +{ + UZKArchive *commentFreeArchive = [[UZKArchive alloc] initWithURL:self.testFileURLs[@"Test Archive.zip"] error:nil]; + + NSString *comment = commentFreeArchive.comment; + XCTAssertNil(comment, @"Comment returned from archive that should have none"); +} + +- (void)testGlobalComment_Write +{ + UZKArchive *commentArchive = [[UZKArchive alloc] initWithURL:self.testFileURLs[@"Test Archive.zip"] error:nil]; + + NSString *originalComment = commentArchive.comment; + XCTAssertNil(originalComment, @"Comment returned from archive that should have none"); + + NSString *expectedComment = @"Fünky unicode stuff"; + commentArchive.comment = expectedComment; + + UZKArchive *newArchiveInstance = [[UZKArchive alloc] initWithURL:commentArchive.fileURL error:nil]; + + NSString *updatedComment = newArchiveInstance.comment.decomposedStringWithCanonicalMapping; + XCTAssertEqualObjects(updatedComment, expectedComment.decomposedStringWithCanonicalMapping, + @"Wrong comment read from archive"); +} + + +@end diff --git a/Carthage/Checkouts/UnzipKit/Tests/DeleteFileTests.m b/Carthage/Checkouts/UnzipKit/Tests/DeleteFileTests.m new file mode 100644 index 0000000..61a3d04 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/DeleteFileTests.m @@ -0,0 +1,150 @@ +// +// DeleteFileTests.m +// UnzipKit +// +// Created by Dov Frankel on 7/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "UZKArchiveTestCase.h" +#import "UnzipKit.h" + +@interface DeleteFileTests : UZKArchiveTestCase +@end + +@implementation DeleteFileTests + + +- (void)testDeleteFile_FirstFile +{ + NSArray *testArchives = @[@"Test Archive.zip", + @"Test Archive (Password).zip"]; + + NSSet *expectedFileSet = self.nonZipTestFilePaths; + NSArray *expectedFiles = [expectedFileSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; + NSString *fileToDelete = expectedFiles[0]; + + NSMutableArray *newFileList = [NSMutableArray arrayWithArray:expectedFiles]; + [newFileList removeObject:fileToDelete]; + + for (NSString *testArchiveName in testArchives) { + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *password = ([testArchiveName rangeOfString:@"Password"].location != NSNotFound + ? @"password" + : nil); + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL password:password error:nil]; + + NSError *deleteError = nil; + BOOL result = [archive deleteFile:fileToDelete error:&deleteError]; + XCTAssertTrue(result, @"Failed to delete %@ from %@", fileToDelete, testArchiveName); + XCTAssertNil(deleteError, @"Error deleting %@ from %@", fileToDelete, testArchiveName); + + __block NSUInteger fileIndex = 0; + NSError *error = nil; + + [archive performOnDataInArchive: + ^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + NSString *expectedFilename = newFileList[fileIndex++]; + XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Unexpected filename encountered"); + + NSURL *expectedURL = self.testFileURLs[expectedFilename]; + NSData *expectedFileData = [NSData dataWithContentsOfURL:expectedURL]; + + XCTAssertNotNil(fileData, @"No data extracted"); + XCTAssertTrue([expectedFileData isEqualToData:fileData], @"File data doesn't match original file"); + } error:&error]; + + XCTAssertNil(error, @"Error iterating through files"); + XCTAssertEqual(fileIndex, newFileList.count, @"Incorrect number of files encountered"); + } +} + +- (void)testDeleteFile_SecondFile +{ + NSArray *testArchives = @[@"Test Archive.zip", + @"Test Archive (Password).zip"]; + + NSSet *expectedFileSet = self.nonZipTestFilePaths; + NSArray *expectedFiles = [expectedFileSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; + NSString *fileToDelete = expectedFiles[1]; + + NSMutableArray *newFileList = [NSMutableArray arrayWithArray:expectedFiles]; + [newFileList removeObject:fileToDelete]; + + for (NSString *testArchiveName in testArchives) { + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *password = ([testArchiveName rangeOfString:@"Password"].location != NSNotFound + ? @"password" + : nil); + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL password:password error:nil]; + + NSError *deleteError = nil; + BOOL result = [archive deleteFile:fileToDelete error:&deleteError]; + XCTAssertTrue(result, @"Failed to delete %@ from %@", fileToDelete, testArchiveName); + XCTAssertNil(deleteError, @"Error deleting %@ from %@", fileToDelete, testArchiveName); + + __block NSUInteger fileIndex = 0; + NSError *error = nil; + + [archive performOnDataInArchive: + ^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + NSString *expectedFilename = newFileList[fileIndex++]; + XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Unexpected filename encountered"); + + NSURL *expectedURL = self.testFileURLs[expectedFilename]; + NSData *expectedFileData = [NSData dataWithContentsOfURL:expectedURL]; + + XCTAssertNotNil(fileData, @"No data extracted"); + XCTAssertTrue([expectedFileData isEqualToData:fileData], @"File data doesn't match original file"); + } error:&error]; + + XCTAssertNil(error, @"Error iterating through files"); + XCTAssertEqual(fileIndex, newFileList.count, @"Incorrect number of files encountered"); + } +} + +- (void)testDeleteFile_ThirdFile +{ + NSArray *testArchives = @[@"Test Archive.zip", + @"Test Archive (Password).zip"]; + + NSSet *expectedFileSet = self.nonZipTestFilePaths; + NSArray *expectedFiles = [expectedFileSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; + NSString *fileToDelete = expectedFiles[2]; + + NSMutableArray *newFileList = [NSMutableArray arrayWithArray:expectedFiles]; + [newFileList removeObject:fileToDelete]; + + for (NSString *testArchiveName in testArchives) { + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *password = ([testArchiveName rangeOfString:@"Password"].location != NSNotFound + ? @"password" + : nil); + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL password:password error:nil]; + + NSError *deleteError = nil; + BOOL result = [archive deleteFile:fileToDelete error:&deleteError]; + XCTAssertTrue(result, @"Failed to delete %@ from %@", fileToDelete, testArchiveName); + XCTAssertNil(deleteError, @"Error deleting %@ from %@", fileToDelete, testArchiveName); + + __block NSUInteger fileIndex = 0; + NSError *error = nil; + + [archive performOnDataInArchive: + ^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + NSString *expectedFilename = newFileList[fileIndex++]; + XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Unexpected filename encountered"); + + NSData *expectedFileData = [NSData dataWithContentsOfURL:self.testFileURLs[expectedFilename]]; + + XCTAssertNotNil(fileData, @"No data extracted"); + XCTAssertTrue([expectedFileData isEqualToData:fileData], @"File data doesn't match original file"); + } error:&error]; + + XCTAssertNil(error, @"Error iterating through files"); + XCTAssertEqual(fileIndex, newFileList.count, @"Incorrect number of files encountered"); + } +} + + +@end diff --git a/Carthage/Checkouts/UnzipKit/Tests/ErrorHandlingTests.m b/Carthage/Checkouts/UnzipKit/Tests/ErrorHandlingTests.m new file mode 100644 index 0000000..8f4d783 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/ErrorHandlingTests.m @@ -0,0 +1,45 @@ +// +// ErrorHandlingTests.m +// UnzipKit +// +// Created by Dov Frankel on 7/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "UZKArchiveTestCase.h" +#import "UnzipKit.h" + +@interface ErrorHandlingTests : UZKArchiveTestCase +@end + +@implementation ErrorHandlingTests + + +- (void)testNestedError +{ + NSURL *testArchiveURL = self.testFileURLs[@"Test Archive.zip"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *error = nil; + NSData *extractedData = [archive extractDataFromFile:@"file-doesnt-exist.txt" + error:&error]; + + XCTAssertNil(extractedData, @"Data returned when there was an error"); + XCTAssertNotNil(error, @"No error returned when extracting data for nonexistant archived file"); + XCTAssertEqual(error.code, UZKErrorCodeFileNotFoundInArchive, @"Unexpected error code"); + + NSString *recoverySuggestion = error.localizedRecoverySuggestion; + XCTAssertNotEqual([recoverySuggestion rangeOfString:@"during buffered read"].location, NSNotFound, + @"Incorrect localized recovery suggestion returned in error: '%@'", recoverySuggestion); + + NSError *underlyingError = error.userInfo[NSUnderlyingErrorKey]; + XCTAssertNotNil(underlyingError, @"No inner error returned when file doesn't exist"); + XCTAssertEqual(underlyingError.code, UZKErrorCodeFileNotFoundInArchive, @"Unexpected underlying error code"); + + NSString *underlyingRecoverySuggestion = underlyingError.localizedRecoverySuggestion; + XCTAssertNotEqual([underlyingRecoverySuggestion rangeOfString:@"No file position found"].location, NSNotFound, + @"Incorrect localized recovery suggestion returned in inner error: '%@'", underlyingRecoverySuggestion); +} + + +@end diff --git a/Carthage/Checkouts/UnzipKit/Tests/ExtractBufferedDataTests.m b/Carthage/Checkouts/UnzipKit/Tests/ExtractBufferedDataTests.m new file mode 100644 index 0000000..d341e01 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/ExtractBufferedDataTests.m @@ -0,0 +1,120 @@ +// +// ExtractBufferedDataTests.m +// UnzipKit +// +// Created by Dov Frankel on 7/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "UnzipKit.h" + +#import "UZKArchiveTestCase.h" +#import "UnzipKitMacros.h" + + +#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200 +#import +enum SignPostCode: uint { // Use to reference in Instruments (http://stackoverflow.com/a/39416673/105717) + SignPostCodeCreateTextFile = 0, + SignPostCodeArchiveData = 1, + SignPostCodeExtractData = 2, +}; + +enum SignPostColor: uint { // standard color scheme for signposts in Instruments + SignPostColorBlue = 0, + SignPostColorGreen = 1, + SignPostColorPurple = 2, + SignPostColorOrange = 3, + SignPostColorRed = 4, +}; +#endif + +@interface ExtractBufferedDataTests : UZKArchiveTestCase +@end + +@implementation ExtractBufferedDataTests + + +- (void)testExtractBufferedData +{ + NSURL *archiveURL = self.testFileURLs[@"Test Archive.zip"]; + NSString *extractedFile = @"Test File B.jpg"; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:archiveURL error:nil]; + + NSError *error = nil; + NSMutableData *reconstructedFile = [NSMutableData data]; + BOOL success = [archive extractBufferedDataFromFile:extractedFile + error:&error + action: + ^(NSData *dataChunk, CGFloat percentDecompressed) { +#if DEBUG + UZKLogDebug("Decompressed: %f%%", percentDecompressed); +#endif + [reconstructedFile appendBytes:dataChunk.bytes + length:dataChunk.length]; + }]; + + XCTAssertTrue(success, @"Failed to read buffered data"); + XCTAssertNil(error, @"Error reading buffered data"); + XCTAssertGreaterThan(reconstructedFile.length, (NSUInteger)0, @"No data returned"); + + NSData *originalFile = [NSData dataWithContentsOfURL:self.testFileURLs[extractedFile]]; + XCTAssertTrue([originalFile isEqualToData:reconstructedFile], + @"File extracted in buffer not returned correctly"); +} + +#if !TARGET_OS_IPHONE && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200 +- (void)testExtractBufferedData_VeryLarge +{ + kdebug_signpost_start(SignPostCodeCreateTextFile, 0, 0, 0, SignPostColorBlue); + NSURL *largeTextFile = [self emptyTextFileOfLength:100000000]; // Increase for a more dramatic test + XCTAssertNotNil(largeTextFile, @"No large text file URL returned"); + kdebug_signpost_end(SignPostCodeCreateTextFile, 0, 0, 0, SignPostColorBlue); + + kdebug_signpost_start(SignPostCodeArchiveData, 0, 0, 0, SignPostColorGreen); + NSURL *archiveURL = [self archiveWithFiles:@[largeTextFile]]; + XCTAssertNotNil(archiveURL, @"No archived large text file URL returned"); + kdebug_signpost_end(SignPostCodeArchiveData, 0, 0, 0, SignPostColorGreen); + + NSURL *deflatedFileURL = [self.tempDirectory URLByAppendingPathComponent:@"DeflatedTextFile.txt"]; + BOOL createSuccess = [[NSFileManager defaultManager] createFileAtPath:deflatedFileURL.path + contents:nil + attributes:nil]; + XCTAssertTrue(createSuccess, @"Failed to create empty deflate file"); + + NSError *handleError = nil; + NSFileHandle *deflated = [NSFileHandle fileHandleForWritingToURL:deflatedFileURL + error:&handleError]; + XCTAssertNil(handleError, @"Error creating a file handle"); + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:archiveURL error:nil]; + + kdebug_signpost_start(SignPostCodeExtractData, 0, 0, 0, SignPostColorPurple); + + NSError *error = nil; + BOOL success = [archive extractBufferedDataFromFile:largeTextFile.lastPathComponent + error:&error + action: + ^(NSData *dataChunk, CGFloat percentDecompressed) { +# if DEBUG + UZKLogDebug("Decompressed: %f%%", percentDecompressed); +# endif + [deflated writeData:dataChunk]; + }]; + + kdebug_signpost_end(SignPostCodeExtractData, 0, 0, 0, SignPostColorPurple); + + XCTAssertTrue(success, @"Failed to read buffered data"); + XCTAssertNil(error, @"Error reading buffered data"); + + [deflated closeFile]; + + NSData *deflatedData = [NSData dataWithContentsOfURL:deflatedFileURL]; + NSData *fileData = [NSData dataWithContentsOfURL:largeTextFile]; + + XCTAssertTrue([fileData isEqualToData:deflatedData], @"Data didn't restore correctly"); +} +#endif + + +@end diff --git a/Carthage/Checkouts/UnzipKit/Tests/ExtractDataTests.m b/Carthage/Checkouts/UnzipKit/Tests/ExtractDataTests.m new file mode 100644 index 0000000..3c71d27 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/ExtractDataTests.m @@ -0,0 +1,127 @@ +// +// ExtractDataTests.m +// UnzipKit +// +// Created by Dov Frankel on 7/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "UZKArchiveTestCase.h" +#import "UnzipKit.h" +#import "UnzipKitMacros.h" + +@interface ExtractDataTests : UZKArchiveTestCase +@end + +@implementation ExtractDataTests + + +- (void)testExtractData +{ + NSArray *testArchives = @[@"Test Archive.zip", + @"Test Archive (Password).zip"]; + + NSSet *expectedFileSet = self.nonZipTestFilePaths; + NSArray *expectedFiles = [expectedFileSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; + + for (NSString *testArchiveName in testArchives) { + + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *password = ([testArchiveName rangeOfString:@"Password"].location != NSNotFound + ? @"password" + : nil); + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL password:password error:nil]; + + NSError *error = nil; + NSArray *fileInfos = [archive listFileInfo:&error]; + XCTAssertNil(error, @"Error reading file info"); + + for (NSUInteger i = 0; i < expectedFiles.count; i++) { + NSString *expectedFilename = expectedFiles[i]; + + NSError *error = nil; + NSData *extractedData = [archive extractDataFromFile:expectedFilename + error:&error]; + + XCTAssertNil(error, @"Error in extractData:error:"); + + NSData *expectedFileData = [NSData dataWithContentsOfURL:self.testFileURLs[expectedFilename]]; + + XCTAssertNotNil(extractedData, @"No data extracted (%@)", testArchiveName); + XCTAssertTrue([expectedFileData isEqualToData:extractedData], @"Extracted data doesn't match original file (%@)", testArchiveName); + + error = nil; + NSData *dataFromFileInfo = [archive extractData:fileInfos[i] + error:&error]; + XCTAssertNil(error, @"Error extracting data by file info (%@)", testArchiveName); + XCTAssertTrue([expectedFileData isEqualToData:dataFromFileInfo], @"Extracted data from file info doesn't match original file (%@)", testArchiveName); + } + } +} + +- (void)testExtractData_Unicode +{ + NSSet *expectedFileSet = self.nonZipUnicodeFilePaths; + NSArray *expectedFiles = [expectedFileSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; + + NSURL *testArchiveURL = self.unicodeFileURLs[@"Ⓣest Ⓐrchive.zip"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *error = nil; + NSArray *fileInfos = [archive listFileInfo:&error]; + XCTAssertNil(error, @"Error reading file info"); + + for (NSUInteger i = 0; i < expectedFiles.count; i++) { + NSString *expectedFilename = expectedFiles[i]; + + NSError *error = nil; + NSData *extractedData = [archive extractDataFromFile:expectedFilename + error:&error]; + + XCTAssertNil(error, @"Error in extractData:error:"); + + NSData *expectedFileData = [NSData dataWithContentsOfURL:self.unicodeFileURLs[expectedFilename]]; + + XCTAssertNotNil(extractedData, @"No data extracted"); + XCTAssertTrue([expectedFileData isEqualToData:extractedData], @"Extracted data doesn't match original file (%@)", expectedFilename); + + error = nil; + NSData *dataFromFileInfo = [archive extractData:fileInfos[i] + error:&error]; + XCTAssertNil(error, @"Error extracting data by file info"); + XCTAssertTrue([expectedFileData isEqualToData:dataFromFileInfo], @"Extracted data from file info doesn't match original file (%@)", expectedFilename); + } +} + +- (void)testExtractData_NoPassword +{ + NSArray *testArchives = @[@"Test Archive (Password).zip"]; + + for (NSString *testArchiveName in testArchives) { + UZKArchive *archive = [[UZKArchive alloc] initWithURL:self.testFileURLs[testArchiveName] error:nil]; + + NSError *error = nil; + NSData *data = [archive extractDataFromFile:@"Test File A.txt" + error:&error]; + + XCTAssertNotNil(error, @"Extract data without password succeeded"); + XCTAssertNil(data, @"Data returned without password"); + XCTAssertEqual(error.code, UZKErrorCodeInvalidPassword, @"Unexpected error code returned"); + } +} + +- (void)testExtractData_InvalidArchive +{ + UZKArchive *archive = [[UZKArchive alloc] initWithURL:self.testFileURLs[@"Test File A.txt"] error:nil]; + + NSError *error = nil; + NSData *data = [archive extractDataFromFile:@"Any file.txt" + error:&error]; + + XCTAssertNotNil(error, @"Extract data for invalid archive succeeded"); + XCTAssertNil(data, @"Data returned for invalid archive"); + XCTAssertEqual(error.code, UZKErrorCodeBadZipFile, @"Unexpected error code returned"); +} + + +@end diff --git a/Carthage/Checkouts/UnzipKit/Tests/ExtractDataTests_Swift.swift b/Carthage/Checkouts/UnzipKit/Tests/ExtractDataTests_Swift.swift new file mode 100644 index 0000000..f1b01c9 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/ExtractDataTests_Swift.swift @@ -0,0 +1,65 @@ +// +// ExtractDataTests_Swift.swift +// UnzipKit +// +// Created by Dov Frankel on 2/11/16. +// Copyright (c) 2016 Abbey Code. All rights reserved. +// + +import UnzipKit + +class ExtractDataTests_Swift: UZKArchiveTestCase { + + func testExtractData_NoPassword() { + let testArchives = ["Test Archive (Password).zip"] + let testFileURLs = (self.testFileURLs as NSDictionary) as! [String: URL] + + for testArchiveName in testArchives { + var thrownError: Error? + + do { + let archive = try UZKArchive(url: testFileURLs[testArchiveName]!) + try archive.extractData(fromFile: "Test File A.txt") + } catch let error { + thrownError = error + } + + XCTAssertNotNil(thrownError, "No error thrown for archive \(testArchiveName)") + + guard let thrownNSError = thrownError as NSError? else { + XCTFail("Error returned is not an NSError (\(testArchiveName))") + continue + } + + XCTAssertEqual(thrownNSError.code, UZKErrorCode.invalidPassword.rawValue, + "Unexpected error code returned for \(testArchiveName)"); + } + } + + func testExtractData_InvalidArchive() { + let testArchives = ["Test File A.txt"] + let testFileURLs = (self.testFileURLs as NSDictionary) as! [String: URL] + + for testArchiveName in testArchives { + var thrownError: Error? + + do { + let archive = try UZKArchive(url: testFileURLs[testArchiveName]!) + try archive.extractData(fromFile: "Test File A.txt") + } catch let error { + thrownError = error + } + + XCTAssertNotNil(thrownError, "No error thrown for archive \(testArchiveName)") + + guard let thrownNSError = thrownError as NSError? else { + XCTFail("Error returned is not an NSError (\(testArchiveName))") + continue + } + + XCTAssertEqual(thrownNSError.code, UZKErrorCode.badZipFile.rawValue, + "Unexpected error code returned for \(testArchiveName)"); + } + } + +} diff --git a/Carthage/Checkouts/UnzipKit/Tests/ExtractFilesTests.m b/Carthage/Checkouts/UnzipKit/Tests/ExtractFilesTests.m new file mode 100644 index 0000000..b376033 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/ExtractFilesTests.m @@ -0,0 +1,295 @@ +// +// ExtractFilesTests.m +// UnzipKit +// +// Created by Dov Frankel on 7/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "UZKArchiveTestCase.h" +@import UnzipKit; +#import "UnzipKitMacros.h" + +@interface ExtractFilesTests : UZKArchiveTestCase +@end + +@implementation ExtractFilesTests + + +- (void)testExtractFiles +{ + NSArray *testArchives = @[@"Test Archive.zip", + @"Test Archive (Password).zip"]; + + NSSet *expectedFileSet = self.nonZipTestFilePaths; + NSArray *expectedFiles = [expectedFileSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; + + NSFileManager *fm = [NSFileManager defaultManager]; + + for (NSString *testArchiveName in testArchives) { + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *extractDirectory = [self randomDirectoryWithPrefix: + [testArchiveName stringByDeletingPathExtension]]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + NSString *password = ([testArchiveName rangeOfString:@"Password"].location != NSNotFound + ? @"password" + : nil); + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL password:password error:nil]; + + NSError *error = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&error]; + + XCTAssertNil(error, @"Error returned by extractFilesTo:overWrite:error:"); + XCTAssertTrue(success, @"Failed to extract %@ to %@", testArchiveName, extractURL); + + error = nil; + NSArray *extractedFiles = [[fm contentsOfDirectoryAtPath:extractURL.path + error:&error] + sortedArrayUsingSelector:@selector(compare:)]; + + XCTAssertNil(error, @"Failed to list contents of extract directory: %@", extractURL); + + XCTAssertNotNil(extractedFiles, @"No list of files returned"); + XCTAssertEqual(extractedFiles.count, expectedFileSet.count, + @"Incorrect number of files listed in archive"); + + for (NSUInteger i = 0; i < extractedFiles.count; i++) { + NSString *extractedFilename = extractedFiles[i]; + NSString *expectedFilename = expectedFiles[i]; + + XCTAssertEqualObjects(extractedFilename, expectedFilename, @"Incorrect filename listed"); + + NSURL *extractedFileURL = [extractURL URLByAppendingPathComponent:extractedFilename]; + NSURL *expectedFileURL = self.testFileURLs[expectedFilename]; + + NSData *extractedFileData = [NSData dataWithContentsOfURL:extractedFileURL]; + NSData *expectedFileData = [NSData dataWithContentsOfURL:expectedFileURL]; + + XCTAssertTrue([expectedFileData isEqualToData:extractedFileData], @"Data in file doesn't match source"); + } + } +} + +- (void)testExtractFiles_Unicode +{ + NSSet *expectedFileSet = self.nonZipUnicodeFilePaths; + NSArray *expectedFiles = [expectedFileSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; + + NSFileManager *fm = [NSFileManager defaultManager]; + + NSString *testArchiveName = @"Ⓣest Ⓐrchive.zip"; + NSURL *testArchiveURL = self.unicodeFileURLs[testArchiveName]; + NSString *extractDirectory = [self randomDirectoryWithPrefix: + [testArchiveName stringByDeletingPathExtension]]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *error = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&error]; + + XCTAssertNil(error, @"Error returned by extractFilesTo:overWrite:error:"); + XCTAssertTrue(success, @"Failed to extract %@ to %@", testArchiveName, extractURL); + + error = nil; + NSArray *extractedFiles = [[fm contentsOfDirectoryAtPath:extractURL.path + error:&error] + sortedArrayUsingSelector:@selector(compare:)]; + + XCTAssertNil(error, @"Failed to list contents of extract directory: %@", extractURL); + + XCTAssertNotNil(extractedFiles, @"No list of files returned"); + XCTAssertEqual(extractedFiles.count, expectedFileSet.count, + @"Incorrect number of files listed in archive"); + + for (NSUInteger i = 0; i < extractedFiles.count; i++) { + NSString *extractedFilename = extractedFiles[i]; + NSString *expectedFilename = expectedFiles[i]; + + XCTAssertEqualObjects(extractedFilename, expectedFilename, @"Incorrect filename listed"); + + NSURL *extractedFileURL = [extractURL URLByAppendingPathComponent:extractedFilename]; + NSURL *expectedFileURL = self.unicodeFileURLs[expectedFilename]; + + NSData *extractedFileData = [NSData dataWithContentsOfURL:extractedFileURL]; + NSData *expectedFileData = [NSData dataWithContentsOfURL:expectedFileURL]; + + XCTAssertTrue([expectedFileData isEqualToData:extractedFileData], @"Data in file doesn't match source"); + } +} + +- (void)testExtractFiles_NoPasswordGiven +{ + UZKArchive *archive = [[UZKArchive alloc] initWithURL:self.testFileURLs[@"Test Archive (Password).zip"] error:nil]; + + NSString *extractDirectory = [self randomDirectoryWithPrefix:archive.filename.stringByDeletingPathExtension]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + + NSError *error = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&error]; + + NSFileManager *fm = [NSFileManager defaultManager]; + BOOL dirExists = [fm fileExistsAtPath:extractURL.path]; + + XCTAssertFalse(success, @"Extract without password succeeded"); + XCTAssertEqual(error.code, UZKErrorCodeInvalidPassword, @"Unexpected error code returned"); + XCTAssertFalse(dirExists, @"Directory successfully created without password"); +} + +- (void)testExtractFiles_InvalidArchive +{ + NSFileManager *fm = [NSFileManager defaultManager]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:self.testFileURLs[@"Test File A.txt"] error:nil]; + + NSString *extractDirectory = [self randomDirectoryWithPrefix:@"ExtractInvalidArchive"]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + NSError *error = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&error]; + BOOL dirExists = [fm fileExistsAtPath:extractURL.path]; + + XCTAssertFalse(success, @"Extract invalid archive succeeded"); + XCTAssertEqual(error.code, UZKErrorCodeBadZipFile, @"Unexpected error code returned"); + XCTAssertFalse(dirExists, @"Directory successfully created for invalid archive"); +} + +- (void)testExtractFiles_Aces +{ + NSFileManager *fm = [NSFileManager defaultManager]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:self.testFileURLs[@"Aces.zip"] error:nil]; + + NSString *extractDirectory = [self randomDirectoryWithPrefix:@"ExtractAcesArchive"]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + NSError *error = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&error]; + + XCTAssertTrue(success, @"Extract Aces archive failed"); + + NSDirectoryEnumerator *enumerator = [fm enumeratorAtURL:extractURL + includingPropertiesForKeys:nil + options:(NSDirectoryEnumerationOptions)0 + errorHandler:^(NSURL *url, NSError *error) { +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments" // This appears to be an erroneous warning. rdar://22133126 + // Handle the error. + // Return YES if the enumeration should continue after the error. + XCTFail(@"Error listing contents of directory %@: %@", url, error); + return NO; +#pragma clang diagnostic pop + }]; + NSArray *extractedURLs = [[enumerator allObjects] + sortedArrayUsingComparator:^NSComparisonResult(NSURL * _Nonnull obj1, NSURL * _Nonnull obj2) { + return [obj1.path compare:obj2.path]; + }]; + + NSArray *expectedFiles = @[ + @"aces-dev-1.0", + @"aces-dev-1.0/CHANGELOG.md", + @"aces-dev-1.0/LICENSE.md", + @"aces-dev-1.0/README.md", + @"aces-dev-1.0/documents", + @"aces-dev-1.0/documents/README.md", + @"aces-dev-1.0/images", + @"aces-dev-1.0/images/README.md", + ]; + + NSUInteger i = 0; + + for (NSURL *extractedURL in extractedURLs) { + NSString *actualPath = extractedURL.path; + NSString *expectedPath = expectedFiles[i++]; + XCTAssertTrue([actualPath hasSuffix:expectedPath], @"Unexpected file extracted: %@", actualPath); + } +} + +#if !TARGET_OS_IPHONE +- (void)testExtractZip64_LargeFile +{ + NSArray *urls = @[ + [self emptyTextFileOfLength:4 * pow(2.0, 30.0)], + self.unicodeFileURLs[@"Test File Ⓐ.txt"] + ]; + + NSError *error = nil; + NSURL *url = [self archiveWithFiles:urls]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:url error:&error]; + + XCTAssertNil(error, @"Failed to init archive"); + + NSString *extractDirectory = [self randomDirectoryWithPrefix:@"LargeZip64"]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&error]; + + XCTAssertTrue(success, @"Extract large Zip64 archive failed"); + XCTAssertNil(error, @"Error extracting large Zip64 archive"); + + NSArray *expectedCRCs = @[ + @([self crcOfFile:urls[0]]), + @([self crcOfFile:urls[1]]) + ]; + + NSArray *actualCRCs = @[ + @([self crcOfFile:[extractURL URLByAppendingPathComponent:urls[0].lastPathComponent]]), + @([self crcOfFile:[extractURL URLByAppendingPathComponent:urls[1].lastPathComponent]]), + ]; + + for (NSUInteger i = 0; i < expectedCRCs.count; i++) { + XCTAssertEqualObjects(expectedCRCs[i], actualCRCs[i], @"CRCs didn't match"); + } +} + +- (void)testExtractZip64_ManyFiles +{ + NSUInteger numberOfFiles = pow(2.0, 16) + 1000; + NSMutableArray *urls = [NSMutableArray arrayWithCapacity:numberOfFiles]; + + for (NSUInteger i = 0; i < numberOfFiles; i++) { + NSURL *smallFileURL = [self emptyTextFileOfLength:1]; + [urls addObject:smallFileURL]; + } + + + NSError *error = nil; + NSURL *url = [self archiveWithFiles:urls]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:url error:&error]; + + XCTAssertNil(error, @"Failed to init archive"); + + NSString *extractDirectory = [self randomDirectoryWithPrefix:@"NumerousZip64"]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&error]; + + XCTAssertTrue(success, @"Extract numerous Zip64 archive failed"); + XCTAssertNil(error, @"Error extracting numerous Zip64 archive"); + + NSArray *extractedFiles = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:extractURL.path + error:&error]; + + XCTAssertNil(error, @"Failed to list extracted files from numerous Zip64 archive"); + XCTAssertEqual(extractedFiles.count, numberOfFiles, @"Incorrect number of files extracted from numerous Zip64 archive"); +} +#endif + + +@end diff --git a/Carthage/Checkouts/UnzipKit/Tests/FileDescriptorUsageTests.m b/Carthage/Checkouts/UnzipKit/Tests/FileDescriptorUsageTests.m new file mode 100644 index 0000000..a824da7 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/FileDescriptorUsageTests.m @@ -0,0 +1,171 @@ +// +// FileDescriptorUsageTests.m +// UnzipKit +// +// Created by Dov Frankel on 7/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "UZKArchiveTestCase.h" +#import "UnzipKit.h" + +@interface FileDescriptorUsageTests : UZKArchiveTestCase +@end + +@implementation FileDescriptorUsageTests + + +#if !TARGET_OS_IPHONE +- (void)testFileDescriptorUsage +{ + NSInteger initialFileCount = [self numberOfOpenFileHandles]; + + NSString *testArchiveName = @"Test Archive.zip"; + NSURL *testArchiveOriginalURL = self.testFileURLs[testArchiveName]; + NSFileManager *fm = [NSFileManager defaultManager]; + + for (NSInteger i = 0; i < 1000; 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 returned"); + + for (NSString *fileName in fileList) { + NSData *fileData = [archive extractDataFromFile:fileName + error:&error]; + XCTAssertNotNil(fileData, @"No data returned"); + XCTAssertNil(error, @"Error extracting data"); + } + } + + NSInteger finalFileCount = [self numberOfOpenFileHandles]; + + XCTAssertEqualWithAccuracy(initialFileCount, finalFileCount, 5, @"File descriptors were left open"); +} + +- (void)testFileDescriptorUsage_ExtractInsidePerformOnFiles +{ + NSInteger initialFileCount = [self numberOfOpenFileHandles]; + + NSString *testArchiveName = @"Test Archive.zip"; + NSURL *testArchiveOriginalURL = self.testFileURLs[testArchiveName]; + NSFileManager *fm = [NSFileManager defaultManager]; + + for (NSInteger i = 0; i < 1000; 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]; + + NSError *performOnFilesError = nil; + BOOL performOnFilesResult = [archive performOnFilesInArchive:^(UZKFileInfo *fileInfo, BOOL *stop) { + NSError *extractError = nil; + NSData *fileData = [archive extractData:fileInfo error:&extractError]; + XCTAssertNotNil(fileData, @"No data extracted"); + XCTAssertNil(extractError, @"Failed to extract file"); + } error:&performOnFilesError]; + XCTAssertTrue(performOnFilesResult, @"Failed to performOnFilesInArchive"); + XCTAssertNil(performOnFilesError, @"Error during performOnFilesInArchive"); + } + NSInteger finalFileCount = [self numberOfOpenFileHandles]; + + XCTAssertEqualWithAccuracy(initialFileCount, finalFileCount, 5, @"File descriptors were left open"); +} + +- (void)testFileDescriptorUsage_WriteIntoArchive +{ + 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; + BOOL writeResult = [archive writeData:newFileData + filePath:fileName + fileDate:[NSDate date] + compressionMethod:UZKCompressionMethodDefault + password:nil + overwrite:YES + 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"); +} +#endif + + +@end diff --git a/Carthage/Checkouts/UnzipKit/Tests/Info.plist b/Carthage/Checkouts/UnzipKit/Tests/Info.plist new file mode 100644 index 0000000..ba72822 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + + diff --git a/Carthage/Checkouts/UnzipKit/Tests/ListFileInfoTests.m b/Carthage/Checkouts/UnzipKit/Tests/ListFileInfoTests.m new file mode 100644 index 0000000..e3fcb7a --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/ListFileInfoTests.m @@ -0,0 +1,182 @@ +// +// ListFileInfoTests.m +// UnzipKit +// +// Created by Dov Frankel on 7/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "UZKArchiveTestCase.h" +#import "UnzipKit.h" + +@interface ListFileInfoTests : UZKArchiveTestCase +@end + +@implementation ListFileInfoTests + + +- (void)testListFileInfo { + UZKArchive *archive = [[UZKArchive alloc] initWithURL:self.testFileURLs[@"Test Archive.zip"] error:nil]; + NSSet *expectedFileSet = self.nonZipTestFilePaths; + NSArray *expectedFiles = [expectedFileSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; + + NSDate *expectedDate = [[UZKArchiveTestCase dateFormatter] dateFromString:@"3/22/2014 11:17 PM"]; + NSDictionary *expectedCompressionMethods = @{@"Test File A.txt": @(UZKCompressionMethodNone), + @"Test File B.jpg": @(UZKCompressionMethodDefault), + @"Test File C.m4a": @(UZKCompressionMethodDefault),}; + + NSError *error = nil; + NSArray *filesInArchive = [archive listFileInfo:&error]; + + XCTAssertNil(error, @"Error returned by listFileInfo"); + XCTAssertNotNil(filesInArchive, @"No list of files returned"); + XCTAssertEqual(filesInArchive.count, expectedFileSet.count, @"Incorrect number of files listed in archive"); + + NSFileManager *fm = [NSFileManager defaultManager]; + + for (NSUInteger i = 0; i < filesInArchive.count; i++) { + UZKFileInfo *fileInfo = filesInArchive[i]; + + // Test Filename + NSString *expectedFilename = expectedFiles[i]; + XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Incorrect filename"); + + // Test CRC + NSUInteger expectedFileCRC = [self crcOfTestFile:expectedFilename]; + XCTAssertEqual(fileInfo.CRC, expectedFileCRC, @"Incorrect CRC checksum"); + + // Test Last Modify Date + NSTimeInterval archiveFileTimeInterval = [fileInfo.timestamp timeIntervalSinceReferenceDate]; + NSTimeInterval expectedFileTimeInterval = [expectedDate timeIntervalSinceReferenceDate]; + XCTAssertEqualWithAccuracy(archiveFileTimeInterval, expectedFileTimeInterval, 60, @"Incorrect file timestamp (more than 60 seconds off)"); + + // Test Uncompressed Size + NSError *attributesError = nil; + NSString *expectedFilePath = [[self urlOfTestFile:expectedFilename] path]; + NSDictionary *expectedFileAttributes = [fm attributesOfItemAtPath:expectedFilePath + error:&attributesError]; + XCTAssertNil(attributesError, @"Error getting file attributes of %@", expectedFilename); + + unsigned long long expectedFileSize = expectedFileAttributes.fileSize; + XCTAssertEqual(fileInfo.uncompressedSize, expectedFileSize, @"Incorrect uncompressed file size"); + + // Test Compression method + UZKCompressionMethod expectedCompressionMethod = ((NSNumber *)expectedCompressionMethods[fileInfo.filename]).integerValue; + XCTAssertEqual(fileInfo.compressionMethod, expectedCompressionMethod, @"Incorrect compression method"); + } +} + +- (void)testListFileInfo_Unicode +{ + NSSet *expectedFileSet = self.nonZipUnicodeFilePaths; + NSArray *expectedFiles = [expectedFileSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; + + NSURL *testArchiveURL = self.unicodeFileURLs[@"Ⓣest Ⓐrchive.zip"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *error = nil; + NSArray *filesInArchive = [archive listFileInfo:&error]; + + XCTAssertNil(error, @"Error returned by listFileInfo"); + XCTAssertNotNil(filesInArchive, @"No list of files returned"); + XCTAssertEqual(filesInArchive.count, expectedFileSet.count, + @"Incorrect number of files listed in archive"); + + for (NSUInteger i = 0; i < filesInArchive.count; i++) { + UZKFileInfo *fileInfo = filesInArchive[i]; + + XCTAssertEqualObjects(fileInfo.filename, expectedFiles[i], @"Incorrect filename listed"); + } +} + +- (void)testListFileInfo_WinZip +{ + NSURL *testArchiveURL = self.testFileURLs[@"L'incertain.zip"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + NSArray *expectedFiles = @[@"Acribor‚a - T01 - L'incertain/Test File A.txt", + @"Acribor‚a - T01 - L'incertain/Test File B.jpg", + @"Acribor‚a - T01 - L'incertain/Test File C.m4a", + @"Acribor‚a - T01 - L'incertain"]; + NSArray *isDirectoryValues = @[@NO, + @NO, + @NO, + @YES]; + + NSError *error = nil; + NSArray *filesInArchive = [archive listFileInfo:&error]; + + XCTAssertNil(error, @"Error returned by listFilenames"); + XCTAssertNotNil(filesInArchive, @"No list of files returned"); + XCTAssertEqual(filesInArchive.count, expectedFiles.count, @"Incorrect number of files listed in archive"); + + for (NSUInteger i = 0; i < filesInArchive.count; i++) { + UZKFileInfo *fileInfo = (UZKFileInfo *)filesInArchive[i]; + + XCTAssertEqualObjects(fileInfo.filename, expectedFiles[i], @"Incorrect filename listed"); + + BOOL expectedIsDirectory = ((NSNumber *)isDirectoryValues[i]).boolValue; + XCTAssertEqual(fileInfo.isDirectory, expectedIsDirectory, @"Incorrect isDirectory value listed"); + } +} + +- (void)testListFileInfo_Password +{ + NSURL *testArchiveURL = self.testFileURLs[@"Test Archive (Password).zip"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL password:@"password" error:nil]; + + NSSet *expectedFileSet = self.nonZipTestFilePaths; + NSArray *expectedFiles = [expectedFileSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; + + NSArray *filesInArchive = nil; + NSError *error = nil; + filesInArchive = [archive listFileInfo:&error]; + + XCTAssertNil(error, @"Error returned by listFilenames"); + XCTAssertEqual(filesInArchive.count, expectedFileSet.count, + @"Incorrect number of files listed in archive"); + + for (NSUInteger i = 0; i < filesInArchive.count; i++) { + UZKFileInfo *fileInfo = filesInArchive[i]; + NSString *expectedFilename = expectedFiles[i]; + + XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Incorrect filename listed"); + } +} + +- (void)testListFileInfo_NoPasswordGiven { + NSURL *testArchiveURL = self.testFileURLs[@"Test Archive (Password).zip"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSSet *expectedFileSet = self.nonZipTestFilePaths; + NSArray *expectedFiles = [expectedFileSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; + + NSArray *filesInArchive = nil; + NSError *error = nil; + filesInArchive = [archive listFileInfo:&error]; + + XCTAssertNil(error, @"Error returned by listFilenames"); + XCTAssertEqual(filesInArchive.count, expectedFileSet.count, + @"Incorrect number of files listed in archive"); + + for (NSUInteger i = 0; i < filesInArchive.count; i++) { + UZKFileInfo *fileInfo = filesInArchive[i]; + NSString *expectedFilename = expectedFiles[i]; + + XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Incorrect filename listed"); + } +} + +- (void)testListFileInfo_InvalidArchive +{ + UZKArchive *archive = [[UZKArchive alloc] initWithURL:self.testFileURLs[@"Test File A.txt"] error:nil]; + + NSError *error = nil; + NSArray *files = [archive listFileInfo:&error]; + + XCTAssertNotNil(error, @"List files of invalid archive succeeded"); + XCTAssertNil(files, @"List returned for invalid archive"); + XCTAssertEqual(error.code, UZKErrorCodeBadZipFile, @"Unexpected error code returned"); +} + + +@end diff --git a/Carthage/Checkouts/UnzipKit/Tests/ListFilenamesTests.m b/Carthage/Checkouts/UnzipKit/Tests/ListFilenamesTests.m new file mode 100644 index 0000000..77eca2b --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/ListFilenamesTests.m @@ -0,0 +1,134 @@ +// +// ListFilenamesTests.m +// UnzipKit +// +// Created by Dov Frankel on 7/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "UZKArchiveTestCase.h" +#import "UnzipKit.h" + +@interface ListFilenamesTests : UZKArchiveTestCase +@end + +@implementation ListFilenamesTests + + +- (void)testListFilenames +{ + NSArray *testArchives = @[@"Test Archive.zip", + @"Test Archive (Password).zip"]; + + NSSet *expectedFileSet = self.nonZipTestFilePaths; + NSArray *expectedFiles = [expectedFileSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; + + for (NSString *testArchiveName in testArchives) { + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *error = nil; + NSArray *filesInArchive = [archive listFilenames:&error]; + + XCTAssertNil(error, @"Error returned by listFilenames"); + XCTAssertNotNil(filesInArchive, @"No list of files returned"); + XCTAssertEqual(filesInArchive.count, expectedFileSet.count, + @"Incorrect number of files listed in archive"); + + for (NSUInteger i = 0; i < filesInArchive.count; i++) { + NSString *archiveFilename = filesInArchive[i]; + NSString *expectedFilename = expectedFiles[i]; + + XCTAssertEqualObjects(archiveFilename, expectedFilename, @"Incorrect filename listed"); + } + } +} + +- (void)testListFilenames_Unicode +{ + NSURL *testArchiveURL = self.unicodeFileURLs[@"Ⓣest Ⓐrchive.zip"]; + NSSet *expectedFileSet = self.nonZipUnicodeFilePaths; + NSArray *expectedFiles = [expectedFileSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *error = nil; + NSArray *filesInArchive = [archive listFilenames:&error]; + + XCTAssertNil(error, @"Error returned by listFilenames"); + XCTAssertNotNil(filesInArchive, @"No list of files returned"); + XCTAssertEqual(filesInArchive.count, expectedFileSet.count, + @"Incorrect number of files listed in archive"); + + for (NSUInteger i = 0; i < filesInArchive.count; i++) { + NSString *archiveFilename = filesInArchive[i]; + NSString *expectedFilename = expectedFiles[i]; + + XCTAssertEqualObjects(archiveFilename, expectedFilename, @"Incorrect filename listed"); + } +} + +- (void)testListFilenames_Password +{ + NSURL *testArchiveURL = self.testFileURLs[@"Test Archive (Password).zip"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL password:@"password" error:nil]; + + NSSet *expectedFileSet = self.nonZipTestFilePaths; + NSArray *expectedFiles = [expectedFileSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; + + NSArray *filesInArchive = nil; + NSError *error = nil; + filesInArchive = [archive listFilenames:&error]; + + XCTAssertNil(error, @"Error returned by listFilenames"); + XCTAssertEqual(filesInArchive.count, expectedFileSet.count, + @"Incorrect number of files listed in archive"); + + for (NSUInteger i = 0; i < filesInArchive.count; i++) { + NSString *archiveFilename = filesInArchive[i]; + NSString *expectedFilename = expectedFiles[i]; + + XCTAssertEqualObjects(archiveFilename, expectedFilename, @"Incorrect filename listed"); + } +} + +- (void)testListFilenames_NoPasswordGiven +{ + NSURL *testArchiveURL = self.testFileURLs[@"Test Archive (Password).zip"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSSet *expectedFileSet = self.nonZipTestFilePaths; + NSArray *expectedFiles = [expectedFileSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; + + NSArray *filesInArchive = nil; + NSError *error = nil; + filesInArchive = [archive listFilenames:&error]; + + XCTAssertNil(error, @"Error returned by listFilenames"); + XCTAssertEqual(filesInArchive.count, expectedFileSet.count, + @"Incorrect number of files listed in archive"); + + for (NSUInteger i = 0; i < filesInArchive.count; i++) { + NSString *archiveFilename = filesInArchive[i]; + NSString *expectedFilename = expectedFiles[i]; + + XCTAssertEqualObjects(archiveFilename, expectedFilename, @"Incorrect filename listed"); + } +} + +- (void)testListFilenames_InvalidArchive +{ + NSURL *testURLA = self.testFileURLs[@"Test File A.txt"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testURLA error:nil]; + + NSError *error = nil; + NSArray *files = [archive listFilenames:&error]; + + XCTAssertNotNil(error, @"List files of invalid archive succeeded"); + XCTAssertNil(files, @"List returned for invalid archive"); + XCTAssertEqual(error.code, UZKErrorCodeBadZipFile, @"Unexpected error code returned"); +} + + +@end diff --git a/Carthage/Checkouts/UnzipKit/Tests/ModesTests.m b/Carthage/Checkouts/UnzipKit/Tests/ModesTests.m new file mode 100644 index 0000000..9d739bc --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/ModesTests.m @@ -0,0 +1,114 @@ +// +// ModesTests.m +// UnzipKit +// +// Created by Dov Frankel on 7/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "UZKArchiveTestCase.h" +#import "UnzipKit.h" + + +@interface ModesTests : UZKArchiveTestCase +@end + +@implementation ModesTests + + +- (void)testModes_WriteWhileReading +{ + NSURL *testArchiveURL = self.testFileURLs[@"Test Archive.zip"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + NSError *readError = nil; + + [archive performOnDataInArchive:^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + NSError *writeError = nil; + [archive writeData:fileData filePath:@"newPath.txt" error:&writeError]; + XCTAssertNotNil(writeError, @"Write operation during a read succeeded"); + XCTAssertEqual(writeError.code, UZKErrorCodeMixedModeAccess, @"Wrong error code returned"); + } error:&readError]; + + XCTAssertNil(readError, @"readError was also non-nil"); +} + +- (void)testModes_NestedReads +{ + NSArray *expectedFiles = [self.nonZipTestFilePaths.allObjects sortedArrayUsingSelector:@selector(compare:)]; + + NSURL *testArchiveURL = self.testFileURLs[@"Test Archive.zip"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSError *performOnFilesError = nil; + __block NSInteger i = 0; + + [archive performOnFilesInArchive:^(UZKFileInfo *fileInfo, BOOL *stop) { + NSString *expectedFilename = expectedFiles[i++]; + + NSError *extractError = nil; + NSData *extractedData = [archive extractDataFromFile:expectedFilename + error:&extractError]; + + XCTAssertNil(extractError, @"Error in extractData:error:"); + + NSData *expectedFileData = [NSData dataWithContentsOfURL:self.testFileURLs[expectedFilename]]; + + XCTAssertNotNil(extractedData, @"No data extracted"); + XCTAssertTrue([expectedFileData isEqualToData:extractedData], @"Extracted data doesn't match original file"); + + extractError = nil; + NSData *dataFromFileInfo = [archive extractData:fileInfo + error:&extractError]; + XCTAssertNil(extractError, @"Error extracting data by file info"); + XCTAssertTrue([expectedFileData isEqualToData:dataFromFileInfo], @"Extracted data from file info doesn't match original file"); + } error:&performOnFilesError]; + + XCTAssertNil(performOnFilesError, @"Error iterating through archive"); +} + +- (void)testModes_ReadWhileWriting +{ + NSURL *testArchiveURL = self.testFileURLs[@"Test Archive.zip"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + NSError *writeError = nil; + + [archive writeIntoBuffer:@"newFile.zip" + error:&writeError + block: + ^BOOL(BOOL(^writeData)(const void *bytes, unsigned int length), NSError**(actionError)) { + NSError *readError = nil; + [archive listFilenames:&readError]; + XCTAssertNotNil(readError, @"Read operation during a read succeeded"); + XCTAssertEqual(readError.code, UZKErrorCodeMixedModeAccess, @"Wrong error code returned"); + + return YES; + }]; + + XCTAssertNil(writeError, @"writeError was also non-nil"); +} + +- (void)testModes_NestedWrites +{ + NSURL *testArchiveURL = self.testFileURLs[@"Test Archive.zip"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + NSError *outerWriteError = nil; + + [archive writeIntoBuffer:@"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"); + XCTAssertEqual(innerWriteError.code, UZKErrorCodeFileWrite, @"Wrong error code returned"); + + return YES; + }]; + + XCTAssertNil(outerWriteError, @"outerWriteError was also non-nil"); +} + + +@end diff --git a/Carthage/Checkouts/UnzipKit/Tests/MultithreadingTests.m b/Carthage/Checkouts/UnzipKit/Tests/MultithreadingTests.m new file mode 100644 index 0000000..8e11988 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/MultithreadingTests.m @@ -0,0 +1,191 @@ +// +// MultithreadingTests.m +// UnzipKit +// +// Created by Dov Frankel on 7/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "UZKArchiveTestCase.h" +#import "UnzipKit.h" +#import "UnzipKitMacros.h" + +@interface MultithreadingTests : UZKArchiveTestCase +@end + +@implementation MultithreadingTests + + +#if !TARGET_OS_IPHONE +- (void)testMultithreading { + UZKArchive *largeArchiveA = [[UZKArchive alloc] initWithURL:[self largeArchive] error:nil]; + UZKArchive *largeArchiveB = [[UZKArchive alloc] initWithURL:[self largeArchive] error:nil]; + UZKArchive *largeArchiveC = [[UZKArchive alloc] initWithURL:[self largeArchive] error:nil]; + + XCTestExpectation *expectationA = [self expectationWithDescription:@"A finished"]; + XCTestExpectation *expectationB = [self expectationWithDescription:@"B finished"]; + XCTestExpectation *expectationC = [self expectationWithDescription:@"C finished"]; + + NSBlockOperation *enumerateA = [NSBlockOperation blockOperationWithBlock:^{ + NSError *error = nil; + [largeArchiveA performOnDataInArchive:^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + UZKLogInfo("File name: %@", fileInfo.filename); + } error:&error]; + + XCTAssertNil(error, @"Failed enumeration A"); + [expectationA fulfill]; + }]; + + NSBlockOperation *enumerateB = [NSBlockOperation blockOperationWithBlock:^{ + NSError *error = nil; + [largeArchiveB performOnDataInArchive:^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + UZKLogInfo("File name: %@", fileInfo.filename); + } error:&error]; + + XCTAssertNil(error, @"Failed enumeration B"); + [expectationB fulfill]; + }]; + + NSBlockOperation *enumerateC = [NSBlockOperation blockOperationWithBlock:^{ + NSError *error = nil; + [largeArchiveC performOnDataInArchive:^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + UZKLogInfo("File name: %@", fileInfo.filename); + } error:&error]; + + XCTAssertNil(error, @"Failed enumeration C"); + [expectationC fulfill]; + }]; + + NSOperationQueue *queue = [[NSOperationQueue alloc] init]; + queue.maxConcurrentOperationCount = 3; + queue.suspended = YES; + + [queue addOperation:enumerateA]; + [queue addOperation:enumerateB]; + [queue addOperation:enumerateC]; + + queue.suspended = NO; + + [self waitForExpectationsWithTimeout:30 handler:^(NSError *error) { + if (error) { + UZKLogError("Error while waiting for expectations: %@", error); + } + }]; +} + +- (void)testMultithreading_SingleFile { + NSURL *largeArchiveURL = [self largeArchive]; + + UZKArchive *largeArchiveA = [[UZKArchive alloc] initWithURL:largeArchiveURL error:nil]; + UZKArchive *largeArchiveB = [[UZKArchive alloc] initWithURL:largeArchiveURL error:nil]; + UZKArchive *largeArchiveC = [[UZKArchive alloc] initWithURL:largeArchiveURL error:nil]; + + XCTestExpectation *expectationA = [self expectationWithDescription:@"A finished"]; + XCTestExpectation *expectationB = [self expectationWithDescription:@"B finished"]; + XCTestExpectation *expectationC = [self expectationWithDescription:@"C finished"]; + + NSBlockOperation *enumerateA = [NSBlockOperation blockOperationWithBlock:^{ + NSError *error = nil; + [largeArchiveA performOnDataInArchive:^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + UZKLogInfo("File name: %@", fileInfo.filename); + } error:&error]; + + XCTAssertNil(error, @"Failed enumeration A"); + [expectationA fulfill]; + }]; + + NSBlockOperation *enumerateB = [NSBlockOperation blockOperationWithBlock:^{ + NSError *error = nil; + [largeArchiveB performOnDataInArchive:^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + UZKLogInfo("File name: %@", fileInfo.filename); + } error:&error]; + + XCTAssertNil(error, @"Failed enumeration B"); + [expectationB fulfill]; + }]; + + NSBlockOperation *enumerateC = [NSBlockOperation blockOperationWithBlock:^{ + NSError *error = nil; + [largeArchiveC performOnDataInArchive:^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + UZKLogInfo("File name: %@", fileInfo.filename); + } error:&error]; + + XCTAssertNil(error, @"Failed enumeration C"); + [expectationC fulfill]; + }]; + + NSOperationQueue *queue = [[NSOperationQueue alloc] init]; + queue.maxConcurrentOperationCount = 3; + queue.suspended = YES; + + [queue addOperation:enumerateA]; + [queue addOperation:enumerateB]; + [queue addOperation:enumerateC]; + + queue.suspended = NO; + + [self waitForExpectationsWithTimeout:30 handler:^(NSError *error) { + if (error) { + UZKLogError("Error while waiting for expectations: %@", error); + } + }]; +} + +- (void)testMultithreading_SingleArchiveObject { + + UZKArchive *largeArchive = [[UZKArchive alloc] initWithURL:[self largeArchive] error:nil]; + + XCTestExpectation *expectationA = [self expectationWithDescription:@"A finished"]; + XCTestExpectation *expectationB = [self expectationWithDescription:@"B finished"]; + XCTestExpectation *expectationC = [self expectationWithDescription:@"C finished"]; + + NSBlockOperation *enumerateA = [NSBlockOperation blockOperationWithBlock:^{ + NSError *error = nil; + [largeArchive performOnDataInArchive:^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + UZKLogInfo("File name: %@", fileInfo.filename); + } error:&error]; + + XCTAssertNil(error, @"Failed enumeration A"); + [expectationA fulfill]; + }]; + + NSBlockOperation *enumerateB = [NSBlockOperation blockOperationWithBlock:^{ + NSError *error = nil; + [largeArchive performOnDataInArchive:^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + UZKLogInfo("File name: %@", fileInfo.filename); + } error:&error]; + + XCTAssertNil(error, @"Failed enumeration B"); + [expectationB fulfill]; + }]; + + NSBlockOperation *enumerateC = [NSBlockOperation blockOperationWithBlock:^{ + NSError *error = nil; + [largeArchive performOnDataInArchive:^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + UZKLogInfo("File name: %@", fileInfo.filename); + } error:&error]; + + XCTAssertNil(error, @"Failed enumeration C"); + [expectationC fulfill]; + }]; + + NSOperationQueue *queue = [[NSOperationQueue alloc] init]; + queue.maxConcurrentOperationCount = 3; + queue.suspended = YES; + + [queue addOperation:enumerateA]; + [queue addOperation:enumerateB]; + [queue addOperation:enumerateC]; + + queue.suspended = NO; + + [self waitForExpectationsWithTimeout:30 handler:^(NSError *error) { + if (error) { + UZKLogError("Error while waiting for expectations: %@", error); + } + }]; +} +#endif + + +@end diff --git a/Carthage/Checkouts/UnzipKit/Tests/PasswordProtectionTests.m b/Carthage/Checkouts/UnzipKit/Tests/PasswordProtectionTests.m new file mode 100644 index 0000000..e942d98 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/PasswordProtectionTests.m @@ -0,0 +1,128 @@ +// +// PasswordProtectionTests.m +// UnzipKit +// +// Created by Dov Frankel on 7/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "UZKArchiveTestCase.h" +#import "UnzipKit.h" + +@interface PasswordProtectionTests : UZKArchiveTestCase +@end + +@implementation PasswordProtectionTests + + + +#pragma mark - Is Password-Protected + + +- (void)testIsPasswordProtected_PasswordRequired_AllFiles +{ + NSURL *archiveURL = self.testFileURLs[@"Test Archive (Password).zip"]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:archiveURL error:nil]; + + XCTAssertTrue(archive.isPasswordProtected, @"isPasswordProtected = NO for password-protected archive"); +} + +- (void)testIsPasswordProtected_PasswordRequired_LastFileOnly +{ + 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"; + } + + BOOL result = [writeArchive writeData:fileData + filePath:testFile + fileDate:nil + compressionMethod:UZKCompressionMethodDefault + password:password + 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_PasswordNotRequired +{ + NSURL *archiveURL = self.testFileURLs[@"Test Archive.zip"]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:archiveURL error:nil]; + + XCTAssertFalse(archive.isPasswordProtected, @"isPasswordProtected = YES for password-protected archive"); +} + + + +#pragma mark - Validate Password + + +- (void)testValidatePassword_PasswordRequired +{ + NSURL *archiveURL = self.testFileURLs[@"Test Archive (Password).zip"]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:archiveURL error:nil]; + + XCTAssertFalse(archive.validatePassword, @"validatePassword = YES when no password supplied"); + + archive.password = @"wrong"; + XCTAssertFalse(archive.validatePassword, @"validatePassword = YES when wrong password supplied"); + + archive.password = @"password"; + XCTAssertTrue(archive.validatePassword, @"validatePassword = NO when correct password supplied"); +} + +- (void)testValidatePassword_PasswordNotRequired +{ + NSURL *archiveURL = self.testFileURLs[@"Test Archive.zip"]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:archiveURL error:nil]; + + XCTAssertTrue(archive.validatePassword, @"validatePassword = NO when no password supplied"); + + archive.password = @"password"; + XCTAssertTrue(archive.validatePassword, @"validatePassword = NO when password supplied"); +} + +#if !TARGET_OS_IPHONE +- (void)testValidatePassword_LargeFile +{ + NSString *password = @"12345-luggage"; + + NSArray *urls = @[[self emptyTextFileOfLength:400000]]; + NSURL *archiveURL = [self archiveWithFiles:urls password:password]; + + NSError *error = nil; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:archiveURL error:&error]; + + XCTAssertNotNil(archive, @"Archive not initialized"); + XCTAssertNil(error, @"Error initializing archive: %@", error); + + BOOL passwordValidated = [archive validatePassword]; + XCTAssertFalse(passwordValidated, @"Expected password to be reported as incorrect"); +} +#endif + +@end diff --git a/Carthage/Checkouts/UnzipKit/Tests/PerformOnDataTests.m b/Carthage/Checkouts/UnzipKit/Tests/PerformOnDataTests.m new file mode 100644 index 0000000..c631458 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/PerformOnDataTests.m @@ -0,0 +1,191 @@ +// +// PerformOnDataTests.m +// UnzipKit +// +// Created by Dov Frankel on 7/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "UZKArchiveTestCase.h" +#import "UnzipKit.h" + +@interface PerformOnDataTests : UZKArchiveTestCase +@end + +@implementation PerformOnDataTests + + +- (void)testPerformOnData +{ + NSArray *testArchives = @[@"Test Archive.zip", + @"Test Archive (Password).zip"]; + + NSSet *expectedFileSet = self.nonZipTestFilePaths; + NSArray *expectedFiles = [expectedFileSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; + + for (NSString *testArchiveName in testArchives) { + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *password = ([testArchiveName rangeOfString:@"Password"].location != NSNotFound + ? @"password" + : nil); + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL password:password error:nil]; + + __block NSUInteger fileIndex = 0; + NSError *error = nil; + + [archive performOnDataInArchive: + ^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + NSString *expectedFilename = expectedFiles[fileIndex++]; + XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Unexpected filename encountered"); + + NSData *expectedFileData = [NSData dataWithContentsOfURL:self.testFileURLs[expectedFilename]]; + + XCTAssertNotNil(fileData, @"No data extracted"); + XCTAssertTrue([expectedFileData isEqualToData:fileData], @"File data doesn't match original file"); + } error:&error]; + + XCTAssertNil(error, @"Error iterating through files"); + XCTAssertEqual(fileIndex, expectedFiles.count, @"Incorrect number of files encountered"); + } +} + +- (void)testPerformOnData_Unicode +{ + NSSet *expectedFileSet = self.nonZipUnicodeFilePaths; + NSArray *expectedFiles = [expectedFileSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; + + NSURL *testArchiveURL = self.unicodeFileURLs[@"Ⓣest Ⓐrchive.zip"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + __block NSUInteger fileIndex = 0; + NSError *error = nil; + + [archive performOnDataInArchive: + ^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + NSString *expectedFilename = expectedFiles[fileIndex++]; + XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Unexpected filename encountered"); + + NSData *expectedFileData = [NSData dataWithContentsOfURL:self.unicodeFileURLs[expectedFilename]]; + + XCTAssertNotNil(fileData, @"No data extracted"); + XCTAssertTrue([expectedFileData isEqualToData:fileData], @"File data doesn't match original file"); + } error:&error]; + + XCTAssertNil(error, @"Error iterating through files"); + XCTAssertEqual(fileIndex, expectedFiles.count, @"Incorrect number of files encountered"); +} + +#if !TARGET_OS_IPHONE +- (void)testPerformOnData_FileMoved +{ + NSURL *largeArchiveURL = [self largeArchive]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:largeArchiveURL error:nil]; + + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); + + NSURL *movedURL = [largeArchiveURL URLByAppendingPathExtension:@"unittest"]; + + NSError *renameError = nil; + NSFileManager *fm = [NSFileManager defaultManager]; + [fm moveItemAtURL:largeArchiveURL toURL:movedURL error:&renameError]; + XCTAssertNil(renameError, @"Error renaming file: %@", renameError); + }); + + __block NSUInteger fileCount = 0; + NSUInteger totalFileCount = 5; + + NSError *error = nil; + BOOL success = [archive performOnDataInArchive:^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + XCTAssertNotNil(fileData, @"Extracted file is nil: %@", fileInfo.filename); + + if (!fileInfo.isDirectory) { + fileCount++; + XCTAssertGreaterThan(fileData.length, (NSUInteger)0, @"Extracted file is empty: %@", fileInfo.filename); + } + + if (fileCount == 2) { + dispatch_semaphore_signal(sema); + } + } error:&error]; + + XCTAssertEqual(fileCount, totalFileCount, @"Not all files read"); + XCTAssertTrue(success, @"Failed to read files"); + XCTAssertNil(error, @"Error reading files: %@", error); +} + +- (void)testPerformOnData_FileDeleted +{ + NSURL *largeArchiveURL = [self largeArchive]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:largeArchiveURL error:nil]; + + dispatch_semaphore_t sema = dispatch_semaphore_create(0); + + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER); + + NSError *removeError = nil; + NSFileManager *fm = [NSFileManager defaultManager]; + [fm removeItemAtURL:largeArchiveURL error:&removeError]; + XCTAssertNil(removeError, @"Error removing file: %@", removeError); + }); + + __block NSUInteger fileCount = 0; + NSUInteger totalFileCount = 5; + + NSError *error = nil; + BOOL success = [archive performOnDataInArchive:^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + XCTAssertNotNil(fileData, @"Extracted file is nil: %@", fileInfo.filename); + + if (!fileInfo.isDirectory) { + fileCount++; + XCTAssertGreaterThan(fileData.length, (NSUInteger)0, @"Extracted file is empty: %@", fileInfo.filename); + } + + if (fileCount == 2) { + dispatch_semaphore_signal(sema); + } + } error:&error]; + + XCTAssertEqual(fileCount, totalFileCount, @"Not all files read"); + XCTAssertTrue(success, @"Failed to read files"); + XCTAssertNil(error, @"Error reading files: %@", error); +} + +- (void)testPerformOnData_FileMovedBeforeBegin +{ + NSURL *largeArchiveURL = [self largeArchive]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:largeArchiveURL error:nil]; + + NSURL *movedURL = [largeArchiveURL URLByAppendingPathExtension:@"unittest"]; + + NSError *renameError = nil; + NSFileManager *fm = [NSFileManager defaultManager]; + [fm moveItemAtURL:largeArchiveURL toURL:movedURL error:&renameError]; + XCTAssertNil(renameError, @"Error renaming file: %@", renameError); + + __block NSUInteger fileCount = 0; + + NSError *error = nil; + BOOL success = [archive performOnDataInArchive:^(UZKFileInfo *fileInfo, NSData *fileData, BOOL *stop) { + XCTAssertNotNil(fileData, @"Extracted file is nil: %@", fileInfo.filename); + + if (!fileInfo.isDirectory) { + fileCount++; + XCTAssertGreaterThan(fileData.length, (NSUInteger)0, @"Extracted file is empty: %@", fileInfo.filename); + } + } error:&error]; + + XCTAssertEqual(fileCount, (NSUInteger)5, @"Not all files read"); + XCTAssertTrue(success, @"Failed to read files"); + XCTAssertNil(error, @"Error reading files: %@", error); +} +#endif + + +@end diff --git a/Carthage/Checkouts/UnzipKit/Tests/PerformOnFilesTests.m b/Carthage/Checkouts/UnzipKit/Tests/PerformOnFilesTests.m new file mode 100644 index 0000000..d07da3c --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/PerformOnFilesTests.m @@ -0,0 +1,69 @@ +// +// PerformOnFilesTests.m +// UnzipKit +// +// Created by Dov Frankel on 7/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "UZKArchiveTestCase.h" +#import "UnzipKit.h" + +@interface PerformOnFilesTests : UZKArchiveTestCase +@end + +@implementation PerformOnFilesTests + + +- (void)testPerformOnFiles +{ + NSArray *testArchives = @[@"Test Archive.zip", + @"Test Archive (Password).zip"]; + + NSSet *expectedFileSet = self.nonZipTestFilePaths; + NSArray *expectedFiles = [expectedFileSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; + + for (NSString *testArchiveName in testArchives) { + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *password = ([testArchiveName rangeOfString:@"Password"].location != NSNotFound + ? @"password" + : nil); + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL password:password error:nil]; + + __block NSUInteger fileIndex = 0; + NSError *error = nil; + + [archive performOnFilesInArchive: + ^(UZKFileInfo *fileInfo, BOOL *stop) { + NSString *expectedFilename = expectedFiles[fileIndex++]; + XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Unexpected filename encountered"); + } error:&error]; + + XCTAssertNil(error, @"Error iterating through files"); + XCTAssertEqual(fileIndex, expectedFiles.count, @"Incorrect number of files encountered"); + } +} + +- (void)testPerformOnFiles_Unicode +{ + NSSet *expectedFileSet = self.nonZipUnicodeFilePaths; + NSArray *expectedFiles = [expectedFileSet.allObjects sortedArrayUsingSelector:@selector(compare:)]; + + NSURL *testArchiveURL = self.unicodeFileURLs[@"Ⓣest Ⓐrchive.zip"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + __block NSUInteger fileIndex = 0; + NSError *error = nil; + + [archive performOnFilesInArchive: + ^(UZKFileInfo *fileInfo, BOOL *stop) { + NSString *expectedFilename = expectedFiles[fileIndex++]; + XCTAssertEqualObjects(fileInfo.filename, expectedFilename, @"Unexpected filename encountered"); + } error:&error]; + + XCTAssertNil(error, @"Error iterating through files"); + XCTAssertEqual(fileIndex, expectedFiles.count, @"Incorrect number of files encountered"); +} + + +@end diff --git a/Carthage/Checkouts/UnzipKit/Tests/PermissionsTests.swift b/Carthage/Checkouts/UnzipKit/Tests/PermissionsTests.swift new file mode 100644 index 0000000..7910068 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/PermissionsTests.swift @@ -0,0 +1,183 @@ +// +// PermissionsTests.swift +// UnzipKitTests +// +// Created by Dov Frankel on 6/24/19. +// Copyright © 2019 Abbey Code. All rights reserved. +// + +import XCTest + +class PermissionsTests: UZKArchiveTestCase { + + #if os(OSX) + func testReadFileInfo() { + let permissionLevelsToTest: [Int16] = [ + 0o777, + 0o707, + 0o770, + 0o477, + 0o666, + 0o606, + 0o660, + 0o466, + ] + + let fileURLs: [URL] = permissionLevelsToTest.map { + let textFile = self.emptyTextFile(ofLength: 20)! + try! FileManager.default.setAttributes([.posixPermissions: $0], + ofItemAtPath: textFile.path) + return textFile + } + + let archiveURL = self.archive(withFiles: fileURLs)! + let archive = try! UZKArchive(url: archiveURL) + + let fileInfo = try! archive.listFileInfo() + + let expectedPermissions = zip( + fileURLs.map { $0.lastPathComponent }, + permissionLevelsToTest + ) + .reduce(into: [String:Int16]()) { result, pair in + result[pair.0] = pair.1 + } + let actualPermissions = fileInfo.reduce([String: Int16]()) { + var resultDict = $0 + resultDict[$1.filename] = $1.posixPermissions + return resultDict + } + + XCTAssertEqual(actualPermissions, expectedPermissions) + } + + func testExtraction() { + let permissionLevelsToTest: [Int16] = [ + 0o777, + 0o707, + 0o770, + 0o477, + 0o666, + 0o606, + 0o660, + 0o466, + ] + + let fileURLs: [URL] = permissionLevelsToTest.map { + let textFile = self.emptyTextFile(ofLength: 20)! + try! FileManager.default.setAttributes([.posixPermissions: $0], + ofItemAtPath: textFile.path) + return textFile + } + + let archiveURL = self.archive(withFiles: fileURLs)! + let archive = try! UZKArchive(url: archiveURL) + + let extractDirectory = self.randomDirectory(withPrefix: "PermissionsTest")! + let extractURL = self.tempDirectory.appendingPathComponent(extractDirectory) + + try! archive.extractFiles(to: extractURL.path, overwrite: false) + NSLog("Extracted to \(extractURL.path)") + + let expectedPermissions = zip( + fileURLs.map { extractURL.appendingPathComponent($0.lastPathComponent).path }, + permissionLevelsToTest + ) + + for (path, expectedPermissionLevel) in expectedPermissions { + let actualPermissions = try! FileManager.default.attributesOfItem(atPath: path)[.posixPermissions] as! NSNumber + XCTAssertEqual(actualPermissions.int16Value, expectedPermissionLevel, "Permissions mismatch for \(path)") + } + } + #endif + + func testWriteData_Default() { + let testArchiveURL = tempDirectory.appendingPathComponent("PermissionsTestWriteData.zip") + let testFilename = nonZipTestFilePaths.first as! String + let testFileURL = testFileURLs[testFilename] as! URL + let testFileData = try! Data(contentsOf: testFileURL) + + let writeArchive = try! UZKArchive(url: testArchiveURL) + + try! writeArchive.write(testFileData, filePath: testFilename) + + let readArchive = try! UZKArchive(url: testArchiveURL) + let fileList = try! readArchive.listFileInfo() + + let writtenFileInfo = fileList.first { $0.filename == testFilename } + let actualPermissions = writtenFileInfo!.posixPermissions + + XCTAssertEqual(actualPermissions, 0o644) + } + + func testWriteData_NonDefault() { + let testArchiveURL = tempDirectory.appendingPathComponent("PermissionsTestWriteData.zip") + let testFilename = nonZipTestFilePaths.first as! String + let testFileURL = testFileURLs[testFilename] as! URL + let testFileData = try! Data(contentsOf: testFileURL) + + let writeArchive = try! UZKArchive(url: testArchiveURL) + + let expectedPermissions: Int16 = 0o742 + + try! writeArchive.write(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 as! String + let testFileURL = testFileURLs[testFilename] as! URL + let testFileData = try! Data(contentsOf: testFileURL) + + let writeArchive = try! UZKArchive(url: testArchiveURL) + try! writeArchive.write(intoBuffer: testFilename) { (writeDataHandler, error) in + testFileData.withUnsafeBytes({ buffer in + 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, 0o644) + } + + func testWriteIntoBuffer_NonDefault() { + let testArchiveURL = tempDirectory.appendingPathComponent("PermissionsTestWriteBufferedData_CustomPermissions.zip") + let testFilename = nonZipTestFilePaths.first as! String + let testFileURL = testFileURLs[testFilename] as! URL + let testFileData = try! Data(contentsOf: testFileURL) + + 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) + { (writeDataHandler, error) in + testFileData.withUnsafeBytes({ buffer in + 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) + } + +} diff --git a/Carthage/Checkouts/UnzipKit/Tests/ProgressReportingTests.m b/Carthage/Checkouts/UnzipKit/Tests/ProgressReportingTests.m new file mode 100644 index 0000000..7db7a28 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/ProgressReportingTests.m @@ -0,0 +1,593 @@ +// +// ProgressReportingTests.m +// UnzipKit +// +// Created by Dov Frankel on 10/7/17. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "UZKArchiveTestCase.h" +#import "UnzipKit.h" +#import "UnzipKitMacros.h" + +@interface ProgressReportingTests : UZKArchiveTestCase + +@property (retain) NSMutableArray *fractionsCompletedReported; +@property (retain) NSMutableArray *descriptionsReported; +@property (retain) NSMutableArray *additionalDescriptionsReported; +@property (retain) NSMutableArray *fileInfosReported; + +@end + +static void *ExtractFilesContext = &ExtractFilesContext; +static void *OtherContext = &OtherContext; +static void *CancelContext = &CancelContext; + +static NSUInteger observerCallCount; + + +@implementation ProgressReportingTests + +- (void)setUp { + [super setUp]; + + self.fractionsCompletedReported = [NSMutableArray array]; + self.descriptionsReported = [NSMutableArray array]; + self.additionalDescriptionsReported = [NSMutableArray array]; + self.fileInfosReported = [NSMutableArray array]; + + observerCallCount = 0; +} + +- (void)testProgressReporting_ExtractFiles_FractionCompleted +{ + NSString *testArchiveName = @"Test Archive.zip"; + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *extractDirectory = [self randomDirectoryWithPrefix: + [testArchiveName stringByDeletingPathExtension]]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSProgress *extractFilesProgress = [NSProgress progressWithTotalUnitCount:1]; + [extractFilesProgress becomeCurrentWithPendingUnitCount:1]; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [extractFilesProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:ExtractFilesContext]; + + NSError *extractError = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&extractError]; + + XCTAssertNil(extractError, @"Error returned by extractFilesTo:overwrite:progress:error:"); + XCTAssertTrue(success, @"Archive failed to extract %@ to %@", testArchiveName, extractURL); + + [extractFilesProgress resignCurrent]; + [extractFilesProgress removeObserver:self forKeyPath:observedSelector]; + + XCTAssertEqualWithAccuracy(extractFilesProgress.fractionCompleted, 1.00, .0000000001, @"Progress never reported as completed"); + + NSUInteger expectedProgressUpdates = 4; + NSArray *expectedProgresses = @[@0, + @0.000315, + @0.533568, + @1.0]; + + XCTAssertEqual(self.fractionsCompletedReported.count, expectedProgressUpdates, @"Incorrect number of progress updates"); + for (NSUInteger i = 0; i < expectedProgressUpdates; i++) { + float expectedProgress = expectedProgresses[i].floatValue; + float actualProgress = self.fractionsCompletedReported[i].floatValue; + + XCTAssertEqualWithAccuracy(actualProgress, expectedProgress, 0.00001f, @"Incorrect progress reported at index %ld", (long)i); + } +} + +- (void)testProgressReporting_ExtractFiles_Description +{ + NSString *testArchiveName = @"Test Archive.zip"; + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *extractDirectory = [self randomDirectoryWithPrefix: + [testArchiveName stringByDeletingPathExtension]]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSProgress *extractFilesProgress = [NSProgress progressWithTotalUnitCount:1]; + archive.progress = extractFilesProgress; + + NSString *observedSelector = NSStringFromSelector(@selector(localizedDescription)); + + [self.descriptionsReported removeAllObjects]; + [extractFilesProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:ExtractFilesContext]; + + NSError *extractError = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&extractError]; + + XCTAssertNil(extractError, @"Error returned by extractFilesTo:overwrite:error:"); + XCTAssertTrue(success, @"Archive failed to extract %@ to %@", testArchiveName, extractURL); + + [extractFilesProgress removeObserver:self forKeyPath:observedSelector]; + + NSArray*expectedDescriptions = @[@"Processing “Test File A.txt”…", + @"Processing “Test File B.jpg”…", + @"Processing “Test File C.m4a”…"]; + + for (NSString *expectedDescription in expectedDescriptions) { + BOOL descriptionFound = [self.descriptionsReported containsObject:expectedDescription]; + XCTAssertTrue(descriptionFound, @"Expected progress updates to contain '%@', but they didn't", expectedDescription); + } +} + +- (void)testProgressReporting_ExtractFiles_AdditionalDescription +{ + NSString *testArchiveName = @"Test Archive.zip"; + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *extractDirectory = [self randomDirectoryWithPrefix: + [testArchiveName stringByDeletingPathExtension]]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSProgress *extractFilesProgress = [NSProgress progressWithTotalUnitCount:1]; + archive.progress = extractFilesProgress; + + NSString *observedSelector = NSStringFromSelector(@selector(localizedAdditionalDescription)); + + [extractFilesProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:ExtractFilesContext]; + + NSError *extractError = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&extractError]; + + XCTAssertNil(extractError, @"Error returned by extractFilesTo:overwrite:error:"); + XCTAssertTrue(success, @"Archive failed to extract %@ to %@", testArchiveName, extractURL); + + [extractFilesProgress removeObserver:self forKeyPath:observedSelector]; + + NSArray*expectedAdditionalDescriptions = @[@"Zero KB of 105 KB", + @"33 bytes of 105 KB", + @"56 KB of 105 KB", + @"105 KB of 105 KB"]; + + for (NSString *expectedDescription in expectedAdditionalDescriptions) { + BOOL descriptionFound = [self.additionalDescriptionsReported containsObject:expectedDescription]; + XCTAssertTrue(descriptionFound, @"Expected progress updates to contain '%@', but they didn't", expectedDescription); + } +} + +- (void)testProgressReporting_ExtractFiles_FileInfo +{ + NSString *testArchiveName = @"Test Archive.zip"; + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *extractDirectory = [self randomDirectoryWithPrefix: + [testArchiveName stringByDeletingPathExtension]]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSProgress *extractFilesProgress = [NSProgress progressWithTotalUnitCount:1]; + archive.progress = extractFilesProgress; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [extractFilesProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:ExtractFilesContext]; + + NSError *extractError = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&extractError]; + + XCTAssertNil(extractError, @"Error returned by extractFilesTo:overwrite:error:"); + XCTAssertTrue(success, @"Archive failed to extract %@ to %@", testArchiveName, extractURL); + + [extractFilesProgress removeObserver:self forKeyPath:observedSelector]; + + NSUInteger expectedFileInfos = 3; + NSArray *expectedFileNames = @[@"Test File A.txt", + @"Test File B.jpg", + @"Test File C.m4a"]; + + NSArray *actualFilenames = [self.fileInfosReported valueForKeyPath:NSStringFromSelector(@selector(filename))]; + + XCTAssertEqual(self.fileInfosReported.count, expectedFileInfos, @"Incorrect number of progress updates"); + XCTAssertTrue([expectedFileNames isEqualToArray:actualFilenames], @"Incorrect filenames returned: %@", actualFilenames); +} + +- (void)testProgressReporting_PerformOnFiles { + NSString *testArchiveName = @"Test Archive.zip"; + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSProgress *performProgress = [NSProgress progressWithTotalUnitCount:1]; + [performProgress becomeCurrentWithPendingUnitCount:1]; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [performProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:OtherContext]; + + NSError *performError = nil; + BOOL success = [archive performOnFilesInArchive:^(UZKFileInfo * _Nonnull fileInfo, BOOL * _Nonnull stop) {} + error:&performError]; + + XCTAssertNil(performError, @"Error returned by performOnFilesInArchive:error:"); + XCTAssertTrue(success, @"Archive failed to perform operation on files of archive"); + + [performProgress resignCurrent]; + [performProgress removeObserver:self forKeyPath:observedSelector]; + + XCTAssertEqualWithAccuracy(performProgress.fractionCompleted, 1.00, 0.000001, @"Progress never reported as completed"); + + NSUInteger expectedProgressUpdates = 4; + NSArray *expectedProgresses = @[@0, + @0.333333, + @0.666666, + @1.0]; + + XCTAssertEqual(self.fractionsCompletedReported.count, expectedProgressUpdates, @"Incorrect number of progress updates"); + for (NSUInteger i = 0; i < expectedProgressUpdates; i++) { + float expectedProgress = expectedProgresses[i].floatValue; + float actualProgress = self.fractionsCompletedReported[i].floatValue; + + XCTAssertEqualWithAccuracy(actualProgress, expectedProgress, 0.000001f, @"Incorrect progress reported at index %ld", (long)i); + } +} + +- (void)testProgressReporting_PerformOnData { + NSString *testArchiveName = @"Test Archive.zip"; + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSProgress *performProgress = [NSProgress progressWithTotalUnitCount:1]; + [performProgress becomeCurrentWithPendingUnitCount:1]; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [performProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:OtherContext]; + + NSError *performError = nil; + BOOL success = [archive performOnDataInArchive: + ^(UZKFileInfo * _Nonnull fileInfo, NSData * _Nonnull fileData, BOOL * _Nonnull stop) {} + error:&performError]; + + XCTAssertNil(performError, @"Error returned by performOnDataInArchive:error:"); + XCTAssertTrue(success, @"Archive failed to perform operation on data of archive"); + + [performProgress resignCurrent]; + [performProgress removeObserver:self forKeyPath:observedSelector]; + + XCTAssertEqualWithAccuracy(performProgress.fractionCompleted, 1.00, 0.000001, @"Progress never reported as completed"); + + NSUInteger expectedProgressUpdates = 4; + NSArray *expectedProgresses = @[@0, + @0.333333, + @0.666666, + @1.0]; + + XCTAssertEqual(self.fractionsCompletedReported.count, expectedProgressUpdates, @"Incorrect number of progress updates"); + for (NSUInteger i = 0; i < expectedProgressUpdates; i++) { + float expectedProgress = expectedProgresses[i].floatValue; + float actualProgress = self.fractionsCompletedReported[i].floatValue; + + XCTAssertEqualWithAccuracy(actualProgress, expectedProgress, 0.000001f, @"Incorrect progress reported at index %ld", (long)i); + } +} + +- (void)testProgressCancellation_ExtractFiles { + NSString *testArchiveName = @"Test Archive.zip"; + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + NSString *extractDirectory = [self randomDirectoryWithPrefix: + [testArchiveName stringByDeletingPathExtension]]; + NSURL *extractURL = [self.tempDirectory URLByAppendingPathComponent:extractDirectory]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSProgress *extractFilesProgress = [NSProgress progressWithTotalUnitCount:1]; + [extractFilesProgress becomeCurrentWithPendingUnitCount:1]; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [extractFilesProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:CancelContext]; + + NSError *extractError = nil; + BOOL success = [archive extractFilesTo:extractURL.path + overwrite:NO + error:&extractError]; + + XCTAssertNotNil(extractError, @"Error not returned by extractFilesTo:overwrite:error:"); + XCTAssertEqual(extractError.code, UZKErrorCodeUserCancelled, @"Incorrect error code returned from user cancellation"); + XCTAssertFalse(success, @"Archive didn't cancel extraction"); + + [extractFilesProgress resignCurrent]; + [extractFilesProgress removeObserver:self forKeyPath:observedSelector]; + + + NSUInteger expectedProgressUpdates = 2; + XCTAssertEqual(self.fractionsCompletedReported.count, expectedProgressUpdates, @"Incorrect number of progress updates"); + + NSError *listContentsError = nil; + NSFileManager *fm = [NSFileManager defaultManager]; + NSArray *extractedFiles = [fm contentsOfDirectoryAtPath:extractURL.path + error:&listContentsError]; + + XCTAssertNil(listContentsError, @"Error listing contents of extraction directory"); + XCTAssertEqual(extractedFiles.count, (unsigned long)1, @"Cancellation didn't occur in as timely a fashion as expected"); +} + +- (void)testProgressReporting_WriteData { + NSURL *testArchiveURL = [self.tempDirectory URLByAppendingPathComponent:@"WriteData.zip"]; + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + +// NSSortDescriptor *sort = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES]; +// NSArray *nonZipFiles = [self.nonZipTestFilePaths sortedArrayUsingDescriptors:@[sort]]; +// NSString *firstFile = nonZipFiles.firstObject; + NSData *firstFileData = [NSData dataWithContentsOfURL:self.testFileURLs[@"Aces.zip"]]; + + NSProgress *performProgress = [NSProgress progressWithTotalUnitCount:1]; + [performProgress becomeCurrentWithPendingUnitCount:1]; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [performProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:OtherContext]; + + NSError *writeError = nil; + BOOL success = [archive writeData:firstFileData + filePath:@"First File.idk" + error:&writeError]; + + XCTAssertNil(writeError, @"Error returned by writeData:filePath:error:"); + XCTAssertTrue(success, @"Failed to write data to archive"); + + [performProgress resignCurrent]; + [performProgress removeObserver:self forKeyPath:observedSelector]; + + XCTAssertEqualWithAccuracy(performProgress.fractionCompleted, 1.00, 0.000001, @"Progress never reported as completed"); + + NSUInteger expectedProgressUpdates = 4; + NSArray *expectedProgresses = @[@0, + @0.402872, + @0.805744, + @1.0]; + + XCTAssertEqual(self.fractionsCompletedReported.count, expectedProgressUpdates, @"Incorrect number of progress updates"); + for (NSUInteger i = 0; i < expectedProgressUpdates; i++) { + float expectedProgress = expectedProgresses[i].floatValue; + float actualProgress = self.fractionsCompletedReported[i].floatValue; + + XCTAssertEqualWithAccuracy(actualProgress, expectedProgress, 0.000001f, @"Incorrect progress reported at index %ld", (long)i); + } +} + + +#pragma mark - Mac-only tests + + +#if !TARGET_OS_IPHONE +- (void)testProgressReporting_ExtractData { + NSURL *largeArchiveURL = [self largeArchive]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:largeArchiveURL error:nil]; + NSString *firstFile = [[archive listFilenames:nil] firstObject]; + + NSProgress *extractFileProgress = [NSProgress progressWithTotalUnitCount:1]; + [extractFileProgress becomeCurrentWithPendingUnitCount:1]; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [extractFileProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:OtherContext]; + + NSError *extractError = nil; + NSData *data = [archive extractDataFromFile:firstFile error:&extractError]; + + XCTAssertNil(extractError, @"Error returned by extractDataFromFile:error:"); + XCTAssertNotNil(data, @"Archive failed to extract large archive"); + + [extractFileProgress resignCurrent]; + [extractFileProgress removeObserver:self forKeyPath:observedSelector]; + + XCTAssertEqualWithAccuracy(extractFileProgress.fractionCompleted, 1.00, 0.000001, @"Progress never reported as completed"); + + NSUInteger expectedProgressUpdates = 78; + NSDictionary *expectedProgresses = @{ + @00: @0, + @20: @0.262144, + @35: @0.458752, + @60: @0.786432, + @76: @0.996147, + @77: @1, + }; + + XCTAssertEqual(self.fractionsCompletedReported.count, expectedProgressUpdates, @"Incorrect number of progress updates"); + [expectedProgresses enumerateKeysAndObjectsUsingBlock: + ^(NSNumber *key, NSNumber *obj, BOOL *stop) { + float expectedProgress = obj.floatValue; + float actualProgress = self.fractionsCompletedReported[key.intValue].floatValue; + + XCTAssertEqualWithAccuracy(actualProgress, expectedProgress, 0.000001f, @"Incorrect progress reported at index %d", key.intValue); + }]; +} + +- (void)testProgressReporting_ExtractBufferedData { + NSURL *largeArchiveURL = [self largeArchive]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:largeArchiveURL error:nil]; + NSString *firstFile = [[archive listFilenames:nil] firstObject]; + + NSProgress *extractFileProgress = [NSProgress progressWithTotalUnitCount:1]; + [extractFileProgress becomeCurrentWithPendingUnitCount:1]; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [extractFileProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:OtherContext]; + + NSError *extractError = nil; + BOOL success = [archive extractBufferedDataFromFile:firstFile + error:&extractError + action:^(NSData * _Nonnull dataChunk, CGFloat percentDecompressed) {}]; + + XCTAssertNil(extractError, @"Error returned by extractDataFromFile:error:"); + XCTAssertTrue(success, @"Archive failed to extract large archive into buffer"); + + [extractFileProgress resignCurrent]; + [extractFileProgress removeObserver:self forKeyPath:observedSelector]; + + XCTAssertEqualWithAccuracy(extractFileProgress.fractionCompleted, 1.00, 0.000001, @"Progress never reported as completed"); + + NSUInteger expectedProgressUpdates = 78; + NSDictionary *expectedProgresses = @{ + @00: @0, + @20: @0.262144, + @35: @0.458752, + @60: @0.786432, + @76: @0.996147, + @77: @1, + }; + + XCTAssertEqual(self.fractionsCompletedReported.count, expectedProgressUpdates, @"Incorrect number of progress updates"); + [expectedProgresses enumerateKeysAndObjectsUsingBlock: + ^(NSNumber *key, NSNumber *obj, BOOL *stop) { + float expectedProgress = obj.floatValue; + float actualProgress = self.fractionsCompletedReported[key.intValue].floatValue; + + XCTAssertEqualWithAccuracy(actualProgress, expectedProgress, 0.000001f, @"Incorrect progress reported at index %d", key.intValue); + }]; +} + +- (void)testProgressCancellation_ExtractData { + NSURL *largeArchiveURL = [self largeArchive]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:largeArchiveURL error:nil]; + NSString *firstFile = [[archive listFilenames:nil] firstObject]; + + NSProgress *extractFileProgress = [NSProgress progressWithTotalUnitCount:1]; + [extractFileProgress becomeCurrentWithPendingUnitCount:1]; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [extractFileProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:CancelContext]; + + NSError *extractError = nil; + NSData *data = [archive extractDataFromFile:firstFile error:&extractError]; + + XCTAssertNotNil(extractError, @"No error returned by cancelled extractDataFromFile:error:"); + XCTAssertEqual(extractError.code, UZKErrorCodeUserCancelled, @"Incorrect error code returned from user cancellation"); + XCTAssertNil(data, @"extractData didn't return nil when cancelled"); + + [extractFileProgress resignCurrent]; + [extractFileProgress removeObserver:self forKeyPath:observedSelector]; + + NSUInteger expectedProgressUpdates = 2; + XCTAssertEqual(self.fractionsCompletedReported.count, expectedProgressUpdates, @"Incorrect number of progress updates"); +} + +- (void)testProgressCancellation_ExtractBufferedData { + NSURL *largeArchiveURL = [self largeArchive]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:largeArchiveURL error:nil]; + NSString *firstFile = [[archive listFilenames:nil] firstObject]; + + NSProgress *extractFileProgress = [NSProgress progressWithTotalUnitCount:1]; + [extractFileProgress becomeCurrentWithPendingUnitCount:1]; + + NSString *observedSelector = NSStringFromSelector(@selector(fractionCompleted)); + + [extractFileProgress addObserver:self + forKeyPath:observedSelector + options:NSKeyValueObservingOptionInitial + context:CancelContext]; + + __block NSUInteger blockCallCount = 0; + + NSError *extractError = nil; + BOOL success = [archive extractBufferedDataFromFile:firstFile + error:&extractError + action:^(NSData * _Nonnull dataChunk, CGFloat percentDecompressed) { + blockCallCount++; + }]; + + XCTAssertNotNil(extractError, @"No error returned by cancelled extractDataFromFile:error:"); + XCTAssertEqual(extractError.code, UZKErrorCodeUserCancelled, @"Incorrect error code returned from user cancellation"); + XCTAssertFalse(success, @"extractBufferedData didn't return false when cancelled"); + + [extractFileProgress resignCurrent]; + [extractFileProgress removeObserver:self forKeyPath:observedSelector]; + + NSUInteger expectedProgressUpdates = 2; + XCTAssertEqual(self.fractionsCompletedReported.count, expectedProgressUpdates, @"Incorrect number of progress updates"); + XCTAssertEqual(blockCallCount, (NSUInteger)1, @"Action block called incorrect number of times after cancellation"); +} +#endif + + +#pragma mark - Private methods + + +- (void)observeValueForKeyPath:(NSString *)keyPath + ofObject:(id)object + change:(NSDictionary *)change + context:(void *)context +{ + observerCallCount++; + + NSProgress *progress; + + if ([object isKindOfClass:[NSProgress class]]) { + progress = object; + [self.fractionsCompletedReported addObject:@(progress.fractionCompleted)]; + } else { + return; + } + + if (context == ExtractFilesContext) { + [self.descriptionsReported addObject:progress.localizedDescription]; + [self.additionalDescriptionsReported addObject:progress.localizedAdditionalDescription]; + + UZKFileInfo *fileInfo = progress.userInfo[UZKProgressInfoKeyFileInfoExtracting]; + if (fileInfo) [self.fileInfosReported addObject:fileInfo]; + } + + if (context == CancelContext && observerCallCount == 2) { + [progress cancel]; + } +} + +@end diff --git a/Carthage/Checkouts/UnzipKit/Tests/PropertyTests.m b/Carthage/Checkouts/UnzipKit/Tests/PropertyTests.m new file mode 100644 index 0000000..136545a --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/PropertyTests.m @@ -0,0 +1,53 @@ +// +// PropertyTests.m +// UnzipKit +// +// Created by Dov Frankel on 7/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "UZKArchiveTestCase.h" +#import "UnzipKit.h" + +@interface PropertyTests : UZKArchiveTestCase +@end + +@implementation PropertyTests + + +- (void)testFileURL { + NSArray *testArchives = @[@"Test Archive.zip", + @"Test Archive (Password).zip"]; + + for (NSString *testArchiveName in testArchives) { + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSURL *resolvedURL = archive.fileURL.URLByResolvingSymlinksInPath; + XCTAssertNotNil(resolvedURL, @"Nil URL returned for valid archive"); + XCTAssertTrue([testArchiveURL isEqual:resolvedURL], @"Resolved URL doesn't match original"); + } +} + +- (void)testFilename { + NSArray *testArchives = @[@"Test Archive.zip", + @"Test Archive (Password).zip"]; + + for (NSString *testArchiveName in testArchives) { + NSURL *testArchiveURL = self.testFileURLs[testArchiveName]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSString *resolvedFilename = archive.filename; + XCTAssertNotNil(resolvedFilename, @"Nil filename returned for valid archive"); + + // Testing by suffix, since the original points to /private/var, but the resolved one + // points straight to /var. They're equivalent, but not character-for-character equal + XCTAssertTrue([resolvedFilename hasSuffix:testArchiveURL.path], + @"Resolved filename doesn't match original"); + } +} + + +@end diff --git a/Carthage/Checkouts/UnzipKit/Tests/Test Data/Aces.zip b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Aces.zip new file mode 100644 index 0000000..3f53fb9 Binary files /dev/null and b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Aces.zip differ diff --git a/Carthage/Checkouts/UnzipKit/Tests/Test Data/Comments Archive.zip b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Comments Archive.zip new file mode 100644 index 0000000..fb42d51 Binary files /dev/null and b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Comments Archive.zip differ diff --git a/Carthage/Checkouts/UnzipKit/Tests/Test Data/Empty Archive.zip b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Empty Archive.zip new file mode 100644 index 0000000..15cb0ec Binary files /dev/null and b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Empty Archive.zip differ diff --git a/Carthage/Checkouts/UnzipKit/Tests/Test Data/Good CRC Archive.zip b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Good CRC Archive.zip new file mode 100644 index 0000000..5e30532 Binary files /dev/null and b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Good CRC Archive.zip differ diff --git a/Carthage/Checkouts/UnzipKit/Tests/Test Data/L'incertain.zip b/Carthage/Checkouts/UnzipKit/Tests/Test Data/L'incertain.zip new file mode 100644 index 0000000..a0b6b00 Binary files /dev/null and b/Carthage/Checkouts/UnzipKit/Tests/Test Data/L'incertain.zip differ diff --git a/Carthage/Checkouts/UnzipKit/Tests/Test Data/Modified CRC Archive.zip b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Modified CRC Archive.zip new file mode 100644 index 0000000..505a16c Binary files /dev/null and b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Modified CRC Archive.zip differ diff --git a/Carthage/Checkouts/UnzipKit/Tests/Test Data/NotAZip-PK-ContentsUnknown b/Carthage/Checkouts/UnzipKit/Tests/Test Data/NotAZip-PK-ContentsUnknown new file mode 100755 index 0000000..cf21436 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/Test Data/NotAZip-PK-ContentsUnknown @@ -0,0 +1 @@ +PK diff --git a/Carthage/Checkouts/UnzipKit/Tests/Test Data/Spanned Archive.zip.001 b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Spanned Archive.zip.001 new file mode 100644 index 0000000..4782eb9 Binary files /dev/null and b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Spanned Archive.zip.001 differ diff --git a/Carthage/Checkouts/UnzipKit/Tests/Test Data/Spanned Archive.zip.002 b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Spanned Archive.zip.002 new file mode 100644 index 0000000..6a80983 Binary files /dev/null and b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Spanned Archive.zip.002 differ diff --git a/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test Archive (Password).zip b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test Archive (Password).zip new file mode 100644 index 0000000..37b87b1 Binary files /dev/null and b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test Archive (Password).zip differ diff --git a/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test Archive.zip b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test Archive.zip new file mode 100644 index 0000000..1854cfb Binary files /dev/null and b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test Archive.zip differ diff --git a/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test File A.txt b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test File A.txt new file mode 100644 index 0000000..2a3321e --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test File A.txt @@ -0,0 +1 @@ +Test File A (secret message here) \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test File B.jpg b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test File B.jpg new file mode 100644 index 0000000..42caa84 Binary files /dev/null and b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test File B.jpg differ diff --git a/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test File C.m4a b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test File C.m4a new file mode 100644 index 0000000..090b5be Binary files /dev/null and b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test File C.m4a differ diff --git a/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test File Ⓐ.txt b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test File Ⓐ.txt new file mode 100644 index 0000000..2a3321e --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test File Ⓐ.txt @@ -0,0 +1 @@ +Test File A (secret message here) \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test File Ⓑ.jpg b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test File Ⓑ.jpg new file mode 100644 index 0000000..42caa84 Binary files /dev/null and b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test File Ⓑ.jpg differ diff --git a/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test File Ⓒ.m4a b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test File Ⓒ.m4a new file mode 100644 index 0000000..090b5be Binary files /dev/null and b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Test File Ⓒ.m4a differ diff --git a/Carthage/Checkouts/UnzipKit/Tests/Test Data/Ⓣest Ⓐrchive.zip b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Ⓣest Ⓐrchive.zip new file mode 100644 index 0000000..0a43c11 Binary files /dev/null and b/Carthage/Checkouts/UnzipKit/Tests/Test Data/Ⓣest Ⓐrchive.zip differ diff --git a/Carthage/Checkouts/UnzipKit/Tests/UZKArchiveTestCase.h b/Carthage/Checkouts/UnzipKit/Tests/UZKArchiveTestCase.h new file mode 100644 index 0000000..1373471 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/UZKArchiveTestCase.h @@ -0,0 +1,55 @@ +// +// UZKArchiveTestCase.h +// UnzipKit +// +// Created by Dov Frankel on 6/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "TargetConditionals.h" + +#if TARGET_OS_IPHONE +#import +#else +#import +#endif + +#import + + +@interface UZKArchiveTestCase : XCTestCase + +@property BOOL testFailed; + +@property (retain) NSURL *tempDirectory; +@property (retain) NSMutableDictionary *testFileURLs; +@property (retain) NSMutableDictionary *unicodeFileURLs; +@property (retain) NSSet *nonZipTestFilePaths; +@property (retain) NSSet *nonZipUnicodeFilePaths; +@property (retain) NSURL *corruptArchive; + + +// Helper Methods + ++ (NSDateFormatter *)dateFormatter; + +- (NSURL *)urlOfTestFile:(NSString *)filename; + +- (NSString *)randomDirectoryName; +- (NSString *)randomDirectoryWithPrefix:(NSString *)prefix; + +- (NSURL *)emptyTextFileOfLength:(NSUInteger)fileSize; + +#if !TARGET_OS_IPHONE +- (NSInteger)numberOfOpenFileHandles; +- (NSURL *)archiveWithFiles:(NSArray *)fileURLs; +- (NSURL *)archiveWithFiles:(NSArray *)fileURLs password:(NSString *)password; +- (BOOL)extractArchive:(NSURL *)url password:(NSString *)password; +- (NSURL *)largeArchive; +#endif + +- (NSUInteger)crcOfFile:(NSURL *)url; +- (NSUInteger)crcOfTestFile:(NSString *)filename; + +@end + diff --git a/Carthage/Checkouts/UnzipKit/Tests/UZKArchiveTestCase.m b/Carthage/Checkouts/UnzipKit/Tests/UZKArchiveTestCase.m new file mode 100644 index 0000000..2cd9fe8 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/UZKArchiveTestCase.m @@ -0,0 +1,368 @@ +// +// UZKArchiveTestCase.m +// UnzipKit +// +// Created by Dov Frankel on 6/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "UZKArchiveTestCase.h" + +#import "unzip.h" +#import "UnzipKitMacros.h" + +static NSDateFormatter *testFileInfoDateFormatter; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wundef" +#if UNIFIED_LOGGING_SUPPORTED +os_log_t unzipkit_log; +BOOL unzipkitIsAtLeast10_13SDK; +#endif +#pragma clang diagnostic pop + + +@implementation UZKArchiveTestCase + + + +#pragma mark - Setup/Teardown + ++ (void)initialize { + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + UZKLogInit(); + }); +} + +- (void)setUp { + [super setUp]; + + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + testFileInfoDateFormatter = [[NSDateFormatter alloc] init]; + testFileInfoDateFormatter.dateFormat = @"M/dd/yyyy h:mm a"; + testFileInfoDateFormatter.locale = [NSLocale localeWithLocaleIdentifier:@"en_US"]; + }); + + + NSFileManager *fm = [NSFileManager defaultManager]; + NSString *uniqueName = [self randomDirectoryName]; + NSError *error = nil; + + NSArray *testFiles = @[ + @"Test Archive.zip", + @"Test Archive (Password).zip", + @"L'incertain.zip", + @"Aces.zip", + @"Comments Archive.zip", + @"Empty Archive.zip", + @"Spanned Archive.zip.001", + @"Test File A.txt", + @"Test File B.jpg", + @"Test File C.m4a", + @"NotAZip-PK-ContentsUnknown", + @"Modified CRC Archive.zip", + ]; + + NSArray *unicodeFiles = @[ + @"Ⓣest Ⓐrchive.zip", + @"Test File Ⓐ.txt", + @"Test File Ⓑ.jpg", + @"Test File Ⓒ.m4a", + ]; + + NSString *tempDirSubtree = [@"UnzipKitTest" stringByAppendingPathComponent:uniqueName]; + + self.testFailed = NO; + self.testFileURLs = [[NSMutableDictionary alloc] init]; + self.unicodeFileURLs = [[NSMutableDictionary alloc] init]; + self.tempDirectory = [NSURL fileURLWithPath:[NSTemporaryDirectory() stringByAppendingPathComponent:tempDirSubtree] + isDirectory:YES]; + + UZKLog("Temp directory: %@", self.tempDirectory); + + [fm createDirectoryAtURL:self.tempDirectory + withIntermediateDirectories:YES + attributes:nil + error:&error]; + + XCTAssertNil(error, @"Failed to create temp directory: %@", self.tempDirectory); + + NSMutableArray *filesToCopy = [NSMutableArray arrayWithArray:testFiles]; + [filesToCopy addObjectsFromArray:unicodeFiles]; + + for (NSString *file in filesToCopy) { + NSURL *testFileURL = [self urlOfTestFile:file]; + BOOL testFileExists = [fm fileExistsAtPath:(NSString* _Nonnull)testFileURL.path]; + XCTAssertTrue(testFileExists, @"%@ not found", file); + + NSURL *destinationURL = [self.tempDirectory URLByAppendingPathComponent:file isDirectory:NO]; + + NSError *error = nil; + if (file.pathComponents.count > 1) { + [fm createDirectoryAtPath:(NSString* _Nonnull)destinationURL.URLByDeletingLastPathComponent.path + withIntermediateDirectories:YES + attributes:nil + error:&error]; + XCTAssertNil(error, @"Failed to create directories for file %@", file); + } + + [fm copyItemAtURL:testFileURL + toURL:destinationURL + error:&error]; + + XCTAssertNil(error, @"Failed to copy temp file %@ from %@ to %@", + file, testFileURL, destinationURL); + + if ([testFiles containsObject:file]) { + self.testFileURLs[file] = destinationURL; + } + else if ([unicodeFiles containsObject:file]) { + self.unicodeFileURLs[file] = destinationURL; + } + } + + self.nonZipTestFilePaths = [self.testFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) { + return [key.lowercaseString rangeOfString:@"zip"].location == NSNotFound; + }]; + + self.nonZipUnicodeFilePaths = [self.unicodeFileURLs keysOfEntriesPassingTest:^BOOL(NSString *key, id obj, BOOL *stop) { + return [key.lowercaseString rangeOfString:@"zip"].location == NSNotFound; + }]; + + // Make a "corrupt" zip file + NSURL *m4aFileURL = [self urlOfTestFile:@"Test File C.m4a"]; + self.corruptArchive = [self.tempDirectory URLByAppendingPathComponent:@"corrupt.zip"]; + [fm copyItemAtURL:m4aFileURL + toURL:self.corruptArchive + error:&error]; +} + +- (void)tearDown { + if (!self.testFailed) { + NSError *error = nil; + [[NSFileManager defaultManager] removeItemAtURL:self.tempDirectory error:&error]; + + XCTAssertNil(error, @"Error deleting temp directory"); + } + + [super tearDown]; +} + + + +#pragma mark - Helper Methods + + ++ (NSDateFormatter *)dateFormatter { + return testFileInfoDateFormatter; +} + +- (NSURL *)urlOfTestFile:(NSString *)filename +{ + NSString *baseDirectory = @"Test Data"; + NSString *subPath = filename.stringByDeletingLastPathComponent; + NSString *bundleSubdir = [baseDirectory stringByAppendingPathComponent:subPath]; + + return [[NSBundle bundleForClass:[self class]] URLForResource:filename.lastPathComponent + withExtension:nil + subdirectory:bundleSubdir]; +} + +- (NSString *)randomDirectoryName +{ + NSString *globallyUnique = [[NSProcessInfo processInfo] globallyUniqueString]; + NSRange firstHyphen = [globallyUnique rangeOfString:@"-"]; + return [globallyUnique substringToIndex:firstHyphen.location]; +} + +- (NSString *)randomDirectoryWithPrefix:(NSString *)prefix +{ + return [NSString stringWithFormat:@"%@ %@", prefix, [self randomDirectoryName]]; +} + +- (NSURL *)emptyTextFileOfLength:(NSUInteger)fileSize +{ + NSURL *resultURL = [self.tempDirectory URLByAppendingPathComponent: + [NSString stringWithFormat:@"%@.txt", [[NSProcessInfo processInfo] globallyUniqueString]]]; + + [[NSFileManager defaultManager] createFileAtPath:(NSString *__nonnull)resultURL.path + contents:nil + attributes:nil]; + + NSError *error = nil; + NSFileHandle *fileHandle = [NSFileHandle fileHandleForWritingToURL:resultURL + error:&error]; + XCTAssertNil(error, @"Error creating file handle for URL: %@", resultURL); + + NSData *emptyByte = [@"\x01" dataUsingEncoding:NSUTF8StringEncoding]; + + [fileHandle writeData:emptyByte]; + [fileHandle seekToFileOffset:fileSize]; + [fileHandle writeData:emptyByte]; + [fileHandle closeFile]; + + return resultURL; +} + +#if !TARGET_OS_IPHONE + +- (NSInteger)numberOfOpenFileHandles { + int pid = [[NSProcessInfo processInfo] processIdentifier]; + NSPipe *pipe = [NSPipe pipe]; + NSFileHandle *file = pipe.fileHandleForReading; + + NSTask *task = [[NSTask alloc] init]; + task.launchPath = @"/usr/sbin/lsof"; + task.arguments = @[@"-P", @"-n", @"-p", [NSString stringWithFormat:@"%d", pid]]; + task.standardOutput = pipe; + + [task launch]; + + NSData *data = [file readDataToEndOfFile]; + [file closeFile]; + + NSString *lsofOutput = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]; + +// UZKLog("LSOF output:\n%@", lsofOutput); + + NSInteger result = [lsofOutput componentsSeparatedByCharactersInSet:[NSCharacterSet newlineCharacterSet]].count; +// UZKLog("LSOF result: %ld", result); + + return result; +} + +- (NSURL *)archiveWithFiles:(NSArray *)fileURLs +{ + return [self archiveWithFiles:fileURLs password:nil]; +} + +- (NSURL *)archiveWithFiles:(NSArray *)fileURLs password:(NSString *)password +{ + NSString *uniqueString = [[NSProcessInfo processInfo] globallyUniqueString]; + return [self archiveWithFiles:fileURLs password:password name:uniqueString]; +} + +- (NSURL *)archiveWithFiles:(NSArray *)fileURLs password:(NSString *)password name:(NSString *)name +{ + NSURL *archiveURL = [[self.tempDirectory URLByAppendingPathComponent:name] + URLByAppendingPathExtension:@"zip"]; + NSFileHandle *consoleOutputHandle = nil; + + if (fileURLs.count > 100) { + NSURL *consoleOutputFile = [archiveURL URLByAppendingPathExtension:@"filewriteoutput.txt"]; + [[NSFileManager defaultManager] createFileAtPath:(NSString *__nonnull)consoleOutputFile.path + contents:nil + attributes:nil]; + + consoleOutputHandle = [NSFileHandle fileHandleForWritingAtPath:consoleOutputFile.path]; + + UZKLog("Writing zip command output to: %@", consoleOutputFile.path); + } + + const NSUInteger maxFilesPerCall = 1500; + NSArray *filePaths = (NSArray *__nonnull)[fileURLs valueForKeyPath:@"path"]; + + NSUInteger startIndex = 0; + NSUInteger pathsRemaining = filePaths.count; + + while (startIndex < filePaths.count) { + @autoreleasepool { + NSMutableArray *zipArgs = [NSMutableArray arrayWithArray: + @[@"-j", archiveURL.path]]; + + if (password) { + [zipArgs addObjectsFromArray:@[@"-P", password]]; + } + + NSRange currentRange = NSMakeRange(startIndex, MIN(pathsRemaining, maxFilesPerCall)); + NSArray *pathArrayChunk = [filePaths subarrayWithRange:currentRange]; + + [zipArgs addObjectsFromArray:pathArrayChunk]; + + NSTask *task = [[NSTask alloc] init]; + task.launchPath = @"/usr/bin/zip"; + task.arguments = zipArgs; + task.standardOutput = consoleOutputHandle; + + UZKLog("Compressing files %lu-%lu of %lu", startIndex + 1, startIndex + pathArrayChunk.count, filePaths.count); + + [task launch]; + [task waitUntilExit]; + + if (task.terminationStatus != 0) { + if (startIndex == 0) { + UZKLog("Failed to create zip archive"); + } else { + UZKLog("Failed to add files to zip archive"); + } + return nil; + } + + pathsRemaining -= currentRange.length; + startIndex += currentRange.length; + } + } + + if (consoleOutputHandle) { + [consoleOutputHandle closeFile]; + } + + return archiveURL; +} + +- (BOOL)extractArchive:(NSURL *)url password:(NSString *)password +{ + NSMutableArray *args = [NSMutableArray array]; + if (password) { + [args addObjectsFromArray:@[@"-P", password]]; + } + + [args addObjectsFromArray:@[url.path, @"-d", url.path.stringByDeletingPathExtension]]; + + NSTask *task = [[NSTask alloc] init]; + task.launchPath = @"/usr/bin/unzip"; + task.arguments = args; + + [task launch]; + [task waitUntilExit]; + + if (task.terminationStatus != 0) { + UZKLog("Failed to extract zip archive"); + return NO; + } + + return YES; +} + +- (NSURL *)largeArchive +{ + NSMutableArray *emptyFiles = [NSMutableArray array]; + for (NSInteger i = 0; i < 5; i++) { + [emptyFiles addObject:[self emptyTextFileOfLength:20000000]]; + } + + static NSInteger archiveNumber = 1; + NSURL *largeArchiveURL = [self archiveWithFiles:emptyFiles + password:nil + name:[NSString stringWithFormat:@"Large Archive %ld", archiveNumber++]]; + return largeArchiveURL; +} + +#endif + +- (NSUInteger)crcOfFile:(NSURL *)url +{ + NSData *fileContents = [[NSFileManager defaultManager] contentsAtPath:url.path]; + return crc32(0, fileContents.bytes, (uInt)fileContents.length); +} + +- (NSUInteger)crcOfTestFile:(NSString *)filename +{ + NSURL *fileURL = [self urlOfTestFile:filename]; + return [self crcOfFile:fileURL]; +} + + +@end diff --git a/Carthage/Checkouts/UnzipKit/Tests/UnzipKitTests-Bridging-Header.h b/Carthage/Checkouts/UnzipKit/Tests/UnzipKitTests-Bridging-Header.h new file mode 100644 index 0000000..6ba7233 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/UnzipKitTests-Bridging-Header.h @@ -0,0 +1,8 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + +#import "UZKArchive.h" + +#import "zip.h" +#import "UZKArchiveTestCase.h" \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/Tests/UtilityMethods.swift b/Carthage/Checkouts/UnzipKit/Tests/UtilityMethods.swift new file mode 100644 index 0000000..00e94e3 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/UtilityMethods.swift @@ -0,0 +1,118 @@ +// +// UtilityMethods.swift +// UnzipKit +// +// Created by Dov Frankel on 6/7/17. +// Copyright © 2017 Abbey Code. All rights reserved. +// + +import Foundation + +#if os(OSX) + +public enum FileSystem: String { + case HFS = "HFS+" + case APFS = "APFS" +} + +public func createAndMountDMG(path dmgURL: URL, source: URL, fileSystem: FileSystem) -> URL? { + let task = Process() + task.launchPath = "/usr/bin/hdiutil" + + var args = ["create", + "-fs", fileSystem.rawValue] + + switch fileSystem { + case .HFS: + args += ["-format", "UDRW", + "-srcfolder", source.path] + break; + + case .APFS: + args += ["-size", "100m"] + break; + } + + args += ["-volname", dmgURL.deletingPathExtension().lastPathComponent, + "-attach", "-plist", + // "-verbose", + dmgURL.path] + + task.arguments = args + + let outputPipe = Pipe() + task.standardOutput = outputPipe + + let errorPipe = Pipe() + task.standardError = errorPipe + + let inputPipe = Pipe() + task.standardInput = inputPipe + inputPipe.fileHandleForWriting.write("y\n".data(using: String.Encoding.utf8)!) + + task.launch() + task.waitUntilExit() + + let readHandle = outputPipe.fileHandleForReading + let outputData = readHandle.readDataToEndOfFile() + + guard task.terminationStatus == 0 else { + let errorHandle = errorPipe.fileHandleForReading + let errorData = errorHandle.readDataToEndOfFile() + + let outputString = String(data: outputData, encoding: String.Encoding.utf8)! + let errorString = String(data: errorData, encoding: String.Encoding.utf8)! + + NSLog("Failed to create and mount DMG: \(dmgURL.path)\n\n\toutput: \(outputString)\n\nerror: \(errorString)"); + return nil + } + + let outputPlist = try! PropertyListSerialization.propertyList(from: outputData, + options: [], + format: nil) + as! [String: Any] + + let entities = outputPlist["system-entities"] as! [[String:AnyObject]] + let mountPoint: URL + + switch fileSystem { + case .HFS: + let hfsEntry = entities.filter{ $0["content-hint"] as! String == "Apple_HFS" }.first! + let mountPointPath = hfsEntry["mount-point"] as! String + mountPoint = URL(fileURLWithPath: mountPointPath) + break; + + case .APFS: + let mountPointEntry = entities.filter{ $0.contains { (k, v) in k == "mount-point" } }.first! + let mountPointPath = mountPointEntry["mount-point"] as! String + mountPoint = URL(fileURLWithPath: mountPointPath) + + // Need to copy the folder's contents in, since -srcfolder doesn't work. Reportedly fixed in 10.13 + let folderContents = try! FileManager.default.contentsOfDirectory(at: source, includingPropertiesForKeys: nil, options: FileManager.DirectoryEnumerationOptions(rawValue: 0)) + for sourceItemURL in folderContents { + let sourceItemPathRelativeToSource = sourceItemURL.path.replacingOccurrences(of: source.path, with: "") + let destinationURL = mountPoint.appendingPathComponent(sourceItemPathRelativeToSource) + try! FileManager.default.copyItem(at: sourceItemURL, to: destinationURL) + } + break; + } + + + return mountPoint +} + + +public func unmountDMG(URL mountPoint: URL) { + let task = Process() + task.launchPath = "/usr/bin/hdiutil" + task.arguments = ["detach", mountPoint.path] + + task.launch() + task.waitUntilExit() + + if task.terminationStatus != 0 { + NSLog("Failed to unmount DMG: \(mountPoint)"); + } +} + +#endif diff --git a/Carthage/Checkouts/UnzipKit/Tests/WriteBufferedDataTests.m b/Carthage/Checkouts/UnzipKit/Tests/WriteBufferedDataTests.m new file mode 100644 index 0000000..bb541b0 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/WriteBufferedDataTests.m @@ -0,0 +1,210 @@ +// +// WriteBufferedDataTests.m +// UnzipKit +// +// Created by Dov Frankel on 7/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "UZKArchiveTestCase.h" +#import "zip.h" +#import "UnzipKit.h" + +@interface WriteBufferedDataTests : UZKArchiveTestCase +@end + +@implementation WriteBufferedDataTests + + +- (void)testWriteInfoBuffer +{ + 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; + + BOOL result = [archive writeIntoBuffer:testFile + fileDate:testDates[idx] + compressionMethod:UZKCompressionMethodDefault + overwrite:YES + 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_Failure +{ + NSURL *testArchiveURL = [self.tempDirectory URLByAppendingPathComponent:@"WriteIntoBufferTest_Failure.zip"]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL error:nil]; + + NSInteger errorCode = 718; + + NSError *writeError = nil; + + BOOL result = [archive writeIntoBuffer:@"Test File A.txt" + fileDate:[[UZKArchiveTestCase dateFormatter] dateFromString:@"12/20/2014 9:35 AM"] + compressionMethod:UZKCompressionMethodDefault + overwrite:YES + 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"); +} + +#if !TARGET_OS_IPHONE +- (void)testWriteInfoBuffer_PasswordGiven +{ + 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; + + BOOL result = [archive writeIntoBuffer:testFile + fileDate:nil + compressionMethod:UZKCompressionMethodDefault + overwrite:YES + CRC:841856539 + 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)"); +} +#endif + +- (void)testWriteInfoBuffer_PasswordGiven_NoCRC +{ + NSURL *testArchiveURL = [self.tempDirectory URLByAppendingPathComponent:@"testWriteInfoBuffer_PasswordGiven_NoCRC.zip"]; + + UZKArchive *archive = [[UZKArchive alloc] initWithURL:testArchiveURL password:@"a password" error:nil]; + + NSError *writeError = nil; + + XCTAssertThrows([archive writeIntoBuffer:@"Test File A.txt" + fileDate:[[UZKArchiveTestCase dateFormatter] dateFromString:@"12/20/2014 9:35 AM"] + compressionMethod:UZKCompressionMethodDefault + overwrite:YES + 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_MismatchedCRC +{ + 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; + + BOOL result = [archive writeIntoBuffer:testFile + fileDate:nil + compressionMethod:UZKCompressionMethodDefault + overwrite:YES + CRC:3 + 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"); +} + + +@end diff --git a/Carthage/Checkouts/UnzipKit/Tests/WriteDataTests.swift b/Carthage/Checkouts/UnzipKit/Tests/WriteDataTests.swift new file mode 100644 index 0000000..c509ffa --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/WriteDataTests.swift @@ -0,0 +1,471 @@ +// +// WriteDataTests.swift +// UnzipKit +// +// Created by Dov Frankel on 6/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#if os(iOS) + import UIKit +#else + import Cocoa +#endif +import XCTest +import UnzipKit + +class WriteDataTests: UZKArchiveTestCase { + + func testWriteData() { + let testFilePaths = [String](nonZipTestFilePaths as! Set).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.write(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") + } + + func testWriteData_Unicode() { + let testFilePaths = [String](nonZipUnicodeFilePaths as! Set).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.write(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") + } + + func testWriteData_Overwrite() { + let testFilePaths = [String](nonZipTestFilePaths as! Set).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.write(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 + 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() { + let testFilePaths = [String](nonZipUnicodeFilePaths as! Set).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.write(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 + 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_NoOverwrite() { + let testFilePaths = [String](nonZipTestFilePaths as! Set).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.write(fileData!, filePath: testFilePath, fileDate: testDates[index], + compressionMethod: .default, password: nil, overwrite: false) + } 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_ManyFiles_MemoryUsage_ForProfiling() { +// let testArchiveURL = tempDirectory.appendingPathComponent("ManyFilesMemoryUsageTest.zip") +// let testFilename = nonZipTestFilePaths.first as! String +// let testFileURL = testFileURLs[testFilename] as! URL +// let testFileData = try! Data(contentsOf: testFileURL) +// +// let archive = try! UZKArchive(url: testArchiveURL) +// +// for i in 1...1000 { +// do { +// try archive.write(testFileData, filePath: "File \(i).txt", fileDate: nil, +// compressionMethod: .default, password: nil, overwrite: true, progress: nil) +// } catch let error as NSError { +// XCTFail("Error writing to file \(testFileURL): \(error)") +// } +// } +// } + + func testWriteData_DefaultDate() { + let testArchiveURL = tempDirectory.appendingPathComponent("DefaultDateWriteTest.zip") + let testFilename = nonZipTestFilePaths.first as! String + let testFileURL = testFileURLs[testFilename] as! URL + let testFileData = try! Data(contentsOf: testFileURL) + + let archive = try! UZKArchive(url: testArchiveURL) + + do { + try archive.write(testFileData, filePath: testFilename, fileDate: nil, + compressionMethod: .default, password: nil) + } 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") + } + + #if os(OSX) + func testWriteData_PasswordProtected() { + let testFilePaths = [String](nonZipTestFilePaths as! Set).sorted(by: <) + var testFileData = [Data]() + + let testArchiveURL = tempDirectory.appendingPathComponent("SwiftWriteDataTest.zip") + let password = "111111" + + let writeArchive = try! UZKArchive(path: testArchiveURL.path, password: password) + + for testFilePath in testFilePaths { + let fileData = try? Data(contentsOf: testFileURLs[testFilePath] as! URL) + testFileData.append(fileData!) + + do { + try writeArchive.write(fileData!, filePath: testFilePath) + } catch let error as NSError { + XCTFail("Error writing to file \(testFilePath): \(error)") + } + } + + // Read with UnzipKit + + let readArchive = try! UZKArchive(path: testArchiveURL.path, password: password) + XCTAssertTrue(readArchive.isPasswordProtected(), "Archive is not marked as password-protected") + + var index = 0 + + try! readArchive.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.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; + }) + + XCTAssertEqual(index, testFilePaths.count, "Not all files enumerated") + + // Read with the unzip command line tool + let success = extractArchive(testArchiveURL, password: password) + XCTAssertTrue(success, "Failed to extract the archive on the command line") + } + + func testWriteData_ExternalVolume() { + // 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.write(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 + } + + 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") + } + + #endif + +} diff --git a/Carthage/Checkouts/UnzipKit/Tests/ZipFileDetectionTests.m b/Carthage/Checkouts/UnzipKit/Tests/ZipFileDetectionTests.m new file mode 100644 index 0000000..34d5384 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/Tests/ZipFileDetectionTests.m @@ -0,0 +1,171 @@ +// +// ZipFileDetectionTests.m +// UnzipKit +// +// Created by Dov Frankel on 7/16/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +#import "UZKArchiveTestCase.h" +#import "UnzipKit.h" + +@interface ZipFileDetectionTests : UZKArchiveTestCase +@end + +@implementation ZipFileDetectionTests + +#pragma mark - By Path + +- (void)testPathIsAZip +{ + NSURL *url = self.testFileURLs[@"Test Archive.zip"]; + NSString *path = url.path; + BOOL pathIsZip = [UZKArchive pathIsAZip:path]; + XCTAssertTrue(pathIsZip, @"Zip file is not reported as a zip"); +} + +- (void)testPathIsAZip_EmptyZip +{ + NSURL *url = self.testFileURLs[@"Empty Archive.zip"]; + NSString *path = url.path; + BOOL pathIsZip = [UZKArchive pathIsAZip:path]; + XCTAssertTrue(pathIsZip, @"Empty Zip file is not reported as a zip"); +} + +- (void)testPathIsAZip_SpannedZip +{ + NSURL *url = self.testFileURLs[@"Spanned Archive.zip.001"]; + NSString *path = url.path; + BOOL pathIsZip = [UZKArchive pathIsAZip:path]; + XCTAssertTrue(pathIsZip, @"Spanned Zip file is not reported as a zip"); +} + +- (void)testPathIsAZip_NotAZip +{ + NSURL *url = self.testFileURLs[@"Test File B.jpg"]; + NSString *path = url.path; + BOOL pathIsZip = [UZKArchive pathIsAZip:path]; + XCTAssertFalse(pathIsZip, @"JPG file is reported as a zip"); +} + +- (void)testPathIsAZip_NotAZip_FirstBytesPK +{ + NSURL *url = self.testFileURLs[@"NotAZip-PK-ContentsUnknown"]; + NSString *path = url.path; + BOOL pathIsZip = [UZKArchive pathIsAZip:path]; + XCTAssertFalse(pathIsZip, @"JPG file is reported as a zip"); +} + +- (void)testPathIsAZip_SmallFile +{ + NSURL *url = [self emptyTextFileOfLength:1]; + NSString *path = url.path; + BOOL pathIsZip = [UZKArchive pathIsAZip:path]; + XCTAssertFalse(pathIsZip, @"Small non-Zip file is reported as a zip"); +} + +- (void)testPathIsAZip_MissingFile +{ + NSURL *url = [self.testFileURLs[@"Test Archive.zip"] URLByAppendingPathExtension:@"missing"]; + NSString *path = url.path; + BOOL pathIsZip = [UZKArchive pathIsAZip:path]; + XCTAssertFalse(pathIsZip, @"Missing file is reported as a zip"); +} + +#if !TARGET_OS_IPHONE +- (void)testPathIsAZip_FileHandleLeaks +{ + NSURL *smallFileURL = [self emptyTextFileOfLength:1]; + NSURL *jpgURL = self.testFileURLs[@"Test File B.jpg"]; + + NSInteger initialFileCount = [self numberOfOpenFileHandles]; + + for (NSInteger i = 0; i < 5000; i++) { + BOOL smallFileIsZip = [UZKArchive pathIsAZip:(NSString *__nonnull)smallFileURL.path]; + XCTAssertFalse(smallFileIsZip, @"Small non-Zip file is reported as a zip"); + + BOOL jpgIsZip = [UZKArchive pathIsAZip:(NSString *__nonnull)jpgURL.path]; + XCTAssertFalse(jpgIsZip, @"JPG file is reported as a zip"); + + NSURL *zipURL = self.testFileURLs[@"Test Archive.zip"]; + BOOL zipFileIsZip = [UZKArchive pathIsAZip:(NSString *__nonnull)zipURL.path]; + XCTAssertTrue(zipFileIsZip, @"Zip file is not reported as a zip"); + } + + NSInteger finalFileCount = [self numberOfOpenFileHandles]; + + XCTAssertEqualWithAccuracy(initialFileCount, finalFileCount, 5, @"File descriptors were left open"); +} +#endif + +#pragma mark - By URL + +- (void)testURLIsAZip +{ + NSURL *url = self.testFileURLs[@"Test Archive.zip"]; + BOOL urlIsZip = [UZKArchive urlIsAZip:url]; + XCTAssertTrue(urlIsZip, @"Zip file is not reported as a zip"); +} + +- (void)testURLIsAZip_EmptyZip +{ + NSURL *url = self.testFileURLs[@"Empty Archive.zip"]; + BOOL urlIsZip = [UZKArchive urlIsAZip:url]; + XCTAssertTrue(urlIsZip, @"Empty Zip file is not reported as a zip"); +} + +- (void)testSpannedIsAZip_SpannedZip +{ + NSURL *url = self.testFileURLs[@"Spanned Archive.zip.001"]; + BOOL urlIsZip = [UZKArchive urlIsAZip:url]; + XCTAssertTrue(urlIsZip, @"Spanned Zip file is not reported as a zip"); +} + +- (void)testURLIsAZip_NotAZip +{ + NSURL *url = self.testFileURLs[@"Test File B.jpg"]; + BOOL urlIsZip = [UZKArchive urlIsAZip:url]; + XCTAssertFalse(urlIsZip, @"JPG file is reported as a zip"); +} + +- (void)testURLIsAZip_SmallFile +{ + NSURL *url = [self emptyTextFileOfLength:1]; + BOOL urlIsZip = [UZKArchive urlIsAZip:url]; + XCTAssertFalse(urlIsZip, @"Small non-Zip file is reported as a zip"); +} + +- (void)testURLIsAZip_MissingFile +{ + NSURL *url = [self.testFileURLs[@"Test Archive.zip"] URLByAppendingPathExtension:@"missing"]; + BOOL urlIsZip = [UZKArchive urlIsAZip:url]; + XCTAssertFalse(urlIsZip, @"Missing file is reported as a zip"); +} + +#if !TARGET_OS_IPHONE +- (void)testURLIsAZip_FileHandleLeaks +{ + NSURL *smallFileURL = [self emptyTextFileOfLength:1]; + NSURL *jpgURL = self.testFileURLs[@"Test File B.jpg"]; + + NSInteger initialFileCount = [self numberOfOpenFileHandles]; + + for (NSInteger i = 0; i < 5000; i++) { + BOOL smallFileIsZip = [UZKArchive urlIsAZip:smallFileURL]; + XCTAssertFalse(smallFileIsZip, @"Small non-Zip file is reported as a zip"); + + BOOL jpgIsZip = [UZKArchive urlIsAZip:jpgURL]; + XCTAssertFalse(jpgIsZip, @"JPG file is reported as a zip"); + + NSURL *zipURL = self.testFileURLs[@"Test Archive.zip"]; + BOOL zipFileIsZip = [UZKArchive urlIsAZip:zipURL]; + XCTAssertTrue(zipFileIsZip, @"Zip file is not reported as a zip"); + } + + NSInteger finalFileCount = [self numberOfOpenFileHandles]; + + XCTAssertEqualWithAccuracy(initialFileCount, finalFileCount, 5, @"File descriptors were left open"); +} +#endif + +@end diff --git a/Carthage/Checkouts/UnzipKit/UnzipKit.podspec b/Carthage/Checkouts/UnzipKit/UnzipKit.podspec new file mode 100644 index 0000000..7b54d19 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKit.podspec @@ -0,0 +1,35 @@ +Pod::Spec.new do |s| + s.name = "UnzipKit" + s.version = ENV["TRAVIS_TAG"] + s.summary = "An Objective-C zlib wrapper for compressing and decompressing Zip files" + s.license = "BSD" + s.homepage = "https://github.com/abbeycode/UnzipKit" + 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.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.exclude_files = 'Resources/**/Info.plist' + s.resource_bundles = { + 'UnzipKitResources' => ['Resources/**/*'] + } + s.test_spec 'Tests' do |test_spec| + test_spec.source_files = 'Tests/*.{h,m}' + test_spec.exclude_files = 'Tests/ExtractFilesTests.m' + test_spec.resources = ['Tests/Test Data'] + test_spec.pod_target_xcconfig = { "OTHER_CFLAGS" => "$(inherited) -Wno-unguarded-availability" } + end + s.library = "z" + + s.subspec "minizip-lib" do |ss| + ss.private_header_files = "Lib/MiniZip/*.h" + ss.source_files = "Lib/MiniZip/*.{h,c}" + ss.pod_target_xcconfig = { "OTHER_CFLAGS" => "$(inherited) -Wno-comma -Wno-strict-prototypes" } + end +end diff --git a/Carthage/Checkouts/UnzipKit/UnzipKit.xcodeproj/project.pbxproj b/Carthage/Checkouts/UnzipKit/UnzipKit.xcodeproj/project.pbxproj new file mode 100644 index 0000000..2986ac9 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKit.xcodeproj/project.pbxproj @@ -0,0 +1,922 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 48; + objects = { + +/* Begin PBXBuildFile section */ + 7A00291B1F93DB9200618503 /* ioapi.c in Sources */ = {isa = PBXBuildFile; fileRef = 96EA65C31A40C44300685B6D /* ioapi.c */; }; + 7A00291C1F93DB9200618503 /* mztools.c in Sources */ = {isa = PBXBuildFile; fileRef = 96EA65C51A40C44300685B6D /* mztools.c */; }; + 7A00291D1F93DB9200618503 /* unzip.c in Sources */ = {isa = PBXBuildFile; fileRef = 96EA65C71A40C44300685B6D /* unzip.c */; }; + 7A00291E1F93DB9200618503 /* zip.c in Sources */ = {isa = PBXBuildFile; fileRef = 96EA65C91A40C44300685B6D /* zip.c */; }; + 7A00291F1F93DBC900618503 /* crypt.h in Headers */ = {isa = PBXBuildFile; fileRef = 96EA66031A435D8200685B6D /* crypt.h */; }; + 7A0029201F93DBC900618503 /* ioapi.h in Headers */ = {isa = PBXBuildFile; fileRef = 96EA65C41A40C44300685B6D /* ioapi.h */; }; + 7A0029211F93DBC900618503 /* mztools.h in Headers */ = {isa = PBXBuildFile; fileRef = 96EA65C61A40C44300685B6D /* mztools.h */; }; + 7A0029221F93DBC900618503 /* unzip.h in Headers */ = {isa = PBXBuildFile; fileRef = 96EA65C81A40C44300685B6D /* unzip.h */; }; + 7A0029231F93DBC900618503 /* zip.h in Headers */ = {isa = PBXBuildFile; fileRef = 96EA65CA1A40C44300685B6D /* zip.h */; }; + 7A0029241F93DBF000618503 /* libminizip.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A0029171F93DB5800618503 /* libminizip.a */; }; + 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 */; }; + 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 */; }; + 9630C0381C6D27A4000693EE /* ExtractDataTests_Swift.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9630C0371C6D27A4000693EE /* ExtractDataTests_Swift.swift */; }; + 963386B91EE89A51006B16BF /* UtilityMethods.swift in Sources */ = {isa = PBXBuildFile; fileRef = 963386B71EE89A49006B16BF /* UtilityMethods.swift */; }; + 963603531BFB815600BF0C4F /* UZKFileInfo_Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 963603521BFB7F6500BF0C4F /* UZKFileInfo_Private.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 965CF00A1D241A8F00C80A88 /* NSURL+UnzipKitExtensions.h in Headers */ = {isa = PBXBuildFile; fileRef = 965CF0081D241A8F00C80A88 /* NSURL+UnzipKitExtensions.h */; }; + 965CF00C1D241A8F00C80A88 /* NSURL+UnzipKitExtensions.m in Sources */ = {isa = PBXBuildFile; fileRef = 965CF0091D241A8F00C80A88 /* NSURL+UnzipKitExtensions.m */; }; + 9677858E1F1405F000A8D6B2 /* UnzipKitMacros.h in Headers */ = {isa = PBXBuildFile; fileRef = 9677858D1F1405DB00A8D6B2 /* UnzipKitMacros.h */; }; + 968C40C01B585FDE004C128E /* ModesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 968C40BF1B585FDE004C128E /* ModesTests.m */; }; + 968C40C21B586132004C128E /* ZipFileDetectionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 968C40C11B586132004C128E /* ZipFileDetectionTests.m */; }; + 968C40C41B58619C004C128E /* ListFilenamesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 968C40C31B58619C004C128E /* ListFilenamesTests.m */; }; + 968C40C61B5861C3004C128E /* ListFileInfoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 968C40C51B5861C3004C128E /* ListFileInfoTests.m */; }; + 968C40C81B5861F4004C128E /* ExtractFilesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 968C40C71B5861F4004C128E /* ExtractFilesTests.m */; }; + 968C40CA1B586227004C128E /* ExtractDataTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 968C40C91B586227004C128E /* ExtractDataTests.m */; }; + 968C40CC1B586253004C128E /* PerformOnFilesTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 968C40CB1B586253004C128E /* PerformOnFilesTests.m */; }; + 968C40CE1B586277004C128E /* PerformOnDataTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 968C40CD1B586277004C128E /* PerformOnDataTests.m */; }; + 968C40D01B5862A0004C128E /* ExtractBufferedDataTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 968C40CF1B5862A0004C128E /* ExtractBufferedDataTests.m */; }; + 968C40D21B586310004C128E /* PasswordProtectionTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 968C40D11B586310004C128E /* PasswordProtectionTests.m */; }; + 968C40D41B586345004C128E /* WriteBufferedDataTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 968C40D31B586345004C128E /* WriteBufferedDataTests.m */; }; + 968C40D61B586380004C128E /* DeleteFileTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 968C40D51B586380004C128E /* DeleteFileTests.m */; }; + 968C40D81B5863A9004C128E /* ErrorHandlingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 968C40D71B5863A9004C128E /* ErrorHandlingTests.m */; }; + 968C40DA1B5863D9004C128E /* FileDescriptorUsageTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 968C40D91B5863D9004C128E /* FileDescriptorUsageTests.m */; }; + 968C40DC1B586401004C128E /* CommentsTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 968C40DB1B586401004C128E /* CommentsTests.m */; }; + 968C40DE1B58642C004C128E /* MultithreadingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 968C40DD1B58642C004C128E /* MultithreadingTests.m */; }; + 968C40E01B586490004C128E /* PropertyTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 968C40DF1B586490004C128E /* PropertyTests.m */; }; + 969993971BE3BA9C003D18DA /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 969993951BE3BA89003D18DA /* libz.tbd */; }; + 969993981BE3BB0C003D18DA /* libz.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 969993951BE3BA89003D18DA /* libz.tbd */; }; + 96EA65A41A40AEAE00685B6D /* UnzipKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 96EA65A31A40AEAE00685B6D /* UnzipKit.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 96EA65AA1A40AEAE00685B6D /* UnzipKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96EA659E1A40AEAE00685B6D /* UnzipKit.framework */; }; + 96EA65BC1A40B2EC00685B6D /* UZKArchive.h in Headers */ = {isa = PBXBuildFile; fileRef = 96EA65BA1A40B2EC00685B6D /* UZKArchive.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 96EA65BD1A40B2EC00685B6D /* UZKArchive.m in Sources */ = {isa = PBXBuildFile; fileRef = 96EA65BB1A40B2EC00685B6D /* UZKArchive.m */; settings = {COMPILER_FLAGS = "-Wno-format-nonliteral"; }; }; + 96EA65C01A40BF1A00685B6D /* Test Data in Resources */ = {isa = PBXBuildFile; fileRef = 96EA65BF1A40BF1A00685B6D /* Test Data */; }; + 96EA66011A40E31900685B6D /* UZKFileInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 96EA65FF1A40E31900685B6D /* UZKFileInfo.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 96EA66021A40E31900685B6D /* UZKFileInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 96EA66001A40E31900685B6D /* UZKFileInfo.m */; }; + 96FCC8411B306CDD00726AC7 /* UZKArchiveTestCase.m in Sources */ = {isa = PBXBuildFile; fileRef = 96FCC8401B306CDD00726AC7 /* UZKArchiveTestCase.m */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 7ACC4CC11F7E7793001A07F6 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 96EA65951A40AEAE00685B6D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 962F9D9D1D5D281E00205BEC; + remoteInfo = UnzipKitResources; + }; + 96EA65AB1A40AEAE00685B6D /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 96EA65951A40AEAE00685B6D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 96EA659D1A40AEAE00685B6D; + remoteInfo = UnzipKit; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXFileReference section */ + 7A0029171F93DB5800618503 /* libminizip.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libminizip.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 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 = ""; }; + 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 = ""; }; + 962F9D9E1D5D281E00205BEC /* UnzipKitResources.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnzipKitResources.bundle; sourceTree = BUILT_PRODUCTS_DIR; }; + 962F9DA01D5D281E00205BEC /* UnzipKitResources-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "UnzipKitResources-Info.plist"; sourceTree = ""; }; + 9630C0371C6D27A4000693EE /* ExtractDataTests_Swift.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ExtractDataTests_Swift.swift; sourceTree = ""; }; + 963386B71EE89A49006B16BF /* UtilityMethods.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UtilityMethods.swift; sourceTree = ""; }; + 963603521BFB7F6500BF0C4F /* UZKFileInfo_Private.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UZKFileInfo_Private.h; sourceTree = ""; }; + 965CF0081D241A8F00C80A88 /* NSURL+UnzipKitExtensions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURL+UnzipKitExtensions.h"; sourceTree = ""; }; + 965CF0091D241A8F00C80A88 /* NSURL+UnzipKitExtensions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURL+UnzipKitExtensions.m"; sourceTree = ""; }; + 9677858D1F1405DB00A8D6B2 /* UnzipKitMacros.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UnzipKitMacros.h; sourceTree = ""; }; + 96889EED1E4A09EC0031A322 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/UnzipKit.strings; sourceTree = ""; }; + 968C40BF1B585FDE004C128E /* ModesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ModesTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 968C40C11B586132004C128E /* ZipFileDetectionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ZipFileDetectionTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 968C40C31B58619C004C128E /* ListFilenamesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ListFilenamesTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 968C40C51B5861C3004C128E /* ListFileInfoTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ListFileInfoTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 968C40C71B5861F4004C128E /* ExtractFilesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ExtractFilesTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 968C40C91B586227004C128E /* ExtractDataTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ExtractDataTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 968C40CB1B586253004C128E /* PerformOnFilesTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PerformOnFilesTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 968C40CD1B586277004C128E /* PerformOnDataTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PerformOnDataTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 968C40CF1B5862A0004C128E /* ExtractBufferedDataTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ExtractBufferedDataTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 968C40D11B586310004C128E /* PasswordProtectionTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PasswordProtectionTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 968C40D31B586345004C128E /* WriteBufferedDataTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = WriteBufferedDataTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 968C40D51B586380004C128E /* DeleteFileTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = DeleteFileTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 968C40D71B5863A9004C128E /* ErrorHandlingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = ErrorHandlingTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 968C40D91B5863D9004C128E /* FileDescriptorUsageTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = FileDescriptorUsageTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 968C40DB1B586401004C128E /* CommentsTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = CommentsTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 968C40DD1B58642C004C128E /* MultithreadingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = MultithreadingTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 968C40DF1B586490004C128E /* PropertyTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = PropertyTests.m; sourceTree = ""; xcLanguageSpecificationIdentifier = xcode.lang.objc; }; + 969993951BE3BA89003D18DA /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.1.sdk/usr/lib/libz.tbd; sourceTree = DEVELOPER_DIR; }; + 96DC15C01C5FFAA800B71F19 /* DTPerformanceSession.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DTPerformanceSession.framework; path = Library/Frameworks/DTPerformanceSession.framework; sourceTree = DEVELOPER_DIR; }; + 96EA659E1A40AEAE00685B6D /* UnzipKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = UnzipKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 96EA65A21A40AEAE00685B6D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 96EA65A31A40AEAE00685B6D /* UnzipKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; lineEnding = 0; path = UnzipKit.h; sourceTree = ""; }; + 96EA65A91A40AEAE00685B6D /* UnzipKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnzipKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 96EA65AF1A40AEAE00685B6D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 96EA65BA1A40B2EC00685B6D /* UZKArchive.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UZKArchive.h; sourceTree = ""; }; + 96EA65BB1A40B2EC00685B6D /* UZKArchive.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; lineEnding = 0; path = UZKArchive.m; sourceTree = ""; }; + 96EA65BF1A40BF1A00685B6D /* Test Data */ = {isa = PBXFileReference; lastKnownFileType = folder; path = "Test Data"; sourceTree = ""; }; + 96EA65C31A40C44300685B6D /* ioapi.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = ioapi.c; sourceTree = ""; }; + 96EA65C41A40C44300685B6D /* ioapi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ioapi.h; sourceTree = ""; }; + 96EA65C51A40C44300685B6D /* mztools.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = mztools.c; sourceTree = ""; }; + 96EA65C61A40C44300685B6D /* mztools.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mztools.h; sourceTree = ""; }; + 96EA65C71A40C44300685B6D /* unzip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = unzip.c; sourceTree = ""; }; + 96EA65C81A40C44300685B6D /* unzip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = unzip.h; sourceTree = ""; }; + 96EA65C91A40C44300685B6D /* zip.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = zip.c; sourceTree = ""; }; + 96EA65CA1A40C44300685B6D /* zip.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = zip.h; sourceTree = ""; }; + 96EA65FF1A40E31900685B6D /* UZKFileInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UZKFileInfo.h; sourceTree = ""; }; + 96EA66001A40E31900685B6D /* UZKFileInfo.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UZKFileInfo.m; sourceTree = ""; }; + 96EA66031A435D8200685B6D /* crypt.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = crypt.h; sourceTree = ""; }; + 96FCC8401B306CDD00726AC7 /* UZKArchiveTestCase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = UZKArchiveTestCase.m; sourceTree = ""; }; + 96FFB3FC1E1EC35900CCA47B /* libz.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libz.tbd; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/usr/lib/libz.tbd; sourceTree = DEVELOPER_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 7A0029141F93DB5800618503 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 962F9D9B1D5D281E00205BEC /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 96EA659A1A40AEAE00685B6D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 7A0029241F93DBF000618503 /* libminizip.a in Frameworks */, + 969993971BE3BA9C003D18DA /* libz.tbd in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 96EA65A61A40AEAE00685B6D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 96EA65AA1A40AEAE00685B6D /* UnzipKit.framework in Frameworks */, + 969993981BE3BB0C003D18DA /* libz.tbd in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 962F9D9F1D5D281E00205BEC /* UnzipKitResources */ = { + isa = PBXGroup; + children = ( + 962F9DA41D5D286B00205BEC /* UnzipKit.strings */, + 962F9DA01D5D281E00205BEC /* UnzipKitResources-Info.plist */, + ); + name = UnzipKitResources; + path = Resources; + sourceTree = ""; + }; + 965CF0071D241A0100C80A88 /* Extensions */ = { + isa = PBXGroup; + children = ( + 965CF0081D241A8F00C80A88 /* NSURL+UnzipKitExtensions.h */, + 965CF0091D241A8F00C80A88 /* NSURL+UnzipKitExtensions.m */, + ); + path = Extensions; + sourceTree = ""; + }; + 96EA65941A40AEAE00685B6D = { + isa = PBXGroup; + children = ( + 96EA65A01A40AEAE00685B6D /* UnzipKit */, + 96EA65AD1A40AEAE00685B6D /* UnzipKitTests */, + 962F9D9F1D5D281E00205BEC /* UnzipKitResources */, + 96EA65C11A40C44300685B6D /* Lib */, + 96EA65F61A40C86200685B6D /* Frameworks */, + 96EA659F1A40AEAE00685B6D /* Products */, + ); + sourceTree = ""; + }; + 96EA659F1A40AEAE00685B6D /* Products */ = { + isa = PBXGroup; + children = ( + 96EA659E1A40AEAE00685B6D /* UnzipKit.framework */, + 96EA65A91A40AEAE00685B6D /* UnzipKitTests.xctest */, + 962F9D9E1D5D281E00205BEC /* UnzipKitResources.bundle */, + 7A0029171F93DB5800618503 /* libminizip.a */, + ); + name = Products; + sourceTree = ""; + }; + 96EA65A01A40AEAE00685B6D /* UnzipKit */ = { + isa = PBXGroup; + children = ( + 965CF0071D241A0100C80A88 /* Extensions */, + 96EA65A31A40AEAE00685B6D /* UnzipKit.h */, + 9677858D1F1405DB00A8D6B2 /* UnzipKitMacros.h */, + 96EA65BA1A40B2EC00685B6D /* UZKArchive.h */, + 96EA65BB1A40B2EC00685B6D /* UZKArchive.m */, + 96EA65FF1A40E31900685B6D /* UZKFileInfo.h */, + 963603521BFB7F6500BF0C4F /* UZKFileInfo_Private.h */, + 96EA66001A40E31900685B6D /* UZKFileInfo.m */, + 96EA65A11A40AEAE00685B6D /* Supporting Files */, + ); + name = UnzipKit; + path = Source; + sourceTree = ""; + }; + 96EA65A11A40AEAE00685B6D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 96EA65A21A40AEAE00685B6D /* Info.plist */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 96EA65AD1A40AEAE00685B6D /* UnzipKitTests */ = { + isa = PBXGroup; + children = ( + 96EA65BF1A40BF1A00685B6D /* Test Data */, + 961A9BB61B306902007C4C6B /* UZKArchiveTestCase.h */, + 96FCC8401B306CDD00726AC7 /* UZKArchiveTestCase.m */, + 963386B71EE89A49006B16BF /* UtilityMethods.swift */, + 7A5652231F90E01C006B782E /* CheckDataTests.m */, + 968C40DB1B586401004C128E /* CommentsTests.m */, + 968C40D51B586380004C128E /* DeleteFileTests.m */, + 968C40D71B5863A9004C128E /* ErrorHandlingTests.m */, + 968C40CF1B5862A0004C128E /* ExtractBufferedDataTests.m */, + 968C40C91B586227004C128E /* ExtractDataTests.m */, + 9630C0371C6D27A4000693EE /* ExtractDataTests_Swift.swift */, + 968C40C71B5861F4004C128E /* ExtractFilesTests.m */, + 7A5A97001F89808900BCA061 /* ProgressReportingTests.m */, + 968C40D91B5863D9004C128E /* FileDescriptorUsageTests.m */, + 968C40C31B58619C004C128E /* ListFilenamesTests.m */, + 968C40C51B5861C3004C128E /* ListFileInfoTests.m */, + 968C40BF1B585FDE004C128E /* ModesTests.m */, + 968C40DD1B58642C004C128E /* MultithreadingTests.m */, + 968C40D11B586310004C128E /* PasswordProtectionTests.m */, + 968C40CD1B586277004C128E /* PerformOnDataTests.m */, + 968C40CB1B586253004C128E /* PerformOnFilesTests.m */, + 7AA77FC722C16CF600121052 /* PermissionsTests.swift */, + 968C40DF1B586490004C128E /* PropertyTests.m */, + 968C40D31B586345004C128E /* WriteBufferedDataTests.m */, + 961A9BB41B306881007C4C6B /* WriteDataTests.swift */, + 968C40C11B586132004C128E /* ZipFileDetectionTests.m */, + 96EA65AE1A40AEAE00685B6D /* Supporting Files */, + ); + name = UnzipKitTests; + path = Tests; + sourceTree = ""; + }; + 96EA65AE1A40AEAE00685B6D /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 96EA65AF1A40AEAE00685B6D /* Info.plist */, + 961A9BB31B306880007C4C6B /* UnzipKitTests-Bridging-Header.h */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + 96EA65C11A40C44300685B6D /* Lib */ = { + isa = PBXGroup; + children = ( + 96EA65C21A40C44300685B6D /* MiniZip */, + ); + path = Lib; + sourceTree = ""; + }; + 96EA65C21A40C44300685B6D /* MiniZip */ = { + isa = PBXGroup; + children = ( + 96EA66031A435D8200685B6D /* crypt.h */, + 96EA65C31A40C44300685B6D /* ioapi.c */, + 96EA65C41A40C44300685B6D /* ioapi.h */, + 96EA65C51A40C44300685B6D /* mztools.c */, + 96EA65C61A40C44300685B6D /* mztools.h */, + 96EA65C71A40C44300685B6D /* unzip.c */, + 96EA65C81A40C44300685B6D /* unzip.h */, + 96EA65C91A40C44300685B6D /* zip.c */, + 96EA65CA1A40C44300685B6D /* zip.h */, + ); + path = MiniZip; + sourceTree = ""; + }; + 96EA65F61A40C86200685B6D /* Frameworks */ = { + isa = PBXGroup; + children = ( + 96FFB3FC1E1EC35900CCA47B /* libz.tbd */, + 96DC15C01C5FFAA800B71F19 /* DTPerformanceSession.framework */, + 969993951BE3BA89003D18DA /* libz.tbd */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 7A0029151F93DB5800618503 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 7A00291F1F93DBC900618503 /* crypt.h in Headers */, + 7A0029201F93DBC900618503 /* ioapi.h in Headers */, + 7A0029211F93DBC900618503 /* mztools.h in Headers */, + 7A0029221F93DBC900618503 /* unzip.h in Headers */, + 7A0029231F93DBC900618503 /* zip.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 96EA659B1A40AEAE00685B6D /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 96EA65BC1A40B2EC00685B6D /* UZKArchive.h in Headers */, + 96EA66011A40E31900685B6D /* UZKFileInfo.h in Headers */, + 96EA65A41A40AEAE00685B6D /* UnzipKit.h in Headers */, + 963603531BFB815600BF0C4F /* UZKFileInfo_Private.h in Headers */, + 9677858E1F1405F000A8D6B2 /* UnzipKitMacros.h in Headers */, + 965CF00A1D241A8F00C80A88 /* NSURL+UnzipKitExtensions.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 7A0029161F93DB5800618503 /* minizip */ = { + isa = PBXNativeTarget; + buildConfigurationList = 7A0029181F93DB5800618503 /* Build configuration list for PBXNativeTarget "minizip" */; + buildPhases = ( + 7A0029131F93DB5800618503 /* Sources */, + 7A0029141F93DB5800618503 /* Frameworks */, + 7A0029151F93DB5800618503 /* Headers */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = minizip; + productName = minizip; + productReference = 7A0029171F93DB5800618503 /* libminizip.a */; + productType = "com.apple.product-type.library.static"; + }; + 962F9D9D1D5D281E00205BEC /* UnzipKitResources */ = { + isa = PBXNativeTarget; + buildConfigurationList = 962F9DA11D5D281E00205BEC /* Build configuration list for PBXNativeTarget "UnzipKitResources" */; + buildPhases = ( + 962F9D9A1D5D281E00205BEC /* Sources */, + 962F9D9B1D5D281E00205BEC /* Frameworks */, + 962F9D9C1D5D281E00205BEC /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = UnzipKitResources; + productName = UnzipKitResources; + productReference = 962F9D9E1D5D281E00205BEC /* UnzipKitResources.bundle */; + productType = "com.apple.product-type.bundle"; + }; + 96EA659D1A40AEAE00685B6D /* UnzipKit */ = { + isa = PBXNativeTarget; + buildConfigurationList = 96EA65B41A40AEAE00685B6D /* Build configuration list for PBXNativeTarget "UnzipKit" */; + buildPhases = ( + 96EA65991A40AEAE00685B6D /* Sources */, + 96EA659A1A40AEAE00685B6D /* Frameworks */, + 96EA659B1A40AEAE00685B6D /* Headers */, + 96EA659C1A40AEAE00685B6D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 7ACC4CC21F7E7793001A07F6 /* PBXTargetDependency */, + ); + name = UnzipKit; + productName = UnzipKit; + productReference = 96EA659E1A40AEAE00685B6D /* UnzipKit.framework */; + productType = "com.apple.product-type.framework"; + }; + 96EA65A81A40AEAE00685B6D /* UnzipKitTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 96EA65B71A40AEAE00685B6D /* Build configuration list for PBXNativeTarget "UnzipKitTests" */; + buildPhases = ( + 96EA65A51A40AEAE00685B6D /* Sources */, + 96EA65A61A40AEAE00685B6D /* Frameworks */, + 96EA65A71A40AEAE00685B6D /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 96EA65AC1A40AEAE00685B6D /* PBXTargetDependency */, + ); + name = UnzipKitTests; + productName = UnzipKitTests; + productReference = 96EA65A91A40AEAE00685B6D /* UnzipKitTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 96EA65951A40AEAE00685B6D /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftMigration = 0700; + LastSwiftUpdateCheck = 0720; + LastUpgradeCheck = 0930; + ORGANIZATIONNAME = "Abbey Code"; + TargetAttributes = { + 7A0029161F93DB5800618503 = { + CreatedOnToolsVersion = 9.0; + ProvisioningStyle = Automatic; + }; + 962F9D9D1D5D281E00205BEC = { + CreatedOnToolsVersion = 7.3.1; + }; + 96EA659D1A40AEAE00685B6D = { + CreatedOnToolsVersion = 6.1.1; + LastSwiftMigration = 0830; + }; + 96EA65A81A40AEAE00685B6D = { + CreatedOnToolsVersion = 6.1.1; + LastSwiftMigration = 0900; + }; + }; + }; + buildConfigurationList = 96EA65981A40AEAE00685B6D /* Build configuration list for PBXProject "UnzipKit" */; + compatibilityVersion = "Xcode 8.0"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + base, + ); + mainGroup = 96EA65941A40AEAE00685B6D; + productRefGroup = 96EA659F1A40AEAE00685B6D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 96EA659D1A40AEAE00685B6D /* UnzipKit */, + 96EA65A81A40AEAE00685B6D /* UnzipKitTests */, + 962F9D9D1D5D281E00205BEC /* UnzipKitResources */, + 7A0029161F93DB5800618503 /* minizip */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 962F9D9C1D5D281E00205BEC /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 962F9DA61D5D286B00205BEC /* UnzipKit.strings in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 96EA659C1A40AEAE00685B6D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 962F9DA81D5D288B00205BEC /* UnzipKitResources.bundle in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 96EA65A71A40AEAE00685B6D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 96EA65C01A40BF1A00685B6D /* Test Data in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 7A0029131F93DB5800618503 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 7A00291B1F93DB9200618503 /* ioapi.c in Sources */, + 7A00291D1F93DB9200618503 /* unzip.c in Sources */, + 7A00291E1F93DB9200618503 /* zip.c in Sources */, + 7A00291C1F93DB9200618503 /* mztools.c in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 962F9D9A1D5D281E00205BEC /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 96EA65991A40AEAE00685B6D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 96EA65BD1A40B2EC00685B6D /* UZKArchive.m in Sources */, + 96EA66021A40E31900685B6D /* UZKFileInfo.m in Sources */, + 965CF00C1D241A8F00C80A88 /* NSURL+UnzipKitExtensions.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 96EA65A51A40AEAE00685B6D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 968C40C41B58619C004C128E /* ListFilenamesTests.m in Sources */, + 968C40D81B5863A9004C128E /* ErrorHandlingTests.m in Sources */, + 968C40DE1B58642C004C128E /* MultithreadingTests.m in Sources */, + 968C40D61B586380004C128E /* DeleteFileTests.m in Sources */, + 96FCC8411B306CDD00726AC7 /* UZKArchiveTestCase.m in Sources */, + 7A5A97011F89808900BCA061 /* ProgressReportingTests.m in Sources */, + 968C40C21B586132004C128E /* ZipFileDetectionTests.m in Sources */, + 968C40D41B586345004C128E /* WriteBufferedDataTests.m in Sources */, + 968C40CC1B586253004C128E /* PerformOnFilesTests.m in Sources */, + 968C40CA1B586227004C128E /* ExtractDataTests.m in Sources */, + 9630C0381C6D27A4000693EE /* ExtractDataTests_Swift.swift in Sources */, + 968C40C01B585FDE004C128E /* ModesTests.m in Sources */, + 968C40DA1B5863D9004C128E /* FileDescriptorUsageTests.m in Sources */, + 7A5652241F90E01C006B782E /* CheckDataTests.m in Sources */, + 961A9BB51B306881007C4C6B /* WriteDataTests.swift in Sources */, + 968C40C61B5861C3004C128E /* ListFileInfoTests.m in Sources */, + 968C40E01B586490004C128E /* PropertyTests.m in Sources */, + 968C40DC1B586401004C128E /* CommentsTests.m in Sources */, + 968C40D21B586310004C128E /* PasswordProtectionTests.m in Sources */, + 963386B91EE89A51006B16BF /* UtilityMethods.swift in Sources */, + 7AA77FC822C16CF600121052 /* PermissionsTests.swift in Sources */, + 968C40C81B5861F4004C128E /* ExtractFilesTests.m in Sources */, + 968C40D01B5862A0004C128E /* ExtractBufferedDataTests.m in Sources */, + 968C40CE1B586277004C128E /* PerformOnDataTests.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 7ACC4CC21F7E7793001A07F6 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 962F9D9D1D5D281E00205BEC /* UnzipKitResources */; + targetProxy = 7ACC4CC11F7E7793001A07F6 /* PBXContainerItemProxy */; + }; + 96EA65AC1A40AEAE00685B6D /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 96EA659D1A40AEAE00685B6D /* UnzipKit */; + targetProxy = 96EA65AB1A40AEAE00685B6D /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 962F9DA41D5D286B00205BEC /* UnzipKit.strings */ = { + isa = PBXVariantGroup; + children = ( + 96889EED1E4A09EC0031A322 /* en */, + ); + name = UnzipKit.strings; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 7A0029191F93DB5800618503 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + DEBUG_INFORMATION_FORMAT = dwarf; + EXECUTABLE_PREFIX = lib; + GCC_C_LANGUAGE_STANDARD = c11; + OTHER_CFLAGS = ( + "-Qunused-arguments", + "-Xanalyzer", + "-analyzer-disable-all-checks", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + WARNING_CFLAGS = ( + "-Wno-comma", + "-Wno-strict-prototypes", + ); + }; + name = Debug; + }; + 7A00291A1F93DB5800618503 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_IDENTITY = "-"; + CODE_SIGN_STYLE = Automatic; + COPY_PHASE_STRIP = NO; + EXECUTABLE_PREFIX = lib; + GCC_C_LANGUAGE_STANDARD = c11; + OTHER_CFLAGS = ( + "-Qunused-arguments", + "-Xanalyzer", + "-analyzer-disable-all-checks", + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = macosx; + SKIP_INSTALL = YES; + WARNING_CFLAGS = ( + "-Wno-comma", + "-Wno-strict-prototypes", + ); + }; + name = Release; + }; + 962F9DA21D5D281E00205BEC /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = "Resources/UnzipKitResources-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; + PRODUCT_BUNDLE_IDENTIFIER = "com.abbey-code.UnzipKitResources"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos"; + WRAPPER_EXTENSION = bundle; + }; + name = Debug; + }; + 962F9DA31D5D281E00205BEC /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ANALYZER_NONNULL = YES; + CODE_SIGN_IDENTITY = "-"; + COMBINE_HIDPI_IMAGES = YES; + COPY_PHASE_STRIP = NO; + GCC_NO_COMMON_BLOCKS = YES; + INFOPLIST_FILE = "Resources/UnzipKitResources-Info.plist"; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Bundles"; + PRODUCT_BUNDLE_IDENTIFIER = "com.abbey-code.UnzipKitResources"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos"; + WRAPPER_EXTENSION = bundle; + }; + name = Release; + }; + 96EA65B21A40AEAE00685B6D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MACOSX_DEPLOYMENT_TARGET = 10.12; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos"; + SWIFT_VERSION = 4.0; + WARNING_CFLAGS = ( + "-Weverything", + "-Wno-auto-import", + "-Wno-objc-missing-property-synthesis", + ); + }; + name = Debug; + }; + 96EA65B31A40AEAE00685B6D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ALLOW_NON_MODULAR_INCLUDES_IN_FRAMEWORK_MODULES = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_TREAT_WARNINGS_AS_ERRORS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.0; + MACOSX_DEPLOYMENT_TARGET = 10.12; + MTL_ENABLE_DEBUG_INFO = NO; + SUPPORTED_PLATFORMS = "macosx iphonesimulator iphoneos"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 4.0; + WARNING_CFLAGS = ( + "-Weverything", + "-Wno-auto-import", + "-Wno-objc-missing-property-synthesis", + ); + }; + name = Release; + }; + 96EA65B51A40AEAE00685B6D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = Source/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.abbey-code.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 96EA65B61A40AEAE00685B6D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + DEFINES_MODULE = YES; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + FRAMEWORK_VERSION = A; + INFOPLIST_FILE = Source/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.abbey-code.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; + 96EA65B81A40AEAE00685B6D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + GCC_PREPROCESSOR_DEFINITIONS = "$(inherited)"; + 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)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Tests/UnzipKitTests-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 4.0; + WARNING_CFLAGS = ( + "$(inherited)", + "-Wno-gnu-statement-expression", + "-Wno-non-modular-include-in-framework-module", + "-Wno-reserved-id-macro", + "-Wno-nullable-to-nonnull-conversion", + "-Wno-pointer-arith", + "-Wno-cast-qual", + "-Wno-undef", + ); + }; + name = Debug; + }; + 96EA65B91A40AEAE00685B6D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CLANG_ENABLE_MODULES = YES; + COMBINE_HIDPI_IMAGES = YES; + 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)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Tests/UnzipKitTests-Bridging-Header.h"; + SWIFT_VERSION = 4.0; + WARNING_CFLAGS = ( + "$(inherited)", + "-Wno-everything", + ); + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 7A0029181F93DB5800618503 /* Build configuration list for PBXNativeTarget "minizip" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 7A0029191F93DB5800618503 /* Debug */, + 7A00291A1F93DB5800618503 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 962F9DA11D5D281E00205BEC /* Build configuration list for PBXNativeTarget "UnzipKitResources" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 962F9DA21D5D281E00205BEC /* Debug */, + 962F9DA31D5D281E00205BEC /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 96EA65981A40AEAE00685B6D /* Build configuration list for PBXProject "UnzipKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 96EA65B21A40AEAE00685B6D /* Debug */, + 96EA65B31A40AEAE00685B6D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 96EA65B41A40AEAE00685B6D /* Build configuration list for PBXNativeTarget "UnzipKit" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 96EA65B51A40AEAE00685B6D /* Debug */, + 96EA65B61A40AEAE00685B6D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 96EA65B71A40AEAE00685B6D /* Build configuration list for PBXNativeTarget "UnzipKitTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 96EA65B81A40AEAE00685B6D /* Debug */, + 96EA65B91A40AEAE00685B6D /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 96EA65951A40AEAE00685B6D /* Project object */; +} diff --git a/Carthage/Checkouts/UnzipKit/UnzipKit.xcodeproj/xcshareddata/xcschemes/UnzipKit.xcscheme b/Carthage/Checkouts/UnzipKit/UnzipKit.xcodeproj/xcshareddata/xcschemes/UnzipKit.xcscheme new file mode 100644 index 0000000..7ead498 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKit.xcodeproj/xcshareddata/xcschemes/UnzipKit.xcscheme @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Carthage/Checkouts/UnzipKit/UnzipKit.xcworkspace/contents.xcworkspacedata b/Carthage/Checkouts/UnzipKit/UnzipKit.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..88836c0 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKit.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Carthage/Checkouts/UnzipKit/UnzipKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Carthage/Checkouts/UnzipKit/UnzipKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Carthage/Checkouts/UnzipKit/UnzipKit.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/Carthage/Checkouts/UnzipKit/UnzipKit.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..08de0be --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKit.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded + + + diff --git a/Carthage/Checkouts/UnzipKit/UnzipKitDemo/Podfile b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/Podfile new file mode 100644 index 0000000..4744369 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/Podfile @@ -0,0 +1,5 @@ +platform :ios, '9.0' + +target 'UnzipKitDemo' do + pod "UnzipKit", :path => "..", :testspecs => ['Tests'] +end \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo-Bridging-Header.h b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo-Bridging-Header.h new file mode 100644 index 0000000..b19b89a --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo-Bridging-Header.h @@ -0,0 +1,5 @@ +// +// Use this file to import your target's public headers that you would like to expose to Swift. +// + +#import \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo.xcodeproj/project.pbxproj b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo.xcodeproj/project.pbxproj new file mode 100644 index 0000000..08fa86f --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo.xcodeproj/project.pbxproj @@ -0,0 +1,415 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 9693812B1D209CFA001B2ED8 /* libUnzipKit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 9693812A1D209CFA001B2ED8 /* libUnzipKit.a */; }; + 969E2FE51AD573F100E19F7A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 969E2FE41AD573F100E19F7A /* AppDelegate.swift */; }; + 969E2FE71AD573F100E19F7A /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 969E2FE61AD573F100E19F7A /* ViewController.swift */; }; + 969E2FEA1AD573F100E19F7A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 969E2FE81AD573F100E19F7A /* Main.storyboard */; }; + 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 */; }; +/* 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; }; + 969E2FE31AD573F100E19F7A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 969E2FE41AD573F100E19F7A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 969E2FE61AD573F100E19F7A /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 969E2FE91AD573F100E19F7A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 969E2FEB1AD573F100E19F7A /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; + 969E2FEE1AD573F100E19F7A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; + 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 = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 969E2FDC1AD573F100E19F7A /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 9693812B1D209CFA001B2ED8 /* libUnzipKit.a in Frameworks */, + D058D1B1EDCAA17D37F1EEC5 /* libPods-UnzipKitDemo.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 11FBF2BE09A55AC8F2F375BC /* Pods */ = { + isa = PBXGroup; + children = ( + 2F87D9A1D0DCA68C622CCE05 /* Pods-UnzipKitDemo.debug.xcconfig */, + D07031CAE5D79F16E6A159A8 /* Pods-UnzipKitDemo.release.xcconfig */, + ); + name = Pods; + sourceTree = ""; + }; + 969E2FD61AD573F100E19F7A = { + isa = PBXGroup; + children = ( + 969E2FE11AD573F100E19F7A /* UnzipKitDemo */, + 969E2FE01AD573F100E19F7A /* Products */, + BCCBCB74C65B47019CC35EFC /* Frameworks */, + 11FBF2BE09A55AC8F2F375BC /* Pods */, + ); + sourceTree = ""; + }; + 969E2FE01AD573F100E19F7A /* Products */ = { + isa = PBXGroup; + children = ( + 969E2FDF1AD573F100E19F7A /* UnzipKitDemo.app */, + ); + name = Products; + sourceTree = ""; + }; + 969E2FE11AD573F100E19F7A /* UnzipKitDemo */ = { + isa = PBXGroup; + children = ( + 969E2FE41AD573F100E19F7A /* AppDelegate.swift */, + 969E2FE61AD573F100E19F7A /* ViewController.swift */, + 969E2FE81AD573F100E19F7A /* Main.storyboard */, + 969E2FEB1AD573F100E19F7A /* Images.xcassets */, + 969E2FED1AD573F100E19F7A /* LaunchScreen.xib */, + 969E2FE21AD573F100E19F7A /* Supporting Files */, + ); + path = UnzipKitDemo; + sourceTree = ""; + }; + 969E2FE21AD573F100E19F7A /* Supporting Files */ = { + isa = PBXGroup; + children = ( + 969E2FE31AD573F100E19F7A /* Info.plist */, + 969E30081AD57BD000E19F7A /* Test Data */, + 969E30041AD5798D00E19F7A /* UnzipKitDemo-Bridging-Header.h */, + ); + name = "Supporting Files"; + sourceTree = ""; + }; + BCCBCB74C65B47019CC35EFC /* Frameworks */ = { + isa = PBXGroup; + children = ( + 9693812A1D209CFA001B2ED8 /* libUnzipKit.a */, + 969381281D209CF5001B2ED8 /* libPods-UnzipKitDemo.a */, + 836C8D3D2EBCC1B567DEBA7E /* libPods-UnzipKitDemo.a */, + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 969E2FDE1AD573F100E19F7A /* UnzipKitDemo */ = { + isa = PBXNativeTarget; + buildConfigurationList = 969E2FFE1AD573F100E19F7A /* Build configuration list for PBXNativeTarget "UnzipKitDemo" */; + buildPhases = ( + B139D6CA2A478F810C88A74D /* [CP] Check Pods Manifest.lock */, + 969E2FDB1AD573F100E19F7A /* Sources */, + 969E2FDC1AD573F100E19F7A /* Frameworks */, + 969E2FDD1AD573F100E19F7A /* Resources */, + FFBBDB5F70B02F25F7B1C9FA /* [CP] Copy Pods Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = UnzipKitDemo; + productName = UnzipKitDemo; + productReference = 969E2FDF1AD573F100E19F7A /* UnzipKitDemo.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 969E2FD71AD573F100E19F7A /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0700; + LastUpgradeCheck = 0930; + ORGANIZATIONNAME = "Abbey Code"; + TargetAttributes = { + 969E2FDE1AD573F100E19F7A = { + CreatedOnToolsVersion = 6.3; + LastSwiftMigration = 0820; + }; + }; + }; + buildConfigurationList = 969E2FDA1AD573F100E19F7A /* Build configuration list for PBXProject "UnzipKitDemo" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 969E2FD61AD573F100E19F7A; + productRefGroup = 969E2FE01AD573F100E19F7A /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 969E2FDE1AD573F100E19F7A /* UnzipKitDemo */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 969E2FDD1AD573F100E19F7A /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 969E2FEA1AD573F100E19F7A /* Main.storyboard in Resources */, + 969E2FEF1AD573F100E19F7A /* LaunchScreen.xib in Resources */, + 969E2FEC1AD573F100E19F7A /* Images.xcassets in Resources */, + 969E30091AD57BD000E19F7A /* Test Data in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + B139D6CA2A478F810C88A74D /* [CP] Check Pods Manifest.lock */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${PODS_PODFILE_DIR_PATH}/Podfile.lock", + "${PODS_ROOT}/Manifest.lock", + ); + name = "[CP] Check Pods Manifest.lock"; + outputPaths = ( + "$(DERIVED_FILE_DIR)/Pods-UnzipKitDemo-checkManifestLockResult.txt", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + 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 */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${SRCROOT}/Pods/Target Support Files/Pods-UnzipKitDemo/Pods-UnzipKitDemo-resources.sh", + "${PODS_CONFIGURATION_BUILD_DIR}/UnzipKit/UnzipKitResources.bundle", + ); + name = "[CP] Copy Pods Resources"; + outputPaths = ( + "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}/UnzipKitResources.bundle", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-UnzipKitDemo/Pods-UnzipKitDemo-resources.sh\"\n"; + showEnvVarsInLog = 0; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 969E2FDB1AD573F100E19F7A /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 969E2FE71AD573F100E19F7A /* ViewController.swift in Sources */, + 969E2FE51AD573F100E19F7A /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXVariantGroup section */ + 969E2FE81AD573F100E19F7A /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 969E2FE91AD573F100E19F7A /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 969E2FED1AD573F100E19F7A /* LaunchScreen.xib */ = { + isa = PBXVariantGroup; + children = ( + 969E2FEE1AD573F100E19F7A /* Base */, + ); + name = LaunchScreen.xib; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 969E2FFC1AD573F100E19F7A /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = NO; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 969E2FFD1AD573F100E19F7A /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 9.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_VERSION = 3.0; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 969E2FFF1AD573F100E19F7A /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 2F87D9A1D0DCA68C622CCE05 /* Pods-UnzipKitDemo.debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CLANG_ENABLE_MODULES = YES; + INFOPLIST_FILE = UnzipKitDemo/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.abbey-code.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "UnzipKitDemo-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + 969E30001AD573F100E19F7A /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = D07031CAE5D79F16E6A159A8 /* Pods-UnzipKitDemo.release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; + CLANG_ENABLE_MODULES = YES; + INFOPLIST_FILE = UnzipKitDemo/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.abbey-code.$(PRODUCT_NAME:rfc1034identifier)"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "UnzipKitDemo-Bridging-Header.h"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 969E2FDA1AD573F100E19F7A /* Build configuration list for PBXProject "UnzipKitDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 969E2FFC1AD573F100E19F7A /* Debug */, + 969E2FFD1AD573F100E19F7A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 969E2FFE1AD573F100E19F7A /* Build configuration list for PBXNativeTarget "UnzipKitDemo" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 969E2FFF1AD573F100E19F7A /* Debug */, + 969E30001AD573F100E19F7A /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 969E2FD71AD573F100E19F7A /* Project object */; +} diff --git a/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..b47e12a --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo.xcodeproj/xcshareddata/xcschemes/UnzipKitDemo.xcscheme b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo.xcodeproj/xcshareddata/xcschemes/UnzipKitDemo.xcscheme new file mode 100644 index 0000000..c4cbc20 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo.xcodeproj/xcshareddata/xcschemes/UnzipKitDemo.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo.xcworkspace/contents.xcworkspacedata b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..280ac5e --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,10 @@ + + + + + + + diff --git a/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/AppDelegate.swift b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/AppDelegate.swift new file mode 100644 index 0000000..14d82be --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/AppDelegate.swift @@ -0,0 +1,46 @@ +// +// AppDelegate.swift +// UnzipKitDemo +// +// Created by Dov Frankel on 4/8/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + func applicationWillResignActive(_ application: UIApplication) { + // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. + // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. + } + + func applicationDidEnterBackground(_ application: UIApplication) { + // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. + // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. + } + + func applicationWillEnterForeground(_ application: UIApplication) { + // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. + } + + func applicationDidBecomeActive(_ application: UIApplication) { + // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. + } + + func applicationWillTerminate(_ application: UIApplication) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + +} + diff --git a/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/Base.lproj/LaunchScreen.xib b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/Base.lproj/LaunchScreen.xib new file mode 100644 index 0000000..3187ce8 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/Base.lproj/LaunchScreen.xib @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/Base.lproj/Main.storyboard b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/Base.lproj/Main.storyboard new file mode 100644 index 0000000..2384bbd --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/Base.lproj/Main.storyboard @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/Images.xcassets/AppIcon.appiconset/Contents.json b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/Images.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d8db8d6 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/Images.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,98 @@ +{ + "images" : [ + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "20x20", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "29x29", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "40x40", + "scale" : "3x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "2x" + }, + { + "idiom" : "iphone", + "size" : "60x60", + "scale" : "3x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "20x20", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "29x29", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "40x40", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "1x" + }, + { + "idiom" : "ipad", + "size" : "76x76", + "scale" : "2x" + }, + { + "idiom" : "ipad", + "size" : "83.5x83.5", + "scale" : "2x" + }, + { + "idiom" : "ios-marketing", + "size" : "1024x1024", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/Images.xcassets/LaunchImage.launchimage/Contents.json b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/Images.xcassets/LaunchImage.launchimage/Contents.json new file mode 100644 index 0000000..a0ad363 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/Images.xcassets/LaunchImage.launchimage/Contents.json @@ -0,0 +1,36 @@ +{ + "images" : [ + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "1x" + }, + { + "orientation" : "portrait", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + }, + { + "orientation" : "landscape", + "idiom" : "ipad", + "extent" : "full-screen", + "minimum-system-version" : "7.0", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/Info.plist b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/Info.plist new file mode 100644 index 0000000..40c6215 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/Info.plist @@ -0,0 +1,47 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/ViewController.swift b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/ViewController.swift new file mode 100644 index 0000000..23cb950 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/UnzipKitDemo/UnzipKitDemo/ViewController.swift @@ -0,0 +1,39 @@ +// +// ViewController.swift +// UnzipKitDemo +// +// Created by Dov Frankel on 4/8/15. +// Copyright (c) 2015 Abbey Code. All rights reserved. +// + +import UIKit + +class ViewController: UIViewController { + + @IBOutlet weak var textView: UITextView! + + override func viewDidLoad() { + super.viewDidLoad() + + textView.text = nil + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + @IBAction func listFiles(_ sender: AnyObject) { + let fileURL = Bundle.main.url(forResource: "Test Data/Test Archive", withExtension: "zip")! + + do { + let archive = try! UZKArchive(url: fileURL) + let filesList = try archive.listFilenames() + self.textView.text = filesList.joined(separator: "\n") + } catch let error as NSError { + self.textView.text = error.localizedDescription + } + } + +} + diff --git a/Carthage/Checkouts/UnzipKit/beta-notes.md b/Carthage/Checkouts/UnzipKit/beta-notes.md new file mode 100644 index 0000000..e908b45 --- /dev/null +++ b/Carthage/Checkouts/UnzipKit/beta-notes.md @@ -0,0 +1 @@ +Added support for archiving and restoring files' POSIX permissions (PRs #84, #86, #87 - Thanks, [@MartinLau7](https://github.com/MartinLau7)!) \ No newline at end of file diff --git a/QuietUnrar.xcodeproj/project.pbxproj b/QuietUnrar.xcodeproj/project.pbxproj index 72f3147..daec819 100644 --- a/QuietUnrar.xcodeproj/project.pbxproj +++ b/QuietUnrar.xcodeproj/project.pbxproj @@ -20,6 +20,9 @@ E2A3B83E265EA8B900A6C0A3 /* UnrarKit.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = E2A3B83B265EA8B800A6C0A3 /* UnrarKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; E2A3B83F265EA8B900A6C0A3 /* UnzipKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E2A3B83C265EA8B800A6C0A3 /* UnzipKit.framework */; }; E2A3B840265EA8B900A6C0A3 /* UnzipKit.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = E2A3B83C265EA8B800A6C0A3 /* UnzipKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + E2A3B843265F199A00A6C0A3 /* Cartfile in Resources */ = {isa = PBXBuildFile; fileRef = E2A3B842265F199A00A6C0A3 /* Cartfile */; }; + E2A3B845265F1AA900A6C0A3 /* DockProgress.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E2A3B844265F1AA800A6C0A3 /* DockProgress.framework */; }; + E2A3B846265F1AA900A6C0A3 /* DockProgress.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = E2A3B844265F1AA800A6C0A3 /* DockProgress.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -39,6 +42,7 @@ dstPath = ""; dstSubfolderSpec = 10; files = ( + E2A3B846265F1AA900A6C0A3 /* DockProgress.framework in CopyFiles */, E2A3B83E265EA8B900A6C0A3 /* UnrarKit.framework in CopyFiles */, D488BCC110AF49C700B3451C /* libunrar.so in CopyFiles */, E2A3B840265EA8B900A6C0A3 /* UnzipKit.framework in CopyFiles */, @@ -171,6 +175,8 @@ E296811E24BE4BCD00974229 /* en */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = en; path = en.lproj/MainMenu.xib; sourceTree = ""; }; E2A3B83B265EA8B800A6C0A3 /* UnrarKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UnrarKit.framework; path = Carthage/Build/Mac/UnrarKit.framework; sourceTree = ""; }; E2A3B83C265EA8B800A6C0A3 /* UnzipKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UnzipKit.framework; path = Carthage/Build/Mac/UnzipKit.framework; sourceTree = ""; }; + E2A3B842265F199A00A6C0A3 /* Cartfile */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Cartfile; sourceTree = ""; }; + E2A3B844265F1AA800A6C0A3 /* DockProgress.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DockProgress.framework; path = Carthage/Build/Mac/DockProgress.framework; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -180,6 +186,7 @@ files = ( D488BC6810AF437B00B3451C /* libunrar.so in Frameworks */, 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, + E2A3B845265F1AA900A6C0A3 /* DockProgress.framework in Frameworks */, E2A3B83D265EA8B900A6C0A3 /* UnrarKit.framework in Frameworks */, D4A96E2110545E9A0091ECB4 /* Carbon.framework in Frameworks */, E2A3B83F265EA8B900A6C0A3 /* UnzipKit.framework in Frameworks */, @@ -250,6 +257,7 @@ 29B97317FDCFA39411CA2CEA /* Resources */ = { isa = PBXGroup; children = ( + E2A3B842265F199A00A6C0A3 /* Cartfile */, D488BE5410B05F3800B3451C /* PasswordView.xib */, 8D1107310486CEB800E47090 /* QuietUnrar-Info.plist */, 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, @@ -261,6 +269,7 @@ 29B97323FDCFA39411CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( + E2A3B844265F1AA800A6C0A3 /* DockProgress.framework */, E2A3B83B265EA8B800A6C0A3 /* UnrarKit.framework */, E2A3B83C265EA8B800A6C0A3 /* UnzipKit.framework */, D488BC6710AF437B00B3451C /* libunrar.so */, @@ -458,6 +467,7 @@ files = ( D4A49692105435C100BE38AE /* MainMenu.xib in Resources */, D4A49691105435BE00BE38AE /* InfoPlist.strings in Resources */, + E2A3B843265F199A00A6C0A3 /* Cartfile in Resources */, D488BE5510B05F3800B3451C /* PasswordView.xib in Resources */, ); runOnlyForDeploymentPostprocessing = 0;