| Index: Source/bindings/core/v8/SerializedScriptValue.cpp
|
| diff --git a/Source/bindings/core/v8/SerializedScriptValue.cpp b/Source/bindings/core/v8/SerializedScriptValue.cpp
|
| index 1458b60de49c71c0b65d0a1a480aacb1d4c80a9c..72ca9d1026e57ed5fe3525cd34bdfab62060536f 100644
|
| --- a/Source/bindings/core/v8/SerializedScriptValue.cpp
|
| +++ b/Source/bindings/core/v8/SerializedScriptValue.cpp
|
| @@ -31,2865 +31,33 @@
|
| #include "config.h"
|
| #include "bindings/core/v8/SerializedScriptValue.h"
|
|
|
| +#include "bindings/core/v8/DOMDataStore.h"
|
| +#include "bindings/core/v8/DOMWrapperWorld.h"
|
| #include "bindings/core/v8/ExceptionState.h"
|
| +#include "bindings/core/v8/ScriptValueSerializer.h"
|
| #include "bindings/core/v8/V8ArrayBuffer.h"
|
| #include "bindings/core/v8/V8ArrayBufferView.h"
|
| #include "bindings/core/v8/V8Binding.h"
|
| -#include "bindings/core/v8/V8Blob.h"
|
| -#include "bindings/core/v8/V8DataView.h"
|
| -#include "bindings/core/v8/V8File.h"
|
| -#include "bindings/core/v8/V8FileList.h"
|
| -#include "bindings/core/v8/V8Float32Array.h"
|
| -#include "bindings/core/v8/V8Float64Array.h"
|
| -#include "bindings/core/v8/V8ImageData.h"
|
| -#include "bindings/core/v8/V8Int16Array.h"
|
| -#include "bindings/core/v8/V8Int32Array.h"
|
| -#include "bindings/core/v8/V8Int8Array.h"
|
| #include "bindings/core/v8/V8MessagePort.h"
|
| -#include "bindings/core/v8/V8Uint16Array.h"
|
| -#include "bindings/core/v8/V8Uint32Array.h"
|
| -#include "bindings/core/v8/V8Uint8Array.h"
|
| -#include "bindings/core/v8/V8Uint8ClampedArray.h"
|
| -#include "bindings/core/v8/WorkerScriptController.h"
|
| -#include "bindings/modules/v8/V8CryptoKey.h"
|
| -#include "bindings/modules/v8/V8DOMFileSystem.h"
|
| +#include "core/dom/DOMArrayBuffer.h"
|
| #include "core/dom/ExceptionCode.h"
|
| -#include "core/dom/MessagePort.h"
|
| -#include "core/fileapi/Blob.h"
|
| -#include "core/fileapi/File.h"
|
| -#include "core/fileapi/FileList.h"
|
| -#include "core/html/ImageData.h"
|
| -#include "core/html/canvas/DataView.h"
|
| #include "platform/SharedBuffer.h"
|
| +#include "platform/blob/BlobData.h"
|
| #include "platform/heap/Handle.h"
|
| #include "public/platform/Platform.h"
|
| -#include "public/platform/WebBlobInfo.h"
|
| -#include "public/platform/WebCrypto.h"
|
| -#include "public/platform/WebCryptoKey.h"
|
| -#include "public/platform/WebCryptoKeyAlgorithm.h"
|
| #include "wtf/ArrayBuffer.h"
|
| #include "wtf/ArrayBufferContents.h"
|
| #include "wtf/ArrayBufferView.h"
|
| #include "wtf/Assertions.h"
|
| #include "wtf/ByteOrder.h"
|
| -#include "wtf/Float32Array.h"
|
| -#include "wtf/Float64Array.h"
|
| -#include "wtf/Int16Array.h"
|
| -#include "wtf/Int32Array.h"
|
| -#include "wtf/Int8Array.h"
|
| -#include "wtf/RefCounted.h"
|
| -#include "wtf/Uint16Array.h"
|
| -#include "wtf/Uint32Array.h"
|
| -#include "wtf/Uint8Array.h"
|
| #include "wtf/Uint8ClampedArray.h"
|
| #include "wtf/Vector.h"
|
| #include "wtf/text/StringBuffer.h"
|
| +#include "wtf/text/StringHash.h"
|
| #include "wtf/text/StringUTF8Adaptor.h"
|
|
|
| -// FIXME: consider crashing in debug mode on deserialization errors
|
| -// NOTE: be sure to change wireFormatVersion as necessary!
|
| -
|
| namespace blink {
|
|
|
| -namespace {
|
| -
|
| -// This code implements the HTML5 Structured Clone algorithm:
|
| -// http://www.whatwg.org/specs/web-apps/current-work/multipage/urls.html#safe-passing-of-structured-data
|
| -
|
| -// V8ObjectMap is a map from V8 objects to arbitrary values of type T.
|
| -// V8 objects (or handles to V8 objects) cannot be used as keys in ordinary wtf::HashMaps;
|
| -// this class should be used instead. GCObject must be a subtype of v8::Object.
|
| -// Suggested usage:
|
| -// V8ObjectMap<v8::Object, int> map;
|
| -// v8::Handle<v8::Object> obj = ...;
|
| -// map.set(obj, 42);
|
| -template<typename GCObject, typename T>
|
| -class V8ObjectMap {
|
| -public:
|
| - bool contains(const v8::Handle<GCObject>& handle)
|
| - {
|
| - return m_map.contains(*handle);
|
| - }
|
| -
|
| - bool tryGet(const v8::Handle<GCObject>& handle, T* valueOut)
|
| - {
|
| - typename HandleToT::iterator result = m_map.find(*handle);
|
| - if (result != m_map.end()) {
|
| - *valueOut = result->value;
|
| - return true;
|
| - }
|
| - return false;
|
| - }
|
| -
|
| - void set(const v8::Handle<GCObject>& handle, const T& value)
|
| - {
|
| - m_map.set(*handle, value);
|
| - }
|
| -
|
| -private:
|
| - // This implementation uses GetIdentityHash(), which sets a hidden property on the object containing
|
| - // a random integer (or returns the one that had been previously set). This ensures that the table
|
| - // never needs to be rebuilt across garbage collections at the expense of doing additional allocation
|
| - // and making more round trips into V8. Note that since GetIdentityHash() is defined only on
|
| - // v8::Objects, this V8ObjectMap cannot be used to map v8::Strings to T (because the public V8 API
|
| - // considers a v8::String to be a v8::Primitive).
|
| -
|
| - // If V8 exposes a way to get at the address of the object held by a handle, then we can produce
|
| - // an alternate implementation that does not need to do any V8-side allocation; however, it will
|
| - // need to rehash after every garbage collection because a key object may have been moved.
|
| - template<typename G>
|
| - struct V8HandlePtrHash {
|
| - static v8::Handle<G> unsafeHandleFromRawValue(const G* value)
|
| - {
|
| - const v8::Handle<G>* handle = reinterpret_cast<const v8::Handle<G>*>(&value);
|
| - return *handle;
|
| - }
|
| -
|
| - static unsigned hash(const G* key)
|
| - {
|
| - return static_cast<unsigned>(unsafeHandleFromRawValue(key)->GetIdentityHash());
|
| - }
|
| - static bool equal(const G* a, const G* b)
|
| - {
|
| - return unsafeHandleFromRawValue(a) == unsafeHandleFromRawValue(b);
|
| - }
|
| - // For HashArg.
|
| - static const bool safeToCompareToEmptyOrDeleted = false;
|
| - };
|
| -
|
| - typedef WTF::HashMap<GCObject*, T, V8HandlePtrHash<GCObject> > HandleToT;
|
| - HandleToT m_map;
|
| -};
|
| -
|
| -typedef UChar BufferValueType;
|
| -
|
| -// Serialization format is a sequence of tags followed by zero or more data arguments.
|
| -// Tags always take exactly one byte. A serialized stream first begins with
|
| -// a complete VersionTag. If the stream does not begin with a VersionTag, we assume that
|
| -// the stream is in format 0.
|
| -
|
| -// This format is private to the implementation of SerializedScriptValue. Do not rely on it
|
| -// externally. It is safe to persist a SerializedScriptValue as a binary blob, but this
|
| -// code should always be used to interpret it.
|
| -
|
| -// WebCoreStrings are read as (length:uint32_t, string:UTF8[length]).
|
| -// RawStrings are read as (length:uint32_t, string:UTF8[length]).
|
| -// RawUCharStrings are read as (length:uint32_t, string:UChar[length/sizeof(UChar)]).
|
| -// RawFiles are read as (path:WebCoreString, url:WebCoreStrng, type:WebCoreString).
|
| -// There is a reference table that maps object references (uint32_t) to v8::Values.
|
| -// Tokens marked with (ref) are inserted into the reference table and given the next object reference ID after decoding.
|
| -// All tags except InvalidTag, PaddingTag, ReferenceCountTag, VersionTag, GenerateFreshObjectTag
|
| -// and GenerateFreshArrayTag push their results to the deserialization stack.
|
| -// There is also an 'open' stack that is used to resolve circular references. Objects or arrays may
|
| -// contain self-references. Before we begin to deserialize the contents of these values, they
|
| -// are first given object reference IDs (by GenerateFreshObjectTag/GenerateFreshArrayTag);
|
| -// these reference IDs are then used with ObjectReferenceTag to tie the recursive knot.
|
| -enum SerializationTag {
|
| - InvalidTag = '!', // Causes deserialization to fail.
|
| - PaddingTag = '\0', // Is ignored (but consumed).
|
| - UndefinedTag = '_', // -> <undefined>
|
| - NullTag = '0', // -> <null>
|
| - TrueTag = 'T', // -> <true>
|
| - FalseTag = 'F', // -> <false>
|
| - StringTag = 'S', // string:RawString -> string
|
| - StringUCharTag = 'c', // string:RawUCharString -> string
|
| - Int32Tag = 'I', // value:ZigZag-encoded int32 -> Integer
|
| - Uint32Tag = 'U', // value:uint32_t -> Integer
|
| - DateTag = 'D', // value:double -> Date (ref)
|
| - MessagePortTag = 'M', // index:int -> MessagePort. Fills the result with transferred MessagePort.
|
| - NumberTag = 'N', // value:double -> Number
|
| - BlobTag = 'b', // uuid:WebCoreString, type:WebCoreString, size:uint64_t -> Blob (ref)
|
| - BlobIndexTag = 'i', // index:int32_t -> Blob (ref)
|
| - FileTag = 'f', // file:RawFile -> File (ref)
|
| - FileIndexTag = 'e', // index:int32_t -> File (ref)
|
| - DOMFileSystemTag = 'd', // type:int32_t, name:WebCoreString, uuid:WebCoreString -> FileSystem (ref)
|
| - FileListTag = 'l', // length:uint32_t, files:RawFile[length] -> FileList (ref)
|
| - FileListIndexTag = 'L', // length:uint32_t, files:int32_t[length] -> FileList (ref)
|
| - ImageDataTag = '#', // width:uint32_t, height:uint32_t, pixelDataLength:uint32_t, data:byte[pixelDataLength] -> ImageData (ref)
|
| - ObjectTag = '{', // numProperties:uint32_t -> pops the last object from the open stack;
|
| - // fills it with the last numProperties name,value pairs pushed onto the deserialization stack
|
| - SparseArrayTag = '@', // numProperties:uint32_t, length:uint32_t -> pops the last object from the open stack;
|
| - // fills it with the last numProperties name,value pairs pushed onto the deserialization stack
|
| - DenseArrayTag = '$', // numProperties:uint32_t, length:uint32_t -> pops the last object from the open stack;
|
| - // fills it with the last length elements and numProperties name,value pairs pushed onto deserialization stack
|
| - RegExpTag = 'R', // pattern:RawString, flags:uint32_t -> RegExp (ref)
|
| - ArrayBufferTag = 'B', // byteLength:uint32_t, data:byte[byteLength] -> ArrayBuffer (ref)
|
| - ArrayBufferTransferTag = 't', // index:uint32_t -> ArrayBuffer. For ArrayBuffer transfer
|
| - ArrayBufferViewTag = 'V', // subtag:byte, byteOffset:uint32_t, byteLength:uint32_t -> ArrayBufferView (ref). Consumes an ArrayBuffer from the top of the deserialization stack.
|
| - CryptoKeyTag = 'K', // subtag:byte, props, usages:uint32_t, keyDataLength:uint32_t, keyData:byte[keyDataLength]
|
| - // If subtag=AesKeyTag:
|
| - // props = keyLengthBytes:uint32_t, algorithmId:uint32_t
|
| - // If subtag=HmacKeyTag:
|
| - // props = keyLengthBytes:uint32_t, hashId:uint32_t
|
| - // If subtag=RsaHashedKeyTag:
|
| - // props = algorithmId:uint32_t, type:uint32_t, modulusLengthBits:uint32_t, publicExponentLength:uint32_t, publicExponent:byte[publicExponentLength], hashId:uint32_t
|
| - // If subtag=EcKeyTag:
|
| - // props = algorithmId:uint32_t, type:uint32_t, namedCurve:uint32_t
|
| - ObjectReferenceTag = '^', // ref:uint32_t -> reference table[ref]
|
| - GenerateFreshObjectTag = 'o', // -> empty object allocated an object ID and pushed onto the open stack (ref)
|
| - GenerateFreshSparseArrayTag = 'a', // length:uint32_t -> empty array[length] allocated an object ID and pushed onto the open stack (ref)
|
| - GenerateFreshDenseArrayTag = 'A', // length:uint32_t -> empty array[length] allocated an object ID and pushed onto the open stack (ref)
|
| - ReferenceCountTag = '?', // refTableSize:uint32_t -> If the reference table is not refTableSize big, fails.
|
| - StringObjectTag = 's', // string:RawString -> new String(string) (ref)
|
| - NumberObjectTag = 'n', // value:double -> new Number(value) (ref)
|
| - TrueObjectTag = 'y', // new Boolean(true) (ref)
|
| - FalseObjectTag = 'x', // new Boolean(false) (ref)
|
| - VersionTag = 0xFF // version:uint32_t -> Uses this as the file version.
|
| -};
|
| -
|
| -enum ArrayBufferViewSubTag {
|
| - ByteArrayTag = 'b',
|
| - UnsignedByteArrayTag = 'B',
|
| - UnsignedByteClampedArrayTag = 'C',
|
| - ShortArrayTag = 'w',
|
| - UnsignedShortArrayTag = 'W',
|
| - IntArrayTag = 'd',
|
| - UnsignedIntArrayTag = 'D',
|
| - FloatArrayTag = 'f',
|
| - DoubleArrayTag = 'F',
|
| - DataViewTag = '?'
|
| -};
|
| -
|
| -enum CryptoKeySubTag {
|
| - AesKeyTag = 1,
|
| - HmacKeyTag = 2,
|
| - // ID 3 was used by RsaKeyTag, while still behind experimental flag.
|
| - RsaHashedKeyTag = 4,
|
| - EcKeyTag = 5,
|
| - // Maximum allowed value is 255
|
| -};
|
| -
|
| -enum AssymetricCryptoKeyType {
|
| - PublicKeyType = 1,
|
| - PrivateKeyType = 2,
|
| - // Maximum allowed value is 2^32-1
|
| -};
|
| -
|
| -enum CryptoKeyAlgorithmTag {
|
| - AesCbcTag = 1,
|
| - HmacTag = 2,
|
| - RsaSsaPkcs1v1_5Tag = 3,
|
| - // ID 4 was used by RsaEs, while still behind experimental flag.
|
| - Sha1Tag = 5,
|
| - Sha256Tag = 6,
|
| - Sha384Tag = 7,
|
| - Sha512Tag = 8,
|
| - AesGcmTag = 9,
|
| - RsaOaepTag = 10,
|
| - AesCtrTag = 11,
|
| - AesKwTag = 12,
|
| - RsaPssTag = 13,
|
| - EcdsaTag = 14,
|
| - // Maximum allowed value is 2^32-1
|
| -};
|
| -
|
| -enum NamedCurveTag {
|
| - P256Tag = 1,
|
| - P384Tag = 2,
|
| - P521Tag = 3,
|
| -};
|
| -
|
| -enum CryptoKeyUsage {
|
| - // Extractability is not a "usage" in the WebCryptoKeyUsages sense, however
|
| - // it fits conveniently into this bitfield.
|
| - ExtractableUsage = 1 << 0,
|
| -
|
| - EncryptUsage = 1 << 1,
|
| - DecryptUsage = 1 << 2,
|
| - SignUsage = 1 << 3,
|
| - VerifyUsage = 1 << 4,
|
| - DeriveKeyUsage = 1 << 5,
|
| - WrapKeyUsage = 1 << 6,
|
| - UnwrapKeyUsage = 1 << 7,
|
| - DeriveBitsUsage = 1 << 8,
|
| - // Maximum allowed value is 1 << 31
|
| -};
|
| -
|
| -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 {
|
| - WTF_MAKE_NONCOPYABLE(Writer);
|
| -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 writeBooleanObject(bool value)
|
| - {
|
| - append(value ? TrueObjectTag : FalseObjectTag);
|
| - }
|
| -
|
| - void writeOneByteString(v8::Handle<v8::String>& string)
|
| - {
|
| - int stringLength = string->Length();
|
| - int utf8Length = string->Utf8Length();
|
| - ASSERT(stringLength >= 0 && utf8Length >= 0);
|
| -
|
| - append(StringTag);
|
| - doWriteUint32(static_cast<uint32_t>(utf8Length));
|
| - ensureSpace(utf8Length);
|
| -
|
| - // ASCII fast path.
|
| - if (stringLength == utf8Length) {
|
| - string->WriteOneByte(byteAt(m_position), 0, utf8Length, v8StringWriteOptions());
|
| - } else {
|
| - char* buffer = reinterpret_cast<char*>(byteAt(m_position));
|
| - string->WriteUtf8(buffer, utf8Length, 0, v8StringWriteOptions());
|
| - }
|
| - m_position += utf8Length;
|
| - }
|
| -
|
| - void writeUCharString(v8::Handle<v8::String>& string)
|
| - {
|
| - int length = string->Length();
|
| - ASSERT(length >= 0);
|
| -
|
| - int size = length * sizeof(UChar);
|
| - int bytes = bytesNeededToWireEncode(static_cast<uint32_t>(size));
|
| - if ((m_position + 1 + bytes) & 1)
|
| - append(PaddingTag);
|
| -
|
| - append(StringUCharTag);
|
| - doWriteUint32(static_cast<uint32_t>(size));
|
| - ensureSpace(size);
|
| -
|
| - ASSERT(!(m_position & 1));
|
| - uint16_t* buffer = reinterpret_cast<uint16_t*>(byteAt(m_position));
|
| - string->Write(buffer, 0, length, v8StringWriteOptions());
|
| - m_position += size;
|
| - }
|
| -
|
| - void writeStringObject(const char* data, int length)
|
| - {
|
| - ASSERT(length >= 0);
|
| - append(StringObjectTag);
|
| - 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 writeVersion()
|
| - {
|
| - append(VersionTag);
|
| - doWriteUint32(SerializedScriptValue::wireFormatVersion);
|
| - }
|
| -
|
| - 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 writeNumberObject(double number)
|
| - {
|
| - append(NumberObjectTag);
|
| - doWriteNumber(number);
|
| - }
|
| -
|
| - void writeBlob(const String& uuid, const String& type, unsigned long long size)
|
| - {
|
| - append(BlobTag);
|
| - doWriteWebCoreString(uuid);
|
| - doWriteWebCoreString(type);
|
| - doWriteUint64(size);
|
| - }
|
| -
|
| - void writeBlobIndex(int blobIndex)
|
| - {
|
| - ASSERT(blobIndex >= 0);
|
| - append(BlobIndexTag);
|
| - doWriteUint32(blobIndex);
|
| - }
|
| -
|
| - void writeDOMFileSystem(int type, const String& name, const String& url)
|
| - {
|
| - append(DOMFileSystemTag);
|
| - doWriteUint32(type);
|
| - doWriteWebCoreString(name);
|
| - doWriteWebCoreString(url);
|
| - }
|
| -
|
| - void writeFile(const File& file)
|
| - {
|
| - append(FileTag);
|
| - doWriteFile(file);
|
| - }
|
| -
|
| - void writeFileIndex(int blobIndex)
|
| - {
|
| - append(FileIndexTag);
|
| - doWriteUint32(blobIndex);
|
| - }
|
| -
|
| - void writeFileList(const FileList& fileList)
|
| - {
|
| - append(FileListTag);
|
| - uint32_t length = fileList.length();
|
| - doWriteUint32(length);
|
| - for (unsigned i = 0; i < length; ++i)
|
| - doWriteFile(*fileList.item(i));
|
| - }
|
| -
|
| - void writeFileListIndex(const Vector<int>& blobIndices)
|
| - {
|
| - append(FileListIndexTag);
|
| - uint32_t length = blobIndices.size();
|
| - doWriteUint32(length);
|
| - for (unsigned i = 0; i < length; ++i)
|
| - doWriteUint32(blobIndices[i]);
|
| - }
|
| -
|
| - bool writeCryptoKey(const WebCryptoKey& key)
|
| - {
|
| - append(static_cast<uint8_t>(CryptoKeyTag));
|
| -
|
| - switch (key.algorithm().paramsType()) {
|
| - case WebCryptoKeyAlgorithmParamsTypeAes:
|
| - doWriteAesKey(key);
|
| - break;
|
| - case WebCryptoKeyAlgorithmParamsTypeHmac:
|
| - doWriteHmacKey(key);
|
| - break;
|
| - case WebCryptoKeyAlgorithmParamsTypeRsaHashed:
|
| - doWriteRsaHashedKey(key);
|
| - break;
|
| - case WebCryptoKeyAlgorithmParamsTypeEc:
|
| - doWriteEcKey(key);
|
| - break;
|
| - case WebCryptoKeyAlgorithmParamsTypeNone:
|
| - ASSERT_NOT_REACHED();
|
| - return false;
|
| - }
|
| -
|
| - doWriteKeyUsages(key.usages(), key.extractable());
|
| -
|
| - WebVector<uint8_t> keyData;
|
| - if (!Platform::current()->crypto()->serializeKeyForClone(key, keyData))
|
| - return false;
|
| -
|
| - doWriteUint32(keyData.size());
|
| - append(keyData.data(), keyData.size());
|
| - return true;
|
| - }
|
| -
|
| - void writeArrayBuffer(const ArrayBuffer& arrayBuffer)
|
| - {
|
| - append(ArrayBufferTag);
|
| - doWriteArrayBuffer(arrayBuffer);
|
| - }
|
| -
|
| - void writeArrayBufferView(const ArrayBufferView& arrayBufferView)
|
| - {
|
| - append(ArrayBufferViewTag);
|
| -#if ENABLE(ASSERT)
|
| - const ArrayBuffer& arrayBuffer = *arrayBufferView.buffer();
|
| - ASSERT(static_cast<const uint8_t*>(arrayBuffer.data()) + arrayBufferView.byteOffset() ==
|
| - static_cast<const uint8_t*>(arrayBufferView.baseAddress()));
|
| -#endif
|
| - ArrayBufferView::ViewType type = arrayBufferView.type();
|
| -
|
| - if (type == ArrayBufferView::TypeInt8)
|
| - append(ByteArrayTag);
|
| - else if (type == ArrayBufferView::TypeUint8Clamped)
|
| - append(UnsignedByteClampedArrayTag);
|
| - else if (type == ArrayBufferView::TypeUint8)
|
| - append(UnsignedByteArrayTag);
|
| - else if (type == ArrayBufferView::TypeInt16)
|
| - append(ShortArrayTag);
|
| - else if (type == ArrayBufferView::TypeUint16)
|
| - append(UnsignedShortArrayTag);
|
| - else if (type == ArrayBufferView::TypeInt32)
|
| - append(IntArrayTag);
|
| - else if (type == ArrayBufferView::TypeUint32)
|
| - append(UnsignedIntArrayTag);
|
| - else if (type == ArrayBufferView::TypeFloat32)
|
| - append(FloatArrayTag);
|
| - else if (type == ArrayBufferView::TypeFloat64)
|
| - append(DoubleArrayTag);
|
| - else if (type == ArrayBufferView::TypeDataView)
|
| - append(DataViewTag);
|
| - else
|
| - ASSERT_NOT_REACHED();
|
| - doWriteUint32(arrayBufferView.byteOffset());
|
| - doWriteUint32(arrayBufferView.byteLength());
|
| - }
|
| -
|
| - 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 writeRegExp(v8::Local<v8::String> pattern, v8::RegExp::Flags flags)
|
| - {
|
| - append(RegExpTag);
|
| - v8::String::Utf8Value patternUtf8Value(pattern);
|
| - doWriteString(*patternUtf8Value, patternUtf8Value.length());
|
| - doWriteUint32(static_cast<uint32_t>(flags));
|
| - }
|
| -
|
| - void writeTransferredMessagePort(uint32_t index)
|
| - {
|
| - append(MessagePortTag);
|
| - doWriteUint32(index);
|
| - }
|
| -
|
| - void writeTransferredArrayBuffer(uint32_t index)
|
| - {
|
| - append(ArrayBufferTransferTag);
|
| - doWriteUint32(index);
|
| - }
|
| -
|
| - void writeObjectReference(uint32_t reference)
|
| - {
|
| - append(ObjectReferenceTag);
|
| - doWriteUint32(reference);
|
| - }
|
| -
|
| - void writeObject(uint32_t numProperties)
|
| - {
|
| - append(ObjectTag);
|
| - doWriteUint32(numProperties);
|
| - }
|
| -
|
| - void writeSparseArray(uint32_t numProperties, uint32_t length)
|
| - {
|
| - append(SparseArrayTag);
|
| - doWriteUint32(numProperties);
|
| - doWriteUint32(length);
|
| - }
|
| -
|
| - void writeDenseArray(uint32_t numProperties, uint32_t length)
|
| - {
|
| - append(DenseArrayTag);
|
| - doWriteUint32(numProperties);
|
| - doWriteUint32(length);
|
| - }
|
| -
|
| - String takeWireString()
|
| - {
|
| - COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes);
|
| - fillHole();
|
| - String data = String(m_buffer.data(), m_buffer.size());
|
| - data.impl()->truncateAssumingIsolated((m_position + 1) / sizeof(BufferValueType));
|
| - return data;
|
| - }
|
| -
|
| - void writeReferenceCount(uint32_t numberOfReferences)
|
| - {
|
| - append(ReferenceCountTag);
|
| - doWriteUint32(numberOfReferences);
|
| - }
|
| -
|
| - void writeGenerateFreshObject()
|
| - {
|
| - append(GenerateFreshObjectTag);
|
| - }
|
| -
|
| - void writeGenerateFreshSparseArray(uint32_t length)
|
| - {
|
| - append(GenerateFreshSparseArrayTag);
|
| - doWriteUint32(length);
|
| - }
|
| -
|
| - void writeGenerateFreshDenseArray(uint32_t length)
|
| - {
|
| - append(GenerateFreshDenseArrayTag);
|
| - doWriteUint32(length);
|
| - }
|
| -
|
| -private:
|
| - void doWriteFile(const File& file)
|
| - {
|
| - doWriteWebCoreString(file.hasBackingFile() ? file.path() : "");
|
| - doWriteWebCoreString(file.name());
|
| - doWriteWebCoreString(file.webkitRelativePath());
|
| - doWriteWebCoreString(file.uuid());
|
| - doWriteWebCoreString(file.type());
|
| -
|
| - // FIXME don't use 1 byte to encode a flag.
|
| - if (file.hasValidSnapshotMetadata()) {
|
| - doWriteUint32(static_cast<uint8_t>(1));
|
| -
|
| - long long size;
|
| - double lastModified;
|
| - file.captureSnapshot(size, lastModified);
|
| - doWriteUint64(static_cast<uint64_t>(size));
|
| - doWriteNumber(lastModified);
|
| - } else {
|
| - doWriteUint32(static_cast<uint8_t>(0));
|
| - }
|
| -
|
| - doWriteUint32(static_cast<uint8_t>((file.userVisibility() == File::IsUserVisible) ? 1 : 0));
|
| - }
|
| -
|
| - void doWriteArrayBuffer(const ArrayBuffer& arrayBuffer)
|
| - {
|
| - uint32_t byteLength = arrayBuffer.byteLength();
|
| - doWriteUint32(byteLength);
|
| - append(static_cast<const uint8_t*>(arrayBuffer.data()), byteLength);
|
| - }
|
| -
|
| - 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)
|
| - {
|
| - StringUTF8Adaptor stringUTF8(string);
|
| - doWriteString(stringUTF8.data(), stringUTF8.length());
|
| - }
|
| -
|
| - void doWriteHmacKey(const WebCryptoKey& key)
|
| - {
|
| - ASSERT(key.algorithm().paramsType() == WebCryptoKeyAlgorithmParamsTypeHmac);
|
| -
|
| - append(static_cast<uint8_t>(HmacKeyTag));
|
| - ASSERT(!(key.algorithm().hmacParams()->lengthBits() % 8));
|
| - doWriteUint32(key.algorithm().hmacParams()->lengthBits() / 8);
|
| - doWriteAlgorithmId(key.algorithm().hmacParams()->hash().id());
|
| - }
|
| -
|
| - void doWriteAesKey(const WebCryptoKey& key)
|
| - {
|
| - ASSERT(key.algorithm().paramsType() == WebCryptoKeyAlgorithmParamsTypeAes);
|
| -
|
| - append(static_cast<uint8_t>(AesKeyTag));
|
| - doWriteAlgorithmId(key.algorithm().id());
|
| - // Converting the key length from bits to bytes is lossless and makes
|
| - // it fit in 1 byte.
|
| - ASSERT(!(key.algorithm().aesParams()->lengthBits() % 8));
|
| - doWriteUint32(key.algorithm().aesParams()->lengthBits() / 8);
|
| - }
|
| -
|
| - void doWriteRsaHashedKey(const WebCryptoKey& key)
|
| - {
|
| - ASSERT(key.algorithm().rsaHashedParams());
|
| - append(static_cast<uint8_t>(RsaHashedKeyTag));
|
| -
|
| - doWriteAlgorithmId(key.algorithm().id());
|
| - doWriteAsymmetricKeyType(key.type());
|
| -
|
| - const WebCryptoRsaHashedKeyAlgorithmParams* params = key.algorithm().rsaHashedParams();
|
| - doWriteUint32(params->modulusLengthBits());
|
| - doWriteUint32(params->publicExponent().size());
|
| - append(params->publicExponent().data(), params->publicExponent().size());
|
| - doWriteAlgorithmId(params->hash().id());
|
| - }
|
| -
|
| - void doWriteEcKey(const WebCryptoKey& key)
|
| - {
|
| - ASSERT(key.algorithm().ecParams());
|
| - append(static_cast<uint8_t>(EcKeyTag));
|
| -
|
| - doWriteAlgorithmId(key.algorithm().id());
|
| - doWriteAsymmetricKeyType(key.type());
|
| - doWriteNamedCurve(key.algorithm().ecParams()->namedCurve());
|
| - }
|
| -
|
| - void doWriteAlgorithmId(WebCryptoAlgorithmId id)
|
| - {
|
| - switch (id) {
|
| - case WebCryptoAlgorithmIdAesCbc:
|
| - return doWriteUint32(AesCbcTag);
|
| - case WebCryptoAlgorithmIdHmac:
|
| - return doWriteUint32(HmacTag);
|
| - case WebCryptoAlgorithmIdRsaSsaPkcs1v1_5:
|
| - return doWriteUint32(RsaSsaPkcs1v1_5Tag);
|
| - case WebCryptoAlgorithmIdSha1:
|
| - return doWriteUint32(Sha1Tag);
|
| - case WebCryptoAlgorithmIdSha256:
|
| - return doWriteUint32(Sha256Tag);
|
| - case WebCryptoAlgorithmIdSha384:
|
| - return doWriteUint32(Sha384Tag);
|
| - case WebCryptoAlgorithmIdSha512:
|
| - return doWriteUint32(Sha512Tag);
|
| - case WebCryptoAlgorithmIdAesGcm:
|
| - return doWriteUint32(AesGcmTag);
|
| - case WebCryptoAlgorithmIdRsaOaep:
|
| - return doWriteUint32(RsaOaepTag);
|
| - case WebCryptoAlgorithmIdAesCtr:
|
| - return doWriteUint32(AesCtrTag);
|
| - case WebCryptoAlgorithmIdAesKw:
|
| - return doWriteUint32(AesKwTag);
|
| - case WebCryptoAlgorithmIdRsaPss:
|
| - return doWriteUint32(RsaPssTag);
|
| - case WebCryptoAlgorithmIdEcdsa:
|
| - return doWriteUint32(EcdsaTag);
|
| - }
|
| - ASSERT_NOT_REACHED();
|
| - }
|
| -
|
| - void doWriteAsymmetricKeyType(WebCryptoKeyType keyType)
|
| - {
|
| - switch (keyType) {
|
| - case WebCryptoKeyTypePublic:
|
| - doWriteUint32(PublicKeyType);
|
| - break;
|
| - case WebCryptoKeyTypePrivate:
|
| - doWriteUint32(PrivateKeyType);
|
| - break;
|
| - case WebCryptoKeyTypeSecret:
|
| - ASSERT_NOT_REACHED();
|
| - }
|
| - }
|
| -
|
| - void doWriteNamedCurve(WebCryptoNamedCurve namedCurve)
|
| - {
|
| - switch (namedCurve) {
|
| - case WebCryptoNamedCurveP256:
|
| - return doWriteUint32(P256Tag);
|
| - case WebCryptoNamedCurveP384:
|
| - return doWriteUint32(P384Tag);
|
| - case WebCryptoNamedCurveP521:
|
| - return doWriteUint32(P521Tag);
|
| - }
|
| - ASSERT_NOT_REACHED();
|
| - }
|
| -
|
| - void doWriteKeyUsages(const WebCryptoKeyUsageMask usages, bool extractable)
|
| - {
|
| - // Reminder to update this when adding new key usages.
|
| - COMPILE_ASSERT(EndOfWebCryptoKeyUsage == (1 << 7) + 1, UpdateMe);
|
| -
|
| - uint32_t value = 0;
|
| -
|
| - if (extractable)
|
| - value |= ExtractableUsage;
|
| -
|
| - if (usages & WebCryptoKeyUsageEncrypt)
|
| - value |= EncryptUsage;
|
| - if (usages & WebCryptoKeyUsageDecrypt)
|
| - value |= DecryptUsage;
|
| - if (usages & WebCryptoKeyUsageSign)
|
| - value |= SignUsage;
|
| - if (usages & WebCryptoKeyUsageVerify)
|
| - value |= VerifyUsage;
|
| - if (usages & WebCryptoKeyUsageDeriveKey)
|
| - value |= DeriveKeyUsage;
|
| - if (usages & WebCryptoKeyUsageWrapKey)
|
| - value |= WrapKeyUsage;
|
| - if (usages & WebCryptoKeyUsageUnwrapKey)
|
| - value |= UnwrapKeyUsage;
|
| - if (usages & WebCryptoKeyUsageDeriveBits)
|
| - value |= DeriveBitsUsage;
|
| -
|
| - doWriteUint32(value);
|
| - }
|
| -
|
| - int bytesNeededToWireEncode(uint32_t value)
|
| - {
|
| - int bytes = 1;
|
| - while (true) {
|
| - value >>= varIntShift;
|
| - if (!value)
|
| - break;
|
| - ++bytes;
|
| - }
|
| -
|
| - return bytes;
|
| - }
|
| -
|
| - template<class T>
|
| - void doWriteUintHelper(T value)
|
| - {
|
| - while (true) {
|
| - uint8_t b = (value & varIntMask);
|
| - value >>= varIntShift;
|
| - if (!value) {
|
| - append(b);
|
| - break;
|
| - }
|
| - append(b | (1 << varIntShift));
|
| - }
|
| - }
|
| -
|
| - void doWriteUint32(uint32_t value)
|
| - {
|
| - doWriteUintHelper(value);
|
| - }
|
| -
|
| - void doWriteUint64(uint64_t value)
|
| - {
|
| - doWriteUintHelper(value);
|
| - }
|
| -
|
| - 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(unsigned extra)
|
| - {
|
| - COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes);
|
| - m_buffer.resize((m_position + extra + 1) / sizeof(BufferValueType)); // "+ 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;
|
| - }
|
| -
|
| - int v8StringWriteOptions()
|
| - {
|
| - return v8::String::NO_NULL_TERMINATION;
|
| - }
|
| -
|
| - Vector<BufferValueType> m_buffer;
|
| - unsigned m_position;
|
| -};
|
| -
|
| -static v8::Handle<v8::Object> toV8Object(MessagePort* impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
|
| -{
|
| - if (!impl)
|
| - return v8::Handle<v8::Object>();
|
| - v8::Handle<v8::Value> wrapper = toV8(impl, creationContext, isolate);
|
| - ASSERT(wrapper->IsObject());
|
| - return wrapper.As<v8::Object>();
|
| -}
|
| -
|
| -static v8::Handle<v8::ArrayBuffer> toV8Object(DOMArrayBuffer* impl, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate)
|
| -{
|
| - if (!impl)
|
| - return v8::Handle<v8::ArrayBuffer>();
|
| - v8::Handle<v8::Value> wrapper = toV8(impl, creationContext, isolate);
|
| - ASSERT(wrapper->IsArrayBuffer());
|
| - return wrapper.As<v8::ArrayBuffer>();
|
| -}
|
| -
|
| -class Serializer {
|
| - class StateBase;
|
| -public:
|
| - enum Status {
|
| - Success,
|
| - InputError,
|
| - DataCloneError,
|
| - JSException
|
| - };
|
| -
|
| - Serializer(Writer& writer, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, WebBlobInfoArray* blobInfo, BlobDataHandleMap& blobDataHandles, v8::TryCatch& tryCatch, ScriptState* scriptState)
|
| - : m_scriptState(scriptState)
|
| - , m_writer(writer)
|
| - , m_tryCatch(tryCatch)
|
| - , m_depth(0)
|
| - , m_status(Success)
|
| - , m_nextObjectReference(0)
|
| - , m_blobInfo(blobInfo)
|
| - , m_blobDataHandles(blobDataHandles)
|
| - {
|
| - ASSERT(!tryCatch.HasCaught());
|
| - v8::Handle<v8::Object> creationContext = m_scriptState->context()->Global();
|
| - if (messagePorts) {
|
| - for (size_t i = 0; i < messagePorts->size(); i++)
|
| - m_transferredMessagePorts.set(toV8Object(messagePorts->at(i).get(), creationContext, isolate()), i);
|
| - }
|
| - if (arrayBuffers) {
|
| - for (size_t i = 0; i < arrayBuffers->size(); i++) {
|
| - v8::Handle<v8::Object> v8ArrayBuffer = toV8Object(arrayBuffers->at(i).get(), creationContext, isolate());
|
| - // Coalesce multiple occurences of the same buffer to the first index.
|
| - if (!m_transferredArrayBuffers.contains(v8ArrayBuffer))
|
| - m_transferredArrayBuffers.set(v8ArrayBuffer, i);
|
| - }
|
| - }
|
| - }
|
| -
|
| - v8::Isolate* isolate() { return m_scriptState->isolate(); }
|
| -
|
| - Status serialize(v8::Handle<v8::Value> value)
|
| - {
|
| - v8::HandleScope scope(isolate());
|
| - m_writer.writeVersion();
|
| - StateBase* state = doSerialize(value, 0);
|
| - while (state)
|
| - state = state->advance(*this);
|
| - return m_status;
|
| - }
|
| -
|
| - String errorMessage() { return m_errorMessage; }
|
| -
|
| - // Functions used by serialization states.
|
| - StateBase* doSerialize(v8::Handle<v8::Value>, StateBase* next);
|
| -
|
| - StateBase* doSerializeArrayBuffer(v8::Handle<v8::Value> arrayBuffer, StateBase* next)
|
| - {
|
| - return doSerialize(arrayBuffer, next);
|
| - }
|
| -
|
| - StateBase* checkException(StateBase* state)
|
| - {
|
| - return m_tryCatch.HasCaught() ? handleError(JSException, "", state) : 0;
|
| - }
|
| -
|
| - 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);
|
| - }
|
| -
|
| - StateBase* writeDenseArray(uint32_t numProperties, uint32_t length, StateBase* state)
|
| - {
|
| - m_writer.writeDenseArray(numProperties, length);
|
| - return pop(state);
|
| - }
|
| -
|
| -
|
| -private:
|
| - class StateBase {
|
| - WTF_MAKE_NONCOPYABLE(StateBase);
|
| - 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 final : public StateBase {
|
| - public:
|
| - ErrorState()
|
| - : StateBase(v8Undefined(), 0)
|
| - {
|
| - }
|
| -
|
| - virtual StateBase* advance(Serializer&) override
|
| - {
|
| - 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)
|
| - {
|
| - }
|
| - };
|
| -
|
| - class AbstractObjectState : public State<v8::Object> {
|
| - public:
|
| - AbstractObjectState(v8::Handle<v8::Object> object, StateBase* next)
|
| - : State<v8::Object>(object, next)
|
| - , m_index(0)
|
| - , m_numSerializedProperties(0)
|
| - , m_nameDone(false)
|
| - {
|
| - }
|
| -
|
| - protected:
|
| - virtual StateBase* objectDone(unsigned numProperties, Serializer&) = 0;
|
| -
|
| - StateBase* serializeProperties(bool ignoreIndexed, Serializer& serializer)
|
| - {
|
| - while (m_index < m_propertyNames->Length()) {
|
| - if (!m_nameDone) {
|
| - v8::Local<v8::Value> propertyName = m_propertyNames->Get(m_index);
|
| - if (StateBase* newState = serializer.checkException(this))
|
| - return newState;
|
| - if (propertyName.IsEmpty())
|
| - return serializer.handleError(InputError, "Empty property names cannot be cloned.", this);
|
| - bool hasStringProperty = propertyName->IsString() && composite()->HasRealNamedProperty(propertyName.As<v8::String>());
|
| - if (StateBase* newState = serializer.checkException(this))
|
| - return newState;
|
| - bool hasIndexedProperty = !hasStringProperty && propertyName->IsUint32() && composite()->HasRealIndexedProperty(propertyName->Uint32Value());
|
| - if (StateBase* newState = serializer.checkException(this))
|
| - return newState;
|
| - if (hasStringProperty || (hasIndexedProperty && !ignoreIndexed)) {
|
| - m_propertyName = propertyName;
|
| - } else {
|
| - ++m_index;
|
| - 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);
|
| - if (StateBase* newState = serializer.checkException(this))
|
| - return newState;
|
| - m_nameDone = false;
|
| - m_propertyName.Clear();
|
| - ++m_index;
|
| - ++m_numSerializedProperties;
|
| - // If we return early here, it's either because we have pushed a new state onto the
|
| - // serialization state stack or because we have encountered an error (and in both cases
|
| - // we are unwinding the native stack).
|
| - if (StateBase* newState = serializer.doSerialize(value, this))
|
| - return newState;
|
| - }
|
| - return objectDone(m_numSerializedProperties, serializer);
|
| - }
|
| -
|
| - v8::Local<v8::Array> m_propertyNames;
|
| -
|
| - private:
|
| - v8::Local<v8::Value> m_propertyName;
|
| - unsigned m_index;
|
| - unsigned m_numSerializedProperties;
|
| - bool m_nameDone;
|
| - };
|
| -
|
| - class ObjectState final : public AbstractObjectState {
|
| - public:
|
| - ObjectState(v8::Handle<v8::Object> object, StateBase* next)
|
| - : AbstractObjectState(object, next)
|
| - {
|
| - }
|
| -
|
| - virtual StateBase* advance(Serializer& serializer) override
|
| - {
|
| - if (m_propertyNames.IsEmpty()) {
|
| - m_propertyNames = composite()->GetPropertyNames();
|
| - if (StateBase* newState = serializer.checkException(this))
|
| - return newState;
|
| - if (m_propertyNames.IsEmpty())
|
| - return serializer.handleError(InputError, "Empty property names cannot be cloned.", nextState());
|
| - }
|
| - return serializeProperties(false, serializer);
|
| - }
|
| -
|
| - protected:
|
| - virtual StateBase* objectDone(unsigned numProperties, Serializer& serializer) override
|
| - {
|
| - return serializer.writeObject(numProperties, this);
|
| - }
|
| - };
|
| -
|
| - class DenseArrayState final : public AbstractObjectState {
|
| - public:
|
| - DenseArrayState(v8::Handle<v8::Array> array, v8::Handle<v8::Array> propertyNames, StateBase* next, v8::Isolate* isolate)
|
| - : AbstractObjectState(array, next)
|
| - , m_arrayIndex(0)
|
| - , m_arrayLength(array->Length())
|
| - {
|
| - m_propertyNames = v8::Local<v8::Array>::New(isolate, propertyNames);
|
| - }
|
| -
|
| - virtual StateBase* advance(Serializer& serializer) override
|
| - {
|
| - while (m_arrayIndex < m_arrayLength) {
|
| - v8::Handle<v8::Value> value = composite().As<v8::Array>()->Get(m_arrayIndex);
|
| - m_arrayIndex++;
|
| - if (StateBase* newState = serializer.checkException(this))
|
| - return newState;
|
| - if (StateBase* newState = serializer.doSerialize(value, this))
|
| - return newState;
|
| - }
|
| - return serializeProperties(true, serializer);
|
| - }
|
| -
|
| - protected:
|
| - virtual StateBase* objectDone(unsigned numProperties, Serializer& serializer) override
|
| - {
|
| - return serializer.writeDenseArray(numProperties, m_arrayLength, this);
|
| - }
|
| -
|
| - private:
|
| - uint32_t m_arrayIndex;
|
| - uint32_t m_arrayLength;
|
| - };
|
| -
|
| - class SparseArrayState final : public AbstractObjectState {
|
| - public:
|
| - SparseArrayState(v8::Handle<v8::Array> array, v8::Handle<v8::Array> propertyNames, StateBase* next, v8::Isolate* isolate)
|
| - : AbstractObjectState(array, next)
|
| - {
|
| - m_propertyNames = v8::Local<v8::Array>::New(isolate, propertyNames);
|
| - }
|
| -
|
| - virtual StateBase* advance(Serializer& serializer) override
|
| - {
|
| - return serializeProperties(false, serializer);
|
| - }
|
| -
|
| - protected:
|
| - virtual StateBase* objectDone(unsigned numProperties, Serializer& serializer) override
|
| - {
|
| - return serializer.writeSparseArray(numProperties, composite().As<v8::Array>()->Length(), this);
|
| - }
|
| - };
|
| -
|
| - StateBase* push(StateBase* state)
|
| - {
|
| - ASSERT(state);
|
| - ++m_depth;
|
| - return checkComposite(state) ? state : handleError(InputError, "Value being cloned is either cyclic or too deeply nested.", state);
|
| - }
|
| -
|
| - StateBase* pop(StateBase* state)
|
| - {
|
| - ASSERT(state);
|
| - --m_depth;
|
| - StateBase* next = state->nextState();
|
| - delete state;
|
| - return next;
|
| - }
|
| -
|
| - StateBase* handleError(Status errorStatus, const String& message, StateBase* state)
|
| - {
|
| - ASSERT(errorStatus != Success);
|
| - m_status = errorStatus;
|
| - m_errorMessage = message;
|
| - 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::Handle<v8::String> string = value.As<v8::String>();
|
| - if (!string->Length() || string->IsOneByte())
|
| - m_writer.writeOneByteString(string);
|
| - else
|
| - m_writer.writeUCharString(string);
|
| - }
|
| -
|
| - void writeStringObject(v8::Handle<v8::Value> value)
|
| - {
|
| - v8::Handle<v8::StringObject> stringObject = value.As<v8::StringObject>();
|
| - v8::String::Utf8Value stringValue(stringObject->ValueOf());
|
| - m_writer.writeStringObject(*stringValue, stringValue.length());
|
| - }
|
| -
|
| - void writeNumberObject(v8::Handle<v8::Value> value)
|
| - {
|
| - v8::Handle<v8::NumberObject> numberObject = value.As<v8::NumberObject>();
|
| - m_writer.writeNumberObject(numberObject->ValueOf());
|
| - }
|
| -
|
| - void writeBooleanObject(v8::Handle<v8::Value> value)
|
| - {
|
| - v8::Handle<v8::BooleanObject> booleanObject = value.As<v8::BooleanObject>();
|
| - m_writer.writeBooleanObject(booleanObject->ValueOf());
|
| - }
|
| -
|
| - StateBase* writeBlob(v8::Handle<v8::Value> value, StateBase* next)
|
| - {
|
| - Blob* blob = V8Blob::toImpl(value.As<v8::Object>());
|
| - if (!blob)
|
| - return 0;
|
| - if (blob->hasBeenClosed())
|
| - return handleError(DataCloneError, "A Blob object has been closed, and could therefore not be cloned.", next);
|
| - int blobIndex = -1;
|
| - m_blobDataHandles.set(blob->uuid(), blob->blobDataHandle());
|
| - if (appendBlobInfo(blob->uuid(), blob->type(), blob->size(), &blobIndex))
|
| - m_writer.writeBlobIndex(blobIndex);
|
| - else
|
| - m_writer.writeBlob(blob->uuid(), blob->type(), blob->size());
|
| - return 0;
|
| - }
|
| -
|
| - StateBase* writeDOMFileSystem(v8::Handle<v8::Value> value, StateBase* next)
|
| - {
|
| - DOMFileSystem* fs = V8DOMFileSystem::toImpl(value.As<v8::Object>());
|
| - if (!fs)
|
| - return 0;
|
| - if (!fs->clonable())
|
| - return handleError(DataCloneError, "A FileSystem object could not be cloned.", next);
|
| - m_writer.writeDOMFileSystem(fs->type(), fs->name(), fs->rootURL().string());
|
| - return 0;
|
| - }
|
| -
|
| - StateBase* writeFile(v8::Handle<v8::Value> value, StateBase* next)
|
| - {
|
| - File* file = V8File::toImpl(value.As<v8::Object>());
|
| - if (!file)
|
| - return 0;
|
| - if (file->hasBeenClosed())
|
| - return handleError(DataCloneError, "A File object has been closed, and could therefore not be cloned.", next);
|
| - int blobIndex = -1;
|
| - m_blobDataHandles.set(file->uuid(), file->blobDataHandle());
|
| - if (appendFileInfo(file, &blobIndex)) {
|
| - ASSERT(blobIndex >= 0);
|
| - m_writer.writeFileIndex(blobIndex);
|
| - } else {
|
| - m_writer.writeFile(*file);
|
| - }
|
| - return 0;
|
| - }
|
| -
|
| - StateBase* writeFileList(v8::Handle<v8::Value> value, StateBase* next)
|
| - {
|
| - FileList* fileList = V8FileList::toImpl(value.As<v8::Object>());
|
| - if (!fileList)
|
| - return 0;
|
| - unsigned length = fileList->length();
|
| - Vector<int> blobIndices;
|
| - for (unsigned i = 0; i < length; ++i) {
|
| - int blobIndex = -1;
|
| - const File* file = fileList->item(i);
|
| - if (file->hasBeenClosed())
|
| - return handleError(DataCloneError, "A File object has been closed, and could therefore not be cloned.", next);
|
| - m_blobDataHandles.set(file->uuid(), file->blobDataHandle());
|
| - if (appendFileInfo(file, &blobIndex)) {
|
| - ASSERT(!i || blobIndex > 0);
|
| - ASSERT(blobIndex >= 0);
|
| - blobIndices.append(blobIndex);
|
| - }
|
| - }
|
| - if (!blobIndices.isEmpty())
|
| - m_writer.writeFileListIndex(blobIndices);
|
| - else
|
| - m_writer.writeFileList(*fileList);
|
| - return 0;
|
| - }
|
| -
|
| - bool writeCryptoKey(v8::Handle<v8::Value> value)
|
| - {
|
| - CryptoKey* key = V8CryptoKey::toImpl(value.As<v8::Object>());
|
| - if (!key)
|
| - return false;
|
| - return m_writer.writeCryptoKey(key->key());
|
| - }
|
| -
|
| - void writeImageData(v8::Handle<v8::Value> value)
|
| - {
|
| - ImageData* imageData = V8ImageData::toImpl(value.As<v8::Object>());
|
| - if (!imageData)
|
| - return;
|
| - Uint8ClampedArray* pixelArray = imageData->data();
|
| - m_writer.writeImageData(imageData->width(), imageData->height(), pixelArray->data(), pixelArray->length());
|
| - }
|
| -
|
| - void writeRegExp(v8::Handle<v8::Value> value)
|
| - {
|
| - v8::Handle<v8::RegExp> regExp = value.As<v8::RegExp>();
|
| - m_writer.writeRegExp(regExp->GetSource(), regExp->GetFlags());
|
| - }
|
| -
|
| - StateBase* writeAndGreyArrayBufferView(v8::Handle<v8::Object> object, StateBase* next)
|
| - {
|
| - ASSERT(!object.IsEmpty());
|
| - DOMArrayBufferView* arrayBufferView = V8ArrayBufferView::toImpl(object);
|
| - if (!arrayBufferView)
|
| - return 0;
|
| - if (!arrayBufferView->buffer())
|
| - return handleError(DataCloneError, "An ArrayBuffer could not be cloned.", next);
|
| - v8::Handle<v8::Value> underlyingBuffer = toV8(arrayBufferView->buffer(), m_scriptState->context()->Global(), isolate());
|
| - if (underlyingBuffer.IsEmpty())
|
| - return handleError(DataCloneError, "An ArrayBuffer could not be cloned.", next);
|
| - StateBase* stateOut = doSerializeArrayBuffer(underlyingBuffer, next);
|
| - if (stateOut)
|
| - return stateOut;
|
| - m_writer.writeArrayBufferView(*arrayBufferView->view());
|
| - // This should be safe: we serialize something that we know to be a wrapper (see
|
| - // the toV8 call above), so the call to doSerializeArrayBuffer should neither
|
| - // cause the system stack to overflow nor should it have potential to reach
|
| - // this ArrayBufferView again.
|
| - //
|
| - // We do need to grey the underlying buffer before we grey its view, however;
|
| - // ArrayBuffers may be shared, so they need to be given reference IDs, and an
|
| - // ArrayBufferView cannot be constructed without a corresponding ArrayBuffer
|
| - // (or without an additional tag that would allow us to do two-stage construction
|
| - // like we do for Objects and Arrays).
|
| - greyObject(object);
|
| - return 0;
|
| - }
|
| -
|
| - StateBase* writeArrayBuffer(v8::Handle<v8::Value> value, StateBase* next)
|
| - {
|
| - DOMArrayBuffer* arrayBuffer = V8ArrayBuffer::toImpl(value.As<v8::Object>());
|
| - if (!arrayBuffer)
|
| - return 0;
|
| - if (arrayBuffer->isNeutered())
|
| - return handleError(DataCloneError, "An ArrayBuffer is neutered and could not be cloned.", next);
|
| - ASSERT(!m_transferredArrayBuffers.contains(value.As<v8::Object>()));
|
| - m_writer.writeArrayBuffer(*arrayBuffer->buffer());
|
| - return 0;
|
| - }
|
| -
|
| - StateBase* writeTransferredArrayBuffer(v8::Handle<v8::Value> value, uint32_t index, StateBase* next)
|
| - {
|
| - DOMArrayBuffer* arrayBuffer = V8ArrayBuffer::toImpl(value.As<v8::Object>());
|
| - if (!arrayBuffer)
|
| - return 0;
|
| - if (arrayBuffer->isNeutered())
|
| - return handleError(DataCloneError, "An ArrayBuffer is neutered and could not be cloned.", next);
|
| - m_writer.writeTransferredArrayBuffer(index);
|
| - return 0;
|
| - }
|
| -
|
| - static bool shouldSerializeDensely(uint32_t length, uint32_t propertyCount)
|
| - {
|
| - // Let K be the cost of serializing all property values that are there
|
| - // Cost of serializing sparsely: 5*propertyCount + K (5 bytes per uint32_t key)
|
| - // Cost of serializing densely: K + 1*(length - propertyCount) (1 byte for all properties that are not there)
|
| - // so densely is better than sparsly whenever 6*propertyCount > length
|
| - return 6 * propertyCount >= length;
|
| - }
|
| -
|
| - StateBase* startArrayState(v8::Handle<v8::Array> array, StateBase* next)
|
| - {
|
| - v8::Handle<v8::Array> propertyNames = array->GetPropertyNames();
|
| - if (StateBase* newState = checkException(next))
|
| - return newState;
|
| - uint32_t length = array->Length();
|
| -
|
| - if (shouldSerializeDensely(length, propertyNames->Length())) {
|
| - m_writer.writeGenerateFreshDenseArray(length);
|
| - return push(new DenseArrayState(array, propertyNames, next, isolate()));
|
| - }
|
| -
|
| - m_writer.writeGenerateFreshSparseArray(length);
|
| - return push(new SparseArrayState(array, propertyNames, next, isolate()));
|
| - }
|
| -
|
| - StateBase* startObjectState(v8::Handle<v8::Object> object, StateBase* next)
|
| - {
|
| - m_writer.writeGenerateFreshObject();
|
| - // FIXME: check not a wrapper
|
| - return push(new ObjectState(object, next));
|
| - }
|
| -
|
| - // Marks object as having been visited by the serializer and assigns it a unique object reference ID.
|
| - // An object may only be greyed once.
|
| - void greyObject(const v8::Handle<v8::Object>& object)
|
| - {
|
| - ASSERT(!m_objectPool.contains(object));
|
| - uint32_t objectReference = m_nextObjectReference++;
|
| - m_objectPool.set(object, objectReference);
|
| - }
|
| -
|
| - bool appendBlobInfo(const String& uuid, const String& type, unsigned long long size, int* index)
|
| - {
|
| - if (!m_blobInfo)
|
| - return false;
|
| - *index = m_blobInfo->size();
|
| - m_blobInfo->append(WebBlobInfo(uuid, type, size));
|
| - return true;
|
| - }
|
| -
|
| - bool appendFileInfo(const File* file, int* index)
|
| - {
|
| - if (!m_blobInfo)
|
| - return false;
|
| -
|
| - long long size = -1;
|
| - double lastModified = invalidFileTime();
|
| - file->captureSnapshot(size, lastModified);
|
| - *index = m_blobInfo->size();
|
| - m_blobInfo->append(WebBlobInfo(file->uuid(), file->path(), file->name(), file->type(), lastModified, size));
|
| - return true;
|
| - }
|
| -
|
| - RefPtr<ScriptState> m_scriptState;
|
| - Writer& m_writer;
|
| - v8::TryCatch& m_tryCatch;
|
| - int m_depth;
|
| - Status m_status;
|
| - String m_errorMessage;
|
| - typedef V8ObjectMap<v8::Object, uint32_t> ObjectPool;
|
| - ObjectPool m_objectPool;
|
| - ObjectPool m_transferredMessagePorts;
|
| - ObjectPool m_transferredArrayBuffers;
|
| - uint32_t m_nextObjectReference;
|
| - WebBlobInfoArray* m_blobInfo;
|
| - BlobDataHandleMap& m_blobDataHandles;
|
| -};
|
| -
|
| -// Returns true if the provided object is to be considered a 'host object', as used in the
|
| -// HTML5 structured clone algorithm.
|
| -static bool isHostObject(v8::Handle<v8::Object> object)
|
| -{
|
| - // If the object has any internal fields, then we won't be able to serialize or deserialize
|
| - // them; conveniently, this is also a quick way to detect DOM wrapper objects, because
|
| - // the mechanism for these relies on data stored in these fields. We should
|
| - // catch external array data as a special case.
|
| - return object->InternalFieldCount() || object->HasIndexedPropertiesInExternalArrayData();
|
| -}
|
| -
|
| -Serializer::StateBase* Serializer::doSerialize(v8::Handle<v8::Value> value, StateBase* next)
|
| -{
|
| - m_writer.writeReferenceCount(m_nextObjectReference);
|
| - uint32_t objectReference;
|
| - uint32_t arrayBufferIndex;
|
| - if ((value->IsObject() || value->IsDate() || value->IsRegExp())
|
| - && m_objectPool.tryGet(value.As<v8::Object>(), &objectReference)) {
|
| - // Note that IsObject() also detects wrappers (eg, it will catch the things
|
| - // that we grey and write below).
|
| - ASSERT(!value->IsString());
|
| - m_writer.writeObjectReference(objectReference);
|
| - } else if (value.IsEmpty()) {
|
| - return handleError(InputError, "The empty property name cannot be cloned.", next);
|
| - } else 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->IsNumber()) {
|
| - m_writer.writeNumber(value.As<v8::Number>()->Value());
|
| - } else if (V8ArrayBufferView::hasInstance(value, isolate())) {
|
| - return writeAndGreyArrayBufferView(value.As<v8::Object>(), next);
|
| - } else if (value->IsString()) {
|
| - writeString(value);
|
| - } else if (V8MessagePort::hasInstance(value, isolate())) {
|
| - uint32_t messagePortIndex;
|
| - if (m_transferredMessagePorts.tryGet(value.As<v8::Object>(), &messagePortIndex)) {
|
| - m_writer.writeTransferredMessagePort(messagePortIndex);
|
| - } else {
|
| - return handleError(DataCloneError, "A MessagePort could not be cloned.", next);
|
| - }
|
| - } else if (V8ArrayBuffer::hasInstance(value, isolate()) && m_transferredArrayBuffers.tryGet(value.As<v8::Object>(), &arrayBufferIndex)) {
|
| - return writeTransferredArrayBuffer(value, arrayBufferIndex, next);
|
| - } else {
|
| - v8::Handle<v8::Object> jsObject = value.As<v8::Object>();
|
| - if (jsObject.IsEmpty())
|
| - return handleError(DataCloneError, "An object could not be cloned.", next);
|
| - greyObject(jsObject);
|
| - if (value->IsDate()) {
|
| - m_writer.writeDate(value->NumberValue());
|
| - } else if (value->IsStringObject()) {
|
| - writeStringObject(value);
|
| - } else if (value->IsNumberObject()) {
|
| - writeNumberObject(value);
|
| - } else if (value->IsBooleanObject()) {
|
| - writeBooleanObject(value);
|
| - } else if (value->IsArray()) {
|
| - return startArrayState(value.As<v8::Array>(), next);
|
| - } else if (V8File::hasInstance(value, isolate())) {
|
| - return writeFile(value, next);
|
| - } else if (V8Blob::hasInstance(value, isolate())) {
|
| - return writeBlob(value, next);
|
| - } else if (V8DOMFileSystem::hasInstance(value, isolate())) {
|
| - return writeDOMFileSystem(value, next);
|
| - } else if (V8FileList::hasInstance(value, isolate())) {
|
| - return writeFileList(value, next);
|
| - } else if (V8CryptoKey::hasInstance(value, isolate())) {
|
| - if (!writeCryptoKey(value))
|
| - return handleError(DataCloneError, "Couldn't serialize key data", next);
|
| - } else if (V8ImageData::hasInstance(value, isolate())) {
|
| - writeImageData(value);
|
| - } else if (value->IsRegExp()) {
|
| - writeRegExp(value);
|
| - } else if (V8ArrayBuffer::hasInstance(value, isolate())) {
|
| - return writeArrayBuffer(value, next);
|
| - } else if (value->IsObject()) {
|
| - if (isHostObject(jsObject) || jsObject->IsCallable() || value->IsNativeError())
|
| - return handleError(DataCloneError, "An object could not be cloned.", next);
|
| - return startObjectState(jsObject, next);
|
| - } else {
|
| - return handleError(DataCloneError, "A value could not be cloned.", next);
|
| - }
|
| - }
|
| - return 0;
|
| -}
|
| -
|
| -// Interface used by Reader to create objects of composite types.
|
| -class CompositeCreator {
|
| - STACK_ALLOCATED();
|
| -public:
|
| - virtual ~CompositeCreator() { }
|
| -
|
| - virtual bool consumeTopOfStack(v8::Handle<v8::Value>*) = 0;
|
| - virtual uint32_t objectReferenceCount() = 0;
|
| - virtual void pushObjectReference(const v8::Handle<v8::Value>&) = 0;
|
| - virtual bool tryGetObjectFromObjectReference(uint32_t reference, v8::Handle<v8::Value>*) = 0;
|
| - virtual bool tryGetTransferredMessagePort(uint32_t index, v8::Handle<v8::Value>*) = 0;
|
| - virtual bool tryGetTransferredArrayBuffer(uint32_t index, v8::Handle<v8::Value>*) = 0;
|
| - virtual bool newSparseArray(uint32_t length) = 0;
|
| - virtual bool newDenseArray(uint32_t length) = 0;
|
| - virtual bool newObject() = 0;
|
| - virtual bool completeObject(uint32_t numProperties, v8::Handle<v8::Value>*) = 0;
|
| - virtual bool completeSparseArray(uint32_t numProperties, uint32_t length, v8::Handle<v8::Value>*) = 0;
|
| - virtual bool completeDenseArray(uint32_t numProperties, uint32_t length, v8::Handle<v8::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, const WebBlobInfoArray* blobInfo, BlobDataHandleMap& blobDataHandles, ScriptState* scriptState)
|
| - : m_scriptState(scriptState)
|
| - , m_buffer(buffer)
|
| - , m_length(length)
|
| - , m_position(0)
|
| - , m_version(0)
|
| - , m_blobInfo(blobInfo)
|
| - , m_blobDataHandles(blobDataHandles)
|
| - {
|
| - ASSERT(!(reinterpret_cast<size_t>(buffer) & 1));
|
| - ASSERT(length >= 0);
|
| - }
|
| -
|
| - bool isEof() const { return m_position >= m_length; }
|
| -
|
| - ScriptState* scriptState() const { return m_scriptState.get(); }
|
| -
|
| -private:
|
| - v8::Isolate* isolate() const { return m_scriptState->isolate(); }
|
| -
|
| -public:
|
| - bool read(v8::Handle<v8::Value>* value, CompositeCreator& creator)
|
| - {
|
| - SerializationTag tag;
|
| - if (!readTag(&tag))
|
| - return false;
|
| - switch (tag) {
|
| - case ReferenceCountTag: {
|
| - if (!m_version)
|
| - return false;
|
| - uint32_t referenceTableSize;
|
| - if (!doReadUint32(&referenceTableSize))
|
| - return false;
|
| - // If this test fails, then the serializer and deserializer disagree about the assignment
|
| - // of object reference IDs. On the deserialization side, this means there are too many or too few
|
| - // calls to pushObjectReference.
|
| - if (referenceTableSize != creator.objectReferenceCount())
|
| - return false;
|
| - return true;
|
| - }
|
| - case InvalidTag:
|
| - return false;
|
| - case PaddingTag:
|
| - return true;
|
| - case UndefinedTag:
|
| - *value = v8::Undefined(isolate());
|
| - break;
|
| - case NullTag:
|
| - *value = v8::Null(isolate());
|
| - break;
|
| - case TrueTag:
|
| - *value = v8Boolean(true, isolate());
|
| - break;
|
| - case FalseTag:
|
| - *value = v8Boolean(false, isolate());
|
| - break;
|
| - case TrueObjectTag:
|
| - *value = v8::BooleanObject::New(true);
|
| - creator.pushObjectReference(*value);
|
| - break;
|
| - case FalseObjectTag:
|
| - *value = v8::BooleanObject::New(false);
|
| - creator.pushObjectReference(*value);
|
| - break;
|
| - case StringTag:
|
| - if (!readString(value))
|
| - return false;
|
| - break;
|
| - case StringUCharTag:
|
| - if (!readUCharString(value))
|
| - return false;
|
| - break;
|
| - case StringObjectTag:
|
| - if (!readStringObject(value))
|
| - return false;
|
| - creator.pushObjectReference(*value);
|
| - break;
|
| - case Int32Tag:
|
| - if (!readInt32(value))
|
| - return false;
|
| - break;
|
| - case Uint32Tag:
|
| - if (!readUint32(value))
|
| - return false;
|
| - break;
|
| - case DateTag:
|
| - if (!readDate(value))
|
| - return false;
|
| - creator.pushObjectReference(*value);
|
| - break;
|
| - case NumberTag:
|
| - if (!readNumber(value))
|
| - return false;
|
| - break;
|
| - case NumberObjectTag:
|
| - if (!readNumberObject(value))
|
| - return false;
|
| - creator.pushObjectReference(*value);
|
| - break;
|
| - case BlobTag:
|
| - case BlobIndexTag:
|
| - if (!readBlob(value, tag == BlobIndexTag))
|
| - return false;
|
| - creator.pushObjectReference(*value);
|
| - break;
|
| - case FileTag:
|
| - case FileIndexTag:
|
| - if (!readFile(value, tag == FileIndexTag))
|
| - return false;
|
| - creator.pushObjectReference(*value);
|
| - break;
|
| - case DOMFileSystemTag:
|
| - if (!readDOMFileSystem(value))
|
| - return false;
|
| - creator.pushObjectReference(*value);
|
| - break;
|
| - case FileListTag:
|
| - case FileListIndexTag:
|
| - if (!readFileList(value, tag == FileListIndexTag))
|
| - return false;
|
| - creator.pushObjectReference(*value);
|
| - break;
|
| - case CryptoKeyTag:
|
| - if (!readCryptoKey(value))
|
| - return false;
|
| - creator.pushObjectReference(*value);
|
| - break;
|
| - case ImageDataTag:
|
| - if (!readImageData(value))
|
| - return false;
|
| - creator.pushObjectReference(*value);
|
| - break;
|
| -
|
| - case RegExpTag:
|
| - if (!readRegExp(value))
|
| - return false;
|
| - creator.pushObjectReference(*value);
|
| - break;
|
| - case ObjectTag: {
|
| - uint32_t numProperties;
|
| - if (!doReadUint32(&numProperties))
|
| - return false;
|
| - if (!creator.completeObject(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.completeSparseArray(numProperties, length, value))
|
| - return false;
|
| - break;
|
| - }
|
| - case DenseArrayTag: {
|
| - uint32_t numProperties;
|
| - uint32_t length;
|
| - if (!doReadUint32(&numProperties))
|
| - return false;
|
| - if (!doReadUint32(&length))
|
| - return false;
|
| - if (!creator.completeDenseArray(numProperties, length, value))
|
| - return false;
|
| - break;
|
| - }
|
| - case ArrayBufferViewTag: {
|
| - if (!m_version)
|
| - return false;
|
| - if (!readArrayBufferView(value, creator))
|
| - return false;
|
| - creator.pushObjectReference(*value);
|
| - break;
|
| - }
|
| - case ArrayBufferTag: {
|
| - if (!m_version)
|
| - return false;
|
| - if (!readArrayBuffer(value))
|
| - return false;
|
| - creator.pushObjectReference(*value);
|
| - break;
|
| - }
|
| - case GenerateFreshObjectTag: {
|
| - if (!m_version)
|
| - return false;
|
| - if (!creator.newObject())
|
| - return false;
|
| - return true;
|
| - }
|
| - case GenerateFreshSparseArrayTag: {
|
| - if (!m_version)
|
| - return false;
|
| - uint32_t length;
|
| - if (!doReadUint32(&length))
|
| - return false;
|
| - if (!creator.newSparseArray(length))
|
| - return false;
|
| - return true;
|
| - }
|
| - case GenerateFreshDenseArrayTag: {
|
| - if (!m_version)
|
| - return false;
|
| - uint32_t length;
|
| - if (!doReadUint32(&length))
|
| - return false;
|
| - if (!creator.newDenseArray(length))
|
| - return false;
|
| - return true;
|
| - }
|
| - case MessagePortTag: {
|
| - if (!m_version)
|
| - return false;
|
| - uint32_t index;
|
| - if (!doReadUint32(&index))
|
| - return false;
|
| - if (!creator.tryGetTransferredMessagePort(index, value))
|
| - return false;
|
| - break;
|
| - }
|
| - case ArrayBufferTransferTag: {
|
| - if (!m_version)
|
| - return false;
|
| - uint32_t index;
|
| - if (!doReadUint32(&index))
|
| - return false;
|
| - if (!creator.tryGetTransferredArrayBuffer(index, value))
|
| - return false;
|
| - break;
|
| - }
|
| - case ObjectReferenceTag: {
|
| - if (!m_version)
|
| - return false;
|
| - uint32_t reference;
|
| - if (!doReadUint32(&reference))
|
| - return false;
|
| - if (!creator.tryGetObjectFromObjectReference(reference, value))
|
| - return false;
|
| - break;
|
| - }
|
| - default:
|
| - return false;
|
| - }
|
| - return !value->IsEmpty();
|
| - }
|
| -
|
| - bool readVersion(uint32_t& version)
|
| - {
|
| - SerializationTag tag;
|
| - if (!readTag(&tag)) {
|
| - // This is a nullary buffer. We're still version 0.
|
| - version = 0;
|
| - return true;
|
| - }
|
| - if (tag != VersionTag) {
|
| - // Versions of the format past 0 start with the version tag.
|
| - version = 0;
|
| - // Put back the tag.
|
| - undoReadTag();
|
| - return true;
|
| - }
|
| - // Version-bearing messages are obligated to finish the version tag.
|
| - return doReadUint32(&version);
|
| - }
|
| -
|
| - void setVersion(uint32_t version)
|
| - {
|
| - m_version = version;
|
| - }
|
| -
|
| -private:
|
| - bool readTag(SerializationTag* tag)
|
| - {
|
| - if (m_position >= m_length)
|
| - return false;
|
| - *tag = static_cast<SerializationTag>(m_buffer[m_position++]);
|
| - return true;
|
| - }
|
| -
|
| - void undoReadTag()
|
| - {
|
| - if (m_position > 0)
|
| - --m_position;
|
| - }
|
| -
|
| - bool readArrayBufferViewSubTag(ArrayBufferViewSubTag* tag)
|
| - {
|
| - if (m_position >= m_length)
|
| - return false;
|
| - *tag = static_cast<ArrayBufferViewSubTag>(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::NewFromUtf8(isolate(), reinterpret_cast<const char*>(m_buffer + m_position), v8::String::kNormalString, length);
|
| - m_position += length;
|
| - return true;
|
| - }
|
| -
|
| - bool readUCharString(v8::Handle<v8::Value>* value)
|
| - {
|
| - uint32_t length;
|
| - if (!doReadUint32(&length) || (length & 1))
|
| - return false;
|
| - if (m_position + length > m_length)
|
| - return false;
|
| - ASSERT(!(m_position & 1));
|
| - *value = v8::String::NewFromTwoByte(isolate(), reinterpret_cast<const uint16_t*>(m_buffer + m_position), v8::String::kNormalString, length / sizeof(UChar));
|
| - m_position += length;
|
| - return true;
|
| - }
|
| -
|
| - bool readStringObject(v8::Handle<v8::Value>* value)
|
| - {
|
| - v8::Handle<v8::Value> stringValue;
|
| - if (!readString(&stringValue) || !stringValue->IsString())
|
| - return false;
|
| - *value = v8::StringObject::New(stringValue.As<v8::String>());
|
| - 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(isolate(), 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::NewFromUnsigned(isolate(), rawValue);
|
| - return true;
|
| - }
|
| -
|
| - bool readDate(v8::Handle<v8::Value>* value)
|
| - {
|
| - double numberValue;
|
| - if (!doReadNumber(&numberValue))
|
| - return false;
|
| - *value = v8DateOrNaN(numberValue, isolate());
|
| - return true;
|
| - }
|
| -
|
| - bool readNumber(v8::Handle<v8::Value>* value)
|
| - {
|
| - double number;
|
| - if (!doReadNumber(&number))
|
| - return false;
|
| - *value = v8::Number::New(isolate(), number);
|
| - return true;
|
| - }
|
| -
|
| - bool readNumberObject(v8::Handle<v8::Value>* value)
|
| - {
|
| - double number;
|
| - if (!doReadNumber(&number))
|
| - return false;
|
| - *value = v8::NumberObject::New(isolate(), 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;
|
| - RefPtrWillBeRawPtr<ImageData> imageData = ImageData::create(IntSize(width, height));
|
| - Uint8ClampedArray* pixelArray = imageData->data();
|
| - ASSERT(pixelArray);
|
| - ASSERT(pixelArray->length() >= pixelDataLength);
|
| - memcpy(pixelArray->data(), m_buffer + m_position, pixelDataLength);
|
| - m_position += pixelDataLength;
|
| - *value = toV8(imageData.release(), m_scriptState->context()->Global(), isolate());
|
| - return true;
|
| - }
|
| -
|
| - PassRefPtr<ArrayBuffer> doReadArrayBuffer()
|
| - {
|
| - uint32_t byteLength;
|
| - if (!doReadUint32(&byteLength))
|
| - return nullptr;
|
| - if (m_position + byteLength > m_length)
|
| - return nullptr;
|
| - const void* bufferStart = m_buffer + m_position;
|
| - m_position += byteLength;
|
| - return ArrayBuffer::create(bufferStart, byteLength);
|
| - }
|
| -
|
| - bool readArrayBuffer(v8::Handle<v8::Value>* value)
|
| - {
|
| - RefPtr<ArrayBuffer> arrayBuffer = doReadArrayBuffer();
|
| - if (!arrayBuffer)
|
| - return false;
|
| - *value = toV8(DOMArrayBuffer::create(arrayBuffer.release()), m_scriptState->context()->Global(), isolate());
|
| - return true;
|
| - }
|
| -
|
| - bool readArrayBufferView(v8::Handle<v8::Value>* value, CompositeCreator& creator)
|
| - {
|
| - ArrayBufferViewSubTag subTag;
|
| - uint32_t byteOffset;
|
| - uint32_t byteLength;
|
| - RefPtr<DOMArrayBuffer> arrayBuffer;
|
| - v8::Handle<v8::Value> arrayBufferV8Value;
|
| - if (!readArrayBufferViewSubTag(&subTag))
|
| - return false;
|
| - if (!doReadUint32(&byteOffset))
|
| - return false;
|
| - if (!doReadUint32(&byteLength))
|
| - return false;
|
| - if (!creator.consumeTopOfStack(&arrayBufferV8Value))
|
| - return false;
|
| - if (arrayBufferV8Value.IsEmpty())
|
| - return false;
|
| - arrayBuffer = V8ArrayBuffer::toImpl(arrayBufferV8Value.As<v8::Object>());
|
| - if (!arrayBuffer)
|
| - return false;
|
| -
|
| - v8::Handle<v8::Object> creationContext = m_scriptState->context()->Global();
|
| - switch (subTag) {
|
| - case ByteArrayTag:
|
| - *value = toV8(DOMInt8Array::create(arrayBuffer.release(), byteOffset, byteLength), creationContext, isolate());
|
| - break;
|
| - case UnsignedByteArrayTag:
|
| - *value = toV8(DOMUint8Array::create(arrayBuffer.release(), byteOffset, byteLength), creationContext, isolate());
|
| - break;
|
| - case UnsignedByteClampedArrayTag:
|
| - *value = toV8(DOMUint8ClampedArray::create(arrayBuffer.release(), byteOffset, byteLength), creationContext, isolate());
|
| - break;
|
| - case ShortArrayTag: {
|
| - uint32_t shortLength = byteLength / sizeof(int16_t);
|
| - if (shortLength * sizeof(int16_t) != byteLength)
|
| - return false;
|
| - *value = toV8(DOMInt16Array::create(arrayBuffer.release(), byteOffset, shortLength), creationContext, isolate());
|
| - break;
|
| - }
|
| - case UnsignedShortArrayTag: {
|
| - uint32_t shortLength = byteLength / sizeof(uint16_t);
|
| - if (shortLength * sizeof(uint16_t) != byteLength)
|
| - return false;
|
| - *value = toV8(DOMUint16Array::create(arrayBuffer.release(), byteOffset, shortLength), creationContext, isolate());
|
| - break;
|
| - }
|
| - case IntArrayTag: {
|
| - uint32_t intLength = byteLength / sizeof(int32_t);
|
| - if (intLength * sizeof(int32_t) != byteLength)
|
| - return false;
|
| - *value = toV8(DOMInt32Array::create(arrayBuffer.release(), byteOffset, intLength), creationContext, isolate());
|
| - break;
|
| - }
|
| - case UnsignedIntArrayTag: {
|
| - uint32_t intLength = byteLength / sizeof(uint32_t);
|
| - if (intLength * sizeof(uint32_t) != byteLength)
|
| - return false;
|
| - *value = toV8(DOMUint32Array::create(arrayBuffer.release(), byteOffset, intLength), creationContext, isolate());
|
| - break;
|
| - }
|
| - case FloatArrayTag: {
|
| - uint32_t floatLength = byteLength / sizeof(float);
|
| - if (floatLength * sizeof(float) != byteLength)
|
| - return false;
|
| - *value = toV8(DOMFloat32Array::create(arrayBuffer.release(), byteOffset, floatLength), creationContext, isolate());
|
| - break;
|
| - }
|
| - case DoubleArrayTag: {
|
| - uint32_t floatLength = byteLength / sizeof(double);
|
| - if (floatLength * sizeof(double) != byteLength)
|
| - return false;
|
| - *value = toV8(DOMFloat64Array::create(arrayBuffer.release(), byteOffset, floatLength), creationContext, isolate());
|
| - break;
|
| - }
|
| - case DataViewTag:
|
| - *value = toV8(DOMDataView::create(arrayBuffer.release(), byteOffset, byteLength), creationContext, isolate());
|
| - break;
|
| - default:
|
| - return false;
|
| - }
|
| - // The various *Array::create() methods will return null if the range the view expects is
|
| - // mismatched with the range the buffer can provide or if the byte offset is not aligned
|
| - // to the size of the element type.
|
| - return !value->IsEmpty();
|
| - }
|
| -
|
| - bool readRegExp(v8::Handle<v8::Value>* value)
|
| - {
|
| - v8::Handle<v8::Value> pattern;
|
| - if (!readString(&pattern))
|
| - return false;
|
| - uint32_t flags;
|
| - if (!doReadUint32(&flags))
|
| - return false;
|
| - *value = v8::RegExp::New(pattern.As<v8::String>(), static_cast<v8::RegExp::Flags>(flags));
|
| - return true;
|
| - }
|
| -
|
| - bool readBlob(v8::Handle<v8::Value>* value, bool isIndexed)
|
| - {
|
| - if (m_version < 3)
|
| - return false;
|
| - Blob* blob = nullptr;
|
| - if (isIndexed) {
|
| - if (m_version < 6)
|
| - return false;
|
| - ASSERT(m_blobInfo);
|
| - uint32_t index;
|
| - if (!doReadUint32(&index) || index >= m_blobInfo->size())
|
| - return false;
|
| - const WebBlobInfo& info = (*m_blobInfo)[index];
|
| - blob = Blob::create(getOrCreateBlobDataHandle(info.uuid(), info.type(), info.size()));
|
| - } else {
|
| - ASSERT(!m_blobInfo);
|
| - String uuid;
|
| - String type;
|
| - uint64_t size;
|
| - ASSERT(!m_blobInfo);
|
| - if (!readWebCoreString(&uuid))
|
| - return false;
|
| - if (!readWebCoreString(&type))
|
| - return false;
|
| - if (!doReadUint64(&size))
|
| - return false;
|
| - blob = Blob::create(getOrCreateBlobDataHandle(uuid, type, size));
|
| - }
|
| - *value = toV8(blob, m_scriptState->context()->Global(), isolate());
|
| - return true;
|
| - }
|
| -
|
| - bool readDOMFileSystem(v8::Handle<v8::Value>* value)
|
| - {
|
| - uint32_t type;
|
| - String name;
|
| - String url;
|
| - if (!doReadUint32(&type))
|
| - return false;
|
| - if (!readWebCoreString(&name))
|
| - return false;
|
| - if (!readWebCoreString(&url))
|
| - return false;
|
| - DOMFileSystem* fs = DOMFileSystem::create(m_scriptState->executionContext(), name, static_cast<FileSystemType>(type), KURL(ParsedURLString, url));
|
| - *value = toV8(fs, m_scriptState->context()->Global(), isolate());
|
| - return true;
|
| - }
|
| -
|
| - bool readFile(v8::Handle<v8::Value>* value, bool isIndexed)
|
| - {
|
| - File* file = nullptr;
|
| - if (isIndexed) {
|
| - if (m_version < 6)
|
| - return false;
|
| - file = readFileIndexHelper();
|
| - } else {
|
| - file = readFileHelper();
|
| - }
|
| - if (!file)
|
| - return false;
|
| - *value = toV8(file, m_scriptState->context()->Global(), isolate());
|
| - return true;
|
| - }
|
| -
|
| - bool readFileList(v8::Handle<v8::Value>* value, bool isIndexed)
|
| - {
|
| - if (m_version < 3)
|
| - return false;
|
| - uint32_t length;
|
| - if (!doReadUint32(&length))
|
| - return false;
|
| - FileList* fileList = FileList::create();
|
| - for (unsigned i = 0; i < length; ++i) {
|
| - File* file = nullptr;
|
| - if (isIndexed) {
|
| - if (m_version < 6)
|
| - return false;
|
| - file = readFileIndexHelper();
|
| - } else {
|
| - file = readFileHelper();
|
| - }
|
| - if (!file)
|
| - return false;
|
| - fileList->append(file);
|
| - }
|
| - *value = toV8(fileList, m_scriptState->context()->Global(), isolate());
|
| - return true;
|
| - }
|
| -
|
| - bool readCryptoKey(v8::Handle<v8::Value>* value)
|
| - {
|
| - uint32_t rawKeyType;
|
| - if (!doReadUint32(&rawKeyType))
|
| - return false;
|
| -
|
| - WebCryptoKeyAlgorithm algorithm;
|
| - WebCryptoKeyType type = WebCryptoKeyTypeSecret;
|
| -
|
| - switch (static_cast<CryptoKeySubTag>(rawKeyType)) {
|
| - case AesKeyTag:
|
| - if (!doReadAesKey(algorithm, type))
|
| - return false;
|
| - break;
|
| - case HmacKeyTag:
|
| - if (!doReadHmacKey(algorithm, type))
|
| - return false;
|
| - break;
|
| - case RsaHashedKeyTag:
|
| - if (!doReadRsaHashedKey(algorithm, type))
|
| - return false;
|
| - break;
|
| - case EcKeyTag:
|
| - if (!doReadEcKey(algorithm, type))
|
| - return false;
|
| - break;
|
| - default:
|
| - return false;
|
| - }
|
| -
|
| - WebCryptoKeyUsageMask usages;
|
| - bool extractable;
|
| - if (!doReadKeyUsages(usages, extractable))
|
| - return false;
|
| -
|
| - uint32_t keyDataLength;
|
| - if (!doReadUint32(&keyDataLength))
|
| - return false;
|
| -
|
| - if (m_position + keyDataLength > m_length)
|
| - return false;
|
| -
|
| - const uint8_t* keyData = m_buffer + m_position;
|
| - m_position += keyDataLength;
|
| -
|
| - WebCryptoKey key = WebCryptoKey::createNull();
|
| - if (!Platform::current()->crypto()->deserializeKeyForClone(
|
| - algorithm, type, extractable, usages, keyData, keyDataLength, key)) {
|
| - return false;
|
| - }
|
| -
|
| - *value = toV8(CryptoKey::create(key), m_scriptState->context()->Global(), isolate());
|
| - return true;
|
| - }
|
| -
|
| - File* readFileHelper()
|
| - {
|
| - if (m_version < 3)
|
| - return nullptr;
|
| - ASSERT(!m_blobInfo);
|
| - String path;
|
| - String name;
|
| - String relativePath;
|
| - String uuid;
|
| - String type;
|
| - uint32_t hasSnapshot = 0;
|
| - uint64_t size = 0;
|
| - double lastModified = 0;
|
| - if (!readWebCoreString(&path))
|
| - return nullptr;
|
| - if (m_version >= 4 && !readWebCoreString(&name))
|
| - return nullptr;
|
| - if (m_version >= 4 && !readWebCoreString(&relativePath))
|
| - return nullptr;
|
| - if (!readWebCoreString(&uuid))
|
| - return nullptr;
|
| - if (!readWebCoreString(&type))
|
| - return nullptr;
|
| - if (m_version >= 4 && !doReadUint32(&hasSnapshot))
|
| - return nullptr;
|
| - if (hasSnapshot) {
|
| - if (!doReadUint64(&size))
|
| - return nullptr;
|
| - if (!doReadNumber(&lastModified))
|
| - return nullptr;
|
| - }
|
| - uint32_t isUserVisible = 1;
|
| - if (m_version >= 7 && !doReadUint32(&isUserVisible))
|
| - return nullptr;
|
| - const File::UserVisibility userVisibility = (isUserVisible > 0) ? File::IsUserVisible : File::IsNotUserVisible;
|
| - return File::createFromSerialization(path, name, relativePath, userVisibility, hasSnapshot > 0, size, lastModified, getOrCreateBlobDataHandle(uuid, type));
|
| - }
|
| -
|
| - File* readFileIndexHelper()
|
| - {
|
| - if (m_version < 3)
|
| - return nullptr;
|
| - ASSERT(m_blobInfo);
|
| - uint32_t index;
|
| - if (!doReadUint32(&index) || index >= m_blobInfo->size())
|
| - return nullptr;
|
| - const WebBlobInfo& info = (*m_blobInfo)[index];
|
| - return File::createFromIndexedSerialization(info.filePath(), info.fileName(), info.size(), info.lastModified(), getOrCreateBlobDataHandle(info.uuid(), info.type(), info.size()));
|
| - }
|
| -
|
| - template<class T>
|
| - bool doReadUintHelper(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 doReadUint32(uint32_t* value)
|
| - {
|
| - return doReadUintHelper(value);
|
| - }
|
| -
|
| - bool doReadUint64(uint64_t* value)
|
| - {
|
| - return doReadUintHelper(value);
|
| - }
|
| -
|
| - 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;
|
| - }
|
| -
|
| - PassRefPtr<BlobDataHandle> getOrCreateBlobDataHandle(const String& uuid, const String& type, long long size = -1)
|
| - {
|
| - // The containing ssv may have a BDH for this uuid if this ssv is just being
|
| - // passed from main to worker thread (for example). We use those values when creating
|
| - // the new blob instead of cons'ing up a new BDH.
|
| - //
|
| - // FIXME: Maybe we should require that it work that way where the ssv must have a BDH for any
|
| - // blobs it comes across during deserialization. Would require callers to explicitly populate
|
| - // the collection of BDH's for blobs to work, which would encourage lifetimes to be considered
|
| - // when passing ssv's around cross process. At present, we get 'lucky' in some cases because
|
| - // the blob in the src process happens to still exist at the time the dest process is deserializing.
|
| - // For example in sharedWorker.postMessage(...).
|
| - BlobDataHandleMap::const_iterator it = m_blobDataHandles.find(uuid);
|
| - if (it != m_blobDataHandles.end()) {
|
| - // make assertions about type and size?
|
| - return it->value;
|
| - }
|
| - return BlobDataHandle::create(uuid, type, size);
|
| - }
|
| -
|
| - bool doReadHmacKey(WebCryptoKeyAlgorithm& algorithm, WebCryptoKeyType& type)
|
| - {
|
| - uint32_t lengthBytes;
|
| - if (!doReadUint32(&lengthBytes))
|
| - return false;
|
| - WebCryptoAlgorithmId hash;
|
| - if (!doReadAlgorithmId(hash))
|
| - return false;
|
| - algorithm = WebCryptoKeyAlgorithm::createHmac(hash, lengthBytes * 8);
|
| - type = WebCryptoKeyTypeSecret;
|
| - return !algorithm.isNull();
|
| - }
|
| -
|
| - bool doReadAesKey(WebCryptoKeyAlgorithm& algorithm, WebCryptoKeyType& type)
|
| - {
|
| - WebCryptoAlgorithmId id;
|
| - if (!doReadAlgorithmId(id))
|
| - return false;
|
| - uint32_t lengthBytes;
|
| - if (!doReadUint32(&lengthBytes))
|
| - return false;
|
| - algorithm = WebCryptoKeyAlgorithm::createAes(id, lengthBytes * 8);
|
| - type = WebCryptoKeyTypeSecret;
|
| - return !algorithm.isNull();
|
| - }
|
| -
|
| - bool doReadRsaHashedKey(WebCryptoKeyAlgorithm& algorithm, WebCryptoKeyType& type)
|
| - {
|
| - WebCryptoAlgorithmId id;
|
| - if (!doReadAlgorithmId(id))
|
| - return false;
|
| -
|
| - if (!doReadAsymmetricKeyType(type))
|
| - return false;
|
| -
|
| - uint32_t modulusLengthBits;
|
| - if (!doReadUint32(&modulusLengthBits))
|
| - return false;
|
| -
|
| - uint32_t publicExponentSize;
|
| - if (!doReadUint32(&publicExponentSize))
|
| - return false;
|
| -
|
| - if (m_position + publicExponentSize > m_length)
|
| - return false;
|
| -
|
| - const uint8_t* publicExponent = m_buffer + m_position;
|
| - m_position += publicExponentSize;
|
| -
|
| - WebCryptoAlgorithmId hash;
|
| - if (!doReadAlgorithmId(hash))
|
| - return false;
|
| - algorithm = WebCryptoKeyAlgorithm::createRsaHashed(id, modulusLengthBits, publicExponent, publicExponentSize, hash);
|
| -
|
| - return !algorithm.isNull();
|
| - }
|
| -
|
| - bool doReadEcKey(WebCryptoKeyAlgorithm& algorithm, WebCryptoKeyType& type)
|
| - {
|
| - WebCryptoAlgorithmId id;
|
| - if (!doReadAlgorithmId(id))
|
| - return false;
|
| -
|
| - if (!doReadAsymmetricKeyType(type))
|
| - return false;
|
| -
|
| - WebCryptoNamedCurve namedCurve;
|
| - if (!doReadNamedCurve(namedCurve))
|
| - return false;
|
| -
|
| - algorithm = WebCryptoKeyAlgorithm::createEc(id, namedCurve);
|
| - return !algorithm.isNull();
|
| - }
|
| -
|
| - bool doReadAlgorithmId(WebCryptoAlgorithmId& id)
|
| - {
|
| - uint32_t rawId;
|
| - if (!doReadUint32(&rawId))
|
| - return false;
|
| -
|
| - switch (static_cast<CryptoKeyAlgorithmTag>(rawId)) {
|
| - case AesCbcTag:
|
| - id = WebCryptoAlgorithmIdAesCbc;
|
| - return true;
|
| - case HmacTag:
|
| - id = WebCryptoAlgorithmIdHmac;
|
| - return true;
|
| - case RsaSsaPkcs1v1_5Tag:
|
| - id = WebCryptoAlgorithmIdRsaSsaPkcs1v1_5;
|
| - return true;
|
| - case Sha1Tag:
|
| - id = WebCryptoAlgorithmIdSha1;
|
| - return true;
|
| - case Sha256Tag:
|
| - id = WebCryptoAlgorithmIdSha256;
|
| - return true;
|
| - case Sha384Tag:
|
| - id = WebCryptoAlgorithmIdSha384;
|
| - return true;
|
| - case Sha512Tag:
|
| - id = WebCryptoAlgorithmIdSha512;
|
| - return true;
|
| - case AesGcmTag:
|
| - id = WebCryptoAlgorithmIdAesGcm;
|
| - return true;
|
| - case RsaOaepTag:
|
| - id = WebCryptoAlgorithmIdRsaOaep;
|
| - return true;
|
| - case AesCtrTag:
|
| - id = WebCryptoAlgorithmIdAesCtr;
|
| - return true;
|
| - case AesKwTag:
|
| - id = WebCryptoAlgorithmIdAesKw;
|
| - return true;
|
| - case RsaPssTag:
|
| - id = WebCryptoAlgorithmIdRsaPss;
|
| - return true;
|
| - case EcdsaTag:
|
| - id = WebCryptoAlgorithmIdEcdsa;
|
| - return true;
|
| - }
|
| -
|
| - return false;
|
| - }
|
| -
|
| - bool doReadAsymmetricKeyType(WebCryptoKeyType& type)
|
| - {
|
| - uint32_t rawType;
|
| - if (!doReadUint32(&rawType))
|
| - return false;
|
| -
|
| - switch (static_cast<AssymetricCryptoKeyType>(rawType)) {
|
| - case PublicKeyType:
|
| - type = WebCryptoKeyTypePublic;
|
| - return true;
|
| - case PrivateKeyType:
|
| - type = WebCryptoKeyTypePrivate;
|
| - return true;
|
| - }
|
| -
|
| - return false;
|
| - }
|
| -
|
| - bool doReadNamedCurve(WebCryptoNamedCurve& namedCurve)
|
| - {
|
| - uint32_t rawName;
|
| - if (!doReadUint32(&rawName))
|
| - return false;
|
| -
|
| - switch (static_cast<NamedCurveTag>(rawName)) {
|
| - case P256Tag:
|
| - namedCurve = WebCryptoNamedCurveP256;
|
| - return true;
|
| - case P384Tag:
|
| - namedCurve = WebCryptoNamedCurveP384;
|
| - return true;
|
| - case P521Tag:
|
| - namedCurve = WebCryptoNamedCurveP521;
|
| - return true;
|
| - }
|
| -
|
| - return false;
|
| - }
|
| -
|
| - bool doReadKeyUsages(WebCryptoKeyUsageMask& usages, bool& extractable)
|
| - {
|
| - // Reminder to update this when adding new key usages.
|
| - COMPILE_ASSERT(EndOfWebCryptoKeyUsage == (1 << 7) + 1, UpdateMe);
|
| - const uint32_t allPossibleUsages = ExtractableUsage | EncryptUsage | DecryptUsage | SignUsage | VerifyUsage | DeriveKeyUsage | WrapKeyUsage | UnwrapKeyUsage | DeriveBitsUsage;
|
| -
|
| - uint32_t rawUsages;
|
| - if (!doReadUint32(&rawUsages))
|
| - return false;
|
| -
|
| - // Make sure it doesn't contain an unrecognized usage value.
|
| - if (rawUsages & ~allPossibleUsages)
|
| - return false;
|
| -
|
| - usages = 0;
|
| -
|
| - extractable = rawUsages & ExtractableUsage;
|
| -
|
| - if (rawUsages & EncryptUsage)
|
| - usages |= WebCryptoKeyUsageEncrypt;
|
| - if (rawUsages & DecryptUsage)
|
| - usages |= WebCryptoKeyUsageDecrypt;
|
| - if (rawUsages & SignUsage)
|
| - usages |= WebCryptoKeyUsageSign;
|
| - if (rawUsages & VerifyUsage)
|
| - usages |= WebCryptoKeyUsageVerify;
|
| - if (rawUsages & DeriveKeyUsage)
|
| - usages |= WebCryptoKeyUsageDeriveKey;
|
| - if (rawUsages & WrapKeyUsage)
|
| - usages |= WebCryptoKeyUsageWrapKey;
|
| - if (rawUsages & UnwrapKeyUsage)
|
| - usages |= WebCryptoKeyUsageUnwrapKey;
|
| - if (rawUsages & DeriveBitsUsage)
|
| - usages |= WebCryptoKeyUsageDeriveBits;
|
| -
|
| - return true;
|
| - }
|
| -
|
| - RefPtr<ScriptState> m_scriptState;
|
| - const uint8_t* m_buffer;
|
| - const unsigned m_length;
|
| - unsigned m_position;
|
| - uint32_t m_version;
|
| - const WebBlobInfoArray* m_blobInfo;
|
| - const BlobDataHandleMap& m_blobDataHandles;
|
| -};
|
| -
|
| -
|
| -typedef Vector<WTF::ArrayBufferContents, 1> ArrayBufferContentsArray;
|
| -
|
| -class Deserializer final : public CompositeCreator {
|
| -public:
|
| - Deserializer(Reader& reader, MessagePortArray* messagePorts, ArrayBufferContentsArray* arrayBufferContents)
|
| - : m_reader(reader)
|
| - , m_transferredMessagePorts(messagePorts)
|
| - , m_arrayBufferContents(arrayBufferContents)
|
| - , m_arrayBuffers(arrayBufferContents ? arrayBufferContents->size() : 0)
|
| - , m_version(0)
|
| - {
|
| - }
|
| -
|
| - v8::Handle<v8::Value> deserialize()
|
| - {
|
| - v8::Isolate* isolate = m_reader.scriptState()->isolate();
|
| - if (!m_reader.readVersion(m_version) || m_version > SerializedScriptValue::wireFormatVersion)
|
| - return v8::Null(isolate);
|
| - m_reader.setVersion(m_version);
|
| - v8::EscapableHandleScope scope(isolate);
|
| - while (!m_reader.isEof()) {
|
| - if (!doDeserialize())
|
| - return v8::Null(isolate);
|
| - }
|
| - if (stackDepth() != 1 || m_openCompositeReferenceStack.size())
|
| - return v8::Null(isolate);
|
| - v8::Handle<v8::Value> result = scope.Escape(element(0));
|
| - return result;
|
| - }
|
| -
|
| - virtual bool newSparseArray(uint32_t) override
|
| - {
|
| - v8::Local<v8::Array> array = v8::Array::New(m_reader.scriptState()->isolate(), 0);
|
| - openComposite(array);
|
| - return true;
|
| - }
|
| -
|
| - virtual bool newDenseArray(uint32_t length) override
|
| - {
|
| - v8::Local<v8::Array> array = v8::Array::New(m_reader.scriptState()->isolate(), length);
|
| - openComposite(array);
|
| - return true;
|
| - }
|
| -
|
| - virtual bool consumeTopOfStack(v8::Handle<v8::Value>* object) override
|
| - {
|
| - if (stackDepth() < 1)
|
| - return false;
|
| - *object = element(stackDepth() - 1);
|
| - pop(1);
|
| - return true;
|
| - }
|
| -
|
| - virtual bool newObject() override
|
| - {
|
| - v8::Local<v8::Object> object = v8::Object::New(m_reader.scriptState()->isolate());
|
| - if (object.IsEmpty())
|
| - return false;
|
| - openComposite(object);
|
| - return true;
|
| - }
|
| -
|
| - virtual bool completeObject(uint32_t numProperties, v8::Handle<v8::Value>* value) override
|
| - {
|
| - v8::Local<v8::Object> object;
|
| - if (m_version > 0) {
|
| - v8::Local<v8::Value> composite;
|
| - if (!closeComposite(&composite))
|
| - return false;
|
| - object = composite.As<v8::Object>();
|
| - } else {
|
| - object = v8::Object::New(m_reader.scriptState()->isolate());
|
| - }
|
| - if (object.IsEmpty())
|
| - return false;
|
| - return initializeObject(object, numProperties, value);
|
| - }
|
| -
|
| - virtual bool completeSparseArray(uint32_t numProperties, uint32_t length, v8::Handle<v8::Value>* value) override
|
| - {
|
| - v8::Local<v8::Array> array;
|
| - if (m_version > 0) {
|
| - v8::Local<v8::Value> composite;
|
| - if (!closeComposite(&composite))
|
| - return false;
|
| - array = composite.As<v8::Array>();
|
| - } else {
|
| - array = v8::Array::New(m_reader.scriptState()->isolate());
|
| - }
|
| - if (array.IsEmpty())
|
| - return false;
|
| - return initializeObject(array, numProperties, value);
|
| - }
|
| -
|
| - virtual bool completeDenseArray(uint32_t numProperties, uint32_t length, v8::Handle<v8::Value>* value) override
|
| - {
|
| - v8::Local<v8::Array> array;
|
| - if (m_version > 0) {
|
| - v8::Local<v8::Value> composite;
|
| - if (!closeComposite(&composite))
|
| - return false;
|
| - array = composite.As<v8::Array>();
|
| - }
|
| - if (array.IsEmpty())
|
| - return false;
|
| - if (!initializeObject(array, numProperties, value))
|
| - return false;
|
| - if (length > stackDepth())
|
| - return false;
|
| - for (unsigned i = 0, stackPos = stackDepth() - length; i < length; i++, stackPos++) {
|
| - v8::Local<v8::Value> elem = element(stackPos);
|
| - if (!elem->IsUndefined())
|
| - array->Set(i, elem);
|
| - }
|
| - pop(length);
|
| - return true;
|
| - }
|
| -
|
| - virtual void pushObjectReference(const v8::Handle<v8::Value>& object) override
|
| - {
|
| - m_objectPool.append(object);
|
| - }
|
| -
|
| - virtual bool tryGetTransferredMessagePort(uint32_t index, v8::Handle<v8::Value>* object) override
|
| - {
|
| - if (!m_transferredMessagePorts)
|
| - return false;
|
| - if (index >= m_transferredMessagePorts->size())
|
| - return false;
|
| - v8::Handle<v8::Object> creationContext = m_reader.scriptState()->context()->Global();
|
| - *object = toV8(m_transferredMessagePorts->at(index).get(), creationContext, m_reader.scriptState()->isolate());
|
| - return true;
|
| - }
|
| -
|
| - virtual bool tryGetTransferredArrayBuffer(uint32_t index, v8::Handle<v8::Value>* object) override
|
| - {
|
| - if (!m_arrayBufferContents)
|
| - return false;
|
| - if (index >= m_arrayBuffers.size())
|
| - return false;
|
| - v8::Handle<v8::Object> result = m_arrayBuffers.at(index);
|
| - if (result.IsEmpty()) {
|
| - RefPtr<DOMArrayBuffer> buffer = DOMArrayBuffer::create(m_arrayBufferContents->at(index));
|
| - v8::Isolate* isolate = m_reader.scriptState()->isolate();
|
| - v8::Handle<v8::Object> creationContext = m_reader.scriptState()->context()->Global();
|
| - result = toV8Object(buffer.get(), creationContext, isolate);
|
| - m_arrayBuffers[index] = result;
|
| - }
|
| - *object = result;
|
| - return true;
|
| - }
|
| -
|
| - virtual bool tryGetObjectFromObjectReference(uint32_t reference, v8::Handle<v8::Value>* object) override
|
| - {
|
| - if (reference >= m_objectPool.size())
|
| - return false;
|
| - *object = m_objectPool[reference];
|
| - return object;
|
| - }
|
| -
|
| - virtual uint32_t objectReferenceCount() override
|
| - {
|
| - return m_objectPool.size();
|
| - }
|
| -
|
| -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_WITH_SECURITY_IMPLICATION(index < m_stack.size());
|
| - return m_stack[index];
|
| - }
|
| -
|
| - void openComposite(const v8::Local<v8::Value>& object)
|
| - {
|
| - uint32_t newObjectReference = m_objectPool.size();
|
| - m_openCompositeReferenceStack.append(newObjectReference);
|
| - m_objectPool.append(object);
|
| - }
|
| -
|
| - bool closeComposite(v8::Handle<v8::Value>* object)
|
| - {
|
| - if (!m_openCompositeReferenceStack.size())
|
| - return false;
|
| - uint32_t objectReference = m_openCompositeReferenceStack[m_openCompositeReferenceStack.size() - 1];
|
| - m_openCompositeReferenceStack.shrink(m_openCompositeReferenceStack.size() - 1);
|
| - if (objectReference >= m_objectPool.size())
|
| - return false;
|
| - *object = m_objectPool[objectReference];
|
| - return true;
|
| - }
|
| -
|
| - Reader& m_reader;
|
| - Vector<v8::Local<v8::Value> > m_stack;
|
| - Vector<v8::Handle<v8::Value> > m_objectPool;
|
| - Vector<uint32_t> m_openCompositeReferenceStack;
|
| - RawPtrWillBeMember<MessagePortArray> m_transferredMessagePorts;
|
| - ArrayBufferContentsArray* m_arrayBufferContents;
|
| - Vector<v8::Handle<v8::Object> > m_arrayBuffers;
|
| - uint32_t m_version;
|
| -};
|
| -
|
| -} // namespace
|
| -
|
| PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(v8::Handle<v8::Value> value, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, ExceptionState& exceptionState, v8::Isolate* isolate)
|
| {
|
| return adoptRef(new SerializedScriptValue(value, messagePorts, arrayBuffers, 0, exceptionState, isolate));
|
| @@ -2933,7 +101,7 @@ PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const String& da
|
|
|
| PassRefPtr<SerializedScriptValue> SerializedScriptValue::create(const String& data, v8::Isolate* isolate)
|
| {
|
| - Writer writer;
|
| + SerializedScriptValueInternal::Writer writer;
|
| writer.writeWebCoreString(data);
|
| String wireData = writer.takeWireString();
|
| return adoptRef(new SerializedScriptValue(wireData));
|
| @@ -2946,7 +114,7 @@ PassRefPtr<SerializedScriptValue> SerializedScriptValue::create()
|
|
|
| PassRefPtr<SerializedScriptValue> SerializedScriptValue::nullValue()
|
| {
|
| - Writer writer;
|
| + SerializedScriptValueInternal::Writer writer;
|
| writer.writeNull();
|
| String wireData = writer.takeWireString();
|
| return adoptRef(new SerializedScriptValue(wireData));
|
| @@ -3031,14 +199,14 @@ PassOwnPtr<SerializedScriptValue::ArrayBufferContentsArray> SerializedScriptValu
|
| SerializedScriptValue::SerializedScriptValue(v8::Handle<v8::Value> value, MessagePortArray* messagePorts, ArrayBufferArray* arrayBuffers, WebBlobInfoArray* blobInfo, ExceptionState& exceptionState, v8::Isolate* isolate)
|
| : m_externallyAllocatedMemory(0)
|
| {
|
| - Writer writer;
|
| - Serializer::Status status;
|
| + SerializedScriptValueInternal::Writer writer;
|
| + SerializedScriptValueInternal::Serializer::Status status;
|
| String errorMessage;
|
| {
|
| v8::TryCatch tryCatch;
|
| - Serializer serializer(writer, messagePorts, arrayBuffers, blobInfo, m_blobDataHandles, tryCatch, ScriptState::current(isolate));
|
| + SerializedScriptValueInternal::Serializer serializer(writer, messagePorts, arrayBuffers, blobInfo, m_blobDataHandles, tryCatch, ScriptState::current(isolate));
|
| status = serializer.serialize(value);
|
| - if (status == Serializer::JSException) {
|
| + if (status == SerializedScriptValueInternal::Serializer::JSException) {
|
| // If there was a JS exception thrown, re-throw it.
|
| exceptionState.rethrowV8Exception(tryCatch.Exception());
|
| return;
|
| @@ -3046,17 +214,17 @@ SerializedScriptValue::SerializedScriptValue(v8::Handle<v8::Value> value, Messag
|
| errorMessage = serializer.errorMessage();
|
| }
|
| switch (status) {
|
| - case Serializer::InputError:
|
| - case Serializer::DataCloneError:
|
| + case SerializedScriptValueInternal::Serializer::InputError:
|
| + case SerializedScriptValueInternal::Serializer::DataCloneError:
|
| exceptionState.throwDOMException(DataCloneError, errorMessage);
|
| return;
|
| - case Serializer::Success:
|
| + case SerializedScriptValueInternal::Serializer::Success:
|
| m_data = writer.takeWireString();
|
| ASSERT(m_data.impl()->hasOneRef());
|
| if (arrayBuffers && arrayBuffers->size())
|
| m_arrayBufferContentsArray = transferArrayBuffers(isolate, *arrayBuffers, exceptionState);
|
| return;
|
| - case Serializer::JSException:
|
| + case SerializedScriptValueInternal::Serializer::JSException:
|
| ASSERT_NOT_REACHED();
|
| break;
|
| }
|
| @@ -3078,14 +246,14 @@ v8::Handle<v8::Value> SerializedScriptValue::deserialize(v8::Isolate* isolate, M
|
| {
|
| if (!m_data.impl())
|
| return v8::Null(isolate);
|
| - COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes);
|
| + COMPILE_ASSERT(sizeof(SerializedScriptValueInternal::Writer::BufferValueType) == 2, BufferValueTypeIsTwoBytes);
|
| m_data.ensure16Bit();
|
| // FIXME: SerializedScriptValue shouldn't use String for its underlying
|
| // storage. Instead, it should use SharedBuffer or Vector<uint8_t>. The
|
| // information stored in m_data isn't even encoded in UTF-16. Instead,
|
| // unicode characters are encoded as UTF-8 with two code units per UChar.
|
| - Reader reader(reinterpret_cast<const uint8_t*>(m_data.impl()->characters16()), 2 * m_data.length(), blobInfo, m_blobDataHandles, ScriptState::current(isolate));
|
| - Deserializer deserializer(reader, messagePorts, m_arrayBufferContentsArray.get());
|
| + SerializedScriptValueInternal::Reader reader(reinterpret_cast<const uint8_t*>(m_data.impl()->characters16()), 2 * m_data.length(), blobInfo, m_blobDataHandles, ScriptState::current(isolate));
|
| + SerializedScriptValueInternal::Deserializer deserializer(reader, messagePorts, m_arrayBufferContentsArray.get());
|
|
|
| // deserialize() can run arbitrary script (e.g., setters), which could result in |this| being destroyed.
|
| // Holding a RefPtr ensures we are alive (along with our internal data) throughout the operation.
|
|
|