1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sw=2 et tw=80:
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "nsStructuredCloneContainer.h"
11 #include "nsIScriptContext.h"
12 #include "nsIVariant.h"
13 #include "nsIXPConnect.h"
14 #include "nsServiceManagerUtils.h"
15 #include "nsContentUtils.h"
17 #include "js/StructuredClone.h"
19 #include "mozilla/Base64.h"
21 using namespace mozilla
;
23 NS_IMPL_ADDREF(nsStructuredCloneContainer
)
24 NS_IMPL_RELEASE(nsStructuredCloneContainer
)
26 NS_INTERFACE_MAP_BEGIN(nsStructuredCloneContainer
)
27 NS_INTERFACE_MAP_ENTRY(nsIStructuredCloneContainer
)
28 NS_INTERFACE_MAP_ENTRY(nsISupports
)
31 nsStructuredCloneContainer::nsStructuredCloneContainer()
32 : mData(nullptr), mSize(0), mVersion(0)
36 nsStructuredCloneContainer::~nsStructuredCloneContainer()
42 nsStructuredCloneContainer::InitFromJSVal(JS::Handle
<JS::Value
> aData
,
45 NS_ENSURE_STATE(!mData
);
46 NS_ENSURE_ARG_POINTER(aCx
);
48 // Make sure that we serialize in the right context.
49 MOZ_ASSERT(aCx
== nsContentUtils::GetCurrentJSContext());
50 JS::Rooted
<JS::Value
> jsData(aCx
, aData
);
51 bool success
= JS_WrapValue(aCx
, &jsData
);
52 NS_ENSURE_STATE(success
);
54 uint64_t* jsBytes
= nullptr;
55 success
= JS_WriteStructuredClone(aCx
, jsData
, &jsBytes
, &mSize
,
57 JS::UndefinedHandleValue
);
58 NS_ENSURE_STATE(success
);
59 NS_ENSURE_STATE(jsBytes
);
61 // Copy jsBytes into our own buffer.
62 mData
= (uint64_t*) malloc(mSize
);
67 JS_ClearStructuredClone(jsBytes
, mSize
, nullptr, nullptr);
68 return NS_ERROR_FAILURE
;
71 mVersion
= JS_STRUCTURED_CLONE_VERSION
;
74 memcpy(mData
, jsBytes
, mSize
);
76 JS_ClearStructuredClone(jsBytes
, mSize
, nullptr, nullptr);
81 nsStructuredCloneContainer::InitFromBase64(const nsAString
&aData
,
82 uint32_t aFormatVersion
,
85 NS_ENSURE_STATE(!mData
);
87 NS_ConvertUTF16toUTF8
data(aData
);
89 nsAutoCString binaryData
;
90 nsresult rv
= Base64Decode(data
, binaryData
);
91 NS_ENSURE_SUCCESS(rv
, rv
);
93 // Copy the string's data into our own buffer.
94 mData
= (uint64_t*) malloc(binaryData
.Length());
95 NS_ENSURE_STATE(mData
);
96 memcpy(mData
, binaryData
.get(), binaryData
.Length());
98 mSize
= binaryData
.Length();
99 mVersion
= aFormatVersion
;
105 nsStructuredCloneContainer::DeserializeToVariant(JSContext
*aCx
,
108 NS_ENSURE_STATE(mData
);
109 NS_ENSURE_ARG_POINTER(aData
);
112 // Deserialize to a JS::Value.
113 JS::Rooted
<JS::Value
> jsStateObj(aCx
);
114 bool hasTransferable
= false;
115 bool success
= JS_ReadStructuredClone(aCx
, mData
, mSize
, mVersion
,
116 &jsStateObj
, nullptr, nullptr) &&
117 JS_StructuredCloneHasTransferables(mData
, mSize
,
119 // We want to be sure that mData doesn't contain transferable objects
120 MOZ_ASSERT(!hasTransferable
);
121 NS_ENSURE_STATE(success
&& !hasTransferable
);
123 // Now wrap the JS::Value as an nsIVariant.
124 nsCOMPtr
<nsIVariant
> varStateObj
;
125 nsCOMPtr
<nsIXPConnect
> xpconnect
= do_GetService(nsIXPConnect::GetCID());
126 NS_ENSURE_STATE(xpconnect
);
127 xpconnect
->JSValToVariant(aCx
, jsStateObj
, getter_AddRefs(varStateObj
));
128 NS_ENSURE_STATE(varStateObj
);
130 NS_ADDREF(*aData
= varStateObj
);
135 nsStructuredCloneContainer::GetDataAsBase64(nsAString
&aOut
)
137 NS_ENSURE_STATE(mData
);
140 nsAutoCString
binaryData(reinterpret_cast<char*>(mData
), mSize
);
141 nsAutoCString base64Data
;
142 nsresult rv
= Base64Encode(binaryData
, base64Data
);
143 NS_ENSURE_SUCCESS(rv
, rv
);
145 aOut
.Assign(NS_ConvertASCIItoUTF16(base64Data
));
150 nsStructuredCloneContainer::GetSerializedNBytes(uint64_t *aSize
)
152 NS_ENSURE_STATE(mData
);
153 NS_ENSURE_ARG_POINTER(aSize
);
155 // mSize is a size_t, while aSize is a uint64_t. We rely on an implicit cast
156 // here so that we'll get a compile error if a size_t-to-uint64_t cast is
164 nsStructuredCloneContainer::GetFormatVersion(uint32_t *aFormatVersion
)
166 NS_ENSURE_STATE(mData
);
167 NS_ENSURE_ARG_POINTER(aFormatVersion
);
168 *aFormatVersion
= mVersion
;