1 : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * vim: set ts=8 sw=2 et tw=80:
3 : *
4 : * ***** BEGIN LICENSE BLOCK *****
5 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
6 : *
7 : * The contents of this file are subject to the Mozilla Public License Version
8 : * 1.1 (the "License"); you may not use this file except in compliance with
9 : * the License. You may obtain a copy of the License at
10 : * http://www.mozilla.org/MPL/
11 : *
12 : * Software distributed under the License is distributed on an "AS IS" basis,
13 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 : * for the specific language governing rights and limitations under the
15 : * License.
16 : *
17 : * The Initial Developer of the Original Code is the Mozilla Foundation.
18 : *
19 : * Portions created by the Initial Developer are Copyright (C) 2011
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * Justin Lebar <justin.lebar@gmail.com>
24 : *
25 : * Alternatively, the contents of this file may be used under the terms of
26 : * either of the GNU General Public License Version 2 or later (the "GPL"),
27 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
28 : * in which case the provisions of the GPL or the LGPL are applicable instead
29 : * of those above. If you wish to allow use of your version of this file only
30 : * under the terms of either the GPL or the LGPL, and not to allow others to
31 : * use your version of this file under the terms of the MPL, indicate your
32 : * decision by deleting the provisions above and replace them with the notice
33 : * and other provisions required by the GPL or the LGPL. If you do not delete
34 : * the provisions above, a recipient may use your version of this file under
35 : * the terms of any one of the MPL, the GPL or the LGPL.
36 : *
37 : * ***** END LICENSE BLOCK ***** */
38 :
39 : #include "nsStructuredCloneContainer.h"
40 :
41 : #include "nsCOMPtr.h"
42 : #include "nsIDocument.h"
43 : #include "nsIJSContextStack.h"
44 : #include "nsIScriptContext.h"
45 : #include "nsIVariant.h"
46 : #include "nsServiceManagerUtils.h"
47 : #include "nsContentUtils.h"
48 :
49 : #include "mozilla/Base64.h"
50 :
51 : using namespace mozilla;
52 :
53 0 : NS_IMPL_ADDREF(nsStructuredCloneContainer)
54 0 : NS_IMPL_RELEASE(nsStructuredCloneContainer)
55 :
56 0 : NS_INTERFACE_MAP_BEGIN(nsStructuredCloneContainer)
57 0 : NS_INTERFACE_MAP_ENTRY(nsIStructuredCloneContainer)
58 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
59 0 : NS_INTERFACE_MAP_END
60 :
61 0 : nsStructuredCloneContainer::nsStructuredCloneContainer()
62 0 : : mData(nsnull), mSize(0), mVersion(0)
63 : {
64 0 : }
65 :
66 0 : nsStructuredCloneContainer::~nsStructuredCloneContainer()
67 : {
68 0 : free(mData);
69 0 : }
70 :
71 : nsresult
72 0 : nsStructuredCloneContainer::InitFromVariant(nsIVariant *aData, JSContext *aCx)
73 : {
74 0 : NS_ENSURE_STATE(!mData);
75 0 : NS_ENSURE_ARG_POINTER(aData);
76 0 : NS_ENSURE_ARG_POINTER(aCx);
77 :
78 : // First, try to extract a jsval from the variant |aData|. This works only
79 : // if the variant implements GetAsJSVal.
80 : jsval jsData;
81 0 : nsresult rv = aData->GetAsJSVal(&jsData);
82 0 : NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
83 :
84 : // Make sure that we serialize in the right context.
85 0 : JSAutoRequest ar(aCx);
86 0 : JSAutoEnterCompartment ac;
87 0 : NS_ENSURE_STATE(ac.enter(aCx, JS_GetGlobalObject(aCx)));
88 :
89 0 : nsCxPusher cxPusher;
90 0 : cxPusher.Push(aCx);
91 :
92 0 : uint64_t* jsBytes = nsnull;
93 : bool success = JS_WriteStructuredClone(aCx, jsData, &jsBytes, &mSize,
94 0 : nsnull, nsnull);
95 0 : NS_ENSURE_STATE(success);
96 0 : NS_ENSURE_STATE(jsBytes);
97 :
98 : // Copy jsBytes into our own buffer.
99 0 : mData = (uint64_t*) malloc(mSize);
100 0 : if (!mData) {
101 0 : mSize = 0;
102 0 : mVersion = 0;
103 :
104 : // FIXME This should really be js::Foreground::Free, but that's not public.
105 0 : JS_free(aCx, jsBytes);
106 :
107 0 : return NS_ERROR_FAILURE;
108 : }
109 : else {
110 0 : mVersion = JS_STRUCTURED_CLONE_VERSION;
111 : }
112 :
113 0 : memcpy(mData, jsBytes, mSize);
114 :
115 : // FIXME Similarly, this should be js::Foreground::free.
116 0 : JS_free(aCx, jsBytes);
117 0 : return NS_OK;
118 : }
119 :
120 : nsresult
121 0 : nsStructuredCloneContainer::InitFromBase64(const nsAString &aData,
122 : PRUint32 aFormatVersion,
123 : JSContext *aCx)
124 : {
125 0 : NS_ENSURE_STATE(!mData);
126 :
127 0 : NS_ConvertUTF16toUTF8 data(aData);
128 :
129 0 : nsCAutoString binaryData;
130 0 : nsresult rv = Base64Decode(data, binaryData);
131 0 : NS_ENSURE_SUCCESS(rv, rv);
132 :
133 : // Copy the string's data into our own buffer.
134 0 : mData = (uint64_t*) malloc(binaryData.Length());
135 0 : NS_ENSURE_STATE(mData);
136 0 : memcpy(mData, binaryData.get(), binaryData.Length());
137 :
138 0 : mSize = binaryData.Length();
139 0 : mVersion = aFormatVersion;
140 0 : return NS_OK;
141 : }
142 :
143 :
144 : nsresult
145 0 : nsStructuredCloneContainer::DeserializeToVariant(JSContext *aCx,
146 : nsIVariant **aData)
147 : {
148 0 : NS_ENSURE_STATE(mData);
149 0 : NS_ENSURE_ARG_POINTER(aData);
150 0 : *aData = nsnull;
151 :
152 : // Deserialize to a jsval.
153 : jsval jsStateObj;
154 : bool success = JS_ReadStructuredClone(aCx, mData, mSize, mVersion,
155 0 : &jsStateObj, nsnull, nsnull);
156 0 : NS_ENSURE_STATE(success);
157 :
158 : // Now wrap the jsval as an nsIVariant.
159 0 : nsCOMPtr<nsIVariant> varStateObj;
160 0 : nsCOMPtr<nsIXPConnect> xpconnect = do_GetService(nsIXPConnect::GetCID());
161 0 : NS_ENSURE_STATE(xpconnect);
162 0 : xpconnect->JSValToVariant(aCx, &jsStateObj, getter_AddRefs(varStateObj));
163 0 : NS_ENSURE_STATE(varStateObj);
164 :
165 0 : NS_IF_ADDREF(*aData = varStateObj);
166 0 : return NS_OK;
167 : }
168 :
169 : nsresult
170 0 : nsStructuredCloneContainer::GetDataAsBase64(nsAString &aOut)
171 : {
172 0 : NS_ENSURE_STATE(mData);
173 0 : aOut.Truncate();
174 :
175 0 : nsCAutoString binaryData(reinterpret_cast<char*>(mData), mSize);
176 0 : nsCAutoString base64Data;
177 0 : nsresult rv = Base64Encode(binaryData, base64Data);
178 0 : NS_ENSURE_SUCCESS(rv, rv);
179 :
180 0 : aOut.Assign(NS_ConvertASCIItoUTF16(base64Data));
181 0 : return NS_OK;
182 : }
183 :
184 : nsresult
185 0 : nsStructuredCloneContainer::GetSerializedNBytes(PRUint64 *aSize)
186 : {
187 0 : NS_ENSURE_STATE(mData);
188 0 : NS_ENSURE_ARG_POINTER(aSize);
189 :
190 : // mSize is a size_t, while aSize is a PRUint64. We rely on an implicit cast
191 : // here so that we'll get a compile error if a size_t-to-uint64 cast is
192 : // narrowing.
193 0 : *aSize = mSize;
194 :
195 0 : return NS_OK;
196 : }
197 :
198 : nsresult
199 0 : nsStructuredCloneContainer::GetFormatVersion(PRUint32 *aFormatVersion)
200 : {
201 0 : NS_ENSURE_STATE(mData);
202 0 : NS_ENSURE_ARG_POINTER(aFormatVersion);
203 0 : *aFormatVersion = mVersion;
204 0 : return NS_OK;
205 : }
|