michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* vim: set sw=4 ts=8 et tw=80 : */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "StructuredCloneUtils.h" michael@0: michael@0: #include "nsIDOMFile.h" michael@0: #include "nsIDOMDOMException.h" michael@0: #include "nsIMutable.h" michael@0: #include "nsIXPConnect.h" michael@0: michael@0: #include "nsContentUtils.h" michael@0: #include "nsJSEnvironment.h" michael@0: #include "MainThreadUtils.h" michael@0: #include "StructuredCloneTags.h" michael@0: #include "jsapi.h" michael@0: michael@0: using namespace mozilla::dom; michael@0: michael@0: namespace { michael@0: michael@0: void michael@0: Error(JSContext* aCx, uint32_t aErrorId) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: NS_DOMStructuredCloneError(aCx, aErrorId); michael@0: } michael@0: michael@0: JSObject* michael@0: Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, michael@0: uint32_t aData, void* aClosure) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: MOZ_ASSERT(aClosure); michael@0: michael@0: StructuredCloneClosure* closure = michael@0: static_cast(aClosure); michael@0: michael@0: if (aTag == SCTAG_DOM_FILE) { michael@0: MOZ_ASSERT(aData < closure->mBlobs.Length()); michael@0: michael@0: nsCOMPtr file = do_QueryInterface(closure->mBlobs[aData]); michael@0: MOZ_ASSERT(file); michael@0: michael@0: #ifdef DEBUG michael@0: { michael@0: // File should not be mutable. michael@0: nsCOMPtr mutableFile = do_QueryInterface(file); michael@0: bool isMutable; michael@0: MOZ_ASSERT(NS_SUCCEEDED(mutableFile->GetMutable(&isMutable))); michael@0: MOZ_ASSERT(!isMutable); michael@0: } michael@0: #endif michael@0: michael@0: JS::Rooted wrappedFile(aCx); michael@0: nsresult rv = nsContentUtils::WrapNative(aCx, file, &NS_GET_IID(nsIDOMFile), michael@0: &wrappedFile); michael@0: if (NS_FAILED(rv)) { michael@0: Error(aCx, nsIDOMDOMException::DATA_CLONE_ERR); michael@0: return nullptr; michael@0: } michael@0: michael@0: return &wrappedFile.toObject(); michael@0: } michael@0: michael@0: if (aTag == SCTAG_DOM_BLOB) { michael@0: MOZ_ASSERT(aData < closure->mBlobs.Length()); michael@0: michael@0: nsCOMPtr blob = do_QueryInterface(closure->mBlobs[aData]); michael@0: MOZ_ASSERT(blob); michael@0: michael@0: #ifdef DEBUG michael@0: { michael@0: // Blob should not be mutable. michael@0: nsCOMPtr mutableBlob = do_QueryInterface(blob); michael@0: bool isMutable; michael@0: MOZ_ASSERT(NS_SUCCEEDED(mutableBlob->GetMutable(&isMutable))); michael@0: MOZ_ASSERT(!isMutable); michael@0: } michael@0: #endif michael@0: michael@0: JS::Rooted wrappedBlob(aCx); michael@0: nsresult rv = nsContentUtils::WrapNative(aCx, blob, &NS_GET_IID(nsIDOMBlob), michael@0: &wrappedBlob); michael@0: if (NS_FAILED(rv)) { michael@0: Error(aCx, nsIDOMDOMException::DATA_CLONE_ERR); michael@0: return nullptr; michael@0: } michael@0: michael@0: return &wrappedBlob.toObject(); michael@0: } michael@0: michael@0: return NS_DOMReadStructuredClone(aCx, aReader, aTag, aData, nullptr); michael@0: } michael@0: michael@0: bool michael@0: Write(JSContext* aCx, JSStructuredCloneWriter* aWriter, michael@0: JS::Handle aObj, void* aClosure) michael@0: { michael@0: MOZ_ASSERT(NS_IsMainThread()); michael@0: MOZ_ASSERT(aClosure); michael@0: michael@0: StructuredCloneClosure* closure = michael@0: static_cast(aClosure); michael@0: michael@0: // See if this is a wrapped native. michael@0: nsCOMPtr wrappedNative; michael@0: nsContentUtils::XPConnect()-> michael@0: GetWrappedNativeOfJSObject(aCx, aObj, getter_AddRefs(wrappedNative)); michael@0: michael@0: if (wrappedNative) { michael@0: // Get the raw nsISupports out of it. michael@0: nsISupports* wrappedObject = wrappedNative->Native(); michael@0: MOZ_ASSERT(wrappedObject); michael@0: michael@0: // See if the wrapped native is a nsIDOMFile. michael@0: nsCOMPtr file = do_QueryInterface(wrappedObject); michael@0: if (file) { michael@0: nsCOMPtr mutableFile = do_QueryInterface(file); michael@0: if (mutableFile && michael@0: NS_SUCCEEDED(mutableFile->SetMutable(false)) && michael@0: JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILE, michael@0: closure->mBlobs.Length())) { michael@0: closure->mBlobs.AppendElement(file); michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: // See if the wrapped native is a nsIDOMBlob. michael@0: nsCOMPtr blob = do_QueryInterface(wrappedObject); michael@0: if (blob) { michael@0: nsCOMPtr mutableBlob = do_QueryInterface(blob); michael@0: if (mutableBlob && michael@0: NS_SUCCEEDED(mutableBlob->SetMutable(false)) && michael@0: JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB, michael@0: closure->mBlobs.Length())) { michael@0: closure->mBlobs.AppendElement(blob); michael@0: return true; michael@0: } michael@0: } michael@0: } michael@0: michael@0: return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr); michael@0: } michael@0: michael@0: JSStructuredCloneCallbacks gCallbacks = { michael@0: Read, michael@0: Write, michael@0: Error, michael@0: nullptr, michael@0: nullptr, michael@0: nullptr michael@0: }; michael@0: michael@0: } // anonymous namespace michael@0: michael@0: namespace mozilla { michael@0: namespace dom { michael@0: michael@0: bool michael@0: ReadStructuredClone(JSContext* aCx, uint64_t* aData, size_t aDataLength, michael@0: const StructuredCloneClosure& aClosure, michael@0: JS::MutableHandle aClone) michael@0: { michael@0: void* closure = &const_cast(aClosure); michael@0: return !!JS_ReadStructuredClone(aCx, aData, aDataLength, michael@0: JS_STRUCTURED_CLONE_VERSION, aClone, michael@0: &gCallbacks, closure); michael@0: } michael@0: michael@0: bool michael@0: WriteStructuredClone(JSContext* aCx, JS::Handle aSource, michael@0: JSAutoStructuredCloneBuffer& aBuffer, michael@0: StructuredCloneClosure& aClosure) michael@0: { michael@0: return aBuffer.write(aCx, aSource, &gCallbacks, &aClosure); michael@0: } michael@0: michael@0: } // namespace dom michael@0: } // namespace mozilla