ObjFW  Diff

Differences From Artifact [0a4862ec8c]:

To Artifact [e94e617a72]:


28
29
30
31
32
33
34
35
36
37
38
39





40
41
42
43
44
45
46
47
48
49
50
51
52
53
54


55
56
57
58
59


60
61
62
63
64
65
66

67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87

88
89

90
91
92
93


94
95
96


97
98
99

100
101

102
103
104
105
106
107
108

109
110
111

112
113

114
115

116
117

118
119

120
121
122


123
124

125
126
127
128

129
130
131
132
133

134
135
136
137
138
139

140
141
142
143
144

145
146
147
148
149

150
151

152
153
154

155
156

157
158
159
160
161

162
163
164

165
166

167
168
169
170

171
172
173
174

175
176
177
178
179
180
181
182
183
184
185


186
187
188
189
190
191
192

193
194
195
196
197
198
199

200
201
202
203
204
205
206


207
208
209
210
211
212
213

214
215
216
217
218
219
220


221
222

223
224
225


226
227
228
229
230
231
232
233
234
235
236





237
238

239
240
241

242
243

244
245

246
247
248
249
250

251
252
253
254
255

256
257
258
259
260
261
262


263
264
265
266
267
268
269

270
271
272


273
274
275
276


277
278
279
280
281
282
283
284
285
286

287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306

307
308

309
310

311
312
313

314
315

316
317

318
319

320
321

322
323

324
325

326
327

328
329

330
331

332
333
334
335
336
337
338
339

340
341
342
343
344
345
346
28
29
30
31
32
33
34





35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52


53
54
55
56
57


58
59
60
61
62
63
64
65

66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86

87
88

89
90
91


92
93
94


95
96
97
98

99
100

101
102
103
104
105
106
107

108
109
110

111
112

113
114

115
116

117
118

119
120


121
122
123

124
125
126
127

128
129
130
131
132

133
134
135
136
137
138

139
140
141
142
143

144
145
146
147
148

149
150

151
152
153

154
155

156
157
158
159
160

161
162
163

164
165

166
167
168
169

170
171
172
173

174
175
176
177
178
179
180
181
182
183


184
185
186
187
188
189
190
191

192
193
194
195
196
197
198

199
200
201
202
203
204
205

206
207
208
209
210
211
212
213

214
215
216
217
218
219


220
221
222

223
224


225
226
227
228
229
230
231
232





233
234
235
236
237
238

239
240
241

242
243

244
245

246
247
248
249
250

251
252
253
254
255

256
257
258
259
260
261


262
263
264
265
266
267
268
269

270
271


272
273
274
275


276
277
278
279
280
281
282
283
284
285
286

287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306

307
308

309
310

311
312
313

314
315

316
317

318
319

320
321

322
323

324
325

326
327

328
329

330
331

332
333
334
335
336
337
338
339

340
341
342
343
344
345
346
347







-
-
-
-
-
+
+
+
+
+













-
-
+
+



-
-
+
+






-
+




















-
+

-
+


-
-
+
+

-
-
+
+


-
+

-
+






-
+


-
+

-
+

-
+

-
+

-
+

-
-
+
+

-
+



-
+




-
+





-
+




-
+




-
+

-
+


-
+

-
+




-
+


-
+

-
+



-
+



-
+









-
-
+
+






-
+






-
+






-
+
+






-
+





-
-
+
+

-
+

-
-
+
+






-
-
-
-
-
+
+
+
+
+

-
+


-
+

-
+

-
+




-
+




-
+





-
-
+
+






-
+

-
-
+
+


-
-
+
+









-
+



















-
+

-
+

-
+


-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+

-
+







-
+







#import "OFInvalidArgumentException.h"
#import "OFInvalidFormatException.h"
#import "OFOutOfMemoryException.h"

#import "macros.h"

#define ADD_STR_HASH(str)			\
	h = [str hash];				\
	OF_HASH_ADD(hash, h >> 24);		\
	OF_HASH_ADD(hash, (h >> 16) & 0xFF);	\
	OF_HASH_ADD(hash, (h >> 8) & 0xFF);	\
	OF_HASH_ADD(hash, h & 0xFF);
	tmp = [str hash];			\
	OF_HASH_ADD(hash, tmp >> 24);		\
	OF_HASH_ADD(hash, (tmp >> 16) & 0xFF);	\
	OF_HASH_ADD(hash, (tmp >> 8) & 0xFF);	\
	OF_HASH_ADD(hash, tmp & 0xFF);

static OF_INLINE OFString*
resolve_relative_path(OFString *path)
{
	OFAutoreleasePool *pool = [[OFAutoreleasePool alloc] init];
	OFMutableArray *array;
	OFString *ret;
	BOOL done = NO;

	array = [[[path componentsSeparatedByString: @"/"] mutableCopy]
	    autorelease];

	while (!done) {
		id *array_c = [array cArray];
		size_t i, array_len = [array count];
		id *cArray = [array cArray];
		size_t i, length = [array count];

		done = YES;

		for (i = 0; i < array_len; i++) {
			if ([array_c[i] isEqual: @"."]) {
		for (i = 0; i < length; i++) {
			if ([cArray[i] isEqual: @"."]) {
				[array removeObjectAtIndex: i];
				done = NO;

				break;
			}

			if ([array_c[i] isEqual: @".."]) {
			if ([cArray[i] isEqual: @".."]) {
				[array removeObjectAtIndex: i];

				if (i > 0)
					[array removeObjectAtIndex: i - 1];

				done = NO;

				break;
			}
		}
	}

	ret = [[array componentsJoinedByString: @"/"] retain];

	[pool release];

	return [ret autorelease];
}

@implementation OFURL
+ URLWithString: (OFString*)str
+ URLWithString: (OFString*)string
{
	return [[[self alloc] initWithString: str] autorelease];
	return [[[self alloc] initWithString: string] autorelease];
}

+ URLWithString: (OFString*)str
  relativeToURL: (OFURL*)url
+ URLWithString: (OFString*)string
  relativeToURL: (OFURL*)URL
{
	return [[[self alloc] initWithString: str
			       relativeToURL: url] autorelease];
	return [[[self alloc] initWithString: string
			       relativeToURL: URL] autorelease];
}

- initWithString: (OFString*)str
- initWithString: (OFString*)string
{
	char *str_c, *str_c2 = NULL;
	char *cString, *cString2 = NULL;

	self = [super init];

	@try {
		char *tmp, *tmp2;

		if ((str_c2 = strdup([str cString])) == NULL)
		if ((cString2 = strdup([string cString])) == NULL)
			@throw [OFOutOfMemoryException
			     newWithClass: isa
			    requestedSize: [str cStringLength]];
			    requestedSize: [string cStringLength]];

		str_c = str_c2;
		cString = cString2;

		if (!strncmp(str_c, "file://", 7)) {
		if (!strncmp(cString, "file://", 7)) {
			scheme = @"file";
			path = [[OFString alloc] initWithCString: str_c + 7];
			path = [[OFString alloc] initWithCString: cString + 7];
			return self;
		} else if (!strncmp(str_c, "http://", 7)) {
		} else if (!strncmp(cString, "http://", 7)) {
			scheme = @"http";
			str_c += 7;
		} else if (!strncmp(str_c, "https://", 8)) {
			cString += 7;
		} else if (!strncmp(cString, "https://", 8)) {
			scheme = @"https";
			str_c += 8;
			cString += 8;
		} else
			@throw [OFInvalidFormatException newWithClass: isa];

		if ((tmp = strchr(str_c, '/')) != NULL) {
		if ((tmp = strchr(cString, '/')) != NULL) {
			*tmp = '\0';
			tmp++;
		}

		if ((tmp2 = strchr(str_c, '@')) != NULL) {
		if ((tmp2 = strchr(cString, '@')) != NULL) {
			char *tmp3;

			*tmp2 = '\0';
			tmp2++;

			if ((tmp3 = strchr(str_c, ':')) != NULL) {
			if ((tmp3 = strchr(cString, ':')) != NULL) {
				*tmp3 = '\0';
				tmp3++;

				user = [[OFString alloc]
				    initWithCString: str_c];
				    initWithCString: cString];
				password = [[OFString alloc]
				    initWithCString: tmp3];
			} else
				user = [[OFString alloc]
				    initWithCString: str_c];
				    initWithCString: cString];

			str_c = tmp2;
			cString = tmp2;
		}

		if ((tmp2 = strchr(str_c, ':')) != NULL) {
		if ((tmp2 = strchr(cString, ':')) != NULL) {
			OFAutoreleasePool *pool;
			OFString *port_str;
			OFString *portString;

			*tmp2 = '\0';
			tmp2++;

			host = [[OFString alloc] initWithCString: str_c];
			host = [[OFString alloc] initWithCString: cString];

			pool = [[OFAutoreleasePool alloc] init];
			port_str = [[OFString alloc] initWithCString: tmp2];
			portString = [[OFString alloc] initWithCString: tmp2];

			if ([port_str decimalValue] > 65535)
			if ([portString decimalValue] > 65535)
				@throw [OFInvalidFormatException
				    newWithClass: isa];

			port = [port_str decimalValue];
			port = [portString decimalValue];

			[pool release];
		} else {
			host = [[OFString alloc] initWithCString: str_c];
			host = [[OFString alloc] initWithCString: cString];

			if ([scheme isEqual: @"http"])
				port = 80;
			else if ([scheme isEqual: @"https"])
				port = 443;
			else
				assert(0);
		}

		if ((str_c = tmp) != NULL) {
			if ((tmp = strchr(str_c, '#')) != NULL) {
		if ((cString = tmp) != NULL) {
			if ((tmp = strchr(cString, '#')) != NULL) {
				*tmp = '\0';

				fragment = [[OFString alloc]
				    initWithCString: tmp + 1];
			}

			if ((tmp = strchr(str_c, '?')) != NULL) {
			if ((tmp = strchr(cString, '?')) != NULL) {
				*tmp = '\0';

				query = [[OFString alloc]
				    initWithCString: tmp + 1];
			}

			if ((tmp = strchr(str_c, ';')) != NULL) {
			if ((tmp = strchr(cString, ';')) != NULL) {
				*tmp = '\0';

				parameters = [[OFString alloc]
				    initWithCString: tmp + 1];
			}

			path = [[OFString alloc] initWithFormat: @"/%s", str_c];
			path = [[OFString alloc] initWithFormat: @"/%s",
								 cString];
		} else
			path = @"";
	} @catch (id e) {
		[self release];
		@throw e;
	} @finally {
		free(str_c2);
		free(cString2);
	}

	return self;
}

- initWithString: (OFString*)str
   relativeToURL: (OFURL*)url
- initWithString: (OFString*)string
   relativeToURL: (OFURL*)URL
{
	char *str_c, *str_c2 = NULL;
	char *cString, *cString2 = NULL;

	if ([str containsString: @"://"])
		return [self initWithString: str];
	if ([string containsString: @"://"])
		return [self initWithString: string];

	self = [super init];

	@try {
		char *tmp;

		scheme = [url->scheme copy];
		host = [url->host copy];
		port = url->port;
		user = [url->user copy];
		password = [url->password copy];
		scheme = [URL->scheme copy];
		host = [URL->host copy];
		port = URL->port;
		user = [URL->user copy];
		password = [URL->password copy];

		if ((str_c2 = strdup([str cString])) == NULL)
		if ((cString2 = strdup([string cString])) == NULL)
			@throw [OFOutOfMemoryException
			     newWithClass: isa
			    requestedSize: [str cStringLength]];
			    requestedSize: [string cStringLength]];

		str_c = str_c2;
		cString = cString2;

		if ((tmp = strchr(str_c, '#')) != NULL) {
		if ((tmp = strchr(cString, '#')) != NULL) {
			*tmp = '\0';
			fragment = [[OFString alloc] initWithCString: tmp + 1];
		}

		if ((tmp = strchr(str_c, '?')) != NULL) {
		if ((tmp = strchr(cString, '?')) != NULL) {
			*tmp = '\0';
			query = [[OFString alloc] initWithCString: tmp + 1];
		}

		if ((tmp = strchr(str_c, ';')) != NULL) {
		if ((tmp = strchr(cString, ';')) != NULL) {
			*tmp = '\0';
			parameters = [[OFString alloc]
			    initWithCString: tmp + 1];
		}

		if (*str_c == '/')
			path = [[OFString alloc] initWithCString: str_c];
		if (*cString == '/')
			path = [[OFString alloc] initWithCString: cString];
		else {
			OFAutoreleasePool *pool;
			OFString *s;

			pool = [[OFAutoreleasePool alloc] init];

			if ([url->path hasSuffix: @"/"])
			if ([URL->path hasSuffix: @"/"])
				s = [OFString stringWithFormat: @"%@%s",
								url->path,
								str_c];
								URL->path,
								cString];
			else
				s = [OFString stringWithFormat: @"%@/../%s",
								url->path,
								str_c];
								URL->path,
								cString];

			path = [resolve_relative_path(s) copy];

			[pool release];
		}
	} @catch (id e) {
		[self release];
		@throw e;
	} @finally {
		free(str_c2);
		free(cString2);
	}

	return self;
}

- (void)dealloc
{
	[scheme release];
	[host release];
	[user release];
	[password release];
	[path release];
	[parameters release];
	[query release];
	[fragment release];

	[super dealloc];
}

- (BOOL)isEqual: (id)obj
- (BOOL)isEqual: (id)object
{
	OFURL *url;
	OFURL *otherURL;

	if (![obj isKindOfClass: [OFURL class]])
	if (![object isKindOfClass: [OFURL class]])
		return NO;

	url = obj;
	otherURL = (OFURL*)object;

	if (![url->scheme isEqual: scheme])
	if (![otherURL->scheme isEqual: scheme])
		return NO;
	if (![url->host isEqual: host])
	if (![otherURL->host isEqual: host])
		return NO;
	if (url->port != port)
	if (otherURL->port != port)
		return NO;
	if (![url->user isEqual: user])
	if (![otherURL->user isEqual: user])
		return NO;
	if (![url->password isEqual: password])
	if (![otherURL->password isEqual: password])
		return NO;
	if (![url->path isEqual: path])
	if (![otherURL->path isEqual: path])
		return NO;
	if (![url->parameters isEqual: parameters])
	if (![otherURL->parameters isEqual: parameters])
		return NO;
	if (![url->query isEqual: query])
	if (![otherURL->query isEqual: query])
		return NO;
	if (![url->fragment isEqual: fragment])
	if (![otherURL->fragment isEqual: fragment])
		return NO;

	return YES;
}

- (uint32_t)hash
{
	uint32_t hash, h;
	uint32_t hash, tmp;

	OF_HASH_INIT(hash);

	ADD_STR_HASH(scheme);
	ADD_STR_HASH(host);

	OF_HASH_ADD(hash, (port >> 8) & 0xFF);
356
357
358
359
360
361
362
363

364
365
366
367
368
369
370
371
372
373
374









375
376

377
378
379
380

381
382
383
384
385
386
387
388
389
390
391
392
393
394

395
396
397
398
399
400
401
402
403
357
358
359
360
361
362
363

364
365
366









367
368
369
370
371
372
373
374
375
376

377
378
379
380

381
382
383
384
385
386
387
388
389
390
391
392
393
394

395


396
397
398
399
400
401
402







-
+


-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+

-
+



-
+













-
+
-
-







	OF_HASH_FINALIZE(hash);

	return hash;
}

- copy
{
	OFURL *new = [[OFURL alloc] init];
	OFURL *copy = [[OFURL alloc] init];

	@try {
		new->scheme = [scheme copy];
		new->host = [host copy];
		new->port = port;
		new->user = [user copy];
		new->password = [password copy];
		new->path = [path copy];
		new->parameters = [parameters copy];
		new->query = [query copy];
		new->fragment = [fragment copy];
		copy->scheme = [scheme copy];
		copy->host = [host copy];
		copy->port = port;
		copy->user = [user copy];
		copy->password = [password copy];
		copy->path = [path copy];
		copy->parameters = [parameters copy];
		copy->query = [query copy];
		copy->fragment = [fragment copy];
	} @catch (id e) {
		[new release];
		[copy release];
		@throw e;
	}

	return new;
	return copy;
}

- (OFString*)scheme
{
	OF_GETTER(scheme, YES)
}

- (void)setScheme: (OFString*)scheme_
{
	if (![scheme_ isEqual: @"http"] && ![scheme_ isEqual: @"https"])
		@throw [OFInvalidArgumentException newWithClass: isa
						       selector: _cmd];

	OFString *old = scheme;
	OF_SETTER(scheme, scheme_, YES, YES)
	scheme = [scheme_ copy];
	[old release];
}

- (OFString*)host
{
	OF_GETTER(host, YES)
}

439
440
441
442
443
444
445
446
447
448
449
450
451
452
453

454
455
456
457
458
459
460
461
462
438
439
440
441
442
443
444


445
446
447
448
449

450


451
452
453
454
455
456
457







-
-





-
+
-
-







- (OFString*)path
{
	OF_GETTER(path, YES)
}

- (void)setPath: (OFString*)path_
{
	OFString *old;

	if (([scheme isEqual: @"http"] || [scheme isEqual: @"https"]) &&
	    ![path_ hasPrefix: @"/"])
		@throw [OFInvalidArgumentException newWithClass: isa
						       selector: _cmd];

	old = path;
	OF_SETTER(path, path_, YES, YES)
	path = [path_ copy];
	[old release];
}

- (OFString*)parameters
{
	OF_GETTER(parameters, YES)
}

483
484
485
486
487
488
489
490
491


492
493
494
495
496


497
498
499
500

501
502

503
504

505
506
507
508
509
510
511

512
513

514
515
516

517
518
519

520
521
522

523
524
525
526
527
528
529
530


531
532
478
479
480
481
482
483
484


485
486
487
488
489


490
491
492
493
494

495
496

497
498

499
500
501
502
503
504
505

506
507

508
509
510

511
512
513

514
515
516

517
518
519
520
521
522
523


524
525
526
527







-
-
+
+



-
-
+
+



-
+

-
+

-
+






-
+

-
+


-
+


-
+


-
+






-
-
+
+


- (void)setFragment: (OFString*)fragment_
{
	OF_SETTER(fragment, fragment_, YES, YES)
}

- (OFString*)description
{
	OFMutableString *desc = [OFMutableString stringWithFormat: @"%@://",
								   scheme];
	OFMutableString *ret = [OFMutableString stringWithFormat: @"%@://",
								  scheme];
	BOOL needPort = YES;

	if ([scheme isEqual: @"file"]) {
		[desc appendString: path];
		return desc;
		[ret appendString: path];
		return ret;
	}

	if (user != nil && password != nil)
		[desc appendFormat: @"%@:%@@", user, password];
		[ret appendFormat: @"%@:%@@", user, password];
	else if (user != nil)
		[desc appendFormat: @"%@@", user];
		[ret appendFormat: @"%@@", user];

	[desc appendString: host];
	[ret appendString: host];

	if (([scheme isEqual: @"http"] && port == 80) ||
	    ([scheme isEqual: @"https"] && port == 443))
		needPort = NO;

	if (needPort)
		[desc appendFormat: @":%d", port];
		[ret appendFormat: @":%d", port];

	[desc appendString: path];
	[ret appendString: path];

	if (parameters != nil)
		[desc appendFormat: @";%@", parameters];
		[ret appendFormat: @";%@", parameters];

	if (query != nil)
		[desc appendFormat: @"?%@", query];
		[ret appendFormat: @"?%@", query];

	if (fragment != nil)
		[desc appendFormat: @"#%@", fragment];
		[ret appendFormat: @"#%@", fragment];

	/*
	 * Class swizzle the string to be immutable. We declared the return type
	 * to be OFString*, so it can't be modified anyway. But not swizzling it
	 * would create a real copy each time -[copy] is called.
	 */
	desc->isa = [OFString class];
	return desc;
	ret->isa = [OFString class];
	return ret;
}
@end