|
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ |
|
2 /* vim: set sw=4 ts=8 et tw=80 : */ |
|
3 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
4 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
6 |
|
7 #include "StructuredCloneUtils.h" |
|
8 |
|
9 #include "nsIDOMFile.h" |
|
10 #include "nsIDOMDOMException.h" |
|
11 #include "nsIMutable.h" |
|
12 #include "nsIXPConnect.h" |
|
13 |
|
14 #include "nsContentUtils.h" |
|
15 #include "nsJSEnvironment.h" |
|
16 #include "MainThreadUtils.h" |
|
17 #include "StructuredCloneTags.h" |
|
18 #include "jsapi.h" |
|
19 |
|
20 using namespace mozilla::dom; |
|
21 |
|
22 namespace { |
|
23 |
|
24 void |
|
25 Error(JSContext* aCx, uint32_t aErrorId) |
|
26 { |
|
27 MOZ_ASSERT(NS_IsMainThread()); |
|
28 NS_DOMStructuredCloneError(aCx, aErrorId); |
|
29 } |
|
30 |
|
31 JSObject* |
|
32 Read(JSContext* aCx, JSStructuredCloneReader* aReader, uint32_t aTag, |
|
33 uint32_t aData, void* aClosure) |
|
34 { |
|
35 MOZ_ASSERT(NS_IsMainThread()); |
|
36 MOZ_ASSERT(aClosure); |
|
37 |
|
38 StructuredCloneClosure* closure = |
|
39 static_cast<StructuredCloneClosure*>(aClosure); |
|
40 |
|
41 if (aTag == SCTAG_DOM_FILE) { |
|
42 MOZ_ASSERT(aData < closure->mBlobs.Length()); |
|
43 |
|
44 nsCOMPtr<nsIDOMFile> file = do_QueryInterface(closure->mBlobs[aData]); |
|
45 MOZ_ASSERT(file); |
|
46 |
|
47 #ifdef DEBUG |
|
48 { |
|
49 // File should not be mutable. |
|
50 nsCOMPtr<nsIMutable> mutableFile = do_QueryInterface(file); |
|
51 bool isMutable; |
|
52 MOZ_ASSERT(NS_SUCCEEDED(mutableFile->GetMutable(&isMutable))); |
|
53 MOZ_ASSERT(!isMutable); |
|
54 } |
|
55 #endif |
|
56 |
|
57 JS::Rooted<JS::Value> wrappedFile(aCx); |
|
58 nsresult rv = nsContentUtils::WrapNative(aCx, file, &NS_GET_IID(nsIDOMFile), |
|
59 &wrappedFile); |
|
60 if (NS_FAILED(rv)) { |
|
61 Error(aCx, nsIDOMDOMException::DATA_CLONE_ERR); |
|
62 return nullptr; |
|
63 } |
|
64 |
|
65 return &wrappedFile.toObject(); |
|
66 } |
|
67 |
|
68 if (aTag == SCTAG_DOM_BLOB) { |
|
69 MOZ_ASSERT(aData < closure->mBlobs.Length()); |
|
70 |
|
71 nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(closure->mBlobs[aData]); |
|
72 MOZ_ASSERT(blob); |
|
73 |
|
74 #ifdef DEBUG |
|
75 { |
|
76 // Blob should not be mutable. |
|
77 nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(blob); |
|
78 bool isMutable; |
|
79 MOZ_ASSERT(NS_SUCCEEDED(mutableBlob->GetMutable(&isMutable))); |
|
80 MOZ_ASSERT(!isMutable); |
|
81 } |
|
82 #endif |
|
83 |
|
84 JS::Rooted<JS::Value> wrappedBlob(aCx); |
|
85 nsresult rv = nsContentUtils::WrapNative(aCx, blob, &NS_GET_IID(nsIDOMBlob), |
|
86 &wrappedBlob); |
|
87 if (NS_FAILED(rv)) { |
|
88 Error(aCx, nsIDOMDOMException::DATA_CLONE_ERR); |
|
89 return nullptr; |
|
90 } |
|
91 |
|
92 return &wrappedBlob.toObject(); |
|
93 } |
|
94 |
|
95 return NS_DOMReadStructuredClone(aCx, aReader, aTag, aData, nullptr); |
|
96 } |
|
97 |
|
98 bool |
|
99 Write(JSContext* aCx, JSStructuredCloneWriter* aWriter, |
|
100 JS::Handle<JSObject*> aObj, void* aClosure) |
|
101 { |
|
102 MOZ_ASSERT(NS_IsMainThread()); |
|
103 MOZ_ASSERT(aClosure); |
|
104 |
|
105 StructuredCloneClosure* closure = |
|
106 static_cast<StructuredCloneClosure*>(aClosure); |
|
107 |
|
108 // See if this is a wrapped native. |
|
109 nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative; |
|
110 nsContentUtils::XPConnect()-> |
|
111 GetWrappedNativeOfJSObject(aCx, aObj, getter_AddRefs(wrappedNative)); |
|
112 |
|
113 if (wrappedNative) { |
|
114 // Get the raw nsISupports out of it. |
|
115 nsISupports* wrappedObject = wrappedNative->Native(); |
|
116 MOZ_ASSERT(wrappedObject); |
|
117 |
|
118 // See if the wrapped native is a nsIDOMFile. |
|
119 nsCOMPtr<nsIDOMFile> file = do_QueryInterface(wrappedObject); |
|
120 if (file) { |
|
121 nsCOMPtr<nsIMutable> mutableFile = do_QueryInterface(file); |
|
122 if (mutableFile && |
|
123 NS_SUCCEEDED(mutableFile->SetMutable(false)) && |
|
124 JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILE, |
|
125 closure->mBlobs.Length())) { |
|
126 closure->mBlobs.AppendElement(file); |
|
127 return true; |
|
128 } |
|
129 } |
|
130 |
|
131 // See if the wrapped native is a nsIDOMBlob. |
|
132 nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(wrappedObject); |
|
133 if (blob) { |
|
134 nsCOMPtr<nsIMutable> mutableBlob = do_QueryInterface(blob); |
|
135 if (mutableBlob && |
|
136 NS_SUCCEEDED(mutableBlob->SetMutable(false)) && |
|
137 JS_WriteUint32Pair(aWriter, SCTAG_DOM_BLOB, |
|
138 closure->mBlobs.Length())) { |
|
139 closure->mBlobs.AppendElement(blob); |
|
140 return true; |
|
141 } |
|
142 } |
|
143 } |
|
144 |
|
145 return NS_DOMWriteStructuredClone(aCx, aWriter, aObj, nullptr); |
|
146 } |
|
147 |
|
148 JSStructuredCloneCallbacks gCallbacks = { |
|
149 Read, |
|
150 Write, |
|
151 Error, |
|
152 nullptr, |
|
153 nullptr, |
|
154 nullptr |
|
155 }; |
|
156 |
|
157 } // anonymous namespace |
|
158 |
|
159 namespace mozilla { |
|
160 namespace dom { |
|
161 |
|
162 bool |
|
163 ReadStructuredClone(JSContext* aCx, uint64_t* aData, size_t aDataLength, |
|
164 const StructuredCloneClosure& aClosure, |
|
165 JS::MutableHandle<JS::Value> aClone) |
|
166 { |
|
167 void* closure = &const_cast<StructuredCloneClosure&>(aClosure); |
|
168 return !!JS_ReadStructuredClone(aCx, aData, aDataLength, |
|
169 JS_STRUCTURED_CLONE_VERSION, aClone, |
|
170 &gCallbacks, closure); |
|
171 } |
|
172 |
|
173 bool |
|
174 WriteStructuredClone(JSContext* aCx, JS::Handle<JS::Value> aSource, |
|
175 JSAutoStructuredCloneBuffer& aBuffer, |
|
176 StructuredCloneClosure& aClosure) |
|
177 { |
|
178 return aBuffer.write(aCx, aSource, &gCallbacks, &aClosure); |
|
179 } |
|
180 |
|
181 } // namespace dom |
|
182 } // namespace mozilla |