Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 234 lines (187 sloc) 7.623 kB
08c3984 @mikeabdullah KSURLFormatter.
mikeabdullah authored
1 //
2 // KSURLFormatter.m
3 //
863123f @danwood update copyrights
danwood authored
4 // Copyright (c) 2008-2011, Mike Abdullah and Karelia Software
08c3984 @mikeabdullah KSURLFormatter.
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.
25 //
26
27
28 #import "KSURLFormatter.h"
29
30 #import "KSURLUtilities.h"
31
32
33 @implementation KSURLFormatter
34
35 #pragma mark Class Methods
36
37 + (NSURL *)URLFromString:(NSString *)string;
38 {
39 // Encode the URL string
40 CFStringEncoding encoding = CFStringConvertNSStringEncodingToEncoding(NSUTF8StringEncoding);
41 CFStringRef escapedString = CFURLCreateStringByAddingPercentEscapes(NULL,
42 (CFStringRef)string,
43 (CFStringRef)@"%+#",
44 NULL,
45 encoding);
46
47
48 // If we're still left with a valid string, turn it into a URL
49 NSURL *result = nil;
50 if (escapedString)
51 {
63b5b9a @mikeabdullah Actually use the escaped string for creating URL, silly me
mikeabdullah authored
52 result = [NSURL URLWithString:(NSString *)escapedString];
08c3984 @mikeabdullah KSURLFormatter.
mikeabdullah authored
53 CFRelease(escapedString);
54 }
55
56 return result;
57 }
58
83c7536 @mikeabdullah +isValidEmailAddress:
mikeabdullah authored
59 + (BOOL)isValidEmailAddress:(NSString *)address;
60 {
61 // for now, just validate that syntactically it it at least _@_.__
62 // though we are not checking actual other characters.
63 // we can refine this over time
64 NSRange whereAt = [address rangeOfString:@"@"];
65 BOOL OK = (whereAt.location != NSNotFound && whereAt.location >= 1); // make sure there is an @ and it's not the first character
66 if (OK)
67 {
68 NSInteger len = [address length] - whereAt.location;
69 NSRange whereDot = [address rangeOfString:@"." options:0 range:NSMakeRange(whereAt.location, len)];
70 OK = (whereDot.location != NSNotFound);
71 if (OK)
72 {
73 // make sure there is room between the @ and the .
74 OK = (whereDot.location - whereAt.location >= 2) && ([address length] - whereDot.location >= 3);
75 }
76 }
77 return OK;
78 }
79
08c3984 @mikeabdullah KSURLFormatter.
mikeabdullah authored
80 #pragma mark Init & Dealloc
81
82 - (id)init
83 {
84 [super init];
85 _fallbackTopLevelDomain = [@"com" retain];
86 return self;
87 }
88
89 - (void)dealloc
90 {
91 [_fallbackTopLevelDomain release];
92 [super dealloc];
93 }
94
95 #pragma mark Managing Behaviour
96
97 @synthesize useDisplayNameForFileURLs = _useDisplayNameForFileURLs;
98 @synthesize fallbackTopLevelDomain = _fallbackTopLevelDomain;
99
100 #pragma mark Textual Representation of Cell Content
101
102 - (NSString *)stringForObjectValue:(id)anObject
103 {
387441e @mikeabdullah Be more forgiving of non-URL objects
mikeabdullah authored
104 if (!anObject) return nil;
105 if (![anObject isKindOfClass:[NSURL class]]) return [anObject description];
08c3984 @mikeabdullah KSURLFormatter.
mikeabdullah authored
106
387441e @mikeabdullah Be more forgiving of non-URL objects
mikeabdullah authored
107
108 NSURL *URL = anObject;
109
110 NSString *result;
111 if ([self useDisplayNameForFileURLs] && [anObject isFileURL])
08c3984 @mikeabdullah KSURLFormatter.
mikeabdullah authored
112 {
387441e @mikeabdullah Be more forgiving of non-URL objects
mikeabdullah authored
113 result = [[NSFileManager defaultManager] displayNameAtPath:[URL path]];
114 }
115 else
116 {
117 result = [URL absoluteString];
118
119 // Append trailing slash if needed
120 if ([URL ks_hasNetworkLocation] && [[URL path] isEqualToString:@""])
08c3984 @mikeabdullah KSURLFormatter.
mikeabdullah authored
121 {
387441e @mikeabdullah Be more forgiving of non-URL objects
mikeabdullah authored
122 result = [result stringByAppendingString:@"/"];
08c3984 @mikeabdullah KSURLFormatter.
mikeabdullah authored
123 }
124 }
125
126 return result;
127 }
128
129 #pragma mark Object Equivalent to Textual Representation
130
131 + (NSURL *)URLFromString:(NSString *)string fallbackScheme:(NSString *)fallbackScheme;
132 {
133 // Tries to interpret the string as a complete URL. If there is no scheme specified, try it as an email address. If that doesn't seem reasonable, combine with fallbackScheme
134
135
136 NSURL *result = [self URLFromString:string];
137
9de9b7d @mikeabdullah Treat hostless URLs (e.g. example.com:8888) like schemeless URLs (e.g…
mikeabdullah authored
138 // This is probably a really naive check
139 if ((![result scheme] && ![string hasPrefix:@"/"]) || // e.g. foo
140 (![result host])) // e.g. foo.com:8888
08c3984 @mikeabdullah KSURLFormatter.
mikeabdullah authored
141 {
142 // if it looks like an email address, use mailto:
83c7536 @mikeabdullah +isValidEmailAddress:
mikeabdullah authored
143 if ([self isValidEmailAddress:string])
08c3984 @mikeabdullah KSURLFormatter.
mikeabdullah authored
144 {
145 result = [NSURL URLWithString:[NSString stringWithFormat:@"mailto:%@", string]];
146 }
147 else
148 {
149 result = [self URLFromString:[NSString stringWithFormat:
150 @"%@://%@",
151 fallbackScheme,
152 string]];
153 }
154 }
5cd1d9b @mikeabdullah Correct URLs to have a trailing slash if needed
mikeabdullah authored
155
156
157 // Append a trailing slash if needed
158 if ([result ks_hasNetworkLocation] && [[result path] isEqualToString:@""])
159 {
160 result = [[NSURL URLWithString:@"/" relativeToURL:result] absoluteURL];
161 }
08c3984 @mikeabdullah KSURLFormatter.
mikeabdullah authored
162
163 return result;
164 }
165
166 - (BOOL)getObjectValue:(id *)anObject forString:(NSString *)string errorDescription:(NSString **)error
167 {
168 BOOL result = YES;
169 NSURL *URL = nil;
170
171 if ([string length] > 0)
172 {
173 URL = [KSURLFormatter URLFromString:string fallbackScheme:@"http"];
174
175
176 // Does the URL have no useful resource specified? If so, generate nil URL
56b5693 @mikeabdullah mailto: URLs are valid
mikeabdullah authored
177 if (URL && ![[URL scheme] isEqualToString:@"mailto"])
08c3984 @mikeabdullah KSURLFormatter.
mikeabdullah authored
178 {
179 NSString *resource = [URL resourceSpecifier];
180 if ([resource length] == 0 ||
181 [resource isEqualToString:@"/"] ||
182 [resource isEqualToString:@"//"])
183 {
184 URL = nil;
185 }
56b5693 @mikeabdullah mailto: URLs are valid
mikeabdullah authored
186
187
188
189 // URLs should also really have a host and a path
190 if (URL)
191 {
192 NSString *host = [URL host];
193 NSString *path = [URL path];
194 if (!host && !path)
195 {
196 URL = nil;
197 }
08c3984 @mikeabdullah KSURLFormatter.
mikeabdullah authored
198 }
199 }
200
201
202 // Did the user not enter a top-level domain? We'll guess for them
203 if (URL && [self fallbackTopLevelDomain])
204 {
205 if ([[URL ks_domains] count] == 1)
206 {
207 NSString *urlString = [NSString stringWithFormat:
208 @"%@://%@.%@/",
209 [URL scheme],
210 [URL host],
211 [self fallbackTopLevelDomain]];
212 URL = [NSURL URLWithString:urlString];
213 }
214 }
215 }
216
217
218 // Finish up
219 if (result && anObject) *anObject = URL;
220 return result;
221 }
222
223 - (NSURL *)URLFromString:(NSString *)string;
224 {
225 NSURL *result = nil;
226
227 NSURL *URL;
228 if ([self getObjectValue:&URL forString:string errorDescription:NULL]) result = URL;
229
230 return result;
231 }
232
233 @end
Something went wrong with that request. Please try again.