@@ -30,10 +30,257 @@ #import "OFXMLElement.h" #import "OFInvalidArgumentException.h" #import "OFInvalidFormatException.h" #import "OFOutOfMemoryException.h" + +static OFCharacterSet *URLAllowedCharacterSet = nil; +static OFCharacterSet *URLPathAllowedCharacterSet = nil; +static OFCharacterSet *URLQueryOrFragmentAllowedCharacterSet = nil; + +@interface OFCharacterSet_URLAllowed: OFCharacterSet ++ (OFCharacterSet *)URLAllowedCharacterSet; +@end + +@interface OFCharacterSet_URLPathAllowed: OFCharacterSet ++ (OFCharacterSet *)URLPathAllowedCharacterSet; +@end + +@interface OFCharacterSet_URLQueryOrFragmentAllowed: OFCharacterSet ++ (OFCharacterSet *)URLQueryOrFragmentAllowedCharacterSet; +@end + +@implementation OFCharacterSet_URLAllowed ++ (void)initialize +{ + if (self != [OFCharacterSet_URLAllowed class]) + return; + + URLAllowedCharacterSet = [[OFCharacterSet_URLAllowed alloc] init]; +} + ++ (OFCharacterSet *)URLAllowedCharacterSet +{ + return URLAllowedCharacterSet; +} + +- (instancetype)autorelease +{ + return self; +} + +- (instancetype)retain +{ + return self; +} + +- (void)release +{ +} + +- (unsigned int)retainCount +{ + return OF_RETAIN_COUNT_MAX; +} + +- (bool)characterIsMember: (of_unichar_t)character +{ + if (character < CHAR_MAX && of_ascii_isalnum(character)) + return true; + + switch (character) { + case '-': + case '.': + case '_': + case '~': + case '!': + case '$': + case '&': + case '\'': + case '(': + case ')': + case '*': + case '+': + case ',': + case ';': + case '=': + return true; + default: + return false; + } +} +@end + +@implementation OFCharacterSet_URLPathAllowed ++ (void)initialize +{ + if (self != [OFCharacterSet_URLPathAllowed class]) + return; + + URLPathAllowedCharacterSet = + [[OFCharacterSet_URLPathAllowed alloc] init]; +} + ++ (OFCharacterSet *)URLPathAllowedCharacterSet +{ + return URLPathAllowedCharacterSet; +} + +- (instancetype)autorelease +{ + return self; +} + +- (instancetype)retain +{ + return self; +} + +- (void)release +{ +} + +- (unsigned int)retainCount +{ + return OF_RETAIN_COUNT_MAX; +} + +- (bool)characterIsMember: (of_unichar_t)character +{ + if (character < CHAR_MAX && of_ascii_isalnum(character)) + return true; + + switch (character) { + case '-': + case '.': + case '_': + case '~': + case '!': + case '$': + case '&': + case '\'': + case '(': + case ')': + case '*': + case '+': + case ',': + case ';': + case '=': + case ':': + case '@': + case '/': + return true; + default: + return false; + } +} +@end + +@implementation OFCharacterSet_URLQueryOrFragmentAllowed ++ (void)initialize +{ + if (self != [OFCharacterSet_URLQueryOrFragmentAllowed class]) + return; + + URLQueryOrFragmentAllowedCharacterSet = + [[OFCharacterSet_URLQueryOrFragmentAllowed alloc] init]; +} + ++ (OFCharacterSet *)URLQueryOrFragmentAllowedCharacterSet +{ + return URLQueryOrFragmentAllowedCharacterSet; +} + +- (instancetype)autorelease +{ + return self; +} + +- (instancetype)retain +{ + return self; +} + +- (void)release +{ +} + +- (unsigned int)retainCount +{ + return OF_RETAIN_COUNT_MAX; +} + +- (bool)characterIsMember: (of_unichar_t)character +{ + if (character < CHAR_MAX && of_ascii_isalnum(character)) + return true; + + switch (character) { + case '-': + case '.': + case '_': + case '~': + case '!': + case '$': + case '&': + case '\'': + case '(': + case ')': + case '*': + case '+': + case ',': + case ';': + case '=': + case ':': + case '@': + case '/': + case '?': + return true; + default: + return false; + } +} +@end + +@implementation OFCharacterSet (URLCharacterSets) ++ (OFCharacterSet *)URLSchemeAllowedCharacterSet +{ + return [OFCharacterSet_URLAllowed URLAllowedCharacterSet]; +} + ++ (OFCharacterSet *)URLHostAllowedCharacterSet +{ + return [OFCharacterSet_URLAllowed URLAllowedCharacterSet]; +} + ++ (OFCharacterSet *)URLUserAllowedCharacterSet +{ + return [OFCharacterSet_URLAllowed URLAllowedCharacterSet]; +} + ++ (OFCharacterSet *)URLPasswordAllowedCharacterSet +{ + return [OFCharacterSet_URLAllowed URLAllowedCharacterSet]; +} + ++ (OFCharacterSet *)URLPathAllowedCharacterSet +{ + return [OFCharacterSet_URLPathAllowed URLPathAllowedCharacterSet]; +} + ++ (OFCharacterSet *)URLQueryAllowedCharacterSet +{ + return [OFCharacterSet_URLQueryOrFragmentAllowed + URLQueryOrFragmentAllowedCharacterSet]; +} + ++ (OFCharacterSet *)URLFragmentAllowedCharacterSet +{ + return [OFCharacterSet_URLQueryOrFragmentAllowed + URLQueryOrFragmentAllowedCharacterSet]; +} +@end @implementation OFURL + (instancetype)URL { return [[[self alloc] init] autorelease]; @@ -399,21 +646,23 @@ return _scheme; } - (OFString *)URLEncodedScheme { - return [_scheme stringByURLEncoding]; + return [_scheme stringByURLEncodingWithAllowedCharacters: + [OFCharacterSet URLSchemeAllowedCharacterSet]]; } - (OFString *)host { return _host; } - (OFString *)URLEncodedHost { - return [_host stringByURLEncoding]; + return [_host stringByURLEncodingWithAllowedCharacters: + [OFCharacterSet URLHostAllowedCharacterSet]]; } - (OFNumber *)port { return _port; @@ -424,21 +673,23 @@ return _user; } - (OFString *)URLEncodedUser { - return [_user stringByURLEncoding]; + return [_user stringByURLEncodingWithAllowedCharacters: + [OFCharacterSet URLUserAllowedCharacterSet]]; } - (OFString *)password { return _password; } - (OFString *)URLEncodedPassword { - return [_password stringByURLEncoding]; + return [_password stringByURLEncodingWithAllowedCharacters: + [OFCharacterSet URLPasswordAllowedCharacterSet]]; } - (OFString *)path { return _path; @@ -445,11 +696,11 @@ } - (OFString *)URLEncodedPath { return [_path stringByURLEncodingWithAllowedCharacters: - "-._~!$&'()*+,;=:@/"]; + [OFCharacterSet URLPathAllowedCharacterSet]]; } - (OFArray *)pathComponents { return [_path componentsSeparatedByString: @"/"]; @@ -501,11 +752,11 @@ } - (OFString *)URLEncodedQuery { return [_query stringByURLEncodingWithAllowedCharacters: - "-._~!$&'()*+,;=:@/?"]; + [OFCharacterSet URLQueryAllowedCharacterSet]]; } - (OFString *)fragment { return _fragment; @@ -512,11 +763,11 @@ } - (OFString *)URLEncodedFragment { return [_fragment stringByURLEncodingWithAllowedCharacters: - "-._~!$&'()*+,;=:@/?"]; + [OFCharacterSet URLFragmentAllowedCharacterSet]]; } - (id)copy { return [self retain];