├── .gitignore ├── COPYING.TXT ├── Demos ├── README.md ├── ZipKit Touch │ ├── ZipKit Touch.xcodeproj │ │ ├── project.pbxproj │ │ └── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── ZipKit Touch.xccheckout │ └── ZipKit Touch │ │ ├── Base.lproj │ │ ├── MainStoryboard_iPad.storyboard │ │ └── MainStoryboard_iPhone.storyboard │ │ ├── Default-568h@2x.png │ │ ├── Default.png │ │ ├── Default@2x.png │ │ ├── Read Me.txt │ │ ├── Settings.bundle │ │ ├── Acknowledgements.plist │ │ ├── Root.plist │ │ └── en.lproj │ │ │ ├── Acknowledgements.strings │ │ │ └── Root.strings │ │ ├── ZKAppDelegate.h │ │ ├── ZKAppDelegate.m │ │ ├── ZKDetailViewController.h │ │ ├── ZKDetailViewController.m │ │ ├── ZKMasterViewController.h │ │ ├── ZKMasterViewController.m │ │ ├── ZipKit Touch-Info.plist │ │ ├── ZipKit.png │ │ ├── ZipKit_Touch.png │ │ ├── en.lproj │ │ └── InfoPlist.strings │ │ └── main.m ├── ZipKit Utility │ ├── Base.lproj │ │ └── MainMenu.xib │ ├── MainWindowController.h │ ├── MainWindowController.m │ ├── RemainingTimeTransformer.h │ ├── RemainingTimeTransformer.m │ ├── ZipFileOperation.h │ ├── ZipFileOperation.m │ ├── ZipKit Utility.xcodeproj │ │ ├── project.pbxproj │ │ └── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ ├── IDEWorkspaceChecks.plist │ │ │ └── ZipKit Utility.xccheckout │ ├── ZipKit.icns │ ├── ZipKit_Utility-Info.plist │ └── main.m └── zku │ ├── zku.m │ └── zku.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ ├── IDEWorkspaceChecks.plist │ └── zku.xccheckout ├── README.md ├── ZipKit Framework.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ ├── IDEWorkspaceChecks.plist │ │ ├── WorkspaceSettings.xcsettings │ │ └── ZipKit.xccheckout └── xcshareddata │ └── xcschemes │ ├── ZipKit.xcscheme │ ├── libtouchzipkit.xcscheme │ └── libzipkit.xcscheme ├── ZipKit.podspec ├── ZipKit.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist └── ZipKit ├── GMAppleDouble+ZKAdditions.h ├── GMAppleDouble+ZKAdditions.m ├── GMAppleDouble.h ├── MacFUSE ├── COPYING.TXT ├── GMAppleDouble.h └── GMAppleDouble.m ├── NSData+ZKAdditions.h ├── NSData+ZKAdditions.m ├── NSDate+ZKAdditions.h ├── NSDate+ZKAdditions.m ├── NSDictionary+ZKAdditions.h ├── NSDictionary+ZKAdditions.m ├── NSFileHandle+ZKAdditions.h ├── NSFileHandle+ZKAdditions.m ├── NSFileManager+ZKAdditions.h ├── NSFileManager+ZKAdditions.m ├── NSString+ZKAdditions.h ├── NSString+ZKAdditions.m ├── ZKArchive.h ├── ZKArchive.m ├── ZKCDHeader.h ├── ZKCDHeader.m ├── ZKCDTrailer.h ├── ZKCDTrailer.m ├── ZKCDTrailer64.h ├── ZKCDTrailer64.m ├── ZKCDTrailer64Locator.h ├── ZKCDTrailer64Locator.m ├── ZKDataArchive.h ├── ZKDataArchive.m ├── ZKDefs.h ├── ZKDefs.m ├── ZKFileArchive.h ├── ZKFileArchive.m ├── ZKLFHeader.h ├── ZKLFHeader.m ├── ZKLog.h ├── ZKLog.m ├── ZipKit-Info.plist └── ZipKit.h /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | profile 14 | *.moved-aside 15 | DerivedData 16 | .idea/ 17 | -------------------------------------------------------------------------------- /COPYING.TXT: -------------------------------------------------------------------------------- 1 | ZipKit is covered under the following BSD-style license: 2 | ================================================================ 3 | Copyright (c) 2009, Karl Moskowski 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are 8 | met: 9 | 10 | * Redistributions of source code must retain the above copyright 11 | notice, this list of conditions and the following disclaimer. 12 | * Redistributions in binary form must reproduce the above 13 | copyright notice, this list of conditions and the following disclaimer 14 | in the documentation and/or other materials provided with the 15 | distribution. 16 | * Neither the name of Karl Moskowski nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 21 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 22 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 23 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 24 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 25 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 26 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 30 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 | ================================================================ 32 | 33 | Acknowledgement using this text is appreciated: 34 | ZipKit developed by Karl Moskowski. 35 | https://kolpanic.github.io/ 36 | 37 | ------------------------------------------------------------------------------------------------ 38 | 39 | The GMAppleDouble class used in this project is part of the MacFUSE project by Google Inc. 40 | 41 | 42 | See the file COPYING.TXT in the MacFUSE folder for license details. 43 | -------------------------------------------------------------------------------- /Demos/README.md: -------------------------------------------------------------------------------- 1 | ZipKit Demo Projects 2 | ============ 3 | 4 | Demo projects for using ZipKit in a macOS application, a macOS command line tool, and an iOS application. 5 | -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch.xcodeproj/project.xcworkspace/xcshareddata/ZipKit Touch.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 1353123E-A861-4E79-A5E3-D9A9ED62FF7E 9 | IDESourceControlProjectName 10 | ZipKit Touch 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 36652C49-72B6-48DE-8764-CBD8011235F9 14 | https://github.com/kolpanic/ZipKit.git 15 | 80B5D05E-133A-4C3C-A2B2-010DDF3C41D1 16 | ssh://github.com/kolpanic/ZipKit-Touch.git 17 | 18 | IDESourceControlProjectPath 19 | ZipKit Touch.xcodeproj/project.xcworkspace 20 | IDESourceControlProjectRelativeInstallPathDictionary 21 | 22 | 36652C49-72B6-48DE-8764-CBD8011235F9 23 | ../../ZipKit 24 | 80B5D05E-133A-4C3C-A2B2-010DDF3C41D1 25 | ../.. 26 | 27 | IDESourceControlProjectURL 28 | ssh://github.com/kolpanic/ZipKit-Touch.git 29 | IDESourceControlProjectVersion 30 | 110 31 | IDESourceControlProjectWCCIdentifier 32 | 80B5D05E-133A-4C3C-A2B2-010DDF3C41D1 33 | IDESourceControlProjectWCConfigurations 34 | 35 | 36 | IDESourceControlRepositoryExtensionIdentifierKey 37 | public.vcs.git 38 | IDESourceControlWCCIdentifierKey 39 | 36652C49-72B6-48DE-8764-CBD8011235F9 40 | IDESourceControlWCCName 41 | ZipKit 42 | 43 | 44 | IDESourceControlRepositoryExtensionIdentifierKey 45 | public.vcs.git 46 | IDESourceControlWCCIdentifierKey 47 | 80B5D05E-133A-4C3C-A2B2-010DDF3C41D1 48 | IDESourceControlWCCName 49 | ZipKit Touch 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/Base.lproj/MainStoryboard_iPad.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/Base.lproj/MainStoryboard_iPhone.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/Default-568h@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolpanic/ZipKit/4bceda944889f4740760b4554f5e24dc7d5a4e84/Demos/ZipKit Touch/ZipKit Touch/Default-568h@2x.png -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/Default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolpanic/ZipKit/4bceda944889f4740760b4554f5e24dc7d5a4e84/Demos/ZipKit Touch/ZipKit Touch/Default.png -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/Default@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolpanic/ZipKit/4bceda944889f4740760b4554f5e24dc7d5a4e84/Demos/ZipKit Touch/ZipKit Touch/Default@2x.png -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/Read Me.txt: -------------------------------------------------------------------------------- 1 | If you can read this, you unzipped the archive. -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/Settings.bundle/Acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | StringsTable 6 | Acknowledgements 7 | PreferenceSpecifiers 8 | 9 | 10 | Type 11 | PSGroupSpecifier 12 | Title 13 | Intro 14 | 15 | 16 | Type 17 | PSGroupSpecifier 18 | Title 19 | Intro2 20 | 21 | 22 | Type 23 | PSGroupSpecifier 24 | Title 25 | ZipKit 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/Settings.bundle/Root.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Title 6 | uShare 7 | PreferenceSpecifiers 8 | 9 | 10 | Type 11 | PSChildPaneSpecifier 12 | Title 13 | Acknowledgements 14 | File 15 | Acknowledgements 16 | 17 | 18 | StringsTable 19 | Root 20 | 21 | 22 | -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/Settings.bundle/en.lproj/Acknowledgements.strings: -------------------------------------------------------------------------------- 1 | "Intro" = "Acknowledgements"; 2 | "Intro2" = "This software utilizes the following copyrighted material, the use of which is hereby acknowledged: 3 | "; 4 | "ZipKit" = "ZipKit developed by Karl Moskowski. https://github.com/kolpanic/ZipKit"; -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/Settings.bundle/en.lproj/Root.strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolpanic/ZipKit/4bceda944889f4740760b4554f5e24dc7d5a4e84/Demos/ZipKit Touch/ZipKit Touch/Settings.bundle/en.lproj/Root.strings -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/ZKAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZKAppDelegate.h 3 | // ZipKit Touch 4 | // 5 | // Created by Karl Moskowski on 2013-05-18. 6 | // Copyright (c) 2013 Karl Moskowski. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ZKAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/ZKAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZKAppDelegate.m 3 | // ZipKit Touch 4 | // 5 | // Created by Karl Moskowski on 2013-05-18. 6 | // Copyright (c) 2013 Karl Moskowski. All rights reserved. 7 | // 8 | 9 | #import "ZKAppDelegate.h" 10 | 11 | @implementation ZKAppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 14 | if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { 15 | UISplitViewController *splitViewController = (UISplitViewController *)self.window.rootViewController; 16 | UINavigationController *navigationController = [splitViewController.viewControllers lastObject]; 17 | splitViewController.delegate = (id)navigationController.topViewController; 18 | } 19 | return YES; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/ZKDetailViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZKDetailViewController.h 3 | // ZipKit Touch 4 | // 5 | // Created by Karl Moskowski on 2013-05-18. 6 | // Copyright (c) 2013 Karl Moskowski. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ZKDetailViewController : UIViewController 12 | 13 | @property (strong, nonatomic) NSData *fileData; 14 | @property (strong, nonatomic) NSString *fileName; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/ZKDetailViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZKDetailViewController.m 3 | // ZipKit Touch 4 | // 5 | // Created by Karl Moskowski on 2013-05-18. 6 | // Copyright (c) 2013 Karl Moskowski. All rights reserved. 7 | // 8 | 9 | #import "ZKDetailViewController.h" 10 | 11 | @interface ZKDetailViewController () 12 | @property (strong, nonatomic) UIPopoverController *masterPopoverController; 13 | - (void)configureView; 14 | @end 15 | 16 | @implementation ZKDetailViewController 17 | 18 | #pragma mark - Managing the detail item 19 | 20 | - (void)setFileData:(NSData *)newFileData { 21 | _fileData = newFileData; 22 | [self configureView]; 23 | if (self.masterPopoverController != nil) { 24 | [self.masterPopoverController dismissPopoverAnimated:YES]; 25 | } 26 | } 27 | - (void)setFileName:(NSString *)newFileName { 28 | _fileName = newFileName; 29 | [self configureView]; 30 | if (self.masterPopoverController != nil) { 31 | [self.masterPopoverController dismissPopoverAnimated:YES]; 32 | } 33 | } 34 | 35 | - (void)configureView { 36 | if (self.fileName != nil && self.fileData != nil) { 37 | self.title = self.fileName; 38 | NSString *ext = [self.fileName pathExtension]; 39 | if ([ext isEqualToString:@"txt"]) { 40 | UITextView *textView = [UITextView new]; 41 | [textView setText:[[NSString alloc] initWithData:self.fileData encoding:NSUTF8StringEncoding]]; 42 | self.view = textView; 43 | } else if ([ext isEqualToString:@"png"]) { 44 | UIImageView *imageView = [UIImageView new]; 45 | [imageView setImage:[UIImage imageWithData:self.fileData]]; 46 | self.view = imageView; 47 | } else { 48 | UITextView *textView = [UITextView new]; 49 | [textView setText:@"Only txt and PNG files are supported"]; 50 | self.view = textView; 51 | } 52 | } 53 | } 54 | 55 | - (void)viewDidLoad { 56 | [super viewDidLoad]; 57 | [self configureView]; 58 | } 59 | 60 | #pragma mark - Split view 61 | 62 | - (void)splitViewController:(UISplitViewController *)splitController willHideViewController:(UIViewController *)viewController withBarButtonItem:(UIBarButtonItem *)barButtonItem forPopoverController:(UIPopoverController *)popoverController { 63 | barButtonItem.title = NSLocalizedString(@"Files", @"Files"); 64 | [self.navigationItem setLeftBarButtonItem:barButtonItem animated:YES]; 65 | self.masterPopoverController = popoverController; 66 | } 67 | 68 | - (void)splitViewController:(UISplitViewController *)splitController willShowViewController:(UIViewController *)viewController invalidatingBarButtonItem:(UIBarButtonItem *)barButtonItem { 69 | // Called when the view is shown again in the split view, invalidating the button and popover controller. 70 | [self.navigationItem setLeftBarButtonItem:nil animated:YES]; 71 | self.masterPopoverController = nil; 72 | } 73 | 74 | @end 75 | -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/ZKMasterViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZKMasterViewController.h 3 | // ZipKit Touch 4 | // 5 | // Created by Karl Moskowski on 2013-05-18. 6 | // Copyright (c) 2013 Karl Moskowski. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @class ZKDetailViewController; 12 | @class ZKDataArchive; 13 | 14 | @interface ZKMasterViewController : UITableViewController 15 | 16 | @property (strong, nonatomic) ZKDetailViewController *detailViewController; 17 | @property (strong, nonatomic) IBOutlet ZKDataArchive *archive; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/ZKMasterViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZKMasterViewController.m 3 | // ZipKit Touch 4 | // 5 | // Created by Karl Moskowski on 2013-05-18. 6 | // Copyright (c) 2013 Karl Moskowski. All rights reserved. 7 | // 8 | 9 | #import "ZKMasterViewController.h" 10 | #import "ZKDetailViewController.h" 11 | #import "ZipKit/ZKDefs.h" 12 | #import "ZipKit/ZKDataArchive.h" 13 | 14 | @implementation ZKMasterViewController 15 | 16 | - (void)awakeFromNib { 17 | if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { 18 | self.clearsSelectionOnViewWillAppear = NO; 19 | self.preferredContentSize = CGSizeMake(320.0, 600.0); 20 | } 21 | [super awakeFromNib]; 22 | } 23 | 24 | - (void)viewDidLoad { 25 | [super viewDidLoad]; 26 | self.detailViewController = (ZKDetailViewController *)[[self.splitViewController.viewControllers lastObject] topViewController]; 27 | 28 | self.archive = [ZKDataArchive new]; 29 | [self.archive deflateFiles:@[[[NSBundle mainBundle] pathForResource:@"Read Me" ofType:@"txt"], [[NSBundle mainBundle] pathForResource:@"ZipKit" ofType:@"png"]] relativeToPath:[[NSBundle mainBundle] bundlePath] usingResourceFork:NO]; 30 | [self.archive inflateAll]; 31 | } 32 | 33 | #pragma mark - Table View 34 | 35 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 36 | return 1; 37 | } 38 | 39 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 40 | return [self.archive.inflatedFiles count]; 41 | } 42 | 43 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 44 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath]; 45 | NSDictionary *entry = self.archive.inflatedFiles[indexPath.row]; 46 | cell.textLabel.text = entry[ZKPathKey]; 47 | return cell; 48 | } 49 | 50 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 51 | if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) { 52 | NSDictionary *entry = self.archive.inflatedFiles[indexPath.row]; 53 | self.detailViewController.fileData = entry[ZKFileDataKey]; 54 | self.detailViewController.fileName = entry[ZKPathKey]; 55 | } 56 | } 57 | 58 | - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { 59 | if ([[segue identifier] isEqualToString:@"showDetail"]) { 60 | NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow]; 61 | NSDictionary *entry = self.archive.inflatedFiles[indexPath.row]; 62 | ZKDetailViewController *iPhoneDVC = (ZKDetailViewController *)[segue destinationViewController]; 63 | iPhoneDVC.fileData = entry[ZKFileDataKey]; 64 | iPhoneDVC.fileName = entry[ZKPathKey]; 65 | } 66 | } 67 | 68 | @end 69 | -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/ZipKit Touch-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | MainStoryboard_iPhone 29 | UIMainStoryboardFile~ipad 30 | MainStoryboard_iPad 31 | UIRequiredDeviceCapabilities 32 | 33 | armv7 34 | 35 | UIStatusBarTintParameters 36 | 37 | UINavigationBar 38 | 39 | Style 40 | UIBarStyleDefault 41 | Translucent 42 | 43 | 44 | 45 | UISupportedInterfaceOrientations 46 | 47 | UIInterfaceOrientationPortrait 48 | UIInterfaceOrientationLandscapeLeft 49 | UIInterfaceOrientationLandscapeRight 50 | 51 | UISupportedInterfaceOrientations~ipad 52 | 53 | UIInterfaceOrientationPortrait 54 | UIInterfaceOrientationPortraitUpsideDown 55 | UIInterfaceOrientationLandscapeLeft 56 | UIInterfaceOrientationLandscapeRight 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/ZipKit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolpanic/ZipKit/4bceda944889f4740760b4554f5e24dc7d5a4e84/Demos/ZipKit Touch/ZipKit Touch/ZipKit.png -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/ZipKit_Touch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolpanic/ZipKit/4bceda944889f4740760b4554f5e24dc7d5a4e84/Demos/ZipKit Touch/ZipKit Touch/ZipKit_Touch.png -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /Demos/ZipKit Touch/ZipKit Touch/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // ZipKit Touch 4 | // 5 | // Created by Karl Moskowski on 2013-05-18. 6 | // Copyright (c) 2013 Karl Moskowski. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "ZKAppDelegate.h" 12 | 13 | int main(int argc, char *argv[]){ 14 | @autoreleasepool { 15 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([ZKAppDelegate class])); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /Demos/ZipKit Utility/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | RemainingTimeTransformer 127 | 128 | 129 | 130 | 131 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | -------------------------------------------------------------------------------- /Demos/ZipKit Utility/MainWindowController.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface MainWindowController : NSWindowController 4 | 5 | - (IBAction)open:(id)sender; 6 | - (IBAction)cancel:(id)sender; 7 | 8 | @property (copy) NSString *message; 9 | @property (copy) NSString *action; 10 | @property (strong) NSDate *startTime; 11 | @property (assign) double progress; 12 | @property (assign) NSTimeInterval remainingTime; 13 | @property (assign) unsigned long long sizeWritten; 14 | @property (assign) unsigned long long totalSize; 15 | @property (assign) unsigned long long totalCount; 16 | @property (assign) BOOL isIndeterminate; 17 | @property (strong) NSOperationQueue *zipQueue; 18 | 19 | @end 20 | -------------------------------------------------------------------------------- /Demos/ZipKit Utility/MainWindowController.m: -------------------------------------------------------------------------------- 1 | #import "MainWindowController.h" 2 | #import "ZipFileOperation.h" 3 | #import "RemainingTimeTransformer.h" 4 | #import "ZipKit/ZKFileArchive.h" 5 | #import "ZipKit/ZKDataArchive.h" 6 | #import "ZipKit/ZKLog.h" 7 | #import "ZipKit/ZKDefs.h" 8 | #import "ZipKit/NSFileManager+ZKAdditions.h" 9 | 10 | const double maxProgress = 100.0; 11 | 12 | @implementation MainWindowController 13 | 14 | - (BOOL)application:(NSApplication *)app openFile:(NSString *)filename { 15 | if ([[self.zipQueue operations] count] < 1) { 16 | ZipFileOperation *zipOp = [ZipFileOperation new]; 17 | zipOp.item = filename; 18 | zipOp.delegate = self; 19 | [self.zipQueue addOperation:zipOp]; 20 | return YES; 21 | } else { 22 | return NO; 23 | } 24 | } 25 | 26 | - (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender { 27 | [self showWindow:self]; 28 | return NO; 29 | } 30 | 31 | - (void)applicationDidFinishLaunching:(NSNotification *)n { 32 | [ZKLog sharedInstance].minimumLevel = [[NSUserDefaults standardUserDefaults] integerForKey:ZKLogLevelKey]; 33 | self.message = NSLocalizedString(@"Ready", @"status message"); 34 | self.progress = 0.0; 35 | self.remainingTime = 0.0; 36 | self.zipQueue = [NSOperationQueue new]; 37 | [self.zipQueue setMaxConcurrentOperationCount:1]; 38 | } 39 | 40 | - (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication *)sender { 41 | if ([[self.zipQueue operations] count] > 0) { 42 | NSBeginAlertSheet(NSLocalizedString(@"Please cancel before quitting", @"alert title"), 43 | NSLocalizedString(@"OK", @"button label"), nil, nil, self.window, self, 44 | nil, nil, nil, 45 | NSLocalizedString(@"An action is in progress. Cancel it before quitting the application.", @"alert message")); 46 | return NSTerminateCancel; 47 | } else { 48 | return NSTerminateNow; 49 | } 50 | } 51 | 52 | - (void)applicationWillTerminate:(NSNotification *)n { 53 | [self.zipQueue cancelAllOperations]; 54 | } 55 | 56 | + (void)initialize { 57 | [NSValueTransformer setValueTransformer:[RemainingTimeTransformer new] forName:@"RemainingTimeTransformer"]; 58 | [[NSUserDefaults standardUserDefaults] registerDefaults: 59 | @{ZKLogLevelKey: @(ZKLogLevelError)}]; 60 | [super initialize]; 61 | } 62 | 63 | - (IBAction)open:(id)sender { 64 | [self showWindow:self]; 65 | if ([[self.zipQueue operations] count] < 1) { 66 | NSOpenPanel *panel = [NSOpenPanel openPanel]; 67 | [panel setCanChooseDirectories:YES]; 68 | [panel setAllowsMultipleSelection:YES]; 69 | [panel setCanChooseFiles:YES]; 70 | [panel setResolvesAliases:NO]; 71 | if ([panel runModal] == NSOKButton) { 72 | NSArray *urls = [panel URLs]; 73 | @try { 74 | NSString *firstFilename = [urls[0] path]; 75 | 76 | ZipFileOperation *zipFileOperation = [ZipFileOperation new]; 77 | zipFileOperation.item = ([urls count] == 1) ? (id)firstFilename : urls; 78 | zipFileOperation.delegate = self; 79 | [self.zipQueue addOperation:zipFileOperation]; 80 | 81 | // if ([filenames count] == 1 && [[firstFilename pathExtension] isEqualToString:ZKArchiveFileExtension]) { 82 | // NSString *archivePath = firstFilename; 83 | // ZKDataArchive *archive = [ZKDataArchive archiveWithArchivePath:archivePath]; 84 | // [archive inflateInFolder:[archivePath stringByDeletingLastPathComponent] 85 | // withFolderName:[[archivePath lastPathComponent] stringByDeletingPathExtension] 86 | // usingResourceFork:YES]; 87 | // } 88 | } 89 | @catch (NSException *e) { 90 | ZKLogWithException(e); 91 | } 92 | } 93 | } 94 | } 95 | 96 | - (IBAction)cancel:(id)sender { 97 | if ([[self.zipQueue operations] count] < 1) { 98 | return; 99 | } 100 | NSBeginAlertSheet(NSLocalizedString(@"Are you sure you want to cancel?", @"alert title"), 101 | NSLocalizedString(@"Yes", @"button label"), NSLocalizedString(@"No", @"button label"), nil, self.window, self, 102 | @selector(sheetDidEnd:returnCode:contextInfo:), nil, nil, 103 | NSLocalizedString(@"An action is in progress.", @"alert message")); 104 | } 105 | - (void)sheetDidEnd:(NSWindow *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo { 106 | if (returnCode == NSOKButton) { 107 | [self.zipQueue cancelAllOperations]; 108 | } 109 | } 110 | 111 | #pragma mark - 112 | #pragma mark Delegate Methods 113 | 114 | - (void)onZKArchiveDidBeginZip:(ZKArchive *)archive { 115 | self.isIndeterminate = YES; 116 | self.progress = 0.0; 117 | self.remainingTime = NSTimeIntervalSince1970; 118 | self.action = NSLocalizedString(@"Archiving", @"action for status message"); 119 | self.message = [NSString stringWithFormat:NSLocalizedString(@"%@ items (%@)...", @"status message"), 120 | self.action, [[archive archivePath] lastPathComponent]]; 121 | self.startTime = [NSDate date]; 122 | [self showWindow:self]; 123 | ZKLogDebug(self.message); 124 | } 125 | 126 | - (void)onZKArchiveDidBeginUnzip:(ZKArchive *)archive { 127 | self.isIndeterminate = YES; 128 | self.progress = 0.0; 129 | self.remainingTime = NSTimeIntervalSince1970; 130 | self.message = @""; 131 | self.action = NSLocalizedString(@"Extracting", @"action for status message"); 132 | self.message = [NSString stringWithFormat:NSLocalizedString(@"%@ items (%@)...", @"status message"), 133 | self.action, [[archive archivePath] lastPathComponent]]; 134 | self.startTime = [NSDate date]; 135 | [self showWindow:self]; 136 | ZKLogDebug(self.message); 137 | } 138 | 139 | - (void)onZKArchiveDidEndZip:(ZKArchive *)archive { 140 | self.progress = maxProgress; 141 | self.remainingTime = 0.0; 142 | self.isIndeterminate = NO; 143 | self.message = [NSString stringWithFormat:NSLocalizedString(@"Archive created (%@)", @"status message"), 144 | [[archive archivePath] lastPathComponent]]; 145 | ZKLogDebug(self.message); 146 | } 147 | 148 | - (void)onZKArchiveDidEndUnzip:(ZKArchive *)archive { 149 | self.progress = maxProgress; 150 | self.remainingTime = 0.0; 151 | self.isIndeterminate = NO; 152 | self.message = [NSString stringWithFormat:NSLocalizedString(@"Archive extracted (%@)", @"status message"), 153 | [[archive archivePath] lastPathComponent]]; 154 | ZKLogDebug(self.message); 155 | } 156 | 157 | - (void)onZKArchiveDidCancel:(ZKArchive *)archive { 158 | self.progress = 0.0; 159 | self.remainingTime = 0.0; 160 | self.isIndeterminate = NO; 161 | self.message = [NSString stringWithFormat:NSLocalizedString(@"%@ cancelled", @"status message"), self.action]; 162 | ZKLogDebug(self.message); 163 | } 164 | 165 | - (void)onZKArchiveDidFail:(ZKArchive *)archive { 166 | self.progress = 0.0; 167 | self.remainingTime = 0.0; 168 | self.isIndeterminate = NO; 169 | self.message = [NSString stringWithFormat:NSLocalizedString(@"%@ failed", @"status message"), self.action]; 170 | ZKLogError(self.message); 171 | } 172 | 173 | - (void)onZKArchive:(ZKArchive *)archive didUpdateTotalSize:(unsigned long long)size { 174 | self.totalSize = size; 175 | } 176 | 177 | - (void)onZKArchive:(ZKArchive *)archive didUpdateTotalCount:(unsigned long long)count { 178 | self.totalCount = count; 179 | if (self.totalCount < 1) { 180 | self.message = [NSString stringWithFormat:NSLocalizedString(@"%@ items (%@)...", @"status message"), 181 | self.action, [[archive archivePath] lastPathComponent]]; 182 | } else if (self.totalCount == 1) { 183 | self.message = [NSString stringWithFormat:NSLocalizedString(@"%@ 1 item (%@)...", @"status message"), 184 | self.action, [[archive archivePath] lastPathComponent]]; 185 | } else { 186 | self.message = [NSString stringWithFormat:NSLocalizedString(@"%@ %qu items (%@)...", @"status message"), 187 | self.action, self.totalCount, [[archive archivePath] lastPathComponent]]; 188 | } 189 | } 190 | 191 | - (void)onZKArchive:(ZKArchive *)archive didUpdateBytesWritten:(unsigned long long)byteCount { 192 | self.sizeWritten += byteCount; 193 | self.isIndeterminate = (self.totalSize == 0); 194 | if (self.totalSize > 0) { 195 | self.progress = maxProgress * ((double)self.sizeWritten) / ((double)self.totalSize); 196 | } 197 | 198 | NSTimeInterval elapsed = [[NSDate date] timeIntervalSinceDate:self.startTime]; 199 | NSTimeInterval rt = (100.0 * elapsed / self.progress) - elapsed; 200 | if (rt < self.remainingTime) { 201 | self.remainingTime = rt; 202 | } 203 | } 204 | 205 | - (void)onZKArchive:(ZKArchive *)archive willZipPath:(NSString *)path { 206 | ZKLogDebug(@"Adding %@...", [path lastPathComponent]); 207 | } 208 | 209 | - (void)onZKArchive:(ZKArchive *)archive willUnzipPath:(NSString *)path { 210 | ZKLogDebug(@"Extracting %@...", [path lastPathComponent]); 211 | } 212 | 213 | - (BOOL)zkDelegateWantsSizes { 214 | return YES; 215 | } 216 | 217 | @end 218 | -------------------------------------------------------------------------------- /Demos/ZipKit Utility/RemainingTimeTransformer.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface RemainingTimeTransformer : NSValueTransformer 4 | 5 | @end 6 | -------------------------------------------------------------------------------- /Demos/ZipKit Utility/RemainingTimeTransformer.m: -------------------------------------------------------------------------------- 1 | #import "RemainingTimeTransformer.h" 2 | 3 | @implementation RemainingTimeTransformer 4 | 5 | + (Class)transformedValueClass { 6 | return [NSString class]; 7 | } 8 | 9 | + (BOOL)allowsReverseTransformation { 10 | return NO; 11 | } 12 | 13 | - (id)transformedValue:(id)value { 14 | NSTimeInterval timeInterval = [value doubleValue]; 15 | if (timeInterval <= 0) { 16 | return nil; 17 | } else if (timeInterval == NSTimeIntervalSince1970) { 18 | return NSLocalizedString(@"Estimating time left", @"remaining time message"); 19 | } 20 | 21 | float s = (float)ABS(timeInterval); 22 | float m = s / 60.0; 23 | float h = m / 60.0; 24 | float d = h / 24.0; 25 | float w = d / 7.0; 26 | float mm = d / 30.0; 27 | 28 | NSUInteger seconds = roundf(s); 29 | NSUInteger minutes = roundf(m); 30 | NSUInteger hours = roundf(h); 31 | NSUInteger days = roundf(d); 32 | NSUInteger weeks = roundf(w); 33 | NSUInteger months = roundf(mm); 34 | 35 | NSString *transformedValue = NSLocalizedString(@"About a second left", @"remaining time message"); 36 | if (weeks > 8) { 37 | transformedValue = [NSString stringWithFormat:NSLocalizedString(@"About %lu months left", @"remaining time message"), (unsigned long)months]; 38 | } else if (days > 10) { 39 | transformedValue = [NSString stringWithFormat:NSLocalizedString(@"About %lu weeks left", @"remaining time message"), (unsigned long)weeks]; 40 | } else if (hours > 48) { 41 | transformedValue = [NSString stringWithFormat:NSLocalizedString(@"About %lu days left", @"remaining time message"), days]; 42 | } else if (minutes > 100) { 43 | transformedValue = [NSString stringWithFormat:NSLocalizedString(@"About %lu hours left", @"remaining time message"), hours]; 44 | } else if (seconds > 100) { 45 | transformedValue = [NSString stringWithFormat:NSLocalizedString(@"About %lu minutes left", @"remaining time message"), minutes]; 46 | } else if (seconds > 50) { 47 | transformedValue = NSLocalizedString(@"About a minute left", @"remaining time message"); 48 | } else if (seconds > 30) { 49 | transformedValue = NSLocalizedString(@"Less than a minute left", @"remaining time message"); 50 | } else if (seconds > 1) { 51 | transformedValue = [NSString stringWithFormat:NSLocalizedString(@"About %lu seconds left", @"remaining time message"), seconds]; 52 | } 53 | 54 | return transformedValue; 55 | } 56 | 57 | @end 58 | -------------------------------------------------------------------------------- /Demos/ZipKit Utility/ZipFileOperation.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | @interface ZipFileOperation : NSOperation 4 | 5 | @property (strong) id item; 6 | @property (weak) id delegate; 7 | 8 | @end 9 | -------------------------------------------------------------------------------- /Demos/ZipKit Utility/ZipFileOperation.m: -------------------------------------------------------------------------------- 1 | #import "ZipFileOperation.h" 2 | #import "ZipKit/ZKFileArchive.h" 3 | #import "ZipKit/ZKLog.h" 4 | 5 | @implementation ZipFileOperation 6 | 7 | - (void)main { 8 | [ZKFileArchive process:self.item usingResourceFork:YES withInvoker:self andDelegate:self.delegate]; 9 | } 10 | 11 | @end 12 | -------------------------------------------------------------------------------- /Demos/ZipKit Utility/ZipKit Utility.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58140DA1D0A300B32029 /* MainMenu.xib */; }; 11 | 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; 12 | 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; 13 | CB2E98EE10A1C59600E04C37 /* ZipKit.icns in Resources */ = {isa = PBXBuildFile; fileRef = CB2E98ED10A1C59600E04C37 /* ZipKit.icns */; }; 14 | CB4AC859243FAB3F00D2BC41 /* ZipKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CB4AC858243FAB3F00D2BC41 /* ZipKit.framework */; }; 15 | CB4AC85A243FAB3F00D2BC41 /* ZipKit.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = CB4AC858243FAB3F00D2BC41 /* ZipKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 16 | CB9B9DD5109F69F1003E3F8B /* MainWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = CB9B9DD4109F69F1003E3F8B /* MainWindowController.m */; }; 17 | CB9B9DDA109F6A03003E3F8B /* RemainingTimeTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = CB9B9DD7109F6A03003E3F8B /* RemainingTimeTransformer.m */; }; 18 | CB9B9DDB109F6A03003E3F8B /* ZipFileOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = CB9B9DD9109F6A03003E3F8B /* ZipFileOperation.m */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXCopyFilesBuildPhase section */ 22 | CB2178F210A06DB30027DEBE /* Copy Frameworks */ = { 23 | isa = PBXCopyFilesBuildPhase; 24 | buildActionMask = 2147483647; 25 | dstPath = ""; 26 | dstSubfolderSpec = 10; 27 | files = ( 28 | CB4AC85A243FAB3F00D2BC41 /* ZipKit.framework in Copy Frameworks */, 29 | ); 30 | name = "Copy Frameworks"; 31 | runOnlyForDeploymentPostprocessing = 0; 32 | }; 33 | /* End PBXCopyFilesBuildPhase section */ 34 | 35 | /* Begin PBXFileReference section */ 36 | 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 37 | 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 38 | 8D1107310486CEB800E47090 /* ZipKit_Utility-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "ZipKit_Utility-Info.plist"; sourceTree = ""; }; 39 | 8D1107320486CEB800E47090 /* ZipKit Utility.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ZipKit Utility.app"; sourceTree = BUILT_PRODUCTS_DIR; }; 40 | CB2E98ED10A1C59600E04C37 /* ZipKit.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = ZipKit.icns; sourceTree = ""; }; 41 | CB4AC858243FAB3F00D2BC41 /* ZipKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = ZipKit.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 42 | CB9B9DD3109F69F1003E3F8B /* MainWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainWindowController.h; sourceTree = ""; }; 43 | CB9B9DD4109F69F1003E3F8B /* MainWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainWindowController.m; sourceTree = ""; }; 44 | CB9B9DD6109F6A03003E3F8B /* RemainingTimeTransformer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemainingTimeTransformer.h; sourceTree = ""; }; 45 | CB9B9DD7109F6A03003E3F8B /* RemainingTimeTransformer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RemainingTimeTransformer.m; sourceTree = ""; }; 46 | CB9B9DD8109F6A03003E3F8B /* ZipFileOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ZipFileOperation.h; sourceTree = ""; }; 47 | CB9B9DD9109F6A03003E3F8B /* ZipFileOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ZipFileOperation.m; sourceTree = ""; }; 48 | D71F5C22257512B500B36AA8 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; 49 | /* End PBXFileReference section */ 50 | 51 | /* Begin PBXFrameworksBuildPhase section */ 52 | 8D11072E0486CEB800E47090 /* Frameworks */ = { 53 | isa = PBXFrameworksBuildPhase; 54 | buildActionMask = 2147483647; 55 | files = ( 56 | 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, 57 | CB4AC859243FAB3F00D2BC41 /* ZipKit.framework in Frameworks */, 58 | ); 59 | runOnlyForDeploymentPostprocessing = 0; 60 | }; 61 | /* End PBXFrameworksBuildPhase section */ 62 | 63 | /* Begin PBXGroup section */ 64 | 080E96DDFE201D6D7F000001 /* Classes */ = { 65 | isa = PBXGroup; 66 | children = ( 67 | CB9B9DD3109F69F1003E3F8B /* MainWindowController.h */, 68 | CB9B9DD4109F69F1003E3F8B /* MainWindowController.m */, 69 | CB9B9DD6109F6A03003E3F8B /* RemainingTimeTransformer.h */, 70 | CB9B9DD7109F6A03003E3F8B /* RemainingTimeTransformer.m */, 71 | CB9B9DD8109F6A03003E3F8B /* ZipFileOperation.h */, 72 | CB9B9DD9109F6A03003E3F8B /* ZipFileOperation.m */, 73 | ); 74 | name = Classes; 75 | sourceTree = ""; 76 | }; 77 | 19C28FACFE9D520D11CA2CBB /* Products */ = { 78 | isa = PBXGroup; 79 | children = ( 80 | 8D1107320486CEB800E47090 /* ZipKit Utility.app */, 81 | ); 82 | name = Products; 83 | sourceTree = ""; 84 | }; 85 | 29B97314FDCFA39411CA2CEA /* ZipKit Utility */ = { 86 | isa = PBXGroup; 87 | children = ( 88 | 080E96DDFE201D6D7F000001 /* Classes */, 89 | 29B97315FDCFA39411CA2CEA /* Other Sources */, 90 | 29B97317FDCFA39411CA2CEA /* Resources */, 91 | 29B97323FDCFA39411CA2CEA /* Linked Frameworks */, 92 | 19C28FACFE9D520D11CA2CBB /* Products */, 93 | CB4AC857243FAB3F00D2BC41 /* Frameworks */, 94 | ); 95 | name = "ZipKit Utility"; 96 | sourceTree = ""; 97 | }; 98 | 29B97315FDCFA39411CA2CEA /* Other Sources */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | 29B97316FDCFA39411CA2CEA /* main.m */, 102 | ); 103 | name = "Other Sources"; 104 | sourceTree = ""; 105 | }; 106 | 29B97317FDCFA39411CA2CEA /* Resources */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | 1DDD58140DA1D0A300B32029 /* MainMenu.xib */, 110 | CB2E98ED10A1C59600E04C37 /* ZipKit.icns */, 111 | 8D1107310486CEB800E47090 /* ZipKit_Utility-Info.plist */, 112 | ); 113 | name = Resources; 114 | sourceTree = ""; 115 | }; 116 | 29B97323FDCFA39411CA2CEA /* Linked Frameworks */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, 120 | ); 121 | name = "Linked Frameworks"; 122 | sourceTree = ""; 123 | }; 124 | CB4AC857243FAB3F00D2BC41 /* Frameworks */ = { 125 | isa = PBXGroup; 126 | children = ( 127 | CB4AC858243FAB3F00D2BC41 /* ZipKit.framework */, 128 | ); 129 | name = Frameworks; 130 | sourceTree = ""; 131 | }; 132 | /* End PBXGroup section */ 133 | 134 | /* Begin PBXNativeTarget section */ 135 | 8D1107260486CEB800E47090 /* ZipKit Utility */ = { 136 | isa = PBXNativeTarget; 137 | buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "ZipKit Utility" */; 138 | buildPhases = ( 139 | 8D1107290486CEB800E47090 /* Resources */, 140 | CB2178F210A06DB30027DEBE /* Copy Frameworks */, 141 | 8D11072C0486CEB800E47090 /* Sources */, 142 | 8D11072E0486CEB800E47090 /* Frameworks */, 143 | ); 144 | buildRules = ( 145 | ); 146 | dependencies = ( 147 | ); 148 | name = "ZipKit Utility"; 149 | productInstallPath = "$(HOME)/Applications"; 150 | productName = "ZipKit Utility"; 151 | productReference = 8D1107320486CEB800E47090 /* ZipKit Utility.app */; 152 | productType = "com.apple.product-type.application"; 153 | }; 154 | /* End PBXNativeTarget section */ 155 | 156 | /* Begin PBXProject section */ 157 | 29B97313FDCFA39411CA2CEA /* Project object */ = { 158 | isa = PBXProject; 159 | attributes = { 160 | LastUpgradeCheck = 1230; 161 | }; 162 | buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ZipKit Utility" */; 163 | compatibilityVersion = "Xcode 3.2"; 164 | developmentRegion = en; 165 | hasScannedForEncodings = 1; 166 | knownRegions = ( 167 | Base, 168 | en, 169 | fr, 170 | de, 171 | ja, 172 | ); 173 | mainGroup = 29B97314FDCFA39411CA2CEA /* ZipKit Utility */; 174 | projectDirPath = ""; 175 | projectRoot = ""; 176 | targets = ( 177 | 8D1107260486CEB800E47090 /* ZipKit Utility */, 178 | ); 179 | }; 180 | /* End PBXProject section */ 181 | 182 | /* Begin PBXResourcesBuildPhase section */ 183 | 8D1107290486CEB800E47090 /* Resources */ = { 184 | isa = PBXResourcesBuildPhase; 185 | buildActionMask = 2147483647; 186 | files = ( 187 | 1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */, 188 | CB2E98EE10A1C59600E04C37 /* ZipKit.icns in Resources */, 189 | ); 190 | runOnlyForDeploymentPostprocessing = 0; 191 | }; 192 | /* End PBXResourcesBuildPhase section */ 193 | 194 | /* Begin PBXSourcesBuildPhase section */ 195 | 8D11072C0486CEB800E47090 /* Sources */ = { 196 | isa = PBXSourcesBuildPhase; 197 | buildActionMask = 2147483647; 198 | files = ( 199 | 8D11072D0486CEB800E47090 /* main.m in Sources */, 200 | CB9B9DD5109F69F1003E3F8B /* MainWindowController.m in Sources */, 201 | CB9B9DDA109F6A03003E3F8B /* RemainingTimeTransformer.m in Sources */, 202 | CB9B9DDB109F6A03003E3F8B /* ZipFileOperation.m in Sources */, 203 | ); 204 | runOnlyForDeploymentPostprocessing = 0; 205 | }; 206 | /* End PBXSourcesBuildPhase section */ 207 | 208 | /* Begin PBXVariantGroup section */ 209 | 1DDD58140DA1D0A300B32029 /* MainMenu.xib */ = { 210 | isa = PBXVariantGroup; 211 | children = ( 212 | D71F5C22257512B500B36AA8 /* Base */, 213 | ); 214 | name = MainMenu.xib; 215 | sourceTree = ""; 216 | }; 217 | /* End PBXVariantGroup section */ 218 | 219 | /* Begin XCBuildConfiguration section */ 220 | C01FCF4B08A954540054247B /* Debug */ = { 221 | isa = XCBuildConfiguration; 222 | buildSettings = { 223 | ALWAYS_SEARCH_USER_PATHS = NO; 224 | CLANG_ENABLE_OBJC_ARC = YES; 225 | COMBINE_HIDPI_IMAGES = YES; 226 | COPY_PHASE_STRIP = NO; 227 | GCC_DYNAMIC_NO_PIC = NO; 228 | GCC_ENABLE_OBJC_GC = unsupported; 229 | GCC_MODEL_TUNING = G5; 230 | GCC_OPTIMIZATION_LEVEL = 0; 231 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 232 | INFOPLIST_FILE = "ZipKit_Utility-Info.plist"; 233 | INSTALL_PATH = "$(HOME)/Applications"; 234 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 235 | PRODUCT_BUNDLE_IDENTIFIER = "me.karlmoskowski.ZipKit-Utility"; 236 | PRODUCT_NAME = "ZipKit Utility"; 237 | USER_HEADER_SEARCH_PATHS = ./ZipKit/; 238 | }; 239 | name = Debug; 240 | }; 241 | C01FCF4C08A954540054247B /* Release */ = { 242 | isa = XCBuildConfiguration; 243 | buildSettings = { 244 | ALWAYS_SEARCH_USER_PATHS = NO; 245 | CLANG_ENABLE_OBJC_ARC = YES; 246 | COMBINE_HIDPI_IMAGES = YES; 247 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 248 | GCC_ENABLE_OBJC_GC = unsupported; 249 | GCC_MODEL_TUNING = G5; 250 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 251 | INFOPLIST_FILE = "ZipKit_Utility-Info.plist"; 252 | INSTALL_PATH = "$(HOME)/Applications"; 253 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; 254 | PRODUCT_BUNDLE_IDENTIFIER = "me.karlmoskowski.ZipKit-Utility"; 255 | PRODUCT_NAME = "ZipKit Utility"; 256 | USER_HEADER_SEARCH_PATHS = ./ZipKit/; 257 | }; 258 | name = Release; 259 | }; 260 | C01FCF4F08A954540054247B /* Debug */ = { 261 | isa = XCBuildConfiguration; 262 | buildSettings = { 263 | CLANG_ENABLE_MODULES = YES; 264 | GCC_C_LANGUAGE_STANDARD = gnu99; 265 | GCC_OPTIMIZATION_LEVEL = 0; 266 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 267 | GCC_WARN_UNUSED_VARIABLE = YES; 268 | MACOSX_DEPLOYMENT_TARGET = 10.9; 269 | ONLY_ACTIVE_ARCH = YES; 270 | SDKROOT = macosx; 271 | }; 272 | name = Debug; 273 | }; 274 | C01FCF5008A954540054247B /* Release */ = { 275 | isa = XCBuildConfiguration; 276 | buildSettings = { 277 | CLANG_ENABLE_MODULES = YES; 278 | GCC_C_LANGUAGE_STANDARD = gnu99; 279 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 280 | GCC_WARN_UNUSED_VARIABLE = YES; 281 | MACOSX_DEPLOYMENT_TARGET = 10.9; 282 | SDKROOT = macosx; 283 | }; 284 | name = Release; 285 | }; 286 | /* End XCBuildConfiguration section */ 287 | 288 | /* Begin XCConfigurationList section */ 289 | C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "ZipKit Utility" */ = { 290 | isa = XCConfigurationList; 291 | buildConfigurations = ( 292 | C01FCF4B08A954540054247B /* Debug */, 293 | C01FCF4C08A954540054247B /* Release */, 294 | ); 295 | defaultConfigurationIsVisible = 0; 296 | defaultConfigurationName = Release; 297 | }; 298 | C01FCF4E08A954540054247B /* Build configuration list for PBXProject "ZipKit Utility" */ = { 299 | isa = XCConfigurationList; 300 | buildConfigurations = ( 301 | C01FCF4F08A954540054247B /* Debug */, 302 | C01FCF5008A954540054247B /* Release */, 303 | ); 304 | defaultConfigurationIsVisible = 0; 305 | defaultConfigurationName = Release; 306 | }; 307 | /* End XCConfigurationList section */ 308 | }; 309 | rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; 310 | } 311 | -------------------------------------------------------------------------------- /Demos/ZipKit Utility/ZipKit Utility.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demos/ZipKit Utility/ZipKit Utility.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Demos/ZipKit Utility/ZipKit Utility.xcodeproj/project.xcworkspace/xcshareddata/ZipKit Utility.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 1EB38A1B-2B18-49C7-B806-0EEBAE4118F5 9 | IDESourceControlProjectName 10 | ZipKit Utility 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 68C00272-727B-48AA-811F-6DD9C3977B5A 14 | ssh://github.com/kolpanic/ZipKit-Utility.git 15 | A5259DC5-6326-4FE7-AE54-E07918A3AC4D 16 | https://github.com/kolpanic/ZipKit.git 17 | 18 | IDESourceControlProjectPath 19 | ZipKit Utility.xcodeproj/project.xcworkspace 20 | IDESourceControlProjectRelativeInstallPathDictionary 21 | 22 | 68C00272-727B-48AA-811F-6DD9C3977B5A 23 | ../.. 24 | A5259DC5-6326-4FE7-AE54-E07918A3AC4D 25 | ../../ZipKit 26 | 27 | IDESourceControlProjectURL 28 | ssh://github.com/kolpanic/ZipKit-Utility.git 29 | IDESourceControlProjectVersion 30 | 110 31 | IDESourceControlProjectWCCIdentifier 32 | 68C00272-727B-48AA-811F-6DD9C3977B5A 33 | IDESourceControlProjectWCConfigurations 34 | 35 | 36 | IDESourceControlRepositoryExtensionIdentifierKey 37 | public.vcs.git 38 | IDESourceControlWCCIdentifierKey 39 | A5259DC5-6326-4FE7-AE54-E07918A3AC4D 40 | IDESourceControlWCCName 41 | ZipKit 42 | 43 | 44 | IDESourceControlRepositoryExtensionIdentifierKey 45 | public.vcs.git 46 | IDESourceControlWCCIdentifierKey 47 | 68C00272-727B-48AA-811F-6DD9C3977B5A 48 | IDESourceControlWCCName 49 | ZipKit Utility 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /Demos/ZipKit Utility/ZipKit.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kolpanic/ZipKit/4bceda944889f4740760b4554f5e24dc7d5a4e84/Demos/ZipKit Utility/ZipKit.icns -------------------------------------------------------------------------------- /Demos/ZipKit Utility/ZipKit_Utility-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | ZipKit 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | 32 | 33 | -------------------------------------------------------------------------------- /Demos/ZipKit Utility/main.m: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | int main(int argc, char *argv[]) { 4 | return NSApplicationMain(argc, (const char **)argv); 5 | } 6 | -------------------------------------------------------------------------------- /Demos/zku/zku.m: -------------------------------------------------------------------------------- 1 | #import 2 | #import "ZipKit/ZipKit.h" 3 | #include 4 | 5 | @interface ZKUController : NSObject 6 | - (void)process:(NSArray *)items; 7 | @end 8 | @implementation ZKUController : NSObject 9 | 10 | - (void)process:(NSArray *)items { 11 | [ZKFileArchive process:items usingResourceFork:YES withInvoker:nil andDelegate:self]; 12 | } 13 | 14 | - (void)onZKArchiveDidBeginZip:(ZKArchive *)archive { 15 | ZKLogNotice(@"Creating archive %@", [archive.archivePath lastPathComponent]); 16 | } 17 | 18 | - (void)onZKArchiveDidBeginUnzip:(ZKArchive *)archive { 19 | ZKLogNotice(@"Extracting from archive %@", [archive.archivePath lastPathComponent]); 20 | } 21 | 22 | - (void)onZKArchiveDidEndZip:(ZKArchive *)archive { 23 | ZKLogNotice(@"%@ created", [archive.archivePath lastPathComponent]); 24 | } 25 | 26 | - (void)onZKArchiveDidEndUnzip:(ZKArchive *)archive { 27 | ZKLogNotice(@"%@ extracted", [archive.archivePath lastPathComponent]); 28 | } 29 | 30 | - (void)onZKArchiveDidFail:(ZKArchive *)archive { 31 | ZKLogError(@"Archiving failed!"); 32 | } 33 | 34 | - (void)onZKArchive:(ZKArchive *)archive willZipPath:(NSString *)path { 35 | ZKLogNotice(@"...adding %@", [path lastPathComponent]); 36 | } 37 | 38 | - (void)onZKArchive:(ZKArchive *)archive willUnzipPath:(NSString *)path { 39 | ZKLogNotice(@"...extracting %@", [path lastPathComponent]); 40 | } 41 | 42 | - (BOOL)zkDelegateWantsSizes { 43 | return NO; 44 | } 45 | 46 | @end 47 | 48 | int main(int argc, const char *argv[]) { 49 | @autoreleasepool { 50 | [ZKLog sharedInstance].minimumLevel = ZKLogLevelAll; 51 | if (argc > 1) { 52 | NSFileManager *fileManager = [NSFileManager defaultManager]; 53 | NSMutableArray *items = [NSMutableArray arrayWithCapacity:(argc - 1)]; 54 | for (NSUInteger i = 1; i <= argc; i++) { 55 | const char *p = argv[i]; 56 | if (p != NULL) { 57 | NSURL *url = [[NSURL alloc] initFileURLWithPath:[@(p)stringByStandardizingPath]]; 58 | NSString *path = [url path]; 59 | if ([fileManager fileExistsAtPath:path]) { 60 | [items addObject:path]; 61 | } 62 | } 63 | } 64 | if ([items count] > 0) { 65 | [[[ZKUController alloc] init] process:items]; 66 | } 67 | } else { 68 | ZKLogDebug(@"Nothing to process"); 69 | } 70 | } 71 | return EXIT_SUCCESS; 72 | } 73 | -------------------------------------------------------------------------------- /Demos/zku/zku.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 8DD76F9A0486AA7600D96B5E /* zku.m in Sources */ = {isa = PBXBuildFile; fileRef = 08FB7796FE84155DC02AAC07 /* zku.m */; settings = {ATTRIBUTES = (); }; }; 11 | 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08FB779EFE84155DC02AAC07 /* Foundation.framework */; }; 12 | CB4AC85D243FAB4B00D2BC41 /* libzipkit.a in Frameworks */ = {isa = PBXBuildFile; fileRef = CB4AC85C243FAB4B00D2BC41 /* libzipkit.a */; }; 13 | CB747FFF109F7662006A143C /* CoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CB747FFE109F7662006A143C /* CoreServices.framework */; }; 14 | CB9B9E2A109F6B20003E3F8B /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = CB9B9E29109F6B20003E3F8B /* libz.dylib */; }; 15 | /* End PBXBuildFile section */ 16 | 17 | /* Begin PBXFileReference section */ 18 | 08FB7796FE84155DC02AAC07 /* zku.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = zku.m; sourceTree = ""; }; 19 | 08FB779EFE84155DC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 20 | 8DD76FA10486AA7600D96B5E /* zku */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = zku; sourceTree = BUILT_PRODUCTS_DIR; }; 21 | CB4AC85C243FAB4B00D2BC41 /* libzipkit.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libzipkit.a; sourceTree = BUILT_PRODUCTS_DIR; }; 22 | CB747FFE109F7662006A143C /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = /System/Library/Frameworks/CoreServices.framework; sourceTree = ""; }; 23 | CB9B9E29109F6B20003E3F8B /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; 24 | /* End PBXFileReference section */ 25 | 26 | /* Begin PBXFrameworksBuildPhase section */ 27 | 8DD76F9B0486AA7600D96B5E /* Frameworks */ = { 28 | isa = PBXFrameworksBuildPhase; 29 | buildActionMask = 2147483647; 30 | files = ( 31 | CB4AC85D243FAB4B00D2BC41 /* libzipkit.a in Frameworks */, 32 | 8DD76F9C0486AA7600D96B5E /* Foundation.framework in Frameworks */, 33 | CB9B9E2A109F6B20003E3F8B /* libz.dylib in Frameworks */, 34 | CB747FFF109F7662006A143C /* CoreServices.framework in Frameworks */, 35 | ); 36 | runOnlyForDeploymentPostprocessing = 0; 37 | }; 38 | /* End PBXFrameworksBuildPhase section */ 39 | 40 | /* Begin PBXGroup section */ 41 | 08FB7794FE84155DC02AAC07 /* zku */ = { 42 | isa = PBXGroup; 43 | children = ( 44 | 08FB7795FE84155DC02AAC07 /* Source */, 45 | 08FB779DFE84155DC02AAC07 /* Linked Frameworks */, 46 | 1AB674ADFE9D54B511CA2CBB /* Products */, 47 | CB4AC85B243FAB4B00D2BC41 /* Frameworks */, 48 | ); 49 | name = zku; 50 | sourceTree = ""; 51 | }; 52 | 08FB7795FE84155DC02AAC07 /* Source */ = { 53 | isa = PBXGroup; 54 | children = ( 55 | 08FB7796FE84155DC02AAC07 /* zku.m */, 56 | ); 57 | name = Source; 58 | sourceTree = ""; 59 | }; 60 | 08FB779DFE84155DC02AAC07 /* Linked Frameworks */ = { 61 | isa = PBXGroup; 62 | children = ( 63 | 08FB779EFE84155DC02AAC07 /* Foundation.framework */, 64 | CB9B9E29109F6B20003E3F8B /* libz.dylib */, 65 | CB747FFE109F7662006A143C /* CoreServices.framework */, 66 | ); 67 | name = "Linked Frameworks"; 68 | sourceTree = ""; 69 | }; 70 | 1AB674ADFE9D54B511CA2CBB /* Products */ = { 71 | isa = PBXGroup; 72 | children = ( 73 | 8DD76FA10486AA7600D96B5E /* zku */, 74 | ); 75 | name = Products; 76 | sourceTree = ""; 77 | }; 78 | CB4AC85B243FAB4B00D2BC41 /* Frameworks */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | CB4AC85C243FAB4B00D2BC41 /* libzipkit.a */, 82 | ); 83 | name = Frameworks; 84 | sourceTree = ""; 85 | }; 86 | /* End PBXGroup section */ 87 | 88 | /* Begin PBXNativeTarget section */ 89 | 8DD76F960486AA7600D96B5E /* zku */ = { 90 | isa = PBXNativeTarget; 91 | buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "zku" */; 92 | buildPhases = ( 93 | 8DD76F990486AA7600D96B5E /* Sources */, 94 | 8DD76F9B0486AA7600D96B5E /* Frameworks */, 95 | ); 96 | buildRules = ( 97 | ); 98 | dependencies = ( 99 | ); 100 | name = zku; 101 | productInstallPath = "$(HOME)/bin"; 102 | productName = zku; 103 | productReference = 8DD76FA10486AA7600D96B5E /* zku */; 104 | productType = "com.apple.product-type.tool"; 105 | }; 106 | /* End PBXNativeTarget section */ 107 | 108 | /* Begin PBXProject section */ 109 | 08FB7793FE84155DC02AAC07 /* Project object */ = { 110 | isa = PBXProject; 111 | attributes = { 112 | LastUpgradeCheck = 1220; 113 | }; 114 | buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "zku" */; 115 | compatibilityVersion = "Xcode 3.2"; 116 | developmentRegion = en; 117 | hasScannedForEncodings = 1; 118 | knownRegions = ( 119 | en, 120 | ja, 121 | fr, 122 | de, 123 | Base, 124 | ); 125 | mainGroup = 08FB7794FE84155DC02AAC07 /* zku */; 126 | projectDirPath = ""; 127 | projectRoot = ""; 128 | targets = ( 129 | 8DD76F960486AA7600D96B5E /* zku */, 130 | ); 131 | }; 132 | /* End PBXProject section */ 133 | 134 | /* Begin PBXSourcesBuildPhase section */ 135 | 8DD76F990486AA7600D96B5E /* Sources */ = { 136 | isa = PBXSourcesBuildPhase; 137 | buildActionMask = 2147483647; 138 | files = ( 139 | 8DD76F9A0486AA7600D96B5E /* zku.m in Sources */, 140 | ); 141 | runOnlyForDeploymentPostprocessing = 0; 142 | }; 143 | /* End PBXSourcesBuildPhase section */ 144 | 145 | /* Begin XCBuildConfiguration section */ 146 | 1DEB927508733DD40010E9CD /* Debug */ = { 147 | isa = XCBuildConfiguration; 148 | buildSettings = { 149 | ALWAYS_SEARCH_USER_PATHS = NO; 150 | CLANG_ENABLE_MODULES = YES; 151 | CLANG_ENABLE_OBJC_ARC = YES; 152 | COPY_PHASE_STRIP = NO; 153 | GCC_DYNAMIC_NO_PIC = NO; 154 | GCC_OPTIMIZATION_LEVEL = 0; 155 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 156 | INSTALL_PATH = /usr/local/bin; 157 | OTHER_LDFLAGS = ( 158 | "-ObjC", 159 | "-all_load", 160 | ); 161 | PRODUCT_NAME = zku; 162 | }; 163 | name = Debug; 164 | }; 165 | 1DEB927608733DD40010E9CD /* Release */ = { 166 | isa = XCBuildConfiguration; 167 | buildSettings = { 168 | ALWAYS_SEARCH_USER_PATHS = NO; 169 | CLANG_ENABLE_MODULES = YES; 170 | CLANG_ENABLE_OBJC_ARC = YES; 171 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 172 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 173 | INSTALL_PATH = /usr/local/bin; 174 | OTHER_LDFLAGS = ( 175 | "-ObjC", 176 | "-all_load", 177 | ); 178 | PRODUCT_NAME = zku; 179 | }; 180 | name = Release; 181 | }; 182 | 1DEB927908733DD40010E9CD /* Debug */ = { 183 | isa = XCBuildConfiguration; 184 | buildSettings = { 185 | GCC_C_LANGUAGE_STANDARD = gnu99; 186 | GCC_OPTIMIZATION_LEVEL = 0; 187 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 188 | GCC_WARN_UNUSED_VARIABLE = YES; 189 | HEADER_SEARCH_PATHS = ../..; 190 | MACOSX_DEPLOYMENT_TARGET = 10.9; 191 | ONLY_ACTIVE_ARCH = YES; 192 | SDKROOT = macosx; 193 | }; 194 | name = Debug; 195 | }; 196 | 1DEB927A08733DD40010E9CD /* Release */ = { 197 | isa = XCBuildConfiguration; 198 | buildSettings = { 199 | GCC_C_LANGUAGE_STANDARD = gnu99; 200 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 201 | GCC_WARN_UNUSED_VARIABLE = YES; 202 | HEADER_SEARCH_PATHS = ../..; 203 | MACOSX_DEPLOYMENT_TARGET = 10.9; 204 | SDKROOT = macosx; 205 | }; 206 | name = Release; 207 | }; 208 | /* End XCBuildConfiguration section */ 209 | 210 | /* Begin XCConfigurationList section */ 211 | 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "zku" */ = { 212 | isa = XCConfigurationList; 213 | buildConfigurations = ( 214 | 1DEB927508733DD40010E9CD /* Debug */, 215 | 1DEB927608733DD40010E9CD /* Release */, 216 | ); 217 | defaultConfigurationIsVisible = 0; 218 | defaultConfigurationName = Release; 219 | }; 220 | 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "zku" */ = { 221 | isa = XCConfigurationList; 222 | buildConfigurations = ( 223 | 1DEB927908733DD40010E9CD /* Debug */, 224 | 1DEB927A08733DD40010E9CD /* Release */, 225 | ); 226 | defaultConfigurationIsVisible = 0; 227 | defaultConfigurationName = Release; 228 | }; 229 | /* End XCConfigurationList section */ 230 | }; 231 | rootObject = 08FB7793FE84155DC02AAC07 /* Project object */; 232 | } 233 | -------------------------------------------------------------------------------- /Demos/zku/zku.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demos/zku/zku.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Demos/zku/zku.xcodeproj/project.xcworkspace/xcshareddata/zku.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 4E91E8DC-A8EB-4B88-B70D-96BA9B0F28ED 9 | IDESourceControlProjectName 10 | zku 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | C34FB7BE-63F4-4719-8110-638F882D6936 14 | https://github.com/kolpanic/ZipKit.git 15 | EAE9B5D4-3932-4032-B639-0B274ECDAD3A 16 | ssh://github.com/kolpanic/zku.git 17 | 18 | IDESourceControlProjectPath 19 | zku.xcodeproj/project.xcworkspace 20 | IDESourceControlProjectRelativeInstallPathDictionary 21 | 22 | C34FB7BE-63F4-4719-8110-638F882D6936 23 | ../../ZipKit 24 | EAE9B5D4-3932-4032-B639-0B274ECDAD3A 25 | ../.. 26 | 27 | IDESourceControlProjectURL 28 | ssh://github.com/kolpanic/zku.git 29 | IDESourceControlProjectVersion 30 | 110 31 | IDESourceControlProjectWCCIdentifier 32 | EAE9B5D4-3932-4032-B639-0B274ECDAD3A 33 | IDESourceControlProjectWCConfigurations 34 | 35 | 36 | IDESourceControlRepositoryExtensionIdentifierKey 37 | public.vcs.git 38 | IDESourceControlWCCIdentifierKey 39 | C34FB7BE-63F4-4719-8110-638F882D6936 40 | IDESourceControlWCCName 41 | ZipKit 42 | 43 | 44 | IDESourceControlRepositoryExtensionIdentifierKey 45 | public.vcs.git 46 | IDESourceControlWCCIdentifierKey 47 | EAE9B5D4-3932-4032-B639-0B274ECDAD3A 48 | IDESourceControlWCCName 49 | zku 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ZipKit 2 | ====== 3 | 4 | ZipKit is an Objective-C framework for reading and writing Zip archives in macOS and iOS apps. It supports: 5 | 6 | * the standard [PKZip format](http://www.pkware.com/documents/casestudies/APPNOTE.TXT); 7 | * files larger than 4GB in size using PKZip's zip64 extensions (`ZKFileArchive` only); 8 | * optionally, resource forks in a manner compatible with macOS's Archive Utility (in the macOS targets only); 9 | * clean interruption, so archiving can be cancelled by the invoking object (e.g., a NSOperation or NSThread). 10 | 11 | It was developed by [Karl Moskowski](https://mstdn.ca/@kolpanic) and released under the BSD license. If you find ZipKit to be useful, please let me know. 12 | 13 | ### Requirements 14 | 15 | ZipKit requires Xcode 4.6 or higher. It works on OS X 10.8 Mountain Lion, and iOS 6.0 or higher. (If you're using older versions, make sure you `git checkout 1.0.0`. The project at that tag supports garbage collection and manual memory management.) The Xcode project contains three targets: a macOS framework, a macOS static library, and an iOS static library. 16 | 17 | ### Using ZipKit 18 | 19 | 1. If you're using git for your project, first add ZipKit as a submodule to your project. If you're not using git, clone ZipKit into your project's directory. (If you're using another VCS, you might want to ignore the ZipKit sub-project, or at least its .git/ directory.) 20 | 2. Open your `.xcodeproj` and drag `ZipKit Framework.xcodeproj` from the Finder to Xcode's Project Navigator for your project. The Frameworks group is a good place for it. 21 | 3. In the Project Navigator for your project, disclose ZipKit's Products and note the one you want to use in your project. 22 | 4. In the Project Navigator, select your project at the top, then: 23 | * add the relevant ZipKit product to your target's Linked Frameworks and Libraries section, and add it to the your target's Target Dependencies under Build Phases; 24 | * add `libz.dylib` to your target's Linked Frameworks; 25 | * add `./ZipKit/` to your "Header Search Paths" setting 26 | 5. If you're using one of ZipKit's static library targets in your project, add -ObjC to your target's Other Linker Flags. You may have to add -all_load as well. (Objective-C categories aren't properly linked by default when using static libraries.) 27 | 28 | Open `ZipKit.xcworkspace` in Xcode and see the included Demo Projects for guidance. 29 | 30 | ### License 31 | 32 | ZipKit is released under the BSD license. It's in COPYING.TXT in the project. Acknowledge ZipKit (and other FOSS projects you use) in your app's About or Settings view or window. (If your iOS app doesn't have either, you can add a Settings Bundle; see the ZipKit Touch demo.) 33 | 34 | ### Credits 35 | 36 | * Thanks to Jaka Jančar for original implementation of manual memory management & iOS support. 37 | * [MacFUSE](http://code.google.com/p/macfuse/)'s `GMAppleDouble` used with appreciation. 38 | -------------------------------------------------------------------------------- /ZipKit Framework.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /ZipKit Framework.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ZipKit Framework.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ZipKit Framework.xcodeproj/project.xcworkspace/xcshareddata/ZipKit.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | B46CE300-6AA4-47DD-8ACF-724FE9BBEBC9 9 | IDESourceControlProjectName 10 | ZipKit 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 940F78D5F98A404F0CE03A452F2871238905218C 14 | github.com:kolpanic/ZipKit.git 15 | 16 | IDESourceControlProjectPath 17 | ZipKit.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 940F78D5F98A404F0CE03A452F2871238905218C 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | github.com:kolpanic/ZipKit.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 940F78D5F98A404F0CE03A452F2871238905218C 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 940F78D5F98A404F0CE03A452F2871238905218C 36 | IDESourceControlWCCName 37 | ZipKit 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /ZipKit Framework.xcodeproj/xcshareddata/xcschemes/ZipKit.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 57 | 58 | 59 | 60 | 62 | 63 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /ZipKit Framework.xcodeproj/xcshareddata/xcschemes/libtouchzipkit.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 57 | 58 | 59 | 60 | 62 | 63 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /ZipKit Framework.xcodeproj/xcshareddata/xcschemes/libzipkit.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 44 | 50 | 51 | 57 | 58 | 59 | 60 | 62 | 63 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /ZipKit.podspec: -------------------------------------------------------------------------------- 1 | # 2 | # Be sure to run `pod spec lint ZipKit.podspec' to ensure this is a 3 | # valid spec and to remove all comments including this before submitting the spec. 4 | # 5 | # To learn more about Podspec attributes see http://docs.cocoapods.org/specification.html 6 | # To see working Podspecs in the CocoaPods repo see https://github.com/CocoaPods/Specs/ 7 | # 8 | 9 | Pod::Spec.new do |s| 10 | 11 | s.name = "ZipKit" 12 | s.version = "1.0.3" 13 | s.summary = "An Objective-C Zip framework for Mac OS X and iOS." 14 | 15 | s.description = <<-DESC 16 | ZipKit is an Objective-C framework for reading and writing Zip archives 17 | in Mac OS X and iOS apps. It supports the standard PKZip format, files 18 | larger than 4GB in size using PKZip's zip64 extensions, optionally, 19 | resource forks in a manner compatible with Mac OS X's Archive 20 | Utility (in the Mac OS X targets only), and clean interruption so archiving 21 | can be cancelled by the invoking object (e.g., a NSOperation or NSThread). 22 | DESC 23 | 24 | s.homepage = "https://github.com/kolpanic/ZipKit" 25 | 26 | s.license = { :type => "BSD", :file => "COPYING.TXT" } 27 | 28 | s.authors = { "Karl Moskowski" => "kmoskowski@me.com" } 29 | s.social_media_url = "http://twitter.com/kolpanic" 30 | 31 | s.ios.deployment_target = "6.1" 32 | s.osx.deployment_target = "10.8" 33 | 34 | s.source = { :git => "https://github.com/kolpanic/ZipKit.git", :tag => "1.0.3" } 35 | 36 | s.source_files = "**/*.{h,m}" 37 | s.ios.exclude_files = "GMAppleDouble" 38 | 39 | s.ios.frameworks = "Foundation" 40 | s.osx.frameworks = "Foundation", "CoreServices" 41 | s.library = "z" 42 | 43 | s.requires_arc = true 44 | 45 | end 46 | -------------------------------------------------------------------------------- /ZipKit.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 12 | 13 | 16 | 18 | 19 | 21 | 22 | 24 | 25 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /ZipKit.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /ZipKit/GMAppleDouble+ZKAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // GMAppleDouble+ZKAdditions.h 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import 9 | 10 | @interface GMAppleDouble (ZKAdditions) 11 | 12 | + (NSData *)zk_appleDoubleDataForPath:(NSString *)path; 13 | + (void)zk_restoreAppleDoubleData:(NSData *)appleDoubleData toPath:(NSString *)path; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ZipKit/GMAppleDouble+ZKAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // GMAppleDouble+ZKAdditions.m 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import "GMAppleDouble+ZKAdditions.h" 9 | #include 10 | 11 | @implementation GMAppleDouble (ZKAdditions) 12 | 13 | + (NSData *)zk_appleDoubleDataForPath:(NSString *)path { 14 | // extract a file's Finder info metadata and resource fork to a NSData object suitable for writing to a ._ file 15 | NSData *appleDoubleData = nil; 16 | if ([[NSFileManager new] fileExistsAtPath:path]) { 17 | GMAppleDouble *appleDouble = [GMAppleDouble appleDouble]; 18 | NSMutableData *data; 19 | 20 | ssize_t finderInfoSize = getxattr([path fileSystemRepresentation], XATTR_FINDERINFO_NAME, NULL, ULONG_MAX, 0, XATTR_NOFOLLOW); 21 | if (finderInfoSize > 0) { 22 | data = [NSMutableData dataWithLength:finderInfoSize]; 23 | if (getxattr([path fileSystemRepresentation], XATTR_FINDERINFO_NAME, [data mutableBytes], [data length], 0, XATTR_NOFOLLOW) > 0) { 24 | [appleDouble addEntryWithID:DoubleEntryFinderInfo data:data]; 25 | } 26 | } 27 | 28 | ssize_t resourceForkSize = getxattr([path fileSystemRepresentation], XATTR_RESOURCEFORK_NAME, NULL, ULONG_MAX, 0, XATTR_NOFOLLOW); 29 | if (resourceForkSize > 0) { 30 | data = [NSMutableData dataWithLength:resourceForkSize]; 31 | if (getxattr([path fileSystemRepresentation], XATTR_RESOURCEFORK_NAME, [data mutableBytes], [data length], 0, XATTR_NOFOLLOW) > 0) { 32 | [appleDouble addEntryWithID:DoubleEntryResourceFork data:data]; 33 | } 34 | } 35 | 36 | if ([[appleDouble entries] count]) { 37 | appleDoubleData = [appleDouble data]; 38 | } 39 | } 40 | return appleDoubleData; 41 | } 42 | 43 | + (void)zk_restoreAppleDoubleData:(NSData *)appleDoubleData toPath:(NSString *)path { 44 | // retsore AppleDouble NSData to a file's Finder info metadata and resource fork 45 | if ([[NSFileManager new] fileExistsAtPath:path]) { 46 | GMAppleDouble *appleDouble = [GMAppleDouble appleDoubleWithData:appleDoubleData]; 47 | if ([appleDouble entries] && [[appleDouble entries] count] > 0) { 48 | for (GMAppleDoubleEntry *entry in [appleDouble entries]) { 49 | char *key = NULL; 50 | if ([entry entryID] == DoubleEntryFinderInfo) { 51 | key = XATTR_FINDERINFO_NAME; 52 | } else if ([entry entryID] == DoubleEntryResourceFork) { 53 | key = XATTR_RESOURCEFORK_NAME; 54 | } 55 | if (key != NULL) { 56 | setxattr([path fileSystemRepresentation], key, [[entry data] bytes], [[entry data] length], 0, XATTR_NOFOLLOW); 57 | } 58 | } 59 | } 60 | } 61 | } 62 | 63 | @end 64 | -------------------------------------------------------------------------------- /ZipKit/GMAppleDouble.h: -------------------------------------------------------------------------------- 1 | MacFUSE/GMAppleDouble.h -------------------------------------------------------------------------------- /ZipKit/MacFUSE/COPYING.TXT: -------------------------------------------------------------------------------- 1 | MacFUSE is a package developed by Google and is covered under the following 2 | BSD-style license: 3 | 4 | ================================================================ 5 | Copyright (c) 2007-2009 Google Inc. 6 | All rights reserved. 7 | 8 | Redistribution and use in source and binary forms, with or without 9 | modification, are permitted provided that the following conditions are 10 | met: 11 | 12 | * Redistributions of source code must retain the above copyright 13 | notice, this list of conditions and the following disclaimer. 14 | * Redistributions in binary form must reproduce the above 15 | copyright notice, this list of conditions and the following disclaimer 16 | in the documentation and/or other materials provided with the 17 | distribution. 18 | * Neither the name of Google Inc. nor the names of its 19 | contributors may be used to endorse or promote products derived from 20 | this software without specific prior written permission. 21 | 22 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 23 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 24 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 25 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 26 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 27 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 28 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 32 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 | ================================================================ 34 | 35 | Note that Google's patches to the FUSE library (libfuse/*.patch) (and to 36 | the SSHFS user-space program (filesystems/sshfs/*.patch) are also released 37 | under the BSD license. 38 | 39 | Portions of this package were derived from code developed by other authors. 40 | Please read further for specific details. 41 | 42 | * fusefs/fuse_kernel.h is an unmodified copy of the interface header from 43 | the Linux FUSE distribution (http://fuse.sourceforge.net). fuse_kernel.h 44 | can be redistributed either under the GPL or under the BSD license. It 45 | is being redistributed here under the BSD license. 46 | 47 | * Unless otherwise noted, parts of MacFUSE (multiple files in fusefs/) contain 48 | code derived from the FreeBSD version of FUSE (http://fuse4bsd.creo.hu), 49 | which is covered by the following BSD-style license: 50 | 51 | ================================================================ 52 | Copyright (C) 2005 Csaba Henk. All rights reserved. 53 | 54 | Redistribution and use in source and binary forms, with or without 55 | modification, are permitted provided that the following conditions 56 | are met: 57 | 1. Redistributions of source code must retain the above copyright 58 | notice, this list of conditions and the following disclaimer. 59 | 2. Redistributions in binary form must reproduce the above copyright 60 | notice, this list of conditions and the following disclaimer in the 61 | documentation and/or other materials provided with the distribution. 62 | 63 | THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 64 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 65 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 66 | ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 67 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 68 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 69 | OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 70 | HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 71 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 72 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 73 | SUCH DAMAGE. 74 | ================================================================ 75 | 76 | * fusefs/fuse_nodehash.c is a modified version of HashNode.c from an 77 | Apple Developer Technical Support (DTS) sample code example. The original 78 | source, which is available on http://developer.apple.com/samplecode/, has 79 | the following disclaimer: 80 | 81 | ================================================================ 82 | Disclaimer: IMPORTANT: This Apple software is supplied to you by 83 | Apple Computer, Inc. Apple") in consideration of your agreement 84 | to the following terms, and your use, installation, modification 85 | or redistribution of this Apple software constitutes acceptance 86 | of these terms. If you do not agree with these terms, please do 87 | not use, install, modify or redistribute this Apple software. 88 | 89 | In consideration of your agreement to abide by the following terms, 90 | and subject to these terms, Apple grants you a personal, non-exclusive 91 | license, under Apple's copyrights in this original Apple software 92 | (the "Apple Software"), to use, reproduce, modify and redistribute 93 | the Apple Software, with or without modifications, in source and/or 94 | binary forms; provided that if you redistribute the Apple Software 95 | in its entirety and without modifications, you must retain this 96 | notice and the following text and disclaimers in all such 97 | redistributions of the Apple Software. Neither the name, 98 | trademarks, service marks or logos of Apple Computer, Inc. may be 99 | used to endorse or promote products derived from the Apple Software 100 | without specific prior written permission from Apple. Except as 101 | expressly stated in this notice, no other rights or licenses, 102 | express or implied, are granted by Apple herein, including but 103 | not limited to any patent rights that may be infringed by your 104 | derivative works or by other works in which the Apple Software 105 | may be incorporated. 106 | 107 | The Apple Software is provided by Apple on an "AS IS" basis. APPLE 108 | MAKES NO WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION 109 | THE IMPLIED WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND 110 | FITNESS FOR A PARTICULAR PURPOSE, REGARDING THE APPLE SOFTWARE OR 111 | ITS USE AND OPERATION ALONE OR IN COMBINATION WITH YOUR PRODUCTS. 112 | 113 | IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, 114 | INCIDENTAL OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 115 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 116 | PROFITS; OR BUSINESS INTERRUPTION) ARISING IN ANY WAY OUT OF THE USE, 117 | REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE APPLE SOFTWARE, 118 | HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT (INCLUDING 119 | NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN 120 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 121 | ================================================================ 122 | 123 | * Parts of the mount_fusefs and the load_fusefs command-line programs 124 | (implemented in fusefs/mount_fusefs/ and fusefs/load_fusefs/, respectively) 125 | come from Apple's Darwin sources and are covered under the Apple Public 126 | Source License (APSL). You can read the APSL at: 127 | 128 | http://www.publicsource.apple.com/apsl/ -------------------------------------------------------------------------------- /ZipKit/MacFUSE/GMAppleDouble.h: -------------------------------------------------------------------------------- 1 | // ================================================================ 2 | // Copyright (c) 2007, Google Inc. 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | // ================================================================ 31 | // 32 | // GMAppleDouble.h 33 | // MacFUSE 34 | // 35 | // Created by ted on 12/29/07. 36 | // 37 | 38 | /*! 39 | * @header GMAppleDouble 40 | * 41 | * A utility class to construct an AppleDouble (._) file. 42 | * 43 | * AppleDouble files contain information about a corresponding file and are 44 | * typically used on file systems that do not support extended attributes. 45 | */ 46 | 47 | #import 48 | 49 | #define GM_EXPORT __attribute__((visibility("default"))) 50 | 51 | /*! 52 | *
 53 |  * Based on "AppleSingle/AppleDouble Formats for Foreign Files Developer's Note"
 54 |  *
 55 |  * Notes:
 56 |  * DoubleEntryFileDatesInfo
 57 |  *    File creation, modification, backup, and access times as number of seconds
 58 |  *    before or after 12:00 AM Jan 1 2000 GMT as SInt32.
 59 |  *  DoubleEntryFinderInfo
 60 |  *    16 bytes of FinderInfo followed by 16 bytes of extended FinderInfo.
 61 |  *    New FinderInfo should be zero'd out. For a directory, when the Finder
 62 |  *    encounters an entry with the init'd bit cleared, it will initialize the
 63 |  *    frView field of the to a value indicating how the contents of the
 64 |  *    directory should be shown. Recommend to set frView to value of 256.
 65 |  *  DoubleEntryMacFileInfo
 66 |  *    This is a 32 bit flag that stores locked (bit 0) and protected (bit 1).
 67 |  * 
68 | */ 69 | typedef enum { 70 | DoubleEntryInvalid = 0, 71 | DoubleEntryDataFork = 1, 72 | DoubleEntryResourceFork = 2, 73 | DoubleEntryRealName = 3, 74 | DoubleEntryComment = 4, 75 | DoubleEntryBlackAndWhiteIcon = 5, 76 | DoubleEntryColorIcon = 6, 77 | DoubleEntryFileDatesInfo = 8, // See notes 78 | DoubleEntryFinderInfo = 9, // See notes 79 | DoubleEntryMacFileInfo = 10, // See notes 80 | DoubleEntryProDosFileInfo = 11, 81 | DoubleEntryMSDosFileinfo = 12, 82 | DoubleEntryShortName = 13, 83 | DoubleEntryAFPFileInfo = 14, 84 | DoubleEntryDirectoryID = 15, 85 | } GMAppleDoubleEntryID; 86 | 87 | /*! 88 | * @class 89 | * @note This class represents a single entry in an AppleDouble file. 90 | */ 91 | GM_EXPORT @interface GMAppleDoubleEntry : NSObject { 92 | @private 93 | GMAppleDoubleEntryID entryID_; 94 | NSData *data_; // Format depends on entryID_ 95 | } 96 | /*! 97 | * @abstract Initializes an AppleDouble entry with ID and data. 98 | * @param entryID A valid entry identifier 99 | * @param data Raw data for the entry 100 | */ 101 | - (id) initWithEntryID:(GMAppleDoubleEntryID)entryID data:(NSData *)data; 102 | 103 | /*! @abstract The entry ID */ 104 | - (GMAppleDoubleEntryID) entryID; 105 | 106 | /*! @abstract The entry data */ 107 | - (NSData *) data; 108 | @end 109 | 110 | /*! 111 | * @class 112 | * @note This class can be used to construct raw AppleDouble data. 113 | */ 114 | GM_EXPORT @interface GMAppleDouble : NSObject { 115 | @private 116 | NSMutableArray *entries_; 117 | } 118 | 119 | /*! @abstract An autoreleased empty GMAppleDouble file */ 120 | + (GMAppleDouble *) appleDouble; 121 | 122 | /*! 123 | * @abstract An autoreleased GMAppleDouble file. 124 | * @note The GMAppleDouble is pre-filled with entries from the raw 125 | * AppleDouble file data. 126 | * @param data Raw AppleDouble file data. 127 | */ 128 | + (GMAppleDouble *) appleDoubleWithData:(NSData *)data; 129 | 130 | /*! 131 | * @abstract Adds an entry to the AppleDouble file. 132 | * @param entry The entry to add 133 | */ 134 | - (void) addEntry:(GMAppleDoubleEntry *)entry; 135 | 136 | /*! 137 | * @abstract Adds an entry to the AppleDouble file with ID and data. 138 | * @param entryID The ID of the entry to add 139 | * @param data The raw data for the entry to add (retained) 140 | */ 141 | - (void) addEntryWithID:(GMAppleDoubleEntryID)entryID data:(NSData *)data; 142 | 143 | /*! 144 | * @abstract Adds entries based on the provided raw AppleDouble file data. 145 | * @note This will attempt to parse the given data as an AppleDouble file 146 | * and add all entries found. 147 | * @param data Raw AppleDouble file data 148 | * @result YES if the provided data was parsed correctly. 149 | */ 150 | - (BOOL) addEntriesFromAppleDoubleData:(NSData *)data; 151 | 152 | /*! 153 | * @abstract The set of GMAppleDoubleEntry present in this GMAppleDouble. 154 | * @result An array of GMAppleDoubleEntry. 155 | */ 156 | - (NSArray *) entries; 157 | 158 | /*! 159 | * @abstract Constructs raw data for the AppleDouble file. 160 | * @result The raw data for an AppleDouble file represented by this GMAppleDouble. 161 | */ 162 | - (NSData *) data; 163 | 164 | @end 165 | 166 | #undef GM_EXPORT 167 | -------------------------------------------------------------------------------- /ZipKit/MacFUSE/GMAppleDouble.m: -------------------------------------------------------------------------------- 1 | // ================================================================ 2 | // Copyright (c) 2007, Google Inc. 3 | // All rights reserved. 4 | // 5 | // Redistribution and use in source and binary forms, with or without 6 | // modification, are permitted provided that the following conditions are 7 | // met: 8 | // 9 | // * Redistributions of source code must retain the above copyright 10 | // notice, this list of conditions and the following disclaimer. 11 | // * Redistributions in binary form must reproduce the above 12 | // copyright notice, this list of conditions and the following disclaimer 13 | // in the documentation and/or other materials provided with the 14 | // distribution. 15 | // * Neither the name of Google Inc. nor the names of its 16 | // contributors may be used to endorse or promote products derived from 17 | // this software without specific prior written permission. 18 | // 19 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 | // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 | // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 | // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 | // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 | // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 | // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | // ================================================================ 31 | // 32 | // GMAppleDouble.m 33 | // MacFUSE 34 | // 35 | // Created by ted on 12/29/07. 36 | // 37 | #import "GMAppleDouble.h" 38 | #import "libkern/OSByteOrder.h" 39 | 40 | #define GM_APPLE_DOUBLE_HEADER_MAGIC 0x00051607 41 | #define GM_APPLE_DOUBLE_HEADER_VERSION 0x00020000 42 | 43 | typedef struct { 44 | UInt32 magicNumber; // Should be 0x00051607 45 | UInt32 versionNumber; // Should be 0x00020000 46 | char filler[16]; // Zero-filled bytes. 47 | UInt16 numberOfEntries; // Number of entries. 48 | } __attribute__ ((packed)) DoubleHeader; 49 | 50 | typedef struct { 51 | UInt32 entryID; // Defines what entry is (0 is invalid) 52 | UInt32 offset; // Offset from beginning of file to entry data. 53 | UInt32 length; // Length of entry data in bytes. 54 | } __attribute__ ((packed)) DoubleEntryHeader; 55 | 56 | @implementation GMAppleDoubleEntry 57 | 58 | + (GMAppleDoubleEntry *) entryWithID :(GMAppleDoubleEntryID)entryID 59 | data :(NSData *)data { 60 | return [[GMAppleDoubleEntry alloc] 61 | initWithEntryID:entryID data:data]; 62 | } 63 | 64 | - (id) initWithEntryID :(GMAppleDoubleEntryID)entryID 65 | data :(NSData *)data { 66 | if ((self = [super init])) { 67 | if (entryID == DoubleEntryInvalid || data == nil) 68 | return nil; 69 | entryID_ = entryID; 70 | data_ = data; 71 | } 72 | return self; 73 | } 74 | 75 | 76 | - (GMAppleDoubleEntryID) entryID { 77 | return entryID_; 78 | } 79 | - (NSData *) data { 80 | return data_; 81 | } 82 | 83 | @end 84 | 85 | @implementation GMAppleDouble 86 | 87 | + (GMAppleDouble *) appleDouble { 88 | return [[GMAppleDouble alloc] init]; 89 | } 90 | 91 | + (GMAppleDouble *) appleDoubleWithData:(NSData *)data { 92 | GMAppleDouble *appleDouble = [[GMAppleDouble alloc] init]; 93 | if ([appleDouble addEntriesFromAppleDoubleData:data]) 94 | return appleDouble; 95 | return nil; 96 | } 97 | 98 | - (id) init { 99 | if ((self = [super init])) 100 | entries_ = [[NSMutableArray alloc] init]; 101 | return self; 102 | } 103 | 104 | 105 | - (void) addEntry:(GMAppleDoubleEntry *)entry { 106 | [entries_ addObject:entry]; 107 | } 108 | 109 | - (void) addEntryWithID:(GMAppleDoubleEntryID)entryID data:(NSData *)data { 110 | GMAppleDoubleEntry *entry = [GMAppleDoubleEntry entryWithID:entryID data:data]; 111 | [self addEntry:entry]; 112 | } 113 | 114 | - (BOOL) addEntriesFromAppleDoubleData:(NSData *)data { 115 | const int len = (int)[data length]; 116 | DoubleHeader header; 117 | if (len < sizeof(header)) 118 | return NO; // To small to even fit our header. 119 | [data getBytes:&header length:sizeof(header)]; 120 | if (OSSwapBigToHostInt32(header.magicNumber) != GM_APPLE_DOUBLE_HEADER_MAGIC || 121 | OSSwapBigToHostInt32(header.versionNumber) != GM_APPLE_DOUBLE_HEADER_VERSION) 122 | return NO; // Invalid header. 123 | int count = OSSwapBigToHostInt16(header.numberOfEntries); 124 | int offset = sizeof(DoubleHeader); 125 | if (len < (offset + (count * sizeof(DoubleEntryHeader)))) 126 | return NO; // Not enough data to hold all the DoubleEntryHeader. 127 | for (int i = 0; i < count; ++i, offset += sizeof(DoubleEntryHeader)) { 128 | // Extract header 129 | DoubleEntryHeader entryHeader; 130 | NSRange range = NSMakeRange(offset, sizeof(entryHeader)); 131 | [data getBytes:&entryHeader range:range]; 132 | 133 | // Extract data 134 | range = NSMakeRange(OSSwapBigToHostInt32(entryHeader.offset), 135 | OSSwapBigToHostInt32(entryHeader.length)); 136 | if (len < (range.location + range.length)) 137 | return NO; // Given data too small to contain this entry. 138 | NSData *entryData = [data subdataWithRange:range]; 139 | [self addEntryWithID:OSSwapBigToHostInt32(entryHeader.entryID) data:entryData]; 140 | } 141 | 142 | return YES; 143 | } 144 | 145 | - (NSArray *) entries { 146 | return entries_; 147 | } 148 | 149 | - (NSData *) data { 150 | NSMutableData *entryListData = [NSMutableData data]; 151 | NSMutableData *entryData = [NSMutableData data]; 152 | int dataStartOffset = 153 | sizeof(DoubleHeader) + (int)[entries_ count] * sizeof(DoubleEntryHeader); 154 | for (int i = 0; i < [entries_ count]; ++i) { 155 | GMAppleDoubleEntry *entry = [entries_ objectAtIndex:i]; 156 | 157 | DoubleEntryHeader entryHeader; 158 | memset(&entryHeader, 0, sizeof(entryHeader)); 159 | entryHeader.entryID = OSSwapHostToBigInt32((UInt32)[entry entryID]); 160 | entryHeader.offset = 161 | OSSwapHostToBigInt32((UInt32)(dataStartOffset + [entryData length])); 162 | entryHeader.length = OSSwapHostToBigInt32((UInt32)[[entry data] length]); 163 | [entryListData appendBytes:&entryHeader length:sizeof(entryHeader)]; 164 | [entryData appendData:[entry data]]; 165 | } 166 | 167 | NSMutableData *data = [NSMutableData data]; 168 | 169 | DoubleHeader header; 170 | memset(&header, 0, sizeof(header)); 171 | header.magicNumber = OSSwapHostToBigConstInt32(GM_APPLE_DOUBLE_HEADER_MAGIC); 172 | header.versionNumber = OSSwapHostToBigConstInt32(GM_APPLE_DOUBLE_HEADER_VERSION); 173 | header.numberOfEntries = OSSwapHostToBigInt16((UInt16)[entries_ count]); 174 | [data appendBytes:&header length:sizeof(header)]; 175 | [data appendData:entryListData]; 176 | [data appendData:entryData]; 177 | return data; 178 | } 179 | 180 | @end 181 | -------------------------------------------------------------------------------- /ZipKit/NSData+ZKAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+ZKAdditions.h 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import 9 | 10 | @interface NSData (ZKAdditions) 11 | 12 | - (UInt16)zk_hostInt16OffsetBy:(UInt64 *)offset; 13 | - (UInt32)zk_hostInt32OffsetBy:(UInt64 *)offset; 14 | - (UInt64)zk_hostInt64OffsetBy:(UInt64 *)offset; 15 | - (BOOL)zk_hostBoolOffsetBy:(UInt64 *)offset; 16 | - (NSString *)zk_stringOffsetBy:(UInt64 *)offset length:(NSUInteger)length; 17 | - (UInt32)zk_crc32; 18 | - (UInt32)zk_crc32:(unsigned long)crc; 19 | 20 | - (NSData *)zk_inflateWithWindowBits:(int)windowBits; 21 | - (NSData *)zk_deflateWithLevel:(int)level windowBits:(int)windowBits memoryLevel:(int)memoryLevel strategy:(int)strategy; 22 | - (NSData *)zk_inflate; 23 | - (NSData *)zk_deflate; 24 | 25 | @end 26 | 27 | @interface NSMutableData (ZKAdditions) 28 | 29 | + (NSMutableData *)zk_dataWithLittleInt16:(UInt16)value; 30 | + (NSMutableData *)zk_dataWithLittleInt32:(UInt32)value; 31 | + (NSMutableData *)zk_dataWithLittleInt64:(UInt64)value; 32 | 33 | - (void)zk_appendLittleInt16:(UInt16)value; 34 | - (void)zk_appendLittleInt32:(UInt32)value; 35 | - (void)zk_appendLittleInt64:(UInt64)value; 36 | - (void)zk_appendLittleBool:(BOOL)value; 37 | - (void)zk_appendPrecomposedUTF8String:(NSString *)value; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /ZipKit/NSData+ZKAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSData+ZKAdditions.m 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import "NSData+ZKAdditions.h" 9 | #import "NSFileManager+ZKAdditions.h" 10 | #import "ZKCDHeader.h" 11 | #import "ZKCDTrailer.h" 12 | #import "ZKLFHeader.h" 13 | #import "zlib.h" 14 | 15 | @implementation NSData (ZKAdditions) 16 | 17 | - (UInt16)zk_hostInt16OffsetBy:(UInt64 *)offset { 18 | UInt16 value; 19 | NSUInteger length = sizeof(value); 20 | [self getBytes:&value range:NSMakeRange((NSUInteger) * offset, length)]; 21 | *offset += length; 22 | return CFSwapInt16LittleToHost(value); 23 | } 24 | 25 | - (UInt32)zk_hostInt32OffsetBy:(UInt64 *)offset { 26 | UInt32 value; 27 | NSUInteger length = sizeof(value); 28 | [self getBytes:&value range:NSMakeRange((NSUInteger) * offset, length)]; 29 | *offset += length; 30 | return CFSwapInt32LittleToHost(value); 31 | } 32 | 33 | - (UInt64)zk_hostInt64OffsetBy:(UInt64 *)offset { 34 | UInt64 value; 35 | NSUInteger length = sizeof(value); 36 | [self getBytes:&value range:NSMakeRange((NSUInteger) * offset, length)]; 37 | *offset += length; 38 | return CFSwapInt64LittleToHost(value); 39 | } 40 | 41 | - (BOOL)zk_hostBoolOffsetBy:(UInt64 *)offset { 42 | UInt32 value = [self zk_hostInt32OffsetBy:offset]; 43 | return value != 0; 44 | } 45 | 46 | - (NSString *)zk_stringOffsetBy:(UInt64 *)offset length:(NSUInteger)length { 47 | NSString *value = nil; 48 | NSData *subData = [self subdataWithRange:NSMakeRange((NSUInteger) * offset, length)]; 49 | if (length > 0) { 50 | value = [[NSString alloc] initWithData:subData encoding:NSUTF8StringEncoding]; 51 | } 52 | if (!value) { 53 | // No valid utf8 encoding, replace everything non-ascii with '?' 54 | NSMutableData *md = [subData mutableCopyWithZone:nil]; 55 | unsigned char *mdd = [md mutableBytes]; 56 | if ([md length] > 0) { 57 | for (unsigned int i = 0; i < [md length]; i++) { 58 | if (mdd[i] > 127) { 59 | mdd[i] = '?'; 60 | } 61 | } 62 | value = [[NSString alloc] initWithData:md encoding:NSUTF8StringEncoding]; 63 | } 64 | } 65 | *offset += length; 66 | return value; 67 | } 68 | 69 | - (UInt32)zk_crc32 { 70 | return [self zk_crc32:0]; 71 | } 72 | 73 | - (UInt32)zk_crc32:(unsigned long)crc { 74 | return (UInt32)crc32(crc, [self bytes], (unsigned int)[self length]); 75 | } 76 | 77 | - (NSData *)zk_inflate { 78 | return [self zk_inflateWithWindowBits:(-MAX_WBITS)]; 79 | } 80 | 81 | - (NSData *)zk_inflateWithWindowBits:(int)windowBits { 82 | NSUInteger full_length = [self length]; 83 | NSUInteger half_length = full_length / 2; 84 | 85 | NSMutableData *inflatedData = [NSMutableData dataWithLength:full_length + half_length]; 86 | BOOL done = NO; 87 | int status; 88 | 89 | z_stream strm; 90 | 91 | strm.next_in = (Bytef *)[self bytes]; 92 | strm.avail_in = (unsigned int)[self length]; 93 | strm.total_out = 0; 94 | strm.zalloc = Z_NULL; 95 | strm.zfree = Z_NULL; 96 | 97 | if (inflateInit2(&strm, windowBits) != Z_OK) { 98 | return nil; 99 | } 100 | while (!done) { 101 | if (strm.total_out >= [inflatedData length]) { 102 | [inflatedData increaseLengthBy:half_length]; 103 | } 104 | strm.next_out = [inflatedData mutableBytes] + strm.total_out; 105 | strm.avail_out = (unsigned int)([inflatedData length] - strm.total_out); 106 | status = inflate(&strm, Z_SYNC_FLUSH); 107 | if (status == Z_STREAM_END) { 108 | done = YES; 109 | } else if (status != Z_OK) { 110 | break; 111 | } 112 | } 113 | if (inflateEnd(&strm) == Z_OK && done) { 114 | [inflatedData setLength:strm.total_out]; 115 | } else { 116 | inflatedData = nil; 117 | } 118 | return inflatedData; 119 | } 120 | 121 | - (NSData *)zk_deflate { 122 | return [self zk_deflateWithLevel:Z_BEST_COMPRESSION windowBits:(-MAX_WBITS) memoryLevel:8 strategy:Z_DEFAULT_STRATEGY]; 123 | } 124 | 125 | - (NSData *)zk_deflateWithLevel:(int)level windowBits:(int)windowBits memoryLevel:(int)memoryLevel strategy:(int)strategy { 126 | z_stream strm; 127 | 128 | strm.zalloc = Z_NULL; 129 | strm.zfree = Z_NULL; 130 | strm.opaque = Z_NULL; 131 | strm.total_out = 0; 132 | strm.next_in = (Bytef *)[self bytes]; 133 | strm.avail_in = (unsigned int)[self length]; 134 | 135 | NSMutableData *deflatedData = [NSMutableData dataWithLength:16384]; 136 | if (deflateInit2(&strm, level, Z_DEFLATED, windowBits, memoryLevel, strategy) != Z_OK) { 137 | return nil; 138 | } 139 | do { 140 | if (strm.total_out >= [deflatedData length]) { 141 | [deflatedData increaseLengthBy:16384]; 142 | } 143 | strm.next_out = [deflatedData mutableBytes] + strm.total_out; 144 | strm.avail_out = (unsigned int)([deflatedData length] - strm.total_out); 145 | deflate(&strm, Z_FINISH); 146 | } while (strm.avail_out == 0); 147 | deflateEnd(&strm); 148 | [deflatedData setLength:strm.total_out]; 149 | 150 | return deflatedData; 151 | } 152 | 153 | @end 154 | 155 | @implementation NSMutableData (ZKAdditions) 156 | 157 | + (NSMutableData *)zk_dataWithLittleInt16:(UInt16)value { 158 | NSMutableData *data = [self data]; 159 | [data zk_appendLittleInt16:value]; 160 | return data; 161 | } 162 | 163 | + (NSMutableData *)zk_dataWithLittleInt32:(UInt32)value { 164 | NSMutableData *data = [self data]; 165 | [data zk_appendLittleInt32:value]; 166 | return data; 167 | } 168 | 169 | + (NSMutableData *)zk_dataWithLittleInt64:(UInt64)value { 170 | NSMutableData *data = [self data]; 171 | [data zk_appendLittleInt64:value]; 172 | return data; 173 | } 174 | 175 | - (void)zk_appendLittleInt16:(UInt16)value { 176 | UInt16 swappedValue = CFSwapInt16HostToLittle(value); 177 | [self appendBytes:&swappedValue length:sizeof(swappedValue)]; 178 | } 179 | 180 | - (void)zk_appendLittleInt32:(UInt32)value { 181 | UInt32 swappedValue = CFSwapInt32HostToLittle(value); 182 | [self appendBytes:&swappedValue length:sizeof(swappedValue)]; 183 | } 184 | 185 | - (void)zk_appendLittleInt64:(UInt64)value { 186 | UInt64 swappedValue = CFSwapInt64HostToLittle(value); 187 | [self appendBytes:&swappedValue length:sizeof(swappedValue)]; 188 | } 189 | 190 | - (void)zk_appendLittleBool:(BOOL)value { 191 | return [self zk_appendLittleInt32:(value ? 1 : 0)]; 192 | } 193 | 194 | - (void)zk_appendPrecomposedUTF8String:(NSString *)value { 195 | return [self appendData:[[value precomposedStringWithCanonicalMapping] dataUsingEncoding:NSUTF8StringEncoding]]; 196 | } 197 | 198 | @end 199 | -------------------------------------------------------------------------------- /ZipKit/NSDate+ZKAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDate+ZKAdditions.h 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import 9 | 10 | @interface NSDate (ZKAdditions) 11 | 12 | + (NSDate *)zk_dateWithDosDate:(NSUInteger)dosDate; 13 | - (UInt32)zk_dosDate; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ZipKit/NSDate+ZKAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDate+ZKAdditions.m 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import "NSDate+ZKAdditions.h" 9 | 10 | typedef NS_OPTIONS (NSUInteger, ZKCalendarUnit){ 11 | ZKCalendarUnitEra = kCFCalendarUnitEra, 12 | ZKCalendarUnitYear = kCFCalendarUnitYear, 13 | ZKCalendarUnitMonth = kCFCalendarUnitMonth, 14 | ZKCalendarUnitDay = kCFCalendarUnitDay, 15 | ZKCalendarUnitHour = kCFCalendarUnitHour, 16 | ZKCalendarUnitMinute = kCFCalendarUnitMinute, 17 | ZKCalendarUnitSecond = kCFCalendarUnitSecond, 18 | }; 19 | 20 | @implementation NSDate (ZKAdditions) 21 | 22 | + (NSDate *)zk_dateWithDosDate:(NSUInteger)dosDate { 23 | NSUInteger date = (NSUInteger)(dosDate >> 16); 24 | NSDateComponents *comps = [NSDateComponents new]; 25 | comps.year = ((date & 0x0FE00) / 0x0200) + 1980; 26 | comps.month = (date & 0x1E0) / 0x20; 27 | comps.day = date & 0x1f; 28 | comps.hour = (dosDate & 0xF800) / 0x800; 29 | comps.minute = (dosDate & 0x7E0) / 0x20; 30 | comps.second = 2 * (dosDate & 0x1f); 31 | return [[NSCalendar currentCalendar] dateFromComponents:comps]; 32 | } 33 | 34 | - (UInt32)zk_dosDate { 35 | NSUInteger options = ZKCalendarUnitYear | ZKCalendarUnitMonth | ZKCalendarUnitDay | 36 | ZKCalendarUnitHour | ZKCalendarUnitMinute | ZKCalendarUnitSecond; 37 | NSDateComponents *comps = [[NSCalendar currentCalendar] components:options fromDate:self]; 38 | return ((UInt32)(comps.day + 32 * comps.month + 512 * (comps.year - 1980)) << 16) | (UInt32)(comps.second / 2 + 32 * comps.minute + 2048 * comps.hour); 39 | } 40 | 41 | @end 42 | -------------------------------------------------------------------------------- /ZipKit/NSDictionary+ZKAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSDictionary+ZKAdditions.h 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import 9 | 10 | @interface NSDictionary (ZKAdditions) 11 | 12 | + (NSDictionary *)zk_totalSizeAndCountDictionaryWithSize:(UInt64)size andItemCount:(UInt64)count; 13 | - (UInt64)zk_totalFileSize; 14 | - (UInt64)zk_itemCount; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /ZipKit/NSDictionary+ZKAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSDictionary+ZKAdditions.m 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import "NSDictionary+ZKAdditions.h" 9 | 10 | NSString *const ZKTotalFileSize = @"ZKTotalFileSize"; 11 | NSString *const ZKItemCount = @"ZKItemCount"; 12 | 13 | @implementation NSDictionary (ZKAdditions) 14 | 15 | + (NSDictionary *)zk_totalSizeAndCountDictionaryWithSize:(UInt64)size andItemCount:(UInt64)count { 16 | return @{ZKTotalFileSize: @(size), ZKItemCount: @(count)}; 17 | } 18 | 19 | - (UInt64)zk_totalFileSize { 20 | return [self[ZKTotalFileSize] unsignedLongLongValue]; 21 | } 22 | 23 | - (UInt64)zk_itemCount { 24 | return [self[ZKItemCount] unsignedLongLongValue]; 25 | } 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /ZipKit/NSFileHandle+ZKAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSFileHandle+ZKAdditions.h 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import 9 | 10 | @interface NSFileHandle (ZKAdditions) 11 | 12 | + (NSFileHandle *)zk_newFileHandleForWritingAtPath:(NSString *)path; 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /ZipKit/NSFileHandle+ZKAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSFileHandle+ZKAdditions.m 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import "NSFileHandle+ZKAdditions.h" 9 | 10 | @implementation NSFileHandle (ZKAdditions) 11 | 12 | + (NSFileHandle *)zk_newFileHandleForWritingAtPath:(NSString *)path { 13 | NSFileManager *fm = [NSFileManager new]; 14 | if (![fm fileExistsAtPath:path]) { 15 | [fm createDirectoryAtPath:[path stringByDeletingLastPathComponent] withIntermediateDirectories:YES attributes:nil error:nil]; 16 | [fm createFileAtPath:path contents:nil attributes:nil]; 17 | } 18 | NSFileHandle *fileHandle = [self fileHandleForWritingAtPath:path]; 19 | return fileHandle; 20 | } 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /ZipKit/NSFileManager+ZKAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSFileManager+ZKAdditions.h 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import 9 | #import 10 | 11 | @interface NSFileManager (ZKAdditions) 12 | 13 | - (BOOL)zk_isSymLinkAtPath:(NSString *)path; 14 | - (BOOL)zk_isDirAtPath:(NSString *)path; 15 | 16 | - (UInt64)zk_dataSizeAtFilePath:(NSString *)path; 17 | - (NSDictionary *)zkTotalSizeAndItemCountAtPath:(NSString *)path usingResourceFork:(BOOL)rfFlag; 18 | #if ZK_TARGET_OS_MAC 19 | - (void)zk_combineAppleDoubleInDirectory:(NSString *)path; 20 | #endif 21 | 22 | - (NSDate *)zk_modificationDateForPath:(NSString *)path; 23 | - (UInt32)zk_posixPermissionsAtPath:(NSString *)path; 24 | - (UInt32)zk_externalFileAttributesAtPath:(NSString *)path; 25 | - (UInt32)zk_externalFileAttributesFor:(NSDictionary *)fileAttributes; 26 | 27 | - (UInt32)zk_crcForPath:(NSString *)path; 28 | - (UInt32)zk_crcForPath:(NSString *)path invoker:(id)invoker; 29 | - (UInt32)zk_crcForPath:(NSString *)path invoker:(id)invoker throttleThreadSleepTime:(NSTimeInterval)throttleThreadSleepTime; 30 | 31 | @end 32 | -------------------------------------------------------------------------------- /ZipKit/NSFileManager+ZKAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSFileManager+ZKAdditions.m 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import "NSFileManager+ZKAdditions.h" 9 | #import "NSData+ZKAdditions.h" 10 | #import "NSDictionary+ZKAdditions.h" 11 | 12 | #if ZK_TARGET_OS_MAC 13 | #import "GMAppleDouble+ZKAdditions.h" 14 | #endif 15 | 16 | const NSUInteger ZKMaxEntriesPerFetch = 40; 17 | 18 | @implementation NSFileManager (ZKAdditions) 19 | 20 | - (BOOL)zk_isSymLinkAtPath:(NSString *)path { 21 | return [[[self attributesOfItemAtPath:path error:nil] fileType] isEqualToString:NSFileTypeSymbolicLink]; 22 | } 23 | 24 | - (BOOL)zk_isDirAtPath:(NSString *)path { 25 | BOOL isDir; 26 | BOOL pathExists = [self fileExistsAtPath:path isDirectory:&isDir]; 27 | return pathExists && isDir; 28 | } 29 | 30 | - (UInt64)zk_dataSizeAtFilePath:(NSString *)path { 31 | return [[self attributesOfItemAtPath:path error:nil] fileSize]; 32 | } 33 | 34 | // pragmas to suppress deprecation warnings about FS*() functions deprecated in 10.8 35 | 36 | #if ZK_TARGET_OS_MAC 37 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 38 | - (void)totalsAtDirectoryFSRef:(FSRef *)fsRef usingResourceFork:(BOOL)rfFlag 39 | totalSize:(UInt64 *)size 40 | itemCount:(UInt64 *)count { 41 | FSIterator iterator; 42 | OSErr fsErr = FSOpenIterator(fsRef, kFSIterateFlat, &iterator); 43 | if (fsErr == noErr) { 44 | ItemCount actualFetched; 45 | FSRef fetchedRefs[ZKMaxEntriesPerFetch]; 46 | FSCatalogInfo fetchedInfos[ZKMaxEntriesPerFetch]; 47 | while (fsErr == noErr) { 48 | fsErr = FSGetCatalogInfoBulk(iterator, ZKMaxEntriesPerFetch, &actualFetched, NULL, 49 | kFSCatInfoDataSizes | kFSCatInfoRsrcSizes | kFSCatInfoNodeFlags, 50 | fetchedInfos, fetchedRefs, NULL, NULL); 51 | if ((fsErr == noErr) || (fsErr == errFSNoMoreItems)) { 52 | (*count) += actualFetched; 53 | for (ItemCount i = 0; i < actualFetched; i++) { 54 | if (fetchedInfos[i].nodeFlags & kFSNodeIsDirectoryMask) { 55 | [self totalsAtDirectoryFSRef:&fetchedRefs[i] usingResourceFork:rfFlag totalSize:size itemCount:count]; 56 | } else { 57 | (*size) += fetchedInfos [i].dataLogicalSize + (rfFlag ? fetchedInfos [i].rsrcLogicalSize : 0); 58 | } 59 | } 60 | } 61 | } 62 | FSCloseIterator(iterator); 63 | } 64 | return; 65 | } 66 | #pragma GCC diagnostic warning "-Wdeprecated-declarations" 67 | #endif 68 | 69 | - (NSDictionary *)zkTotalSizeAndItemCountAtPath:(NSString *)path usingResourceFork:(BOOL)rfFlag { 70 | unsigned long long size = 0; 71 | unsigned long long count = 0; 72 | #if ZK_TARGET_OS_MAC 73 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 74 | FSRef fsRef; 75 | Boolean isDirectory; 76 | OSStatus status = FSPathMakeRef((const unsigned char *)[path fileSystemRepresentation], &fsRef, &isDirectory); 77 | if (status != noErr) { 78 | return nil; 79 | } 80 | if (isDirectory) { 81 | [self totalsAtDirectoryFSRef:&fsRef usingResourceFork:rfFlag totalSize:&size itemCount:&count]; 82 | } else { 83 | count = 1; 84 | FSCatalogInfo info; 85 | OSErr fsErr = FSGetCatalogInfo(&fsRef, kFSCatInfoDataSizes | kFSCatInfoRsrcSizes, &info, NULL, NULL, NULL); 86 | if (fsErr == noErr) { 87 | size = info.dataLogicalSize + (rfFlag ? info.rsrcLogicalSize : 0); 88 | } 89 | } 90 | #pragma GCC diagnostic warning "-Wdeprecated-declarations" 91 | #else 92 | // TODO: maybe fix this for non-Mac targets 93 | size = 0; 94 | count = 0; 95 | #endif 96 | return [NSDictionary zk_totalSizeAndCountDictionaryWithSize:size andItemCount:count]; 97 | } 98 | 99 | #if ZK_TARGET_OS_MAC 100 | - (void)zk_combineAppleDoubleInDirectory:(NSString *)path { 101 | if (![self zk_isDirAtPath:path]) { 102 | return; 103 | } 104 | NSArray *dirContents = [self contentsOfDirectoryAtPath:path error:nil]; 105 | for (NSString *entry in dirContents) { 106 | NSString *subPath = [path stringByAppendingPathComponent:entry]; 107 | if (![self zk_isSymLinkAtPath:subPath]) { 108 | if ([self zk_isDirAtPath:subPath]) { 109 | [self zk_combineAppleDoubleInDirectory:subPath]; 110 | } else { 111 | // if the file is an AppleDouble file (i.e., it begins with "._") in the __MACOSX hierarchy, 112 | // find its corresponding data fork and combine them 113 | if ([subPath rangeOfString:ZKMacOSXDirectory].location != NSNotFound) { 114 | NSString *fileName = [subPath lastPathComponent]; 115 | NSRange ZKDotUnderscoreRange = [fileName rangeOfString:ZKDotUnderscore]; 116 | if (ZKDotUnderscoreRange.location == 0 && ZKDotUnderscoreRange.length == 2) { 117 | NSMutableArray *pathComponents = 118 | (NSMutableArray *)[[[subPath stringByDeletingLastPathComponent] stringByAppendingPathComponent: 119 | [fileName substringFromIndex:2]] pathComponents]; 120 | for (NSString *pathComponent in pathComponents) { 121 | if ([ZKMacOSXDirectory isEqualToString:pathComponent]) { 122 | [pathComponents removeObject:pathComponent]; 123 | break; 124 | } 125 | } 126 | NSData *appleDoubleData = [NSData dataWithContentsOfFile:subPath]; 127 | [GMAppleDouble zk_restoreAppleDoubleData:appleDoubleData toPath:[NSString pathWithComponents:pathComponents]]; 128 | } 129 | } 130 | } 131 | } 132 | } 133 | } 134 | #endif 135 | 136 | - (NSDate *)zk_modificationDateForPath:(NSString *)path { 137 | return [[self attributesOfItemAtPath:path error:nil] fileModificationDate]; 138 | } 139 | 140 | - (UInt32)zk_posixPermissionsAtPath:(NSString *)path { 141 | return (UInt32)[[self attributesOfItemAtPath:path error:nil] filePosixPermissions]; 142 | } 143 | 144 | - (UInt32)zk_externalFileAttributesAtPath:(NSString *)path { 145 | return [self zk_externalFileAttributesFor:[self attributesOfItemAtPath:path error:nil]]; 146 | } 147 | 148 | - (UInt32)zk_externalFileAttributesFor:(NSDictionary *)fileAttributes { 149 | UInt32 externalFileAttributes = 0; 150 | @try { 151 | BOOL isSymLink = [[fileAttributes fileType] isEqualToString:NSFileTypeSymbolicLink]; 152 | BOOL isDir = [[fileAttributes fileType] isEqualToString:NSFileTypeDirectory]; 153 | UInt32 posixPermissions = (UInt32)[fileAttributes filePosixPermissions]; 154 | externalFileAttributes = posixPermissions << 16 | (isSymLink ? 0xA0004000 : (isDir ? 0x40004000 : 0x80004000)); 155 | } @catch (NSException *e) { 156 | externalFileAttributes = 0; 157 | } 158 | return externalFileAttributes; 159 | } 160 | 161 | - (UInt32)zk_crcForPath:(NSString *)path { 162 | return [self zk_crcForPath:path invoker:nil throttleThreadSleepTime:0.0]; 163 | } 164 | 165 | - (UInt32)zk_crcForPath:(NSString *)path invoker:(id)invoker { 166 | return [self zk_crcForPath:path invoker:invoker throttleThreadSleepTime:0.0]; 167 | } 168 | 169 | - (UInt32)zk_crcForPath:(NSString *)path invoker:(id)invoker throttleThreadSleepTime:(NSTimeInterval)throttleThreadSleepTime { 170 | UInt32 crc32 = 0; 171 | path = [path stringByExpandingTildeInPath]; 172 | BOOL isDirectory; 173 | if ([self fileExistsAtPath:path isDirectory:&isDirectory] && !isDirectory) { 174 | BOOL irtsIsCancelled = [invoker respondsToSelector:@selector(isCancelled)]; 175 | const NSUInteger crcBlockSize = 1048576; 176 | NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:path]; 177 | NSData *block = [fileHandle readDataOfLength:crcBlockSize]; 178 | while ([block length] > 0) { 179 | crc32 = [block zk_crc32:crc32]; 180 | if (irtsIsCancelled) { 181 | if ([invoker isCancelled]) { 182 | [fileHandle closeFile]; 183 | return 0; 184 | } 185 | } 186 | block = [fileHandle readDataOfLength:crcBlockSize]; 187 | [NSThread sleepForTimeInterval:throttleThreadSleepTime]; 188 | } 189 | [fileHandle closeFile]; 190 | } else { 191 | crc32 = 0; 192 | } 193 | return crc32; 194 | } 195 | 196 | @end 197 | -------------------------------------------------------------------------------- /ZipKit/NSString+ZKAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+ZKAdditions.h 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import 9 | 10 | @interface NSString (ZKAdditions) 11 | 12 | - (UInt32)zk_precomposedUTF8Length; 13 | - (BOOL)zk_isResourceForkPath; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /ZipKit/NSString+ZKAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+ZKAdditions.m 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import "NSString+ZKAdditions.h" 9 | #import "ZKDefs.h" 10 | 11 | @implementation NSString (ZKAdditions) 12 | 13 | - (UInt32)zk_precomposedUTF8Length { 14 | return (UInt32)[[self precomposedStringWithCanonicalMapping] lengthOfBytesUsingEncoding:NSUTF8StringEncoding]; 15 | } 16 | 17 | - (BOOL)zk_isResourceForkPath { 18 | return [[self pathComponents][0] isEqualToString:ZKMacOSXDirectory]; 19 | } 20 | 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /ZipKit/ZKArchive.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZKArchive.h 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 08/05/09. 6 | // 7 | 8 | #import 9 | 10 | @class ZKCDTrailer; 11 | @class ZKArchive; 12 | 13 | @protocol ZipKitDelegate 14 | @optional 15 | - (void)onZKArchiveDidBeginZip:(ZKArchive *)archive; 16 | - (void)onZKArchiveDidBeginUnzip:(ZKArchive *)archive; 17 | - (void)onZKArchive:(ZKArchive *)archive willZipPath:(NSString *)path; 18 | - (void)onZKArchive:(ZKArchive *)archive willUnzipPath:(NSString *)path; 19 | - (void)onZKArchive:(ZKArchive *)archive didUpdateTotalSize:(UInt64)size; 20 | - (void)onZKArchive:(ZKArchive *)archive didUpdateTotalCount:(UInt64)count; 21 | - (void)onZKArchive:(ZKArchive *)archive didUpdateBytesWritten:(UInt64)byteCount; 22 | - (void)onZKArchiveDidEndZip:(ZKArchive *)archive; 23 | - (void)onZKArchiveDidEndUnzip:(ZKArchive *)archive; 24 | - (void)onZKArchiveDidCancel:(ZKArchive *)archive; 25 | - (void)onZKArchiveDidFail:(ZKArchive *)archive; 26 | - (BOOL)zkDelegateWantsSizes; 27 | @end 28 | 29 | @interface ZKArchive : NSObject { 30 | @protected 31 | // cached respondsToSelector: checks 32 | BOOL drtsDelegateWantsSizes; 33 | BOOL drtsDidBeginZip; 34 | BOOL drtsDidBeginUnzip; 35 | BOOL drtsWillZipPath; 36 | BOOL drtsWillUnzipPath; 37 | BOOL drtsDidEndZip; 38 | BOOL drtsDidEndUnzip; 39 | BOOL drtsDidCancel; 40 | BOOL drtsDidFail; 41 | BOOL drtsDidUpdateTotalSize; 42 | BOOL drtsDidUpdateTotalCount; 43 | BOOL drtsDidUpdateBytesWritten; 44 | 45 | BOOL irtsIsCancelled; 46 | } 47 | 48 | + (BOOL)validArchiveAtPath:(NSString *)path; 49 | + (NSString *)uniquify:(NSString *)path; 50 | - (void)calculateSizeAndItemCount:(NSDictionary *)userInfo; 51 | - (NSString *)uniqueExpansionDirectoryIn:(NSString *)enclosingFolder; 52 | - (void)cleanUpExpansionDirectory:(NSString *)expansionDirectory; 53 | 54 | - (BOOL)delegateWantsSizes; 55 | 56 | - (void)didBeginZip; 57 | - (void)didBeginUnzip; 58 | - (void)willZipPath:(NSString *)path; 59 | - (void)willUnzipPath:(NSString *)path; 60 | - (void)didEndZip; 61 | - (void)didEndUnzip; 62 | - (void)didCancel; 63 | - (void)didFail; 64 | - (void)didUpdateTotalSize:(NSNumber *)size; 65 | - (void)didUpdateTotalCount:(NSNumber *)count; 66 | - (void)didUpdateBytesWritten:(NSNumber *)byteCount; 67 | 68 | @property (weak, nonatomic) id invoker; 69 | @property (weak, nonatomic) id delegate; 70 | @property (copy) NSString *archivePath; 71 | @property (strong) NSMutableArray *centralDirectory; 72 | @property (strong) NSFileManager *fileManager; 73 | @property (strong) ZKCDTrailer *cdTrailer; 74 | @property (assign) NSTimeInterval throttleThreadSleepTime; 75 | @property (copy) NSString *comment; 76 | 77 | @property (assign) BOOL overwriteExistingFiles; 78 | 79 | @end 80 | -------------------------------------------------------------------------------- /ZipKit/ZKArchive.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZKArchive.m 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 08/05/09. 6 | // 7 | 8 | #import "ZKArchive.h" 9 | #import "NSDictionary+ZKAdditions.h" 10 | #import "NSFileManager+ZKAdditions.h" 11 | #import "ZKCDTrailer.h" 12 | #import "ZKDefs.h" 13 | 14 | #pragma mark - 15 | 16 | @implementation ZKArchive 17 | 18 | #pragma mark - 19 | #pragma mark Utility 20 | 21 | + (BOOL)validArchiveAtPath:(NSString *)path { 22 | // check that the first few bytes of the file are a local file header 23 | NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:path]; 24 | NSData *fileHeader = [fileHandle readDataOfLength:4]; 25 | [fileHandle closeFile]; 26 | UInt32 headerValue; 27 | [fileHeader getBytes:&headerValue length:sizeof(UInt32)]; 28 | return CFSwapInt32LittleToHost(headerValue) == ZKLFHeaderMagicNumber; 29 | } 30 | 31 | + (NSString *)uniquify:(NSString *)path { 32 | // avoid name collisions by adding a sequence number if needed 33 | NSString *uniquePath = [NSString stringWithString:path]; 34 | NSString *dir = [path stringByDeletingLastPathComponent]; 35 | NSString *fileNameBase = [[path lastPathComponent] stringByDeletingPathExtension]; 36 | NSString *ext = [path pathExtension]; 37 | NSUInteger i = 2; 38 | NSFileManager *fm = [NSFileManager new]; 39 | while ([fm fileExistsAtPath:uniquePath]) { 40 | uniquePath = [dir stringByAppendingPathComponent:[NSString stringWithFormat:@"%@ %lu", fileNameBase, (unsigned long)i++]]; 41 | if (ext && [ext length] > 0) { 42 | uniquePath = [uniquePath stringByAppendingPathExtension:ext]; 43 | } 44 | } 45 | return uniquePath; 46 | } 47 | 48 | - (void)calculateSizeAndItemCount:(NSDictionary *)userInfo { 49 | NSArray *paths = userInfo[ZKPathsKey]; 50 | BOOL rfFlag = [userInfo[ZKusingResourceForkKey] boolValue]; 51 | unsigned long long size = 0; 52 | unsigned long long count = 0; 53 | NSFileManager *fmgr = [NSFileManager new]; 54 | NSDictionary *dict = nil; 55 | for (NSString *path in paths) { 56 | dict = [fmgr zkTotalSizeAndItemCountAtPath:path usingResourceFork:rfFlag]; 57 | size += [dict zk_totalFileSize]; 58 | count += [dict zk_itemCount]; 59 | } 60 | [self performSelectorOnMainThread:@selector(didUpdateTotalSize:) 61 | withObject:@(size) waitUntilDone:NO]; 62 | [self performSelectorOnMainThread:@selector(didUpdateTotalCount:) 63 | withObject:@(count) waitUntilDone:NO]; 64 | } 65 | 66 | - (NSString *)uniqueExpansionDirectoryIn:(NSString *)enclosingFolder { 67 | NSString *expansionDirectory = [enclosingFolder stringByAppendingPathComponent:ZKExpansionDirectoryName]; 68 | NSUInteger i = 1; 69 | while ([self.fileManager fileExistsAtPath:expansionDirectory]) { 70 | expansionDirectory = [enclosingFolder stringByAppendingPathComponent: 71 | [NSString stringWithFormat:@"%@ %lu", ZKExpansionDirectoryName, (unsigned long)i++]]; 72 | } 73 | return expansionDirectory; 74 | } 75 | 76 | - (void)cleanUpExpansionDirectory:(NSString *)expansionDirectory { 77 | NSString *enclosingFolder = [expansionDirectory stringByDeletingLastPathComponent]; 78 | NSArray *dirContents = [self.fileManager contentsOfDirectoryAtPath:expansionDirectory error:nil]; 79 | for (NSString *item in dirContents) { 80 | if (![item isEqualToString:ZKMacOSXDirectory]) { 81 | NSString *subPath = [expansionDirectory stringByAppendingPathComponent:item]; 82 | NSString *dest = [enclosingFolder stringByAppendingPathComponent:item]; 83 | 84 | if (self.overwriteExistingFiles) { 85 | 86 | if ([self.fileManager fileExistsAtPath:dest]) { 87 | [self.fileManager removeItemAtPath:dest error:nil]; 88 | } 89 | 90 | } else { 91 | 92 | NSUInteger i = 2; 93 | while ([self.fileManager fileExistsAtPath:dest]) { 94 | NSString *ext = [item pathExtension]; 95 | dest = [enclosingFolder stringByAppendingPathComponent:[NSString stringWithFormat:@"%@ %lu", 96 | [item stringByDeletingPathExtension], (unsigned long)i++]]; 97 | if (ext && [ext length] > 0) { 98 | dest = [dest stringByAppendingPathExtension:ext]; 99 | } 100 | } 101 | 102 | } 103 | 104 | [self.fileManager moveItemAtPath:subPath toPath:dest error:nil]; 105 | } 106 | } 107 | [self.fileManager removeItemAtPath:expansionDirectory error:nil]; 108 | 109 | } 110 | 111 | #pragma mark - 112 | #pragma mark Accessors 113 | 114 | - (NSString *)comment { 115 | return self.cdTrailer.comment; 116 | } 117 | - (void)setComment:(NSString *)comment { 118 | self.cdTrailer.comment = comment; 119 | } 120 | 121 | #pragma mark - 122 | #pragma mark Delegate 123 | 124 | - (void)setInvoker:(id)i { 125 | _invoker = i; 126 | if (_invoker) { 127 | irtsIsCancelled = [self.invoker respondsToSelector:@selector(isCancelled)]; 128 | } else { 129 | irtsIsCancelled = NO; 130 | } 131 | } 132 | 133 | - (void)setDelegate:(id)d { 134 | _delegate = d; 135 | if (_delegate) { 136 | drtsDelegateWantsSizes = [_delegate respondsToSelector:@selector(zkDelegateWantsSizes)]; 137 | drtsDidBeginZip = [_delegate respondsToSelector:@selector(onZKArchiveDidBeginZip:)]; 138 | drtsDidBeginUnzip = [_delegate respondsToSelector:@selector(onZKArchiveDidBeginUnzip:)]; 139 | drtsWillZipPath = [_delegate respondsToSelector:@selector(onZKArchive:willZipPath:)]; 140 | drtsWillUnzipPath = [_delegate respondsToSelector:@selector(onZKArchive:willUnzipPath:)]; 141 | drtsDidEndZip = [_delegate respondsToSelector:@selector(onZKArchiveDidEndZip:)]; 142 | drtsDidEndUnzip = [_delegate respondsToSelector:@selector(onZKArchiveDidEndUnzip:)]; 143 | drtsDidCancel = [_delegate respondsToSelector:@selector(onZKArchiveDidCancel:)]; 144 | drtsDidFail = [_delegate respondsToSelector:@selector(onZKArchiveDidFail:)]; 145 | drtsDidUpdateTotalSize = [_delegate respondsToSelector:@selector(onZKArchive:didUpdateTotalSize:)]; 146 | drtsDidUpdateTotalCount = [_delegate respondsToSelector:@selector(onZKArchive:didUpdateTotalCount:)]; 147 | drtsDidUpdateBytesWritten = [_delegate respondsToSelector:@selector(onZKArchive:didUpdateBytesWritten:)]; 148 | } else { 149 | drtsDelegateWantsSizes = NO; 150 | drtsDidBeginZip = NO; 151 | drtsDidBeginUnzip = NO; 152 | drtsWillZipPath = NO; 153 | drtsWillUnzipPath = NO; 154 | drtsDidEndZip = NO; 155 | drtsDidEndUnzip = NO; 156 | drtsDidCancel = NO; 157 | drtsDidFail = NO; 158 | drtsDidUpdateTotalSize = NO; 159 | drtsDidUpdateTotalCount = NO; 160 | drtsDidUpdateBytesWritten = NO; 161 | } 162 | } 163 | 164 | - (BOOL)delegateWantsSizes { 165 | BOOL delegateWantsSizes = NO; 166 | if (drtsDelegateWantsSizes) { 167 | delegateWantsSizes = [self.delegate zkDelegateWantsSizes]; 168 | } 169 | return delegateWantsSizes; 170 | } 171 | 172 | - (void)didBeginZip { 173 | if (drtsDidBeginZip) { 174 | [self.delegate onZKArchiveDidBeginZip:self]; 175 | } 176 | } 177 | 178 | - (void)didBeginUnzip { 179 | if (drtsDidBeginUnzip) { 180 | [self.delegate onZKArchiveDidBeginUnzip:self]; 181 | } 182 | } 183 | 184 | - (void)willZipPath:(NSString *)path { 185 | if (drtsWillZipPath) { 186 | [self.delegate onZKArchive:self willZipPath:path]; 187 | } 188 | } 189 | 190 | - (void)willUnzipPath:(NSString *)path { 191 | if (drtsWillUnzipPath) { 192 | [self.delegate onZKArchive:self willUnzipPath:path]; 193 | } 194 | } 195 | 196 | - (void)didEndZip { 197 | if (drtsDidEndZip) { 198 | [self.delegate onZKArchiveDidEndZip:self]; 199 | } 200 | } 201 | 202 | - (void)didEndUnzip { 203 | if (drtsDidEndUnzip) { 204 | [self.delegate onZKArchiveDidEndUnzip:self]; 205 | } 206 | } 207 | 208 | - (void)didCancel { 209 | if (drtsDidCancel) { 210 | [self.delegate onZKArchiveDidCancel:self]; 211 | } 212 | } 213 | 214 | - (void)didFail { 215 | if (drtsDidFail) { 216 | [self.delegate onZKArchiveDidFail:self]; 217 | } 218 | } 219 | 220 | - (void)didUpdateTotalSize:(NSNumber *)size { 221 | if (drtsDidUpdateTotalSize) { 222 | [self.delegate onZKArchive:self didUpdateTotalSize:[size unsignedLongLongValue]]; 223 | } 224 | } 225 | 226 | - (void)didUpdateTotalCount:(NSNumber *)count { 227 | if (drtsDidUpdateTotalCount) { 228 | [self.delegate onZKArchive:self didUpdateTotalCount:[count unsignedLongLongValue]]; 229 | } 230 | } 231 | 232 | - (void)didUpdateBytesWritten:(NSNumber *)byteCount { 233 | if (drtsDidUpdateBytesWritten) { 234 | [self.delegate onZKArchive:self didUpdateBytesWritten:[byteCount unsignedLongLongValue]]; 235 | } 236 | } 237 | 238 | #pragma mark - 239 | #pragma mark Setup 240 | 241 | - (id)init { 242 | if (self = [super init]) { 243 | self.invoker = nil; 244 | self.delegate = nil; 245 | self.archivePath = nil; 246 | self.centralDirectory = [NSMutableArray array]; 247 | self.fileManager = [NSFileManager new]; 248 | self.cdTrailer = [ZKCDTrailer new]; 249 | self.throttleThreadSleepTime = 0.0; 250 | } 251 | return self; 252 | } 253 | 254 | - (void)dealloc { 255 | self.invoker = nil; 256 | self.delegate = nil; 257 | } 258 | 259 | - (NSString *)description { 260 | return [NSString stringWithFormat:@"%@\n\ttrailer:%@\n\tcentral directory:%@", self.archivePath, self.cdTrailer, self.centralDirectory]; 261 | } 262 | 263 | @dynamic comment; 264 | 265 | @end 266 | -------------------------------------------------------------------------------- /ZipKit/ZKCDHeader.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZKCDHeader.h 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import 9 | 10 | @interface ZKCDHeader : NSObject 11 | 12 | + (ZKCDHeader *)recordWithData:(NSData *)data atOffset:(UInt64)offset; 13 | + (ZKCDHeader *)recordWithArchivePath:(NSString *)path atOffset:(UInt64)offset; 14 | - (void)parseZip64ExtraField; 15 | - (NSData *)zip64ExtraField; 16 | - (NSData *)data; 17 | - (NSUInteger)length; 18 | - (BOOL)useZip64Extensions; 19 | - (NSNumber *)posixPermissions; 20 | - (BOOL)isDirectory; 21 | - (BOOL)isSymLink; 22 | - (BOOL)isResourceFork; 23 | 24 | @property (assign) UInt32 magicNumber; 25 | @property (assign) UInt32 versionMadeBy; 26 | @property (assign) UInt32 versionNeededToExtract; 27 | @property (assign) UInt32 generalPurposeBitFlag; 28 | @property (assign) UInt32 compressionMethod; 29 | @property (strong) NSDate *lastModDate; 30 | @property (assign) UInt32 crc; 31 | @property (assign) UInt64 compressedSize; 32 | @property (assign) UInt64 uncompressedSize; 33 | @property (assign) UInt32 filenameLength; 34 | @property (assign) UInt32 extraFieldLength; 35 | @property (assign) UInt32 commentLength; 36 | @property (assign) UInt32 diskNumberStart; 37 | @property (assign) UInt32 internalFileAttributes; 38 | @property (assign) UInt32 externalFileAttributes; 39 | @property (assign) UInt64 localHeaderOffset; 40 | @property (copy) NSString *filename; 41 | @property (strong) NSData *extraField; 42 | @property (copy) NSString *comment; 43 | @property (strong) NSMutableData *cachedData; 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /ZipKit/ZKCDHeader.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZKCDHeader.m 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import "ZKCDHeader.h" 9 | #import "NSDate+ZKAdditions.h" 10 | #import "NSData+ZKAdditions.h" 11 | #import "NSString+ZKAdditions.h" 12 | #import "ZKDefs.h" 13 | #import "zlib.h" 14 | 15 | @implementation ZKCDHeader 16 | 17 | - (id)init { 18 | if (self = [super init]) { 19 | self.magicNumber = ZKCDHeaderMagicNumber; 20 | self.versionNeededToExtract = 20; 21 | self.versionMadeBy = 789; 22 | self.generalPurposeBitFlag = 0; 23 | self.compressionMethod = Z_DEFLATED; 24 | self.lastModDate = [NSDate date]; 25 | self.crc = 0; 26 | self.compressedSize = 0; 27 | self.uncompressedSize = 0; 28 | self.filenameLength = 0; 29 | self.extraFieldLength = 0; 30 | self.commentLength = 0; 31 | self.diskNumberStart = 0; 32 | self.internalFileAttributes = 0; 33 | self.externalFileAttributes = 0; 34 | self.localHeaderOffset = 0; 35 | self.extraField = nil; 36 | self.comment = nil; 37 | 38 | [self addObserver:self forKeyPath:@"compressedSize" options:NSKeyValueObservingOptionNew context:nil]; 39 | [self addObserver:self forKeyPath:@"uncompressedSize" options:NSKeyValueObservingOptionNew context:nil]; 40 | [self addObserver:self forKeyPath:@"localHeaderOffset" options:NSKeyValueObservingOptionNew context:nil]; 41 | [self addObserver:self forKeyPath:@"extraField" options:NSKeyValueObservingOptionNew context:nil]; 42 | [self addObserver:self forKeyPath:@"filename" options:NSKeyValueObservingOptionNew context:nil]; 43 | [self addObserver:self forKeyPath:@"comment" options:NSKeyValueObservingOptionNew context:nil]; 44 | } 45 | return self; 46 | } 47 | 48 | - (void)removeObservers { 49 | [self removeObserver:self forKeyPath:@"compressedSize"]; 50 | [self removeObserver:self forKeyPath:@"uncompressedSize"]; 51 | [self removeObserver:self forKeyPath:@"localHeaderOffset"]; 52 | [self removeObserver:self forKeyPath:@"extraField"]; 53 | [self removeObserver:self forKeyPath:@"filename"]; 54 | [self removeObserver:self forKeyPath:@"comment"]; 55 | } 56 | 57 | - (void)dealloc { 58 | [self removeObservers]; 59 | } 60 | 61 | 62 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 63 | if ([keyPath isEqualToString:@"compressedSize"] 64 | || [keyPath isEqualToString:@"uncompressedSize"] 65 | || [keyPath isEqualToString:@"localHeaderOffset"]) { 66 | self.versionNeededToExtract = ([self useZip64Extensions] ? 45 : 20); 67 | } else if ([keyPath isEqualToString:@"extraField"] && self.extraFieldLength < 1) { 68 | self.extraFieldLength = (UInt32)[self.extraField length]; 69 | } else if ([keyPath isEqualToString:@"filename"] && self.filenameLength < 1) { 70 | self.filenameLength = [self.filename zk_precomposedUTF8Length]; 71 | } else if ([keyPath isEqualToString:@"comment"] && self.commentLength < 1) { 72 | self.commentLength = [self.comment zk_precomposedUTF8Length]; 73 | } 74 | } 75 | 76 | + (ZKCDHeader *)recordWithData:(NSData *)data atOffset:(UInt64)offset { 77 | if (!data || data.length < 1) { 78 | return nil; 79 | } 80 | UInt32 mn = [data zk_hostInt32OffsetBy:&offset]; 81 | if (mn != ZKCDHeaderMagicNumber) { 82 | return nil; 83 | } 84 | ZKCDHeader *record = [ZKCDHeader new]; 85 | record.magicNumber = mn; 86 | record.versionMadeBy = [data zk_hostInt16OffsetBy:&offset]; 87 | record.versionNeededToExtract = [data zk_hostInt16OffsetBy:&offset]; 88 | record.generalPurposeBitFlag = [data zk_hostInt16OffsetBy:&offset]; 89 | record.compressionMethod = [data zk_hostInt16OffsetBy:&offset]; 90 | record.lastModDate = [NSDate zk_dateWithDosDate:[data zk_hostInt32OffsetBy:&offset]]; 91 | record.crc = [data zk_hostInt32OffsetBy:&offset]; 92 | record.compressedSize = [data zk_hostInt32OffsetBy:&offset]; 93 | record.uncompressedSize = [data zk_hostInt32OffsetBy:&offset]; 94 | record.filenameLength = [data zk_hostInt16OffsetBy:&offset]; 95 | record.extraFieldLength = [data zk_hostInt16OffsetBy:&offset]; 96 | record.commentLength = [data zk_hostInt16OffsetBy:&offset]; 97 | record.diskNumberStart = [data zk_hostInt16OffsetBy:&offset]; 98 | record.internalFileAttributes = [data zk_hostInt16OffsetBy:&offset]; 99 | record.externalFileAttributes = [data zk_hostInt32OffsetBy:&offset]; 100 | record.localHeaderOffset = [data zk_hostInt32OffsetBy:&offset]; 101 | if ([data length] > ZKCDHeaderFixedDataLength) { 102 | if (record.filenameLength) { 103 | record.filename = [data zk_stringOffsetBy:&offset length:record.filenameLength]; 104 | } 105 | if (record.extraFieldLength) { 106 | record.extraField = [data subdataWithRange:NSMakeRange((NSUInteger)offset, record.extraFieldLength)]; 107 | offset += record.extraFieldLength; 108 | [record parseZip64ExtraField]; 109 | } 110 | if (record.commentLength) { 111 | record.comment = [data zk_stringOffsetBy:&offset length:record.commentLength]; 112 | } 113 | } 114 | return record; 115 | } 116 | 117 | + (ZKCDHeader *)recordWithArchivePath:(NSString *)path atOffset:(UInt64)offset { 118 | NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path]; 119 | [file seekToFileOffset:offset]; 120 | NSData *fixedData = [file readDataOfLength:ZKCDHeaderFixedDataLength]; 121 | ZKCDHeader *record = [self recordWithData:fixedData atOffset:0]; 122 | if (record.filenameLength > 0) { 123 | NSData *data = [file readDataOfLength:record.filenameLength]; 124 | record.filename = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 125 | } 126 | if (record.extraFieldLength > 0) { 127 | record.extraField = [file readDataOfLength:record.extraFieldLength]; 128 | [record parseZip64ExtraField]; 129 | } 130 | if (record.commentLength > 0) { 131 | NSData *data = [file readDataOfLength:record.commentLength]; 132 | record.comment = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 133 | } else { 134 | record.comment = nil; 135 | } 136 | 137 | [file closeFile]; 138 | return record; 139 | } 140 | 141 | - (NSData *)data { 142 | if (!self.cachedData || ([self.cachedData length] < ZKCDHeaderFixedDataLength)) { 143 | self.extraField = [self zip64ExtraField]; 144 | 145 | self.cachedData = [NSMutableData zk_dataWithLittleInt32:self.magicNumber]; 146 | [self.cachedData zk_appendLittleInt16:self.versionMadeBy]; 147 | [self.cachedData zk_appendLittleInt16:self.versionNeededToExtract]; 148 | [self.cachedData zk_appendLittleInt16:self.generalPurposeBitFlag]; 149 | [self.cachedData zk_appendLittleInt16:self.compressionMethod]; 150 | [self.cachedData zk_appendLittleInt32:[self.lastModDate zk_dosDate]]; 151 | [self.cachedData zk_appendLittleInt32:self.crc]; 152 | if ([self useZip64Extensions]) { 153 | [self.cachedData zk_appendLittleInt32:0xFFFFFFFF]; 154 | [self.cachedData zk_appendLittleInt32:0xFFFFFFFF]; 155 | } else { 156 | [self.cachedData zk_appendLittleInt32:(UInt32)self.compressedSize]; 157 | [self.cachedData zk_appendLittleInt32:(UInt32)self.uncompressedSize]; 158 | } 159 | [self.cachedData zk_appendLittleInt16:[self.filename zk_precomposedUTF8Length]]; 160 | [self.cachedData zk_appendLittleInt16:[self.extraField length]]; 161 | [self.cachedData zk_appendLittleInt16:[self.comment zk_precomposedUTF8Length]]; 162 | [self.cachedData zk_appendLittleInt16:self.diskNumberStart]; 163 | [self.cachedData zk_appendLittleInt16:self.internalFileAttributes]; 164 | [self.cachedData zk_appendLittleInt32:self.externalFileAttributes]; 165 | if ([self useZip64Extensions]) { 166 | [self.cachedData zk_appendLittleInt32:0xFFFFFFFF]; 167 | } else { 168 | [self.cachedData zk_appendLittleInt32:(UInt32)self.localHeaderOffset]; 169 | } 170 | [self.cachedData zk_appendPrecomposedUTF8String:self.filename]; 171 | [self.cachedData appendData:self.extraField]; 172 | [self.cachedData zk_appendPrecomposedUTF8String:self.comment]; 173 | } 174 | return self.cachedData; 175 | } 176 | 177 | - (void)parseZip64ExtraField { 178 | NSUInteger tag, length; 179 | UInt64 offset = 0; 180 | while (offset < self.extraFieldLength) { 181 | tag = [self.extraField zk_hostInt16OffsetBy:&offset]; 182 | length = [self.extraField zk_hostInt16OffsetBy:&offset]; 183 | if (tag == 0x0001) { 184 | if (length >= 8) { 185 | self.uncompressedSize = [self.extraField zk_hostInt64OffsetBy:&offset]; 186 | } 187 | if (length >= 16) { 188 | self.compressedSize = [self.extraField zk_hostInt64OffsetBy:&offset]; 189 | } 190 | if (length >= 24) { 191 | self.localHeaderOffset = [self.extraField zk_hostInt64OffsetBy:&offset]; 192 | } 193 | break; 194 | } else { 195 | offset += length; 196 | } 197 | } 198 | } 199 | 200 | - (NSData *)zip64ExtraField { 201 | NSMutableData *zip64ExtraField = nil; 202 | if ([self useZip64Extensions]) { 203 | zip64ExtraField = [NSMutableData zk_dataWithLittleInt16:0x0001]; 204 | [zip64ExtraField zk_appendLittleInt16:24]; 205 | [zip64ExtraField zk_appendLittleInt64:self.uncompressedSize]; 206 | [zip64ExtraField zk_appendLittleInt64:self.compressedSize]; 207 | [zip64ExtraField zk_appendLittleInt64:self.localHeaderOffset]; 208 | } 209 | return zip64ExtraField; 210 | } 211 | 212 | - (NSUInteger)length { 213 | if (!self.extraField || [self.extraField length] == 0) { 214 | self.extraField = [self zip64ExtraField]; 215 | } 216 | return ZKCDHeaderFixedDataLength + self.filenameLength + self.commentLength + [self.extraField length]; 217 | } 218 | 219 | - (BOOL)useZip64Extensions { 220 | return (self.uncompressedSize >= 0xFFFFFFFF) || (self.compressedSize >= 0xFFFFFFFF) || (self.localHeaderOffset >= 0xFFFFFFFF); 221 | } 222 | 223 | - (NSString *)description { 224 | return [NSString stringWithFormat:@"%@ modified %@, %qu bytes (%qu compressed), @ %qu", 225 | self.filename, self.lastModDate, self.uncompressedSize, self.compressedSize, self.localHeaderOffset]; 226 | } 227 | 228 | - (NSNumber *)posixPermissions { 229 | // if posixPermissions are 0, e.g. on Windows-produced archives, then default them to rwxr-wr-w a la Archive Utility 230 | return @((self.externalFileAttributes >> 16 & 0x1FF) ? : 0755U); 231 | } 232 | 233 | - (BOOL)isDirectory { 234 | uLong type = self.externalFileAttributes >> 29 & 0x1F; 235 | if (0 == (self.versionMadeBy >> 8)) { // DOS-originated archive 236 | type = self.externalFileAttributes >> 4; 237 | return (type == 0x01) && ![self isSymLink]; 238 | } 239 | return (0x02 == type) && ![self isSymLink]; 240 | } 241 | 242 | - (BOOL)isSymLink { 243 | uLong type = self.externalFileAttributes >> 29 & 0x1F; 244 | return 0x05 == type; 245 | } 246 | 247 | - (BOOL)isResourceFork { 248 | return [self.filename zk_isResourceForkPath]; 249 | } 250 | 251 | @end 252 | -------------------------------------------------------------------------------- /ZipKit/ZKCDTrailer.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZKCDTrailer.h 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import 9 | 10 | @interface ZKCDTrailer : NSObject 11 | 12 | + (ZKCDTrailer *)recordWithData:(NSData *)data atOffset:(UInt64)offset; 13 | + (ZKCDTrailer *)recordWithData:(NSData *)data; 14 | + (ZKCDTrailer *)recordWithArchivePath:(NSString *)path; 15 | - (NSData *)data; 16 | - (NSUInteger)length; 17 | - (BOOL)useZip64Extensions; 18 | 19 | @property (assign) UInt32 magicNumber; 20 | @property (assign) UInt32 thisDiskNumber; 21 | @property (assign) UInt32 diskNumberWithStartOfCentralDirectory; 22 | @property (assign) UInt32 numberOfCentralDirectoryEntriesOnThisDisk; 23 | @property (assign) UInt32 totalNumberOfCentralDirectoryEntries; 24 | @property (assign) UInt64 sizeOfCentralDirectory; 25 | @property (assign) UInt64 offsetOfStartOfCentralDirectory; 26 | @property (assign) UInt32 commentLength; 27 | @property (copy) NSString *comment; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /ZipKit/ZKCDTrailer.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZKCDTrailer.m 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import "ZKCDTrailer.h" 9 | #import "NSData+ZKAdditions.h" 10 | #import "NSString+ZKAdditions.h" 11 | #import "ZKDefs.h" 12 | #import "zlib.h" 13 | 14 | @implementation ZKCDTrailer 15 | 16 | - (id)init { 17 | if (self = [super init]) { 18 | [self addObserver:self forKeyPath:@"comment" options:NSKeyValueObservingOptionNew context:nil]; 19 | 20 | self.magicNumber = ZKCDTrailerMagicNumber; 21 | self.thisDiskNumber = 0; 22 | self.diskNumberWithStartOfCentralDirectory = 0; 23 | self.numberOfCentralDirectoryEntriesOnThisDisk = 0; 24 | self.totalNumberOfCentralDirectoryEntries = 0; 25 | self.sizeOfCentralDirectory = 0; 26 | self.offsetOfStartOfCentralDirectory = 0; 27 | self.comment = @"Archive created with ZipKit"; 28 | } 29 | return self; 30 | } 31 | 32 | - (void)removeObservers { 33 | [self removeObserver:self forKeyPath:@"comment"]; 34 | } 35 | 36 | 37 | - (void)dealloc { 38 | [self removeObservers]; 39 | } 40 | 41 | 42 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 43 | if ([keyPath isEqualToString:@"comment"] && self.commentLength < 1) { 44 | self.commentLength = [self.comment zk_precomposedUTF8Length]; 45 | } 46 | } 47 | 48 | + (ZKCDTrailer *)recordWithData:(NSData *)data atOffset:(UInt64)offset { 49 | if (!data || data.length < 1) { 50 | return nil; 51 | } 52 | UInt32 mn = [data zk_hostInt32OffsetBy:&offset]; 53 | if (mn != ZKCDTrailerMagicNumber) { 54 | return nil; 55 | } 56 | ZKCDTrailer *record = [ZKCDTrailer new]; 57 | record.magicNumber = mn; 58 | record.thisDiskNumber = [data zk_hostInt16OffsetBy:&offset]; 59 | record.diskNumberWithStartOfCentralDirectory = [data zk_hostInt16OffsetBy:&offset]; 60 | record.numberOfCentralDirectoryEntriesOnThisDisk = [data zk_hostInt16OffsetBy:&offset]; 61 | record.totalNumberOfCentralDirectoryEntries = [data zk_hostInt16OffsetBy:&offset]; 62 | record.sizeOfCentralDirectory = [data zk_hostInt32OffsetBy:&offset]; 63 | record.offsetOfStartOfCentralDirectory = [data zk_hostInt32OffsetBy:&offset]; 64 | record.commentLength = [data zk_hostInt16OffsetBy:&offset]; 65 | if (record.commentLength > 0) { 66 | record.comment = [data zk_stringOffsetBy:&offset length:record.commentLength]; 67 | } else { 68 | record.comment = nil; 69 | } 70 | return record; 71 | } 72 | 73 | + (ZKCDTrailer *)recordWithData:(NSData *)data { 74 | UInt32 trailerCheck = 0; 75 | NSInteger offset = [data length] - sizeof(trailerCheck); 76 | while (trailerCheck != ZKCDTrailerMagicNumber && offset > 0) { 77 | UInt64 o = offset; 78 | trailerCheck = [data zk_hostInt32OffsetBy:&o]; 79 | offset--; 80 | } 81 | if (offset < 1) { 82 | return nil; 83 | } 84 | ZKCDTrailer *record = [self recordWithData:data atOffset:++offset]; 85 | return record; 86 | } 87 | 88 | + (ZKCDTrailer *)recordWithArchivePath:(NSString *)path { 89 | NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path]; 90 | unsigned long long fileOffset = [file seekToEndOfFile]; 91 | for (UInt32 trailerCheck = 0; trailerCheck != ZKCDTrailerMagicNumber && fileOffset > 0; fileOffset--) { 92 | [file seekToFileOffset:fileOffset]; 93 | NSData *data = [file readDataOfLength:sizeof(UInt32)]; 94 | [data getBytes:&trailerCheck length:sizeof(UInt32)]; 95 | } 96 | if (fileOffset < 1) { 97 | [file closeFile]; 98 | return nil; 99 | } 100 | fileOffset++; 101 | [file seekToFileOffset:fileOffset]; 102 | NSData *data = [file readDataToEndOfFile]; 103 | [file closeFile]; 104 | ZKCDTrailer *record = [self recordWithData:data atOffset:(NSUInteger)0]; 105 | return record; 106 | } 107 | 108 | - (NSData *)data { 109 | NSMutableData *data = [NSMutableData zk_dataWithLittleInt32:self.magicNumber]; 110 | [data zk_appendLittleInt16:self.thisDiskNumber]; 111 | [data zk_appendLittleInt16:self.diskNumberWithStartOfCentralDirectory]; 112 | [data zk_appendLittleInt16:self.numberOfCentralDirectoryEntriesOnThisDisk]; 113 | [data zk_appendLittleInt16:self.totalNumberOfCentralDirectoryEntries]; 114 | if ([self useZip64Extensions]) { 115 | [data zk_appendLittleInt32:0xFFFFFFFF]; 116 | [data zk_appendLittleInt32:0xFFFFFFFF]; 117 | } else { 118 | [data zk_appendLittleInt32:(UInt32)self.sizeOfCentralDirectory]; 119 | [data zk_appendLittleInt32:(UInt32)self.offsetOfStartOfCentralDirectory]; 120 | } 121 | [data zk_appendLittleInt16:[self.comment zk_precomposedUTF8Length]]; 122 | [data zk_appendPrecomposedUTF8String:self.comment]; 123 | return data; 124 | } 125 | 126 | - (NSUInteger)length { 127 | return ZKCDTrailerFixedDataLength + [self.comment length]; 128 | } 129 | 130 | - (BOOL)useZip64Extensions { 131 | return (self.sizeOfCentralDirectory >= 0xFFFFFFFF) || (self.offsetOfStartOfCentralDirectory >= 0xFFFFFFFF); 132 | } 133 | 134 | - (NSString *)description { 135 | return [NSString stringWithFormat:@"%u entries (%qu bytes) @: %qu", 136 | (unsigned int)self.totalNumberOfCentralDirectoryEntries, 137 | self.sizeOfCentralDirectory, 138 | self.offsetOfStartOfCentralDirectory]; 139 | } 140 | 141 | @end 142 | -------------------------------------------------------------------------------- /ZipKit/ZKCDTrailer64.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZKCDTrailer64.h 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import 9 | 10 | @interface ZKCDTrailer64 : NSObject 11 | 12 | + (ZKCDTrailer64 *)recordWithData:(NSData *)data atOffset:(UInt64)offset; 13 | + (ZKCDTrailer64 *)recordWithArchivePath:(NSString *)path atOffset:(UInt64)offset; 14 | 15 | - (NSData *)data; 16 | - (NSUInteger)length; 17 | 18 | @property (assign) UInt32 magicNumber; 19 | @property (assign) unsigned long long sizeOfTrailer; 20 | @property (assign) UInt32 versionMadeBy; 21 | @property (assign) UInt32 versionNeededToExtract; 22 | @property (assign) UInt32 thisDiskNumber; 23 | @property (assign) UInt32 diskNumberWithStartOfCentralDirectory; 24 | @property (assign) UInt64 numberOfCentralDirectoryEntriesOnThisDisk; 25 | @property (assign) UInt64 totalNumberOfCentralDirectoryEntries; 26 | @property (assign) UInt64 sizeOfCentralDirectory; 27 | @property (assign) UInt64 offsetOfStartOfCentralDirectory; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /ZipKit/ZKCDTrailer64.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZKCDTrailer64.m 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import "ZKCDTrailer64.h" 9 | #import "NSData+ZKAdditions.h" 10 | #import "ZKDefs.h" 11 | 12 | @implementation ZKCDTrailer64 13 | 14 | - (id)init { 15 | if (self = [super init]) { 16 | self.magicNumber = ZKCDTrailer64MagicNumber; 17 | self.sizeOfTrailer = 44; 18 | self.versionMadeBy = 789; 19 | self.versionNeededToExtract = 45; 20 | self.thisDiskNumber = 0; 21 | self.diskNumberWithStartOfCentralDirectory = 0; 22 | } 23 | return self; 24 | } 25 | 26 | + (ZKCDTrailer64 *)recordWithData:(NSData *)data atOffset:(UInt64)offset { 27 | if (!data || data.length < 1) { 28 | return nil; 29 | } 30 | UInt32 mn = [data zk_hostInt32OffsetBy:&offset]; 31 | if (mn != ZKCDTrailer64MagicNumber) { 32 | return nil; 33 | } 34 | ZKCDTrailer64 *record = [ZKCDTrailer64 new]; 35 | record.magicNumber = mn; 36 | record.sizeOfTrailer = [data zk_hostInt64OffsetBy:&offset]; 37 | record.versionMadeBy = [data zk_hostInt16OffsetBy:&offset]; 38 | record.versionNeededToExtract = [data zk_hostInt16OffsetBy:&offset]; 39 | record.thisDiskNumber = [data zk_hostInt32OffsetBy:&offset]; 40 | record.diskNumberWithStartOfCentralDirectory = [data zk_hostInt32OffsetBy:&offset]; 41 | record.numberOfCentralDirectoryEntriesOnThisDisk = [data zk_hostInt64OffsetBy:&offset]; 42 | record.totalNumberOfCentralDirectoryEntries = [data zk_hostInt64OffsetBy:&offset]; 43 | record.sizeOfCentralDirectory = [data zk_hostInt64OffsetBy:&offset]; 44 | record.offsetOfStartOfCentralDirectory = [data zk_hostInt64OffsetBy:&offset]; 45 | return record; 46 | } 47 | 48 | + (ZKCDTrailer64 *)recordWithArchivePath:(NSString *)path atOffset:(UInt64)offset { 49 | NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path]; 50 | [file seekToFileOffset:offset]; 51 | NSData *data = [file readDataOfLength:ZKCDTrailer64FixedDataLength]; 52 | [file closeFile]; 53 | ZKCDTrailer64 *record = [self recordWithData:data atOffset:0]; 54 | return record; 55 | } 56 | 57 | - (NSData *)data { 58 | NSMutableData *data = [NSMutableData zk_dataWithLittleInt32:self.magicNumber]; 59 | [data zk_appendLittleInt64:self.sizeOfTrailer]; 60 | [data zk_appendLittleInt16:self.versionMadeBy]; 61 | [data zk_appendLittleInt16:self.versionNeededToExtract]; 62 | [data zk_appendLittleInt32:self.thisDiskNumber]; 63 | [data zk_appendLittleInt32:self.diskNumberWithStartOfCentralDirectory]; 64 | [data zk_appendLittleInt64:self.numberOfCentralDirectoryEntriesOnThisDisk]; 65 | [data zk_appendLittleInt64:self.totalNumberOfCentralDirectoryEntries]; 66 | [data zk_appendLittleInt64:self.sizeOfCentralDirectory]; 67 | [data zk_appendLittleInt64:self.offsetOfStartOfCentralDirectory]; 68 | return data; 69 | } 70 | 71 | - (NSUInteger)length { 72 | return ZKCDTrailer64FixedDataLength; 73 | } 74 | 75 | - (NSString *)description { 76 | return [NSString stringWithFormat:@"%qu entries @ offset of CD: %qu (%qu bytes)", 77 | self.numberOfCentralDirectoryEntriesOnThisDisk, 78 | self.offsetOfStartOfCentralDirectory, 79 | self.sizeOfCentralDirectory]; 80 | } 81 | 82 | @end 83 | -------------------------------------------------------------------------------- /ZipKit/ZKCDTrailer64Locator.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZKCDTrailer64Locator.h 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import 9 | 10 | @interface ZKCDTrailer64Locator : NSObject 11 | 12 | + (ZKCDTrailer64Locator *)recordWithData:(NSData *)data atOffset:(UInt64)offset; 13 | + (ZKCDTrailer64Locator *)recordWithArchivePath:(NSString *)path andCDTrailerLength:(NSUInteger)cdTrailerLength; 14 | 15 | - (NSData *)data; 16 | - (NSUInteger)length; 17 | 18 | @property (assign) UInt32 magicNumber; 19 | @property (assign) UInt32 diskNumberWithStartOfCentralDirectory; 20 | @property (assign) UInt64 offsetOfStartOfCentralDirectoryTrailer64; 21 | @property (assign) UInt32 numberOfDisks; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /ZipKit/ZKCDTrailer64Locator.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZKCDTrailer64Locator.m 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import "ZKCDTrailer64Locator.h" 9 | #import "NSData+ZKAdditions.h" 10 | #import "ZKDefs.h" 11 | 12 | @implementation ZKCDTrailer64Locator 13 | 14 | - (id)init { 15 | if (self = [super init]) { 16 | self.magicNumber = ZKCDTrailer64LocatorMagicNumber; 17 | self.diskNumberWithStartOfCentralDirectory = 0; 18 | self.numberOfDisks = 1; 19 | } 20 | return self; 21 | } 22 | 23 | + (ZKCDTrailer64Locator *)recordWithData:(NSData *)data atOffset:(UInt64)offset { 24 | if (!data || data.length < 1) { 25 | return nil; 26 | } 27 | UInt32 mn = [data zk_hostInt32OffsetBy:&offset]; 28 | if (mn != ZKCDTrailer64LocatorMagicNumber) { 29 | return nil; 30 | } 31 | ZKCDTrailer64Locator *record = [ZKCDTrailer64Locator new]; 32 | record.magicNumber = mn; 33 | record.diskNumberWithStartOfCentralDirectory = [data zk_hostInt32OffsetBy:&offset]; 34 | record.offsetOfStartOfCentralDirectoryTrailer64 = [data zk_hostInt64OffsetBy:&offset]; 35 | record.numberOfDisks = [data zk_hostInt32OffsetBy:&offset]; 36 | return record; 37 | } 38 | 39 | + (ZKCDTrailer64Locator *)recordWithArchivePath:(NSString *)path andCDTrailerLength:(NSUInteger)cdTrailerLength { 40 | NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path]; 41 | unsigned long long fileOffset = [file seekToEndOfFile] - cdTrailerLength - ZKCDTrailer64LocatorFixedDataLength; 42 | [file seekToFileOffset:fileOffset]; 43 | NSData *data = [file readDataOfLength:ZKCDTrailer64LocatorFixedDataLength]; 44 | [file closeFile]; 45 | ZKCDTrailer64Locator *record = [self recordWithData:data atOffset:0]; 46 | return record; 47 | } 48 | 49 | - (NSData *)data { 50 | NSMutableData *data = [NSMutableData zk_dataWithLittleInt32:self.magicNumber]; 51 | [data zk_appendLittleInt32:self.diskNumberWithStartOfCentralDirectory]; 52 | [data zk_appendLittleInt64:self.offsetOfStartOfCentralDirectoryTrailer64]; 53 | [data zk_appendLittleInt32:self.numberOfDisks]; 54 | return data; 55 | } 56 | 57 | - (NSUInteger)length { 58 | return ZKCDTrailer64LocatorFixedDataLength; 59 | } 60 | 61 | - (NSString *)description { 62 | return [NSString stringWithFormat:@"offset of CD64: %qu", self.offsetOfStartOfCentralDirectoryTrailer64]; 63 | } 64 | 65 | @end 66 | -------------------------------------------------------------------------------- /ZipKit/ZKDataArchive.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZKDataArchive.h 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 07/05/09. 6 | // 7 | 8 | #import 9 | #import 10 | 11 | @class ZKCDHeader; 12 | 13 | @interface ZKDataArchive : ZKArchive { 14 | NSMutableData *_data; 15 | NSMutableArray *_inflatedFiles; 16 | } 17 | 18 | + (ZKDataArchive *)archiveWithArchivePath:(NSString *)path; 19 | + (ZKDataArchive *)archiveWithArchiveData:(NSMutableData *)archiveData; 20 | - (NSUInteger)inflateAll; 21 | - (NSData *)inflateFile:(ZKCDHeader *)cdHeader attributes:(NSDictionary **)fileAttributes; 22 | - (NSUInteger)inflateInFolder:(NSString *)enclosingFolder withFolderName:(NSString *)folderName usingResourceFork:(BOOL)rfFlag; 23 | 24 | - (NSInteger)deflateFiles:(NSArray *)paths relativeToPath:(NSString *)basePath usingResourceFork:(BOOL)flag; 25 | - (NSInteger)deflateDirectory:(NSString *)dirPath relativeToPath:(NSString *)basePath usingResourceFork:(BOOL)flag; 26 | - (NSInteger)deflateFile:(NSString *)path relativeToPath:(NSString *)basePath usingResourceFork:(BOOL)rfFlag; 27 | - (NSInteger)deflateData:(NSData *)data withFilename:(NSString *)filename andAttributes:(NSDictionary *)fileAttributes; 28 | 29 | @property (strong) NSMutableData *data; 30 | @property (strong) NSMutableArray *inflatedFiles; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /ZipKit/ZKDefs.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZKDefs.h 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import 9 | 10 | #define ZK_TARGET_OS_MAC (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) 11 | #define ZK_TARGET_OS_IPHONE (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE || TARGET_OS_IPHONE_SIMULATOR) 12 | 13 | enum ZKReturnCodes { 14 | zkFailed = -1, 15 | zkCancelled = 0, 16 | zkSucceeded = 1, 17 | }; 18 | 19 | // File & path naming 20 | extern NSString *const ZKArchiveFileExtension; 21 | extern NSString *const ZKMacOSXDirectory; 22 | extern NSString *const ZKDotUnderscore; 23 | extern NSString *const ZKExpansionDirectoryName; 24 | 25 | // Keys for dictionary passed to size calculation thread 26 | extern NSString *const ZKPathsKey; 27 | extern NSString *const ZKusingResourceForkKey; 28 | 29 | // Keys for dictionary returned from ZKDataArchive inflation 30 | extern NSString *const ZKFileDataKey; 31 | extern NSString *const ZKFileAttributesKey; 32 | extern NSString *const ZKPathKey; 33 | 34 | // Zipping & Unzipping 35 | extern const unsigned long long ZKZipBlockSize; 36 | extern const UInt32 ZKNotificationIterations; 37 | 38 | // Magic numbers and lengths for zip records 39 | extern const UInt32 ZKCDHeaderMagicNumber; 40 | extern const UInt32 ZKCDHeaderFixedDataLength; 41 | 42 | extern const UInt32 ZKCDTrailerMagicNumber; 43 | extern const UInt32 ZKCDTrailerFixedDataLength; 44 | 45 | extern const UInt32 ZKLFHeaderMagicNumber; 46 | extern const UInt32 ZKLFHeaderFixedDataLength; 47 | 48 | extern const UInt32 ZKCDTrailer64MagicNumber; 49 | extern const UInt32 ZKCDTrailer64FixedDataLength; 50 | 51 | extern const UInt32 ZKCDTrailer64LocatorMagicNumber; 52 | extern const UInt32 ZKCDTrailer64LocatorFixedDataLength; 53 | -------------------------------------------------------------------------------- /ZipKit/ZKDefs.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZKDefs.m 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import "ZKDefs.h" 9 | 10 | NSString *const ZKArchiveFileExtension = @"zip"; 11 | NSString *const ZKMacOSXDirectory = @"__MACOSX"; 12 | NSString *const ZKDotUnderscore = @"._"; 13 | NSString *const ZKExpansionDirectoryName = @".ZipKit"; 14 | 15 | NSString *const ZKPathsKey = @"paths"; 16 | NSString *const ZKusingResourceForkKey = @"usingResourceFork"; 17 | 18 | NSString *const ZKFileDataKey = @"fileData"; 19 | NSString *const ZKFileAttributesKey = @"fileAttributes"; 20 | NSString *const ZKPathKey = @"path"; 21 | 22 | const unsigned long long ZKZipBlockSize = 262144; 23 | const UInt32 ZKNotificationIterations = 100; 24 | 25 | const UInt32 ZKCDHeaderMagicNumber = 0x02014B50; 26 | const UInt32 ZKCDHeaderFixedDataLength = 46; 27 | 28 | const UInt32 ZKCDTrailerMagicNumber = 0x06054B50; 29 | const UInt32 ZKCDTrailerFixedDataLength = 22; 30 | 31 | const UInt32 ZKLFHeaderMagicNumber = 0x04034B50; 32 | const UInt32 ZKLFHeaderFixedDataLength = 30; 33 | 34 | const UInt32 ZKCDTrailer64MagicNumber = 0x06064b50; 35 | const UInt32 ZKCDTrailer64FixedDataLength = 56; 36 | 37 | const UInt32 ZKCDTrailer64LocatorMagicNumber = 0x07064b50; 38 | const UInt32 ZKCDTrailer64LocatorFixedDataLength = 20; 39 | -------------------------------------------------------------------------------- /ZipKit/ZKFileArchive.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZKFileArchive.h 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import 9 | #import 10 | 11 | @class ZKCDHeader; 12 | 13 | @interface ZKFileArchive : ZKArchive 14 | 15 | + (ZKFileArchive *)process:(id)item usingResourceFork:(BOOL)flag withInvoker:(id)invoker andDelegate:(id)delegate; 16 | + (ZKFileArchive *)archiveWithArchivePath:(NSString *)archivePath; 17 | 18 | - (NSInteger)inflateToDiskUsingResourceFork:(BOOL)flag; 19 | - (NSInteger)inflateToDirectory:(NSString *)expansionDirectory usingResourceFork:(BOOL)rfFlag; 20 | - (NSInteger)inflateFile:(ZKCDHeader *)cdHeader toDirectory:(NSString *)expansionDirectory; 21 | 22 | - (NSInteger)deflateFiles:(NSArray *)paths relativeToPath:(NSString *)basePath usingResourceFork:(BOOL)flag; 23 | - (NSInteger)deflateDirectory:(NSString *)dirPath relativeToPath:(NSString *)basePath usingResourceFork:(BOOL)flag; 24 | - (NSInteger)deflateFile:(NSString *)path relativeToPath:(NSString *)basePath usingResourceFork:(BOOL)flag; 25 | 26 | @property (assign) BOOL useZip64Extensions; 27 | @property (atomic) int compressionLevel; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /ZipKit/ZKLFHeader.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZKLFHeader.h 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import 9 | 10 | @interface ZKLFHeader : NSObject 11 | 12 | + (ZKLFHeader *)recordWithData:(NSData *)data atOffset:(UInt64)offset; 13 | + (ZKLFHeader *)recordWithArchivePath:(NSString *)path atOffset:(UInt64)offset; 14 | - (void)parseZip64ExtraField; 15 | - (NSData *)zip64ExtraField; 16 | - (NSData *)data; 17 | - (NSUInteger)length; 18 | - (BOOL)useZip64Extensions; 19 | - (BOOL)isResourceFork; 20 | 21 | @property (assign) UInt32 magicNumber; 22 | @property (assign) UInt32 versionNeededToExtract; 23 | @property (assign) UInt32 generalPurposeBitFlag; 24 | @property (assign) UInt32 compressionMethod; 25 | @property (strong) NSDate *lastModDate; 26 | @property (assign) UInt32 crc; 27 | @property (assign) UInt64 compressedSize; 28 | @property (assign) UInt64 uncompressedSize; 29 | @property (assign) UInt32 filenameLength; 30 | @property (assign) UInt32 extraFieldLength; 31 | @property (copy) NSString *filename; 32 | @property (strong) NSData *extraField; 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /ZipKit/ZKLFHeader.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZKLFHeader.m 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import "ZKLFHeader.h" 9 | #import "NSDate+ZKAdditions.h" 10 | #import "NSData+ZKAdditions.h" 11 | #import "NSString+ZKAdditions.h" 12 | #import "ZKDefs.h" 13 | #import "zlib.h" 14 | 15 | @implementation ZKLFHeader 16 | 17 | - (id)init { 18 | if (self = [super init]) { 19 | self.magicNumber = ZKLFHeaderMagicNumber; 20 | self.versionNeededToExtract = 20; 21 | self.generalPurposeBitFlag = 0; 22 | self.compressionMethod = Z_DEFLATED; 23 | self.lastModDate = [NSDate date]; 24 | self.crc = 0; 25 | self.compressedSize = 0; 26 | self.uncompressedSize = 0; 27 | self.filenameLength = 0; 28 | self.extraFieldLength = 0; 29 | self.filename = nil; 30 | self.extraField = nil; 31 | 32 | [self addObserver:self forKeyPath:@"compressedSize" options:NSKeyValueObservingOptionNew context:nil]; 33 | [self addObserver:self forKeyPath:@"uncompressedSize" options:NSKeyValueObservingOptionNew context:nil]; 34 | [self addObserver:self forKeyPath:@"extraField" options:NSKeyValueObservingOptionNew context:nil]; 35 | [self addObserver:self forKeyPath:@"filename" options:NSKeyValueObservingOptionNew context:nil]; 36 | } 37 | return self; 38 | } 39 | 40 | - (void)removeObservers { 41 | [self removeObserver:self forKeyPath:@"compressedSize"]; 42 | [self removeObserver:self forKeyPath:@"uncompressedSize"]; 43 | [self removeObserver:self forKeyPath:@"extraField"]; 44 | [self removeObserver:self forKeyPath:@"filename"]; 45 | } 46 | 47 | - (void)dealloc { 48 | [self removeObservers]; 49 | } 50 | 51 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 52 | if ([keyPath isEqualToString:@"compressedSize"] || [keyPath isEqualToString:@"uncompressedSize"]) { 53 | self.versionNeededToExtract = ([self useZip64Extensions] ? 45 : 20); 54 | } else if ([keyPath isEqualToString:@"extraField"] && self.extraFieldLength < 1) { 55 | self.extraFieldLength = (UInt32)[self.extraField length]; 56 | } else if ([keyPath isEqualToString:@"filename"] && self.filenameLength < 1) { 57 | self.filenameLength = [self.filename zk_precomposedUTF8Length]; 58 | } 59 | } 60 | 61 | + (ZKLFHeader *)recordWithData:(NSData *)data atOffset:(UInt64)offset { 62 | if (!data || data.length < 1) { 63 | return nil; 64 | } 65 | UInt32 mn = [data zk_hostInt32OffsetBy:&offset]; 66 | if (mn != ZKLFHeaderMagicNumber) { 67 | return nil; 68 | } 69 | ZKLFHeader *record = [ZKLFHeader new]; 70 | record.magicNumber = mn; 71 | record.versionNeededToExtract = [data zk_hostInt16OffsetBy:&offset]; 72 | record.generalPurposeBitFlag = [data zk_hostInt16OffsetBy:&offset]; 73 | record.compressionMethod = [data zk_hostInt16OffsetBy:&offset]; 74 | record.lastModDate = [NSDate zk_dateWithDosDate:[data zk_hostInt32OffsetBy:&offset]]; 75 | record.crc = [data zk_hostInt32OffsetBy:&offset]; 76 | record.compressedSize = [data zk_hostInt32OffsetBy:&offset]; 77 | record.uncompressedSize = [data zk_hostInt32OffsetBy:&offset]; 78 | record.filenameLength = [data zk_hostInt16OffsetBy:&offset]; 79 | record.extraFieldLength = [data zk_hostInt16OffsetBy:&offset]; 80 | if ([data length] > ZKLFHeaderFixedDataLength) { 81 | if (record.filenameLength > 0) { 82 | record.filename = [data zk_stringOffsetBy:&offset length:record.filenameLength]; 83 | } 84 | if (record.extraFieldLength > 0) { 85 | record.extraField = [data subdataWithRange:NSMakeRange((NSUInteger)offset, record.extraFieldLength)]; 86 | [record parseZip64ExtraField]; 87 | } 88 | } 89 | return record; 90 | } 91 | 92 | + (ZKLFHeader *)recordWithArchivePath:(NSString *)path atOffset:(UInt64)offset { 93 | NSFileHandle *file = [NSFileHandle fileHandleForReadingAtPath:path]; 94 | [file seekToFileOffset:offset]; 95 | NSData *fixedData = [file readDataOfLength:ZKLFHeaderFixedDataLength]; 96 | ZKLFHeader *record = [self recordWithData:fixedData atOffset:0]; 97 | if (record.filenameLength > 0) { 98 | NSData *data = [file readDataOfLength:record.filenameLength]; 99 | record.filename = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; 100 | } 101 | if (record.extraFieldLength > 0) { 102 | record.extraField = [file readDataOfLength:record.extraFieldLength]; 103 | [record parseZip64ExtraField]; 104 | } 105 | [file closeFile]; 106 | return record; 107 | } 108 | 109 | - (NSData *)data { 110 | self.extraField = [self zip64ExtraField]; 111 | 112 | NSMutableData *data = [NSMutableData zk_dataWithLittleInt32:self.magicNumber]; 113 | [data zk_appendLittleInt16:self.versionNeededToExtract]; 114 | [data zk_appendLittleInt16:self.generalPurposeBitFlag]; 115 | [data zk_appendLittleInt16:self.compressionMethod]; 116 | [data zk_appendLittleInt32:[self.lastModDate zk_dosDate]]; 117 | [data zk_appendLittleInt32:self.crc]; 118 | if ([self useZip64Extensions]) { 119 | [data zk_appendLittleInt32:0xFFFFFFFF]; 120 | [data zk_appendLittleInt32:0xFFFFFFFF]; 121 | } else { 122 | [data zk_appendLittleInt32:(UInt32)self.compressedSize]; 123 | [data zk_appendLittleInt32:(UInt32)self.uncompressedSize]; 124 | } 125 | [data zk_appendLittleInt16:self.filenameLength]; 126 | [data zk_appendLittleInt16:[self.extraField length]]; 127 | [data zk_appendPrecomposedUTF8String:self.filename]; 128 | [data appendData:self.extraField]; 129 | return data; 130 | } 131 | 132 | - (void)parseZip64ExtraField { 133 | NSUInteger tag, length; 134 | UInt64 offset = 0; 135 | while (offset < self.extraFieldLength) { 136 | tag = [self.extraField zk_hostInt16OffsetBy:&offset]; 137 | length = [self.extraField zk_hostInt16OffsetBy:&offset]; 138 | if (tag == 0x0001) { 139 | if (length >= 8) { 140 | self.uncompressedSize = [self.extraField zk_hostInt64OffsetBy:&offset]; 141 | } 142 | if (length >= 16) { 143 | self.compressedSize = [self.extraField zk_hostInt64OffsetBy:&offset]; 144 | } 145 | break; 146 | } else { 147 | offset += length; 148 | } 149 | } 150 | } 151 | 152 | - (NSData *)zip64ExtraField { 153 | NSMutableData *zip64ExtraField = nil; 154 | if ([self useZip64Extensions]) { 155 | zip64ExtraField = [NSMutableData zk_dataWithLittleInt16:0x0001]; 156 | [zip64ExtraField zk_appendLittleInt16:16]; 157 | [zip64ExtraField zk_appendLittleInt64:self.uncompressedSize]; 158 | [zip64ExtraField zk_appendLittleInt64:self.compressedSize]; 159 | } 160 | return zip64ExtraField; 161 | } 162 | 163 | - (NSUInteger)length { 164 | if (!self.extraField || [self.extraField length] == 0) { 165 | self.extraField = [self zip64ExtraField]; 166 | } 167 | return ZKLFHeaderFixedDataLength + self.filenameLength + [self.extraField length]; 168 | } 169 | 170 | - (BOOL)useZip64Extensions { 171 | return (self.uncompressedSize >= 0xFFFFFFFF) || (self.compressedSize >= 0xFFFFFFFF); 172 | } 173 | 174 | - (NSString *)description { 175 | return [NSString stringWithFormat:@"%@ modified %@, %qu bytes (%qu compressed)", 176 | self.filename, self.lastModDate, self.uncompressedSize, self.compressedSize]; 177 | } 178 | 179 | - (BOOL)isResourceFork { 180 | return [self.filename zk_isResourceForkPath]; 181 | } 182 | 183 | @end 184 | -------------------------------------------------------------------------------- /ZipKit/ZKLog.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZKLog.h 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import 9 | 10 | enum ZKLogLevel { 11 | ZKLogLevelNotice = 3, 12 | ZKLogLevelError = 2, 13 | ZKLogLevelDebug = 1, 14 | ZKLogLevelAll = 0, 15 | }; 16 | 17 | #define ZKLog(s, l, ...) [[ZKLog sharedInstance] logFile:__FILE__ lineNumber: __LINE__ level: l format: (s), ## __VA_ARGS__] 18 | 19 | #define ZKLogError(s, ...) ZKLog((s), ZKLogLevelError, ## __VA_ARGS__) 20 | #define ZKLogNotice(s, ...) ZKLog((s), ZKLogLevelNotice, ## __VA_ARGS__) 21 | #define ZKLogDebug(s, ...) ZKLog((s), ZKLogLevelDebug, ## __VA_ARGS__) 22 | 23 | #define ZKLogWithException(e) ZKLogError(@"Exception in %@: \n\tname: %@\n\treason: %@\n\tuserInfo: %@", NSStringFromSelector(_cmd), [e name], [e reason], [e userInfo]); 24 | #define ZKLogWithError(e) ZKLogError(@"Error in %@: \n\tdomain: %@\n\tcode: %@\n\tdescription: %@", NSStringFromSelector(_cmd), [e domain], [e code], [e localizedDescription]); 25 | 26 | #define ZKStringFromBOOL(b) (b ? @"YES" : @"NO") 27 | 28 | extern NSString *const ZKLogLevelKey; 29 | extern NSString *const ZKLogToFileKey; 30 | 31 | @interface ZKLog : NSObject { 32 | @private 33 | NSUInteger _minimumLevel; 34 | } 35 | 36 | - (void)logFile:(char *)sourceFile lineNumber:(NSUInteger)lineNumber level:(NSUInteger)level format:(NSString *)format, ...; 37 | 38 | - (NSString *)levelToLabel:(NSUInteger)level; 39 | 40 | + (ZKLog *)sharedInstance; 41 | 42 | @property (assign) NSUInteger minimumLevel; 43 | @property (strong) NSDateFormatter *dateFormatter; 44 | @property (assign) int pid; 45 | @property (copy) NSString *logFilePath; 46 | @property (assign) FILE *logFilePointer; 47 | 48 | @end 49 | -------------------------------------------------------------------------------- /ZipKit/ZKLog.m: -------------------------------------------------------------------------------- 1 | // 2 | // ZKLog.m 3 | // ZipKit 4 | // 5 | // Created by Karl Moskowski on 01/04/09. 6 | // 7 | 8 | #import "ZKLog.h" 9 | 10 | NSString *const ZKLogLevelKey = @"ZKLogLevel"; 11 | NSString *const ZKLogToFileKey = @"ZKLogToFile"; 12 | 13 | @implementation ZKLog 14 | 15 | - (void)logFile:(char *)sourceFile lineNumber:(NSUInteger)lineNumber level:(NSUInteger)level format:(NSString *)format, ... { 16 | if (level >= self.minimumLevel) { 17 | va_list args; 18 | va_start(args, format); 19 | NSString *message = [[NSString alloc] initWithFormat:format arguments:args]; 20 | va_end(args); 21 | NSString *label = [self levelToLabel:level]; 22 | NSString *now = [self.dateFormatter stringFromDate:[NSDate date]]; 23 | if (label) { 24 | NSString *line = [NSString stringWithFormat:@"%@ [%i] %@ %@ (%@:%lu)", now, self.pid, label, message, [@(sourceFile)lastPathComponent], (unsigned long)lineNumber]; 25 | fprintf(stderr, "%s\n", [line UTF8String]); 26 | fflush(stderr); 27 | } 28 | } 29 | return; 30 | } 31 | 32 | - (NSUInteger)minimumLevel { 33 | return _minimumLevel; 34 | } 35 | - (void)setMinimumLevel:(NSUInteger)value { 36 | switch (value) { 37 | case ZKLogLevelError: 38 | case ZKLogLevelNotice: 39 | case ZKLogLevelDebug: 40 | case ZKLogLevelAll: 41 | _minimumLevel = value; 42 | break; 43 | default: 44 | ZKLogError(@"Invalid logging level: %u. Old value %@ unchanged.", value, [self levelToLabel:self.minimumLevel]); 45 | break; 46 | } 47 | return; 48 | } 49 | 50 | - (NSString *)levelToLabel:(NSUInteger)level { 51 | NSString *label = nil; 52 | switch (level) { 53 | case ZKLogLevelError: 54 | label = @""; 55 | break; 56 | case ZKLogLevelNotice: 57 | label = @""; 58 | break; 59 | case ZKLogLevelDebug: 60 | label = @""; 61 | break; 62 | default: 63 | label = nil; 64 | break; 65 | } 66 | return label; 67 | } 68 | 69 | static ZKLog *zkSharedInstance = nil; 70 | + (ZKLog *)sharedInstance { 71 | @synchronized(self) { 72 | if (zkSharedInstance == nil) { 73 | zkSharedInstance = [self new]; 74 | } 75 | } 76 | return zkSharedInstance; 77 | } 78 | 79 | - (id)init { 80 | @synchronized([self class]) { 81 | if (zkSharedInstance == nil) { 82 | if (self = [super init]) { 83 | zkSharedInstance = self; 84 | 85 | self.pid = [[NSProcessInfo processInfo] processIdentifier]; 86 | self.minimumLevel = ZKLogLevelError; 87 | self.dateFormatter = [NSDateFormatter new]; 88 | [self.dateFormatter setDateFormat:@"yyyy-MM-dd HH:mm:ss.SSS"]; 89 | 90 | if ([[NSUserDefaults standardUserDefaults] boolForKey:ZKLogToFileKey]) { 91 | NSArray *searchPaths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); 92 | NSString *libraryFolder = searchPaths[0]; 93 | NSString *logFolder = [libraryFolder stringByAppendingPathComponent:@"Logs"]; 94 | [[NSFileManager new] createDirectoryAtPath:logFolder withIntermediateDirectories:YES attributes:nil error:nil]; 95 | self.logFilePath = [logFolder stringByAppendingPathComponent: 96 | [[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"] 97 | stringByAppendingPathExtension:@"log"]]; 98 | freopen([self.logFilePath fileSystemRepresentation], "a+", stderr); 99 | } 100 | } 101 | } 102 | } 103 | return zkSharedInstance; 104 | } 105 | 106 | + (id)allocWithZone:(NSZone *)zone { 107 | @synchronized(self) { 108 | if (zkSharedInstance == nil) { 109 | return [super allocWithZone:zone]; 110 | } 111 | } 112 | return zkSharedInstance; 113 | } 114 | 115 | + (void)initialize { 116 | [[NSUserDefaults standardUserDefaults] registerDefaults: 117 | @{ZKLogToFileKey: @NO}]; 118 | [super initialize]; 119 | } 120 | 121 | - (id)copyWithZone:(NSZone *)zone { 122 | return self; 123 | } 124 | 125 | 126 | - (void)dealloc { 127 | if (self.logFilePointer) { 128 | fclose(self.logFilePointer); 129 | } 130 | } 131 | 132 | @dynamic minimumLevel; 133 | 134 | @end 135 | -------------------------------------------------------------------------------- /ZipKit/ZipKit-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | NSHumanReadableCopyright 26 | Copyright © 2020 Karl Moskowski. All rights reserved. 27 | NSPrincipalClass 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /ZipKit/ZipKit.h: -------------------------------------------------------------------------------- 1 | // 2 | // ZipKit.h 3 | // ZipKit 4 | // 5 | // Created by Sam Deane on 25/10/13. 6 | // 7 | 8 | #import 9 | #import 10 | #import 11 | #import 12 | #import 13 | 14 | #import 15 | #import 16 | #import 17 | #import 18 | #import 19 | #import 20 | 21 | #if ZK_TARGET_OS_MAC 22 | #import 23 | #import 24 | #endif 25 | --------------------------------------------------------------------------------