Wired Foundation  2.0
A foundation framework for the Wired implementation on Mac OS X
WIURL.m
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
 All Classes