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