dom/workers/File.cpp

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

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

mercurial