1 : /* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
2 : /* vim: set ts=2 et sw=2 tw=80: */
3 : /* ***** BEGIN LICENSE BLOCK *****
4 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
5 : *
6 : * The contents of this file are subject to the Mozilla Public License Version
7 : * 1.1 (the "License"); you may not use this file except in compliance with
8 : * the License. You may obtain a copy of the License at
9 : * http://www.mozilla.org/MPL/
10 : *
11 : * Software distributed under the License is distributed on an "AS IS" basis,
12 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
13 : * for the specific language governing rights and limitations under the
14 : * License.
15 : *
16 : * The Original Code is Web Workers.
17 : *
18 : * The Initial Developer of the Original Code is
19 : * The Mozilla Foundation.
20 : * Portions created by the Initial Developer are Copyright (C) 2011
21 : * the Initial Developer. All Rights Reserved.
22 : *
23 : * Contributor(s):
24 : * William Chen <wchen@mozilla.com> (Original Author)
25 : *
26 : * Alternatively, the contents of this file may be used under the terms of
27 : * either the GNU General Public License Version 2 or later (the "GPL"), or
28 : * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
29 : * in which case the provisions of the GPL or the LGPL are applicable instead
30 : * of those above. If you wish to allow use of your version of this file only
31 : * under the terms of either the GPL or the LGPL, and not to allow others to
32 : * use your version of this file under the terms of the MPL, indicate your
33 : * decision by deleting the provisions above and replace them with the notice
34 : * and other provisions required by the GPL or the LGPL. If you do not delete
35 : * the provisions above, a recipient may use your version of this file under
36 : * the terms of any one of the MPL, the GPL or the LGPL.
37 : *
38 : * ***** END LICENSE BLOCK ***** */
39 :
40 : #include "FileReaderSync.h"
41 :
42 : #include "nsIDOMFile.h"
43 :
44 : #include "jsapi.h"
45 : #include "jsatom.h"
46 : #include "jsfriendapi.h"
47 : #include "jstypedarray.h"
48 : #include "nsJSUtils.h"
49 :
50 : #include "Exceptions.h"
51 : #include "File.h"
52 : #include "FileReaderSyncPrivate.h"
53 : #include "WorkerInlines.h"
54 :
55 : #define FUNCTION_FLAGS \
56 : JSPROP_ENUMERATE
57 :
58 : USING_WORKERS_NAMESPACE
59 :
60 : using mozilla::dom::workers::exceptions::ThrowFileExceptionForCode;
61 : using js::ArrayBuffer;
62 :
63 : namespace {
64 :
65 : inline bool
66 0 : EnsureSucceededOrThrow(JSContext* aCx, nsresult rv)
67 : {
68 0 : if (NS_SUCCEEDED(rv)) {
69 0 : return true;
70 : }
71 :
72 : int code = rv == NS_ERROR_FILE_NOT_FOUND ?
73 : FILE_NOT_FOUND_ERR :
74 0 : FILE_NOT_READABLE_ERR;
75 0 : ThrowFileExceptionForCode(aCx, code);
76 0 : return false;
77 : }
78 :
79 : inline nsIDOMBlob*
80 0 : GetDOMBlobFromJSObject(JSContext* aCx, JSObject* aObj) {
81 : // aObj can be null as JS_ConvertArguments("o") successfully converts JS
82 : // null to a null pointer to JSObject
83 0 : if (aObj) {
84 0 : nsIDOMBlob* blob = file::GetDOMBlobFromJSObject(aObj);
85 0 : if (blob) {
86 0 : return blob;
87 : }
88 : }
89 :
90 : JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL, JSMSG_UNEXPECTED_TYPE,
91 0 : aObj ? JS_GetClass(aObj)->name : "Object", "not a Blob.");
92 0 : return NULL;
93 : }
94 :
95 : class FileReaderSync
96 : {
97 : // FileReaderSync should not be instantiated.
98 : FileReaderSync();
99 : ~FileReaderSync();
100 :
101 : static JSClass sClass;
102 : static JSFunctionSpec sFunctions[];
103 :
104 : public:
105 : static JSObject*
106 0 : InitClass(JSContext* aCx, JSObject* aObj)
107 : {
108 : return JS_InitClass(aCx, aObj, NULL, &sClass, Construct, 0,
109 0 : NULL, sFunctions, NULL, NULL);
110 : }
111 :
112 : static FileReaderSyncPrivate*
113 0 : GetPrivate(JSObject* aObj)
114 : {
115 0 : if (aObj) {
116 0 : JSClass* classPtr = JS_GetClass(aObj);
117 0 : if (classPtr == &sClass) {
118 : FileReaderSyncPrivate* fileReader =
119 0 : GetJSPrivateSafeish<FileReaderSyncPrivate>(aObj);
120 0 : return fileReader;
121 : }
122 : }
123 0 : return NULL;
124 : }
125 :
126 : private:
127 : static FileReaderSyncPrivate*
128 0 : GetInstancePrivate(JSContext* aCx, JSObject* aObj, const char* aFunctionName)
129 : {
130 0 : FileReaderSyncPrivate* fileReader = GetPrivate(aObj);
131 0 : if (fileReader) {
132 0 : return fileReader;
133 : }
134 :
135 : JS_ReportErrorNumber(aCx, js_GetErrorMessage, NULL,
136 : JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
137 0 : JS_GetClass(aObj)->name);
138 0 : return NULL;
139 : }
140 :
141 : static JSBool
142 0 : Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
143 : {
144 0 : JSObject* obj = JS_NewObject(aCx, &sClass, NULL, NULL);
145 0 : if (!obj) {
146 0 : return false;
147 : }
148 :
149 0 : FileReaderSyncPrivate* fileReader = new FileReaderSyncPrivate();
150 0 : NS_ADDREF(fileReader);
151 :
152 0 : SetJSPrivateSafeish(obj, fileReader);
153 :
154 0 : JS_SET_RVAL(aCx, aVp, OBJECT_TO_JSVAL(obj));
155 0 : return true;
156 : }
157 :
158 : static void
159 0 : Finalize(JSContext* aCx, JSObject* aObj)
160 : {
161 0 : JS_ASSERT(JS_GetClass(aObj) == &sClass);
162 : FileReaderSyncPrivate* fileReader =
163 0 : GetJSPrivateSafeish<FileReaderSyncPrivate>(aObj);
164 0 : NS_IF_RELEASE(fileReader);
165 0 : }
166 :
167 : static JSBool
168 0 : ReadAsArrayBuffer(JSContext* aCx, unsigned aArgc, jsval* aVp)
169 : {
170 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
171 0 : if (!obj) {
172 0 : return false;
173 : }
174 :
175 : FileReaderSyncPrivate* fileReader =
176 0 : GetInstancePrivate(aCx, obj, "readAsArrayBuffer");
177 0 : if (!fileReader) {
178 0 : return false;
179 : }
180 :
181 : JSObject* jsBlob;
182 0 : if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "o", &jsBlob)) {
183 0 : return false;
184 : }
185 :
186 0 : nsIDOMBlob* blob = GetDOMBlobFromJSObject(aCx, jsBlob);
187 0 : if (!blob) {
188 0 : return false;
189 : }
190 :
191 : PRUint64 blobSize;
192 0 : nsresult rv = blob->GetSize(&blobSize);
193 0 : if (!EnsureSucceededOrThrow(aCx, rv)) {
194 0 : return false;
195 : }
196 :
197 0 : JSObject* jsArrayBuffer = js_CreateArrayBuffer(aCx, blobSize);
198 0 : if (!jsArrayBuffer) {
199 0 : return false;
200 : }
201 :
202 0 : uint32_t bufferLength = JS_GetArrayBufferByteLength(jsArrayBuffer);
203 0 : uint8_t* arrayBuffer = JS_GetArrayBufferData(jsArrayBuffer);
204 :
205 0 : rv = fileReader->ReadAsArrayBuffer(blob, bufferLength, arrayBuffer);
206 0 : if (!EnsureSucceededOrThrow(aCx, rv)) {
207 0 : return false;
208 : }
209 :
210 0 : JS_SET_RVAL(aCx, aVp, OBJECT_TO_JSVAL(jsArrayBuffer));
211 0 : return true;
212 : }
213 :
214 : static JSBool
215 0 : ReadAsDataURL(JSContext* aCx, unsigned aArgc, jsval* aVp)
216 : {
217 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
218 0 : if (!obj) {
219 0 : return false;
220 : }
221 :
222 : FileReaderSyncPrivate* fileReader =
223 0 : GetInstancePrivate(aCx, obj, "readAsDataURL");
224 0 : if (!fileReader) {
225 0 : return false;
226 : }
227 :
228 : JSObject* jsBlob;
229 0 : if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "o", &jsBlob)) {
230 0 : return false;
231 : }
232 :
233 0 : nsIDOMBlob* blob = GetDOMBlobFromJSObject(aCx, jsBlob);
234 0 : if (!blob) {
235 0 : return false;
236 : }
237 :
238 0 : nsString blobText;
239 0 : nsresult rv = fileReader->ReadAsDataURL(blob, blobText);
240 0 : if (!EnsureSucceededOrThrow(aCx, rv)) {
241 0 : return false;
242 : }
243 :
244 : JSString* jsBlobText = JS_NewUCStringCopyN(aCx, blobText.get(),
245 0 : blobText.Length());
246 0 : if (!jsBlobText) {
247 0 : return false;
248 : }
249 :
250 0 : JS_SET_RVAL(aCx, aVp, STRING_TO_JSVAL(jsBlobText));
251 0 : return true;
252 : }
253 :
254 : static JSBool
255 0 : ReadAsBinaryString(JSContext* aCx, unsigned aArgc, jsval* aVp)
256 : {
257 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
258 0 : if (!obj) {
259 0 : return false;
260 : }
261 :
262 : FileReaderSyncPrivate* fileReader =
263 0 : GetInstancePrivate(aCx, obj, "readAsBinaryString");
264 0 : if (!fileReader) {
265 0 : return false;
266 : }
267 :
268 : JSObject* jsBlob;
269 0 : if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "o", &jsBlob)) {
270 0 : return false;
271 : }
272 :
273 0 : nsIDOMBlob* blob = GetDOMBlobFromJSObject(aCx, jsBlob);
274 0 : if (!blob) {
275 0 : return false;
276 : }
277 :
278 0 : nsString blobText;
279 0 : nsresult rv = fileReader->ReadAsBinaryString(blob, blobText);
280 0 : if (!EnsureSucceededOrThrow(aCx, rv)) {
281 0 : return false;
282 : }
283 :
284 : JSString* jsBlobText = JS_NewUCStringCopyN(aCx, blobText.get(),
285 0 : blobText.Length());
286 0 : if (!jsBlobText) {
287 0 : return false;
288 : }
289 :
290 0 : JS_SET_RVAL(aCx, aVp, STRING_TO_JSVAL(jsBlobText));
291 0 : return true;
292 : }
293 :
294 : static JSBool
295 0 : ReadAsText(JSContext* aCx, unsigned aArgc, jsval* aVp)
296 : {
297 0 : JSObject* obj = JS_THIS_OBJECT(aCx, aVp);
298 0 : if (!obj) {
299 0 : return false;
300 : }
301 :
302 : FileReaderSyncPrivate* fileReader =
303 0 : GetInstancePrivate(aCx, obj, "readAsText");
304 0 : if (!fileReader) {
305 0 : return false;
306 : }
307 :
308 : JSObject* jsBlob;
309 0 : JSString* jsEncoding = JS_GetEmptyString(JS_GetRuntime(aCx));
310 0 : if (!JS_ConvertArguments(aCx, aArgc, JS_ARGV(aCx, aVp), "o/S", &jsBlob,
311 0 : &jsEncoding)) {
312 0 : return false;
313 : }
314 :
315 0 : nsDependentJSString encoding;
316 0 : if (!encoding.init(aCx, jsEncoding)) {
317 0 : return false;
318 : }
319 :
320 0 : nsIDOMBlob* blob = GetDOMBlobFromJSObject(aCx, jsBlob);
321 0 : if (!blob) {
322 0 : return false;
323 : }
324 :
325 0 : nsString blobText;
326 0 : nsresult rv = fileReader->ReadAsText(blob, encoding, blobText);
327 0 : if (!EnsureSucceededOrThrow(aCx, rv)) {
328 0 : return false;
329 : }
330 :
331 : JSString* jsBlobText = JS_NewUCStringCopyN(aCx, blobText.get(),
332 0 : blobText.Length());
333 0 : if (!jsBlobText) {
334 0 : return false;
335 : }
336 :
337 0 : JS_SET_RVAL(aCx, aVp, STRING_TO_JSVAL(jsBlobText));
338 0 : return true;
339 : }
340 : };
341 :
342 : JSClass FileReaderSync::sClass = {
343 : "FileReaderSync",
344 : JSCLASS_HAS_PRIVATE,
345 : JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
346 : JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize,
347 : JSCLASS_NO_OPTIONAL_MEMBERS
348 : };
349 :
350 : JSFunctionSpec FileReaderSync::sFunctions[] = {
351 : JS_FN("readAsArrayBuffer", ReadAsArrayBuffer, 1, FUNCTION_FLAGS),
352 : JS_FN("readAsBinaryString", ReadAsBinaryString, 1, FUNCTION_FLAGS),
353 : JS_FN("readAsText", ReadAsText, 1, FUNCTION_FLAGS),
354 : JS_FN("readAsDataURL", ReadAsDataURL, 1, FUNCTION_FLAGS),
355 : JS_FS_END
356 : };
357 :
358 : } // anonymous namespace
359 :
360 : BEGIN_WORKERS_NAMESPACE
361 :
362 : namespace filereadersync {
363 :
364 : bool
365 0 : InitClass(JSContext* aCx, JSObject* aGlobal)
366 : {
367 0 : return !!FileReaderSync::InitClass(aCx, aGlobal);
368 : }
369 :
370 : } // namespace filereadersync
371 :
372 : END_WORKERS_NAMESPACE
|