diff options
author | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-27 00:20:51 +0000 |
---|---|---|
committer | initial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-07-27 00:20:51 +0000 |
commit | f5b16fed647e941aa66933178da85db2860d639b (patch) | |
tree | f00e9856c04aad3b558a140955e7674add33f051 /webkit/glue/glue_serialize.cc | |
parent | 920c091ac3ee15079194c82ae8a7a18215f3f23c (diff) | |
download | chromium_src-f5b16fed647e941aa66933178da85db2860d639b.zip chromium_src-f5b16fed647e941aa66933178da85db2860d639b.tar.gz chromium_src-f5b16fed647e941aa66933178da85db2860d639b.tar.bz2 |
Add webkit to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@18 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'webkit/glue/glue_serialize.cc')
-rw-r--r-- | webkit/glue/glue_serialize.cc | 385 |
1 files changed, 385 insertions, 0 deletions
diff --git a/webkit/glue/glue_serialize.cc b/webkit/glue/glue_serialize.cc new file mode 100644 index 0000000..8ea4286 --- /dev/null +++ b/webkit/glue/glue_serialize.cc @@ -0,0 +1,385 @@ +// Copyright 2008, Google 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: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * 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. +// * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT +// OWNER OR 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 <string> + +#pragma warning(push, 0) +#include "HistoryItem.h" +#include "PlatformString.h" +#include "ResourceRequest.h" +#pragma warning(pop) +#undef LOG + +#include "webkit/glue/glue_serialize.h" + +#include "base/pickle.h" +#include "base/scoped_ptr.h" +#include "base/string_util.h" +#include "webkit/glue/glue_util.h" +#include "webkit/glue/webkit_glue.h" + +using namespace WebCore; + +namespace webkit_glue { + +struct SerializeObject { + SerializeObject() : iter(NULL) {} + SerializeObject(const char* data, int len) : pickle(data, len), iter(NULL) {} + + std::string GetAsString() { + return std::string(static_cast<const char*>(pickle.data()), pickle.size()); + } + + Pickle pickle; + mutable void* iter; + mutable int version; +}; + +// TODO(mpcomplete): obsolete versions 1 and 2 after 1/1/2008. +// Version ID used in reading/writing history items. +// 1: Initial revision. +// 2: Added case for NULL string versus "". Version 2 code can read Version 1 +// data, but not vice versa. +// 3: Version 2 was broken, it stored number of UChars, not number of bytes. +// This version checks and reads v1 and v2 correctly. +// Should be const, but unit tests may modify it. +int kVersion = 3; + +// A bunch of convenience functions to read/write to SerializeObjects. +// The serializers assume the input data is in the correct format and so does +// no error checking. +inline void WriteData(const void* data, int length, SerializeObject* obj) { + obj->pickle.WriteData(static_cast<const char*>(data), length); +} + +inline void ReadData(const SerializeObject* obj, const void** data, + int* length) { + const char* tmp; + obj->pickle.ReadData(&obj->iter, &tmp, length); + *data = tmp; +} + +inline bool ReadBytes(const SerializeObject* obj, const void** data, + int length) { + const char *tmp; + if (!obj->pickle.ReadBytes(&obj->iter, &tmp, length)) + return false; + *data = tmp; + return true; +} + +inline void WriteInteger(int data, SerializeObject* obj) { + obj->pickle.WriteInt(data); +} + +inline int ReadInteger(const SerializeObject* obj) { + int tmp; + obj->pickle.ReadInt(&obj->iter, &tmp); + return tmp; +} + +inline void WriteReal(double data, SerializeObject* obj) { + WriteData(&data, sizeof(double), obj); +} + +inline double ReadReal(const SerializeObject* obj) { + const void* tmp; + int length; + ReadData(obj, &tmp, &length); + return *static_cast<const double*>(tmp); +} + +inline void WriteBoolean(bool data, SerializeObject* obj) { + obj->pickle.WriteInt(data ? 1 : 0); +} + +inline bool ReadBoolean(const SerializeObject* obj) { + bool tmp; + obj->pickle.ReadBool(&obj->iter, &tmp); + return tmp; +} + +// Read/WriteString pickle the String as <int length><UChar* data>. +// If length == -1, then the String itself is NULL (String()). +// Otherwise the length is the number of UChars (not bytes) in the String. +inline void WriteString(const String& data, SerializeObject* obj) { + switch (kVersion) { + case 1: + // Version 1 writes <length in bytes><string data>. + // It saves String() and "" as "". + obj->pickle.WriteInt(data.length() * sizeof(UChar)); + obj->pickle.WriteBytes(data.characters(), data.length() * sizeof(UChar)); + break; + case 2: + // Version 2 writes <length in UChars><string data>. + // It uses -1 in the length field to mean String(). + if (data.isNull()) { + obj->pickle.WriteInt(-1); + } else { + obj->pickle.WriteInt(data.length()); + obj->pickle.WriteBytes(data.characters(), + data.length() * sizeof(UChar)); + } + break; + case 3: + // Version 3 writes <length in bytes><string data>. + // It uses -1 in the length field to mean String(). + if (data.isNull()) { + obj->pickle.WriteInt(-1); + } else { + obj->pickle.WriteInt(data.length() * sizeof(UChar)); + obj->pickle.WriteBytes(data.characters(), + data.length() * sizeof(UChar)); + } + break; + default: + NOTREACHED(); + break; + } +} + +// This reads a serialized String from obj. If a string can't be read, +// String() is returned. +inline String ReadString(const SerializeObject* obj) { + int length; + + // Versions 1, 2, and 3 all start with an integer. + if (!obj->pickle.ReadInt(&obj->iter, &length)) + return String(); + + // Starting with version 2, -1 means String(). + if (length == -1) + return String(); + + // In version 2, the length field was the length in UChars. + // In version 1 and 3 it is the length in bytes. + int bytes = ((obj->version == 2) ? length * sizeof(UChar) : length); + + const void* data; + if (!ReadBytes(obj, &data, bytes)) + return String(); + return String(static_cast<const UChar*>(data), bytes / sizeof(UChar)); +} + +// Writes a Vector of Strings into a SerializeObject for serialization. +static void WriteStringVector(const Vector<String>& data, SerializeObject* obj) { + WriteInteger(static_cast<int>(data.size()), obj); + for (size_t i = 0, c = data.size(); i < c; ++i) { + unsigned ui = static_cast<unsigned>(i); // sigh + WriteString(data[ui], obj); + } +} + +static void ReadStringVector(const SerializeObject* obj, Vector<String>* data) { + int num_elements = ReadInteger(obj); + data->reserveCapacity(num_elements); + for (int i = 0; i < num_elements; ++i) { + data->append(ReadString(obj)); + } +} + +// Writes a FormData object into a SerializeObject for serialization. +static void WriteFormData(const FormData* form_data, SerializeObject* obj) { + if (form_data == NULL) { + WriteInteger(0, obj); + return; + } + + WriteInteger(static_cast<int>(form_data->elements().size()), obj); + for (size_t i = 0, c = form_data->elements().size(); i < c; ++i) { + const FormDataElement& e = form_data->elements().at(i); + WriteInteger(e.m_type, obj); + + if (e.m_type == FormDataElement::data) { + WriteData(e.m_data.data(), static_cast<int>(e.m_data.size()), obj); + } else { + WriteString(e.m_filename, obj); + } + } +} + +static FormData* ReadFormData(const SerializeObject* obj) { + int num_elements = ReadInteger(obj); + if (num_elements == 0) + return NULL; + + FormData* form_data = new FormData(); + + for (int i = 0; i < num_elements; ++i) { + int type = ReadInteger(obj); + if (type == FormDataElement::data) { + const void* data; + int length; + ReadData(obj, &data, &length); + form_data->appendData(static_cast<const char*>(data), length); + } else { + form_data->appendFile(ReadString(obj)); + } + } + + return form_data; +} + +// Writes the HistoryItem data into the SerializeObject object for +// serialization. +static void WriteHistoryItem(const HistoryItem* item, SerializeObject* obj) { + // WARNING: This data may be persisted for later use. As such, care must be + // taken when changing the serialized format. If a new field needs to be + // written, only adding at the end will make it easier to deal with loading + // older versions. Similarly, this should NOT save fields with sensitive + // data, such as password fields. + WriteInteger(kVersion, obj); + WriteString(item->urlString(), obj); + WriteString(item->originalURLString(), obj); + WriteString(item->target(), obj); + WriteString(item->parent(), obj); + WriteString(item->title(), obj); + WriteString(item->alternateTitle(), obj); + WriteReal(item->lastVisitedTime(), obj); + WriteInteger(item->scrollPoint().x(), obj); + WriteInteger(item->scrollPoint().y(), obj); + WriteBoolean(item->isTargetItem(), obj); + WriteInteger(item->visitCount(), obj); + WriteString(item->rssFeedReferrer(), obj); + + WriteStringVector(item->documentState(), obj); + + // No access to formData through a const HistoryItem = lame. + WriteFormData(const_cast<HistoryItem*>(item)->formData(), obj); + WriteString(item->formContentType(), obj); + WriteString(item->formReferrer(), obj); + + // Subitems + WriteInteger(static_cast<int>(item->children().size()), obj); + for (size_t i = 0, c = item->children().size(); i < c; ++i) + WriteHistoryItem(item->children().at(i).get(), obj); +} + +// Creates a new HistoryItem tree based on the serialized string. +// Assumes the data is in the format returned by WriteHistoryItem. +static HistoryItem* ReadHistoryItem(const SerializeObject* obj) { + // See note in WriteHistoryItem. on this. + obj->version = ReadInteger(obj); + + if (obj->version > kVersion) + return NULL; + + HistoryItem* item = new HistoryItem(); + + item->setURLString(ReadString(obj)); + item->setOriginalURLString(ReadString(obj)); + item->setTarget(ReadString(obj)); + item->setParent(ReadString(obj)); + item->setTitle(ReadString(obj)); + item->setAlternateTitle(ReadString(obj)); + item->setLastVisitedTime(ReadReal(obj)); + int x = ReadInteger(obj); + int y = ReadInteger(obj); + item->setScrollPoint(IntPoint(x, y)); + item->setIsTargetItem(ReadBoolean(obj)); + item->setVisitCount(ReadInteger(obj)); + item->setRSSFeedReferrer(ReadString(obj)); + + Vector<String> document_state; + ReadStringVector(obj, &document_state); + item->setDocumentState(document_state); + + // Form data. If there is any form data, we assume POST, otherwise GET. + // ResourceRequest takes ownership of the new FormData, then gives it to + // HistoryItem. + ResourceRequest dummy_request; // only way to initialize HistoryItem + dummy_request.setHTTPBody(ReadFormData(obj)); + dummy_request.setHTTPContentType(ReadString(obj)); + dummy_request.setHTTPReferrer(ReadString(obj)); + if (dummy_request.httpBody()) + dummy_request.setHTTPMethod("POST"); + item->setFormInfoFromRequest(dummy_request); + + // Subitems + int num_children = ReadInteger(obj); + for (int i = 0; i < num_children; ++i) + item->addChildItem(ReadHistoryItem(obj)); + + return item; +} + +// Serialize a HistoryItem to a string, using our JSON Value serializer. +void HistoryItemToString(PassRefPtr<HistoryItem> item, + std::string* serialized_item) { + if (!item) { + serialized_item->clear(); + return; + } + + SerializeObject obj; + WriteHistoryItem(item.get(), &obj); + *serialized_item = obj.GetAsString(); +} + +// Reconstruct a HistoryItem from a string, using our JSON Value deserializer. +// This assumes that the given serialized string has all the required key,value +// pairs, and does minimal error checking. +PassRefPtr<HistoryItem> HistoryItemFromString( + const std::string& serialized_item) { + if (serialized_item.empty()) + return NULL; + + SerializeObject obj(serialized_item.data(), + static_cast<int>(serialized_item.length())); + return ReadHistoryItem(&obj); +} + +// For testing purposes only. +void HistoryItemToVersionedString(PassRefPtr<HistoryItem> item, int version, + std::string* serialized_item) { + if (!item) { + serialized_item->clear(); + return; + } + + // Temporarily change the version. + int real_version = kVersion; + kVersion = version; + + SerializeObject obj; + WriteHistoryItem(item.get(), &obj); + *serialized_item = obj.GetAsString(); + + kVersion = real_version; +} + +std::string CreateHistoryStateForURL(const GURL& url) { + RefPtr<HistoryItem> item(new HistoryItem(GURLToKURL(url), String())); + std::string data; + HistoryItemToString(item, &data); + return data; +} + +} // namespace webkit_glue |