|
1 /* |
|
2 * Copyright (C) 2005, 2006, 2007, 2008 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 "WebArchive.h" |
|
30 #import "WebArchiveInternal.h" |
|
31 |
|
32 #import "WebKitLogging.h" |
|
33 #import "WebNSObjectExtras.h" |
|
34 #import "WebResourceInternal.h" |
|
35 #import "WebTypesInternal.h" |
|
36 #import <JavaScriptCore/InitializeThreading.h> |
|
37 #import <WebCore/ArchiveResource.h> |
|
38 #import <WebCore/LegacyWebArchive.h> |
|
39 #import <WebCore/ThreadCheck.h> |
|
40 #import <WebCore/WebCoreObjCExtras.h> |
|
41 #import <wtf/Threading.h> |
|
42 |
|
43 using namespace WebCore; |
|
44 |
|
45 NSString *WebArchivePboardType = @"Apple Web Archive pasteboard type"; |
|
46 |
|
47 static NSString * const WebMainResourceKey = @"WebMainResource"; |
|
48 static NSString * const WebSubresourcesKey = @"WebSubresources"; |
|
49 static NSString * const WebSubframeArchivesKey = @"WebSubframeArchives"; |
|
50 |
|
51 @interface WebArchivePrivate : NSObject { |
|
52 @public |
|
53 WebResource *cachedMainResource; |
|
54 NSArray *cachedSubresources; |
|
55 NSArray *cachedSubframeArchives; |
|
56 @private |
|
57 RefPtr<LegacyWebArchive> coreArchive; |
|
58 } |
|
59 |
|
60 - (id)initWithCoreArchive:(PassRefPtr<LegacyWebArchive>)coreArchive; |
|
61 - (LegacyWebArchive*)coreArchive; |
|
62 - (void)setCoreArchive:(PassRefPtr<LegacyWebArchive>)newCoreArchive; |
|
63 @end |
|
64 |
|
65 @implementation WebArchivePrivate |
|
66 |
|
67 + (void)initialize |
|
68 { |
|
69 JSC::initializeThreading(); |
|
70 WTF::initializeMainThreadToProcessMainThread(); |
|
71 #ifndef BUILDING_ON_TIGER |
|
72 WebCoreObjCFinalizeOnMainThread(self); |
|
73 #endif |
|
74 } |
|
75 |
|
76 - (id)init |
|
77 { |
|
78 self = [super init]; |
|
79 if (!self) |
|
80 return nil; |
|
81 coreArchive = LegacyWebArchive::create(); |
|
82 return self; |
|
83 } |
|
84 |
|
85 - (id)initWithCoreArchive:(PassRefPtr<LegacyWebArchive>)_coreArchive |
|
86 { |
|
87 self = [super init]; |
|
88 if (!self || !_coreArchive) { |
|
89 [self release]; |
|
90 return nil; |
|
91 } |
|
92 coreArchive = _coreArchive; |
|
93 return self; |
|
94 } |
|
95 |
|
96 - (LegacyWebArchive*)coreArchive |
|
97 { |
|
98 return coreArchive.get(); |
|
99 } |
|
100 |
|
101 - (void)setCoreArchive:(PassRefPtr<LegacyWebArchive>)newCoreArchive |
|
102 { |
|
103 ASSERT(coreArchive); |
|
104 ASSERT(newCoreArchive); |
|
105 coreArchive = newCoreArchive; |
|
106 } |
|
107 |
|
108 - (void)dealloc |
|
109 { |
|
110 if (WebCoreObjCScheduleDeallocateOnMainThread([WebArchivePrivate class], self)) |
|
111 return; |
|
112 |
|
113 [cachedMainResource release]; |
|
114 [cachedSubresources release]; |
|
115 [cachedSubframeArchives release]; |
|
116 |
|
117 [super dealloc]; |
|
118 } |
|
119 |
|
120 @end |
|
121 |
|
122 @implementation WebArchive |
|
123 |
|
124 - (id)init |
|
125 { |
|
126 WebCoreThreadViolationCheckRoundTwo(); |
|
127 |
|
128 self = [super init]; |
|
129 if (!self) |
|
130 return nil; |
|
131 _private = [[WebArchivePrivate alloc] init]; |
|
132 return self; |
|
133 } |
|
134 |
|
135 static BOOL isArrayOfClass(id object, Class elementClass) |
|
136 { |
|
137 if (![object isKindOfClass:[NSArray class]]) |
|
138 return NO; |
|
139 NSArray *array = (NSArray *)object; |
|
140 NSUInteger count = [array count]; |
|
141 for (NSUInteger i = 0; i < count; ++i) |
|
142 if (![[array objectAtIndex:i] isKindOfClass:elementClass]) |
|
143 return NO; |
|
144 return YES; |
|
145 } |
|
146 |
|
147 - (id)initWithMainResource:(WebResource *)mainResource subresources:(NSArray *)subresources subframeArchives:(NSArray *)subframeArchives |
|
148 { |
|
149 #ifdef MAIL_THREAD_WORKAROUND |
|
150 if (needMailThreadWorkaround()) |
|
151 return [[self _webkit_invokeOnMainThread] initWithMainResource:mainResource subresources:subresources subframeArchives:subframeArchives]; |
|
152 #endif |
|
153 |
|
154 WebCoreThreadViolationCheckRoundTwo(); |
|
155 |
|
156 self = [super init]; |
|
157 if (!self) |
|
158 return nil; |
|
159 |
|
160 _private = [[WebArchivePrivate alloc] init]; |
|
161 |
|
162 _private->cachedMainResource = [mainResource retain]; |
|
163 if (!_private->cachedMainResource) { |
|
164 [self release]; |
|
165 return nil; |
|
166 } |
|
167 |
|
168 if (!subresources || isArrayOfClass(subresources, [WebResource class])) |
|
169 _private->cachedSubresources = [subresources retain]; |
|
170 else { |
|
171 [self release]; |
|
172 return nil; |
|
173 } |
|
174 |
|
175 if (!subframeArchives || isArrayOfClass(subframeArchives, [WebArchive class])) |
|
176 _private->cachedSubframeArchives = [subframeArchives retain]; |
|
177 else { |
|
178 [self release]; |
|
179 return nil; |
|
180 } |
|
181 |
|
182 RefPtr<ArchiveResource> coreMainResource = mainResource ? [mainResource _coreResource] : 0; |
|
183 |
|
184 Vector<PassRefPtr<ArchiveResource> > coreResources; |
|
185 NSEnumerator *enumerator = [subresources objectEnumerator]; |
|
186 WebResource *subresource; |
|
187 while ((subresource = [enumerator nextObject]) != nil) |
|
188 coreResources.append([subresource _coreResource]); |
|
189 |
|
190 Vector<PassRefPtr<LegacyWebArchive> > coreArchives; |
|
191 enumerator = [subframeArchives objectEnumerator]; |
|
192 WebArchive *subframeArchive; |
|
193 while ((subframeArchive = [enumerator nextObject]) != nil) |
|
194 coreArchives.append([subframeArchive->_private coreArchive]); |
|
195 |
|
196 [_private setCoreArchive:LegacyWebArchive::create(coreMainResource.release(), coreResources, coreArchives)]; |
|
197 if (![_private coreArchive]) { |
|
198 [self release]; |
|
199 return nil; |
|
200 } |
|
201 |
|
202 return self; |
|
203 } |
|
204 |
|
205 - (id)initWithData:(NSData *)data |
|
206 { |
|
207 WebCoreThreadViolationCheckRoundTwo(); |
|
208 |
|
209 self = [super init]; |
|
210 if (!self) |
|
211 return nil; |
|
212 |
|
213 #if !LOG_DISABLED |
|
214 CFAbsoluteTime start = CFAbsoluteTimeGetCurrent(); |
|
215 #endif |
|
216 |
|
217 _private = [[WebArchivePrivate alloc] init]; |
|
218 RefPtr<LegacyWebArchive> coreArchive = LegacyWebArchive::create(SharedBuffer::wrapNSData(data).get()); |
|
219 if (!coreArchive) { |
|
220 [self release]; |
|
221 return nil; |
|
222 } |
|
223 |
|
224 [_private setCoreArchive:coreArchive.release()]; |
|
225 |
|
226 #if !LOG_DISABLED |
|
227 CFAbsoluteTime end = CFAbsoluteTimeGetCurrent(); |
|
228 CFAbsoluteTime duration = end - start; |
|
229 #endif |
|
230 LOG(Timing, "Parsing web archive with [NSPropertyListSerialization propertyListFromData::::] took %f seconds", duration); |
|
231 |
|
232 return self; |
|
233 } |
|
234 |
|
235 - (id)initWithCoder:(NSCoder *)decoder |
|
236 { |
|
237 WebResource *mainResource = nil; |
|
238 NSArray *subresources = nil; |
|
239 NSArray *subframeArchives = nil; |
|
240 |
|
241 @try { |
|
242 id object = [decoder decodeObjectForKey:WebMainResourceKey]; |
|
243 if ([object isKindOfClass:[WebResource class]]) |
|
244 mainResource = object; |
|
245 object = [decoder decodeObjectForKey:WebSubresourcesKey]; |
|
246 if (isArrayOfClass(object, [WebResource class])) |
|
247 subresources = object; |
|
248 object = [decoder decodeObjectForKey:WebSubframeArchivesKey]; |
|
249 if (isArrayOfClass(object, [WebArchive class])) |
|
250 subframeArchives = object; |
|
251 } @catch(id) { |
|
252 [self release]; |
|
253 return nil; |
|
254 } |
|
255 |
|
256 return [self initWithMainResource:mainResource subresources:subresources subframeArchives:subframeArchives]; |
|
257 } |
|
258 |
|
259 - (void)encodeWithCoder:(NSCoder *)encoder |
|
260 { |
|
261 [encoder encodeObject:[self mainResource] forKey:WebMainResourceKey]; |
|
262 [encoder encodeObject:[self subresources] forKey:WebSubresourcesKey]; |
|
263 [encoder encodeObject:[self subframeArchives] forKey:WebSubframeArchivesKey]; |
|
264 } |
|
265 |
|
266 - (void)dealloc |
|
267 { |
|
268 [_private release]; |
|
269 [super dealloc]; |
|
270 } |
|
271 |
|
272 - (id)copyWithZone:(NSZone *)zone |
|
273 { |
|
274 return [self retain]; |
|
275 } |
|
276 |
|
277 - (WebResource *)mainResource |
|
278 { |
|
279 #ifdef MAIL_THREAD_WORKAROUND |
|
280 if (needMailThreadWorkaround()) |
|
281 return [[self _webkit_invokeOnMainThread] mainResource]; |
|
282 #endif |
|
283 |
|
284 WebCoreThreadViolationCheckRoundTwo(); |
|
285 |
|
286 // Currently from WebKit API perspective, WebArchives are entirely immutable once created |
|
287 // If they ever become mutable, we'll need to rethink this. |
|
288 if (!_private->cachedMainResource) { |
|
289 LegacyWebArchive* coreArchive = [_private coreArchive]; |
|
290 if (coreArchive) |
|
291 _private->cachedMainResource = [[WebResource alloc] _initWithCoreResource:coreArchive->mainResource()]; |
|
292 } |
|
293 |
|
294 return [[_private->cachedMainResource retain] autorelease]; |
|
295 } |
|
296 |
|
297 - (NSArray *)subresources |
|
298 { |
|
299 #ifdef MAIL_THREAD_WORKAROUND |
|
300 if (needMailThreadWorkaround()) |
|
301 return [[self _webkit_invokeOnMainThread] subresources]; |
|
302 #endif |
|
303 |
|
304 WebCoreThreadViolationCheckRoundTwo(); |
|
305 |
|
306 // Currently from WebKit API perspective, WebArchives are entirely immutable once created |
|
307 // If they ever become mutable, we'll need to rethink this. |
|
308 if (!_private->cachedSubresources) { |
|
309 LegacyWebArchive* coreArchive = [_private coreArchive]; |
|
310 if (!coreArchive) |
|
311 _private->cachedSubresources = [[NSArray alloc] init]; |
|
312 else { |
|
313 const Vector<RefPtr<ArchiveResource> >& subresources(coreArchive->subresources()); |
|
314 NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithCapacity:subresources.size()]; |
|
315 _private->cachedSubresources = mutableArray; |
|
316 for (unsigned i = 0; i < subresources.size(); ++i) { |
|
317 WebResource *resource = [[WebResource alloc] _initWithCoreResource:subresources[i].get()]; |
|
318 if (resource) { |
|
319 [mutableArray addObject:resource]; |
|
320 [resource release]; |
|
321 } |
|
322 } |
|
323 } |
|
324 } |
|
325 // Maintain the WebKit 3 behavior of this API, which is documented and |
|
326 // relied upon by some clients, of returning nil if there are no subresources. |
|
327 return [_private->cachedSubresources count] ? [[_private->cachedSubresources retain] autorelease] : nil; |
|
328 } |
|
329 |
|
330 - (NSArray *)subframeArchives |
|
331 { |
|
332 #ifdef MAIL_THREAD_WORKAROUND |
|
333 if (needMailThreadWorkaround()) |
|
334 return [[self _webkit_invokeOnMainThread] subframeArchives]; |
|
335 #endif |
|
336 |
|
337 WebCoreThreadViolationCheckRoundTwo(); |
|
338 |
|
339 // Currently from WebKit API perspective, WebArchives are entirely immutable once created |
|
340 // If they ever become mutable, we'll need to rethink this. |
|
341 if (!_private->cachedSubframeArchives) { |
|
342 LegacyWebArchive* coreArchive = [_private coreArchive]; |
|
343 if (!coreArchive) |
|
344 _private->cachedSubframeArchives = [[NSArray alloc] init]; |
|
345 else { |
|
346 const Vector<RefPtr<Archive> >& subframeArchives(coreArchive->subframeArchives()); |
|
347 NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithCapacity:subframeArchives.size()]; |
|
348 _private->cachedSubframeArchives = mutableArray; |
|
349 for (unsigned i = 0; i < subframeArchives.size(); ++i) { |
|
350 WebArchive *archive = [[WebArchive alloc] _initWithCoreLegacyWebArchive:(LegacyWebArchive *)subframeArchives[i].get()]; |
|
351 [mutableArray addObject:archive]; |
|
352 [archive release]; |
|
353 } |
|
354 } |
|
355 } |
|
356 |
|
357 return [[_private->cachedSubframeArchives retain] autorelease]; |
|
358 } |
|
359 |
|
360 - (NSData *)data |
|
361 { |
|
362 WebCoreThreadViolationCheckRoundTwo(); |
|
363 |
|
364 #if !LOG_DISABLED |
|
365 CFAbsoluteTime start = CFAbsoluteTimeGetCurrent(); |
|
366 #endif |
|
367 |
|
368 RetainPtr<CFDataRef> data = [_private coreArchive]->rawDataRepresentation(); |
|
369 |
|
370 #if !LOG_DISABLED |
|
371 CFAbsoluteTime end = CFAbsoluteTimeGetCurrent(); |
|
372 CFAbsoluteTime duration = end - start; |
|
373 #endif |
|
374 LOG(Timing, "Serializing web archive to raw CFPropertyList data took %f seconds", duration); |
|
375 |
|
376 return [[(NSData *)data.get() retain] autorelease]; |
|
377 } |
|
378 |
|
379 @end |
|
380 |
|
381 @implementation WebArchive (WebInternal) |
|
382 |
|
383 - (id)_initWithCoreLegacyWebArchive:(PassRefPtr<WebCore::LegacyWebArchive>)coreLegacyWebArchive |
|
384 { |
|
385 WebCoreThreadViolationCheckRoundTwo(); |
|
386 |
|
387 self = [super init]; |
|
388 if (!self) |
|
389 return nil; |
|
390 |
|
391 _private = [[WebArchivePrivate alloc] initWithCoreArchive:coreLegacyWebArchive]; |
|
392 if (!_private) { |
|
393 [self release]; |
|
394 return nil; |
|
395 } |
|
396 |
|
397 return self; |
|
398 } |
|
399 |
|
400 - (WebCore::LegacyWebArchive *)_coreLegacyWebArchive |
|
401 { |
|
402 WebCoreThreadViolationCheckRoundTwo(); |
|
403 |
|
404 return [_private coreArchive]; |
|
405 } |
|
406 |
|
407 @end |