2008-03-24 David Hyatt <hyatt@apple.com>
[WebKit-https.git] / WebKit / mac / WebView / WebArchive.m
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
31 #import "WebKitLogging.h"
32 #import "WebResourcePrivate.h"
33 #import "WebTypesInternal.h"
34
35 NSString *WebArchivePboardType = @"Apple Web Archive pasteboard type";
36
37 static NSString * const WebMainResourceKey = @"WebMainResource";
38 static NSString * const WebSubresourcesKey = @"WebSubresources";
39 static NSString * const WebSubframeArchivesKey = @"WebSubframeArchives";
40
41 @interface WebArchivePrivate : NSObject
42 {
43     @public
44     WebResource *mainResource;
45     NSArray *subresources;
46     NSArray *subframeArchives;
47 }
48 @end
49
50 @implementation WebArchivePrivate
51
52 - (void)dealloc
53 {
54     [mainResource release];
55     [subresources release];
56     [subframeArchives release];
57     [super dealloc];
58 }
59
60 @end
61
62 static BOOL isArrayOfClass(id object, Class elementClass)
63 {
64     if (![object isKindOfClass:[NSArray class]])
65         return NO;
66     NSArray *array = (NSArray *)object;
67     NSUInteger count = [array count];
68     for (NSUInteger i = 0; i < count; ++i)
69         if (![[array objectAtIndex:i] isKindOfClass:elementClass])
70             return NO;
71     return YES;
72 }
73
74 @implementation WebArchive
75
76 - (id)init
77 {
78     self = [super init];
79     if (!self)
80         return nil;
81     _private = [[WebArchivePrivate alloc] init];
82     return self;
83 }
84
85 - (id)initWithMainResource:(WebResource *)mainResource subresources:(NSArray *)subresources subframeArchives:(NSArray *)subframeArchives
86 {
87     self = [self init];
88     if (!self)
89         return nil;
90     
91     _private->mainResource = [mainResource retain];
92     _private->subresources = [subresources retain];
93     _private->subframeArchives = [subframeArchives retain];
94     
95     if (!_private->mainResource) {
96         [self release];
97         return nil;
98     }
99     
100     return self;
101 }
102
103 - (id)_initWithPropertyList:(id)propertyList
104 {
105     self = [self init];
106     if (!self)
107         return nil;
108     
109     if (![propertyList isKindOfClass:[NSDictionary class]]) {
110         [self release];
111         return nil;
112     }
113     
114     _private->mainResource = [[WebResource alloc] _initWithPropertyList:[propertyList objectForKey:WebMainResourceKey]];    
115     if (!_private->mainResource) {
116         [self release];
117         return nil;
118     }
119     
120     _private->subresources = [[WebResource _resourcesFromPropertyLists:[propertyList objectForKey:WebSubresourcesKey]] retain];
121     
122     NSEnumerator *enumerator = [[propertyList objectForKey:WebSubframeArchivesKey] objectEnumerator];
123     NSMutableArray *subframeArchives = [[NSMutableArray alloc] init];
124     NSDictionary *archivePropertyList;
125     while ((archivePropertyList = [enumerator nextObject]) != nil) {
126         WebArchive *archive = [[WebArchive alloc] _initWithPropertyList:archivePropertyList];
127         if (archive) {
128             [subframeArchives addObject:archive];
129             [archive release];
130         }
131     }
132     _private->subframeArchives = subframeArchives;
133
134     return self;
135 }
136
137 - (id)initWithData:(NSData *)data
138 {
139 #if !LOG_DISABLED
140     CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
141 #endif
142     NSDictionary *propertyList = [NSPropertyListSerialization propertyListFromData:data 
143                                                                   mutabilityOption:NSPropertyListImmutable 
144                                                                             format:nil
145                                                                   errorDescription:nil];
146 #if !LOG_DISABLED
147     CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
148     CFAbsoluteTime duration = end - start;
149 #endif
150     LOG(Timing, "Parsing web archive with [NSPropertyListSerialization propertyListFromData::::] took %f seconds", duration);
151     
152     return [self _initWithPropertyList:propertyList];
153 }
154
155 - (id)initWithCoder:(NSCoder *)decoder
156 {    
157     self = [self init];
158     if (!self)
159         return nil;
160
161     @try {
162         id object = [decoder decodeObjectForKey:WebMainResourceKey];
163         if ([object isKindOfClass:[WebResource class]])
164             _private->mainResource = [object retain];
165         object = [decoder decodeObjectForKey:WebSubresourcesKey];
166         if (isArrayOfClass(object, [WebResource class]))
167             _private->subresources = [object retain];
168         object = [decoder decodeObjectForKey:WebSubframeArchivesKey];
169         if (isArrayOfClass(object, [WebArchive class]))
170             _private->subframeArchives = [object retain];
171     } @catch(id) {
172         [self release];
173         return nil;
174     }
175
176     if (!_private->mainResource) {
177         [self release];
178         return nil;
179     }
180
181     return self;
182 }
183
184 - (void)encodeWithCoder:(NSCoder *)encoder
185 {
186     [encoder encodeObject:_private->mainResource forKey:WebMainResourceKey];
187     [encoder encodeObject:_private->subresources forKey:WebSubresourcesKey];
188     [encoder encodeObject:_private->subframeArchives forKey:WebSubframeArchivesKey];    
189 }
190
191 - (void)dealloc
192 {
193     [_private release];
194     [super dealloc];
195 }
196
197 - (id)copyWithZone:(NSZone *)zone
198 {
199     return [self retain];
200 }
201
202 - (WebResource *)mainResource
203 {
204     return [[_private->mainResource retain] autorelease];
205 }
206
207 - (NSArray *)subresources
208 {
209     return [[_private->subresources retain] autorelease];
210 }
211
212 - (NSArray *)subframeArchives
213 {
214     return [[_private->subframeArchives retain] autorelease];
215 }
216
217 - (NSDictionary *)_propertyListRepresentation
218 {
219     NSMutableDictionary *propertyList = [NSMutableDictionary dictionary];
220     if (_private->mainResource) {
221         [propertyList setObject:[_private->mainResource _propertyListRepresentation] forKey:WebMainResourceKey];
222     }
223     NSArray *propertyLists = [WebResource _propertyListsFromResources:_private->subresources];
224     if ([propertyLists count] > 0) {
225         [propertyList setObject:propertyLists forKey:WebSubresourcesKey];
226     }
227     NSEnumerator *enumerator = [_private->subframeArchives objectEnumerator];
228     NSMutableArray *subarchivePropertyLists = [[NSMutableArray alloc] init];
229     WebArchive *archive;
230     while ((archive = [enumerator nextObject]) != nil) {
231         [subarchivePropertyLists addObject:[archive _propertyListRepresentation]];
232     }
233     if ([subarchivePropertyLists count] > 0) {
234         [propertyList setObject:subarchivePropertyLists forKey:WebSubframeArchivesKey];
235     }
236     [subarchivePropertyLists release];
237     return propertyList;
238 }
239
240 - (NSData *)data
241 {
242     NSDictionary *propertyList = [self _propertyListRepresentation];
243 #if !LOG_DISABLED
244     CFAbsoluteTime start = CFAbsoluteTimeGetCurrent();
245 #endif
246     NSData *data = [NSPropertyListSerialization dataFromPropertyList:propertyList format:NSPropertyListBinaryFormat_v1_0 errorDescription:nil];
247 #if !LOG_DISABLED
248     CFAbsoluteTime end = CFAbsoluteTimeGetCurrent();
249     CFAbsoluteTime duration = end - start;
250 #endif
251     LOG(Timing, "Serializing web archive with [NSPropertyListSerialization dataFromPropertyList:::] took %f seconds", duration);
252     return data;
253 }
254
255 @end