Sandbox Broker now returns a handle to the exact path object that was retained by the caller, so it will be released correctly, regardless of what happens to the list of bookmarked paths. Also refined the bookmark path comparison function. For existing paths, it will find the first match. For new paths, it will prefer the longest path instead, to try to find the deepest matching bookmark. Signed-off-by: Christopher Snowhill <kode54@gmail.com>
191 lines
3.6 KiB
Objective-C
191 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
|