|
Wired Foundation
2.0
A foundation framework for the Wired implementation on Mac OS X
|
00001 /* $Id$ */ 00002 00003 /* 00004 * Copyright (c) 2003-2009 Axel Andersson 00005 * All rights reserved. 00006 * 00007 * Redistribution and use in source and binary forms, with or without 00008 * modification, are permitted provided that the following conditions 00009 * are met: 00010 * 1. Redistributions of source code must retain the above copyright 00011 * notice, this list of conditions and the following disclaimer. 00012 * 2. Redistributions in binary form must reproduce the above copyright 00013 * notice, this list of conditions and the following disclaimer in the 00014 * documentation and/or other materials provided with the distribution. 00015 * 00016 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 00017 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00018 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00019 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 00020 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 00021 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 00022 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00023 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 00024 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00025 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 00026 * POSSIBILITY OF SUCH DAMAGE. 00027 */ 00028 00029 #import <WiredFoundation/NSString-WIFoundation.h> 00030 #import <WiredFoundation/WIMacros.h> 00031 #import <WiredFoundation/WIURL.h> 00032 00033 @interface WIURL(Private) 00034 00035 + (NSDictionary *)_portmap; 00036 00037 @end 00038 00039 00040 @implementation WIURL(Private) 00041 00042 + (NSDictionary *)_portmap { 00043 static NSDictionary *portmap; 00044 00045 if(!portmap) { 00046 portmap = [[NSDictionary alloc] initWithObjectsAndKeys: 00047 [NSNumber numberWithInt:2000], @"wired", 00048 [NSNumber numberWithInt:2002], @"wiredtracker", 00049 [NSNumber numberWithInt:4871], @"wiredp7", 00050 NULL]; 00051 } 00052 00053 return portmap; 00054 } 00055 00056 @end 00057 00058 00059 00060 @implementation WIURL 00061 00062 + (NSInteger)version { 00063 return 1; 00064 } 00065 00066 00067 00068 #pragma mark - 00069 00070 + (id)URLWithString:(NSString *)string { 00071 return [self URLWithString:string scheme:NULL]; 00072 } 00073 00074 00075 00076 + (id)URLWithString:(NSString *)string scheme:(NSString *)defaultScheme { 00077 NSString *scheme, *auth, *user, *password, *path, *query; 00078 WIURL *url; 00079 NSRange range; 00080 00081 string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; 00082 range = [string rangeOfString:@"://"]; 00083 00084 if(range.location == NSNotFound) { 00085 scheme = NULL; 00086 } else { 00087 scheme = [string substringToIndex:range.location]; 00088 string = [string substringFromIndex:range.location + 3]; 00089 } 00090 00091 range = [string rangeOfString:@"://"]; 00092 00093 if(range.location != NSNotFound) 00094 string = [string substringFromIndex:range.location + 3]; 00095 00096 range = [string rangeOfString:@"/"]; 00097 00098 if(range.location == NSNotFound) { 00099 path = NULL; 00100 } else { 00101 path = [string substringFromIndex:range.location]; 00102 string = [string substringToIndex:range.location]; 00103 } 00104 00105 range = [string rangeOfString:@"@"]; 00106 00107 if(range.location == NSNotFound) { 00108 user = NULL; 00109 password = NULL; 00110 } else { 00111 auth = [string substringToIndex:range.location]; 00112 string = [string substringFromIndex:range.location + 1]; 00113 00114 range = [auth rangeOfString:@":"]; 00115 00116 if(range.location == NSNotFound) { 00117 user = auth; 00118 password = NULL; 00119 } else { 00120 user = [auth substringToIndex:range.location]; 00121 password = [auth substringFromIndex:range.location + 1]; 00122 } 00123 } 00124 00125 if(defaultScheme) 00126 scheme = defaultScheme; 00127 00128 if(!scheme) { 00129 if([string hasPrefix:@"www."]) 00130 scheme = @"http"; 00131 else if([string hasPrefix:@"wired."]) 00132 scheme = @"wired"; 00133 } 00134 00135 if(!scheme) 00136 return NULL; 00137 00138 url = [[self alloc] init]; 00139 [url setScheme:scheme]; 00140 [url setHostpair:string]; 00141 [url setUser:user]; 00142 [url setPassword:password]; 00143 00144 if(path) { 00145 range = [path rangeOfString:@"?"]; 00146 00147 if(range.location == NSNotFound) { 00148 [url setPath:path]; 00149 } else { 00150 query = [path substringFromIndex:range.location + 1]; 00151 path = [path substringToIndex:range.location]; 00152 00153 [url setPath:path]; 00154 [url setQuery:query]; 00155 } 00156 } 00157 00158 return [url autorelease]; 00159 } 00160 00161 00162 00163 + (id)URLWithScheme:(NSString *)scheme hostpair:(NSString *)hostpair { 00164 WIURL *url; 00165 00166 url = [[self alloc] init]; 00167 [url setScheme:scheme]; 00168 [url setHostpair:hostpair]; 00169 00170 return [url autorelease]; 00171 } 00172 00173 00174 00175 + (id)URLWithScheme:(NSString *)scheme host:(NSString *)host port:(NSUInteger)port { 00176 return [[[self alloc] initWithScheme:scheme host:host port:port] autorelease]; 00177 } 00178 00179 00180 00181 + (id)URLWithURL:(NSURL *)url { 00182 return [self URLWithString:[url absoluteString]]; 00183 } 00184 00185 00186 00187 + (id)fileURLWithPath:(NSString *)path { 00188 WIURL *url; 00189 00190 url = [self URLWithScheme:@"file" host:NULL port:0]; 00191 [url setPath:path]; 00192 00193 return url; 00194 } 00195 00196 00197 00198 - (id)initWithScheme:(NSString *)scheme host:(NSString *)host port:(NSUInteger)port { 00199 self = [super init]; 00200 00201 _scheme = [scheme retain]; 00202 _host = [host retain]; 00203 _port = port; 00204 00205 return self; 00206 } 00207 00208 00209 00210 - (id)initWithCoder:(NSCoder *)coder { 00211 self = [self init]; 00212 00213 if([coder decodeIntForKey:@"WIURLVersion"] != [[self class] version]) { 00214 [self release]; 00215 00216 return NULL; 00217 } 00218 00219 _scheme = [[coder decodeObjectForKey:@"WIURLScheme"] retain]; 00220 _host = [[coder decodeObjectForKey:@"WIURLHost"] retain]; 00221 _port = [coder decodeIntForKey:@"WIURLPort"]; 00222 _user = [[coder decodeObjectForKey:@"WIURLUser"] retain]; 00223 _password = [[coder decodeObjectForKey:@"WIURLPassword"] retain]; 00224 _path = [[coder decodeObjectForKey:@"WIURLPath"] retain]; 00225 _query = [[coder decodeObjectForKey:@"WIURLQuery"] retain]; 00226 00227 return self; 00228 } 00229 00230 00231 00232 - (void)encodeWithCoder:(NSCoder *)coder { 00233 [coder encodeInt:(int)[[self class] version] forKey:@"WIURLVersion"]; 00234 00235 [coder encodeObject:_scheme forKey:@"WIURLScheme"]; 00236 [coder encodeObject:_host forKey:@"WIURLHost"]; 00237 [coder encodeInt:(int)_port forKey:@"WIURLPort"]; 00238 [coder encodeObject:_user forKey:@"WIURLUser"]; 00239 [coder encodeObject:_password forKey:@"WIURLPassword"]; 00240 [coder encodeObject:_path forKey:@"WIURLPath"]; 00241 [coder encodeObject:_query forKey:@"WIURLQuery"]; 00242 } 00243 00244 00245 00246 - (NSString *)description { 00247 return [self humanReadableString]; 00248 } 00249 00250 00251 00252 - (void)dealloc { 00253 [_scheme release]; 00254 [_host release]; 00255 [_user release]; 00256 [_password release]; 00257 [_path release]; 00258 [_query release]; 00259 00260 [super dealloc]; 00261 } 00262 00263 00264 00265 #pragma mark - 00266 00267 - (id)copyWithZone:(NSZone *)zone { 00268 WIURL *url; 00269 00270 url = [[[self class] allocWithZone:zone] initWithScheme:[self scheme] host:[self host] port:[self port]]; 00271 [url setUser:[self user]]; 00272 [url setPassword:[self password]]; 00273 [url setPath:[self path]]; 00274 [url setQuery:[self query]]; 00275 00276 return url; 00277 } 00278 00279 00280 00281 #pragma mark - 00282 00283 - (NSUInteger)hash { 00284 return [[self string] hash]; 00285 } 00286 00287 00288 00289 - (BOOL)isEqual:(id)url { 00290 return [[self string] isEqualToString:[url string]]; 00291 } 00292 00293 00294 00295 #pragma mark - 00296 00297 - (NSString *)string { 00298 NSMutableString *string; 00299 00300 string = [[NSMutableString alloc] init]; 00301 [string appendString:[[self scheme] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; 00302 [string appendString:@"://"]; 00303 00304 if([[self host] length] > 0) { 00305 if([[self user] length] > 0) { 00306 [string appendString:[[self user] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; 00307 00308 if([[self password] length] > 0) { 00309 [string appendString:@":"]; 00310 [string appendString:[[self password] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; 00311 } 00312 00313 [string appendString:@"@"]; 00314 } 00315 00316 [string appendString:[[self host] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; 00317 00318 if([self port] != 0) 00319 [string appendFormat:@":%lu", [self port]]; 00320 } 00321 00322 if([[self path] length] > 0) 00323 [string appendString:[[self path] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding charactersToLeaveUnescaped:@"#"]]; 00324 00325 if([[self query] length] > 0) 00326 [string appendFormat:@"?%@", [[self query] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]]; 00327 00328 return [string autorelease]; 00329 } 00330 00331 00332 00333 - (NSString *)humanReadableString { 00334 NSMutableString *string; 00335 00336 if([self isFileURL]) 00337 return [self path]; 00338 00339 string = [[NSMutableString alloc] init]; 00340 [string appendFormat:@"%@://", [self scheme]]; 00341 00342 if([[self host] length] > 0) { 00343 if([[self user] length] > 0 && ![[self user] isEqualToString:@"guest"]) 00344 [string appendFormat:@"%@@", [self user]]; 00345 00346 [string appendString:[self hostpair]]; 00347 } 00348 00349 [string appendString:[[self path] length] > 0 ? [self path] : @"/"]; 00350 00351 if([[self query] length] > 0) 00352 [string appendFormat:@"?%@", [self query]]; 00353 00354 return [string autorelease]; 00355 } 00356 00357 00358 00359 - (WIURL *)URLByDeletingLastPathComponent { 00360 WIURL *url; 00361 00362 url = [self copy]; 00363 [url setPath:[[url path] stringByDeletingLastPathComponent]]; 00364 00365 return [url autorelease]; 00366 } 00367 00368 00369 00370 - (NSURL *)URL { 00371 if([self isFileURL]) 00372 return [NSURL fileURLWithPath:[self path]]; 00373 00374 return [NSURL URLWithString:[self string]]; 00375 } 00376 00377 00378 00379 - (BOOL)isFileURL { 00380 return [[self scheme] isEqualToString:@"file"]; 00381 } 00382 00383 00384 00385 #pragma mark - 00386 00387 - (void)setScheme:(NSString *)value { 00388 [value retain]; 00389 [_scheme release]; 00390 00391 _scheme = value; 00392 } 00393 00394 00395 00396 - (NSString *)scheme { 00397 return _scheme; 00398 } 00399 00400 00401 00402 - (void)setHostpair:(NSString *)value { 00403 NSString *host; 00404 NSRange range; 00405 NSUInteger port; 00406 00407 if([value hasPrefix:@"["] && [value containsSubstring:@"]"]) { 00408 value = [value substringFromIndex:1]; 00409 range = [value rangeOfString:@"]" options:NSBackwardsSearch]; 00410 host = [value substringToIndex:range.location]; 00411 port = 0; 00412 00413 if([value containsSubstring:@"]:"]) { 00414 range = [value rangeOfString:@"]:" options:NSBackwardsSearch]; 00415 00416 if(range.location != [value length] - 2) 00417 port = [[value substringFromIndex:range.location + 2] unsignedIntValue]; 00418 } 00419 } 00420 else if([[value componentsSeparatedByString:@":"] count] == 2) { 00421 range = [value rangeOfString:@":" options:NSBackwardsSearch]; 00422 00423 if(range.location == NSNotFound || range.location == 0 || 00424 range.location == [value length] - 1) { 00425 host = value; 00426 port = 0; 00427 } else { 00428 host = [value substringToIndex:range.location]; 00429 port = [[value substringFromIndex:range.location + 1] unsignedIntValue]; 00430 } 00431 } else { 00432 host = value; 00433 port = 0; 00434 } 00435 00436 if(port == 0) 00437 port = [[[WIURL _portmap] objectForKey:_scheme] unsignedIntValue]; 00438 00439 [self setHost:host]; 00440 [self setPort:port]; 00441 } 00442 00443 00444 00445 - (NSString *)hostpair { 00446 if([[[WIURL _portmap] objectForKey:[self scheme]] unsignedIntValue] == [self port]) 00447 return [self host]; 00448 00449 if([[self host] containsSubstring:@":"]) 00450 return [NSSWF:@"[%@]:%lu", [self host], [self port]]; 00451 00452 return [NSSWF:@"%@:%lu", [self host], [self port]]; 00453 } 00454 00455 00456 00457 - (void)setHost:(NSString *)value { 00458 [value retain]; 00459 [_host release]; 00460 00461 _host = value; 00462 } 00463 00464 00465 00466 - (NSString *)host { 00467 return _host; 00468 } 00469 00470 00471 00472 - (void)setPort:(NSUInteger)value { 00473 _port = value; 00474 } 00475 00476 00477 00478 - (NSUInteger)port { 00479 return _port; 00480 } 00481 00482 00483 00484 - (void)setUser:(NSString *)value { 00485 [value retain]; 00486 [_user release]; 00487 00488 _user = value; 00489 } 00490 00491 00492 00493 - (NSString *)user { 00494 return _user; 00495 } 00496 00497 00498 00499 - (void)setPassword:(NSString *)value { 00500 [value retain]; 00501 [_password release]; 00502 00503 _password = value; 00504 } 00505 00506 00507 00508 - (NSString *)password { 00509 return _password; 00510 } 00511 00512 00513 00514 - (void)setPath:(NSString *)value { 00515 [value retain]; 00516 [_path release]; 00517 00518 _path = value; 00519 } 00520 00521 00522 00523 - (NSString *)path { 00524 return _path; 00525 } 00526 00527 00528 00529 - (NSString *)pathExtension { 00530 return [_path pathExtension]; 00531 } 00532 00533 00534 00535 - (NSString *)lastPathComponent { 00536 return [_path lastPathComponent]; 00537 } 00538 00539 00540 00541 - (void)setQuery:(NSString *)value { 00542 [value retain]; 00543 [_query release]; 00544 00545 _query = value; 00546 } 00547 00548 00549 00550 - (NSString *)query { 00551 return _query; 00552 } 00553 00554 00555 00556 - (NSDictionary *)queryParameters { 00557 NSEnumerator *enumerator; 00558 NSMutableDictionary *dictionary; 00559 NSArray *parameters, *sides; 00560 NSString *string; 00561 00562 dictionary = [NSMutableDictionary dictionary]; 00563 parameters = [[self query] componentsSeparatedByCharactersFromSet:[NSCharacterSet characterSetWithCharactersInString:@"&;"]]; 00564 enumerator = [parameters objectEnumerator]; 00565 00566 while((string = [enumerator nextObject])) { 00567 sides = [string componentsSeparatedByString:@"="]; 00568 00569 if([sides count] == 2) 00570 [dictionary setObject:[sides objectAtIndex:1] forKey:[sides objectAtIndex:0]]; 00571 } 00572 00573 return dictionary; 00574 } 00575 00576 @end