Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(280)

Unified Diff: Source/bindings/core/v8/ScriptValueSerializer.cpp

Issue 721133002: bindings: preparation for fixing incorrect dependency of SerializedScriptValue. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: Patch for landing Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/bindings/core/v8/ScriptValueSerializer.h ('k') | Source/bindings/core/v8/SerializationTag.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/bindings/core/v8/ScriptValueSerializer.cpp
diff --git a/Source/bindings/core/v8/ScriptValueSerializer.cpp b/Source/bindings/core/v8/ScriptValueSerializer.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..38455c8c93d06ea54e9ab0d119fd143cc6da7331
--- /dev/null
+++ b/Source/bindings/core/v8/ScriptValueSerializer.cpp
@@ -0,0 +1,2338 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "bindings/core/v8/ScriptValueSerializer.h"
+
+#include "bindings/core/v8/V8ArrayBuffer.h"
+#include "bindings/core/v8/V8ArrayBufferView.h"
+#include "bindings/core/v8/V8Blob.h"
+#include "bindings/core/v8/V8File.h"
+#include "bindings/core/v8/V8FileList.h"
+#include "bindings/core/v8/V8ImageData.h"
+#include "bindings/core/v8/V8MessagePort.h"
+#include "bindings/modules/v8/V8CryptoKey.h"
+#include "bindings/modules/v8/V8DOMFileSystem.h"
+#include "core/dom/DOMDataView.h"
+#include "core/fileapi/Blob.h"
+#include "core/fileapi/File.h"
+#include "core/fileapi/FileList.h"
+#include "public/platform/Platform.h"
+#include "public/platform/WebBlobInfo.h"
+#include "wtf/ArrayBuffer.h"
+#include "wtf/ArrayBufferContents.h"
+#include "wtf/ArrayBufferView.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 SerializedScriptValueInternal {
+
+// 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
+
+// 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();
+};
+
+static const int maxDepth = 20000;
+
+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));
+}
+
+void Writer::writeUndefined()
+{
+ append(UndefinedTag);
+}
+
+void Writer::writeNull()
+{
+ append(NullTag);
+}
+
+void Writer::writeTrue()
+{
+ append(TrueTag);
+}
+
+void Writer::writeFalse()
+{
+ append(FalseTag);
+}
+
+void Writer::writeBooleanObject(bool value)
+{
+ append(value ? TrueObjectTag : FalseObjectTag);
+}
+
+void Writer::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 Writer::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 Writer::writeStringObject(const char* data, int length)
+{
+ ASSERT(length >= 0);
+ append(StringObjectTag);
+ doWriteString(data, length);
+}
+
+void Writer::writeWebCoreString(const String& string)
+{
+ // Uses UTF8 encoding so we can read it back as either V8 or
+ // WebCore string.
+ append(StringTag);
+ doWriteWebCoreString(string);
+}
+
+void Writer::writeVersion()
+{
+ append(VersionTag);
+ doWriteUint32(SerializedScriptValue::wireFormatVersion);
+}
+
+void Writer::writeInt32(int32_t value)
+{
+ append(Int32Tag);
+ doWriteUint32(ZigZag::encode(static_cast<uint32_t>(value)));
+}
+
+void Writer::writeUint32(uint32_t value)
+{
+ append(Uint32Tag);
+ doWriteUint32(value);
+}
+
+void Writer::writeDate(double numberValue)
+{
+ append(DateTag);
+ doWriteNumber(numberValue);
+}
+
+void Writer::writeNumber(double number)
+{
+ append(NumberTag);
+ doWriteNumber(number);
+}
+
+void Writer::writeNumberObject(double number)
+{
+ append(NumberObjectTag);
+ doWriteNumber(number);
+}
+
+void Writer::writeBlob(const String& uuid, const String& type, unsigned long long size)
+{
+ append(BlobTag);
+ doWriteWebCoreString(uuid);
+ doWriteWebCoreString(type);
+ doWriteUint64(size);
+}
+
+void Writer::writeDOMFileSystem(int type, const String& name, const String& url)
+{
+ append(DOMFileSystemTag);
+ doWriteUint32(type);
+ doWriteWebCoreString(name);
+ doWriteWebCoreString(url);
+}
+
+void Writer::writeBlobIndex(int blobIndex)
+{
+ ASSERT(blobIndex >= 0);
+ append(BlobIndexTag);
+ doWriteUint32(blobIndex);
+}
+
+void Writer::writeFile(const File& file)
+{
+ append(FileTag);
+ doWriteFile(file);
+}
+
+void Writer::writeFileIndex(int blobIndex)
+{
+ append(FileIndexTag);
+ doWriteUint32(blobIndex);
+}
+
+void Writer::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 Writer::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 Writer::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 Writer::writeArrayBuffer(const ArrayBuffer& arrayBuffer)
+{
+ append(ArrayBufferTag);
+ doWriteArrayBuffer(arrayBuffer);
+}
+
+void Writer::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 Writer::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 Writer::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 Writer::writeTransferredMessagePort(uint32_t index)
+{
+ append(MessagePortTag);
+ doWriteUint32(index);
+}
+
+void Writer::writeTransferredArrayBuffer(uint32_t index)
+{
+ append(ArrayBufferTransferTag);
+ doWriteUint32(index);
+}
+
+void Writer::writeObjectReference(uint32_t reference)
+{
+ append(ObjectReferenceTag);
+ doWriteUint32(reference);
+}
+
+void Writer::writeObject(uint32_t numProperties)
+{
+ append(ObjectTag);
+ doWriteUint32(numProperties);
+}
+
+void Writer::writeSparseArray(uint32_t numProperties, uint32_t length)
+{
+ append(SparseArrayTag);
+ doWriteUint32(numProperties);
+ doWriteUint32(length);
+}
+
+void Writer::writeDenseArray(uint32_t numProperties, uint32_t length)
+{
+ append(DenseArrayTag);
+ doWriteUint32(numProperties);
+ doWriteUint32(length);
+}
+
+String Writer::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 Writer::writeReferenceCount(uint32_t numberOfReferences)
+{
+ append(ReferenceCountTag);
+ doWriteUint32(numberOfReferences);
+}
+
+void Writer::writeGenerateFreshObject()
+{
+ append(GenerateFreshObjectTag);
+}
+
+void Writer::writeGenerateFreshSparseArray(uint32_t length)
+{
+ append(GenerateFreshSparseArrayTag);
+ doWriteUint32(length);
+}
+
+void Writer::writeGenerateFreshDenseArray(uint32_t length)
+{
+ append(GenerateFreshDenseArrayTag);
+ doWriteUint32(length);
+}
+
+void Writer::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 Writer::doWriteArrayBuffer(const ArrayBuffer& arrayBuffer)
+{
+ uint32_t byteLength = arrayBuffer.byteLength();
+ doWriteUint32(byteLength);
+ append(static_cast<const uint8_t*>(arrayBuffer.data()), byteLength);
+}
+
+void Writer::doWriteString(const char* data, int length)
+{
+ doWriteUint32(static_cast<uint32_t>(length));
+ append(reinterpret_cast<const uint8_t*>(data), length);
+}
+
+void Writer::doWriteWebCoreString(const String& string)
+{
+ StringUTF8Adaptor stringUTF8(string);
+ doWriteString(stringUTF8.data(), stringUTF8.length());
+}
+
+void Writer::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 Writer::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 Writer::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 Writer::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 Writer::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 Writer::doWriteAsymmetricKeyType(WebCryptoKeyType keyType)
+{
+ switch (keyType) {
+ case WebCryptoKeyTypePublic:
+ doWriteUint32(PublicKeyType);
+ break;
+ case WebCryptoKeyTypePrivate:
+ doWriteUint32(PrivateKeyType);
+ break;
+ case WebCryptoKeyTypeSecret:
+ ASSERT_NOT_REACHED();
+ }
+}
+
+void Writer::doWriteNamedCurve(WebCryptoNamedCurve namedCurve)
+{
+ switch (namedCurve) {
+ case WebCryptoNamedCurveP256:
+ return doWriteUint32(P256Tag);
+ case WebCryptoNamedCurveP384:
+ return doWriteUint32(P384Tag);
+ case WebCryptoNamedCurveP521:
+ return doWriteUint32(P521Tag);
+ }
+ ASSERT_NOT_REACHED();
+}
+
+void Writer::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 Writer::bytesNeededToWireEncode(uint32_t value)
+{
+ int bytes = 1;
+ while (true) {
+ value >>= SerializedScriptValue::varIntShift;
+ if (!value)
+ break;
+ ++bytes;
+ }
+
+ return bytes;
+}
+
+void Writer::doWriteUint32(uint32_t value)
+{
+ doWriteUintHelper(value);
+}
+
+void Writer::doWriteUint64(uint64_t value)
+{
+ doWriteUintHelper(value);
+}
+
+void Writer::doWriteNumber(double number)
+{
+ append(reinterpret_cast<uint8_t*>(&number), sizeof(number));
+}
+
+void Writer::append(SerializationTag tag)
+{
+ append(static_cast<uint8_t>(tag));
+}
+
+void Writer::append(uint8_t b)
+{
+ ensureSpace(1);
+ *byteAt(m_position++) = b;
+}
+
+void Writer::append(const uint8_t* data, int length)
+{
+ ensureSpace(length);
+ memcpy(byteAt(m_position), data, length);
+ m_position += length;
+}
+
+void Writer::ensureSpace(unsigned extra)
+{
+ COMPILE_ASSERT(sizeof(BufferValueType) == 2, BufferValueTypeIsTwoBytes);
+ m_buffer.resize((m_position + extra + 1) / sizeof(BufferValueType)); // "+ 1" to round up.
+}
+
+void Writer::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* Writer::byteAt(int position)
+{
+ return reinterpret_cast<uint8_t*>(m_buffer.data()) + position;
+}
+
+int Writer::v8StringWriteOptions()
+{
+ return v8::String::NO_NULL_TERMINATION;
+}
+
+Serializer::StateBase* Serializer::AbstractObjectState::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);
+}
+
+Serializer::StateBase* Serializer::ObjectState::advance(Serializer& serializer)
+{
+ 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);
+}
+
+Serializer::StateBase* Serializer::ObjectState::objectDone(unsigned numProperties, Serializer& serializer)
+{
+ return serializer.writeObject(numProperties, this);
+}
+
+Serializer::StateBase* Serializer::DenseArrayState::advance(Serializer& serializer)
+{
+ 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);
+}
+
+Serializer::StateBase* Serializer::DenseArrayState::objectDone(unsigned numProperties, Serializer& serializer)
+{
+ return serializer.writeDenseArray(numProperties, m_arrayLength, this);
+}
+
+Serializer::StateBase* Serializer::SparseArrayState::advance(Serializer& serializer)
+{
+ return serializeProperties(false, serializer);
+}
+
+Serializer::StateBase* Serializer::SparseArrayState::objectDone(unsigned numProperties, Serializer& serializer)
+{
+ return serializer.writeSparseArray(numProperties, composite().As<v8::Array>()->Length(), this);
+}
+
+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>();
+}
+
+// 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::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);
+ }
+ }
+}
+
+Serializer::Status Serializer::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;
+}
+
+Serializer::StateBase* Serializer::doSerialize(v8::Handle<v8::Value> value, Serializer::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;
+}
+
+Serializer::StateBase* Serializer::doSerializeArrayBuffer(v8::Handle<v8::Value> arrayBuffer, Serializer::StateBase* next)
+{
+ return doSerialize(arrayBuffer, next);
+}
+
+Serializer::StateBase* Serializer::checkException(Serializer::StateBase* state)
+{
+ return m_tryCatch.HasCaught() ? handleError(JSException, "", state) : 0;
+}
+
+Serializer::StateBase* Serializer::writeObject(uint32_t numProperties, Serializer::StateBase* state)
+{
+ m_writer.writeObject(numProperties);
+ return pop(state);
+}
+
+Serializer::StateBase* Serializer::writeSparseArray(uint32_t numProperties, uint32_t length, Serializer::StateBase* state)
+{
+ m_writer.writeSparseArray(numProperties, length);
+ return pop(state);
+}
+
+Serializer::StateBase* Serializer::writeDenseArray(uint32_t numProperties, uint32_t length, Serializer::StateBase* state)
+{
+ m_writer.writeDenseArray(numProperties, length);
+ return pop(state);
+}
+
+Serializer::StateBase* Serializer::handleError(Serializer::Status errorStatus, const String& message, Serializer::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 Serializer::checkComposite(Serializer::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 Serializer::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 Serializer::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 Serializer::writeNumberObject(v8::Handle<v8::Value> value)
+{
+ v8::Handle<v8::NumberObject> numberObject = value.As<v8::NumberObject>();
+ m_writer.writeNumberObject(numberObject->ValueOf());
+}
+
+void Serializer::writeBooleanObject(v8::Handle<v8::Value> value)
+{
+ v8::Handle<v8::BooleanObject> booleanObject = value.As<v8::BooleanObject>();
+ m_writer.writeBooleanObject(booleanObject->ValueOf());
+}
+
+Serializer::StateBase* Serializer::writeBlob(v8::Handle<v8::Value> value, Serializer::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;
+}
+
+Serializer::StateBase* Serializer::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;
+}
+
+Serializer::StateBase* Serializer::writeFile(v8::Handle<v8::Value> value, Serializer::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;
+}
+
+Serializer::StateBase* Serializer::writeFileList(v8::Handle<v8::Value> value, Serializer::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 Serializer::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 Serializer::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 Serializer::writeRegExp(v8::Handle<v8::Value> value)
+{
+ v8::Handle<v8::RegExp> regExp = value.As<v8::RegExp>();
+ m_writer.writeRegExp(regExp->GetSource(), regExp->GetFlags());
+}
+
+Serializer::StateBase* Serializer::writeAndGreyArrayBufferView(v8::Handle<v8::Object> object, Serializer::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;
+}
+
+Serializer::StateBase* Serializer::writeArrayBuffer(v8::Handle<v8::Value> value, Serializer::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;
+}
+
+Serializer::StateBase* Serializer::writeTransferredArrayBuffer(v8::Handle<v8::Value> value, uint32_t index, Serializer::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;
+}
+
+bool Serializer::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;
+}
+
+Serializer::StateBase* Serializer::startArrayState(v8::Handle<v8::Array> array, Serializer::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()));
+}
+
+Serializer::StateBase* Serializer::startObjectState(v8::Handle<v8::Object> object, Serializer::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 Serializer::greyObject(const v8::Handle<v8::Object>& object)
+{
+ ASSERT(!m_objectPool.contains(object));
+ uint32_t objectReference = m_nextObjectReference++;
+ m_objectPool.set(object, objectReference);
+}
+
+bool Serializer::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 Serializer::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;
+}
+
+bool Reader::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 Reader::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 Reader::setVersion(uint32_t version)
+{
+ m_version = version;
+}
+
+bool Reader::readTag(SerializationTag* tag)
+{
+ if (m_position >= m_length)
+ return false;
+ *tag = static_cast<SerializationTag>(m_buffer[m_position++]);
+ return true;
+}
+
+void Reader::undoReadTag()
+{
+ if (m_position > 0)
+ --m_position;
+}
+
+bool Reader::readArrayBufferViewSubTag(ArrayBufferViewSubTag* tag)
+{
+ if (m_position >= m_length)
+ return false;
+ *tag = static_cast<ArrayBufferViewSubTag>(m_buffer[m_position++]);
+ return true;
+}
+
+bool Reader::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 Reader::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 Reader::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 Reader::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 Reader::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 Reader::readUint32(v8::Handle<v8::Value>* value)
+{
+ uint32_t rawValue;
+ if (!doReadUint32(&rawValue))
+ return false;
+ *value = v8::Integer::NewFromUnsigned(isolate(), rawValue);
+ return true;
+}
+
+bool Reader::readDate(v8::Handle<v8::Value>* value)
+{
+ double numberValue;
+ if (!doReadNumber(&numberValue))
+ return false;
+ *value = v8DateOrNaN(numberValue, isolate());
+ return true;
+}
+
+bool Reader::readNumber(v8::Handle<v8::Value>* value)
+{
+ double number;
+ if (!doReadNumber(&number))
+ return false;
+ *value = v8::Number::New(isolate(), number);
+ return true;
+}
+
+bool Reader::readNumberObject(v8::Handle<v8::Value>* value)
+{
+ double number;
+ if (!doReadNumber(&number))
+ return false;
+ *value = v8::NumberObject::New(isolate(), number);
+ return true;
+}
+
+bool Reader::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> Reader::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 Reader::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 Reader::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 Reader::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 Reader::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 Reader::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 Reader::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 Reader::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 Reader::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* Reader::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* Reader::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()));
+}
+
+bool Reader::doReadUint32(uint32_t* value)
+{
+ return doReadUintHelper(value);
+}
+
+bool Reader::doReadUint64(uint64_t* value)
+{
+ return doReadUintHelper(value);
+}
+
+bool Reader::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> Reader::getOrCreateBlobDataHandle(const String& uuid, const String& type, long long size)
+{
+ // 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 Reader::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 Reader::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 Reader::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 Reader::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 Reader::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 Reader::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 Reader::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 Reader::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;
+}
+
+v8::Handle<v8::Value> Deserializer::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;
+}
+
+bool Deserializer::newSparseArray(uint32_t)
+{
+ v8::Local<v8::Array> array = v8::Array::New(m_reader.scriptState()->isolate(), 0);
+ openComposite(array);
+ return true;
+}
+
+bool Deserializer::newDenseArray(uint32_t length)
+{
+ v8::Local<v8::Array> array = v8::Array::New(m_reader.scriptState()->isolate(), length);
+ openComposite(array);
+ return true;
+}
+
+bool Deserializer::consumeTopOfStack(v8::Handle<v8::Value>* object)
+{
+ if (stackDepth() < 1)
+ return false;
+ *object = element(stackDepth() - 1);
+ pop(1);
+ return true;
+}
+
+bool Deserializer::newObject()
+{
+ v8::Local<v8::Object> object = v8::Object::New(m_reader.scriptState()->isolate());
+ if (object.IsEmpty())
+ return false;
+ openComposite(object);
+ return true;
+}
+
+bool Deserializer::completeObject(uint32_t numProperties, v8::Handle<v8::Value>* value)
+{
+ 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);
+}
+
+bool Deserializer::completeSparseArray(uint32_t numProperties, uint32_t length, v8::Handle<v8::Value>* value)
+{
+ 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);
+}
+
+bool Deserializer::completeDenseArray(uint32_t numProperties, uint32_t length, v8::Handle<v8::Value>* value)
+{
+ 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;
+}
+
+void Deserializer::pushObjectReference(const v8::Handle<v8::Value>& object)
+{
+ m_objectPool.append(object);
+}
+
+bool Deserializer::tryGetTransferredMessagePort(uint32_t index, v8::Handle<v8::Value>* object)
+{
+ 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;
+}
+
+bool Deserializer::tryGetTransferredArrayBuffer(uint32_t index, v8::Handle<v8::Value>* object)
+{
+ 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;
+}
+
+bool Deserializer::tryGetObjectFromObjectReference(uint32_t reference, v8::Handle<v8::Value>* object)
+{
+ if (reference >= m_objectPool.size())
+ return false;
+ *object = m_objectPool[reference];
+ return object;
+}
+
+uint32_t Deserializer::objectReferenceCount()
+{
+ return m_objectPool.size();
+}
+
+bool Deserializer::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 Deserializer::read(v8::Local<v8::Value>* value)
+{
+ return m_reader.read(value, *this);
+}
+
+bool Deserializer::doDeserialize()
+{
+ v8::Local<v8::Value> value;
+ if (!read(&value))
+ return false;
+ if (!value.IsEmpty())
+ push(value);
+ return true;
+}
+
+v8::Local<v8::Value> Deserializer::element(unsigned index)
+{
+ ASSERT_WITH_SECURITY_IMPLICATION(index < m_stack.size());
+ return m_stack[index];
+}
+
+void Deserializer::openComposite(const v8::Local<v8::Value>& object)
+{
+ uint32_t newObjectReference = m_objectPool.size();
+ m_openCompositeReferenceStack.append(newObjectReference);
+ m_objectPool.append(object);
+}
+
+bool Deserializer::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;
+}
+
+} // SerializedScriptValueInternal
+
+} // namespace blink
« no previous file with comments | « Source/bindings/core/v8/ScriptValueSerializer.h ('k') | Source/bindings/core/v8/SerializationTag.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698