diff options
Diffstat (limited to 'WebCore/bindings/v8/SerializedScriptValue.cpp')
-rw-r--r-- | WebCore/bindings/v8/SerializedScriptValue.cpp | 817 |
1 files changed, 584 insertions, 233 deletions
diff --git a/WebCore/bindings/v8/SerializedScriptValue.cpp b/WebCore/bindings/v8/SerializedScriptValue.cpp index bac7f20..50ac86b 100644 --- a/WebCore/bindings/v8/SerializedScriptValue.cpp +++ b/WebCore/bindings/v8/SerializedScriptValue.cpp @@ -31,7 +31,18 @@ #include "config.h" #include "SerializedScriptValue.h" +#include "Blob.h" +#include "ByteArray.h" +#include "CanvasPixelArray.h" +#include "File.h" +#include "FileList.h" +#include "ImageData.h" #include "SharedBuffer.h" +#include "V8Blob.h" +#include "V8File.h" +#include "V8FileList.h" +#include "V8ImageData.h" +#include "V8Proxy.h" #include <v8.h> #include <wtf/Assertions.h> @@ -40,7 +51,6 @@ // FIXME: // - catch V8 exceptions -// - be ready to get empty handles // - consider crashing in debug mode on deserialization errors namespace WebCore { @@ -60,19 +70,18 @@ enum SerializationTag { FalseTag = 'F', StringTag = 'S', Int32Tag = 'I', + Uint32Tag = 'U', + DateTag = 'D', NumberTag = 'N', - ObjectTag = '{', + BlobTag = 'b', + FileTag = 'f', + FileListTag = 'l', + ImageDataTag = '#', ArrayTag = '[', + ObjectTag = '{', + SparseArrayTag = '@', }; -// Helpers to do verbose handle casts. - -template <typename T, typename U> -static v8::Handle<T> handleCast(v8::Handle<U> handle) { return v8::Handle<T>::Cast(handle); } - -template <typename T, typename U> -static v8::Local<T> handleCast(v8::Local<U> handle) { return v8::Local<T>::Cast(handle); } - static bool shouldCheckForCycles(int depth) { ASSERT(depth >= 0); @@ -118,7 +127,8 @@ private: // information used to reconstruct composite types. class Writer : Noncopyable { public: - Writer() : m_position(0) + Writer() + : m_position(0) { } @@ -134,9 +144,17 @@ public: void writeString(const char* data, int length) { + ASSERT(length >= 0); append(StringTag); - doWriteUint32(static_cast<uint32_t>(length)); - append(data, length); + 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) @@ -145,19 +163,71 @@ public: 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); - append(reinterpret_cast<char*>(&number), sizeof(number)); + doWriteNumber(number); } - // Records that a composite object can be constructed by using - // |length| previously stored values. - void endComposite(SerializationTag tag, int32_t length) + void writeBlob(const String& path) { - ASSERT(tag == ObjectTag || tag == ArrayTag); - append(tag); - doWriteUint32(static_cast<uint32_t>(length)); + 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() @@ -167,10 +237,22 @@ public: } 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) { - char b = (value & varIntMask); + uint8_t b = (value & varIntMask); value >>= varIntShift; if (!value) { append(b); @@ -180,21 +262,26 @@ private: } } + void doWriteNumber(double number) + { + append(reinterpret_cast<uint8_t*>(&number), sizeof(number)); + } + void append(SerializationTag tag) { - append(static_cast<char>(tag)); + append(static_cast<uint8_t>(tag)); } - void append(char b) + void append(uint8_t b) { ensureSpace(1); - *charAt(m_position++) = b; + *byteAt(m_position++) = b; } - void append(const char* data, int length) + void append(const uint8_t* data, int length) { ensureSpace(length); - memcpy(charAt(m_position), data, length); + memcpy(byteAt(m_position), data, length); m_position += length; } @@ -210,41 +297,54 @@ private: // 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) - *charAt(m_position) = static_cast<char>(PaddingTag); + *byteAt(m_position) = static_cast<uint8_t>(PaddingTag); } - char* charAt(int position) { return reinterpret_cast<char*>(m_buffer.data()) + position; } + 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_state(0) , m_depth(0) + , m_hasError(false) { } bool serialize(v8::Handle<v8::Value> value) { v8::HandleScope scope; - StackCleaner cleaner(&m_state); - if (!doSerialize(value)) - return false; - while (top()) { - int length; - while (!top()->isDone(&length)) { - // Note that doSerialize() can change current top(). - if (!doSerialize(top()->advance())) - return false; - } - m_writer.endComposite(top()->tag(), length); - pop(); - } - return true; + 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: @@ -254,221 +354,308 @@ private: // Link to the next state to form a stack. StateBase* nextState() { return m_next; } - void setNextState(StateBase* next) { m_next = next; } // Composite object we're processing in this state. v8::Handle<v8::Value> composite() { return m_composite; } - // Serialization tag for the current composite. - virtual SerializationTag tag() const = 0; - - // Returns whether iteration over subobjects of the current - // composite object is done. If yes, |*length| is set to the - // number of subobjects. - virtual bool isDone(int* length) = 0; - - // Advances to the next subobject. - // Requires: !this->isDone(). - virtual v8::Local<v8::Value> advance() = 0; + // 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) - : m_next(0) - , m_composite(composite) + StateBase(v8::Handle<v8::Value> composite, StateBase* next) + : m_composite(composite) + , m_next(next) { } private: - StateBase* m_next; v8::Handle<v8::Value> m_composite; + StateBase* m_next; }; - template <typename T, SerializationTag compositeTag> - class State : public StateBase { + // Dummy state that is used to signal serialization errors. + class ErrorState : public StateBase { public: - v8::Handle<T> composite() { return handleCast<T>(StateBase::composite()); } + ErrorState() + : StateBase(v8::Handle<v8::Value>(), 0) + { + } - virtual SerializationTag tag() const { return compositeTag; } + 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: - explicit State(v8::Handle<T> composite) : StateBase(composite) + State(v8::Handle<T> composite, StateBase* next) + : StateBase(composite, next) { } }; - // Helper to clean up the state stack in case of errors. - class StackCleaner : Noncopyable { +#if 0 + // Currently unused, see comment in newArrayState. + class ArrayState : public State<v8::Array> { public: - explicit StackCleaner(StateBase** stack) : m_stack(stack) + ArrayState(v8::Handle<v8::Array> array, StateBase* next) + : State<v8::Array>(array, next) + , m_index(-1) { } - ~StackCleaner() + virtual StateBase* advance(Serializer& serializer) { - StateBase* state = *m_stack; - while (state) { - StateBase* tmp = state->nextState(); - delete state; - state = tmp; + ++m_index; + for (; m_index < composite()->Length(); ++m_index) { + if (StateBase* newState = serializer.doSerialize(composite()->Get(m_index), this)) + return newState; } - *m_stack = 0; + return serializer.writeArray(composite()->Length(), this); } private: - StateBase** m_stack; + unsigned m_index; }; +#endif - class ArrayState : public State<v8::Array, ArrayTag> { + class AbstractObjectState : public State<v8::Object> { public: - ArrayState(v8::Handle<v8::Array> array) - : State<v8::Array, ArrayTag>(array) - , m_index(0) + 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 bool isDone(int* length) + virtual StateBase* advance(Serializer& serializer) { - *length = composite()->Length(); - return static_cast<int>(m_index) >= *length; + ++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); } - virtual v8::Local<v8::Value> advance() - { - ASSERT(m_index < composite()->Length()); - v8::HandleScope scope; - return scope.Close(composite()->Get(v8::Integer::New(m_index++))); - } + 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 State<v8::Object, ObjectTag> { + class ObjectState : public AbstractObjectState { public: - ObjectState(v8::Handle<v8::Object> object) - : State<v8::Object, ObjectTag>(object) - , m_propertyNames(object->GetPropertyNames()) - , m_index(-1) - , m_length(0) + ObjectState(v8::Handle<v8::Object> object, StateBase* next) + : AbstractObjectState(object, next) { - nextProperty(); } - virtual bool isDone(int* length) + protected: + virtual StateBase* objectDone(unsigned numProperties, Serializer& serializer) { - *length = m_length; - return m_index >= 2 * m_propertyNames->Length(); + return serializer.writeObject(numProperties, this); } + }; - virtual v8::Local<v8::Value> advance() + class SparseArrayState : public AbstractObjectState { + public: + SparseArrayState(v8::Handle<v8::Array> array, StateBase* next) + : AbstractObjectState(array, next) { - ASSERT(m_index < 2 * m_propertyNames->Length()); - if (!(m_index % 2)) { - ++m_index; - return m_propertyName; - } - v8::Local<v8::Value> result = composite()->Get(m_propertyName); - nextProperty(); - return result; } - private: - void nextProperty() + protected: + virtual StateBase* objectDone(unsigned numProperties, Serializer& serializer) { - v8::HandleScope scope; - ++m_index; - ASSERT(!(m_index % 2)); - for (; m_index < 2 * m_propertyNames->Length(); m_index += 2) { - v8::Local<v8::Value> propertyName = m_propertyNames->Get(v8::Integer::New(m_index / 2)); - if ((propertyName->IsString() && composite()->HasRealNamedProperty(handleCast<v8::String>(propertyName))) - || (propertyName->IsInt32() && composite()->HasRealIndexedProperty(propertyName->Uint32Value()))) { - m_propertyName = scope.Close(propertyName); - m_length += 2; - return; - } - } + return serializer.writeSparseArray(numProperties, composite().As<v8::Array>()->Length(), this); } - - v8::Local<v8::Array> m_propertyNames; - v8::Local<v8::Value> m_propertyName; - unsigned m_index; - unsigned m_length; }; - bool doSerialize(v8::Handle<v8::Value> value) - { - 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->IsNumber()) - m_writer.writeNumber(handleCast<v8::Number>(value)->Value()); - else if (value->IsString()) { - v8::String::Utf8Value stringValue(value); - m_writer.writeString(*stringValue, stringValue.length()); - } else if (value->IsArray()) { - if (!checkComposite(value)) - return false; - push(new ArrayState(handleCast<v8::Array>(value))); - } else if (value->IsObject()) { - if (!checkComposite(value)) - return false; - push(new ObjectState(handleCast<v8::Object>(value))); - // FIXME: - // - check not a wrapper - // - support File, ImageData, etc. - } - return true; - } - - void push(StateBase* state) + StateBase* push(StateBase* state) { - state->setNextState(m_state); - m_state = state; + ASSERT(state); ++m_depth; + return checkComposite(state) ? state : handleError(state); } - StateBase* top() { return m_state; } - - void pop() + StateBase* pop(StateBase* state) { - if (!m_state) - return; - StateBase* top = m_state; - m_state = top->nextState(); - delete top; + 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(v8::Handle<v8::Value> composite) + bool checkComposite(StateBase* top) { + ASSERT(top); if (m_depth > maxDepth) return false; if (!shouldCheckForCycles(m_depth)) return true; - for (StateBase* state = top(); state; state = state->nextState()) { + 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; - StateBase* m_state; 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 char* buffer, int length) + Reader(const uint8_t* buffer, int length) : m_buffer(buffer) , m_length(length) , m_position(0) @@ -478,16 +665,16 @@ public: bool isEof() const { return m_position >= m_length; } - bool read(SerializationTag* tag, v8::Handle<v8::Value>* value, int* length) + bool read(v8::Handle<v8::Value>* value, CompositeCreator& creator) { - uint32_t rawLength; - if (!readTag(tag)) + SerializationTag tag; + if (!readTag(&tag)) return false; - switch (*tag) { + switch (tag) { case InvalidTag: return false; case PaddingTag: - break; + return true; case UndefinedTag: *value = v8::Undefined(); break; @@ -508,18 +695,65 @@ public: 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 ObjectTag: - case ArrayTag: - if (!doReadUint32(&rawLength)) + 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; - *length = rawLength; break; } - return true; + 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: @@ -538,7 +772,19 @@ private: return false; if (m_position + length > m_length) return false; - *value = v8::String::New(m_buffer + m_position, length); + *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; } @@ -552,22 +798,96 @@ private: return true; } - bool readNumber(v8::Handle<v8::Value>* value) + bool readUint32(v8::Handle<v8::Value>* value) { - if (m_position + sizeof(double) > m_length) + 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; - char* numberAsByteArray = reinterpret_cast<char*>(&number); - for (unsigned i = 0; i < sizeof(double); ++i) - numberAsByteArray[i] = m_buffer[m_position++]; + 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; - char currentByte; + uint8_t currentByte; int shift = 0; do { if (m_position >= m_length) @@ -579,64 +899,94 @@ private: return true; } - const char* m_buffer; + 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 { +class Deserializer : public CompositeCreator { public: - explicit Deserializer(Reader& reader) : m_reader(reader) + explicit Deserializer(Reader& reader) + : m_reader(reader) { } - v8::Local<v8::Value> deserialize() + v8::Handle<v8::Value> deserialize() { v8::HandleScope scope; while (!m_reader.isEof()) { if (!doDeserialize()) - return v8::Local<v8::Value>(); + return v8::Null(); } if (stackDepth() != 1) - return v8::Local<v8::Value>(); + 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() { - SerializationTag tag; v8::Local<v8::Value> value; - int length = 0; - if (!m_reader.read(&tag, &value, &length)) + if (!m_reader.read(&value, *this)) return false; - if (!value.IsEmpty()) { + if (!value.IsEmpty()) push(value); - } else if (tag == ObjectTag) { - if (length > stackDepth()) - return false; - v8::Local<v8::Object> object = v8::Object::New(); - for (int 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); - push(object); - } else if (tag == ArrayTag) { - if (length > stackDepth()) - return false; - v8::Local<v8::Array> array = v8::Array::New(length); - const int depth = stackDepth() - length; - { - v8::HandleScope scope; - for (int i = 0; i < length; ++i) - array->Set(v8::Integer::New(i), element(depth + i)); - } - pop(length); - push(array); - } else if (tag != PaddingTag) - return false; return true; } @@ -648,7 +998,7 @@ private: m_stack.shrink(m_stack.size() - length); } - int stackDepth() const { return m_stack.size(); } + unsigned stackDepth() const { return m_stack.size(); } v8::Local<v8::Value> element(unsigned index) { @@ -662,12 +1012,14 @@ private: } // namespace -SerializedScriptValue::SerializedScriptValue(v8::Handle<v8::Value> value) +SerializedScriptValue::SerializedScriptValue(v8::Handle<v8::Value> value, bool& didThrow) { + didThrow = false; Writer writer; Serializer serializer(writer); if (!serializer.serialize(value)) { - // FIXME: throw exception + throwError(NOT_SUPPORTED_ERR); + didThrow = true; return; } m_data = StringImpl::adopt(writer.data()); @@ -679,19 +1031,18 @@ SerializedScriptValue::SerializedScriptValue(String data, StringDataMode mode) m_data = data; else { ASSERT(mode == StringValue); - RefPtr<SharedBuffer> buffer = utf8Buffer(data); Writer writer; - writer.writeString(buffer->data(), buffer->size()); + writer.writeWebCoreString(data); m_data = StringImpl::adopt(writer.data()); } } -v8::Local<v8::Value> SerializedScriptValue::deserialize() +v8::Handle<v8::Value> SerializedScriptValue::deserialize() { if (!m_data.impl()) - return v8::Local<v8::Value>(); + return v8::Null(); COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes); - Reader reader(reinterpret_cast<const char*>(m_data.impl()->characters()), 2 * m_data.length()); + Reader reader(reinterpret_cast<const uint8_t*>(m_data.impl()->characters()), 2 * m_data.length()); Deserializer deserializer(reader); return deserializer.deserialize(); } |