--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/WebCore/bindings/v8/SerializedScriptValue.cpp Fri Sep 17 09:02:29 2010 +0300
@@ -0,0 +1,1097 @@
+/*
+ * Copyright (C) 2010 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 "SerializedScriptValue.h"
+
+#include "Blob.h"
+#include "ByteArray.h"
+#include "CanvasPixelArray.h"
+#include "ExceptionCode.h"
+#include "File.h"
+#include "FileList.h"
+#include "ImageData.h"
+#include "SharedBuffer.h"
+#include "V8Binding.h"
+#include "V8Blob.h"
+#include "V8File.h"
+#include "V8FileList.h"
+#include "V8ImageData.h"
+#include "V8Proxy.h"
+
+#include <wtf/Assertions.h>
+#include <wtf/RefCounted.h>
+#include <wtf/Vector.h>
+
+// FIXME:
+// - catch V8 exceptions
+// - consider crashing in debug mode on deserialization errors
+
+namespace WebCore {
+
+namespace {
+
+typedef UChar BufferValueType;
+
+// Serialization format is a sequence of (tag, optional data)
+// pairs. Tag always takes exactly one byte.
+enum SerializationTag {
+ InvalidTag = '!',
+ PaddingTag = '\0',
+ UndefinedTag = '_',
+ NullTag = '0',
+ TrueTag = 'T',
+ FalseTag = 'F',
+ StringTag = 'S',
+ Int32Tag = 'I',
+ Uint32Tag = 'U',
+ DateTag = 'D',
+ NumberTag = 'N',
+ BlobTag = 'b',
+ FileTag = 'f',
+ FileListTag = 'l',
+ ImageDataTag = '#',
+ ArrayTag = '[',
+ ObjectTag = '{',
+ SparseArrayTag = '@',
+};
+
+static bool shouldCheckForCycles(int depth)
+{
+ ASSERT(depth >= 0);
+ // Since we are not required to spot the cycle as soon as it
+ // happens we can check for cycles only when the current depth
+ // is a power of two.
+ return !(depth & (depth - 1));
+}
+
+static const int maxDepth = 20000;
+
+// VarInt encoding constants.
+static const int varIntShift = 7;
+static const int varIntMask = (1 << varIntShift) - 1;
+
+// ZigZag encoding helps VarInt encoding stay small for negative
+// numbers with small absolute values.
+class ZigZag {
+public:
+ static uint32_t encode(uint32_t value)
+ {
+ if (value & (1U << 31))
+ value = ((~value) << 1) + 1;
+ else
+ value <<= 1;
+ return value;
+ }
+
+ static uint32_t decode(uint32_t value)
+ {
+ if (value & 1)
+ value = ~(value >> 1);
+ else
+ value >>= 1;
+ return value;
+ }
+
+private:
+ ZigZag();
+};
+
+// Writer is responsible for serializing primitive types and storing
+// information used to reconstruct composite types.
+class Writer : Noncopyable {
+public:
+ Writer()
+ : m_position(0)
+ {
+ }
+
+ // Write functions for primitive types.
+
+ void writeUndefined() { append(UndefinedTag); }
+
+ void writeNull() { append(NullTag); }
+
+ void writeTrue() { append(TrueTag); }
+
+ void writeFalse() { append(FalseTag); }
+
+ void writeString(const char* data, int length)
+ {
+ ASSERT(length >= 0);
+ append(StringTag);
+ doWriteString(data, length);
+ }
+
+ void writeWebCoreString(const String& string)
+ {
+ // Uses UTF8 encoding so we can read it back as either V8 or
+ // WebCore string.
+ append(StringTag);
+ doWriteWebCoreString(string);
+ }
+
+ void writeInt32(int32_t value)
+ {
+ append(Int32Tag);
+ doWriteUint32(ZigZag::encode(static_cast<uint32_t>(value)));
+ }
+
+ void writeUint32(uint32_t value)
+ {
+ append(Uint32Tag);
+ doWriteUint32(value);
+ }
+
+ void writeDate(double numberValue)
+ {
+ append(DateTag);
+ doWriteNumber(numberValue);
+ }
+
+ void writeNumber(double number)
+ {
+ append(NumberTag);
+ doWriteNumber(number);
+ }
+
+ void writeBlob(const String& path)
+ {
+ append(BlobTag);
+ doWriteWebCoreString(path);
+ }
+
+ void writeFile(const String& path)
+ {
+ append(FileTag);
+ doWriteWebCoreString(path);
+ }
+
+ void writeFileList(const FileList& fileList)
+ {
+ append(FileListTag);
+ uint32_t length = fileList.length();
+ doWriteUint32(length);
+ for (unsigned i = 0; i < length; ++i)
+ doWriteWebCoreString(fileList.item(i)->path());
+ }
+
+ void writeImageData(uint32_t width, uint32_t height, const uint8_t* pixelData, uint32_t pixelDataLength)
+ {
+ append(ImageDataTag);
+ doWriteUint32(width);
+ doWriteUint32(height);
+ doWriteUint32(pixelDataLength);
+ append(pixelData, pixelDataLength);
+ }
+
+ void writeArray(uint32_t length)
+ {
+ append(ArrayTag);
+ doWriteUint32(length);
+ }
+
+ void writeObject(uint32_t numProperties)
+ {
+ append(ObjectTag);
+ doWriteUint32(numProperties);
+ }
+
+ void writeSparseArray(uint32_t numProperties, uint32_t length)
+ {
+ append(SparseArrayTag);
+ doWriteUint32(numProperties);
+ doWriteUint32(length);
+ }
+
+ Vector<BufferValueType>& data()
+ {
+ fillHole();
+ return m_buffer;
+ }
+
+private:
+ void doWriteString(const char* data, int length)
+ {
+ doWriteUint32(static_cast<uint32_t>(length));
+ append(reinterpret_cast<const uint8_t*>(data), length);
+ }
+
+ void doWriteWebCoreString(const String& string)
+ {
+ RefPtr<SharedBuffer> buffer = utf8Buffer(string);
+ doWriteString(buffer->data(), buffer->size());
+ }
+
+ void doWriteUint32(uint32_t value)
+ {
+ while (true) {
+ uint8_t b = (value & varIntMask);
+ value >>= varIntShift;
+ if (!value) {
+ append(b);
+ break;
+ }
+ append(b | (1 << varIntShift));
+ }
+ }
+
+ void doWriteNumber(double number)
+ {
+ append(reinterpret_cast<uint8_t*>(&number), sizeof(number));
+ }
+
+ void append(SerializationTag tag)
+ {
+ append(static_cast<uint8_t>(tag));
+ }
+
+ void append(uint8_t b)
+ {
+ ensureSpace(1);
+ *byteAt(m_position++) = b;
+ }
+
+ void append(const uint8_t* data, int length)
+ {
+ ensureSpace(length);
+ memcpy(byteAt(m_position), data, length);
+ m_position += length;
+ }
+
+ void ensureSpace(int extra)
+ {
+ COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes);
+ m_buffer.grow((m_position + extra + 1) / 2); // "+ 1" to round up.
+ }
+
+ void fillHole()
+ {
+ COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes);
+ // If the writer is at odd position in the buffer, then one of
+ // the bytes in the last UChar is not initialized.
+ if (m_position % 2)
+ *byteAt(m_position) = static_cast<uint8_t>(PaddingTag);
+ }
+
+ uint8_t* byteAt(int position) { return reinterpret_cast<uint8_t*>(m_buffer.data()) + position; }
+
+ Vector<BufferValueType> m_buffer;
+ unsigned m_position;
+};
+
+class Serializer {
+ class StateBase;
+public:
+ explicit Serializer(Writer& writer)
+ : m_writer(writer)
+ , m_depth(0)
+ , m_hasError(false)
+ {
+ }
+
+ bool serialize(v8::Handle<v8::Value> value)
+ {
+ v8::HandleScope scope;
+ StateBase* state = doSerialize(value, 0);
+ while (state)
+ state = state->advance(*this);
+ return !m_hasError;
+ }
+
+ // Functions used by serialization states.
+
+ StateBase* doSerialize(v8::Handle<v8::Value> value, StateBase* next);
+
+ StateBase* writeArray(uint32_t length, StateBase* state)
+ {
+ m_writer.writeArray(length);
+ return pop(state);
+ }
+
+ StateBase* writeObject(uint32_t numProperties, StateBase* state)
+ {
+ m_writer.writeObject(numProperties);
+ return pop(state);
+ }
+
+ StateBase* writeSparseArray(uint32_t numProperties, uint32_t length, StateBase* state)
+ {
+ m_writer.writeSparseArray(numProperties, length);
+ return pop(state);
+ }
+
+private:
+ class StateBase : public Noncopyable {
+ public:
+ virtual ~StateBase() { }
+
+ // Link to the next state to form a stack.
+ StateBase* nextState() { return m_next; }
+
+ // Composite object we're processing in this state.
+ v8::Handle<v8::Value> composite() { return m_composite; }
+
+ // Serializes (a part of) the current composite and returns
+ // the next state to process or null when this is the final
+ // state.
+ virtual StateBase* advance(Serializer&) = 0;
+
+ protected:
+ StateBase(v8::Handle<v8::Value> composite, StateBase* next)
+ : m_composite(composite)
+ , m_next(next)
+ {
+ }
+
+ private:
+ v8::Handle<v8::Value> m_composite;
+ StateBase* m_next;
+ };
+
+ // Dummy state that is used to signal serialization errors.
+ class ErrorState : public StateBase {
+ public:
+ ErrorState()
+ : StateBase(v8::Handle<v8::Value>(), 0)
+ {
+ }
+
+ virtual StateBase* advance(Serializer&)
+ {
+ delete this;
+ return 0;
+ }
+ };
+
+ template <typename T>
+ class State : public StateBase {
+ public:
+ v8::Handle<T> composite() { return v8::Handle<T>::Cast(StateBase::composite()); }
+
+ protected:
+ State(v8::Handle<T> composite, StateBase* next)
+ : StateBase(composite, next)
+ {
+ }
+ };
+
+#if 0
+ // Currently unused, see comment in newArrayState.
+ class ArrayState : public State<v8::Array> {
+ public:
+ ArrayState(v8::Handle<v8::Array> array, StateBase* next)
+ : State<v8::Array>(array, next)
+ , m_index(-1)
+ {
+ }
+
+ virtual StateBase* advance(Serializer& serializer)
+ {
+ ++m_index;
+ for (; m_index < composite()->Length(); ++m_index) {
+ if (StateBase* newState = serializer.doSerialize(composite()->Get(m_index), this))
+ return newState;
+ }
+ return serializer.writeArray(composite()->Length(), this);
+ }
+
+ private:
+ unsigned m_index;
+ };
+#endif
+
+ class AbstractObjectState : public State<v8::Object> {
+ public:
+ AbstractObjectState(v8::Handle<v8::Object> object, StateBase* next)
+ : State<v8::Object>(object, next)
+ , m_propertyNames(object->GetPropertyNames())
+ , m_index(-1)
+ , m_numSerializedProperties(0)
+ , m_nameDone(false)
+ {
+ }
+
+ virtual StateBase* advance(Serializer& serializer)
+ {
+ ++m_index;
+ for (; m_index < m_propertyNames->Length(); ++m_index) {
+ if (m_propertyName.IsEmpty()) {
+ v8::Local<v8::Value> propertyName = m_propertyNames->Get(m_index);
+ if ((propertyName->IsString() && composite()->HasRealNamedProperty(propertyName.As<v8::String>()))
+ || (propertyName->IsUint32() && composite()->HasRealIndexedProperty(propertyName->Uint32Value()))) {
+ m_propertyName = propertyName;
+ } else
+ continue;
+ }
+ ASSERT(!m_propertyName.IsEmpty());
+ if (!m_nameDone) {
+ m_nameDone = true;
+ if (StateBase* newState = serializer.doSerialize(m_propertyName, this))
+ return newState;
+ }
+ v8::Local<v8::Value> value = composite()->Get(m_propertyName);
+ m_nameDone = false;
+ m_propertyName.Clear();
+ ++m_numSerializedProperties;
+ if (StateBase* newState = serializer.doSerialize(value, this))
+ return newState;
+ }
+ return objectDone(m_numSerializedProperties, serializer);
+ }
+
+ protected:
+ virtual StateBase* objectDone(unsigned numProperties, Serializer&) = 0;
+
+ private:
+ v8::Local<v8::Array> m_propertyNames;
+ v8::Local<v8::Value> m_propertyName;
+ unsigned m_index;
+ unsigned m_numSerializedProperties;
+ bool m_nameDone;
+ };
+
+ class ObjectState : public AbstractObjectState {
+ public:
+ ObjectState(v8::Handle<v8::Object> object, StateBase* next)
+ : AbstractObjectState(object, next)
+ {
+ }
+
+ protected:
+ virtual StateBase* objectDone(unsigned numProperties, Serializer& serializer)
+ {
+ return serializer.writeObject(numProperties, this);
+ }
+ };
+
+ class SparseArrayState : public AbstractObjectState {
+ public:
+ SparseArrayState(v8::Handle<v8::Array> array, StateBase* next)
+ : AbstractObjectState(array, next)
+ {
+ }
+
+ protected:
+ virtual StateBase* objectDone(unsigned numProperties, Serializer& serializer)
+ {
+ return serializer.writeSparseArray(numProperties, composite().As<v8::Array>()->Length(), this);
+ }
+ };
+
+ StateBase* push(StateBase* state)
+ {
+ ASSERT(state);
+ ++m_depth;
+ return checkComposite(state) ? state : handleError(state);
+ }
+
+ StateBase* pop(StateBase* state)
+ {
+ ASSERT(state);
+ --m_depth;
+ StateBase* next = state->nextState();
+ delete state;
+ return next;
+ }
+
+ StateBase* handleError(StateBase* state)
+ {
+ m_hasError = true;
+ while (state) {
+ StateBase* tmp = state->nextState();
+ delete state;
+ state = tmp;
+ }
+ return new ErrorState;
+ }
+
+ bool checkComposite(StateBase* top)
+ {
+ ASSERT(top);
+ if (m_depth > maxDepth)
+ return false;
+ if (!shouldCheckForCycles(m_depth))
+ return true;
+ v8::Handle<v8::Value> composite = top->composite();
+ for (StateBase* state = top->nextState(); state; state = state->nextState()) {
+ if (state->composite() == composite)
+ return false;
+ }
+ return true;
+ }
+
+ void writeString(v8::Handle<v8::Value> value)
+ {
+ v8::String::Utf8Value stringValue(value);
+ m_writer.writeString(*stringValue, stringValue.length());
+ }
+
+ void writeBlob(v8::Handle<v8::Value> value)
+ {
+ Blob* blob = V8Blob::toNative(value.As<v8::Object>());
+ if (!blob)
+ return;
+ m_writer.writeBlob(blob->path());
+ }
+
+ void writeFile(v8::Handle<v8::Value> value)
+ {
+ File* file = V8File::toNative(value.As<v8::Object>());
+ if (!file)
+ return;
+ m_writer.writeFile(file->path());
+ }
+
+ void writeFileList(v8::Handle<v8::Value> value)
+ {
+ FileList* fileList = V8FileList::toNative(value.As<v8::Object>());
+ if (!fileList)
+ return;
+ m_writer.writeFileList(*fileList);
+ }
+
+ void writeImageData(v8::Handle<v8::Value> value)
+ {
+ ImageData* imageData = V8ImageData::toNative(value.As<v8::Object>());
+ if (!imageData)
+ return;
+ WTF::ByteArray* pixelArray = imageData->data()->data();
+ m_writer.writeImageData(imageData->width(), imageData->height(), pixelArray->data(), pixelArray->length());
+ }
+
+ static StateBase* newArrayState(v8::Handle<v8::Array> array, StateBase* next)
+ {
+ // FIXME: use plain Array state when we can quickly check that
+ // an array is not sparse and has only indexed properties.
+ return new SparseArrayState(array, next);
+ }
+
+ static StateBase* newObjectState(v8::Handle<v8::Object> object, StateBase* next)
+ {
+ // FIXME:
+ // - check not a wrapper
+ // - support File, etc.
+ return new ObjectState(object, next);
+ }
+
+ Writer& m_writer;
+ int m_depth;
+ bool m_hasError;
+};
+
+Serializer::StateBase* Serializer::doSerialize(v8::Handle<v8::Value> value, StateBase* next)
+{
+ if (value->IsUndefined())
+ m_writer.writeUndefined();
+ else if (value->IsNull())
+ m_writer.writeNull();
+ else if (value->IsTrue())
+ m_writer.writeTrue();
+ else if (value->IsFalse())
+ m_writer.writeFalse();
+ else if (value->IsInt32())
+ m_writer.writeInt32(value->Int32Value());
+ else if (value->IsUint32())
+ m_writer.writeUint32(value->Uint32Value());
+ else if (value->IsDate())
+ m_writer.writeDate(value->NumberValue());
+ else if (value->IsNumber())
+ m_writer.writeNumber(value.As<v8::Number>()->Value());
+ else if (value->IsString())
+ writeString(value);
+ else if (value->IsArray())
+ return push(newArrayState(value.As<v8::Array>(), next));
+ else if (V8File::HasInstance(value))
+ writeFile(value);
+ else if (V8Blob::HasInstance(value))
+ writeBlob(value);
+ else if (V8FileList::HasInstance(value))
+ writeFileList(value);
+ else if (V8ImageData::HasInstance(value))
+ writeImageData(value);
+ else if (value->IsObject())
+ return push(newObjectState(value.As<v8::Object>(), next));
+ return 0;
+}
+
+// Interface used by Reader to create objects of composite types.
+class CompositeCreator {
+public:
+ virtual ~CompositeCreator() { }
+
+ virtual bool createArray(uint32_t length, v8::Handle<v8::Value>* value) = 0;
+ virtual bool createObject(uint32_t numProperties, v8::Handle<v8::Value>* value) = 0;
+ virtual bool createSparseArray(uint32_t numProperties, uint32_t length, v8::Handle<v8::Value>* value) = 0;
+};
+
+// Reader is responsible for deserializing primitive types and
+// restoring information about saved objects of composite types.
+class Reader {
+public:
+ Reader(const uint8_t* buffer, int length)
+ : m_buffer(buffer)
+ , m_length(length)
+ , m_position(0)
+ {
+ ASSERT(length >= 0);
+ }
+
+ bool isEof() const { return m_position >= m_length; }
+
+ bool read(v8::Handle<v8::Value>* value, CompositeCreator& creator)
+ {
+ SerializationTag tag;
+ if (!readTag(&tag))
+ return false;
+ switch (tag) {
+ case InvalidTag:
+ return false;
+ case PaddingTag:
+ return true;
+ case UndefinedTag:
+ *value = v8::Undefined();
+ break;
+ case NullTag:
+ *value = v8::Null();
+ break;
+ case TrueTag:
+ *value = v8::True();
+ break;
+ case FalseTag:
+ *value = v8::False();
+ break;
+ case StringTag:
+ if (!readString(value))
+ return false;
+ break;
+ case Int32Tag:
+ if (!readInt32(value))
+ return false;
+ break;
+ case Uint32Tag:
+ if (!readUint32(value))
+ return false;
+ break;
+ case DateTag:
+ if (!readDate(value))
+ return false;
+ break;
+ case NumberTag:
+ if (!readNumber(value))
+ return false;
+ break;
+ case BlobTag:
+ if (!readBlob(value))
+ return false;
+ break;
+ case FileTag:
+ if (!readFile(value))
+ return false;
+ break;
+ case FileListTag:
+ if (!readFileList(value))
+ return false;
+ break;
+ case ImageDataTag:
+ if (!readImageData(value))
+ return false;
+ break;
+ case ArrayTag: {
+ uint32_t length;
+ if (!doReadUint32(&length))
+ return false;
+ if (!creator.createArray(length, value))
+ return false;
+ break;
+ }
+ case ObjectTag: {
+ uint32_t numProperties;
+ if (!doReadUint32(&numProperties))
+ return false;
+ if (!creator.createObject(numProperties, value))
+ return false;
+ break;
+ }
+ case SparseArrayTag: {
+ uint32_t numProperties;
+ uint32_t length;
+ if (!doReadUint32(&numProperties))
+ return false;
+ if (!doReadUint32(&length))
+ return false;
+ if (!creator.createSparseArray(numProperties, length, value))
+ return false;
+ break;
+ }
+ default:
+ return false;
+ }
+ return !value->IsEmpty();
+ }
+
+private:
+ bool readTag(SerializationTag* tag)
+ {
+ if (m_position >= m_length)
+ return false;
+ *tag = static_cast<SerializationTag>(m_buffer[m_position++]);
+ return true;
+ }
+
+ bool readString(v8::Handle<v8::Value>* value)
+ {
+ uint32_t length;
+ if (!doReadUint32(&length))
+ return false;
+ if (m_position + length > m_length)
+ return false;
+ *value = v8::String::New(reinterpret_cast<const char*>(m_buffer + m_position), length);
+ m_position += length;
+ return true;
+ }
+
+ bool readWebCoreString(String* string)
+ {
+ uint32_t length;
+ if (!doReadUint32(&length))
+ return false;
+ if (m_position + length > m_length)
+ return false;
+ *string = String::fromUTF8(reinterpret_cast<const char*>(m_buffer + m_position), length);
+ m_position += length;
+ return true;
+ }
+
+ bool readInt32(v8::Handle<v8::Value>* value)
+ {
+ uint32_t rawValue;
+ if (!doReadUint32(&rawValue))
+ return false;
+ *value = v8::Integer::New(static_cast<int32_t>(ZigZag::decode(rawValue)));
+ return true;
+ }
+
+ bool readUint32(v8::Handle<v8::Value>* value)
+ {
+ uint32_t rawValue;
+ if (!doReadUint32(&rawValue))
+ return false;
+ *value = v8::Integer::New(rawValue);
+ return true;
+ }
+
+ bool readDate(v8::Handle<v8::Value>* value)
+ {
+ double numberValue;
+ if (!doReadNumber(&numberValue))
+ return false;
+ *value = v8::Date::New(numberValue);
+ return true;
+ }
+
+ bool readNumber(v8::Handle<v8::Value>* value)
+ {
+ double number;
+ if (!doReadNumber(&number))
+ return false;
+ *value = v8::Number::New(number);
+ return true;
+ }
+
+ bool readImageData(v8::Handle<v8::Value>* value)
+ {
+ uint32_t width;
+ uint32_t height;
+ uint32_t pixelDataLength;
+ if (!doReadUint32(&width))
+ return false;
+ if (!doReadUint32(&height))
+ return false;
+ if (!doReadUint32(&pixelDataLength))
+ return false;
+ if (m_position + pixelDataLength > m_length)
+ return false;
+ PassRefPtr<ImageData> imageData = ImageData::create(width, height);
+ WTF::ByteArray* pixelArray = imageData->data()->data();
+ ASSERT(pixelArray);
+ ASSERT(pixelArray->length() >= pixelDataLength);
+ memcpy(pixelArray->data(), m_buffer + m_position, pixelDataLength);
+ m_position += pixelDataLength;
+ *value = toV8(imageData);
+ return true;
+ }
+
+ bool readBlob(v8::Handle<v8::Value>* value)
+ {
+ String path;
+ if (!readWebCoreString(&path))
+ return false;
+ PassRefPtr<Blob> blob = Blob::create(path);
+ *value = toV8(blob);
+ return true;
+ }
+
+ bool readFile(v8::Handle<v8::Value>* value)
+ {
+ String path;
+ if (!readWebCoreString(&path))
+ return false;
+ PassRefPtr<File> file = File::create(path);
+ *value = toV8(file);
+ return true;
+ }
+
+ bool readFileList(v8::Handle<v8::Value>* value)
+ {
+ uint32_t length;
+ if (!doReadUint32(&length))
+ return false;
+ PassRefPtr<FileList> fileList = FileList::create();
+ for (unsigned i = 0; i < length; ++i) {
+ String path;
+ if (!readWebCoreString(&path))
+ return false;
+ fileList->append(File::create(path));
+ }
+ *value = toV8(fileList);
+ return true;
+ }
+
+ bool doReadUint32(uint32_t* value)
+ {
+ *value = 0;
+ uint8_t currentByte;
+ int shift = 0;
+ do {
+ if (m_position >= m_length)
+ return false;
+ currentByte = m_buffer[m_position++];
+ *value |= ((currentByte & varIntMask) << shift);
+ shift += varIntShift;
+ } while (currentByte & (1 << varIntShift));
+ return true;
+ }
+
+ bool doReadNumber(double* number)
+ {
+ if (m_position + sizeof(double) > m_length)
+ return false;
+ uint8_t* numberAsByteArray = reinterpret_cast<uint8_t*>(number);
+ for (unsigned i = 0; i < sizeof(double); ++i)
+ numberAsByteArray[i] = m_buffer[m_position++];
+ return true;
+ }
+
+ const uint8_t* m_buffer;
+ const unsigned m_length;
+ unsigned m_position;
+};
+
+class Deserializer : public CompositeCreator {
+public:
+ explicit Deserializer(Reader& reader)
+ : m_reader(reader)
+ {
+ }
+
+ v8::Handle<v8::Value> deserialize()
+ {
+ v8::HandleScope scope;
+ while (!m_reader.isEof()) {
+ if (!doDeserialize())
+ return v8::Null();
+ }
+ if (stackDepth() != 1)
+ return v8::Null();
+ return scope.Close(element(0));
+ }
+
+ virtual bool createArray(uint32_t length, v8::Handle<v8::Value>* value)
+ {
+ if (length > stackDepth())
+ return false;
+ v8::Local<v8::Array> array = v8::Array::New(length);
+ if (array.IsEmpty())
+ return false;
+ const int depth = stackDepth() - length;
+ for (unsigned i = 0; i < length; ++i)
+ array->Set(i, element(depth + i));
+ pop(length);
+ *value = array;
+ return true;
+ }
+
+ virtual bool createObject(uint32_t numProperties, v8::Handle<v8::Value>* value)
+ {
+ v8::Local<v8::Object> object = v8::Object::New();
+ if (object.IsEmpty())
+ return false;
+ return initializeObject(object, numProperties, value);
+ }
+
+ virtual bool createSparseArray(uint32_t numProperties, uint32_t length, v8::Handle<v8::Value>* value)
+ {
+ v8::Local<v8::Array> array = v8::Array::New(length);
+ if (array.IsEmpty())
+ return false;
+ return initializeObject(array, numProperties, value);
+ }
+
+private:
+ bool initializeObject(v8::Handle<v8::Object> object, uint32_t numProperties, v8::Handle<v8::Value>* value)
+ {
+ unsigned length = 2 * numProperties;
+ if (length > stackDepth())
+ return false;
+ for (unsigned i = stackDepth() - length; i < stackDepth(); i += 2) {
+ v8::Local<v8::Value> propertyName = element(i);
+ v8::Local<v8::Value> propertyValue = element(i + 1);
+ object->Set(propertyName, propertyValue);
+ }
+ pop(length);
+ *value = object;
+ return true;
+ }
+
+ bool doDeserialize()
+ {
+ v8::Local<v8::Value> value;
+ if (!m_reader.read(&value, *this))
+ return false;
+ if (!value.IsEmpty())
+ push(value);
+ return true;
+ }
+
+ void push(v8::Local<v8::Value> value) { m_stack.append(value); }
+
+ void pop(unsigned length)
+ {
+ ASSERT(length <= m_stack.size());
+ m_stack.shrink(m_stack.size() - length);
+ }
+
+ unsigned stackDepth() const { return m_stack.size(); }
+
+ v8::Local<v8::Value> element(unsigned index)
+ {
+ ASSERT(index < m_stack.size());
+ return m_stack[index];
+ }
+
+ Reader& m_reader;
+ Vector<v8::Local<v8::Value> > m_stack;
+};
+
+} // namespace
+
+void SerializedScriptValue::deserializeAndSetProperty(v8::Handle<v8::Object> object, const char* propertyName,
+ v8::PropertyAttribute attribute, SerializedScriptValue* value)
+{
+ if (!value)
+ return;
+ v8::Handle<v8::Value> deserialized = value->deserialize();
+ object->ForceSet(v8::String::NewSymbol(propertyName), deserialized, attribute);
+}
+
+PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(v8::Handle<v8::Value> value, bool& didThrow)
+{
+ return adoptRef(new SerializedScriptValue(value, didThrow));
+}
+
+PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(v8::Handle<v8::Value> value)
+{
+ bool didThrow;
+ return adoptRef(new SerializedScriptValue(value, didThrow));
+}
+
+PassRefPtr<SerializedScriptValue> SerializedScriptValue::createFromWire(String data)
+{
+ return adoptRef(new SerializedScriptValue(data, WireData));
+}
+
+PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(String data)
+{
+ return adoptRef(new SerializedScriptValue(data, StringValue));
+}
+
+PassRefPtr<SerializedScriptValue> SerializedScriptValue::create()
+{
+ return adoptRef(new SerializedScriptValue());
+}
+
+PassRefPtr<SerializedScriptValue> SerializedScriptValue::release()
+{
+ RefPtr<SerializedScriptValue> result = adoptRef(new SerializedScriptValue(m_data, WireData));
+ m_data = String();
+ return result.release();
+}
+
+SerializedScriptValue::SerializedScriptValue()
+{
+}
+
+SerializedScriptValue::SerializedScriptValue(v8::Handle<v8::Value> value, bool& didThrow)
+{
+ didThrow = false;
+ Writer writer;
+ Serializer serializer(writer);
+ if (!serializer.serialize(value)) {
+ throwError(NOT_SUPPORTED_ERR);
+ didThrow = true;
+ return;
+ }
+ m_data = StringImpl::adopt(writer.data());
+}
+
+SerializedScriptValue::SerializedScriptValue(String data, StringDataMode mode)
+{
+ if (mode == WireData)
+ m_data = data;
+ else {
+ ASSERT(mode == StringValue);
+ Writer writer;
+ writer.writeWebCoreString(data);
+ m_data = StringImpl::adopt(writer.data());
+ }
+}
+
+v8::Handle<v8::Value> SerializedScriptValue::deserialize()
+{
+ if (!m_data.impl())
+ return v8::Null();
+ COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes);
+ Reader reader(reinterpret_cast<const uint8_t*>(m_data.impl()->characters()), 2 * m_data.length());
+ Deserializer deserializer(reader);
+ return deserializer.deserialize();
+}
+
+} // namespace WebCore