Index: third_party/WebKit/WebCore/loader/archive/cf/LegacyWebArchive.cpp |
=================================================================== |
--- third_party/WebKit/WebCore/loader/archive/cf/LegacyWebArchive.cpp (revision 9391) |
+++ third_party/WebKit/WebCore/loader/archive/cf/LegacyWebArchive.cpp (working copy) |
@@ -1,596 +1,596 @@ |
-/* |
- * Copyright (C) 2008, 2009 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. |
- */ |
- |
-#include "config.h" |
-#include "LegacyWebArchive.h" |
- |
-#include "CString.h" |
-#include "Cache.h" |
-#include "Document.h" |
-#include "DocumentLoader.h" |
-#include "Frame.h" |
-#include "FrameLoader.h" |
-#include "FrameTree.h" |
-#include "HTMLFrameOwnerElement.h" |
-#include "HTMLNames.h" |
-#include "IconDatabase.h" |
-#include "KURLHash.h" |
-#include "Logging.h" |
-#include "markup.h" |
-#include "Node.h" |
-#include "Range.h" |
-#include "SelectionController.h" |
-#include "SharedBuffer.h" |
-#include <wtf/ListHashSet.h> |
-#include <wtf/RetainPtr.h> |
- |
-namespace WebCore { |
- |
-static const CFStringRef LegacyWebArchiveMainResourceKey = CFSTR("WebMainResource"); |
-static const CFStringRef LegacyWebArchiveSubresourcesKey = CFSTR("WebSubresources"); |
-static const CFStringRef LegacyWebArchiveSubframeArchivesKey = CFSTR("WebSubframeArchives"); |
-static const CFStringRef LegacyWebArchiveResourceDataKey = CFSTR("WebResourceData"); |
-static const CFStringRef LegacyWebArchiveResourceFrameNameKey = CFSTR("WebResourceFrameName"); |
-static const CFStringRef LegacyWebArchiveResourceMIMETypeKey = CFSTR("WebResourceMIMEType"); |
-static const CFStringRef LegacyWebArchiveResourceURLKey = CFSTR("WebResourceURL"); |
-static const CFStringRef LegacyWebArchiveResourceTextEncodingNameKey = CFSTR("WebResourceTextEncodingName"); |
-static const CFStringRef LegacyWebArchiveResourceResponseKey = CFSTR("WebResourceResponse"); |
-static const CFStringRef LegacyWebArchiveResourceResponseVersionKey = CFSTR("WebResourceResponseVersion"); |
- |
-static RetainPtr<CFDictionaryRef> createPropertyListRepresentationFromResource(ArchiveResource* resource, bool mainResource) |
-{ |
- if (!resource) { |
- // The property list representation of a null/empty WebResource has the following 3 objects stored as nil |
- RetainPtr<CFMutableDictionaryRef> propertyList(AdoptCF, CFDictionaryCreateMutable(0, 3, 0, 0)); |
- CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceDataKey, 0); |
- CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceURLKey, 0); |
- CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceMIMETypeKey, 0); |
- |
- return propertyList; |
- } |
- |
- RetainPtr<CFMutableDictionaryRef> propertyList(AdoptCF, CFDictionaryCreateMutable(0, 6, 0, &kCFTypeDictionaryValueCallBacks)); |
- |
- // Resource data can be empty, but must be represented by an empty CFDataRef |
- SharedBuffer* data = resource->data(); |
- RetainPtr<CFDataRef> cfData; |
- if (data) |
- cfData.adoptCF(data->createCFData()); |
- else |
- cfData.adoptCF(CFDataCreate(0, 0, 0)); |
- CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceDataKey, cfData.get()); |
- |
- // Resource URL cannot be null |
- RetainPtr<CFStringRef> cfURL(AdoptCF, resource->url().string().createCFString()); |
- if (cfURL) |
- CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceURLKey, cfURL.get()); |
- else { |
- LOG(Archives, "LegacyWebArchive - NULL resource URL is invalid - returning null property list"); |
- return 0; |
- } |
- |
- // FrameName should be left out if empty for subresources, but always included for main resources |
- const String& frameName(resource->frameName()); |
- if (!frameName.isEmpty() || mainResource) { |
- RetainPtr<CFStringRef> cfFrameName(AdoptCF, frameName.createCFString()); |
- CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceFrameNameKey, cfFrameName.get()); |
- } |
- |
- // Set MIMEType, TextEncodingName, and ResourceResponse only if they actually exist |
- const String& mimeType(resource->mimeType()); |
- if (!mimeType.isEmpty()) { |
- RetainPtr<CFStringRef> cfMIMEType(AdoptCF, mimeType.createCFString()); |
- CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceMIMETypeKey, cfMIMEType.get()); |
- } |
- |
- const String& textEncoding(resource->textEncoding()); |
- if (!textEncoding.isEmpty()) { |
- RetainPtr<CFStringRef> cfTextEncoding(AdoptCF, textEncoding.createCFString()); |
- CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceTextEncodingNameKey, cfTextEncoding.get()); |
- } |
- |
- // Don't include the resource response for the main resource |
- if (!mainResource) { |
- RetainPtr<CFDataRef> resourceResponseData = propertyListDataFromResourceResponse(resource->response()); |
- if (resourceResponseData) |
- CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceResponseKey, resourceResponseData.get()); |
- } |
- |
- return propertyList; |
-} |
- |
-static RetainPtr<CFDictionaryRef> createPropertyListRep(Archive* archive) |
-{ |
- RetainPtr<CFMutableDictionaryRef> propertyList(AdoptCF, CFDictionaryCreateMutable(0, 3, 0, &kCFTypeDictionaryValueCallBacks)); |
- |
- RetainPtr<CFDictionaryRef> mainResourceDict = createPropertyListRepresentationFromResource(archive->mainResource(), true); |
- if (!mainResourceDict) |
- return 0; |
- CFDictionarySetValue(propertyList.get(), LegacyWebArchiveMainResourceKey, mainResourceDict.get()); |
- |
- RetainPtr<CFMutableArrayRef> subresourcesArray(AdoptCF, CFArrayCreateMutable(0, archive->subresources().size(), &kCFTypeArrayCallBacks)); |
- const Vector<RefPtr<ArchiveResource> >& subresources(archive->subresources()); |
- for (unsigned i = 0; i < subresources.size(); ++i) { |
- RetainPtr<CFDictionaryRef> subresource = createPropertyListRepresentationFromResource(subresources[i].get(), false); |
- if (subresource) |
- CFArrayAppendValue(subresourcesArray.get(), subresource.get()); |
- else |
- LOG(Archives, "LegacyWebArchive - Failed to create property list for subresource"); |
- } |
- if (CFArrayGetCount(subresourcesArray.get())) |
- CFDictionarySetValue(propertyList.get(), LegacyWebArchiveSubresourcesKey, subresourcesArray.get()); |
- |
- RetainPtr<CFMutableArrayRef> subframesArray(AdoptCF, CFArrayCreateMutable(0, archive->subframeArchives().size(), &kCFTypeArrayCallBacks)); |
- const Vector<RefPtr<Archive> >& subframeArchives(archive->subframeArchives()); |
- for (unsigned i = 0; i < subframeArchives.size(); ++i) { |
- RetainPtr<CFDictionaryRef> subframeArchive = createPropertyListRep(subframeArchives[i].get()); |
- if (subframeArchive) |
- CFArrayAppendValue(subframesArray.get(), subframeArchive.get()); |
- else |
- LOG(Archives, "LegacyWebArchive - Failed to create property list for subframe archive"); |
- } |
- if (CFArrayGetCount(subframesArray.get())) |
- CFDictionarySetValue(propertyList.get(), LegacyWebArchiveSubframeArchivesKey, subframesArray.get()); |
- |
- return propertyList; |
-} |
- |
-static ResourceResponse createResourceResponseFromPropertyListData(CFDataRef data, CFStringRef responseDataType) |
-{ |
- ASSERT(data); |
- if (!data) |
- return ResourceResponse(); |
- |
- // If the ResourceResponseVersion (passed in as responseDataType) exists at all, this is a "new" webarchive that we can parse well in a cross platform manner |
- // If it doesn't exist, we will assume this is an "old" Cocoa-based WebArchive, and parse the ResourceResponse as such |
- if (!responseDataType) |
- return createResourceResponseFromMacArchivedData(data); |
- |
- // FIXME: Parse the "new" format that the above comment references here |
- return ResourceResponse(); |
-} |
- |
-static PassRefPtr<ArchiveResource> createResource(CFDictionaryRef dictionary) |
-{ |
- ASSERT(dictionary); |
- if (!dictionary) |
- return 0; |
- |
- CFDataRef resourceData = static_cast<CFDataRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceDataKey)); |
- if (resourceData && CFGetTypeID(resourceData) != CFDataGetTypeID()) { |
- LOG(Archives, "LegacyWebArchive - Resource data is not of type CFData, cannot create invalid resource"); |
- return 0; |
- } |
- |
- CFStringRef frameName = static_cast<CFStringRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceFrameNameKey)); |
- if (frameName && CFGetTypeID(frameName) != CFStringGetTypeID()) { |
- LOG(Archives, "LegacyWebArchive - Frame name is not of type CFString, cannot create invalid resource"); |
- return 0; |
- } |
- |
- CFStringRef mimeType = static_cast<CFStringRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceMIMETypeKey)); |
- if (mimeType && CFGetTypeID(mimeType) != CFStringGetTypeID()) { |
- LOG(Archives, "LegacyWebArchive - MIME type is not of type CFString, cannot create invalid resource"); |
- return 0; |
- } |
- |
- CFStringRef url = static_cast<CFStringRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceURLKey)); |
- if (url && CFGetTypeID(url) != CFStringGetTypeID()) { |
- LOG(Archives, "LegacyWebArchive - URL is not of type CFString, cannot create invalid resource"); |
- return 0; |
- } |
- |
- CFStringRef textEncoding = static_cast<CFStringRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceTextEncodingNameKey)); |
- if (textEncoding && CFGetTypeID(textEncoding) != CFStringGetTypeID()) { |
- LOG(Archives, "LegacyWebArchive - Text encoding is not of type CFString, cannot create invalid resource"); |
- return 0; |
- } |
- |
- ResourceResponse response; |
- |
- CFDataRef resourceResponseData = static_cast<CFDataRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceResponseKey)); |
- if (resourceResponseData) { |
- if (CFGetTypeID(resourceResponseData) != CFDataGetTypeID()) { |
- LOG(Archives, "LegacyWebArchive - Resource response data is not of type CFData, cannot create invalid resource"); |
- return 0; |
- } |
- |
- CFStringRef resourceResponseVersion = static_cast<CFStringRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceResponseVersionKey)); |
- if (resourceResponseVersion && CFGetTypeID(resourceResponseVersion) != CFStringGetTypeID()) { |
- LOG(Archives, "LegacyWebArchive - Resource response version is not of type CFString, cannot create invalid resource"); |
- return 0; |
- } |
- |
- response = createResourceResponseFromPropertyListData(resourceResponseData, resourceResponseVersion); |
- } |
- |
- return ArchiveResource::create(SharedBuffer::create(CFDataGetBytePtr(resourceData), CFDataGetLength(resourceData)), KURL(url), mimeType, textEncoding, frameName, response); |
-} |
- |
-PassRefPtr<LegacyWebArchive> LegacyWebArchive::create() |
-{ |
- return adoptRef(new LegacyWebArchive); |
-} |
- |
-PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(SharedBuffer* data) |
-{ |
- LOG(Archives, "LegacyWebArchive - Creating from raw data"); |
- |
- RefPtr<LegacyWebArchive> archive = create(); |
- if (!archive->init(data)) |
- return 0; |
- |
- return archive.release(); |
-} |
- |
-PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(PassRefPtr<ArchiveResource> mainResource, Vector<PassRefPtr<ArchiveResource> >& subresources, Vector<PassRefPtr<LegacyWebArchive> >& subframeArchives) |
-{ |
- ASSERT(mainResource); |
- if (!mainResource) |
- return 0; |
- |
- RefPtr<LegacyWebArchive> archive = create(); |
- archive->setMainResource(mainResource); |
- |
- for (unsigned i = 0; i < subresources.size(); ++i) |
- archive->addSubresource(subresources[i]); |
- |
- for (unsigned i = 0; i < subframeArchives.size(); ++i) |
- archive->addSubframeArchive(subframeArchives[i]); |
- |
- return archive.release(); |
-} |
- |
-LegacyWebArchive::LegacyWebArchive() |
-{ |
-} |
- |
-bool LegacyWebArchive::init(SharedBuffer* data) |
-{ |
- ASSERT(data); |
- if (!data) |
- return false; |
- |
- RetainPtr<CFDataRef> cfData(AdoptCF, data->createCFData()); |
- if (!cfData) |
- return false; |
- |
- CFStringRef errorString = 0; |
- |
- RetainPtr<CFDictionaryRef> plist(AdoptCF, static_cast<CFDictionaryRef>(CFPropertyListCreateFromXMLData(0, cfData.get(), kCFPropertyListImmutable, &errorString))); |
- if (!plist) { |
-#ifndef NDEBUG |
- const char* cError = errorString ? CFStringGetCStringPtr(errorString, kCFStringEncodingUTF8) : "unknown error"; |
- LOG(Archives, "LegacyWebArchive - Error parsing PropertyList from archive data - %s", cError); |
-#endif |
- if (errorString) |
- CFRelease(errorString); |
- return false; |
- } |
- |
- if (CFGetTypeID(plist.get()) != CFDictionaryGetTypeID()) { |
- LOG(Archives, "LegacyWebArchive - Archive property list is not the expected CFDictionary, aborting invalid WebArchive"); |
- return false; |
- } |
- |
- return extract(plist.get()); |
-} |
- |
-bool LegacyWebArchive::extract(CFDictionaryRef dictionary) |
-{ |
- ASSERT(dictionary); |
- if (!dictionary) { |
- LOG(Archives, "LegacyWebArchive - Null root CFDictionary, aborting invalid WebArchive"); |
- return false; |
- } |
- |
- CFDictionaryRef mainResourceDict = static_cast<CFDictionaryRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveMainResourceKey)); |
- if (!mainResourceDict) { |
- LOG(Archives, "LegacyWebArchive - No main resource in archive, aborting invalid WebArchive"); |
- return false; |
- } |
- if (CFGetTypeID(mainResourceDict) != CFDictionaryGetTypeID()) { |
- LOG(Archives, "LegacyWebArchive - Main resource is not the expected CFDictionary, aborting invalid WebArchive"); |
- return false; |
- } |
- |
- setMainResource(createResource(mainResourceDict)); |
- if (!mainResource()) { |
- LOG(Archives, "LegacyWebArchive - Failed to parse main resource from CFDictionary or main resource does not exist, aborting invalid WebArchive"); |
- return false; |
- } |
- |
- CFArrayRef subresourceArray = static_cast<CFArrayRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveSubresourcesKey)); |
- if (subresourceArray && CFGetTypeID(subresourceArray) != CFArrayGetTypeID()) { |
- LOG(Archives, "LegacyWebArchive - Subresources is not the expected Array, aborting invalid WebArchive"); |
- return false; |
- } |
- |
- if (subresourceArray) { |
- CFIndex count = CFArrayGetCount(subresourceArray); |
- for (CFIndex i = 0; i < count; ++i) { |
- CFDictionaryRef subresourceDict = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(subresourceArray, i)); |
- if (CFGetTypeID(subresourceDict) != CFDictionaryGetTypeID()) { |
- LOG(Archives, "LegacyWebArchive - Subresource is not expected CFDictionary, aborting invalid WebArchive"); |
- return false; |
- } |
- addSubresource(createResource(subresourceDict)); |
- } |
- } |
- |
- CFArrayRef subframeArray = static_cast<CFArrayRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveSubframeArchivesKey)); |
- if (subframeArray && CFGetTypeID(subframeArray) != CFArrayGetTypeID()) { |
- LOG(Archives, "LegacyWebArchive - Subframe archives is not the expected Array, aborting invalid WebArchive"); |
- return false; |
- } |
- |
- if (subframeArray) { |
- CFIndex count = CFArrayGetCount(subframeArray); |
- for (CFIndex i = 0; i < count; ++i) { |
- CFDictionaryRef subframeDict = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(subframeArray, i)); |
- if (CFGetTypeID(subframeDict) != CFDictionaryGetTypeID()) { |
- LOG(Archives, "LegacyWebArchive - Subframe array is not expected CFDictionary, aborting invalid WebArchive"); |
- return false; |
- } |
- |
- RefPtr<LegacyWebArchive> subframeArchive = create(); |
- if (subframeArchive->extract(subframeDict)) |
- addSubframeArchive(subframeArchive.release()); |
- else |
- LOG(Archives, "LegacyWebArchive - Invalid subframe archive skipped"); |
- } |
- } |
- |
- return true; |
-} |
- |
-RetainPtr<CFDataRef> LegacyWebArchive::rawDataRepresentation() |
-{ |
- RetainPtr<CFDictionaryRef> propertyList = createPropertyListRep(this); |
- if (!propertyList) { |
- LOG(Archives, "LegacyWebArchive - Failed to create property list for archive, returning no data"); |
- return 0; |
- } |
- |
- RetainPtr<CFWriteStreamRef> stream(AdoptCF, CFWriteStreamCreateWithAllocatedBuffers(0, 0)); |
- |
- CFWriteStreamOpen(stream.get()); |
- CFPropertyListWriteToStream(propertyList.get(), stream.get(), kCFPropertyListBinaryFormat_v1_0, 0); |
- |
- RetainPtr<CFDataRef> plistData(AdoptCF, static_cast<CFDataRef>(CFWriteStreamCopyProperty(stream.get(), kCFStreamPropertyDataWritten))); |
- |
- CFWriteStreamClose(stream.get()); |
- |
- if (!plistData) { |
- LOG(Archives, "LegacyWebArchive - Failed to convert property list into raw data, returning no data"); |
- return 0; |
- } |
- |
- return plistData; |
-} |
- |
-#if !PLATFORM(MAC) |
-// FIXME: Is it possible to parse in a Cocoa-style resource response manually, |
-// without NSKeyed(Un)Archiver, manipulating plists directly? |
-// If so, the code that does it will go here. |
-// In the meantime, Mac will continue to NSKeyed(Un)Archive the response as it always has |
-ResourceResponse createResourceResponseFromMacArchivedData(CFDataRef responseData) |
-{ |
- return ResourceResponse(); |
-} |
- |
-RetainPtr<CFDataRef> propertyListDataFromResourceResponse(const ResourceResponse& response) |
-{ |
- // FIXME: Write out the "new" format described in ::createResourceResponseFromPropertyListData() up above |
- return 0; |
-} |
-#endif |
- |
-PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(Node* node) |
-{ |
- ASSERT(node); |
- if (!node) |
- return create(); |
- |
- Document* document = node->document(); |
- Frame* frame = document ? document->frame() : 0; |
- if (!frame) |
- return create(); |
- |
- Vector<Node*> nodeList; |
- String markupString = createMarkup(node, IncludeNode, &nodeList); |
- Node::NodeType nodeType = node->nodeType(); |
- if (nodeType != Node::DOCUMENT_NODE && nodeType != Node::DOCUMENT_TYPE_NODE) |
- markupString = frame->documentTypeString() + markupString; |
- |
- return create(markupString, frame, nodeList); |
-} |
- |
-PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(Frame* frame) |
-{ |
- ASSERT(frame); |
- |
- DocumentLoader* documentLoader = frame->loader()->documentLoader(); |
- |
- if (!documentLoader) |
- return 0; |
- |
- Vector<PassRefPtr<LegacyWebArchive> > subframeArchives; |
- |
- unsigned children = frame->tree()->childCount(); |
- for (unsigned i = 0; i < children; ++i) { |
- RefPtr<LegacyWebArchive> childFrameArchive = create(frame->tree()->child(i)); |
- if (childFrameArchive) |
- subframeArchives.append(childFrameArchive.release()); |
- } |
- |
- Vector<PassRefPtr<ArchiveResource> > subresources; |
- documentLoader->getSubresources(subresources); |
- |
- return LegacyWebArchive::create(documentLoader->mainResource(), subresources, subframeArchives); |
-} |
- |
-PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(Range* range) |
-{ |
- if (!range) |
- return 0; |
- |
- Node* startContainer = range->startContainer(); |
- if (!startContainer) |
- return 0; |
- |
- Document* document = startContainer->document(); |
- if (!document) |
- return 0; |
- |
- Frame* frame = document->frame(); |
- if (!frame) |
- return 0; |
- |
- Vector<Node*> nodeList; |
- |
- // FIXME: This is always "for interchange". Is that right? See the previous method. |
- String markupString = frame->documentTypeString() + createMarkup(range, &nodeList, AnnotateForInterchange); |
- |
- return create(markupString, frame, nodeList); |
-} |
- |
-PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(const String& markupString, Frame* frame, Vector<Node*>& nodes) |
-{ |
- ASSERT(frame); |
- |
- const ResourceResponse& response = frame->loader()->documentLoader()->response(); |
- KURL responseURL = response.url(); |
- |
- // it's possible to have a response without a URL here |
- // <rdar://problem/5454935> |
- if (responseURL.isNull()) |
- responseURL = KURL(""); |
- |
- PassRefPtr<ArchiveResource> mainResource = ArchiveResource::create(utf8Buffer(markupString), responseURL, response.mimeType(), "UTF-8", frame->tree()->name()); |
- |
- Vector<PassRefPtr<LegacyWebArchive> > subframeArchives; |
- Vector<PassRefPtr<ArchiveResource> > subresources; |
- HashSet<KURL> uniqueSubresources; |
- |
- Vector<Node*>::iterator it = nodes.begin(); |
- Vector<Node*>::iterator end = nodes.end(); |
- |
- for (; it != end; ++it) { |
- Frame* childFrame; |
- if (((*it)->hasTagName(HTMLNames::frameTag) || (*it)->hasTagName(HTMLNames::iframeTag) || (*it)->hasTagName(HTMLNames::objectTag)) && |
- (childFrame = static_cast<HTMLFrameOwnerElement*>(*it)->contentFrame())) { |
- RefPtr<LegacyWebArchive> subframeArchive; |
- if (Document* document = childFrame->document()) |
- subframeArchive = LegacyWebArchive::create(document); |
- else |
- subframeArchive = create(childFrame); |
- |
- if (subframeArchive) |
- subframeArchives.append(subframeArchive); |
- else |
- LOG_ERROR("Unabled to archive subframe %s", childFrame->tree()->name().string().utf8().data()); |
- } else { |
- ListHashSet<KURL> subresourceURLs; |
- (*it)->getSubresourceURLs(subresourceURLs); |
- |
- DocumentLoader* documentLoader = frame->loader()->documentLoader(); |
- ListHashSet<KURL>::iterator iterEnd = subresourceURLs.end(); |
- for (ListHashSet<KURL>::iterator iter = subresourceURLs.begin(); iter != iterEnd; ++iter) { |
- const KURL& subresourceURL = *iter; |
- if (uniqueSubresources.contains(subresourceURL)) |
- continue; |
- |
- uniqueSubresources.add(subresourceURL); |
- |
- RefPtr<ArchiveResource> resource = documentLoader->subresource(subresourceURL); |
- if (resource) { |
- subresources.append(resource.release()); |
- continue; |
- } |
- |
- CachedResource *cachedResource = cache()->resourceForURL(subresourceURL); |
- if (cachedResource) { |
- resource = ArchiveResource::create(cachedResource->data(), subresourceURL, cachedResource->response()); |
- if (resource) { |
- subresources.append(resource.release()); |
- continue; |
- } |
- } |
- |
- // FIXME: should do something better than spew to console here |
- LOG_ERROR("Failed to archive subresource for %s", subresourceURL.string().utf8().data()); |
- } |
- } |
- } |
- |
- // Add favicon if one exists for this page |
- if (iconDatabase() && iconDatabase()->isEnabled()) { |
- const String& iconURL = iconDatabase()->iconURLForPageURL(responseURL); |
- if (!iconURL.isEmpty() && iconDatabase()->iconDataKnownForIconURL(iconURL)) { |
- if (Image* iconImage = iconDatabase()->iconForPageURL(responseURL, IntSize(16, 16))) { |
- RefPtr<ArchiveResource> resource = ArchiveResource::create(iconImage->data(), KURL(iconURL), "image/x-icon", "", ""); |
- subresources.append(resource.release()); |
- } |
- } |
- } |
- |
- return create(mainResource, subresources, subframeArchives); |
-} |
- |
-PassRefPtr<LegacyWebArchive> LegacyWebArchive::createFromSelection(Frame* frame) |
-{ |
- if (!frame) |
- return 0; |
- |
- RefPtr<Range> selectionRange = frame->selection()->toRange(); |
- Vector<Node*> nodeList; |
- String markupString = frame->documentTypeString() + createMarkup(selectionRange.get(), &nodeList, AnnotateForInterchange); |
- |
- RefPtr<LegacyWebArchive> archive = create(markupString, frame, nodeList); |
- |
- if (!frame->document() || !frame->document()->isFrameSet()) |
- return archive.release(); |
- |
- // Wrap the frameset document in an iframe so it can be pasted into |
- // another document (which will have a body or frameset of its own). |
- String iframeMarkup = String::format("<iframe frameborder=\"no\" marginwidth=\"0\" marginheight=\"0\" width=\"98%%\" height=\"98%%\" src=\"%s\"></iframe>", |
- frame->loader()->documentLoader()->response().url().string().utf8().data()); |
- RefPtr<ArchiveResource> iframeResource = ArchiveResource::create(utf8Buffer(iframeMarkup), blankURL(), "text/html", "UTF-8", String()); |
- |
- Vector<PassRefPtr<ArchiveResource> > subresources; |
- |
- Vector<PassRefPtr<LegacyWebArchive> > subframeArchives; |
- subframeArchives.append(archive); |
- |
- archive = LegacyWebArchive::create(iframeResource.release(), subresources, subframeArchives); |
- |
- return archive.release(); |
-} |
- |
-} |
+/* |
+ * Copyright (C) 2008, 2009 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. |
+ */ |
+ |
+#include "config.h" |
+#include "LegacyWebArchive.h" |
+ |
+#include "CString.h" |
+#include "Cache.h" |
+#include "Document.h" |
+#include "DocumentLoader.h" |
+#include "Frame.h" |
+#include "FrameLoader.h" |
+#include "FrameTree.h" |
+#include "HTMLFrameOwnerElement.h" |
+#include "HTMLNames.h" |
+#include "IconDatabase.h" |
+#include "KURLHash.h" |
+#include "Logging.h" |
+#include "markup.h" |
+#include "Node.h" |
+#include "Range.h" |
+#include "SelectionController.h" |
+#include "SharedBuffer.h" |
+#include <wtf/ListHashSet.h> |
+#include <wtf/RetainPtr.h> |
+ |
+namespace WebCore { |
+ |
+static const CFStringRef LegacyWebArchiveMainResourceKey = CFSTR("WebMainResource"); |
+static const CFStringRef LegacyWebArchiveSubresourcesKey = CFSTR("WebSubresources"); |
+static const CFStringRef LegacyWebArchiveSubframeArchivesKey = CFSTR("WebSubframeArchives"); |
+static const CFStringRef LegacyWebArchiveResourceDataKey = CFSTR("WebResourceData"); |
+static const CFStringRef LegacyWebArchiveResourceFrameNameKey = CFSTR("WebResourceFrameName"); |
+static const CFStringRef LegacyWebArchiveResourceMIMETypeKey = CFSTR("WebResourceMIMEType"); |
+static const CFStringRef LegacyWebArchiveResourceURLKey = CFSTR("WebResourceURL"); |
+static const CFStringRef LegacyWebArchiveResourceTextEncodingNameKey = CFSTR("WebResourceTextEncodingName"); |
+static const CFStringRef LegacyWebArchiveResourceResponseKey = CFSTR("WebResourceResponse"); |
+static const CFStringRef LegacyWebArchiveResourceResponseVersionKey = CFSTR("WebResourceResponseVersion"); |
+ |
+static RetainPtr<CFDictionaryRef> createPropertyListRepresentationFromResource(ArchiveResource* resource, bool mainResource) |
+{ |
+ if (!resource) { |
+ // The property list representation of a null/empty WebResource has the following 3 objects stored as nil |
+ RetainPtr<CFMutableDictionaryRef> propertyList(AdoptCF, CFDictionaryCreateMutable(0, 3, 0, 0)); |
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceDataKey, 0); |
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceURLKey, 0); |
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceMIMETypeKey, 0); |
+ |
+ return propertyList; |
+ } |
+ |
+ RetainPtr<CFMutableDictionaryRef> propertyList(AdoptCF, CFDictionaryCreateMutable(0, 6, 0, &kCFTypeDictionaryValueCallBacks)); |
+ |
+ // Resource data can be empty, but must be represented by an empty CFDataRef |
+ SharedBuffer* data = resource->data(); |
+ RetainPtr<CFDataRef> cfData; |
+ if (data) |
+ cfData.adoptCF(data->createCFData()); |
+ else |
+ cfData.adoptCF(CFDataCreate(0, 0, 0)); |
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceDataKey, cfData.get()); |
+ |
+ // Resource URL cannot be null |
+ RetainPtr<CFStringRef> cfURL(AdoptCF, resource->url().string().createCFString()); |
+ if (cfURL) |
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceURLKey, cfURL.get()); |
+ else { |
+ LOG(Archives, "LegacyWebArchive - NULL resource URL is invalid - returning null property list"); |
+ return 0; |
+ } |
+ |
+ // FrameName should be left out if empty for subresources, but always included for main resources |
+ const String& frameName(resource->frameName()); |
+ if (!frameName.isEmpty() || mainResource) { |
+ RetainPtr<CFStringRef> cfFrameName(AdoptCF, frameName.createCFString()); |
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceFrameNameKey, cfFrameName.get()); |
+ } |
+ |
+ // Set MIMEType, TextEncodingName, and ResourceResponse only if they actually exist |
+ const String& mimeType(resource->mimeType()); |
+ if (!mimeType.isEmpty()) { |
+ RetainPtr<CFStringRef> cfMIMEType(AdoptCF, mimeType.createCFString()); |
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceMIMETypeKey, cfMIMEType.get()); |
+ } |
+ |
+ const String& textEncoding(resource->textEncoding()); |
+ if (!textEncoding.isEmpty()) { |
+ RetainPtr<CFStringRef> cfTextEncoding(AdoptCF, textEncoding.createCFString()); |
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceTextEncodingNameKey, cfTextEncoding.get()); |
+ } |
+ |
+ // Don't include the resource response for the main resource |
+ if (!mainResource) { |
+ RetainPtr<CFDataRef> resourceResponseData = propertyListDataFromResourceResponse(resource->response()); |
+ if (resourceResponseData) |
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveResourceResponseKey, resourceResponseData.get()); |
+ } |
+ |
+ return propertyList; |
+} |
+ |
+static RetainPtr<CFDictionaryRef> createPropertyListRep(Archive* archive) |
+{ |
+ RetainPtr<CFMutableDictionaryRef> propertyList(AdoptCF, CFDictionaryCreateMutable(0, 3, 0, &kCFTypeDictionaryValueCallBacks)); |
+ |
+ RetainPtr<CFDictionaryRef> mainResourceDict = createPropertyListRepresentationFromResource(archive->mainResource(), true); |
+ if (!mainResourceDict) |
+ return 0; |
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveMainResourceKey, mainResourceDict.get()); |
+ |
+ RetainPtr<CFMutableArrayRef> subresourcesArray(AdoptCF, CFArrayCreateMutable(0, archive->subresources().size(), &kCFTypeArrayCallBacks)); |
+ const Vector<RefPtr<ArchiveResource> >& subresources(archive->subresources()); |
+ for (unsigned i = 0; i < subresources.size(); ++i) { |
+ RetainPtr<CFDictionaryRef> subresource = createPropertyListRepresentationFromResource(subresources[i].get(), false); |
+ if (subresource) |
+ CFArrayAppendValue(subresourcesArray.get(), subresource.get()); |
+ else |
+ LOG(Archives, "LegacyWebArchive - Failed to create property list for subresource"); |
+ } |
+ if (CFArrayGetCount(subresourcesArray.get())) |
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveSubresourcesKey, subresourcesArray.get()); |
+ |
+ RetainPtr<CFMutableArrayRef> subframesArray(AdoptCF, CFArrayCreateMutable(0, archive->subframeArchives().size(), &kCFTypeArrayCallBacks)); |
+ const Vector<RefPtr<Archive> >& subframeArchives(archive->subframeArchives()); |
+ for (unsigned i = 0; i < subframeArchives.size(); ++i) { |
+ RetainPtr<CFDictionaryRef> subframeArchive = createPropertyListRep(subframeArchives[i].get()); |
+ if (subframeArchive) |
+ CFArrayAppendValue(subframesArray.get(), subframeArchive.get()); |
+ else |
+ LOG(Archives, "LegacyWebArchive - Failed to create property list for subframe archive"); |
+ } |
+ if (CFArrayGetCount(subframesArray.get())) |
+ CFDictionarySetValue(propertyList.get(), LegacyWebArchiveSubframeArchivesKey, subframesArray.get()); |
+ |
+ return propertyList; |
+} |
+ |
+static ResourceResponse createResourceResponseFromPropertyListData(CFDataRef data, CFStringRef responseDataType) |
+{ |
+ ASSERT(data); |
+ if (!data) |
+ return ResourceResponse(); |
+ |
+ // If the ResourceResponseVersion (passed in as responseDataType) exists at all, this is a "new" webarchive that we can parse well in a cross platform manner |
+ // If it doesn't exist, we will assume this is an "old" Cocoa-based WebArchive, and parse the ResourceResponse as such |
+ if (!responseDataType) |
+ return createResourceResponseFromMacArchivedData(data); |
+ |
+ // FIXME: Parse the "new" format that the above comment references here |
+ return ResourceResponse(); |
+} |
+ |
+static PassRefPtr<ArchiveResource> createResource(CFDictionaryRef dictionary) |
+{ |
+ ASSERT(dictionary); |
+ if (!dictionary) |
+ return 0; |
+ |
+ CFDataRef resourceData = static_cast<CFDataRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceDataKey)); |
+ if (resourceData && CFGetTypeID(resourceData) != CFDataGetTypeID()) { |
+ LOG(Archives, "LegacyWebArchive - Resource data is not of type CFData, cannot create invalid resource"); |
+ return 0; |
+ } |
+ |
+ CFStringRef frameName = static_cast<CFStringRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceFrameNameKey)); |
+ if (frameName && CFGetTypeID(frameName) != CFStringGetTypeID()) { |
+ LOG(Archives, "LegacyWebArchive - Frame name is not of type CFString, cannot create invalid resource"); |
+ return 0; |
+ } |
+ |
+ CFStringRef mimeType = static_cast<CFStringRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceMIMETypeKey)); |
+ if (mimeType && CFGetTypeID(mimeType) != CFStringGetTypeID()) { |
+ LOG(Archives, "LegacyWebArchive - MIME type is not of type CFString, cannot create invalid resource"); |
+ return 0; |
+ } |
+ |
+ CFStringRef url = static_cast<CFStringRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceURLKey)); |
+ if (url && CFGetTypeID(url) != CFStringGetTypeID()) { |
+ LOG(Archives, "LegacyWebArchive - URL is not of type CFString, cannot create invalid resource"); |
+ return 0; |
+ } |
+ |
+ CFStringRef textEncoding = static_cast<CFStringRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceTextEncodingNameKey)); |
+ if (textEncoding && CFGetTypeID(textEncoding) != CFStringGetTypeID()) { |
+ LOG(Archives, "LegacyWebArchive - Text encoding is not of type CFString, cannot create invalid resource"); |
+ return 0; |
+ } |
+ |
+ ResourceResponse response; |
+ |
+ CFDataRef resourceResponseData = static_cast<CFDataRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceResponseKey)); |
+ if (resourceResponseData) { |
+ if (CFGetTypeID(resourceResponseData) != CFDataGetTypeID()) { |
+ LOG(Archives, "LegacyWebArchive - Resource response data is not of type CFData, cannot create invalid resource"); |
+ return 0; |
+ } |
+ |
+ CFStringRef resourceResponseVersion = static_cast<CFStringRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveResourceResponseVersionKey)); |
+ if (resourceResponseVersion && CFGetTypeID(resourceResponseVersion) != CFStringGetTypeID()) { |
+ LOG(Archives, "LegacyWebArchive - Resource response version is not of type CFString, cannot create invalid resource"); |
+ return 0; |
+ } |
+ |
+ response = createResourceResponseFromPropertyListData(resourceResponseData, resourceResponseVersion); |
+ } |
+ |
+ return ArchiveResource::create(SharedBuffer::create(CFDataGetBytePtr(resourceData), CFDataGetLength(resourceData)), KURL(url), mimeType, textEncoding, frameName, response); |
+} |
+ |
+PassRefPtr<LegacyWebArchive> LegacyWebArchive::create() |
+{ |
+ return adoptRef(new LegacyWebArchive); |
+} |
+ |
+PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(SharedBuffer* data) |
+{ |
+ LOG(Archives, "LegacyWebArchive - Creating from raw data"); |
+ |
+ RefPtr<LegacyWebArchive> archive = create(); |
+ if (!archive->init(data)) |
+ return 0; |
+ |
+ return archive.release(); |
+} |
+ |
+PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(PassRefPtr<ArchiveResource> mainResource, Vector<PassRefPtr<ArchiveResource> >& subresources, Vector<PassRefPtr<LegacyWebArchive> >& subframeArchives) |
+{ |
+ ASSERT(mainResource); |
+ if (!mainResource) |
+ return 0; |
+ |
+ RefPtr<LegacyWebArchive> archive = create(); |
+ archive->setMainResource(mainResource); |
+ |
+ for (unsigned i = 0; i < subresources.size(); ++i) |
+ archive->addSubresource(subresources[i]); |
+ |
+ for (unsigned i = 0; i < subframeArchives.size(); ++i) |
+ archive->addSubframeArchive(subframeArchives[i]); |
+ |
+ return archive.release(); |
+} |
+ |
+LegacyWebArchive::LegacyWebArchive() |
+{ |
+} |
+ |
+bool LegacyWebArchive::init(SharedBuffer* data) |
+{ |
+ ASSERT(data); |
+ if (!data) |
+ return false; |
+ |
+ RetainPtr<CFDataRef> cfData(AdoptCF, data->createCFData()); |
+ if (!cfData) |
+ return false; |
+ |
+ CFStringRef errorString = 0; |
+ |
+ RetainPtr<CFDictionaryRef> plist(AdoptCF, static_cast<CFDictionaryRef>(CFPropertyListCreateFromXMLData(0, cfData.get(), kCFPropertyListImmutable, &errorString))); |
+ if (!plist) { |
+#ifndef NDEBUG |
+ const char* cError = errorString ? CFStringGetCStringPtr(errorString, kCFStringEncodingUTF8) : "unknown error"; |
+ LOG(Archives, "LegacyWebArchive - Error parsing PropertyList from archive data - %s", cError); |
+#endif |
+ if (errorString) |
+ CFRelease(errorString); |
+ return false; |
+ } |
+ |
+ if (CFGetTypeID(plist.get()) != CFDictionaryGetTypeID()) { |
+ LOG(Archives, "LegacyWebArchive - Archive property list is not the expected CFDictionary, aborting invalid WebArchive"); |
+ return false; |
+ } |
+ |
+ return extract(plist.get()); |
+} |
+ |
+bool LegacyWebArchive::extract(CFDictionaryRef dictionary) |
+{ |
+ ASSERT(dictionary); |
+ if (!dictionary) { |
+ LOG(Archives, "LegacyWebArchive - Null root CFDictionary, aborting invalid WebArchive"); |
+ return false; |
+ } |
+ |
+ CFDictionaryRef mainResourceDict = static_cast<CFDictionaryRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveMainResourceKey)); |
+ if (!mainResourceDict) { |
+ LOG(Archives, "LegacyWebArchive - No main resource in archive, aborting invalid WebArchive"); |
+ return false; |
+ } |
+ if (CFGetTypeID(mainResourceDict) != CFDictionaryGetTypeID()) { |
+ LOG(Archives, "LegacyWebArchive - Main resource is not the expected CFDictionary, aborting invalid WebArchive"); |
+ return false; |
+ } |
+ |
+ setMainResource(createResource(mainResourceDict)); |
+ if (!mainResource()) { |
+ LOG(Archives, "LegacyWebArchive - Failed to parse main resource from CFDictionary or main resource does not exist, aborting invalid WebArchive"); |
+ return false; |
+ } |
+ |
+ CFArrayRef subresourceArray = static_cast<CFArrayRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveSubresourcesKey)); |
+ if (subresourceArray && CFGetTypeID(subresourceArray) != CFArrayGetTypeID()) { |
+ LOG(Archives, "LegacyWebArchive - Subresources is not the expected Array, aborting invalid WebArchive"); |
+ return false; |
+ } |
+ |
+ if (subresourceArray) { |
+ CFIndex count = CFArrayGetCount(subresourceArray); |
+ for (CFIndex i = 0; i < count; ++i) { |
+ CFDictionaryRef subresourceDict = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(subresourceArray, i)); |
+ if (CFGetTypeID(subresourceDict) != CFDictionaryGetTypeID()) { |
+ LOG(Archives, "LegacyWebArchive - Subresource is not expected CFDictionary, aborting invalid WebArchive"); |
+ return false; |
+ } |
+ addSubresource(createResource(subresourceDict)); |
+ } |
+ } |
+ |
+ CFArrayRef subframeArray = static_cast<CFArrayRef>(CFDictionaryGetValue(dictionary, LegacyWebArchiveSubframeArchivesKey)); |
+ if (subframeArray && CFGetTypeID(subframeArray) != CFArrayGetTypeID()) { |
+ LOG(Archives, "LegacyWebArchive - Subframe archives is not the expected Array, aborting invalid WebArchive"); |
+ return false; |
+ } |
+ |
+ if (subframeArray) { |
+ CFIndex count = CFArrayGetCount(subframeArray); |
+ for (CFIndex i = 0; i < count; ++i) { |
+ CFDictionaryRef subframeDict = static_cast<CFDictionaryRef>(CFArrayGetValueAtIndex(subframeArray, i)); |
+ if (CFGetTypeID(subframeDict) != CFDictionaryGetTypeID()) { |
+ LOG(Archives, "LegacyWebArchive - Subframe array is not expected CFDictionary, aborting invalid WebArchive"); |
+ return false; |
+ } |
+ |
+ RefPtr<LegacyWebArchive> subframeArchive = create(); |
+ if (subframeArchive->extract(subframeDict)) |
+ addSubframeArchive(subframeArchive.release()); |
+ else |
+ LOG(Archives, "LegacyWebArchive - Invalid subframe archive skipped"); |
+ } |
+ } |
+ |
+ return true; |
+} |
+ |
+RetainPtr<CFDataRef> LegacyWebArchive::rawDataRepresentation() |
+{ |
+ RetainPtr<CFDictionaryRef> propertyList = createPropertyListRep(this); |
+ if (!propertyList) { |
+ LOG(Archives, "LegacyWebArchive - Failed to create property list for archive, returning no data"); |
+ return 0; |
+ } |
+ |
+ RetainPtr<CFWriteStreamRef> stream(AdoptCF, CFWriteStreamCreateWithAllocatedBuffers(0, 0)); |
+ |
+ CFWriteStreamOpen(stream.get()); |
+ CFPropertyListWriteToStream(propertyList.get(), stream.get(), kCFPropertyListBinaryFormat_v1_0, 0); |
+ |
+ RetainPtr<CFDataRef> plistData(AdoptCF, static_cast<CFDataRef>(CFWriteStreamCopyProperty(stream.get(), kCFStreamPropertyDataWritten))); |
+ |
+ CFWriteStreamClose(stream.get()); |
+ |
+ if (!plistData) { |
+ LOG(Archives, "LegacyWebArchive - Failed to convert property list into raw data, returning no data"); |
+ return 0; |
+ } |
+ |
+ return plistData; |
+} |
+ |
+#if !PLATFORM(MAC) |
+// FIXME: Is it possible to parse in a Cocoa-style resource response manually, |
+// without NSKeyed(Un)Archiver, manipulating plists directly? |
+// If so, the code that does it will go here. |
+// In the meantime, Mac will continue to NSKeyed(Un)Archive the response as it always has |
+ResourceResponse createResourceResponseFromMacArchivedData(CFDataRef responseData) |
+{ |
+ return ResourceResponse(); |
+} |
+ |
+RetainPtr<CFDataRef> propertyListDataFromResourceResponse(const ResourceResponse& response) |
+{ |
+ // FIXME: Write out the "new" format described in ::createResourceResponseFromPropertyListData() up above |
+ return 0; |
+} |
+#endif |
+ |
+PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(Node* node) |
+{ |
+ ASSERT(node); |
+ if (!node) |
+ return create(); |
+ |
+ Document* document = node->document(); |
+ Frame* frame = document ? document->frame() : 0; |
+ if (!frame) |
+ return create(); |
+ |
+ Vector<Node*> nodeList; |
+ String markupString = createMarkup(node, IncludeNode, &nodeList); |
+ Node::NodeType nodeType = node->nodeType(); |
+ if (nodeType != Node::DOCUMENT_NODE && nodeType != Node::DOCUMENT_TYPE_NODE) |
+ markupString = frame->documentTypeString() + markupString; |
+ |
+ return create(markupString, frame, nodeList); |
+} |
+ |
+PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(Frame* frame) |
+{ |
+ ASSERT(frame); |
+ |
+ DocumentLoader* documentLoader = frame->loader()->documentLoader(); |
+ |
+ if (!documentLoader) |
+ return 0; |
+ |
+ Vector<PassRefPtr<LegacyWebArchive> > subframeArchives; |
+ |
+ unsigned children = frame->tree()->childCount(); |
+ for (unsigned i = 0; i < children; ++i) { |
+ RefPtr<LegacyWebArchive> childFrameArchive = create(frame->tree()->child(i)); |
+ if (childFrameArchive) |
+ subframeArchives.append(childFrameArchive.release()); |
+ } |
+ |
+ Vector<PassRefPtr<ArchiveResource> > subresources; |
+ documentLoader->getSubresources(subresources); |
+ |
+ return LegacyWebArchive::create(documentLoader->mainResource(), subresources, subframeArchives); |
+} |
+ |
+PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(Range* range) |
+{ |
+ if (!range) |
+ return 0; |
+ |
+ Node* startContainer = range->startContainer(); |
+ if (!startContainer) |
+ return 0; |
+ |
+ Document* document = startContainer->document(); |
+ if (!document) |
+ return 0; |
+ |
+ Frame* frame = document->frame(); |
+ if (!frame) |
+ return 0; |
+ |
+ Vector<Node*> nodeList; |
+ |
+ // FIXME: This is always "for interchange". Is that right? See the previous method. |
+ String markupString = frame->documentTypeString() + createMarkup(range, &nodeList, AnnotateForInterchange); |
+ |
+ return create(markupString, frame, nodeList); |
+} |
+ |
+PassRefPtr<LegacyWebArchive> LegacyWebArchive::create(const String& markupString, Frame* frame, Vector<Node*>& nodes) |
+{ |
+ ASSERT(frame); |
+ |
+ const ResourceResponse& response = frame->loader()->documentLoader()->response(); |
+ KURL responseURL = response.url(); |
+ |
+ // it's possible to have a response without a URL here |
+ // <rdar://problem/5454935> |
+ if (responseURL.isNull()) |
+ responseURL = KURL(""); |
+ |
+ PassRefPtr<ArchiveResource> mainResource = ArchiveResource::create(utf8Buffer(markupString), responseURL, response.mimeType(), "UTF-8", frame->tree()->name()); |
+ |
+ Vector<PassRefPtr<LegacyWebArchive> > subframeArchives; |
+ Vector<PassRefPtr<ArchiveResource> > subresources; |
+ HashSet<KURL> uniqueSubresources; |
+ |
+ Vector<Node*>::iterator it = nodes.begin(); |
+ Vector<Node*>::iterator end = nodes.end(); |
+ |
+ for (; it != end; ++it) { |
+ Frame* childFrame; |
+ if (((*it)->hasTagName(HTMLNames::frameTag) || (*it)->hasTagName(HTMLNames::iframeTag) || (*it)->hasTagName(HTMLNames::objectTag)) && |
+ (childFrame = static_cast<HTMLFrameOwnerElement*>(*it)->contentFrame())) { |
+ RefPtr<LegacyWebArchive> subframeArchive; |
+ if (Document* document = childFrame->document()) |
+ subframeArchive = LegacyWebArchive::create(document); |
+ else |
+ subframeArchive = create(childFrame); |
+ |
+ if (subframeArchive) |
+ subframeArchives.append(subframeArchive); |
+ else |
+ LOG_ERROR("Unabled to archive subframe %s", childFrame->tree()->name().string().utf8().data()); |
+ } else { |
+ ListHashSet<KURL> subresourceURLs; |
+ (*it)->getSubresourceURLs(subresourceURLs); |
+ |
+ DocumentLoader* documentLoader = frame->loader()->documentLoader(); |
+ ListHashSet<KURL>::iterator iterEnd = subresourceURLs.end(); |
+ for (ListHashSet<KURL>::iterator iter = subresourceURLs.begin(); iter != iterEnd; ++iter) { |
+ const KURL& subresourceURL = *iter; |
+ if (uniqueSubresources.contains(subresourceURL)) |
+ continue; |
+ |
+ uniqueSubresources.add(subresourceURL); |
+ |
+ RefPtr<ArchiveResource> resource = documentLoader->subresource(subresourceURL); |
+ if (resource) { |
+ subresources.append(resource.release()); |
+ continue; |
+ } |
+ |
+ CachedResource *cachedResource = cache()->resourceForURL(subresourceURL); |
+ if (cachedResource) { |
+ resource = ArchiveResource::create(cachedResource->data(), subresourceURL, cachedResource->response()); |
+ if (resource) { |
+ subresources.append(resource.release()); |
+ continue; |
+ } |
+ } |
+ |
+ // FIXME: should do something better than spew to console here |
+ LOG_ERROR("Failed to archive subresource for %s", subresourceURL.string().utf8().data()); |
+ } |
+ } |
+ } |
+ |
+ // Add favicon if one exists for this page |
+ if (iconDatabase() && iconDatabase()->isEnabled()) { |
+ const String& iconURL = iconDatabase()->iconURLForPageURL(responseURL); |
+ if (!iconURL.isEmpty() && iconDatabase()->iconDataKnownForIconURL(iconURL)) { |
+ if (Image* iconImage = iconDatabase()->iconForPageURL(responseURL, IntSize(16, 16))) { |
+ RefPtr<ArchiveResource> resource = ArchiveResource::create(iconImage->data(), KURL(iconURL), "image/x-icon", "", ""); |
+ subresources.append(resource.release()); |
+ } |
+ } |
+ } |
+ |
+ return create(mainResource, subresources, subframeArchives); |
+} |
+ |
+PassRefPtr<LegacyWebArchive> LegacyWebArchive::createFromSelection(Frame* frame) |
+{ |
+ if (!frame) |
+ return 0; |
+ |
+ RefPtr<Range> selectionRange = frame->selection()->toNormalizedRange(); |
+ Vector<Node*> nodeList; |
+ String markupString = frame->documentTypeString() + createMarkup(selectionRange.get(), &nodeList, AnnotateForInterchange); |
+ |
+ RefPtr<LegacyWebArchive> archive = create(markupString, frame, nodeList); |
+ |
+ if (!frame->document() || !frame->document()->isFrameSet()) |
+ return archive.release(); |
+ |
+ // Wrap the frameset document in an iframe so it can be pasted into |
+ // another document (which will have a body or frameset of its own). |
+ String iframeMarkup = String::format("<iframe frameborder=\"no\" marginwidth=\"0\" marginheight=\"0\" width=\"98%%\" height=\"98%%\" src=\"%s\"></iframe>", |
+ frame->loader()->documentLoader()->response().url().string().utf8().data()); |
+ RefPtr<ArchiveResource> iframeResource = ArchiveResource::create(utf8Buffer(iframeMarkup), blankURL(), "text/html", "UTF-8", String()); |
+ |
+ Vector<PassRefPtr<ArchiveResource> > subresources; |
+ |
+ Vector<PassRefPtr<LegacyWebArchive> > subframeArchives; |
+ subframeArchives.append(archive); |
+ |
+ archive = LegacyWebArchive::create(iframeResource.release(), subresources, subframeArchives); |
+ |
+ return archive.release(); |
+} |
+ |
+} |