1d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter/*
2d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter * Copyright 2010, The Android Open Source Project
3d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter *
4d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter * Redistribution and use in source and binary forms, with or without
5d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter * modification, are permitted provided that the following conditions
6d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter * are met:
7d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter *  * Redistributions of source code must retain the above copyright
8d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter *    notice, this list of conditions and the following disclaimer.
9d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter *  * Redistributions in binary form must reproduce the above copyright
10d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter *    notice, this list of conditions and the following disclaimer in the
11d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter *    documentation and/or other materials provided with the distribution.
12d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter *
13d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter */
25d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
26d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter#define LOG_TAG "webarchive"
27d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
28d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter#include "config.h"
29d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter#include "WebArchiveAndroid.h"
30d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
31d73b16bdebb9d20b17be0a30e626dc9e66b6d868Steve Block#if ENABLE(WEB_ARCHIVE)
325dc3f82ee1d379f4df8606cdf60369965b44486cSteve Block
33d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter#include "Base64.h"
34d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter#include <libxml/encoding.h>
35d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter#include <libxml/parser.h>
36d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter#include <libxml/tree.h>
37d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter#include <libxml/xmlstring.h>
38d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter#include <libxml/xmlwriter.h>
3930a9d6dfa5ddf75aef0fcf23f7bfbffa41a704ffSteve Block#include <utils/Log.h>
40d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter#include <wtf/text/CString.h>
41d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
42d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughternamespace WebCore {
43d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
44d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic const xmlChar* const archiveTag = BAD_CAST "Archive";
45d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic const xmlChar* const archiveResourceTag = BAD_CAST "ArchiveResource";
46d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic const xmlChar* const mainResourceTag = BAD_CAST "mainResource";
47d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic const xmlChar* const subresourcesTag = BAD_CAST "subresources";
48d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic const xmlChar* const subframesTag = BAD_CAST "subframes";
49d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic const xmlChar* const urlFieldTag = BAD_CAST "url";
50d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic const xmlChar* const mimeFieldTag = BAD_CAST "mimeType";
51d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic const xmlChar* const encodingFieldTag = BAD_CAST "textEncoding";
52d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic const xmlChar* const frameFieldTag = BAD_CAST "frameName";
53d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic const xmlChar* const dataFieldTag = BAD_CAST "data";
54d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
55d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott SlaughterPassRefPtr<WebArchiveAndroid> WebArchiveAndroid::create(PassRefPtr<ArchiveResource> mainResource,
56d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        Vector<PassRefPtr<ArchiveResource> >& subresources,
57d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        Vector<PassRefPtr<Archive> >& subframeArchives)
58d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter{
59320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter    if (mainResource)
60d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return adoptRef(new WebArchiveAndroid(mainResource, subresources, subframeArchives));
61320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter    return 0;
62d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter}
63d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
64d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott SlaughterPassRefPtr<WebArchiveAndroid> WebArchiveAndroid::create(Frame* frame)
65d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter{
66d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    PassRefPtr<ArchiveResource> mainResource = frame->loader()->documentLoader()->mainResource();
67d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    Vector<PassRefPtr<ArchiveResource> > subresources;
68d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    Vector<PassRefPtr<Archive> > subframes;
69d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    int children = frame->tree()->childCount();
70d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
71d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    frame->loader()->documentLoader()->getSubresources(subresources);
72d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
73320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter    for (int child = 0; child < children; child++)
74d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        subframes.append(create(frame->tree()->child(child)));
75d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
76d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    return create(mainResource, subresources, subframes);
77d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter}
78d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
79d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott SlaughterWebArchiveAndroid::WebArchiveAndroid(PassRefPtr<ArchiveResource> mainResource,
80d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        Vector<PassRefPtr<ArchiveResource> >& subresources,
81d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        Vector<PassRefPtr<Archive> >& subframeArchives)
82d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter{
83d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    setMainResource(mainResource);
84d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
85d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    for (Vector<PassRefPtr<ArchiveResource> >::iterator subresourcesIterator = subresources.begin();
86d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter         subresourcesIterator != subresources.end();
87d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter         subresourcesIterator++) {
88d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        addSubresource(*subresourcesIterator);
89d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
90d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
91d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    for (Vector<PassRefPtr<Archive> >::iterator subframesIterator = subframeArchives.begin();
92d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter         subframesIterator != subframeArchives.end();
93d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter         subframesIterator++) {
94d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        addSubframeArchive(*subframesIterator);
95d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
96d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter}
97d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
98d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic bool loadArchiveResourceField(xmlNodePtr resourceNode, const xmlChar* fieldName, Vector<char>* outputData)
99d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter{
100d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (!outputData)
101d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return false;
102d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
103d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    outputData->clear();
104d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
105320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter    const char* base64Data = 0;
106d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
107d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    for (xmlNodePtr fieldNode = resourceNode->xmlChildrenNode;
108320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter         fieldNode;
109d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter         fieldNode = fieldNode->next) {
110d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        if (xmlStrEqual(fieldNode->name, fieldName)) {
111d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter            base64Data = (const char*)xmlNodeGetContent(fieldNode->xmlChildrenNode);
112d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter            if (!base64Data) {
113d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter                /* Empty fields seem to break if they aren't null terminated. */
114d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter                outputData->append('\0');
115d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter                return true;
116d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter            }
117d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter            break;
118d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        }
119d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
120d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (!base64Data) {
121a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("loadArchiveResourceField: Failed to load field.");
122d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return false;
123d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
124d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
125d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    const int base64Size = xmlStrlen(BAD_CAST base64Data);
126d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
127d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    const int result = base64Decode(base64Data, base64Size, *outputData);
128d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (!result) {
129a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("loadArchiveResourceField: Failed to decode field.");
130d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return false;
131d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
132d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
133d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    return true;
134d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter}
135d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
136d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic PassRefPtr<SharedBuffer> loadArchiveResourceFieldBuffer(xmlNodePtr resourceNode, const xmlChar* fieldName)
137d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter{
138d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    Vector<char> fieldData;
139d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
140d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (loadArchiveResourceField(resourceNode, fieldName, &fieldData))
141d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return SharedBuffer::create(fieldData.data(), fieldData.size());
142d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
143320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter    return 0;
144d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter}
145d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
146d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic String loadArchiveResourceFieldString(xmlNodePtr resourceNode, const xmlChar* fieldName)
147d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter{
148d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    Vector<char> fieldData;
149d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
150d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (loadArchiveResourceField(resourceNode, fieldName, &fieldData))
151d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return String::fromUTF8(fieldData.data(), fieldData.size());
152d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
153d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    return String();
154d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter}
155d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
156d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic KURL loadArchiveResourceFieldURL(xmlNodePtr resourceNode, const xmlChar* fieldName)
157d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter{
158d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    Vector<char> fieldData;
159d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
160d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (loadArchiveResourceField(resourceNode, fieldName, &fieldData))
161d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return KURL(ParsedURLString, String::fromUTF8(fieldData.data(), fieldData.size()));
162d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
163d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    return KURL();
164d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter}
165d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
166d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic PassRefPtr<ArchiveResource> loadArchiveResource(xmlNodePtr resourceNode)
167d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter{
168d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (!xmlStrEqual(resourceNode->name, archiveResourceTag)) {
169a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("loadArchiveResource: Malformed resource.");
170320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter        return 0;
171d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
172d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
173d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    KURL url = loadArchiveResourceFieldURL(resourceNode, urlFieldTag);
174d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (url.isNull()) {
175a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("loadArchiveResource: Failed to load resource.");
176320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter        return 0;
177d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
178d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
179d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    String mimeType = loadArchiveResourceFieldString(resourceNode, mimeFieldTag);
180d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (mimeType.isNull()) {
181a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("loadArchiveResource: Failed to load resource.");
182320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter        return 0;
183d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
184d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
185d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    String textEncoding = loadArchiveResourceFieldString(resourceNode, encodingFieldTag);
186d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (textEncoding.isNull()) {
187a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("loadArchiveResource: Failed to load resource.");
188320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter        return 0;
189d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
190d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
191d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    String frameName = loadArchiveResourceFieldString(resourceNode, frameFieldTag);
192d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (frameName.isNull()) {
193a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("loadArchiveResource: Failed to load resource.");
194320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter        return 0;
195d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
196d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
197d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    PassRefPtr<SharedBuffer> data = loadArchiveResourceFieldBuffer(resourceNode, dataFieldTag);
198d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (!data) {
199a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("loadArchiveResource: Failed to load resource.");
200320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter        return 0;
201d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
202d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
203d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    return ArchiveResource::create(data, url, mimeType, textEncoding, frameName);
204d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter}
205d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
206d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic PassRefPtr<WebArchiveAndroid> loadArchive(xmlNodePtr archiveNode)
207d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter{
208320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter    xmlNodePtr resourceNode = 0;
209d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
210d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    PassRefPtr<ArchiveResource> mainResource;
211d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    Vector<PassRefPtr<ArchiveResource> > subresources;
212d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    Vector<PassRefPtr<Archive> > subframes;
213d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
214d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (!xmlStrEqual(archiveNode->name, archiveTag)) {
215a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("loadArchive: Malformed archive.");
216320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter        return 0;
217d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
218d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
219d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    for (resourceNode = archiveNode->xmlChildrenNode;
220320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter         resourceNode;
221d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter         resourceNode = resourceNode->next) {
222d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        if (xmlStrEqual(resourceNode->name, mainResourceTag)) {
223d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter            resourceNode = resourceNode->xmlChildrenNode;
224320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter            if (!resourceNode)
225d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter                break;
226d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter            mainResource = loadArchiveResource(resourceNode);
227d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter            break;
228d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        }
229d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
230d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (!mainResource) {
231a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("loadArchive: Failed to load main resource.");
232320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter        return 0;
233d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
234d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
235d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    for (resourceNode = archiveNode->xmlChildrenNode;
236320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter         resourceNode;
237d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter         resourceNode = resourceNode->next) {
238d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        if (xmlStrEqual(resourceNode->name, subresourcesTag)) {
239d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter            for (resourceNode = resourceNode->xmlChildrenNode;
240320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter                 resourceNode;
241d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter                 resourceNode = resourceNode->next) {
242d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter                PassRefPtr<ArchiveResource> subresource = loadArchiveResource(resourceNode);
243d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter                if (!subresource) {
244a09e7cf49f43950a799f936bf42a9912d696547bSteve Block                    ALOGD("loadArchive: Failed to load subresource.");
245d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter                    break;
246d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter                }
247d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter                subresources.append(subresource);
248d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter            }
249d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter            break;
250d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        }
251d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
252d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
253d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    for (resourceNode = archiveNode->xmlChildrenNode;
254320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter         resourceNode;
255d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter         resourceNode = resourceNode->next) {
256d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        if (xmlStrEqual(resourceNode->name, subframesTag)) {
257d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter            for (resourceNode = resourceNode->xmlChildrenNode;
258320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter                 resourceNode;
259d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter                 resourceNode = resourceNode->next) {
260d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter                PassRefPtr<WebArchiveAndroid> subframe = loadArchive(resourceNode);
261d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter                if (!subframe) {
262a09e7cf49f43950a799f936bf42a9912d696547bSteve Block                    ALOGD("loadArchive: Failed to load subframe.");
263d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter                    break;
264d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter                }
265d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter                subframes.append(subframe);
266d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter            }
267d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter            break;
268d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        }
269d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
270d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
271d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    return WebArchiveAndroid::create(mainResource, subresources, subframes);
272d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter}
273d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
274320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughterstatic PassRefPtr<WebArchiveAndroid> createArchiveForError()
275320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter{
276d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    /* When an archive cannot be loaded, we return an empty archive instead. */
277d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    PassRefPtr<ArchiveResource> mainResource = ArchiveResource::create(
278d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        SharedBuffer::create(), KURL(ParsedURLString, String::fromUTF8("file:///dummy")),
279d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        String::fromUTF8("text/plain"), String(""), String(""));
280d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    Vector<PassRefPtr<ArchiveResource> > subresources;
281d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    Vector<PassRefPtr<Archive> > subframes;
282d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
283d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    return WebArchiveAndroid::create(mainResource, subresources, subframes);
284d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter}
285d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
286d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott SlaughterPassRefPtr<WebArchiveAndroid> WebArchiveAndroid::create(SharedBuffer* buffer)
287d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter{
288d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    const char* const noBaseUrl = "";
289320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter    const char* const defaultEncoding = 0;
290d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    const int noParserOptions = 0;
291d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
292d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    xmlDocPtr doc = xmlReadMemory(buffer->data(), buffer->size(), noBaseUrl, defaultEncoding, noParserOptions);
293320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter    if (!doc) {
294a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("create: Failed to parse document.");
295d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return createArchiveForError();
296d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
297d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
298d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    xmlNodePtr root = xmlDocGetRootElement(doc);
299320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter    if (!root) {
300a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("create: Empty document.");
301d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        xmlFreeDoc(doc);
302d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return createArchiveForError();
303d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
304d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
305d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    RefPtr<WebArchiveAndroid> archive = loadArchive(root);
306d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (!archive) {
307a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("create: Failed to load archive.");
308d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        xmlFreeDoc(doc);
309d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return createArchiveForError();
310d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
311d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
312d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    xmlFreeDoc(doc);
313d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    return archive.release();
314d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter}
315d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
316d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic bool saveArchiveResourceField(xmlTextWriterPtr writer, const xmlChar* tag, const char* data, int size)
317d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter{
318d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    int result = xmlTextWriterStartElement(writer, tag);
319d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (result < 0) {
320a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("saveArchiveResourceField: Failed to start element.");
321d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return false;
322d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
323d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
324d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (size > 0) {
325d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        Vector<char> base64Data;
326d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        base64Encode(data, size, base64Data, false);
327d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        if (base64Data.isEmpty()) {
328a09e7cf49f43950a799f936bf42a9912d696547bSteve Block            ALOGD("saveArchiveResourceField: Failed to base64 encode data.");
329d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter            return false;
330d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        }
331d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
332d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        result = xmlTextWriterWriteRawLen(writer, BAD_CAST base64Data.data(), base64Data.size());
333d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        if (result < 0) {
334a09e7cf49f43950a799f936bf42a9912d696547bSteve Block            ALOGD("saveArchiveResourceField: Failed to write data.");
335d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter            return false;
336d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        }
337d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
338d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
339d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    result = xmlTextWriterEndElement(writer);
340d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (result < 0) {
341a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("saveArchiveResourceField: Failed to end element.");
342d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return false;
343d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
344d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
345d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    return true;
346d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter}
347d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
348d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic bool saveArchiveResourceField(xmlTextWriterPtr writer, const xmlChar* tag, SharedBuffer* buffer)
349d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter{
350d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    return saveArchiveResourceField(writer, tag, buffer->data(), buffer->size());
351d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter}
352d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
353d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic bool saveArchiveResourceField(xmlTextWriterPtr writer, const xmlChar* tag, const String& string)
354d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter{
355d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    CString utf8String = string.utf8();
356d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
357d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    return saveArchiveResourceField(writer, tag, utf8String.data(), utf8String.length());
358d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter}
359d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
360d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughterstatic bool saveArchiveResource(xmlTextWriterPtr writer, PassRefPtr<ArchiveResource> resource)
361d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter{
362d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    int result = xmlTextWriterStartElement(writer, archiveResourceTag);
363d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (result < 0) {
364a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("saveArchiveResource: Failed to start element.");
365d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return false;
366d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
367d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
368d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (!saveArchiveResourceField(writer, urlFieldTag, resource->url().string())
369d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        || !saveArchiveResourceField(writer, mimeFieldTag, resource->mimeType())
370d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        || !saveArchiveResourceField(writer, encodingFieldTag, resource->textEncoding())
371d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        || !saveArchiveResourceField(writer, frameFieldTag, resource->frameName())
372d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        || !saveArchiveResourceField(writer, dataFieldTag, resource->data()))
373d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return false;
374d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
375d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    result = xmlTextWriterEndElement(writer);
376d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (result < 0) {
377a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("saveArchiveResource: Failed to end element.");
378d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return false;
379d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
380d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
381d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    return true;
382d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter}
383d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
384320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughterstatic bool saveArchive(xmlTextWriterPtr writer, PassRefPtr<Archive> archive)
385320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter{
386d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    int result = xmlTextWriterStartElement(writer, archiveTag);
387d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (result < 0) {
388a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("saveArchive: Failed to start element.");
389d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return false;
390d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
391d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
392d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    result = xmlTextWriterStartElement(writer, mainResourceTag);
393d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (result < 0) {
394a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("saveArchive: Failed to start element.");
395d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return false;
396d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
397d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
398d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (!saveArchiveResource(writer, archive->mainResource()))
399d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return false;
400d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
401d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    result = xmlTextWriterEndElement(writer);
402d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (result < 0) {
403a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("saveArchive: Failed to end element.");
404d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return false;
405d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
406d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
407d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    result = xmlTextWriterStartElement(writer, subresourcesTag);
408d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (result < 0) {
409a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("saveArchive: Failed to start element.");
410d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return false;
411d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
412d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
413d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    for (Vector<const RefPtr<ArchiveResource> >::iterator subresource = archive->subresources().begin();
414d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter         subresource != archive->subresources().end();
415d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter         subresource++) {
416d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        if (!saveArchiveResource(writer, *subresource))
417d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter            return false;
418d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
419d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
420d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    result = xmlTextWriterEndElement(writer);
421d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (result < 0) {
422a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("saveArchive: Failed to end element.");
423d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return false;
424d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
425d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
426d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    result = xmlTextWriterStartElement(writer, subframesTag);
427d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (result < 0) {
428a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("saveArchive: Failed to start element.");
429d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return false;
430d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
431d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
432d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    for (Vector<const RefPtr<Archive> >::iterator subframe = archive->subframeArchives().begin();
433d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter            subframe != archive->subframeArchives().end();
434d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter            subframe++) {
435320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter        if (!saveArchive(writer, *subframe))
436d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter            return false;
437d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
438d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
439d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    result = xmlTextWriterEndElement(writer);
440d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (result < 0) {
441a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("saveArchive: Failed to end element.");
442d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return true;
443d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
444d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
445d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    return true;
446d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter}
447d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
448320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughterbool WebArchiveAndroid::saveWebArchive(xmlTextWriterPtr writer)
449320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter{
450320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter    const char* const defaultXmlVersion = 0;
451320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter    const char* const defaultEncoding = 0;
452320d49d8900163ea450b99f106701a3455fb1bb6Elliott Slaughter    const char* const defaultStandalone = 0;
453d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
454d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    int result = xmlTextWriterStartDocument(writer, defaultXmlVersion, defaultEncoding, defaultStandalone);
455d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (result < 0) {
456a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("saveWebArchive: Failed to start document.");
457d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return false;
458d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
459d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
460d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (!saveArchive(writer, this))
461d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return false;
462d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
463d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    result = xmlTextWriterEndDocument(writer);
464d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    if (result< 0) {
465a09e7cf49f43950a799f936bf42a9912d696547bSteve Block        ALOGD("saveWebArchive: Failed to end document.");
466d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter        return false;
467d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    }
468d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
469d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter    return true;
470d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter}
471d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter
472d66cc5d8dc3be3dcfc78f5155cf9f7b8015ee7b4Elliott Slaughter}
4735dc3f82ee1d379f4df8606cdf60369965b44486cSteve Block
474d73b16bdebb9d20b17be0a30e626dc9e66b6d868Steve Block#endif // ENABLE(WEB_ARCHIVE)
475