Index: src/OFURI.h ================================================================== --- src/OFURI.h +++ src/OFURI.h @@ -373,10 +373,12 @@ * @brief Returns the characters allowed in the fragment part of a URI. * * @return The characters allowed in the fragment part of a URI. */ + (OFCharacterSet *)URIFragmentAllowedCharacterSet; + ++ (OFCharacterSet *)of_URIPathAllowedCharacterSetWithoutExclamationMark; @end #ifdef __cplusplus extern "C" { #endif Index: src/OFURI.m ================================================================== --- src/OFURI.m +++ src/OFURI.m @@ -50,16 +50,35 @@ @interface OFURIQueryOrFragmentAllowedCharacterSet: OFURIAllowedCharacterSetBase @end @interface OFURIQueryKeyValueAllowedCharacterSet: OFURIAllowedCharacterSetBase @end + +@interface OFURIPathAllowedCharacterSetWithoutExclamationMark: + OFURIPathAllowedCharacterSet +{ + OFCharacterSet *_characterSet; + bool (*_characterIsMember)(id, SEL, OFUnichar); +} +@end + +OF_DIRECT_MEMBERS +@interface OFInvertedCharacterSetWithoutPercent: OFCharacterSet +{ + OFCharacterSet *_characterSet; + bool (*_characterIsMember)(id, SEL, OFUnichar); +} + +- (instancetype)initWithCharacterSet: (OFCharacterSet *)characterSet; +@end static OFCharacterSet *URIAllowedCharacterSet = nil; static OFCharacterSet *URISchemeAllowedCharacterSet = nil; static OFCharacterSet *URIPathAllowedCharacterSet = nil; static OFCharacterSet *URIQueryOrFragmentAllowedCharacterSet = nil; static OFCharacterSet *URIQueryKeyValueAllowedCharacterSet = nil; +static OFCharacterSet *URIPathAllowedCharacterSetWithoutExclamationMark = nil; static OFOnceControl URIAllowedCharacterSetOnce = OFOnceControlInitValue; static OFOnceControl URIQueryOrFragmentAllowedCharacterSetOnce = OFOnceControlInitValue; @@ -95,19 +114,16 @@ { URIQueryKeyValueAllowedCharacterSet = [[OFURIQueryKeyValueAllowedCharacterSet alloc] init]; } -OF_DIRECT_MEMBERS -@interface OFInvertedCharacterSetWithoutPercent: OFCharacterSet -{ - OFCharacterSet *_characterSet; - bool (*_characterIsMember)(id, SEL, OFUnichar); -} - -- (instancetype)initWithCharacterSet: (OFCharacterSet *)characterSet; -@end +static void +initURIPathAllowedCharacterSetWithoutExclamationMark(void) +{ + URIPathAllowedCharacterSetWithoutExclamationMark = + [[OFURIPathAllowedCharacterSetWithoutExclamationMark alloc] init]; +} bool OFURIIsIPv6Host(OFString *host) { const char *UTF8String = host.UTF8String; @@ -288,10 +304,43 @@ default: return false; } } @end + +@implementation OFURIPathAllowedCharacterSetWithoutExclamationMark +- (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 @implementation OFInvertedCharacterSetWithoutPercent - (instancetype)initWithCharacterSet: (OFCharacterSet *)characterSet { self = [super init]; @@ -396,10 +445,19 @@ OFOnce(&URIQueryOrFragmentAllowedCharacterSetOnce, initURIQueryOrFragmentAllowedCharacterSet); return URIQueryOrFragmentAllowedCharacterSet; } + ++ (OFCharacterSet *)of_URIPathAllowedCharacterSetWithoutExclamationMark +{ + static OFOnceControl onceControl = OFOnceControlInitValue; + OFOnce(&onceControl, + initURIPathAllowedCharacterSetWithoutExclamationMark); + + return URIPathAllowedCharacterSetWithoutExclamationMark; +} @end @implementation OFURI + (instancetype)URI { Index: src/OFZIPArchive.h ================================================================== --- src/OFZIPArchive.h +++ src/OFZIPArchive.h @@ -83,10 +83,21 @@ * archive. * @return A new, autoreleased OFZIPArchive */ + (instancetype)archiveWithURI: (OFURI *)URI mode: (OFString *)mode; +/** + * @brief Creates a URI for accessing a the specified file within the specified + * ZIP archive. + * + * @param path The path of the file within the archive + * @param archive The URI of the archive + * @return A URI for accessing the specified file within the specified ZIP + * archive + */ ++ (OFURI *)URIForFile: (OFString *)path inArchive: (OFURI *)archive; + - (instancetype)init OF_UNAVAILABLE; /** * @brief Initializes an already allocated OFZIPArchive object with the * specified stream. Index: src/OFZIPArchive.m ================================================================== --- src/OFZIPArchive.m +++ src/OFZIPArchive.m @@ -26,10 +26,11 @@ #import "OFDictionary.h" #import "OFInflate64Stream.h" #import "OFInflateStream.h" #import "OFSeekableStream.h" #import "OFStream.h" +#import "OFURI.h" #import "OFURIHandler.h" #import "OFChecksumMismatchException.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" @@ -164,10 +165,34 @@ + (instancetype)archiveWithURI: (OFURI *)URI mode: (OFString *)mode { return [[[self alloc] initWithURI: URI mode: mode] autorelease]; } + ++ (OFURI *)URIForFile: (OFString *)path inArchive: (OFURI *)archive +{ + OFMutableURI *URI = [OFMutableURI URI]; + void *pool = objc_autoreleasePoolPush(); + OFCharacterSet *characterSet = [OFCharacterSet + of_URIPathAllowedCharacterSetWithoutExclamationMark]; + OFString *archiveURI; + + path = [path + stringByAddingPercentEncodingWithAllowedCharacters: characterSet]; + archiveURI = [archive.string + stringByAddingPercentEncodingWithAllowedCharacters: characterSet]; + + URI.scheme = @"of-zip"; + URI.percentEncodedPath = [OFString stringWithFormat: @"%@!%@", + archiveURI, path]; + + [URI makeImmutable]; + + objc_autoreleasePoolPop(pool); + + return URI; +} - (instancetype)init { OF_INVALID_INIT_METHOD }