/*
* Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "WebArchive.h"
#import "WebKitLogging.h"
#import "WebResourcePrivate.h"
#import "WebTypesInternal.h"
NSString *WebArchivePboardType = @"Apple Web Archive pasteboard type";
static NSString * const WebMainResourceKey = @"WebMainResource";
static NSString * const WebSubresourcesKey = @"WebSubresources";
static NSString * const WebSubframeArchivesKey = @"WebSubframeArchives";
@interface WebArchivePrivate : NSObject
{
@public
WebResource *mainResource;
NSArray *subresources;
NSArray *subframeArchives;
}
@end
@implementation WebArchivePrivate
- (void)dealloc
{
[mainResource release];
[subresources release];
[subframeArchives release];
[super dealloc];
}
@end
static BOOL isArrayOfClass(id object, Class elementClass)
{
if (![object isKindOfClass:[NSArray class]])
return NO;
NSArray *array = (NSArray *)object;
NSUInteger count = [array count];
for (NSUInteger i = 0; i < count; ++i)
if (![[array objectAtIndex:i] isKindOfClass:elementClass])
return NO;
return YES;
}
@implementation WebArchive
- (id)init
{
self = [super init];
if (!self)
return nil;
_private = [[WebArchivePrivate alloc] init];
return self;
}
- (id)initWithMainResource:(WebResource *)mainResource subresources:(NSArray *)subresources subframeArchives:(NSArray *)subframeArchives
{
self = [self init];
if (!self)
return nil;
_private->mainResource = [mainResource retain];
_private->subresources = [subresources retain];
_private->subframeArchives = [subframeArchives retain];
if (!_private->mainResource) {
[self release];
return nil;
}
return self;
}
- (id)_initWithPropertyList:(id)propertyList
{
self = [self init];
if (!self)
return nil;
if (![propertyList isKindOfClass:[NSDictionary class]]) {
[self release];
return nil;
}
_private->mainResource = [[WebResource alloc] _initWithPropertyList:[propertyList objectForKey:WebMainResourceKey]];
if (!_private->mainResource) {
[self release];
return nil;
}
_private->subresources = [[WebResource _resourcesFromPropertyLists:[propertyList objectForKey:WebSubresourcesKey]] retain];
NSEnumerator *enumerator = [[propertyList objectForKey:WebSubframeArchivesKey] objectEnumerator];
NSMutableArray *subframeArchives = [[NSMutableArray alloc] init];
NSDictionary *archivePropertyList;
while ((archivePropertyList = [enumerator nextObject]) != nil) {
WebArchive *archive = [[WebArchive alloc] _initWithPropertyList:archivePropertyList];
if (archive) {
[subframeArchives addObject:archive];
[archive release];
}
}
_private->subframeArchives = subframeArchives;
return self;
}
- (id)initWithData:(NSData *)data
{
#if !LOG_DISABLED
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
#endif
NSDictionary *propertyList = [NSPropertyListSerialization propertyListFromData:data
mutabilityOption:NSPropertyListImmutable
format:nil
errorDescription:nil];
#if !LOG_DISABLED
CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
CFAbsoluteTime duration = end - start;
#endif
LOG(Timing, "Parsing web archive with [NSPropertyListSerialization propertyListFromData::::] took %f seconds", duration);
return [self _initWithPropertyList:propertyList];
}
- (id)initWithCoder:(NSCoder *)decoder
{
self = [self init];
if (!self)
return nil;
@try {
id object = [decoder decodeObjectForKey:WebMainResourceKey];
if ([object isKindOfClass:[WebResource class]])
_private->mainResource = [object retain];
object = [decoder decodeObjectForKey:WebSubresourcesKey];
if (isArrayOfClass(object, [WebResource class]))
_private->subresources = [object retain];
object = [decoder decodeObjectForKey:WebSubframeArchivesKey];
if (isArrayOfClass(object, [WebArchive class]))
_private->subframeArchives = [object retain];
} @catch(id) {
[self release];
return nil;
}
if (!_private->mainResource) {
[self release];
return nil;
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)encoder
{
[encoder encodeObject:_private->mainResource forKey:WebMainResourceKey];
[encoder encodeObject:_private->subresources forKey:WebSubresourcesKey];
[encoder encodeObject:_private->subframeArchives forKey:WebSubframeArchivesKey];
}
- (void)dealloc
{
[_private release];
[super dealloc];
}
- (id)copyWithZone:(NSZone *)zone
{
return [self retain];
}
- (WebResource *)mainResource
{
return [[_private->mainResource retain] autorelease];
}
- (NSArray *)subresources
{
return [[_private->subresources retain] autorelease];
}
- (NSArray *)subframeArchives
{
return [[_private->subframeArchives retain] autorelease];
}
- (NSDictionary *)_propertyListRepresentation
{
NSMutableDictionary *propertyList = [NSMutableDictionary dictionary];
if (_private->mainResource) {
[propertyList setObject:[_private->mainResource _propertyListRepresentation] forKey:WebMainResourceKey];
}
NSArray *propertyLists = [WebResource _propertyListsFromResources:_private->subresources];
if ([propertyLists count] > 0) {
[propertyList setObject:propertyLists forKey:WebSubresourcesKey];
}
NSEnumerator *enumerator = [_private->subframeArchives objectEnumerator];
NSMutableArray *subarchivePropertyLists = [[NSMutableArray alloc] init];
WebArchive *archive;
while ((archive = [enumerator nextObject]) != nil) {
[subarchivePropertyLists addObject:[archive _propertyListRepresentation]];
}
if ([subarchivePropertyLists count] > 0) {
[propertyList setObject:subarchivePropertyLists forKey:WebSubframeArchivesKey];
}
[subarchivePropertyLists release];
return propertyList;
}
- (NSData *)data
{
NSDictionary *propertyList = [self _propertyListRepresentation];
#if !LOG_DISABLED
CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
#endif
NSData *data = [NSPropertyListSerialization dataFromPropertyList:propertyList format:NSPropertyListBinaryFormat_v1_0 errorDescription:nil];
#if !LOG_DISABLED
CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
CFAbsoluteTime duration = end - start;
#endif
LOG(Timing, "Serializing web archive with [NSPropertyListSerialization dataFromPropertyList:::] took %f seconds", duration);
return data;
}
@end