cog/Plugins/ArchiveSource/ArchiveSource/ArchiveSource.m

192 lines
3.6 KiB
Objective-C

//
// ArchiveSource.m
// ArchiveSource
//
// Created by Christopher Snowhill on 10/4/13.
// Copyright 2013 __NoWork, Inc__. All rights reserved.
//
#import "ArchiveSource.h"
#import "SandboxBroker.h"
#import "Logging.h"
static NSString *path_unpack_string(NSString *src, NSRange *remainder) {
NSRange bar = [src rangeOfString:@"|"];
if(bar.location != 0 || bar.length != 1)
return nil;
NSRange next = {
.location = 1,
.length = [src length] - 1
};
bar = [src rangeOfString:@"|" options:0 range:next];
if(bar.length != 1)
return nil;
NSRange lengthRange = {
.location = 1,
.length = bar.location - 1
};
NSUInteger length = [[src substringWithRange:lengthRange] integerValue];
if(length >= ([src length] - bar.location - 1))
return nil;
NSRange pathRange = {
.location = bar.location + 1,
.length = length
};
NSString *ret = [src substringWithRange:pathRange];
remainder->location = bar.location + length + 1;
remainder->length = [src length] - remainder->location;
return ret;
}
static BOOL g_parse_unpack_path(NSString *src, NSString **archive, NSString **file, NSString **type) {
NSRange typeRange;
NSRange range;
range = [src rangeOfString:@"|"];
if(range.length != 1)
return NO;
range.length = [src length] - range.location;
typeRange.location = 9;
typeRange.length = range.location - 9;
*type = [src substringWithRange:typeRange];
NSString *url = [src substringWithRange:range];
*archive = path_unpack_string(url, &range);
if(!*archive)
return NO;
range.location++;
range.length--;
*file = [url substringWithRange:range];
return YES;
}
@implementation ArchiveSource
- (id)init {
self = [super init];
if(self) {
fex = NULL;
}
return self;
}
- (BOOL)open:(NSURL *)url {
[self setURL:url];
NSString *urlDecoded = [[url absoluteString] stringByRemovingPercentEncoding];
NSString *type;
NSString *archive;
NSString *file;
if(!g_parse_unpack_path(urlDecoded, &archive, &file, &type))
return NO;
if(![type isEqualToString:@"fex"])
return NO;
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
sbHandle = [sandboxBroker beginFolderAccess:[NSURL fileURLWithPath:archive]];
fex_err_t error;
error = fex_open(&fex, [archive UTF8String]);
if(error) {
ALog(@"Error opening archive: %s", error);
return NO;
}
while(!fex_done(fex)) {
if([file isEqualToString:guess_encoding_of_string(fex_name(fex))])
break;
fex_next(fex);
}
if(fex_done(fex))
return NO;
error = fex_data(fex, &data);
if(error) {
ALog(@"Error unpacking file from archive: %s", error);
return NO;
}
offset = 0;
size = fex_size(fex);
return YES;
}
- (BOOL)seekable {
return YES;
}
- (BOOL)seek:(long)position whence:(int)whence {
switch(whence) {
case SEEK_CUR:
position += offset;
break;
case SEEK_END:
position += size;
break;
}
offset = position;
return (offset <= size);
}
- (long)tell {
return offset;
}
- (long)read:(void *)buffer amount:(long)amount {
if(offset >= size)
return 0;
if(size - offset < amount)
amount = size - offset;
memcpy(buffer, (const uint8_t *)data + offset, amount);
offset += amount;
return amount;
}
- (void)close {
if(fex) {
fex_close(fex);
fex = NULL;
}
if(sbHandle) {
id sandboxBrokerClass = NSClassFromString(@"SandboxBroker");
id sandboxBroker = [sandboxBrokerClass sharedSandboxBroker];
[sandboxBroker endFolderAccess:sbHandle];
sbHandle = NULL;
}
}
- (NSURL *)url {
return _url;
}
- (NSString *)mimeType {
return nil;
}
- (void)setURL:(NSURL *)url {
_url = url;
}
+ (NSArray *)schemes {
return @[@"unpack"];
}
- (void)dealloc {
[self close];
}
@end