|
1 /* |
|
2 * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. |
|
3 * |
|
4 * Redistribution and use in source and binary forms, with or without |
|
5 * modification, are permitted provided that the following conditions |
|
6 * are met: |
|
7 * |
|
8 * 1. Redistributions of source code must retain the above copyright |
|
9 * notice, this list of conditions and the following disclaimer. |
|
10 * 2. Redistributions in binary form must reproduce the above copyright |
|
11 * notice, this list of conditions and the following disclaimer in the |
|
12 * documentation and/or other materials provided with the distribution. |
|
13 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of |
|
14 * its contributors may be used to endorse or promote products derived |
|
15 * from this software without specific prior written permission. |
|
16 * |
|
17 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
|
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
|
19 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
|
20 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
|
21 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
|
22 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
|
23 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
|
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
|
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
|
27 */ |
|
28 |
|
29 #import "WebResourcePrivate.h" |
|
30 |
|
31 #import "WebFrameBridge.h" |
|
32 #import "WebNSDictionaryExtras.h" |
|
33 #import "WebNSURLExtras.h" |
|
34 |
|
35 static NSString * const WebResourceDataKey = @"WebResourceData"; |
|
36 static NSString * const WebResourceFrameNameKey = @"WebResourceFrameName"; |
|
37 static NSString * const WebResourceMIMETypeKey = @"WebResourceMIMEType"; |
|
38 static NSString * const WebResourceURLKey = @"WebResourceURL"; |
|
39 static NSString * const WebResourceTextEncodingNameKey = @"WebResourceTextEncodingName"; |
|
40 static NSString * const WebResourceResponseKey = @"WebResourceResponse"; |
|
41 |
|
42 #define WebResourceVersion 1 |
|
43 |
|
44 @interface WebResourcePrivate : NSObject |
|
45 { |
|
46 @public |
|
47 NSData *data; |
|
48 NSURL *URL; |
|
49 NSString *frameName; |
|
50 NSString *MIMEType; |
|
51 NSString *textEncodingName; |
|
52 NSURLResponse *response; |
|
53 BOOL shouldIgnoreWhenUnarchiving; |
|
54 } |
|
55 @end |
|
56 |
|
57 @implementation WebResourcePrivate |
|
58 |
|
59 - (void)dealloc |
|
60 { |
|
61 [data release]; |
|
62 [URL release]; |
|
63 [frameName release]; |
|
64 [MIMEType release]; |
|
65 [textEncodingName release]; |
|
66 [response release]; |
|
67 [super dealloc]; |
|
68 } |
|
69 |
|
70 @end |
|
71 |
|
72 @implementation WebResource |
|
73 |
|
74 - (id)init |
|
75 { |
|
76 self = [super init]; |
|
77 if (!self) |
|
78 return nil; |
|
79 _private = [[WebResourcePrivate alloc] init]; |
|
80 return self; |
|
81 } |
|
82 |
|
83 - (id)initWithData:(NSData *)data URL:(NSURL *)URL MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)textEncodingName frameName:(NSString *)frameName |
|
84 { |
|
85 return [self _initWithData:data URL:URL MIMEType:MIMEType textEncodingName:textEncodingName frameName:frameName response:nil copyData:YES]; |
|
86 } |
|
87 |
|
88 - (id)initWithCoder:(NSCoder *)decoder |
|
89 { |
|
90 self = [self init]; |
|
91 if (!self) |
|
92 return nil; |
|
93 |
|
94 @try { |
|
95 id object = [decoder decodeObjectForKey:WebResourceDataKey]; |
|
96 if ([object isKindOfClass:[NSData class]]) |
|
97 _private->data = [object retain]; |
|
98 object = [decoder decodeObjectForKey:WebResourceURLKey]; |
|
99 if ([object isKindOfClass:[NSURL class]]) |
|
100 _private->URL = [object retain]; |
|
101 object = [decoder decodeObjectForKey:WebResourceMIMETypeKey]; |
|
102 if ([object isKindOfClass:[NSString class]]) |
|
103 _private->MIMEType = [object retain]; |
|
104 object = [decoder decodeObjectForKey:WebResourceTextEncodingNameKey]; |
|
105 if ([object isKindOfClass:[NSString class]]) |
|
106 _private->textEncodingName = [object retain]; |
|
107 object = [decoder decodeObjectForKey:WebResourceFrameNameKey]; |
|
108 if ([object isKindOfClass:[NSString class]]) |
|
109 _private->frameName = [object retain]; |
|
110 object = [decoder decodeObjectForKey:WebResourceResponseKey]; |
|
111 if ([object isKindOfClass:[NSURLResponse class]]) |
|
112 _private->response = [object retain]; |
|
113 } @catch(id) { |
|
114 [self release]; |
|
115 return nil; |
|
116 } |
|
117 |
|
118 return self; |
|
119 } |
|
120 |
|
121 - (void)encodeWithCoder:(NSCoder *)encoder |
|
122 { |
|
123 [encoder encodeObject:_private->data forKey:WebResourceDataKey]; |
|
124 [encoder encodeObject:_private->URL forKey:WebResourceURLKey]; |
|
125 [encoder encodeObject:_private->MIMEType forKey:WebResourceMIMETypeKey]; |
|
126 [encoder encodeObject:_private->textEncodingName forKey:WebResourceTextEncodingNameKey]; |
|
127 [encoder encodeObject:_private->frameName forKey:WebResourceFrameNameKey]; |
|
128 [encoder encodeObject:_private->response forKey:WebResourceResponseKey]; |
|
129 } |
|
130 |
|
131 - (void)dealloc |
|
132 { |
|
133 [_private release]; |
|
134 [super dealloc]; |
|
135 } |
|
136 |
|
137 - (id)copyWithZone:(NSZone *)zone |
|
138 { |
|
139 return [self retain]; |
|
140 } |
|
141 |
|
142 - (NSData *)data |
|
143 { |
|
144 return _private->data; |
|
145 } |
|
146 |
|
147 - (NSURL *)URL |
|
148 { |
|
149 return _private->URL; |
|
150 } |
|
151 |
|
152 - (NSString *)MIMEType |
|
153 { |
|
154 return _private->MIMEType; |
|
155 } |
|
156 |
|
157 - (NSString *)textEncodingName |
|
158 { |
|
159 return _private->textEncodingName; |
|
160 } |
|
161 |
|
162 - (NSString *)frameName |
|
163 { |
|
164 return _private->frameName; |
|
165 } |
|
166 |
|
167 - (id)description |
|
168 { |
|
169 return [NSString stringWithFormat:@"<%@ %@>", [self className], [self URL]]; |
|
170 } |
|
171 |
|
172 @end |
|
173 |
|
174 @implementation WebResource (WebResourcePrivate) |
|
175 |
|
176 // SPI for Mail (5066325) |
|
177 - (void)_ignoreWhenUnarchiving |
|
178 { |
|
179 _private->shouldIgnoreWhenUnarchiving = YES; |
|
180 } |
|
181 |
|
182 - (BOOL)_shouldIgnoreWhenUnarchiving |
|
183 { |
|
184 return _private->shouldIgnoreWhenUnarchiving; |
|
185 } |
|
186 |
|
187 + (NSArray *)_resourcesFromPropertyLists:(NSArray *)propertyLists |
|
188 { |
|
189 if (![propertyLists isKindOfClass:[NSArray class]]) { |
|
190 return nil; |
|
191 } |
|
192 NSEnumerator *enumerator = [propertyLists objectEnumerator]; |
|
193 NSMutableArray *resources = [NSMutableArray array]; |
|
194 NSDictionary *propertyList; |
|
195 while ((propertyList = [enumerator nextObject]) != nil) { |
|
196 WebResource *resource = [[WebResource alloc] _initWithPropertyList:propertyList]; |
|
197 if (resource) { |
|
198 [resources addObject:resource]; |
|
199 [resource release]; |
|
200 } |
|
201 } |
|
202 return resources; |
|
203 } |
|
204 |
|
205 + (NSArray *)_propertyListsFromResources:(NSArray *)resources |
|
206 { |
|
207 NSEnumerator *enumerator = [resources objectEnumerator]; |
|
208 NSMutableArray *propertyLists = [NSMutableArray array]; |
|
209 WebResource *resource; |
|
210 while ((resource = [enumerator nextObject]) != nil) { |
|
211 [propertyLists addObject:[resource _propertyListRepresentation]]; |
|
212 } |
|
213 return propertyLists; |
|
214 } |
|
215 |
|
216 - (id)_initWithData:(NSData *)data |
|
217 URL:(NSURL *)URL |
|
218 MIMEType:(NSString *)MIMEType |
|
219 textEncodingName:(NSString *)textEncodingName |
|
220 frameName:(NSString *)frameName |
|
221 response:(NSURLResponse *)response |
|
222 copyData:(BOOL)copyData |
|
223 { |
|
224 [self init]; |
|
225 |
|
226 if (!data) { |
|
227 [self release]; |
|
228 return nil; |
|
229 } |
|
230 _private->data = copyData ? [data copy] : [data retain]; |
|
231 |
|
232 if (!URL) { |
|
233 [self release]; |
|
234 return nil; |
|
235 } |
|
236 _private->URL = [URL copy]; |
|
237 |
|
238 if (!MIMEType) { |
|
239 [self release]; |
|
240 return nil; |
|
241 } |
|
242 _private->MIMEType = [MIMEType copy]; |
|
243 |
|
244 _private->textEncodingName = [textEncodingName copy]; |
|
245 _private->frameName = [frameName copy]; |
|
246 _private->response = [response retain]; |
|
247 |
|
248 return self; |
|
249 } |
|
250 |
|
251 - (id)_initWithData:(NSData *)data URL:(NSURL *)URL response:(NSURLResponse *)response |
|
252 { |
|
253 // Pass NO for copyData since the data doesn't need to be copied since we know that callers will no longer modify it. |
|
254 // Copying it will also cause a performance regression. |
|
255 return [self _initWithData:data |
|
256 URL:URL |
|
257 MIMEType:[response MIMEType] |
|
258 textEncodingName:[response textEncodingName] |
|
259 frameName:nil |
|
260 response:response |
|
261 copyData:NO]; |
|
262 } |
|
263 |
|
264 - (id)_initWithPropertyList:(id)propertyList |
|
265 { |
|
266 if (![propertyList isKindOfClass:[NSDictionary class]]) { |
|
267 [self release]; |
|
268 return nil; |
|
269 } |
|
270 |
|
271 NSURLResponse *response = nil; |
|
272 NSData *responseData = [propertyList objectForKey:WebResourceResponseKey]; |
|
273 if ([responseData isKindOfClass:[NSData class]]) { |
|
274 NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:responseData]; |
|
275 @try { |
|
276 id responseObject = [unarchiver decodeObjectForKey:WebResourceResponseKey]; |
|
277 if ([responseObject isKindOfClass:[NSURLResponse class]]) |
|
278 response = responseObject; |
|
279 [unarchiver finishDecoding]; |
|
280 } @catch(id) { |
|
281 response = nil; |
|
282 } |
|
283 [unarchiver release]; |
|
284 } |
|
285 |
|
286 NSData *data = [propertyList objectForKey:WebResourceDataKey]; |
|
287 NSString *URLString = [propertyList _webkit_stringForKey:WebResourceURLKey]; |
|
288 return [self _initWithData:[data isKindOfClass:[NSData class]] ? data : nil |
|
289 URL:URLString ? [NSURL _web_URLWithDataAsString:URLString] : nil |
|
290 MIMEType:[propertyList _webkit_stringForKey:WebResourceMIMETypeKey] |
|
291 textEncodingName:[propertyList _webkit_stringForKey:WebResourceTextEncodingNameKey] |
|
292 frameName:[propertyList _webkit_stringForKey:WebResourceFrameNameKey] |
|
293 response:response |
|
294 copyData:NO]; |
|
295 } |
|
296 |
|
297 - (NSFileWrapper *)_fileWrapperRepresentation |
|
298 { |
|
299 NSFileWrapper *wrapper = [[[NSFileWrapper alloc] initRegularFileWithContents:_private->data] autorelease]; |
|
300 NSString *preferredFilename = [_private->response suggestedFilename]; |
|
301 if (!preferredFilename || ![preferredFilename length]) |
|
302 preferredFilename = [_private->URL _webkit_suggestedFilenameWithMIMEType:_private->MIMEType]; |
|
303 [wrapper setPreferredFilename:preferredFilename]; |
|
304 return wrapper; |
|
305 } |
|
306 |
|
307 - (id)_propertyListRepresentation |
|
308 { |
|
309 NSMutableDictionary *propertyList = [NSMutableDictionary dictionary]; |
|
310 [propertyList setObject:_private->data forKey:WebResourceDataKey]; |
|
311 [propertyList setObject:[_private->URL _web_originalDataAsString] forKey:WebResourceURLKey]; |
|
312 [propertyList setObject:_private->MIMEType forKey:WebResourceMIMETypeKey]; |
|
313 if (_private->textEncodingName != nil) { |
|
314 [propertyList setObject:_private->textEncodingName forKey:WebResourceTextEncodingNameKey]; |
|
315 } |
|
316 if (_private->frameName != nil) { |
|
317 [propertyList setObject:_private->frameName forKey:WebResourceFrameNameKey]; |
|
318 } |
|
319 if (_private->response != nil) { |
|
320 NSMutableData *responseData = [[NSMutableData alloc] init]; |
|
321 NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:responseData]; |
|
322 [archiver encodeObject:_private->response forKey:WebResourceResponseKey]; |
|
323 [archiver finishEncoding]; |
|
324 [archiver release]; |
|
325 [propertyList setObject:responseData forKey:WebResourceResponseKey]; |
|
326 [responseData release]; |
|
327 } |
|
328 return propertyList; |
|
329 } |
|
330 |
|
331 - (NSURLResponse *)_response |
|
332 { |
|
333 if (_private->response != nil) { |
|
334 return _private->response; |
|
335 } |
|
336 return [[[NSURLResponse alloc] initWithURL:_private->URL |
|
337 MIMEType:_private->MIMEType |
|
338 expectedContentLength:[_private->data length] |
|
339 textEncodingName:_private->textEncodingName] autorelease]; |
|
340 } |
|
341 |
|
342 - (NSString *)_stringValue |
|
343 { |
|
344 NSString *textEncodingName = [self textEncodingName]; |
|
345 return [WebFrameBridge stringWithData:_private->data textEncodingName:textEncodingName]; |
|
346 } |
|
347 |
|
348 @end |