Created
February 1, 2011 17:20
-
-
Save davepeck/806192 to your computer and use it in GitHub Desktop.
How to use libarchive to unextract on iOS
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* call processNextArchiveEntry in some kind of loop! */ | |
- (int)processNextArchiveEntry:(struct archive *)archive | |
{ | |
struct archive_entry *entry = NULL; | |
int result = ARCHIVE_OK; | |
result = archive_read_next_header(archive, &entry); | |
if (result == ARCHIVE_OK) | |
{ | |
if (archive_entry_filetype(entry) == AE_IFDIR) | |
{ | |
result = [self processDirectory:entry inArchive:archive]; | |
} | |
else if (archive_entry_filetype(entry) == AE_IFREG) | |
{ | |
result = [self processFile:entry inArchive:archive]; | |
} | |
} | |
return result; | |
} | |
- (int)processDirectory:(struct archive_entry *)entry inArchive:(struct archive *)archive | |
{ | |
NSString *path = nil; | |
NSError *error = nil; | |
BOOL exists, isDirectory; | |
BOOL ok = NO; | |
path = [self fullDestinationPathForEntry:entry]; | |
exists = [fileManager fileExistsAtPath:path isDirectory:&isDirectory]; | |
if (!exists) | |
{ | |
ok = [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&error]; | |
} | |
else if (exists && isDirectory) | |
{ | |
// we allow users to re-download content, in which case this can happen. | |
ok = YES; | |
} | |
return ok ? ARCHIVE_OK : ARCHIVE_FATAL; | |
} | |
- (int)processFile:(struct archive_entry *)entry inArchive:(struct archive *)archive | |
{ | |
NSFileHandle *file = nil; | |
NSString *path = nil; | |
BOOL ok = NO; | |
int result = ARCHIVE_FAILED; | |
path = [self fullDestinationPathForEntry:entry]; | |
ok = [fileManager createFileAtPath:path contents:nil attributes:nil]; | |
if (ok) | |
{ | |
file = [NSFileHandle fileHandleForWritingAtPath:path]; | |
} | |
if(file != nil) | |
{ | |
result = archive_read_data_into_fd(archive, [file fileDescriptor]); | |
[file closeFile]; | |
} | |
return result; | |
} | |
- (NSString *)fullDestinationPathForEntry:(struct archive_entry *)entry | |
{ | |
NSString *path = nil; | |
const char *entry_path = NULL; | |
entry_path = archive_entry_pathname(entry); | |
if (entry_path != NULL) | |
{ | |
path = [fileManager stringWithFileSystemRepresentation:entry_path length:strlen(entry_path)]; | |
} | |
if (path != nil) | |
{ | |
path = [tempDirectory stringByAppendingPathComponent:path]; | |
} | |
return path; | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* this is the 'main' method of my "download & unarchive" operation. */ | |
- (void)main | |
{ | |
struct archive *archive; | |
int result; | |
// kick off downloading the archive file from my web site | |
[self beginDownload]; | |
// initialize the libarchive reading structures | |
result = [self initArchive:&archive]; | |
// here's the loop that both signals for progress updates and deals with next entries | |
while (result == ARCHIVE_OK && ![self isCancelled]) | |
{ | |
[self updateProgressForArchive:archive]; | |
result = [self processNextArchiveEntry:archive]; | |
} | |
// all good loops must come to an end | |
if (result == ARCHIVE_EOF) | |
{ | |
result = archive_read_finish(archive); | |
} | |
// this is somewhat lame, but we _are_ in an NSOperation so it's polite | |
if ([self isCancelled]) | |
{ | |
NSLog(@"MyDownloadOperation was canceled"); | |
[downloadThread cancel]; | |
[[pipe fileHandleForReading] readDataToEndOfFile]; // Unblock the download thread | |
result = ARCHIVE_RETRY; | |
} | |
// everything worked! | |
if (result == ARCHIVE_OK) | |
{ | |
[self moveContentFromStagingAreaToFinalArea]; // this is how my app rolls; yours may be different | |
} | |
else | |
{ | |
[self removeTempDirectory]; // this is how my app rolls; yours may be different | |
} | |
} | |
- (void)beginDownload | |
{ | |
pipe = [NSPipe new]; | |
downloadThread = [[MyDownloadThread alloc] initWithURL:myDownloadUrl stream:[pipe fileHandleForWriting]]; | |
[downloadThread start]; | |
} | |
- (int)initArchive:(struct archive **)outArchive | |
{ | |
struct archive *archive = NULL; | |
int result = ARCHIVE_OK; | |
archive = archive_read_new(); | |
archive_read_support_compression_bzip2(archive); | |
archive_read_support_compression_gzip(archive); | |
archive_read_support_format_tar(archive); | |
archive_read_support_format_gnutar(archive); | |
result = archive_read_open_fd(archive, [[pipe fileHandleForReading] fileDescriptor], getpagesize()); | |
if(result == ARCHIVE_OK && outArchive != NULL) | |
{ | |
*outArchive = archive; | |
} | |
lastArchivePosition = 0; | |
return result; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment