@@ -16,19 +16,36 @@ #include "config.h" #include #import "OFArchiveURIHandler.h" +#import "OFCharacterSet.h" #import "OFGZIPStream.h" #import "OFLHAArchive.h" #import "OFStream.h" #import "OFTarArchive.h" #import "OFURI.h" #import "OFZIPArchive.h" #import "OFInvalidArgumentException.h" #import "OFOpenItemFailedException.h" + +@interface OFArchiveURIHandlerPathAllowedCharacterSet: OFCharacterSet +{ + OFCharacterSet *_characterSet; + bool (*_characterIsMember)(id, SEL, OFUnichar); +} +@end + +static OFCharacterSet *pathAllowedCharacters; + +static void +initPathAllowedCharacters(void) +{ + pathAllowedCharacters = + [[OFArchiveURIHandlerPathAllowedCharacterSet alloc] init]; +} @implementation OFArchiveURIHandler - (OFStream *)openItemAtURI: (OFURI *)URI mode: (OFString *)mode { void *pool = objc_autoreleasePoolPush(); @@ -119,5 +136,66 @@ objc_autoreleasePoolPop(pool); return [stream autorelease]; } @end + +@implementation OFArchiveURIHandlerPathAllowedCharacterSet +- (instancetype)init +{ + self = [super init]; + + @try { + _characterSet = + [[OFCharacterSet URIPathAllowedCharacterSet] retain]; + _characterIsMember = (bool (*)(id, SEL, OFUnichar)) + [_characterSet methodForSelector: + @selector(characterIsMember:)]; + } @catch (id e) { + [self release]; + @throw e; + } + + return self; +} + +- (void)dealloc +{ + [_characterSet release]; + + [super dealloc]; +} + +- (bool)characterIsMember: (OFUnichar)character +{ + return (character != '!' && _characterIsMember(_characterSet, + @selector(characterIsMember:), character)); +} +@end + +OFURI * +OFArchiveURIHandlerURIForFileInArchive(OFString *scheme, + OFString *pathInArchive, OFURI *archiveURI) +{ + static OFOnceControl onceControl = OFOnceControlInitValue; + OFMutableURI *ret = [OFMutableURI URI]; + void *pool = objc_autoreleasePoolPush(); + OFString *archiveURIString; + + OFOnce(&onceControl, initPathAllowedCharacters); + + pathInArchive = [pathInArchive + stringByAddingPercentEncodingWithAllowedCharacters: + pathAllowedCharacters]; + archiveURIString = [archiveURI.string + stringByAddingPercentEncodingWithAllowedCharacters: + pathAllowedCharacters]; + + ret.scheme = scheme; + ret.percentEncodedPath = [OFString + stringWithFormat: @"%@!%@", archiveURIString, pathInArchive]; + [ret makeImmutable]; + + objc_autoreleasePoolPop(pool); + + return ret; +}