2006-06-16 15:21:39 +00:00
|
|
|
|
/** NSURL.m - Class NSURL
|
1999-02-13 00:50:41 +00:00
|
|
|
|
Copyright (C) 1999 Free Software Foundation, Inc.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1999-06-24 19:30:29 +00:00
|
|
|
|
Written by: Manuel Guesdon <mguesdon@sbuilders.com>
|
2001-12-17 14:31:42 +00:00
|
|
|
|
Date: Jan 1999
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
|
Rewrite by: Richard Frith-Macdonald <rfm@gnu.org>
|
|
|
|
|
Date: Jun 2002
|
|
|
|
|
|
1999-02-13 00:50:41 +00:00
|
|
|
|
This file is part of the GNUstep Library.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
1999-02-13 00:50:41 +00:00
|
|
|
|
This library is free software; you can redistribute it and/or
|
2007-09-14 11:36:11 +00:00
|
|
|
|
modify it under the terms of the GNU Lesser General Public
|
1999-02-13 00:50:41 +00:00
|
|
|
|
License as published by the Free Software Foundation; either
|
2008-06-08 10:38:33 +00:00
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
1999-02-13 00:50:41 +00:00
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
Library General Public License for more details.
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2007-09-14 11:36:11 +00:00
|
|
|
|
You should have received a copy of the GNU Lesser General Public
|
1999-02-13 00:50:41 +00:00
|
|
|
|
License along with this library; if not, write to the Free
|
2006-06-06 06:51:26 +00:00
|
|
|
|
Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
|
Boston, MA 02111 USA.
|
2001-12-18 16:54:15 +00:00
|
|
|
|
|
|
|
|
|
<title>NSURL class reference</title>
|
|
|
|
|
$Date$ $Revision$
|
1999-02-13 00:50:41 +00:00
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/*
|
2005-02-22 11:22:44 +00:00
|
|
|
|
Note from Manuel Guesdon:
|
|
|
|
|
* I've made some test to compare apple NSURL results
|
1999-02-13 00:50:41 +00:00
|
|
|
|
and GNUstep NSURL results but as there this class is not very documented, some
|
|
|
|
|
function may be incorrect
|
|
|
|
|
* I've put 2 functions to make tests. You can add your own tests
|
|
|
|
|
* Some functions are not implemented
|
|
|
|
|
*/
|
2010-02-19 08:12:46 +00:00
|
|
|
|
#import "common.h"
|
2010-02-14 10:48:10 +00:00
|
|
|
|
#define EXPOSE_NSURL_IVARS 1
|
2007-11-29 20:53:26 +00:00
|
|
|
|
#import "Foundation/NSArray.h"
|
2007-12-06 10:56:22 +00:00
|
|
|
|
#import "Foundation/NSCoder.h"
|
2010-10-12 10:59:05 +00:00
|
|
|
|
#import "Foundation/NSData.h"
|
2007-11-29 20:53:26 +00:00
|
|
|
|
#import "Foundation/NSDictionary.h"
|
2011-06-04 15:08:37 +00:00
|
|
|
|
#import "Foundation/NSError.h"
|
2007-11-29 20:53:26 +00:00
|
|
|
|
#import "Foundation/NSException.h"
|
|
|
|
|
#import "Foundation/NSFileManager.h"
|
|
|
|
|
#import "Foundation/NSLock.h"
|
|
|
|
|
#import "Foundation/NSMapTable.h"
|
2009-04-27 20:58:17 +00:00
|
|
|
|
#import "Foundation/NSPortCoder.h"
|
2007-11-29 20:53:26 +00:00
|
|
|
|
#import "Foundation/NSRunLoop.h"
|
2007-12-06 10:56:22 +00:00
|
|
|
|
#import "Foundation/NSURL.h"
|
|
|
|
|
#import "Foundation/NSURLHandle.h"
|
2007-11-29 20:53:26 +00:00
|
|
|
|
#import "Foundation/NSValue.h"
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2011-06-17 11:45:28 +00:00
|
|
|
|
#import "GNUstepBase/NSURL+GNUstepBase.h"
|
|
|
|
|
|
|
|
|
|
|
2006-06-16 15:21:39 +00:00
|
|
|
|
NSString * const NSURLErrorDomain = @"NSURLErrorDomain";
|
|
|
|
|
NSString * const NSErrorFailingURLStringKey = @"NSErrorFailingURLStringKey";
|
|
|
|
|
|
2010-10-12 10:59:05 +00:00
|
|
|
|
@interface NSString (NSURLPrivate)
|
|
|
|
|
- (NSString*) _stringByAddingPercentEscapes;
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSString (NSURLPrivate)
|
2011-06-17 11:45:28 +00:00
|
|
|
|
|
2010-10-12 10:59:05 +00:00
|
|
|
|
/* Like the normal percent escape method, but with additional characters
|
2012-02-02 17:12:42 +00:00
|
|
|
|
* escaped (for use by file scheme URLs).
|
2010-10-12 10:59:05 +00:00
|
|
|
|
*/
|
|
|
|
|
- (NSString*) _stringByAddingPercentEscapes
|
|
|
|
|
{
|
|
|
|
|
NSData *data = [self dataUsingEncoding: NSUTF8StringEncoding];
|
|
|
|
|
NSString *s = nil;
|
|
|
|
|
|
|
|
|
|
if (data != nil)
|
|
|
|
|
{
|
|
|
|
|
unsigned char *src = (unsigned char*)[data bytes];
|
|
|
|
|
unsigned int slen = [data length];
|
|
|
|
|
unsigned char *dst;
|
|
|
|
|
unsigned int spos = 0;
|
|
|
|
|
unsigned int dpos = 0;
|
|
|
|
|
|
|
|
|
|
dst = (unsigned char*)NSZoneMalloc(NSDefaultMallocZone(), slen * 3);
|
|
|
|
|
while (spos < slen)
|
|
|
|
|
{
|
|
|
|
|
unsigned char c = src[spos++];
|
|
|
|
|
unsigned int hi;
|
|
|
|
|
unsigned int lo;
|
|
|
|
|
|
|
|
|
|
if (c <= 32
|
|
|
|
|
|| c > 126
|
|
|
|
|
|| c == 34
|
|
|
|
|
|| c == 35
|
|
|
|
|
|| c == 37
|
|
|
|
|
|| c == 59
|
|
|
|
|
|| c == 60
|
|
|
|
|
|| c == 62
|
|
|
|
|
|| c == 63
|
|
|
|
|
|| c == 91
|
|
|
|
|
|| c == 92
|
|
|
|
|
|| c == 93
|
|
|
|
|
|| c == 94
|
|
|
|
|
|| c == 96
|
|
|
|
|
|| c == 123
|
|
|
|
|
|| c == 124
|
|
|
|
|
|| c == 125)
|
|
|
|
|
{
|
|
|
|
|
dst[dpos++] = '%';
|
|
|
|
|
hi = (c & 0xf0) >> 4;
|
|
|
|
|
dst[dpos++] = (hi > 9) ? 'A' + hi - 10 : '0' + hi;
|
|
|
|
|
lo = (c & 0x0f);
|
|
|
|
|
dst[dpos++] = (lo > 9) ? 'A' + lo - 10 : '0' + lo;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
dst[dpos++] = c;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
s = [[NSString alloc] initWithBytes: dst
|
|
|
|
|
length: dpos
|
|
|
|
|
encoding: NSASCIIStringEncoding];
|
|
|
|
|
NSZoneFree(NSDefaultMallocZone(), dst);
|
|
|
|
|
IF_NO_GC([s autorelease];)
|
|
|
|
|
}
|
|
|
|
|
return s;
|
|
|
|
|
}
|
2011-06-17 11:45:28 +00:00
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@interface NSURL (GSPrivate)
|
|
|
|
|
- (NSURL*) _URLBySettingPath: (NSString*)newPath;
|
|
|
|
|
@end
|
|
|
|
|
|
|
|
|
|
@implementation NSURL (GSPrivate)
|
|
|
|
|
|
|
|
|
|
- (NSURL*) _URLBySettingPath: (NSString*)newPath
|
|
|
|
|
{
|
|
|
|
|
if ([self isFileURL])
|
|
|
|
|
{
|
|
|
|
|
return [NSURL fileURLWithPath: newPath];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSURL *u;
|
|
|
|
|
|
|
|
|
|
u = [[NSURL alloc] initWithScheme: [self scheme]
|
|
|
|
|
user: [self user]
|
|
|
|
|
password: [self password]
|
|
|
|
|
host: [self host]
|
|
|
|
|
port: [self port]
|
|
|
|
|
fullPath: newPath
|
|
|
|
|
parameterString: [self parameterString]
|
|
|
|
|
query: [self query]
|
|
|
|
|
fragment: [self fragment]];
|
|
|
|
|
return [u autorelease];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-12 10:59:05 +00:00
|
|
|
|
@end
|
|
|
|
|
|
2002-06-17 10:04:53 +00:00
|
|
|
|
/*
|
|
|
|
|
* Structure describing a URL.
|
|
|
|
|
* All the char* fields may be NULL pointers, except path, which
|
|
|
|
|
* is *always* non-null (though it may be an empty string).
|
|
|
|
|
*/
|
2002-06-05 12:39:28 +00:00
|
|
|
|
typedef struct {
|
2002-06-17 10:04:53 +00:00
|
|
|
|
id absolute; // Cache absolute string or nil
|
2002-06-05 12:39:28 +00:00
|
|
|
|
char *scheme;
|
|
|
|
|
char *user;
|
|
|
|
|
char *password;
|
|
|
|
|
char *host;
|
|
|
|
|
char *port;
|
2002-06-17 10:04:53 +00:00
|
|
|
|
char *path; // May never be NULL
|
2002-06-05 12:39:28 +00:00
|
|
|
|
char *parameters;
|
|
|
|
|
char *query;
|
|
|
|
|
char *fragment;
|
|
|
|
|
BOOL pathIsAbsolute;
|
2002-06-18 06:46:05 +00:00
|
|
|
|
BOOL hasNoPath;
|
2002-06-05 15:42:41 +00:00
|
|
|
|
BOOL isGeneric;
|
2002-08-24 06:00:44 +00:00
|
|
|
|
BOOL isFile;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
} parsedURL;
|
|
|
|
|
|
|
|
|
|
#define myData ((parsedURL*)(self->_data))
|
|
|
|
|
#define baseData ((self->_baseURL == 0)?0:((parsedURL*)(self->_baseURL->_data)))
|
|
|
|
|
|
|
|
|
|
static NSLock *clientsLock = nil;
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
/*
|
|
|
|
|
* Local utility functions.
|
|
|
|
|
*/
|
|
|
|
|
static char *buildURL(parsedURL *base, parsedURL *rel, BOOL standardize);
|
|
|
|
|
static id clientForHandle(void *data, NSURLHandle *hdl);
|
|
|
|
|
static char *findUp(char *str);
|
2008-12-04 09:51:49 +00:00
|
|
|
|
static char *unescape(const char *from, char * to);
|
2002-06-05 12:39:28 +00:00
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Build an absolute URL as a C string
|
|
|
|
|
*/
|
|
|
|
|
static char *buildURL(parsedURL *base, parsedURL *rel, BOOL standardize)
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2011-02-10 10:52:54 +00:00
|
|
|
|
const char *rpath;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
char *buf;
|
|
|
|
|
char *ptr;
|
|
|
|
|
char *tmp;
|
2011-03-07 11:34:17 +00:00
|
|
|
|
int l;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
unsigned int len = 1;
|
1999-09-16 07:21:34 +00:00
|
|
|
|
|
2013-12-21 07:56:33 +00:00
|
|
|
|
if (NO == rel->hasNoPath)
|
|
|
|
|
{
|
|
|
|
|
len += 1; // trailing '/' to be added
|
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if (rel->scheme != 0)
|
|
|
|
|
{
|
|
|
|
|
len += strlen(rel->scheme) + 3; // scheme://
|
|
|
|
|
}
|
2013-12-21 07:56:33 +00:00
|
|
|
|
else if (YES == rel->isGeneric)
|
|
|
|
|
{
|
|
|
|
|
len += 2; // need '//' even if no scheme
|
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if (rel->user != 0)
|
|
|
|
|
{
|
|
|
|
|
len += strlen(rel->user) + 1; // user...@
|
|
|
|
|
}
|
|
|
|
|
if (rel->password != 0)
|
|
|
|
|
{
|
|
|
|
|
len += strlen(rel->password) + 1; // :password
|
|
|
|
|
}
|
|
|
|
|
if (rel->host != 0)
|
|
|
|
|
{
|
|
|
|
|
len += strlen(rel->host) + 1; // host.../
|
|
|
|
|
}
|
|
|
|
|
if (rel->port != 0)
|
|
|
|
|
{
|
|
|
|
|
len += strlen(rel->port) + 1; // :port
|
|
|
|
|
}
|
|
|
|
|
if (rel->path != 0)
|
|
|
|
|
{
|
2011-02-10 10:52:54 +00:00
|
|
|
|
rpath = rel->path;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
2011-02-10 10:52:54 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
rpath = "";
|
|
|
|
|
}
|
|
|
|
|
len += strlen(rpath) + 1; // path
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if (base != 0 && base->path != 0)
|
|
|
|
|
{
|
|
|
|
|
len += strlen(base->path) + 1; // path
|
|
|
|
|
}
|
|
|
|
|
if (rel->parameters != 0)
|
|
|
|
|
{
|
|
|
|
|
len += strlen(rel->parameters) + 1; // ;parameters
|
|
|
|
|
}
|
|
|
|
|
if (rel->query != 0)
|
|
|
|
|
{
|
|
|
|
|
len += strlen(rel->query) + 1; // ?query
|
|
|
|
|
}
|
|
|
|
|
if (rel->fragment != 0)
|
|
|
|
|
{
|
|
|
|
|
len += strlen(rel->fragment) + 1; // #fragment
|
|
|
|
|
}
|
2000-09-22 13:45:58 +00:00
|
|
|
|
|
2009-03-09 15:11:51 +00:00
|
|
|
|
#if GS_WITH_GC
|
|
|
|
|
ptr = buf = (char*)NSAllocateCollectable(len, 0);
|
|
|
|
|
#else
|
|
|
|
|
ptr = buf = (char*)NSZoneMalloc(NSDefaultMallocZone(), len);
|
|
|
|
|
#endif
|
2000-09-22 13:45:58 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if (rel->scheme != 0)
|
|
|
|
|
{
|
2011-03-07 11:34:17 +00:00
|
|
|
|
l = strlen(rel->scheme);
|
|
|
|
|
memcpy(ptr, rel->scheme, l);
|
|
|
|
|
ptr += l;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
*ptr++ = ':';
|
|
|
|
|
}
|
2002-06-05 15:42:41 +00:00
|
|
|
|
if (rel->isGeneric == YES
|
|
|
|
|
|| rel->user != 0 || rel->password != 0 || rel->host != 0 || rel->port != 0)
|
2002-06-05 12:39:28 +00:00
|
|
|
|
{
|
|
|
|
|
*ptr++ = '/';
|
|
|
|
|
*ptr++ = '/';
|
|
|
|
|
if (rel->user != 0 || rel->password != 0)
|
|
|
|
|
{
|
|
|
|
|
if (rel->user != 0)
|
|
|
|
|
{
|
2011-03-07 11:34:17 +00:00
|
|
|
|
l = strlen(rel->user);
|
|
|
|
|
memcpy(ptr, rel->user, l);
|
|
|
|
|
ptr += l;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
if (rel->password != 0)
|
|
|
|
|
{
|
|
|
|
|
*ptr++ = ':';
|
2011-03-07 11:34:17 +00:00
|
|
|
|
l = strlen(rel->password);
|
|
|
|
|
memcpy(ptr, rel->password, l);
|
|
|
|
|
ptr += l;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
if (rel->host != 0 || rel->port != 0)
|
|
|
|
|
{
|
|
|
|
|
*ptr++ = '@';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (rel->host != 0)
|
|
|
|
|
{
|
2011-03-07 11:34:17 +00:00
|
|
|
|
l = strlen(rel->host);
|
|
|
|
|
memcpy(ptr, rel->host, l);
|
|
|
|
|
ptr += l;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
if (rel->port != 0)
|
|
|
|
|
{
|
|
|
|
|
*ptr++ = ':';
|
2011-03-07 11:34:17 +00:00
|
|
|
|
l = strlen(rel->port);
|
|
|
|
|
memcpy(ptr, rel->port, l);
|
|
|
|
|
ptr += l;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
/*
|
|
|
|
|
* Now build path.
|
|
|
|
|
*/
|
1999-09-16 07:21:34 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
tmp = ptr;
|
|
|
|
|
if (rel->pathIsAbsolute == YES)
|
|
|
|
|
{
|
2002-06-18 06:46:05 +00:00
|
|
|
|
if (rel->hasNoPath == NO)
|
|
|
|
|
{
|
|
|
|
|
*tmp++ = '/';
|
|
|
|
|
}
|
2011-03-07 11:34:17 +00:00
|
|
|
|
l = strlen(rpath);
|
|
|
|
|
memcpy(tmp, rpath, l);
|
|
|
|
|
tmp += l;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
else if (base == 0)
|
|
|
|
|
{
|
2011-03-07 11:34:17 +00:00
|
|
|
|
l = strlen(rpath);
|
|
|
|
|
memcpy(tmp, rpath, l);
|
|
|
|
|
tmp += l;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
2011-02-10 10:52:54 +00:00
|
|
|
|
else if (rpath[0] == 0)
|
2002-06-05 12:39:28 +00:00
|
|
|
|
{
|
2002-06-18 06:46:05 +00:00
|
|
|
|
if (base->hasNoPath == NO)
|
|
|
|
|
{
|
|
|
|
|
*tmp++ = '/';
|
|
|
|
|
}
|
2013-04-15 06:04:40 +00:00
|
|
|
|
if (base->path)
|
|
|
|
|
{
|
|
|
|
|
l = strlen(base->path);
|
|
|
|
|
memcpy(tmp, base->path, l);
|
|
|
|
|
tmp += l;
|
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
else
|
2002-06-05 12:39:28 +00:00
|
|
|
|
{
|
|
|
|
|
char *start = base->path;
|
2002-08-24 06:59:30 +00:00
|
|
|
|
char *end = strrchr(start, '/');
|
2000-09-22 13:45:58 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if (end != 0)
|
|
|
|
|
{
|
|
|
|
|
*tmp++ = '/';
|
2011-03-07 11:34:17 +00:00
|
|
|
|
memcpy(tmp, start, end - start);
|
2002-06-05 12:39:28 +00:00
|
|
|
|
tmp += (end - start);
|
|
|
|
|
}
|
|
|
|
|
*tmp++ = '/';
|
2011-03-07 11:34:17 +00:00
|
|
|
|
l = strlen(rpath);
|
|
|
|
|
memcpy(tmp, rpath, l);
|
|
|
|
|
tmp += l;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
2011-03-07 11:34:17 +00:00
|
|
|
|
*tmp = '\0';
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if (standardize == YES)
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Compact '/./' to '/' and strip any trailing '/.'
|
|
|
|
|
*/
|
|
|
|
|
tmp = ptr;
|
|
|
|
|
while (*tmp != '\0')
|
|
|
|
|
{
|
|
|
|
|
if (tmp[0] == '/' && tmp[1] == '.'
|
|
|
|
|
&& (tmp[2] == '/' || tmp[2] == '\0'))
|
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Ensure we don't remove the leading '/'
|
|
|
|
|
*/
|
|
|
|
|
if (tmp == ptr && tmp[2] == '\0')
|
|
|
|
|
{
|
|
|
|
|
tmp[1] = '\0';
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2011-03-07 11:34:17 +00:00
|
|
|
|
l = strlen(&tmp[2]) + 1;
|
|
|
|
|
memmove(tmp, &tmp[2], l);
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tmp++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Reduce any sequence of '/' characters to a single '/'
|
|
|
|
|
*/
|
|
|
|
|
tmp = ptr;
|
|
|
|
|
while (*tmp != '\0')
|
|
|
|
|
{
|
|
|
|
|
if (tmp[0] == '/' && tmp[1] == '/')
|
|
|
|
|
{
|
2011-03-07 11:34:17 +00:00
|
|
|
|
l = strlen(&tmp[1]) + 1;
|
|
|
|
|
memmove(tmp, &tmp[1], l);
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
tmp++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Reduce any '/something/../' sequence to '/' and a trailing
|
|
|
|
|
* "/something/.." to ""
|
2005-02-22 11:22:44 +00:00
|
|
|
|
*/
|
2002-06-05 12:39:28 +00:00
|
|
|
|
tmp = ptr;
|
|
|
|
|
while ((tmp = findUp(tmp)) != 0)
|
|
|
|
|
{
|
|
|
|
|
char *next = &tmp[3];
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
while (tmp > ptr)
|
|
|
|
|
{
|
|
|
|
|
if (*--tmp == '/')
|
|
|
|
|
{
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
* Ensure we don't remove the leading '/'
|
|
|
|
|
*/
|
|
|
|
|
if (tmp == ptr && *next == '\0')
|
|
|
|
|
{
|
|
|
|
|
tmp[1] = '\0';
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2011-03-07 11:34:17 +00:00
|
|
|
|
l = strlen(next) + 1;
|
|
|
|
|
memmove(tmp, next, l);
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2002-06-18 06:46:05 +00:00
|
|
|
|
/*
|
|
|
|
|
* if we have an empty path, we standardize to a single slash.
|
|
|
|
|
*/
|
|
|
|
|
tmp = ptr;
|
|
|
|
|
if (*tmp == '\0')
|
|
|
|
|
{
|
2011-03-07 11:34:17 +00:00
|
|
|
|
memcpy(tmp, "/", 2);
|
2002-06-18 06:46:05 +00:00
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
ptr = &ptr[strlen(ptr)];
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if (rel->parameters != 0)
|
|
|
|
|
{
|
|
|
|
|
*ptr++ = ';';
|
2011-03-07 11:34:17 +00:00
|
|
|
|
l = strlen(rel->parameters);
|
|
|
|
|
memcpy(ptr, rel->parameters, l);
|
|
|
|
|
ptr += l;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
if (rel->query != 0)
|
|
|
|
|
{
|
|
|
|
|
*ptr++ = '?';
|
2011-03-07 11:34:17 +00:00
|
|
|
|
l = strlen(rel->query);
|
|
|
|
|
memcpy(ptr, rel->query, l);
|
|
|
|
|
ptr += l;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
if (rel->fragment != 0)
|
|
|
|
|
{
|
|
|
|
|
*ptr++ = '#';
|
2011-03-07 11:34:17 +00:00
|
|
|
|
l = strlen(rel->fragment);
|
|
|
|
|
memcpy(ptr, rel->fragment, l);
|
|
|
|
|
ptr += l;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
2011-03-07 11:34:17 +00:00
|
|
|
|
*ptr = '\0';
|
2002-06-05 12:39:28 +00:00
|
|
|
|
return buf;
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
static id clientForHandle(void *data, NSURLHandle *hdl)
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
id client = nil;
|
|
|
|
|
|
|
|
|
|
if (data != 0)
|
|
|
|
|
{
|
|
|
|
|
[clientsLock lock];
|
|
|
|
|
client = (id)NSMapGet((NSMapTable*)data, hdl);
|
|
|
|
|
[clientsLock unlock];
|
|
|
|
|
}
|
|
|
|
|
return client;
|
1999-02-13 00:50:41 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
/**
|
2005-02-22 11:22:44 +00:00
|
|
|
|
* Locate a '/../ or trailing '/..'
|
2002-06-05 12:39:28 +00:00
|
|
|
|
*/
|
|
|
|
|
static char *findUp(char *str)
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
while (*str != '\0')
|
|
|
|
|
{
|
|
|
|
|
if (str[0] == '/' && str[1] == '.' && str[2] == '.'
|
|
|
|
|
&& (str[3] == '/' || str[3] == '\0'))
|
|
|
|
|
{
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
str++;
|
|
|
|
|
}
|
|
|
|
|
return 0;
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-18 06:46:05 +00:00
|
|
|
|
/*
|
|
|
|
|
* Check a string to see if it contains only legal data characters
|
|
|
|
|
* or percent escape sequences.
|
|
|
|
|
*/
|
|
|
|
|
static BOOL legal(const char *str, const char *extras)
|
|
|
|
|
{
|
|
|
|
|
const char *mark = "-_.!~*'()";
|
|
|
|
|
|
|
|
|
|
if (str != 0)
|
|
|
|
|
{
|
|
|
|
|
while (*str != 0)
|
|
|
|
|
{
|
|
|
|
|
if (*str == '%' && isxdigit(str[1]) && isxdigit(str[2]))
|
|
|
|
|
{
|
|
|
|
|
str += 3;
|
|
|
|
|
}
|
|
|
|
|
else if (isalnum(*str))
|
|
|
|
|
{
|
|
|
|
|
str++;
|
|
|
|
|
}
|
|
|
|
|
else if (strchr(mark, *str) != 0)
|
|
|
|
|
{
|
|
|
|
|
str++;
|
|
|
|
|
}
|
|
|
|
|
else if (strchr(extras, *str) != 0)
|
|
|
|
|
{
|
|
|
|
|
str++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return YES;
|
|
|
|
|
}
|
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
/*
|
|
|
|
|
* Convert percent escape sequences to individual characters.
|
|
|
|
|
*/
|
2008-12-04 09:51:49 +00:00
|
|
|
|
static char *unescape(const char *from, char * to)
|
2002-05-02 06:10:51 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
while (*from != '\0')
|
|
|
|
|
{
|
|
|
|
|
if (*from == '%')
|
|
|
|
|
{
|
|
|
|
|
unsigned char c;
|
2002-05-02 06:10:51 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
from++;
|
|
|
|
|
if (isxdigit(*from))
|
|
|
|
|
{
|
|
|
|
|
if (*from <= '9')
|
|
|
|
|
{
|
|
|
|
|
c = *from - '0';
|
|
|
|
|
}
|
2006-04-27 09:49:13 +00:00
|
|
|
|
else if (*from <= 'F')
|
2002-06-05 12:39:28 +00:00
|
|
|
|
{
|
|
|
|
|
c = *from - 'A' + 10;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
c = *from - 'a' + 10;
|
|
|
|
|
}
|
|
|
|
|
from++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2003-07-28 16:44:24 +00:00
|
|
|
|
c = 0; // Avoid compiler warning
|
2002-06-05 12:39:28 +00:00
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
|
format: @"Bad percent escape sequence in URL string"];
|
|
|
|
|
}
|
|
|
|
|
c <<= 4;
|
|
|
|
|
if (isxdigit(*from))
|
|
|
|
|
{
|
|
|
|
|
if (*from <= '9')
|
|
|
|
|
{
|
|
|
|
|
c |= *from - '0';
|
|
|
|
|
}
|
2006-04-27 09:49:13 +00:00
|
|
|
|
else if (*from <= 'F')
|
2002-06-05 12:39:28 +00:00
|
|
|
|
{
|
|
|
|
|
c |= *from - 'A' + 10;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
c |= *from - 'a' + 10;
|
|
|
|
|
}
|
|
|
|
|
from++;
|
|
|
|
|
*to++ = c;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSGenericException
|
|
|
|
|
format: @"Bad percent escape sequence in URL string"];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
*to++ = *from++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
*to = '\0';
|
2008-12-04 09:51:49 +00:00
|
|
|
|
return to;
|
2002-05-02 06:10:51 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
@implementation NSURL
|
2002-05-02 06:10:51 +00:00
|
|
|
|
|
2011-05-12 16:03:08 +00:00
|
|
|
|
static NSUInteger urlAlign;
|
2003-04-09 09:23:10 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
+ (id) fileURLWithPath: (NSString*)aPath
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
return AUTORELEASE([[NSURL alloc] initFileURLWithPath: aPath]);
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2011-06-18 07:09:28 +00:00
|
|
|
|
+ (NSURL*) fileURLWithPathComponents: (NSArray*)components
|
|
|
|
|
{
|
|
|
|
|
return [self fileURLWithPath: [NSString pathWithComponents: components]];
|
|
|
|
|
}
|
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
+ (void) initialize
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if (clientsLock == nil)
|
2002-05-02 06:10:51 +00:00
|
|
|
|
{
|
2011-05-12 16:03:08 +00:00
|
|
|
|
NSGetSizeAndAlignment(@encode(parsedURL), &urlAlign, 0);
|
2002-06-05 12:39:28 +00:00
|
|
|
|
clientsLock = [NSLock new];
|
2013-08-22 15:44:54 +00:00
|
|
|
|
[[NSObject leakAt: &clientsLock] release];
|
2002-05-02 06:10:51 +00:00
|
|
|
|
}
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
+ (id) URLWithString: (NSString*)aUrlString
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
return AUTORELEASE([[NSURL alloc] initWithString: aUrlString]);
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
+ (id) URLWithString: (NSString*)aUrlString
|
|
|
|
|
relativeToURL: (NSURL*)aBaseUrl
|
|
|
|
|
{
|
|
|
|
|
return AUTORELEASE([[NSURL alloc] initWithString: aUrlString
|
|
|
|
|
relativeToURL: aBaseUrl]);
|
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2011-06-17 11:45:28 +00:00
|
|
|
|
- (id) initFileURLWithPath: (NSString*)aPath
|
|
|
|
|
{
|
|
|
|
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
|
|
|
|
BOOL flag = NO;
|
|
|
|
|
|
2011-10-04 05:40:29 +00:00
|
|
|
|
if (nil == aPath)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ %@] nil string parameter",
|
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
|
|
|
|
}
|
2011-06-17 11:45:28 +00:00
|
|
|
|
if ([aPath isAbsolutePath] == NO)
|
|
|
|
|
{
|
|
|
|
|
aPath = [[mgr currentDirectoryPath]
|
|
|
|
|
stringByAppendingPathComponent: aPath];
|
|
|
|
|
}
|
|
|
|
|
if ([mgr fileExistsAtPath: aPath isDirectory: &flag] == YES)
|
|
|
|
|
{
|
|
|
|
|
if ([aPath isAbsolutePath] == NO)
|
|
|
|
|
{
|
|
|
|
|
aPath = [aPath stringByStandardizingPath];
|
|
|
|
|
}
|
|
|
|
|
if (flag == YES && [aPath hasSuffix: @"/"] == NO)
|
|
|
|
|
{
|
|
|
|
|
aPath = [aPath stringByAppendingString: @"/"];
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
self = [self initWithScheme: NSURLFileScheme
|
|
|
|
|
host: @"localhost"
|
|
|
|
|
path: aPath];
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-17 13:47:24 +00:00
|
|
|
|
- (id) initFileURLWithPath: (NSString*)aPath isDirectory: (BOOL)isDir
|
|
|
|
|
{
|
|
|
|
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
|
|
|
|
BOOL flag = NO;
|
|
|
|
|
|
2011-10-04 05:40:29 +00:00
|
|
|
|
if (nil == aPath)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ %@] nil string parameter",
|
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
|
|
|
|
}
|
2011-06-17 13:47:24 +00:00
|
|
|
|
if ([aPath isAbsolutePath] == NO)
|
|
|
|
|
{
|
|
|
|
|
aPath = [[mgr currentDirectoryPath]
|
|
|
|
|
stringByAppendingPathComponent: aPath];
|
|
|
|
|
}
|
|
|
|
|
if ([mgr fileExistsAtPath: aPath isDirectory: &flag] == YES)
|
|
|
|
|
{
|
|
|
|
|
if ([aPath isAbsolutePath] == NO)
|
|
|
|
|
{
|
|
|
|
|
aPath = [aPath stringByStandardizingPath];
|
|
|
|
|
}
|
|
|
|
|
isDir = flag;
|
|
|
|
|
}
|
|
|
|
|
if (isDir == YES && [aPath hasSuffix: @"/"] == NO)
|
|
|
|
|
{
|
|
|
|
|
aPath = [aPath stringByAppendingString: @"/"];
|
|
|
|
|
}
|
|
|
|
|
self = [self initWithScheme: NSURLFileScheme
|
|
|
|
|
host: @"localhost"
|
|
|
|
|
path: aPath];
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (id) initWithScheme: (NSString*)aScheme
|
|
|
|
|
host: (NSString*)aHost
|
|
|
|
|
path: (NSString*)aPath
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
NSString *aUrlString = [NSString alloc];
|
2000-09-22 13:45:58 +00:00
|
|
|
|
|
2012-02-02 17:12:42 +00:00
|
|
|
|
if ([aScheme isEqualToString: @"file"])
|
|
|
|
|
{
|
|
|
|
|
aPath = [aPath _stringByAddingPercentEscapes];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
aPath = [aPath
|
|
|
|
|
stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding];
|
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if ([aHost length] > 0)
|
1999-09-16 07:21:34 +00:00
|
|
|
|
{
|
2008-12-14 19:03:58 +00:00
|
|
|
|
NSRange r = [aHost rangeOfString: @"@"];
|
|
|
|
|
NSString *auth = nil;
|
|
|
|
|
|
|
|
|
|
/* Allow for authentication (username:password) before actual host.
|
|
|
|
|
*/
|
|
|
|
|
if (r.length > 0)
|
|
|
|
|
{
|
|
|
|
|
auth = [aHost substringToIndex: r.location];
|
|
|
|
|
aHost = [aHost substringFromIndex: NSMaxRange(r)];
|
|
|
|
|
}
|
|
|
|
|
|
2008-12-04 09:51:49 +00:00
|
|
|
|
/* Add square brackets around ipv6 address if necessary
|
|
|
|
|
*/
|
2008-12-14 18:04:01 +00:00
|
|
|
|
if ([[aHost componentsSeparatedByString: @":"] count] > 2
|
2008-12-04 09:51:49 +00:00
|
|
|
|
&& [aHost hasPrefix: @"["] == NO)
|
|
|
|
|
{
|
|
|
|
|
aHost = [NSString stringWithFormat: @"[%@]", aHost];
|
|
|
|
|
}
|
2008-12-14 19:03:58 +00:00
|
|
|
|
|
|
|
|
|
if (auth != nil)
|
|
|
|
|
{
|
|
|
|
|
aHost = [NSString stringWithFormat: @"%@@%@", auth, aHost];
|
|
|
|
|
}
|
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if ([aPath length] > 0)
|
|
|
|
|
{
|
2003-01-16 15:09:18 +00:00
|
|
|
|
/*
|
|
|
|
|
* For MacOS-X compatibility, assume a path component with
|
|
|
|
|
* a leading slash is intended to have that slash separating
|
|
|
|
|
* the host from the path as specified in the RFC1738
|
|
|
|
|
*/
|
|
|
|
|
if ([aPath hasPrefix: @"/"] == YES)
|
|
|
|
|
{
|
|
|
|
|
aUrlString = [aUrlString initWithFormat: @"%@://%@%@",
|
|
|
|
|
aScheme, aHost, aPath];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
aUrlString = [aUrlString initWithFormat: @"%@://%@/%@",
|
|
|
|
|
aScheme, aHost, aPath];
|
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
else
|
2002-06-05 12:39:28 +00:00
|
|
|
|
{
|
|
|
|
|
aUrlString = [aUrlString initWithFormat: @"%@://%@/",
|
|
|
|
|
aScheme, aHost];
|
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
else
|
2002-04-21 05:25:54 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if ([aPath length] > 0)
|
|
|
|
|
{
|
|
|
|
|
aUrlString = [aUrlString initWithFormat: @"%@:%@",
|
|
|
|
|
aScheme, aPath];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
aUrlString = [aUrlString initWithFormat: @"%@:",
|
|
|
|
|
aScheme];
|
|
|
|
|
}
|
2002-04-21 05:25:54 +00:00
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
self = [self initWithString: aUrlString relativeToURL: nil];
|
|
|
|
|
RELEASE(aUrlString);
|
|
|
|
|
return self;
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (id) initWithString: (NSString*)aUrlString
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
self = [self initWithString: aUrlString relativeToURL: nil];
|
|
|
|
|
return self;
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (id) initWithString: (NSString*)aUrlString
|
|
|
|
|
relativeToURL: (NSURL*)aBaseUrl
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2007-01-17 09:40:24 +00:00
|
|
|
|
/* RFC 2396 'reserved' characters ...
|
2008-12-04 09:51:49 +00:00
|
|
|
|
* as modified by RFC2732
|
2010-10-01 07:13:31 +00:00
|
|
|
|
* static const char *reserved = ";/?:@&=+$,[]";
|
2007-01-17 09:40:24 +00:00
|
|
|
|
*/
|
2010-10-01 07:13:31 +00:00
|
|
|
|
/* Same as reserved set but allow the hash character in a path too.
|
|
|
|
|
*/
|
|
|
|
|
static const char *filepath = ";/?:@&=+$,[]#";
|
2007-01-17 09:40:24 +00:00
|
|
|
|
|
2008-11-18 09:19:44 +00:00
|
|
|
|
if ([aUrlString isKindOfClass: [NSString class]] == NO)
|
2000-09-22 13:45:58 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
2011-11-24 14:46:06 +00:00
|
|
|
|
format: @"[%@ %@] bad string parameter",
|
2002-06-05 12:39:28 +00:00
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
2000-09-22 13:45:58 +00:00
|
|
|
|
}
|
2008-11-18 09:19:44 +00:00
|
|
|
|
if (aBaseUrl != nil
|
|
|
|
|
&& [aBaseUrl isKindOfClass: [NSURL class]] == NO)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ %@] bad base URL parameter",
|
|
|
|
|
NSStringFromClass([self class]), NSStringFromSelector(_cmd)];
|
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
ASSIGNCOPY(_urlString, aUrlString);
|
|
|
|
|
ASSIGN(_baseURL, [aBaseUrl absoluteURL]);
|
|
|
|
|
NS_DURING
|
2000-09-22 13:45:58 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
parsedURL *buf;
|
|
|
|
|
parsedURL *base = baseData;
|
2006-02-27 09:35:19 +00:00
|
|
|
|
unsigned size = [_urlString length];
|
2002-06-05 12:39:28 +00:00
|
|
|
|
char *end;
|
|
|
|
|
char *start;
|
|
|
|
|
char *ptr;
|
|
|
|
|
BOOL usesFragments = YES;
|
|
|
|
|
BOOL usesParameters = YES;
|
|
|
|
|
BOOL usesQueries = YES;
|
2002-06-05 15:42:41 +00:00
|
|
|
|
BOOL canBeGeneric = YES;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
|
2003-04-09 09:23:10 +00:00
|
|
|
|
size += sizeof(parsedURL) + urlAlign + 1;
|
2009-03-09 15:11:51 +00:00
|
|
|
|
#if GS_WITH_GC
|
|
|
|
|
buf = _data = (parsedURL*)NSAllocateCollectable(size, 0);
|
|
|
|
|
#else
|
|
|
|
|
buf = _data = (parsedURL*)NSZoneMalloc(NSDefaultMallocZone(), size);
|
|
|
|
|
#endif
|
2002-06-05 12:39:28 +00:00
|
|
|
|
memset(buf, '\0', size);
|
|
|
|
|
start = end = ptr = (char*)&buf[1];
|
2006-02-27 09:35:19 +00:00
|
|
|
|
[_urlString getCString: start
|
|
|
|
|
maxLength: size
|
|
|
|
|
encoding: NSASCIIStringEncoding];
|
2002-06-05 12:39:28 +00:00
|
|
|
|
|
2000-09-22 13:45:58 +00:00
|
|
|
|
/*
|
2002-06-05 12:39:28 +00:00
|
|
|
|
* Parse the scheme if possible.
|
2000-09-22 13:45:58 +00:00
|
|
|
|
*/
|
2002-06-05 12:39:28 +00:00
|
|
|
|
ptr = start;
|
|
|
|
|
if (isalpha(*ptr))
|
2000-09-22 13:45:58 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
ptr++;
|
|
|
|
|
while (isalnum(*ptr) || *ptr == '+' || *ptr == '-' || *ptr == '.')
|
|
|
|
|
{
|
|
|
|
|
ptr++;
|
|
|
|
|
}
|
|
|
|
|
if (*ptr == ':')
|
|
|
|
|
{
|
|
|
|
|
buf->scheme = start; // Got scheme.
|
|
|
|
|
*ptr = '\0'; // Terminate it.
|
|
|
|
|
end = &ptr[1];
|
|
|
|
|
/*
|
2002-08-23 20:57:42 +00:00
|
|
|
|
* Standardise uppercase to lower.
|
2002-06-05 12:39:28 +00:00
|
|
|
|
*/
|
|
|
|
|
while (--ptr > start)
|
|
|
|
|
{
|
|
|
|
|
if (isupper(*ptr))
|
|
|
|
|
{
|
|
|
|
|
*ptr = tolower(*ptr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-09-22 13:45:58 +00:00
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
start = end;
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2013-02-10 06:24:56 +00:00
|
|
|
|
if (buf->scheme != 0 && base != 0
|
|
|
|
|
&& 0 != strcmp(buf->scheme, base->scheme))
|
|
|
|
|
{
|
|
|
|
|
/* The relative URL is of a different scheme to the base ...
|
|
|
|
|
* so it's actually an absolute URL without a base.
|
|
|
|
|
*/
|
|
|
|
|
DESTROY(_baseURL);
|
|
|
|
|
base = 0;
|
|
|
|
|
}
|
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if (buf->scheme == 0 && base != 0)
|
|
|
|
|
{
|
|
|
|
|
buf->scheme = base->scheme;
|
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
|
2000-09-22 13:45:58 +00:00
|
|
|
|
/*
|
2002-06-05 12:39:28 +00:00
|
|
|
|
* Set up scheme specific parsing options.
|
2000-09-22 13:45:58 +00:00
|
|
|
|
*/
|
2009-09-23 10:07:13 +00:00
|
|
|
|
if (buf->scheme != 0)
|
2006-12-05 14:20:55 +00:00
|
|
|
|
{
|
2009-09-23 10:07:13 +00:00
|
|
|
|
if (strcmp(buf->scheme, "file") == 0)
|
|
|
|
|
{
|
|
|
|
|
buf->isFile = YES;
|
|
|
|
|
}
|
2013-02-16 08:02:44 +00:00
|
|
|
|
else if (strcmp(buf->scheme, "data") == 0)
|
|
|
|
|
{
|
|
|
|
|
canBeGeneric = NO;
|
|
|
|
|
DESTROY(_baseURL);
|
|
|
|
|
base = 0;
|
|
|
|
|
}
|
|
|
|
|
else if (strcmp(buf->scheme, "mailto") == 0)
|
2009-09-23 10:07:13 +00:00
|
|
|
|
{
|
|
|
|
|
usesFragments = NO;
|
|
|
|
|
usesParameters = NO;
|
|
|
|
|
usesQueries = NO;
|
|
|
|
|
}
|
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
|
2002-06-05 15:42:41 +00:00
|
|
|
|
if (canBeGeneric == YES)
|
2000-09-22 13:45:58 +00:00
|
|
|
|
{
|
2002-06-05 15:42:41 +00:00
|
|
|
|
/*
|
|
|
|
|
* Parse the 'authority'
|
|
|
|
|
* //user:password@host:port
|
|
|
|
|
*/
|
|
|
|
|
if (start[0] == '/' && start[1] == '/')
|
2002-06-05 12:39:28 +00:00
|
|
|
|
{
|
2002-06-05 15:42:41 +00:00
|
|
|
|
buf->isGeneric = YES;
|
|
|
|
|
start = end = &end[2];
|
2002-06-18 06:46:05 +00:00
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Set 'end' to point to the start of the path, or just past
|
|
|
|
|
* the 'authority' if there is no path.
|
|
|
|
|
*/
|
2002-06-05 12:39:28 +00:00
|
|
|
|
end = strchr(start, '/');
|
2002-06-18 06:46:05 +00:00
|
|
|
|
if (end == 0)
|
|
|
|
|
{
|
|
|
|
|
buf->hasNoPath = YES;
|
|
|
|
|
end = &start[strlen(start)];
|
|
|
|
|
}
|
|
|
|
|
else
|
2002-06-05 12:39:28 +00:00
|
|
|
|
{
|
|
|
|
|
*end++ = '\0';
|
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
/*
|
|
|
|
|
* Parser username:password part
|
|
|
|
|
*/
|
|
|
|
|
ptr = strchr(start, '@');
|
|
|
|
|
if (ptr != 0)
|
|
|
|
|
{
|
|
|
|
|
buf->user = start;
|
|
|
|
|
*ptr++ = '\0';
|
|
|
|
|
start = ptr;
|
2002-06-18 06:46:05 +00:00
|
|
|
|
if (legal(buf->user, ";:&=+$,") == NO)
|
|
|
|
|
{
|
2007-12-06 10:56:22 +00:00
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ %@](%@, %@) "
|
|
|
|
|
@"illegal character in user/password part",
|
|
|
|
|
NSStringFromClass([self class]),
|
|
|
|
|
NSStringFromSelector(_cmd),
|
|
|
|
|
aUrlString, aBaseUrl];
|
2002-06-18 06:46:05 +00:00
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
ptr = strchr(buf->user, ':');
|
|
|
|
|
if (ptr != 0)
|
|
|
|
|
{
|
|
|
|
|
*ptr++ = '\0';
|
|
|
|
|
buf->password = ptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
/*
|
|
|
|
|
* Parse host:port part
|
|
|
|
|
*/
|
|
|
|
|
buf->host = start;
|
2008-12-04 09:51:49 +00:00
|
|
|
|
if (*start == '[')
|
|
|
|
|
{
|
|
|
|
|
ptr = strchr(buf->host, ']');
|
|
|
|
|
if (ptr == 0)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ %@](%@, %@) "
|
|
|
|
|
@"illegal ipv6 host address",
|
|
|
|
|
NSStringFromClass([self class]),
|
|
|
|
|
NSStringFromSelector(_cmd),
|
|
|
|
|
aUrlString, aBaseUrl];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ptr = start + 1;
|
|
|
|
|
while (*ptr != ']')
|
|
|
|
|
{
|
|
|
|
|
if (*ptr != ':' && *ptr != '.' && !isxdigit(*ptr))
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ %@](%@, %@) "
|
|
|
|
|
@"illegal ipv6 host address",
|
|
|
|
|
NSStringFromClass([self class]),
|
|
|
|
|
NSStringFromSelector(_cmd),
|
|
|
|
|
aUrlString, aBaseUrl];
|
|
|
|
|
}
|
|
|
|
|
ptr++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
ptr = strchr(ptr, ':');
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
ptr = strchr(buf->host, ':');
|
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if (ptr != 0)
|
|
|
|
|
{
|
2002-06-18 06:46:05 +00:00
|
|
|
|
const char *str;
|
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
*ptr++ = '\0';
|
|
|
|
|
buf->port = ptr;
|
2002-06-18 06:46:05 +00:00
|
|
|
|
str = buf->port;
|
|
|
|
|
while (*str != 0)
|
|
|
|
|
{
|
|
|
|
|
if (*str == '%' && isxdigit(str[1]) && isxdigit(str[2]))
|
|
|
|
|
{
|
|
|
|
|
unsigned char c;
|
|
|
|
|
|
|
|
|
|
str++;
|
|
|
|
|
if (*str <= '9')
|
|
|
|
|
{
|
|
|
|
|
c = *str - '0';
|
|
|
|
|
}
|
2012-03-02 07:07:43 +00:00
|
|
|
|
else if (*str <= 'F')
|
2002-06-18 06:46:05 +00:00
|
|
|
|
{
|
|
|
|
|
c = *str - 'A' + 10;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
c = *str - 'a' + 10;
|
|
|
|
|
}
|
|
|
|
|
c <<= 4;
|
|
|
|
|
str++;
|
|
|
|
|
if (*str <= '9')
|
|
|
|
|
{
|
|
|
|
|
c |= *str - '0';
|
|
|
|
|
}
|
2012-03-02 07:07:43 +00:00
|
|
|
|
else if (*str <= 'F')
|
2002-06-18 06:46:05 +00:00
|
|
|
|
{
|
|
|
|
|
c |= *str - 'A' + 10;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
c |= *str - 'a' + 10;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isdigit(c))
|
|
|
|
|
{
|
|
|
|
|
str++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2007-12-06 10:56:22 +00:00
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ %@](%@, %@) "
|
|
|
|
|
@"illegal port part",
|
|
|
|
|
NSStringFromClass([self class]),
|
|
|
|
|
NSStringFromSelector(_cmd),
|
|
|
|
|
aUrlString, aBaseUrl];
|
2002-06-18 06:46:05 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (isdigit(*str))
|
|
|
|
|
{
|
|
|
|
|
str++;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
2007-12-06 10:56:22 +00:00
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ %@](%@, %@) "
|
|
|
|
|
@"illegal character in port part",
|
|
|
|
|
NSStringFromClass([self class]),
|
|
|
|
|
NSStringFromSelector(_cmd),
|
|
|
|
|
aUrlString, aBaseUrl];
|
2002-06-18 06:46:05 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
start = end;
|
2008-12-04 09:51:49 +00:00
|
|
|
|
/* Check for a legal host, unless it's an ipv6 address
|
|
|
|
|
* (which would have been checked earlier).
|
|
|
|
|
*/
|
|
|
|
|
if (*buf->host != '[' && legal(buf->host, "-") == NO)
|
2002-06-18 06:46:05 +00:00
|
|
|
|
{
|
2007-12-06 10:56:22 +00:00
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ %@](%@, %@) "
|
|
|
|
|
@"illegal character in host part",
|
|
|
|
|
NSStringFromClass([self class]),
|
|
|
|
|
NSStringFromSelector(_cmd),
|
|
|
|
|
aUrlString, aBaseUrl];
|
2002-06-18 06:46:05 +00:00
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
|
2002-06-05 15:42:41 +00:00
|
|
|
|
/*
|
|
|
|
|
* If we have an authority component,
|
|
|
|
|
* this must be an absolute URL
|
|
|
|
|
*/
|
|
|
|
|
buf->pathIsAbsolute = YES;
|
|
|
|
|
base = 0;
|
|
|
|
|
}
|
|
|
|
|
else
|
1999-09-16 07:21:34 +00:00
|
|
|
|
{
|
2002-06-05 15:42:41 +00:00
|
|
|
|
if (base != 0)
|
2002-06-05 12:39:28 +00:00
|
|
|
|
{
|
2002-06-05 15:42:41 +00:00
|
|
|
|
buf->isGeneric = base->isGeneric;
|
|
|
|
|
}
|
|
|
|
|
if (*start == '/')
|
|
|
|
|
{
|
|
|
|
|
buf->pathIsAbsolute = YES;
|
|
|
|
|
start++;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
2000-09-22 13:45:58 +00:00
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
|
2002-06-05 15:42:41 +00:00
|
|
|
|
if (usesFragments == YES)
|
2000-09-22 13:45:58 +00:00
|
|
|
|
{
|
2002-06-05 15:42:41 +00:00
|
|
|
|
/*
|
|
|
|
|
* Strip fragment string from end of url.
|
|
|
|
|
*/
|
|
|
|
|
ptr = strchr(start, '#');
|
|
|
|
|
if (ptr != 0)
|
|
|
|
|
{
|
|
|
|
|
*ptr++ = '\0';
|
|
|
|
|
if (*ptr != 0)
|
|
|
|
|
{
|
|
|
|
|
buf->fragment = ptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (buf->fragment == 0 && base != 0)
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 15:42:41 +00:00
|
|
|
|
buf->fragment = base->fragment;
|
2010-10-13 17:41:22 +00:00
|
|
|
|
}
|
|
|
|
|
if (legal(buf->fragment, filepath) == NO)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ %@](%@, %@) "
|
|
|
|
|
@"illegal character in fragment part",
|
|
|
|
|
NSStringFromClass([self class]),
|
|
|
|
|
NSStringFromSelector(_cmd),
|
|
|
|
|
aUrlString, aBaseUrl];
|
1999-02-13 00:50:41 +00:00
|
|
|
|
}
|
2000-09-22 13:45:58 +00:00
|
|
|
|
}
|
2002-06-05 15:42:41 +00:00
|
|
|
|
|
|
|
|
|
if (usesQueries == YES)
|
2000-09-22 13:45:58 +00:00
|
|
|
|
{
|
2002-06-05 15:42:41 +00:00
|
|
|
|
/*
|
|
|
|
|
* Strip query string from end of url.
|
|
|
|
|
*/
|
|
|
|
|
ptr = strchr(start, '?');
|
|
|
|
|
if (ptr != 0)
|
|
|
|
|
{
|
|
|
|
|
*ptr++ = '\0';
|
|
|
|
|
if (*ptr != 0)
|
|
|
|
|
{
|
|
|
|
|
buf->query = ptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (buf->query == 0 && base != 0)
|
|
|
|
|
{
|
|
|
|
|
buf->query = base->query;
|
2010-10-13 17:41:22 +00:00
|
|
|
|
}
|
|
|
|
|
if (legal(buf->query, filepath) == NO)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ %@](%@, %@) "
|
|
|
|
|
@"illegal character in query part",
|
|
|
|
|
NSStringFromClass([self class]),
|
|
|
|
|
NSStringFromSelector(_cmd),
|
|
|
|
|
aUrlString, aBaseUrl];
|
2002-06-05 15:42:41 +00:00
|
|
|
|
}
|
2000-09-22 13:45:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-06-05 15:42:41 +00:00
|
|
|
|
if (usesParameters == YES)
|
2000-09-22 13:45:58 +00:00
|
|
|
|
{
|
2002-06-05 15:42:41 +00:00
|
|
|
|
/*
|
|
|
|
|
* Strip parameters string from end of url.
|
|
|
|
|
*/
|
|
|
|
|
ptr = strchr(start, ';');
|
|
|
|
|
if (ptr != 0)
|
|
|
|
|
{
|
|
|
|
|
*ptr++ = '\0';
|
|
|
|
|
if (*ptr != 0)
|
|
|
|
|
{
|
|
|
|
|
buf->parameters = ptr;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (buf->parameters == 0 && base != 0)
|
2000-09-22 13:45:58 +00:00
|
|
|
|
{
|
2002-06-05 15:42:41 +00:00
|
|
|
|
buf->parameters = base->parameters;
|
2010-10-13 17:41:22 +00:00
|
|
|
|
}
|
|
|
|
|
if (legal(buf->parameters, filepath) == NO)
|
|
|
|
|
{
|
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ %@](%@, %@) "
|
|
|
|
|
@"illegal character in parameters part",
|
|
|
|
|
NSStringFromClass([self class]),
|
|
|
|
|
NSStringFromSelector(_cmd),
|
|
|
|
|
aUrlString, aBaseUrl];
|
1999-02-13 00:50:41 +00:00
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
}
|
2002-06-05 15:42:41 +00:00
|
|
|
|
|
2002-08-24 06:16:13 +00:00
|
|
|
|
if (buf->isFile == YES)
|
|
|
|
|
{
|
|
|
|
|
buf->user = 0;
|
|
|
|
|
buf->password = 0;
|
2010-10-19 09:29:23 +00:00
|
|
|
|
if (base != 0 && base->host != 0)
|
2010-10-13 17:41:22 +00:00
|
|
|
|
{
|
2010-10-19 09:29:23 +00:00
|
|
|
|
buf->host = base->host;
|
|
|
|
|
}
|
|
|
|
|
else if (buf->host != 0 && *buf->host == 0)
|
|
|
|
|
{
|
|
|
|
|
buf->host = 0;
|
2010-10-13 17:41:22 +00:00
|
|
|
|
}
|
2002-08-24 06:16:13 +00:00
|
|
|
|
buf->port = 0;
|
|
|
|
|
buf->isGeneric = YES;
|
|
|
|
|
}
|
|
|
|
|
else if (base != 0
|
2002-06-05 15:42:41 +00:00
|
|
|
|
&& buf->user == 0 && buf->password == 0
|
|
|
|
|
&& buf->host == 0 && buf->port == 0)
|
2000-09-22 13:45:58 +00:00
|
|
|
|
{
|
2002-06-05 15:42:41 +00:00
|
|
|
|
buf->user = base->user;
|
|
|
|
|
buf->password = base->password;
|
|
|
|
|
buf->host = base->host;
|
|
|
|
|
buf->port = base->port;
|
2000-09-22 13:45:58 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
/*
|
|
|
|
|
* Store the path.
|
|
|
|
|
*/
|
|
|
|
|
buf->path = start;
|
2010-06-08 16:53:30 +00:00
|
|
|
|
if (0 == base && '\0' == *buf->path && NO == buf->pathIsAbsolute)
|
|
|
|
|
{
|
|
|
|
|
buf->hasNoPath = YES;
|
|
|
|
|
}
|
2010-10-01 07:13:31 +00:00
|
|
|
|
if (legal(buf->path, filepath) == NO)
|
2007-01-17 09:40:24 +00:00
|
|
|
|
{
|
2007-12-06 10:56:22 +00:00
|
|
|
|
[NSException raise: NSInvalidArgumentException
|
|
|
|
|
format: @"[%@ %@](%@, %@) "
|
|
|
|
|
@"illegal character in path part",
|
|
|
|
|
NSStringFromClass([self class]),
|
|
|
|
|
NSStringFromSelector(_cmd),
|
|
|
|
|
aUrlString, aBaseUrl];
|
2007-01-17 09:40:24 +00:00
|
|
|
|
}
|
1999-09-16 07:21:34 +00:00
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
NS_HANDLER
|
1999-09-16 07:21:34 +00:00
|
|
|
|
{
|
2007-12-06 10:56:22 +00:00
|
|
|
|
NSDebugLog(@"%@", localException);
|
2002-06-05 12:39:28 +00:00
|
|
|
|
DESTROY(self);
|
1999-09-16 07:21:34 +00:00
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
NS_ENDHANDLER
|
|
|
|
|
return self;
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (void) dealloc
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if (_clients != 0)
|
|
|
|
|
{
|
|
|
|
|
NSFreeMapTable(_clients);
|
|
|
|
|
_clients = 0;
|
|
|
|
|
}
|
|
|
|
|
if (_data != 0)
|
|
|
|
|
{
|
|
|
|
|
DESTROY(myData->absolute);
|
2010-03-05 09:30:18 +00:00
|
|
|
|
NSZoneFree([self zone], _data);
|
2002-06-05 12:39:28 +00:00
|
|
|
|
_data = 0;
|
|
|
|
|
}
|
|
|
|
|
DESTROY(_urlString);
|
|
|
|
|
DESTROY(_baseURL);
|
|
|
|
|
[super dealloc];
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (id) copyWithZone: (NSZone*)zone
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if (NSShouldRetainWithZone(self, zone) == NO)
|
|
|
|
|
{
|
2011-02-20 16:21:43 +00:00
|
|
|
|
return [[[self class] allocWithZone: zone] initWithString: _urlString
|
|
|
|
|
relativeToURL: _baseURL];
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return RETAIN(self);
|
|
|
|
|
}
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (NSString*) description
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
NSString *dscr = _urlString;
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if (_baseURL != nil)
|
|
|
|
|
{
|
|
|
|
|
dscr = [dscr stringByAppendingFormat: @" -- %@", _baseURL];
|
|
|
|
|
}
|
|
|
|
|
return dscr;
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (void) encodeWithCoder: (NSCoder*)aCoder
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2010-06-25 13:38:06 +00:00
|
|
|
|
if ([aCoder allowsKeyedCoding])
|
|
|
|
|
{
|
|
|
|
|
[aCoder encodeObject: _baseURL forKey: @"NS.base"];
|
|
|
|
|
[aCoder encodeObject: _urlString forKey: @"NS.relative"];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
[aCoder encodeObject: _urlString];
|
|
|
|
|
[aCoder encodeObject: _baseURL];
|
|
|
|
|
}
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2009-02-23 20:42:32 +00:00
|
|
|
|
- (NSUInteger) hash
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
return [[self absoluteString] hash];
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (id) initWithCoder: (NSCoder*)aCoder
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
NSURL *base;
|
|
|
|
|
NSString *rel;
|
|
|
|
|
|
2010-06-25 13:38:06 +00:00
|
|
|
|
if ([aCoder allowsKeyedCoding])
|
|
|
|
|
{
|
|
|
|
|
base = [aCoder decodeObjectForKey: @"NS.base"];
|
|
|
|
|
rel = [aCoder decodeObjectForKey: @"NS.relative"];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
rel = [aCoder decodeObject];
|
|
|
|
|
base = [aCoder decodeObject];
|
|
|
|
|
}
|
2010-06-23 07:21:01 +00:00
|
|
|
|
if (nil == rel)
|
|
|
|
|
{
|
|
|
|
|
rel = @"";
|
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
self = [self initWithString: rel relativeToURL: base];
|
|
|
|
|
return self;
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (BOOL) isEqual: (id)other
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if (other == nil || [other isKindOfClass: [NSURL class]] == NO)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
return [[self absoluteString] isEqualToString: [other absoluteString]];
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (NSString*) absoluteString
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
NSString *absString = myData->absolute;
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if (absString == nil)
|
|
|
|
|
{
|
|
|
|
|
char *url = buildURL(baseData, myData, NO);
|
|
|
|
|
unsigned len = strlen(url);
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
absString = [[NSString alloc] initWithCStringNoCopy: url
|
|
|
|
|
length: len
|
|
|
|
|
freeWhenDone: YES];
|
|
|
|
|
myData->absolute = absString;
|
|
|
|
|
}
|
|
|
|
|
return absString;
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (NSURL*) absoluteURL
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2010-10-19 12:56:30 +00:00
|
|
|
|
if (_baseURL == nil)
|
2002-06-05 12:39:28 +00:00
|
|
|
|
{
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return [NSURL URLWithString: [self absoluteString]];
|
|
|
|
|
}
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (NSURL*) baseURL
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
return _baseURL;
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2011-06-04 15:08:37 +00:00
|
|
|
|
- (BOOL) checkResourceIsReachableAndReturnError: (NSError **)error
|
|
|
|
|
{
|
|
|
|
|
NSString *errorStr = nil;
|
|
|
|
|
|
|
|
|
|
if ([self isFileURL])
|
|
|
|
|
{
|
|
|
|
|
NSFileManager *mgr = [NSFileManager defaultManager];
|
|
|
|
|
NSString *path = [self path];
|
|
|
|
|
|
|
|
|
|
if ([mgr fileExistsAtPath: path])
|
|
|
|
|
{
|
|
|
|
|
if (![mgr isReadableFileAtPath: path])
|
|
|
|
|
{
|
|
|
|
|
errorStr = @"File not readable";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
errorStr = @"File does not exist";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
errorStr = @"No file URL";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((errorStr != nil) && (error != NULL))
|
|
|
|
|
{
|
2011-06-17 11:45:28 +00:00
|
|
|
|
NSDictionary *info;
|
|
|
|
|
|
|
|
|
|
info = [NSDictionary dictionaryWithObjectsAndKeys:
|
|
|
|
|
errorStr, NSLocalizedDescriptionKey, nil];
|
2011-06-04 15:08:37 +00:00
|
|
|
|
*error = [NSError errorWithDomain: @"NSURLError"
|
|
|
|
|
code: 0
|
2011-06-17 11:45:28 +00:00
|
|
|
|
userInfo: info];
|
2011-06-04 15:08:37 +00:00
|
|
|
|
}
|
2011-06-17 11:45:28 +00:00
|
|
|
|
return nil == errorStr ? YES : NO;
|
2011-06-04 15:08:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (NSString*) fragment
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
NSString *fragment = nil;
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if (myData->fragment != 0)
|
|
|
|
|
{
|
|
|
|
|
fragment = [NSString stringWithUTF8String: myData->fragment];
|
|
|
|
|
}
|
|
|
|
|
return fragment;
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2012-03-07 08:37:54 +00:00
|
|
|
|
- (char*) _path: (char*)buf withEscapes: (BOOL)withEscapes
|
2009-08-26 16:48:15 +00:00
|
|
|
|
{
|
2011-03-07 11:34:17 +00:00
|
|
|
|
char *ptr = buf;
|
|
|
|
|
char *tmp = buf;
|
|
|
|
|
int l;
|
2009-08-26 16:48:15 +00:00
|
|
|
|
|
|
|
|
|
if (myData->pathIsAbsolute == YES)
|
|
|
|
|
{
|
|
|
|
|
if (myData->hasNoPath == NO)
|
|
|
|
|
{
|
|
|
|
|
*tmp++ = '/';
|
|
|
|
|
}
|
2009-09-23 10:07:13 +00:00
|
|
|
|
if (myData->path != 0)
|
|
|
|
|
{
|
2011-03-07 11:34:17 +00:00
|
|
|
|
l = strlen(myData->path);
|
|
|
|
|
memcpy(tmp, myData->path, l + 1);
|
2009-09-23 10:07:13 +00:00
|
|
|
|
}
|
2009-08-26 16:48:15 +00:00
|
|
|
|
}
|
2013-04-14 09:04:40 +00:00
|
|
|
|
else if (nil == _baseURL)
|
2009-08-26 16:48:15 +00:00
|
|
|
|
{
|
2009-09-23 10:07:13 +00:00
|
|
|
|
if (myData->path != 0)
|
|
|
|
|
{
|
2011-03-07 11:34:17 +00:00
|
|
|
|
l = strlen(myData->path);
|
|
|
|
|
memcpy(tmp, myData->path, l + 1);
|
2009-09-23 10:07:13 +00:00
|
|
|
|
}
|
2009-08-26 16:48:15 +00:00
|
|
|
|
}
|
2013-04-14 09:04:40 +00:00
|
|
|
|
else if (0 == myData->path || 0 == *myData->path)
|
2009-08-26 16:48:15 +00:00
|
|
|
|
{
|
|
|
|
|
if (baseData->hasNoPath == NO)
|
|
|
|
|
{
|
|
|
|
|
*tmp++ = '/';
|
|
|
|
|
}
|
2009-09-23 10:07:13 +00:00
|
|
|
|
if (baseData->path != 0)
|
|
|
|
|
{
|
2011-03-07 11:34:17 +00:00
|
|
|
|
l = strlen(baseData->path);
|
|
|
|
|
memcpy(tmp, baseData->path, l + 1);
|
2009-09-23 10:07:13 +00:00
|
|
|
|
}
|
2009-08-26 16:48:15 +00:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
char *start = baseData->path;
|
2009-09-23 10:07:13 +00:00
|
|
|
|
char *end = (start == 0) ? 0 : strrchr(start, '/');
|
2009-08-26 16:48:15 +00:00
|
|
|
|
|
|
|
|
|
if (end != 0)
|
|
|
|
|
{
|
|
|
|
|
*tmp++ = '/';
|
|
|
|
|
strncpy(tmp, start, end - start);
|
|
|
|
|
tmp += end - start;
|
|
|
|
|
}
|
|
|
|
|
*tmp++ = '/';
|
2009-09-23 10:07:13 +00:00
|
|
|
|
if (myData->path != 0)
|
|
|
|
|
{
|
2011-03-07 11:34:17 +00:00
|
|
|
|
l = strlen(myData->path);
|
|
|
|
|
memcpy(tmp, myData->path, l + 1);
|
2009-09-23 10:07:13 +00:00
|
|
|
|
}
|
2009-08-26 16:48:15 +00:00
|
|
|
|
}
|
|
|
|
|
|
2012-03-07 08:37:54 +00:00
|
|
|
|
if (!withEscapes)
|
|
|
|
|
{
|
|
|
|
|
unescape(buf, buf);
|
|
|
|
|
}
|
2009-08-26 16:48:15 +00:00
|
|
|
|
|
2010-03-19 12:10:11 +00:00
|
|
|
|
#if defined(__MINGW__)
|
2009-08-26 16:48:15 +00:00
|
|
|
|
/* On windows a file URL path may be of the form C:\xxx (ie we should
|
|
|
|
|
* not insert the leading slash).
|
|
|
|
|
* Also the vertical bar symbol may have been used instead of the
|
|
|
|
|
* colon, so we need to convert that.
|
|
|
|
|
*/
|
|
|
|
|
if (myData->isFile == YES)
|
|
|
|
|
{
|
|
|
|
|
if (ptr[1] && isalpha(ptr[1]))
|
|
|
|
|
{
|
|
|
|
|
if (ptr[2] == ':' || ptr[2] == '|')
|
|
|
|
|
{
|
|
|
|
|
if (ptr[3] == '\0' || ptr[3] == '/' || ptr[3] == '\\')
|
|
|
|
|
{
|
|
|
|
|
ptr[2] = ':';
|
|
|
|
|
ptr++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
return ptr;
|
|
|
|
|
}
|
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (NSString*) host
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
NSString *host = nil;
|
|
|
|
|
|
|
|
|
|
if (myData->host != 0)
|
|
|
|
|
{
|
2002-06-17 16:20:21 +00:00
|
|
|
|
char buf[strlen(myData->host)+1];
|
|
|
|
|
|
2008-12-04 09:51:49 +00:00
|
|
|
|
if (*myData->host == '[')
|
|
|
|
|
{
|
|
|
|
|
char *end = unescape(myData->host + 1, buf);
|
|
|
|
|
|
|
|
|
|
if (end[-1] == ']')
|
|
|
|
|
{
|
|
|
|
|
end[-1] = '\0';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
unescape(myData->host, buf);
|
|
|
|
|
}
|
2002-06-17 16:20:21 +00:00
|
|
|
|
host = [NSString stringWithUTF8String: buf];
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
return host;
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (BOOL) isFileURL
|
|
|
|
|
{
|
2002-08-24 06:00:44 +00:00
|
|
|
|
return myData->isFile;
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2011-06-17 11:45:28 +00:00
|
|
|
|
- (NSString*) lastPathComponent
|
|
|
|
|
{
|
|
|
|
|
return [[self path] lastPathComponent];
|
|
|
|
|
}
|
|
|
|
|
|
2000-09-22 13:45:58 +00:00
|
|
|
|
- (void) loadResourceDataNotifyingClient: (id)client
|
|
|
|
|
usingCache: (BOOL)shouldUseCache
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2004-05-12 17:17:53 +00:00
|
|
|
|
NSURLHandle *handle = [self URLHandleUsingCache: YES];
|
|
|
|
|
NSData *d;
|
2005-02-22 11:22:44 +00:00
|
|
|
|
|
2004-05-12 17:17:53 +00:00
|
|
|
|
if (shouldUseCache == YES && (d = [handle availableResourceData]) != nil)
|
2002-06-05 12:39:28 +00:00
|
|
|
|
{
|
2004-05-12 17:17:53 +00:00
|
|
|
|
/*
|
|
|
|
|
* We already have cached data we should use.
|
|
|
|
|
*/
|
|
|
|
|
if ([client respondsToSelector:
|
|
|
|
|
@selector(URL:resourceDataDidBecomeAvailable:)])
|
2002-06-05 12:39:28 +00:00
|
|
|
|
{
|
2004-05-12 17:17:53 +00:00
|
|
|
|
[client URL: self resourceDataDidBecomeAvailable: d];
|
|
|
|
|
}
|
|
|
|
|
if ([client respondsToSelector: @selector(URLResourceDidFinishLoading:)])
|
|
|
|
|
{
|
|
|
|
|
[client URLResourceDidFinishLoading: self];
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2004-05-12 17:17:53 +00:00
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (client != nil)
|
|
|
|
|
{
|
|
|
|
|
[clientsLock lock];
|
|
|
|
|
if (_clients == 0)
|
|
|
|
|
{
|
|
|
|
|
_clients = NSCreateMapTable (NSObjectMapKeyCallBacks,
|
|
|
|
|
NSNonRetainedObjectMapValueCallBacks, 0);
|
|
|
|
|
}
|
|
|
|
|
NSMapInsert((NSMapTable*)_clients, (void*)handle, (void*)client);
|
|
|
|
|
[clientsLock unlock];
|
|
|
|
|
[handle addClient: self];
|
|
|
|
|
}
|
2000-09-22 13:45:58 +00:00
|
|
|
|
|
2004-05-12 17:17:53 +00:00
|
|
|
|
/*
|
|
|
|
|
* Kick off the load process.
|
|
|
|
|
*/
|
|
|
|
|
[handle loadInBackground];
|
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) parameterString
|
|
|
|
|
{
|
|
|
|
|
NSString *parameters = nil;
|
|
|
|
|
|
|
|
|
|
if (myData->parameters != 0)
|
|
|
|
|
{
|
|
|
|
|
parameters = [NSString stringWithUTF8String: myData->parameters];
|
|
|
|
|
}
|
|
|
|
|
return parameters;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) password
|
|
|
|
|
{
|
|
|
|
|
NSString *password = nil;
|
|
|
|
|
|
|
|
|
|
if (myData->password != 0)
|
|
|
|
|
{
|
2002-06-17 16:20:21 +00:00
|
|
|
|
char buf[strlen(myData->password)+1];
|
|
|
|
|
|
|
|
|
|
unescape(myData->password, buf);
|
|
|
|
|
password = [NSString stringWithUTF8String: buf];
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
return password;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-07 08:37:54 +00:00
|
|
|
|
- (NSString*) _pathWithEscapes: (BOOL)withEscapes
|
2002-06-05 12:39:28 +00:00
|
|
|
|
{
|
2002-06-05 15:42:41 +00:00
|
|
|
|
NSString *path = nil;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
|
2012-09-16 07:39:18 +00:00
|
|
|
|
if (YES == myData->isGeneric || 0 == myData->scheme)
|
2009-09-23 10:07:13 +00:00
|
|
|
|
{
|
2012-09-16 07:39:18 +00:00
|
|
|
|
unsigned int len = 3;
|
|
|
|
|
|
|
|
|
|
if (_baseURL != nil)
|
2009-09-24 15:24:24 +00:00
|
|
|
|
{
|
2012-09-16 07:39:18 +00:00
|
|
|
|
if (baseData->path && *baseData->path)
|
|
|
|
|
{
|
|
|
|
|
len += strlen(baseData->path);
|
|
|
|
|
}
|
|
|
|
|
else if (baseData->hasNoPath == NO)
|
|
|
|
|
{
|
|
|
|
|
len++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (myData->path && *myData->path)
|
|
|
|
|
{
|
|
|
|
|
len += strlen(myData->path);
|
|
|
|
|
}
|
|
|
|
|
else if (myData->hasNoPath == NO)
|
|
|
|
|
{
|
|
|
|
|
len++;
|
|
|
|
|
}
|
|
|
|
|
if (len > 3)
|
|
|
|
|
{
|
|
|
|
|
char buf[len];
|
|
|
|
|
char *ptr;
|
|
|
|
|
char *tmp;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
|
2012-09-16 07:39:18 +00:00
|
|
|
|
ptr = [self _path: buf withEscapes: withEscapes];
|
2002-06-05 12:39:28 +00:00
|
|
|
|
|
2012-09-16 07:39:18 +00:00
|
|
|
|
/* Remove any trailing '/' from the path for MacOS-X compatibility.
|
|
|
|
|
*/
|
|
|
|
|
tmp = ptr + strlen(ptr) - 1;
|
|
|
|
|
if (tmp > ptr && *tmp == '/')
|
|
|
|
|
{
|
|
|
|
|
*tmp = '\0';
|
|
|
|
|
}
|
2009-05-16 10:34:22 +00:00
|
|
|
|
|
2012-09-16 07:39:18 +00:00
|
|
|
|
path = [NSString stringWithUTF8String: ptr];
|
|
|
|
|
}
|
2002-06-05 15:42:41 +00:00
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
return path;
|
|
|
|
|
}
|
|
|
|
|
|
2012-03-07 08:37:54 +00:00
|
|
|
|
- (NSString*) path
|
|
|
|
|
{
|
|
|
|
|
return [self _pathWithEscapes: NO];
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-18 07:09:28 +00:00
|
|
|
|
- (NSArray*) pathComponents
|
|
|
|
|
{
|
|
|
|
|
return [[self path] pathComponents];
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-17 11:45:28 +00:00
|
|
|
|
- (NSString*) pathExtension
|
|
|
|
|
{
|
|
|
|
|
return [[self path] pathExtension];
|
|
|
|
|
}
|
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (NSNumber*) port
|
|
|
|
|
{
|
|
|
|
|
NSNumber *port = nil;
|
|
|
|
|
|
|
|
|
|
if (myData->port != 0)
|
|
|
|
|
{
|
2002-06-17 16:20:21 +00:00
|
|
|
|
char buf[strlen(myData->port)+1];
|
|
|
|
|
|
|
|
|
|
unescape(myData->port, buf);
|
|
|
|
|
port = [NSNumber numberWithUnsignedShort: atol(buf)];
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
return port;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (id) propertyForKey: (NSString*)propertyKey
|
|
|
|
|
{
|
|
|
|
|
NSURLHandle *handle = [self URLHandleUsingCache: YES];
|
|
|
|
|
|
|
|
|
|
return [handle propertyForKey: propertyKey];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) query
|
|
|
|
|
{
|
|
|
|
|
NSString *query = nil;
|
|
|
|
|
|
|
|
|
|
if (myData->query != 0)
|
|
|
|
|
{
|
|
|
|
|
query = [NSString stringWithUTF8String: myData->query];
|
|
|
|
|
}
|
|
|
|
|
return query;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) relativePath
|
|
|
|
|
{
|
2010-10-13 17:41:22 +00:00
|
|
|
|
if (nil == _baseURL)
|
2002-06-05 12:39:28 +00:00
|
|
|
|
{
|
2010-10-13 17:41:22 +00:00
|
|
|
|
return [self path];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
NSString *path = nil;
|
|
|
|
|
|
|
|
|
|
if (myData->path != 0)
|
|
|
|
|
{
|
2013-02-15 19:56:03 +00:00
|
|
|
|
char buf[strlen(myData->path) + 1];
|
|
|
|
|
|
|
|
|
|
strcpy(buf, myData->path);
|
|
|
|
|
unescape(buf, buf);
|
|
|
|
|
path = [NSString stringWithUTF8String: buf];
|
2010-10-13 17:41:22 +00:00
|
|
|
|
}
|
|
|
|
|
return path;
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSString*) relativeString
|
|
|
|
|
{
|
|
|
|
|
return _urlString;
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2009-04-27 20:58:17 +00:00
|
|
|
|
/* Encode bycopy unless explicitly requested otherwise.
|
|
|
|
|
*/
|
|
|
|
|
- (id) replacementObjectForPortCoder: (NSPortCoder*)aCoder
|
|
|
|
|
{
|
|
|
|
|
if ([aCoder isByref] == NO)
|
|
|
|
|
return self;
|
|
|
|
|
return [super replacementObjectForPortCoder: aCoder];
|
|
|
|
|
}
|
|
|
|
|
|
2000-09-22 13:45:58 +00:00
|
|
|
|
- (NSData*) resourceDataUsingCache: (BOOL)shouldUseCache
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2006-11-21 18:15:47 +00:00
|
|
|
|
NSURLHandle *handle = [self URLHandleUsingCache: YES];
|
2012-07-08 12:03:09 +00:00
|
|
|
|
NSData *data = nil;
|
2000-09-22 13:45:58 +00:00
|
|
|
|
|
2012-07-08 12:03:09 +00:00
|
|
|
|
if ([handle status] == NSURLHandleLoadSucceeded)
|
|
|
|
|
{
|
|
|
|
|
data = [handle availableResourceData];
|
|
|
|
|
}
|
2000-09-22 13:45:58 +00:00
|
|
|
|
if (shouldUseCache == NO || [handle status] != NSURLHandleLoadSucceeded)
|
|
|
|
|
{
|
2012-07-08 12:03:09 +00:00
|
|
|
|
data = [handle loadInForeground];
|
|
|
|
|
}
|
|
|
|
|
if (nil == data)
|
|
|
|
|
{
|
|
|
|
|
data = [handle availableResourceData];
|
2000-09-22 13:45:58 +00:00
|
|
|
|
}
|
|
|
|
|
return data;
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (NSString*) resourceSpecifier
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2012-09-16 07:39:18 +00:00
|
|
|
|
if (YES == myData->isGeneric)
|
2000-09-22 13:45:58 +00:00
|
|
|
|
{
|
2012-09-16 07:39:18 +00:00
|
|
|
|
NSRange range = [_urlString rangeOfString: @"://"];
|
2011-01-07 10:19:51 +00:00
|
|
|
|
|
2012-09-16 07:39:18 +00:00
|
|
|
|
if (range.length > 0)
|
|
|
|
|
{
|
|
|
|
|
NSString *specifier;
|
|
|
|
|
|
|
|
|
|
/* MacOSX compatibility - in the case where there is no
|
|
|
|
|
* host in the URL, just return the path (without the "//").
|
|
|
|
|
* For all other cases we return the whole specifier.
|
|
|
|
|
*/
|
|
|
|
|
if (nil == [self host])
|
|
|
|
|
{
|
|
|
|
|
specifier = [_urlString substringFromIndex: NSMaxRange(range)];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
specifier = [_urlString substringFromIndex: range.location+1];
|
|
|
|
|
}
|
|
|
|
|
return specifier;
|
|
|
|
|
}
|
2010-12-22 18:10:33 +00:00
|
|
|
|
else
|
2012-09-16 07:39:18 +00:00
|
|
|
|
{
|
|
|
|
|
/*
|
|
|
|
|
* Cope with URLs missing net_path info - <scheme>:/<path>...
|
|
|
|
|
*/
|
|
|
|
|
range = [_urlString rangeOfString: @":"];
|
|
|
|
|
if (range.length > 0)
|
|
|
|
|
{
|
|
|
|
|
return [_urlString substringFromIndex: range.location + 1];
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
return _urlString;
|
|
|
|
|
}
|
|
|
|
|
}
|
2000-09-22 13:45:58 +00:00
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
else
|
2000-09-22 13:45:58 +00:00
|
|
|
|
{
|
2012-09-16 07:39:18 +00:00
|
|
|
|
return [NSString stringWithUTF8String: myData->path];
|
2000-09-22 13:45:58 +00:00
|
|
|
|
}
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (NSString*) scheme
|
|
|
|
|
{
|
|
|
|
|
NSString *scheme = nil;
|
|
|
|
|
|
|
|
|
|
if (myData->scheme != 0)
|
|
|
|
|
{
|
|
|
|
|
scheme = [NSString stringWithUTF8String: myData->scheme];
|
|
|
|
|
}
|
|
|
|
|
return scheme;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (BOOL) setProperty: (id)property
|
|
|
|
|
forKey: (NSString*)propertyKey
|
|
|
|
|
{
|
|
|
|
|
NSURLHandle *handle = [self URLHandleUsingCache: YES];
|
|
|
|
|
|
|
|
|
|
return [handle writeProperty: property forKey: propertyKey];
|
|
|
|
|
}
|
|
|
|
|
|
1999-06-24 19:30:29 +00:00
|
|
|
|
- (BOOL) setResourceData: (NSData*)data
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2000-09-22 13:45:58 +00:00
|
|
|
|
NSURLHandle *handle = [self URLHandleUsingCache: YES];
|
|
|
|
|
|
2001-12-12 14:17:03 +00:00
|
|
|
|
if (handle == nil)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
if ([handle writeData: data] == NO)
|
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
2006-11-21 18:15:47 +00:00
|
|
|
|
if ([handle loadInForeground] == nil)
|
2001-12-12 14:17:03 +00:00
|
|
|
|
{
|
|
|
|
|
return NO;
|
|
|
|
|
}
|
|
|
|
|
return YES;
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (NSURL*) standardizedURL
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
char *url = buildURL(baseData, myData, YES);
|
|
|
|
|
unsigned len = strlen(url);
|
|
|
|
|
NSString *str;
|
|
|
|
|
NSURL *tmp;
|
|
|
|
|
|
|
|
|
|
str = [[NSString alloc] initWithCStringNoCopy: url
|
|
|
|
|
length: len
|
|
|
|
|
freeWhenDone: YES];
|
|
|
|
|
tmp = [NSURL URLWithString: str];
|
|
|
|
|
RELEASE(str);
|
|
|
|
|
return tmp;
|
|
|
|
|
}
|
2000-09-22 13:45:58 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (NSURLHandle*) URLHandleUsingCache: (BOOL)shouldUseCache
|
|
|
|
|
{
|
|
|
|
|
NSURLHandle *handle = nil;
|
|
|
|
|
|
|
|
|
|
if (shouldUseCache)
|
|
|
|
|
{
|
|
|
|
|
handle = [NSURLHandle cachedHandleForURL: self];
|
|
|
|
|
}
|
|
|
|
|
if (handle == nil)
|
|
|
|
|
{
|
|
|
|
|
Class c = [NSURLHandle URLHandleClassForURL: self];
|
|
|
|
|
|
|
|
|
|
if (c != 0)
|
|
|
|
|
{
|
|
|
|
|
handle = [[c alloc] initWithURL: self cached: shouldUseCache];
|
2009-01-12 12:48:46 +00:00
|
|
|
|
IF_NO_GC([handle autorelease];)
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return handle;
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (NSString*) user
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
2002-06-05 12:39:28 +00:00
|
|
|
|
NSString *user = nil;
|
2000-09-22 13:45:58 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
if (myData->user != 0)
|
|
|
|
|
{
|
2002-06-17 16:20:21 +00:00
|
|
|
|
char buf[strlen(myData->user)+1];
|
|
|
|
|
|
|
|
|
|
unescape(myData->user, buf);
|
|
|
|
|
user = [NSString stringWithUTF8String: buf];
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
return user;
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-17 11:45:28 +00:00
|
|
|
|
- (NSURL*) URLByAppendingPathComponent: (NSString*)pathComponent
|
|
|
|
|
{
|
|
|
|
|
return [self _URLBySettingPath:
|
2011-06-18 07:09:28 +00:00
|
|
|
|
[[self path] stringByAppendingPathComponent: pathComponent]];
|
2011-06-17 11:45:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSURL*) URLByAppendingPathExtension: (NSString*)pathExtension
|
|
|
|
|
{
|
|
|
|
|
return [self _URLBySettingPath:
|
|
|
|
|
[[self path] stringByAppendingPathExtension: pathExtension]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSURL*) URLByDeletingLastPathComponent
|
|
|
|
|
{
|
|
|
|
|
return [self _URLBySettingPath:
|
|
|
|
|
[[self path] stringByDeletingLastPathComponent]];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSURL*) URLByDeletingPathExtension
|
|
|
|
|
{
|
|
|
|
|
return [self _URLBySettingPath:
|
|
|
|
|
[[self path] stringByDeletingPathExtension]];
|
|
|
|
|
}
|
|
|
|
|
|
2011-06-18 07:09:28 +00:00
|
|
|
|
- (NSURL*) URLByResolvingSymlinksInPath
|
|
|
|
|
{
|
|
|
|
|
if ([self isFileURL])
|
|
|
|
|
{
|
|
|
|
|
return [NSURL fileURLWithPath:
|
|
|
|
|
[[self path] stringByResolvingSymlinksInPath]];
|
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (NSURL*) URLByStandardizingPath
|
|
|
|
|
{
|
|
|
|
|
if ([self isFileURL])
|
|
|
|
|
{
|
|
|
|
|
return [NSURL fileURLWithPath: [[self path] stringByStandardizingPath]];
|
|
|
|
|
}
|
|
|
|
|
return self;
|
|
|
|
|
}
|
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (void) URLHandle: (NSURLHandle*)sender
|
|
|
|
|
resourceDataDidBecomeAvailable: (NSData*)newData
|
|
|
|
|
{
|
2003-03-25 10:03:43 +00:00
|
|
|
|
id c = clientForHandle(_clients, sender);
|
|
|
|
|
|
|
|
|
|
if ([c respondsToSelector: @selector(URL:resourceDataDidBecomeAvailable:)])
|
|
|
|
|
{
|
|
|
|
|
[c URL: self resourceDataDidBecomeAvailable: newData];
|
|
|
|
|
}
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
2003-03-25 10:03:43 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (void) URLHandle: (NSURLHandle*)sender
|
|
|
|
|
resourceDidFailLoadingWithReason: (NSString*)reason
|
|
|
|
|
{
|
2003-03-25 10:03:43 +00:00
|
|
|
|
id c = clientForHandle(_clients, sender);
|
|
|
|
|
|
2003-03-25 18:02:14 +00:00
|
|
|
|
if (c != nil)
|
2003-03-25 10:03:43 +00:00
|
|
|
|
{
|
2003-03-25 18:02:14 +00:00
|
|
|
|
if ([c respondsToSelector:
|
|
|
|
|
@selector(URL:resourceDidFailLoadingWithReason:)])
|
|
|
|
|
{
|
|
|
|
|
[c URL: self resourceDidFailLoadingWithReason: reason];
|
|
|
|
|
}
|
|
|
|
|
[clientsLock lock];
|
|
|
|
|
NSMapRemove((NSMapTable*)_clients, (void*)sender);
|
|
|
|
|
[clientsLock unlock];
|
2003-03-25 10:03:43 +00:00
|
|
|
|
}
|
2003-03-25 18:02:14 +00:00
|
|
|
|
[sender removeClient: self];
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) URLHandleResourceDidBeginLoading: (NSURLHandle*)sender
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) URLHandleResourceDidCancelLoading: (NSURLHandle*)sender
|
|
|
|
|
{
|
2003-03-25 10:03:43 +00:00
|
|
|
|
id c = clientForHandle(_clients, sender);
|
|
|
|
|
|
2003-03-25 18:02:14 +00:00
|
|
|
|
if (c != nil)
|
2003-03-25 10:03:43 +00:00
|
|
|
|
{
|
2003-03-25 18:02:14 +00:00
|
|
|
|
if ([c respondsToSelector: @selector(URLResourceDidCancelLoading:)])
|
|
|
|
|
{
|
|
|
|
|
[c URLResourceDidCancelLoading: self];
|
|
|
|
|
}
|
|
|
|
|
[clientsLock lock];
|
|
|
|
|
NSMapRemove((NSMapTable*)_clients, (void*)sender);
|
|
|
|
|
[clientsLock unlock];
|
2003-03-25 10:03:43 +00:00
|
|
|
|
}
|
2003-03-25 18:02:14 +00:00
|
|
|
|
[sender removeClient: self];
|
2002-06-05 12:39:28 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
- (void) URLHandleResourceDidFinishLoading: (NSURLHandle*)sender
|
|
|
|
|
{
|
2003-03-25 10:03:43 +00:00
|
|
|
|
id c = clientForHandle(_clients, sender);
|
|
|
|
|
|
2009-01-12 12:48:46 +00:00
|
|
|
|
IF_NO_GC([self retain];)
|
2003-07-25 13:58:25 +00:00
|
|
|
|
[sender removeClient: self];
|
2003-03-25 18:02:14 +00:00
|
|
|
|
if (c != nil)
|
2003-03-25 10:03:43 +00:00
|
|
|
|
{
|
2003-03-25 19:19:27 +00:00
|
|
|
|
if ([c respondsToSelector: @selector(URLResourceDidFinishLoading:)])
|
2003-03-25 18:02:14 +00:00
|
|
|
|
{
|
|
|
|
|
[c URLResourceDidFinishLoading: self];
|
|
|
|
|
}
|
|
|
|
|
[clientsLock lock];
|
|
|
|
|
NSMapRemove((NSMapTable*)_clients, (void*)sender);
|
|
|
|
|
[clientsLock unlock];
|
2003-03-25 10:03:43 +00:00
|
|
|
|
}
|
2010-02-26 08:39:47 +00:00
|
|
|
|
RELEASE(self);
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
|
2000-11-03 14:30:00 +00:00
|
|
|
|
|
|
|
|
|
|
2002-06-06 14:02:59 +00:00
|
|
|
|
/**
|
|
|
|
|
* An informal protocol to which clients may conform if they wish to be
|
2004-06-22 22:40:40 +00:00
|
|
|
|
* notified of the progress in loading a URL for them. NSURL conforms to
|
|
|
|
|
* this protocol but all methods are implemented as no-ops. See also
|
2004-07-29 15:30:47 +00:00
|
|
|
|
* the [(NSURLHandleClient)] protocol.
|
2002-06-06 14:02:59 +00:00
|
|
|
|
*/
|
1999-02-13 00:50:41 +00:00
|
|
|
|
@implementation NSObject (NSURLClient)
|
|
|
|
|
|
1999-06-24 19:30:29 +00:00
|
|
|
|
- (void) URL: (NSURL*)sender
|
2000-09-22 13:45:58 +00:00
|
|
|
|
resourceDataDidBecomeAvailable: (NSData*)newBytes
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (void) URL: (NSURL*)sender
|
|
|
|
|
resourceDidFailLoadingWithReason: (NSString*)reason
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
1999-06-24 19:30:29 +00:00
|
|
|
|
- (void) URLResourceDidCancelLoading: (NSURL*)sender
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
2002-06-05 12:39:28 +00:00
|
|
|
|
- (void) URLResourceDidFinishLoading: (NSURL*)sender
|
1999-02-13 00:50:41 +00:00
|
|
|
|
{
|
1999-06-24 19:30:29 +00:00
|
|
|
|
}
|
1999-02-13 00:50:41 +00:00
|
|
|
|
|
|
|
|
|
@end
|
2011-06-17 11:45:28 +00:00
|
|
|
|
|
|
|
|
|
@implementation NSURL (GNUstepBase)
|
|
|
|
|
- (NSString*) fullPath
|
|
|
|
|
{
|
|
|
|
|
NSString *path = nil;
|
|
|
|
|
|
2012-09-16 07:39:18 +00:00
|
|
|
|
if (YES == myData->isGeneric || 0 == myData->scheme)
|
2011-06-17 11:45:28 +00:00
|
|
|
|
{
|
2012-09-16 07:39:18 +00:00
|
|
|
|
unsigned int len = 3;
|
|
|
|
|
|
|
|
|
|
if (_baseURL != nil)
|
2011-06-17 11:45:28 +00:00
|
|
|
|
{
|
2012-09-16 07:39:18 +00:00
|
|
|
|
if (baseData->path && *baseData->path)
|
|
|
|
|
{
|
|
|
|
|
len += strlen(baseData->path);
|
|
|
|
|
}
|
|
|
|
|
else if (baseData->hasNoPath == NO)
|
|
|
|
|
{
|
|
|
|
|
len++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (myData->path && *myData->path)
|
|
|
|
|
{
|
|
|
|
|
len += strlen(myData->path);
|
|
|
|
|
}
|
|
|
|
|
else if (myData->hasNoPath == NO)
|
|
|
|
|
{
|
|
|
|
|
len++;
|
|
|
|
|
}
|
|
|
|
|
if (len > 3)
|
|
|
|
|
{
|
|
|
|
|
char buf[len];
|
|
|
|
|
char *ptr;
|
2011-06-17 11:45:28 +00:00
|
|
|
|
|
2012-09-16 07:39:18 +00:00
|
|
|
|
ptr = [self _path: buf withEscapes: NO];
|
|
|
|
|
path = [NSString stringWithUTF8String: ptr];
|
|
|
|
|
}
|
2011-06-17 11:45:28 +00:00
|
|
|
|
}
|
|
|
|
|
return path;
|
|
|
|
|
}
|
2012-03-07 08:37:54 +00:00
|
|
|
|
|
|
|
|
|
- (NSString*) pathWithEscapes
|
|
|
|
|
{
|
|
|
|
|
return [self _pathWithEscapes: YES];
|
|
|
|
|
}
|
2011-06-17 11:45:28 +00:00
|
|
|
|
@end
|
|
|
|
|
|