dom/workers/File.cpp

branch
TOR_BUG_9701
changeset 14
925c144e1f1f
equal deleted inserted replaced
-1:000000000000 0:e322667637f2
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 /* 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 "File.h"
8
9 #include "nsIDOMFile.h"
10 #include "nsDOMBlobBuilder.h"
11 #include "nsError.h"
12
13 #include "jsapi.h"
14 #include "jsfriendapi.h"
15 #include "nsCOMPtr.h"
16 #include "nsJSUtils.h"
17 #include "nsString.h"
18
19 #include "mozilla/dom/Exceptions.h"
20 #include "WorkerInlines.h"
21 #include "WorkerPrivate.h"
22
23 USING_WORKERS_NAMESPACE
24 using mozilla::dom::Throw;
25
26 namespace {
27
28 class Blob
29 {
30 // Blob should never be instantiated.
31 Blob();
32 ~Blob();
33
34 static const JSClass sClass;
35 static const JSPropertySpec sProperties[];
36 static const JSFunctionSpec sFunctions[];
37
38 public:
39 static JSObject*
40 InitClass(JSContext* aCx, JS::Handle<JSObject*> aObj)
41 {
42 return JS_InitClass(aCx, aObj, JS::NullPtr(), &sClass, Construct, 0,
43 sProperties, sFunctions, nullptr, nullptr);
44 }
45
46 static JSObject*
47 Create(JSContext* aCx, nsIDOMBlob* aBlob)
48 {
49 MOZ_ASSERT(SameCOMIdentity(static_cast<nsISupports*>(aBlob), aBlob));
50
51 JSObject* obj = JS_NewObject(aCx, &sClass, JS::NullPtr(), JS::NullPtr());
52 if (obj) {
53 JS_SetPrivate(obj, aBlob);
54 NS_ADDREF(aBlob);
55 }
56 return obj;
57 }
58
59 static nsIDOMBlob*
60 GetPrivate(JSObject* aObj);
61
62 private:
63 static nsIDOMBlob*
64 GetInstancePrivate(JSContext* aCx, JS::Handle<JSObject*> aObj, const char* aFunctionName)
65 {
66 nsIDOMBlob* blob = GetPrivate(aObj);
67 if (blob) {
68 return blob;
69 }
70
71 JS_ReportErrorNumber(aCx, js_GetErrorMessage, nullptr,
72 JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
73 JS_GetClass(aObj)->name);
74 return nullptr;
75 }
76
77 static nsIDOMBlob*
78 Unwrap(JSContext* aCx, JSObject* aObj)
79 {
80 return GetPrivate(aObj);
81 }
82
83 static bool
84 Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
85 {
86 JS::CallArgs args = CallArgsFromVp(aArgc, aVp);
87
88 nsRefPtr<nsDOMMultipartFile> file = new nsDOMMultipartFile();
89 nsresult rv = file->InitBlob(aCx, args.length(), args.array(), Unwrap);
90 if (NS_FAILED(rv)) {
91 return Throw(aCx, rv);
92 }
93
94 JSObject* obj = file::CreateBlob(aCx, file);
95 if (!obj) {
96 return false;
97 }
98
99 args.rval().setObject(*obj);
100 return true;
101 }
102
103 static void
104 Finalize(JSFreeOp* aFop, JSObject* aObj)
105 {
106 MOZ_ASSERT(JS_GetClass(aObj) == &sClass);
107
108 nsIDOMBlob* blob = GetPrivate(aObj);
109 NS_IF_RELEASE(blob);
110 }
111
112 static bool
113 IsBlob(JS::Handle<JS::Value> v)
114 {
115 return v.isObject() && GetPrivate(&v.toObject()) != nullptr;
116 }
117
118 static bool
119 GetSizeImpl(JSContext* aCx, JS::CallArgs aArgs)
120 {
121 JS::Rooted<JSObject*> obj(aCx, &aArgs.thisv().toObject());
122 nsIDOMBlob* blob = GetInstancePrivate(aCx, obj, "size");
123 MOZ_ASSERT(blob);
124
125 uint64_t size;
126 if (NS_FAILED(blob->GetSize(&size))) {
127 return Throw(aCx, NS_ERROR_DOM_FILE_NOT_READABLE_ERR);
128 }
129
130 aArgs.rval().setNumber(double(size));
131 return true;
132 }
133
134 static bool
135 GetSize(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
136 {
137 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
138 return JS::CallNonGenericMethod<IsBlob, GetSizeImpl>(aCx, args);
139 }
140
141 static bool
142 GetTypeImpl(JSContext* aCx, JS::CallArgs aArgs)
143 {
144 JS::Rooted<JSObject*> obj(aCx, &aArgs.thisv().toObject());
145 nsIDOMBlob* blob = GetInstancePrivate(aCx, obj, "type");
146 MOZ_ASSERT(blob);
147
148 nsString type;
149 if (NS_FAILED(blob->GetType(type))) {
150 return Throw(aCx, NS_ERROR_DOM_FILE_NOT_READABLE_ERR);
151 }
152
153 JSString* jsType = JS_NewUCStringCopyN(aCx, type.get(), type.Length());
154 if (!jsType) {
155 return false;
156 }
157
158 aArgs.rval().setString(jsType);
159 return true;
160 }
161
162 static bool
163 GetType(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
164 {
165 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
166 return JS::CallNonGenericMethod<IsBlob, GetTypeImpl>(aCx, args);
167 }
168
169 static bool
170 Slice(JSContext* aCx, unsigned aArgc, jsval* aVp)
171 {
172 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
173
174 JS::Rooted<JSObject*> obj(aCx, args.thisv().toObjectOrNull());
175 if (!obj) {
176 return false;
177 }
178
179 nsIDOMBlob* blob = GetInstancePrivate(aCx, obj, "slice");
180 if (!blob) {
181 return false;
182 }
183
184 double start = 0, end = 0;
185 JS::Rooted<JSString*> jsContentType(aCx, JS_GetEmptyString(JS_GetRuntime(aCx)));
186 if (!JS_ConvertArguments(aCx, args, "/IIS", &start,
187 &end, jsContentType.address())) {
188 return false;
189 }
190
191 nsDependentJSString contentType;
192 if (!contentType.init(aCx, jsContentType)) {
193 return false;
194 }
195
196 uint8_t optionalArgc = aArgc;
197 nsCOMPtr<nsIDOMBlob> rtnBlob;
198 if (NS_FAILED(blob->Slice(static_cast<uint64_t>(start),
199 static_cast<uint64_t>(end),
200 contentType, optionalArgc,
201 getter_AddRefs(rtnBlob)))) {
202 return Throw(aCx, NS_ERROR_DOM_FILE_NOT_READABLE_ERR);
203 }
204
205 JSObject* rtnObj = file::CreateBlob(aCx, rtnBlob);
206 if (!rtnObj) {
207 return false;
208 }
209
210 args.rval().setObject(*rtnObj);
211 return true;
212 }
213 };
214
215 const JSClass Blob::sClass = {
216 "Blob",
217 JSCLASS_HAS_PRIVATE,
218 JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
219 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize
220 };
221
222 const JSPropertySpec Blob::sProperties[] = {
223 JS_PSGS("size", GetSize, GetterOnlyJSNative, JSPROP_ENUMERATE),
224 JS_PSGS("type", GetType, GetterOnlyJSNative, JSPROP_ENUMERATE),
225 JS_PS_END
226 };
227
228 const JSFunctionSpec Blob::sFunctions[] = {
229 JS_FN("slice", Slice, 1, JSPROP_ENUMERATE),
230 JS_FS_END
231 };
232
233 class File : public Blob
234 {
235 // File should never be instantiated.
236 File();
237 ~File();
238
239 static const JSClass sClass;
240 static const JSPropertySpec sProperties[];
241
242 public:
243 static JSObject*
244 InitClass(JSContext* aCx, JS::Handle<JSObject*> aObj, JS::Handle<JSObject*> aParentProto)
245 {
246 return JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct, 0,
247 sProperties, nullptr, nullptr, nullptr);
248 }
249
250 static JSObject*
251 Create(JSContext* aCx, nsIDOMFile* aFile)
252 {
253 MOZ_ASSERT(SameCOMIdentity(static_cast<nsISupports*>(aFile), aFile));
254
255 JSObject* obj = JS_NewObject(aCx, &sClass, JS::NullPtr(), JS::NullPtr());
256 if (obj) {
257 JS_SetPrivate(obj, aFile);
258 NS_ADDREF(aFile);
259 }
260 return obj;
261 }
262
263 static nsIDOMFile*
264 GetPrivate(JSObject* aObj)
265 {
266 if (aObj) {
267 const JSClass* classPtr = JS_GetClass(aObj);
268 if (classPtr == &sClass) {
269 nsISupports* priv = static_cast<nsISupports*>(JS_GetPrivate(aObj));
270 nsCOMPtr<nsIDOMFile> file = do_QueryInterface(priv);
271 MOZ_ASSERT_IF(priv, file);
272 return file;
273 }
274 }
275 return nullptr;
276 }
277
278 static const JSClass*
279 Class()
280 {
281 return &sClass;
282 }
283
284 private:
285 static nsIDOMFile*
286 GetInstancePrivate(JSContext* aCx, JS::Handle<JSObject*> aObj, const char* aFunctionName)
287 {
288 nsIDOMFile* file = GetPrivate(aObj);
289 if (file) {
290 return file;
291 }
292
293 JS_ReportErrorNumber(aCx, js_GetErrorMessage, nullptr,
294 JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
295 JS_GetClass(aObj)->name);
296 return nullptr;
297 }
298
299 static bool
300 Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
301 {
302 JS_ReportErrorNumber(aCx, js_GetErrorMessage, nullptr,
303 JSMSG_WRONG_CONSTRUCTOR,
304 sClass.name);
305 return false;
306 }
307
308 static void
309 Finalize(JSFreeOp* aFop, JSObject* aObj)
310 {
311 MOZ_ASSERT(JS_GetClass(aObj) == &sClass);
312
313 nsIDOMFile* file = GetPrivate(aObj);
314 NS_IF_RELEASE(file);
315 }
316
317 static bool
318 IsFile(JS::Handle<JS::Value> v)
319 {
320 return v.isObject() && GetPrivate(&v.toObject()) != nullptr;
321 }
322
323 static bool
324 GetMozFullPathImpl(JSContext* aCx, JS::CallArgs aArgs)
325 {
326 JS::Rooted<JSObject*> obj(aCx, &aArgs.thisv().toObject());
327 nsIDOMFile* file = GetInstancePrivate(aCx, obj, "mozFullPath");
328 MOZ_ASSERT(file);
329
330 nsString fullPath;
331
332 if (GetWorkerPrivateFromContext(aCx)->UsesSystemPrincipal() &&
333 NS_FAILED(file->GetMozFullPathInternal(fullPath))) {
334 return Throw(aCx, NS_ERROR_DOM_FILE_NOT_READABLE_ERR);
335 }
336
337 JSString* jsFullPath = JS_NewUCStringCopyN(aCx, fullPath.get(),
338 fullPath.Length());
339 if (!jsFullPath) {
340 return false;
341 }
342
343 aArgs.rval().setString(jsFullPath);
344 return true;
345 }
346
347 static bool
348 GetMozFullPath(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
349 {
350 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
351 return JS::CallNonGenericMethod<IsFile, GetMozFullPathImpl>(aCx, args);
352 }
353
354 static bool
355 GetNameImpl(JSContext* aCx, JS::CallArgs aArgs)
356 {
357 JS::Rooted<JSObject*> obj(aCx, &aArgs.thisv().toObject());
358 nsIDOMFile* file = GetInstancePrivate(aCx, obj, "name");
359 MOZ_ASSERT(file);
360
361 nsString name;
362 if (NS_FAILED(file->GetName(name))) {
363 name.Truncate();
364 }
365
366 JSString* jsName = JS_NewUCStringCopyN(aCx, name.get(), name.Length());
367 if (!jsName) {
368 return false;
369 }
370
371 aArgs.rval().setString(jsName);
372 return true;
373 }
374
375 static bool
376 GetName(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
377 {
378 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
379 return JS::CallNonGenericMethod<IsFile, GetNameImpl>(aCx, args);
380 }
381
382 static bool
383 GetPathImpl(JSContext* aCx, JS::CallArgs aArgs)
384 {
385 JS::Rooted<JSObject*> obj(aCx, &aArgs.thisv().toObject());
386 nsIDOMFile* file = GetInstancePrivate(aCx, obj, "path");
387 MOZ_ASSERT(file);
388
389 nsString path;
390 if (NS_FAILED(file->GetPath(path))) {
391 path.Truncate();
392 }
393
394 JSString* jsPath = JS_NewUCStringCopyN(aCx, path.get(), path.Length());
395 if (!jsPath) {
396 return false;
397 }
398
399 aArgs.rval().setString(jsPath);
400 return true;
401 }
402
403 static bool
404 GetPath(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
405 {
406 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
407 return JS::CallNonGenericMethod<IsFile, GetPathImpl>(aCx, args);
408 }
409
410 static bool
411 GetLastModifiedDateImpl(JSContext* aCx, JS::CallArgs aArgs)
412 {
413 JS::Rooted<JSObject*> obj(aCx, &aArgs.thisv().toObject());
414 nsIDOMFile* file = GetInstancePrivate(aCx, obj, "lastModifiedDate");
415 MOZ_ASSERT(file);
416
417 if (NS_FAILED(file->GetLastModifiedDate(aCx, aArgs.rval()))) {
418 return false;
419 }
420 return true;
421 }
422
423 static bool
424 GetLastModifiedDate(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
425 {
426 JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
427 return JS::CallNonGenericMethod<IsFile, GetLastModifiedDateImpl>(aCx, args);
428 }
429 };
430
431 const JSClass File::sClass = {
432 "File",
433 JSCLASS_HAS_PRIVATE,
434 JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
435 JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize
436 };
437
438 const JSPropertySpec File::sProperties[] = {
439 JS_PSGS("name", GetName, GetterOnlyJSNative, JSPROP_ENUMERATE),
440 JS_PSGS("path", GetPath, GetterOnlyJSNative, JSPROP_ENUMERATE),
441 JS_PSGS("lastModifiedDate", GetLastModifiedDate, GetterOnlyJSNative,
442 JSPROP_ENUMERATE),
443 JS_PSGS("mozFullPath", GetMozFullPath, GetterOnlyJSNative, JSPROP_ENUMERATE),
444 JS_PS_END
445 };
446
447 nsIDOMBlob*
448 Blob::GetPrivate(JSObject* aObj)
449 {
450 if (aObj) {
451 const JSClass* classPtr = JS_GetClass(aObj);
452 if (classPtr == &sClass || classPtr == File::Class()) {
453 nsISupports* priv = static_cast<nsISupports*>(JS_GetPrivate(aObj));
454 nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(priv);
455 MOZ_ASSERT_IF(priv, blob);
456 return blob;
457 }
458 }
459 return nullptr;
460 }
461
462 } // anonymous namespace
463
464 BEGIN_WORKERS_NAMESPACE
465
466 namespace file {
467
468 JSObject*
469 CreateBlob(JSContext* aCx, nsIDOMBlob* aBlob)
470 {
471 return Blob::Create(aCx, aBlob);
472 }
473
474 bool
475 InitClasses(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
476 {
477 JS::Rooted<JSObject*> blobProto(aCx, Blob::InitClass(aCx, aGlobal));
478 return blobProto && File::InitClass(aCx, aGlobal, blobProto);
479 }
480
481 nsIDOMBlob*
482 GetDOMBlobFromJSObject(JSObject* aObj)
483 {
484 return Blob::GetPrivate(aObj);
485 }
486
487 JSObject*
488 CreateFile(JSContext* aCx, nsIDOMFile* aFile)
489 {
490 return File::Create(aCx, aFile);
491 }
492
493 nsIDOMFile*
494 GetDOMFileFromJSObject(JSObject* aObj)
495 {
496 return File::GetPrivate(aObj);
497 }
498
499 } // namespace file
500
501 END_WORKERS_NAMESPACE

mercurial