232 lines
7.6 KiB
Objective-C
232 lines
7.6 KiB
Objective-C
//
|
|
// UnrarExampleViewController.m
|
|
// UnrarExample
|
|
//
|
|
//
|
|
|
|
#import "UnrarExampleViewController.h"
|
|
@import UnrarKit;
|
|
|
|
@interface UnrarExampleViewController ()
|
|
|
|
@property (strong) NSURL *largeArchiveURL;
|
|
@property (strong) NSProgress *currentExtractionProgress;
|
|
|
|
@end
|
|
|
|
static void *ProgressObserverContext = &ProgressObserverContext;
|
|
|
|
|
|
@implementation UnrarExampleViewController
|
|
|
|
|
|
- (void)awakeFromNib {
|
|
[super awakeFromNib];
|
|
|
|
self.extractionStepLabel.text = @"";
|
|
|
|
NSFileManager *fm = [NSFileManager defaultManager];
|
|
NSURL *docsDir = [[fm URLsForDirectory:NSDocumentDirectory
|
|
inDomains:NSUserDomainMask] firstObject];
|
|
self.largeArchiveURL = [docsDir URLByAppendingPathComponent:@"large-archive.rar"];
|
|
}
|
|
|
|
- (IBAction)listFiles:(id)sender {
|
|
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"Test Archive (Password)" ofType:@"rar"];
|
|
|
|
NSError *archiveError = nil;
|
|
URKArchive *archive = [[URKArchive alloc] initWithPath:filePath error:&archiveError];
|
|
archive.password = self.passwordField.text;
|
|
|
|
if (!archive) {
|
|
UIAlertController *controller = [UIAlertController alertControllerWithTitle:@"Failed to create archive"
|
|
message:@"Error creating the archive"
|
|
preferredStyle:UIAlertControllerStyleAlert];
|
|
[controller addAction:[UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:nil]];
|
|
|
|
[self presentViewController:controller animated:YES completion:nil];
|
|
return;
|
|
}
|
|
|
|
NSError *error = nil;
|
|
NSArray *filenames = [archive listFilenames:&error];
|
|
|
|
if (!filenames) {
|
|
self.fileListTextView.text = error.localizedDescription;
|
|
return;
|
|
}
|
|
|
|
NSMutableString *fileList = [NSMutableString string];
|
|
|
|
for (NSString *filename in filenames) {
|
|
[fileList appendFormat:@"• %@\n", filename];
|
|
}
|
|
|
|
self.fileListTextView.text = fileList;
|
|
}
|
|
|
|
- (IBAction)extractLargeFile:(id)sender {
|
|
NSProgress *progress = [NSProgress progressWithTotalUnitCount:1];
|
|
self.currentExtractionProgress = progress;
|
|
[progress addObserver:self
|
|
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
|
|
options:NSKeyValueObservingOptionInitial
|
|
context:ProgressObserverContext];
|
|
|
|
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
|
|
[self updateExtractionStep:@"Creating large archive…"];
|
|
|
|
NSURL *archiveURL = [self createLargeArchive];
|
|
|
|
if (!archiveURL) {
|
|
return;
|
|
}
|
|
|
|
[self updateExtractionStep:@"Extracting archive…"];
|
|
|
|
NSError *initError = nil;
|
|
URKArchive *archive = [[URKArchive alloc] initWithURL:archiveURL
|
|
error:&initError];
|
|
|
|
if (!archive) {
|
|
[self reportError:[NSString stringWithFormat:@"Failed to create URKArchive: %@", initError.localizedDescription]];
|
|
return;
|
|
}
|
|
|
|
NSString *firstFile = [[archive listFilenames:nil] firstObject];
|
|
|
|
[progress becomeCurrentWithPendingUnitCount:1];
|
|
|
|
NSError *extractError = nil;
|
|
NSData *data = [archive extractDataFromFile:firstFile
|
|
error:&extractError];
|
|
|
|
self.currentExtractionProgress = nil;
|
|
[progress removeObserver:self
|
|
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
|
|
context:ProgressObserverContext];
|
|
[progress resignCurrent];
|
|
|
|
if (!data) {
|
|
[self reportError:[NSString stringWithFormat:@"Failed to extract archive: %@", extractError.localizedDescription]];
|
|
return;
|
|
}
|
|
|
|
// On extraction completion:
|
|
[self updateExtractionStep:[NSString stringWithFormat:@"Extracted %lub", (unsigned long)data.length]];
|
|
});
|
|
}
|
|
|
|
- (IBAction)cancelExtraction:(id)sender {
|
|
if (self.currentExtractionProgress) {
|
|
[self.currentExtractionProgress cancel];
|
|
}
|
|
}
|
|
|
|
- (void)observeValueForKeyPath:(NSString *)keyPath
|
|
ofObject:(id)object
|
|
change:(NSDictionary<NSKeyValueChangeKey,id> *)change
|
|
context:(void *)context
|
|
{
|
|
if (context == ProgressObserverContext) {
|
|
NSProgress *progress = object;
|
|
|
|
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
|
[self.extractionProgressView setProgress:progress.fractionCompleted
|
|
animated:YES];
|
|
}];
|
|
} else {
|
|
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
|
|
}
|
|
}
|
|
|
|
- (void)reportError:(NSString *)message {
|
|
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
|
self.fileListTextView.text = message;
|
|
}];
|
|
}
|
|
|
|
- (void)updateExtractionStep:(NSString *)message {
|
|
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
|
self.extractionStepLabel.text = message;
|
|
}];
|
|
}
|
|
|
|
- (void)updateProgress:(float)progress {
|
|
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
|
|
[self.extractionProgressView setProgress:progress animated:YES];
|
|
}];
|
|
}
|
|
|
|
- (NSURL *)createLargeArchive {
|
|
[self reportError:@""];
|
|
[self updateExtractionStep:@"Creating large text file…"];
|
|
|
|
[self updateProgress:0];
|
|
|
|
NSURL *largeFile = [self randomTextFileOfLength:100000000];
|
|
|
|
if (!largeFile) {
|
|
[self reportError:@"Failed to create large text file"];
|
|
return nil;
|
|
}
|
|
|
|
[self updateProgress:0];
|
|
|
|
[self updateExtractionStep:@"Compressing large text file…"];
|
|
|
|
// Create archive
|
|
NSURL *archiveURL = self.largeArchiveURL;
|
|
|
|
if (![archiveURL checkResourceIsReachableAndReturnError:nil]) {
|
|
[self updateExtractionStep:@"No archive"];
|
|
[self reportError:
|
|
@"The large archive has not been created yet. A Terminal command "
|
|
"has been copied to the clipboard. Press ⌘C to copy it out "
|
|
"of the Simulator. From a prompt at the UnrarKit/Example "
|
|
"directory, paste it and run"];
|
|
|
|
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
|
|
pasteboard.string = largeFile.path;
|
|
|
|
return nil;
|
|
}
|
|
|
|
return archiveURL;
|
|
}
|
|
|
|
- (NSURL *)randomTextFileOfLength:(NSUInteger)numberOfCharacters {
|
|
NSFileManager *fm = [NSFileManager defaultManager];
|
|
NSURL *docsDir = [[fm URLsForDirectory:NSDocumentDirectory
|
|
inDomains:NSUserDomainMask] firstObject];
|
|
NSString *filename = [NSString stringWithFormat:@"long-random-str-%lu.txt", (unsigned long)numberOfCharacters];
|
|
NSURL *fileURL = [docsDir URLByAppendingPathComponent:filename];
|
|
|
|
if ([fileURL checkResourceIsReachableAndReturnError:nil]) {
|
|
return fileURL;
|
|
}
|
|
|
|
NSString *letters = @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 .,?!\n";
|
|
NSUInteger letterCount = letters.length;
|
|
|
|
NSMutableString *randomString = [NSMutableString stringWithCapacity:numberOfCharacters];
|
|
|
|
for (NSUInteger i = 0; i < numberOfCharacters; i++) {
|
|
uint32_t charIndex = arc4random_uniform((uint32_t)letterCount);
|
|
[randomString appendFormat:@"%C", [letters characterAtIndex:charIndex]];
|
|
|
|
float progress = i / (float)numberOfCharacters;
|
|
[self updateProgress:progress];
|
|
}
|
|
|
|
NSError *error = nil;
|
|
if (![randomString writeToURL:fileURL atomically:YES encoding:NSUTF16StringEncoding error:&error]) {
|
|
return nil;
|
|
}
|
|
|
|
return fileURL;
|
|
}
|
|
|
|
|
|
@end
|