Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Newer
Older
100644 558 lines (432 sloc) 18.549 kb
9354734 A whole smorgasbord of URL-related methods.
Mike authored
1 //
cec2f16 Updating file info.
Mike authored
2 // KSURLUtilities.m
9354734 A whole smorgasbord of URL-related methods.
Mike authored
3 //
5e343ed Dan Wood update copyrights to 2012
danwood authored
4 // Copyright (c) 2007-2012 Mike Abdullah and Karelia Software
20a1855 Mike Abdullah Settle on BSD license.
mikeabdullah authored
5 // All rights reserved.
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions are met:
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above copyright
12 // notice, this list of conditions and the following disclaimer in the
13 // documentation and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
16 // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 // WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 // DISCLAIMED. IN NO EVENT SHALL MIKE ABDULLAH OR KARELIA SOFTWARE BE LIABLE FOR ANY
19 // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
20 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
21 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
22 // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
24 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
9354734 A whole smorgasbord of URL-related methods.
Mike authored
25 //
26
20a1855 Mike Abdullah Settle on BSD license.
mikeabdullah authored
27
9354734 A whole smorgasbord of URL-related methods.
Mike authored
28 #import "KSURLUtilities.h"
29
30 #import "KSPathUtilities.h"
31
32
33 @implementation NSURL (KSPathUtilities)
34
84fbfdd Mike Abdullah -ks_URLWithScheme: for deriving same resource specifier, but different s...
mikeabdullah authored
35 #pragma mark Scheme
36
dd1e676 Mike Abdullah Handle URLs like file:///path
mikeabdullah authored
37 - (NSURL *)ks_URLWithScheme:(NSString *)newScheme;
84fbfdd Mike Abdullah -ks_URLWithScheme: for deriving same resource specifier, but different s...
mikeabdullah authored
38 {
dd1e676 Mike Abdullah Handle URLs like file:///path
mikeabdullah authored
39 NSString *scheme = [self scheme];
40 if (!scheme) return nil;
41
42 // -resourceSpecifier is supposed to give me everything after the scheme's colon, but for file:///path URLs, it just returns /path. Work around by deducing when resource specifier truly starts. Also found CFURLCopyResourceSpecifier() returns NULL for such URLs, against its documentation
43 NSString *string = [[NSString alloc] initWithFormat:
44 @"%@:%@",
45 newScheme,
46 [[self absoluteString] substringFromIndex:[scheme length] + 1]]; // should be safe since a colon was needed to know scheme
47
dd480c6 Mike Abdullah leak fix
mikeabdullah authored
48 NSURL *result = [[self class] URLWithString:string];
49 [string release];
50 return result;
84fbfdd Mike Abdullah -ks_URLWithScheme: for deriving same resource specifier, but different s...
mikeabdullah authored
51 }
52
9354734 A whole smorgasbord of URL-related methods.
Mike authored
53 #pragma mark Host
54
55 - (NSURL *)ks_hostURL; // returns a URL like "http://launch.karelia.com/"
56 {
b6bcb44 Mike Abdullah Doesn't make sense to return relative URLs from -ks_hostURL.
mikeabdullah authored
57 NSURL *result = [[NSURL URLWithString:@"/" relativeToURL:self] absoluteURL];
9354734 A whole smorgasbord of URL-related methods.
Mike authored
58 return result;
59 }
60
61
62 - (NSArray *)ks_domains;
63 {
64 NSArray *result = [[self host] componentsSeparatedByString:@"."];
65 return result;
66 }
67
68 - (BOOL)ks_hasNetworkLocation
69 {
70 NSString *resourceSpecifier = [self resourceSpecifier];
71
72 BOOL result = (resourceSpecifier != nil &&
73 [resourceSpecifier length] > 2 &&
74 [[self ks_domains] count] >= 2);
75
76 return result;
77 }
78
6c1ea7a Mike Abdullah -ks_URLWithHost:
mikeabdullah authored
79 - (NSURL *)ks_URLWithHost:(NSString *)host;
80 {
81 NSParameterAssert(host);
82
83 NSURL *result = nil;
84 CFURLRef absolute = CFURLCopyAbsoluteURL((CFURLRef)self);
85 CFRange range = CFURLGetByteRangeForComponent(absolute, kCFURLComponentHost, NULL);
86
87 if (range.location != kCFNotFound)
88 {
89 // Grab data
90 CFIndex length = CFURLGetBytes(absolute, NULL, 0);
91 NSMutableData *data = [[NSMutableData alloc] initWithLength:length];
92 length = CFURLGetBytes(absolute, [data mutableBytes], [data length]);
93 NSAssert(length == [data length], @"CFURLGetBytes() lied to us!");
94
95 // Replace the host
96 NSData *hostData = [host dataUsingEncoding:NSASCIIStringEncoding];
97 [data replaceBytesInRange:NSMakeRange(range.location, range.length) withBytes:[hostData bytes] length:[hostData length]];
98
99 // Create final URL
100 result = NSMakeCollectable(CFURLCreateWithBytes(NULL, [data bytes], [data length], kCFStringEncodingASCII, NULL));
101 [result autorelease];
102 [data release];
103 }
104
105 CFRelease(absolute);
106 return result;
107 }
108
9354734 A whole smorgasbord of URL-related methods.
Mike authored
109 #pragma mark Paths
110
111 /* These two methods operate very similarly to -initWithString:relativeToURL:
112 * However, they assume the string is a path and ensure it has a trailing slash to match isDirectory.
113 */
114
115 + (NSURL *)ks_URLWithPath:(NSString *)path relativeToURL:(NSURL *)baseURL isDirectory:(BOOL)isDirectory
116 {
2201f65 Mike Abdullah Use standard NSParameterAssert macro instead of OBPRECONDITION
mikeabdullah authored
117 NSParameterAssert(path);
9354734 A whole smorgasbord of URL-related methods.
Mike authored
118
119 NSString *URLString = path;
120 if ([path hasSuffix:@"/"] != isDirectory)
121 {
122 if (isDirectory)
123 {
124 URLString = [path stringByAppendingString:@"/"];
125 }
126 else
127 {
128 URLString = [path substringToIndex:([path length] - 1)];
129 }
130 }
131
1d009b9 Mike Abdullah ks-prefixed init methods confuse the analyser, so don't bother.
mikeabdullah authored
132 return [self URLWithString:URLString relativeToURL:baseURL];
9354734 A whole smorgasbord of URL-related methods.
Mike authored
133 }
134
135
136 /* Getting a file:// URL from a path and then turning it into a string is pretty common for us.
137 * This is a simple method to make it faster.
138 */
139 + (NSString *)ks_fileURLStringWithPath:(NSString *)path;
140 {
141 NSURL *URL = [[NSURL alloc] initFileURLWithPath:path];
142 NSString *result = [URL absoluteString];
143 [URL release];
144
145 return result;
146 }
147
148
ba85590 Mike Abdullah Use min required OS, not max available
mikeabdullah authored
149 #if !(defined MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6
9354734 A whole smorgasbord of URL-related methods.
Mike authored
150 // already defined in Snow Leopard
151
152 /* The CFURL APIs expose a bunch more path functionality than NSURL. You could of course use
153 * toll-free bridging, but it's more hassle and less readable. So these methods are here
154 * to simplify that.
155 */
156
157 - (NSString *)ks_lastPathComponent
158 {
159 NSString *result = NSMakeCollectable(CFURLCopyLastPathComponent((CFURLRef)[self absoluteURL]));
160 return [result autorelease];
161 }
162
163 - (NSString *)ks_pathExtension
164 {
165 NSString *result = NSMakeCollectable(CFURLCopyPathExtension((CFURLRef)[self absoluteURL]));
166 return [result autorelease];
167 }
168
169 - (NSURL *)ks_URLByAppendingPathExtension:(NSString *)pathExtension
170 {
171 NSURL *result = NSMakeCollectable(CFURLCreateCopyAppendingPathExtension(NULL,
172 (CFURLRef)self,
173 (CFStringRef)pathExtension));
174 return [result autorelease];
175 }
176
177 - (NSURL *)ks_URLByDeletingLastPathComponent
178 {
1caa440 Mike Abdullah Handle pathless URLs in -ks_URLByDeletingLastPathComponent.
mikeabdullah authored
179 NSURL *result = self;
180 if ([[self path] length]) // #74010
181 {
182 result = NSMakeCollectable(CFURLCreateCopyDeletingLastPathComponent(NULL, (CFURLRef)self));
183 [result autorelease];
184 }
185
186 return result;
9354734 A whole smorgasbord of URL-related methods.
Mike authored
187 }
188
189 - (NSURL *)ks_URLByDeletingPathExtension
190 {
191 NSURL *result = NSMakeCollectable(CFURLCreateCopyDeletingPathExtension(NULL, (CFURLRef)self));
192 return [result autorelease];
193 }
194
195 #endif
196
197 - (BOOL)ks_hasDirectoryPath
198 {
b803999 Mike Abdullah Test suite says CFURLHasDirectoryPath() copes properly with relative URL...
mikeabdullah authored
199 BOOL result = CFURLHasDirectoryPath((CFURLRef)self);
9354734 A whole smorgasbord of URL-related methods.
Mike authored
200 return result;
201 }
202
203 - (NSURL *)ks_URLByAppendingPathComponent:(NSString *)pathComponent isDirectory:(BOOL)isDirectory
204 {
4305f75 Mike Abdullah assertion
mikeabdullah authored
205 NSParameterAssert(pathComponent);
206
9354734 A whole smorgasbord of URL-related methods.
Mike authored
207 NSURL *result = NSMakeCollectable(CFURLCreateCopyAppendingPathComponent(NULL,
208 (CFURLRef)self,
209 (CFStringRef)pathComponent,
210 isDirectory));
211 return [result autorelease];
212 }
213
214 /* e.g. http://example.com/foo/bar.html is a subpath of http://example.com/foo/
215 * The URLs should have the same scheme and host. After that, path comparison is used
216 */
217 - (BOOL)ks_isSubpathOfURL:(NSURL *)aURL;
218 {
219 BOOL result = NO;
220
221
222 // File URLs are treated specially to handle 'localhost' versus '///' and symlinks
223 if ([self isFileURL] && [aURL isFileURL])
224 {
225 // Resolve aliases for local paths
226 NSString *myPath = [[self path] stringByResolvingSymlinksInPath];
227 NSString *otherPath = [[aURL path] stringByResolvingSymlinksInPath];
228
229 result = [myPath ks_isSubpathOfPath:otherPath];
230 }
231 else
232 {
233 NSString *scheme = [self scheme];
234 NSString *otherScheme = [aURL scheme];
f10870a Mike Abdullah Test scheme case-insensitively.
mikeabdullah authored
235 if (scheme && otherScheme && [scheme compare:otherScheme options:NSCaseInsensitiveSearch] == NSOrderedSame)
9354734 A whole smorgasbord of URL-related methods.
Mike authored
236 {
237 NSString *myHost = [self host];
238 NSString *otherHost = [aURL host];
89c4ced Mike Abdullah Test host case-insensitively too.
mikeabdullah authored
239 if (myHost && otherHost && [myHost compare:otherHost options:NSCaseInsensitiveSearch] == NSOrderedSame)
9354734 A whole smorgasbord of URL-related methods.
Mike authored
240 {
241 NSString *myPath = [[self standardizedURL] path];
242 NSString *otherPath = [[aURL standardizedURL] path];
243
244 if (myPath && otherPath)
245 {
246 result = [myPath ks_isSubpathOfPath:otherPath];
247 }
248 }
249 }
250 }
251
252 return result;
253 }
254
255 #pragma mark RFC 1808
256
257 - (BOOL)ks_canBeDecomposed { return CFURLCanBeDecomposed((CFURLRef)self); }
258
259 #pragma mark Relative URLs
260
261 - (NSString *)ks_stringRelativeToURL:(NSURL *)URL
262 {
36b669c Mike Abdullah Ah, looks like I effectively broke a check for nil scheme or host. #1967...
mikeabdullah authored
263
264 #define BAIL return [self absoluteString];
265
9354734 A whole smorgasbord of URL-related methods.
Mike authored
266 // If the base URL is nil then no comparison is needed
36b669c Mike Abdullah Ah, looks like I effectively broke a check for nil scheme or host. #1967...
mikeabdullah authored
267 if (!URL) BAIL;
9354734 A whole smorgasbord of URL-related methods.
Mike authored
268
269
270 // URLs not compliant with RFC 1808 cannot be interpreted
36b669c Mike Abdullah Ah, looks like I effectively broke a check for nil scheme or host. #1967...
mikeabdullah authored
271 if (![self ks_canBeDecomposed] || ![URL ks_canBeDecomposed]) BAIL;
9354734 A whole smorgasbord of URL-related methods.
Mike authored
272
273
840ff21 Mike Abdullah Host and scheme of URLs are considered case-insensitive, so bear that in...
mikeabdullah authored
274 // If the scheme, host or port differs, there is no possible relative path. Schemes and domains are considered to be case-insensitive. http://en.wikipedia.org/wiki/URL_normalization
36b669c Mike Abdullah Ah, looks like I effectively broke a check for nil scheme or host. #1967...
mikeabdullah authored
275 NSString *myHost = [self host];
ecef994 Mike Abdullah Return nil when faced with a URL which can't be reached.
mikeabdullah authored
276 if (!myHost)
277 {
278 // If self is an empty URL, there's no way to get to it. Falls through to here; return nil
279 NSString *result = [self absoluteString];
280 return ([result length] ? result : nil);
281 }
36b669c Mike Abdullah Ah, looks like I effectively broke a check for nil scheme or host. #1967...
mikeabdullah authored
282
283 NSString *otherHost = [URL host];
284 if (!otherHost) BAIL;
285
286 if ([myHost caseInsensitiveCompare:otherHost] != NSOrderedSame) BAIL;
287
288 NSString *myScheme = [self scheme];
289 if (!myScheme) BAIL;
290
291 NSString *otherScheme = [URL scheme];
292 if (!otherScheme) BAIL;
293
294 if ([myScheme caseInsensitiveCompare:otherScheme] != NSOrderedSame) BAIL;
180ba20 Mike Abdullah Differing port numbers should cause the same treatment as a differing ho...
mikeabdullah authored
295
296 NSNumber *myPort = [self port];
297 NSNumber *aPort = [URL port];
298 if (aPort != myPort && ![myPort isEqual:aPort]) // -isEqualToNumber: throws when passed nil
299 {
36b669c Mike Abdullah Ah, looks like I effectively broke a check for nil scheme or host. #1967...
mikeabdullah authored
300 BAIL;
180ba20 Mike Abdullah Differing port numbers should cause the same treatment as a differing ho...
mikeabdullah authored
301 }
9354734 A whole smorgasbord of URL-related methods.
Mike authored
302
303
9d96ce9 Mike Abdullah Handle http://example.com/foo relative to http://example.com/foo/ edge ...
mikeabdullah authored
304 // OK, to figure out, need my path...
f7f1ad3 Mike Abdullah More optimisation of absolute URLs.
mikeabdullah authored
305 CFURLRef absoluteSelf = CFURLCopyAbsoluteURL((CFURLRef)self);
306 CFStringRef myPath = CFURLCopyPath((CFURLRef)absoluteSelf);
307
94d1a00 Mike Abdullah Switch to using CFURLCopyPath() because:
mikeabdullah authored
308 if (!CFStringGetLength(myPath)) // e.g. http://example.com
309 {
310 CFRelease(myPath); myPath = CFRetain(CFSTR("/"));
311 }
9354734 A whole smorgasbord of URL-related methods.
Mike authored
312
9d96ce9 Mike Abdullah Handle http://example.com/foo relative to http://example.com/foo/ edge ...
mikeabdullah authored
313
314 // ... and the other path
f7f1ad3 Mike Abdullah More optimisation of absolute URLs.
mikeabdullah authored
315 CFURLRef absoluteURL = CFURLCopyAbsoluteURL((CFURLRef)URL);
316 CFStringRef dirPath = CFURLCopyPath(absoluteURL);
317
9d96ce9 Mike Abdullah Handle http://example.com/foo relative to http://example.com/foo/ edge ...
mikeabdullah authored
318 if (!CFStringGetLength(dirPath))
94d1a00 Mike Abdullah Switch to using CFURLCopyPath() because:
mikeabdullah authored
319 {
9d96ce9 Mike Abdullah Handle http://example.com/foo relative to http://example.com/foo/ edge ...
mikeabdullah authored
320 // e.g. http://example.com
321 CFRelease(dirPath); dirPath = CFRetain(CFSTR("/"));
322 }
f7f1ad3 Mike Abdullah More optimisation of absolute URLs.
mikeabdullah authored
323 else if (!CFURLHasDirectoryPath(absoluteURL)) // faster than -ks_hasDirectoryPath
9d96ce9 Mike Abdullah Handle http://example.com/foo relative to http://example.com/foo/ edge ...
mikeabdullah authored
324 {
325 NSString *shortenedPath = [(NSString *)dirPath stringByDeletingLastPathComponent];
326 CFRelease(dirPath); dirPath = CFRetain(shortenedPath);
327 }
328
f7f1ad3 Mike Abdullah More optimisation of absolute URLs.
mikeabdullah authored
329 CFRelease(absoluteURL);
330
9d96ce9 Mike Abdullah Handle http://example.com/foo relative to http://example.com/foo/ edge ...
mikeabdullah authored
331
332 // Let -ks_pathRelativeToDirectory: do the heavy lifting
333 NSString *result = [(NSString *)myPath ks_pathRelativeToDirectory:(NSString *)dirPath];
334
335 // But here's an odd edge case, http://example.com/foo relative to http://example.com/foo/ should be '../foo' which -ks_pathRelativeToDirectory returns '.' from; perfectly fine for posix, but not us!
336 if ([result isEqualToString:@"."])
337 {
338 if ([[(NSString *)myPath stringByAppendingString:@"/"] isEqualToString:(NSString *)dirPath])
94d1a00 Mike Abdullah Switch to using CFURLCopyPath() because:
mikeabdullah authored
339 {
9d96ce9 Mike Abdullah Handle http://example.com/foo relative to http://example.com/foo/ edge ...
mikeabdullah authored
340 result = [@"../" stringByAppendingString:[(NSString *)myPath lastPathComponent]];
94d1a00 Mike Abdullah Switch to using CFURLCopyPath() because:
mikeabdullah authored
341 }
342 }
53fdafa Mike Abdullah CFURLCopyPath() cannot be trusted to escape the path
mikeabdullah authored
343
9d96ce9 Mike Abdullah Handle http://example.com/foo relative to http://example.com/foo/ edge ...
mikeabdullah authored
344
53fdafa Mike Abdullah CFURLCopyPath() cannot be trusted to escape the path
mikeabdullah authored
345 // Need trailing slash?
f7f1ad3 Mike Abdullah More optimisation of absolute URLs.
mikeabdullah authored
346 if (CFURLHasDirectoryPath(absoluteSelf) && ![result hasSuffix:@"/"])
171fa9a Mike Abdullah Stop pathless URLs generating relative strings with an extra slash
mikeabdullah authored
347 {
348 result = [result stringByAppendingString:@"/"];
349 }
06977e9 Mike Abdullah Oh, and need to escape the result
mikeabdullah authored
350
351
f7f1ad3 Mike Abdullah More optimisation of absolute URLs.
mikeabdullah authored
352 // Time for a little cleanup
353 CFRelease(dirPath);
354 CFRelease(myPath);
355 CFRelease(absoluteSelf);
356
357
94d1a00 Mike Abdullah Switch to using CFURLCopyPath() because:
mikeabdullah authored
358 // Re-build any non-path information
9354734 A whole smorgasbord of URL-related methods.
Mike authored
359 NSString *parameters = [self parameterString];
360 if (parameters)
361 {
362 result = [result stringByAppendingFormat:@";%@", parameters];
363 }
364
365 NSString *query = [self query];
366 if (query)
367 {
368 result = [result stringByAppendingFormat:@"?%@", query];
369 }
370
371 NSString *fragment = [self fragment];
372 if (fragment)
373 {
374 result = [result stringByAppendingFormat:@"#%@", fragment];
375 }
376
377
378 // Finish up
379 return result;
380 }
381
382 /* Builds on -ks_stringRelativeToURL: by wrapping it into an NSURL object.
383 */
384 - (NSURL *)ks_URLRelativeToURL:(NSURL *)URL;
385 {
386 NSURL *result = nil;
387
388 NSString *relativeString = [self ks_stringRelativeToURL:URL];
389 if (relativeString)
390 {
391 result = [NSURL URLWithString:relativeString relativeToURL:URL];
392 }
393
394 return result;
395 }
396
397 #pragma mark Comparison
398
71f0acb Mike Abdullah Speed up equality testing two equal file URLs
mikeabdullah authored
399 - (BOOL)ks_isEqualToURL:(NSURL *)otherURL;
9354734 A whole smorgasbord of URL-related methods.
Mike authored
400 {
71f0acb Mike Abdullah Speed up equality testing two equal file URLs
mikeabdullah authored
401 BOOL result = [self isEqual:otherURL];
402
403 // For file: URLs the default check might have failed because they reference the host differently. If so, fall back to checking paths
404 if (!result && [self isFileURL] && [otherURL isFileURL])
9354734 A whole smorgasbord of URL-related methods.
Mike authored
405 {
71f0acb Mike Abdullah Speed up equality testing two equal file URLs
mikeabdullah authored
406 result = [[self path] isEqualToString:[otherURL path]];
9354734 A whole smorgasbord of URL-related methods.
Mike authored
407 }
71f0acb Mike Abdullah Speed up equality testing two equal file URLs
mikeabdullah authored
408
409 return result;
9354734 A whole smorgasbord of URL-related methods.
Mike authored
410 }
411
412 - (BOOL)ks_isEqualExceptFragmentToURL:(NSURL *)anotherURL
413 {
414 // cover case where both are nil
415 return ( ([self baseURL] == [anotherURL baseURL]) || [[self baseURL] isEqual:[anotherURL baseURL]] )
416 &&
417 ( ([self scheme] == [anotherURL scheme]) || [[self scheme] isEqual:[anotherURL scheme]] )
418 &&
419 ( ([self host] == [anotherURL host]) || [[self host] isEqual:[anotherURL host]] )
420 &&
421 ( ([self path] == [anotherURL path]) || [[self path] isEqual:[anotherURL path]] )
422 &&
423
424 // query == parameterString?
425
426 ( ([self query] == [anotherURL query]) || [[self query] isEqual:[anotherURL query]] )
427 &&
428 ( ([self parameterString] == [anotherURL parameterString]) || [[self parameterString] isEqual:[anotherURL parameterString]] )
429 &&
430 ( ([self baseURL] == [anotherURL baseURL]) || [[self baseURL] isEqual:[anotherURL baseURL]] )
431
432 // less common pieces, but we gotta be careful
433 &&
434 ( ([self baseURL] == [anotherURL baseURL]) || [[self baseURL] isEqual:[anotherURL baseURL]] )
435 &&
436 ( ([self port] == [anotherURL port]) || [[self port] isEqual:[anotherURL port]] )
437 &&
438 ( ([self password] == [anotherURL password]) || [[self password] isEqual:[anotherURL password]] )
439 &&
440 ( ([self user] == [anotherURL user]) || [[self user] isEqual:[anotherURL user]] )
441 ;
442
443 }
444
1eeedf4 Mike Abdullah -[NSURL ks_accessSecurityScopedResourceUsingBlock:] convenience.
mikeabdullah authored
445 #pragma mark Security-Scoped Bookmarks
446
447 - (void)ks_accessSecurityScopedResourceUsingBlock:(void (^)(BOOL started))block;
448 {
449 BOOL started = NO;
450 if ([self respondsToSelector:@selector(startAccessingSecurityScopedResource)])
451 {
452 started = [self startAccessingSecurityScopedResource];
453 }
454
455 @try
456 {
457 block(started);
458 }
459 @finally
460 {
461 if (started) [self stopAccessingSecurityScopedResource];
462 }
463 }
464
9354734 A whole smorgasbord of URL-related methods.
Mike authored
465 @end
466
467
468 #pragma mark -
469
470
471 @implementation NSString (KSURLUtilities)
472
473 - (NSString *)ks_stringByAddingPercentEscapesUsingEncoding:(NSStringEncoding)encoding
474 charactersToLeaveUnescaped:(NSString *)unescapedCharacters
475 legalURLCharactersToBeEscaped:(NSString *)legalCharactersToEscape;
476 {
477 NSString *result = NSMakeCollectable(CFURLCreateStringByAddingPercentEscapes(NULL,
478 (CFStringRef)self,
479 (CFStringRef)unescapedCharacters,
480 (CFStringRef)legalCharactersToEscape,
481 CFStringConvertNSStringEncodingToEncoding(encoding)));
482
483 return [result autorelease];
484 }
485
486 - (NSString *)ks_stringByAddingPercentEscapesWithSpacesAsPlusCharacters:(BOOL)encodeSpacesAsPlusCharacters
487 {
488 // Add the percent escapes. If encodeSpacesAsPlusCharacters has been requested, then don't both escaping them
489 NSString *charactersToLeaveUnescaped = (encodeSpacesAsPlusCharacters) ? @" " : @"";
490
491 NSString *result = [self ks_stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding
492 charactersToLeaveUnescaped:charactersToLeaveUnescaped
493 legalURLCharactersToBeEscaped:@"&+%="];
494
495
cec2f16 Updating file info.
Mike authored
496 // If the user requested it, replace spaces with + signs
9354734 A whole smorgasbord of URL-related methods.
Mike authored
497 if (encodeSpacesAsPlusCharacters)
498 {
499 NSMutableString *mutableResult = [result mutableCopy];
500 [mutableResult replaceOccurrencesOfString:@" "
501 withString:@"+"
502 options:NSLiteralSearch
503 range:NSMakeRange(0, [mutableResult length])];
504
505 result = [mutableResult autorelease];
506 }
507
508
509 return result;
510 }
511
512 // For more fine grain escaping.... we want to escape dashes when URLs are in comments.
513 - (NSString *)ks_stringByAddingPercentEscapesWithSpacesAsPlusCharacters:(BOOL)encodeSpacesAsPlusCharacters escape:(NSString *)toEscape;
514 {
515 // Add the percent escapes. If encodeSpacesAsPlusCharacters has been requested, then don't both escaping them
516 NSString *charactersToLeaveUnescaped = (encodeSpacesAsPlusCharacters) ? @" " : @"";
517
518 NSString *result = [self ks_stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding
519 charactersToLeaveUnescaped:charactersToLeaveUnescaped
520 legalURLCharactersToBeEscaped:toEscape];
521
522
523 // If the user requested it, replace sapces with + signs
524 if (encodeSpacesAsPlusCharacters)
525 {
526 NSMutableString *mutableResult = [result mutableCopy];
527 [mutableResult replaceOccurrencesOfString:@" "
528 withString:@"+"
529 options:NSLiteralSearch
530 range:NSMakeRange(0, [mutableResult length])];
531
532 result = [mutableResult autorelease];
533 }
534
535
536 return result;
537 }
538
539 /* Turns a given path into a directory path suitable for HTML.
540 *
541 * e.g. /photo_album -> /photo_album/
542 *
543 * Empty strings are ignored
544 */
545 - (NSString *)ks_URLDirectoryPath
546 {
547 NSString *result = self;
548
549 if (![self isEqualToString:@""] && ![self hasSuffix:@"/"])
550 {
551 result = [self stringByAppendingString:@"/"];
552 }
553
554 return result;
555 }
556
557 @end
Something went wrong with that request. Please try again.