dom/workers/File.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/workers/File.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,501 @@
     1.4 +/* -*- Mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 40 -*- */
     1.5 +/* vim: set ts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "File.h"
    1.11 +
    1.12 +#include "nsIDOMFile.h"
    1.13 +#include "nsDOMBlobBuilder.h"
    1.14 +#include "nsError.h"
    1.15 +
    1.16 +#include "jsapi.h"
    1.17 +#include "jsfriendapi.h"
    1.18 +#include "nsCOMPtr.h"
    1.19 +#include "nsJSUtils.h"
    1.20 +#include "nsString.h"
    1.21 +
    1.22 +#include "mozilla/dom/Exceptions.h"
    1.23 +#include "WorkerInlines.h"
    1.24 +#include "WorkerPrivate.h"
    1.25 +
    1.26 +USING_WORKERS_NAMESPACE
    1.27 +using mozilla::dom::Throw;
    1.28 +
    1.29 +namespace {
    1.30 +
    1.31 +class Blob
    1.32 +{
    1.33 +  // Blob should never be instantiated.
    1.34 +  Blob();
    1.35 +  ~Blob();
    1.36 +
    1.37 +  static const JSClass sClass;
    1.38 +  static const JSPropertySpec sProperties[];
    1.39 +  static const JSFunctionSpec sFunctions[];
    1.40 +
    1.41 +public:
    1.42 +  static JSObject*
    1.43 +  InitClass(JSContext* aCx, JS::Handle<JSObject*> aObj)
    1.44 +  {
    1.45 +    return JS_InitClass(aCx, aObj, JS::NullPtr(), &sClass, Construct, 0,
    1.46 +                        sProperties, sFunctions, nullptr, nullptr);
    1.47 +  }
    1.48 +
    1.49 +  static JSObject*
    1.50 +  Create(JSContext* aCx, nsIDOMBlob* aBlob)
    1.51 +  {
    1.52 +    MOZ_ASSERT(SameCOMIdentity(static_cast<nsISupports*>(aBlob), aBlob));
    1.53 +
    1.54 +    JSObject* obj = JS_NewObject(aCx, &sClass, JS::NullPtr(), JS::NullPtr());
    1.55 +    if (obj) {
    1.56 +      JS_SetPrivate(obj, aBlob);
    1.57 +      NS_ADDREF(aBlob);
    1.58 +    }
    1.59 +    return obj;
    1.60 +  }
    1.61 +
    1.62 +  static nsIDOMBlob*
    1.63 +  GetPrivate(JSObject* aObj);
    1.64 +
    1.65 +private:
    1.66 +  static nsIDOMBlob*
    1.67 +  GetInstancePrivate(JSContext* aCx, JS::Handle<JSObject*> aObj, const char* aFunctionName)
    1.68 +  {
    1.69 +    nsIDOMBlob* blob = GetPrivate(aObj);
    1.70 +    if (blob) {
    1.71 +      return blob;
    1.72 +    }
    1.73 +
    1.74 +    JS_ReportErrorNumber(aCx, js_GetErrorMessage, nullptr,
    1.75 +                         JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
    1.76 +                         JS_GetClass(aObj)->name);
    1.77 +    return nullptr;
    1.78 +  }
    1.79 +
    1.80 +  static nsIDOMBlob*
    1.81 +  Unwrap(JSContext* aCx, JSObject* aObj)
    1.82 +  {
    1.83 +    return GetPrivate(aObj);
    1.84 +  }
    1.85 +
    1.86 +  static bool
    1.87 +  Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
    1.88 +  {
    1.89 +    JS::CallArgs args = CallArgsFromVp(aArgc, aVp);
    1.90 +
    1.91 +    nsRefPtr<nsDOMMultipartFile> file = new nsDOMMultipartFile();
    1.92 +    nsresult rv = file->InitBlob(aCx, args.length(), args.array(), Unwrap);
    1.93 +    if (NS_FAILED(rv)) {
    1.94 +      return Throw(aCx, rv);
    1.95 +    }
    1.96 +
    1.97 +    JSObject* obj = file::CreateBlob(aCx, file);
    1.98 +    if (!obj) {
    1.99 +      return false;
   1.100 +    }
   1.101 +
   1.102 +    args.rval().setObject(*obj);
   1.103 +    return true;
   1.104 +  }
   1.105 +
   1.106 +  static void
   1.107 +  Finalize(JSFreeOp* aFop, JSObject* aObj)
   1.108 +  {
   1.109 +    MOZ_ASSERT(JS_GetClass(aObj) == &sClass);
   1.110 +
   1.111 +    nsIDOMBlob* blob = GetPrivate(aObj);
   1.112 +    NS_IF_RELEASE(blob);
   1.113 +  }
   1.114 +
   1.115 +  static bool
   1.116 +  IsBlob(JS::Handle<JS::Value> v)
   1.117 +  {
   1.118 +    return v.isObject() && GetPrivate(&v.toObject()) != nullptr;
   1.119 +  }
   1.120 +
   1.121 +  static bool
   1.122 +  GetSizeImpl(JSContext* aCx, JS::CallArgs aArgs)
   1.123 +  {
   1.124 +    JS::Rooted<JSObject*> obj(aCx, &aArgs.thisv().toObject());
   1.125 +    nsIDOMBlob* blob = GetInstancePrivate(aCx, obj, "size");
   1.126 +    MOZ_ASSERT(blob);
   1.127 +
   1.128 +    uint64_t size;
   1.129 +    if (NS_FAILED(blob->GetSize(&size))) {
   1.130 +      return Throw(aCx, NS_ERROR_DOM_FILE_NOT_READABLE_ERR);
   1.131 +    }
   1.132 +
   1.133 +    aArgs.rval().setNumber(double(size));
   1.134 +    return true;
   1.135 +  }
   1.136 +
   1.137 +  static bool
   1.138 +  GetSize(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
   1.139 +  {
   1.140 +    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
   1.141 +    return JS::CallNonGenericMethod<IsBlob, GetSizeImpl>(aCx, args);
   1.142 +  }
   1.143 +
   1.144 +  static bool
   1.145 +  GetTypeImpl(JSContext* aCx, JS::CallArgs aArgs)
   1.146 +  {
   1.147 +    JS::Rooted<JSObject*> obj(aCx, &aArgs.thisv().toObject());
   1.148 +    nsIDOMBlob* blob = GetInstancePrivate(aCx, obj, "type");
   1.149 +    MOZ_ASSERT(blob);
   1.150 +
   1.151 +    nsString type;
   1.152 +    if (NS_FAILED(blob->GetType(type))) {
   1.153 +      return Throw(aCx, NS_ERROR_DOM_FILE_NOT_READABLE_ERR);
   1.154 +    }
   1.155 +
   1.156 +    JSString* jsType = JS_NewUCStringCopyN(aCx, type.get(), type.Length());
   1.157 +    if (!jsType) {
   1.158 +      return false;
   1.159 +    }
   1.160 +
   1.161 +    aArgs.rval().setString(jsType);
   1.162 +    return true;
   1.163 +  }
   1.164 +
   1.165 +  static bool
   1.166 +  GetType(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
   1.167 +  {
   1.168 +    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
   1.169 +    return JS::CallNonGenericMethod<IsBlob, GetTypeImpl>(aCx, args);
   1.170 +  }
   1.171 +
   1.172 +  static bool
   1.173 +  Slice(JSContext* aCx, unsigned aArgc, jsval* aVp)
   1.174 +  {
   1.175 +    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
   1.176 +
   1.177 +    JS::Rooted<JSObject*> obj(aCx, args.thisv().toObjectOrNull());
   1.178 +    if (!obj) {
   1.179 +      return false;
   1.180 +    }
   1.181 +
   1.182 +    nsIDOMBlob* blob = GetInstancePrivate(aCx, obj, "slice");
   1.183 +    if (!blob) {
   1.184 +      return false;
   1.185 +    }
   1.186 +
   1.187 +    double start = 0, end = 0;
   1.188 +    JS::Rooted<JSString*> jsContentType(aCx, JS_GetEmptyString(JS_GetRuntime(aCx)));
   1.189 +    if (!JS_ConvertArguments(aCx, args, "/IIS", &start,
   1.190 +                             &end, jsContentType.address())) {
   1.191 +      return false;
   1.192 +    }
   1.193 +
   1.194 +    nsDependentJSString contentType;
   1.195 +    if (!contentType.init(aCx, jsContentType)) {
   1.196 +      return false;
   1.197 +    }
   1.198 +
   1.199 +    uint8_t optionalArgc = aArgc;
   1.200 +    nsCOMPtr<nsIDOMBlob> rtnBlob;
   1.201 +    if (NS_FAILED(blob->Slice(static_cast<uint64_t>(start),
   1.202 +                              static_cast<uint64_t>(end),
   1.203 +                              contentType, optionalArgc,
   1.204 +                              getter_AddRefs(rtnBlob)))) {
   1.205 +      return Throw(aCx, NS_ERROR_DOM_FILE_NOT_READABLE_ERR);
   1.206 +    }
   1.207 +
   1.208 +    JSObject* rtnObj = file::CreateBlob(aCx, rtnBlob);
   1.209 +    if (!rtnObj) {
   1.210 +      return false;
   1.211 +    }
   1.212 +
   1.213 +    args.rval().setObject(*rtnObj);
   1.214 +    return true;
   1.215 +  }
   1.216 +};
   1.217 +
   1.218 +const JSClass Blob::sClass = {
   1.219 +  "Blob",
   1.220 +  JSCLASS_HAS_PRIVATE,
   1.221 +  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   1.222 +  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize
   1.223 +};
   1.224 +
   1.225 +const JSPropertySpec Blob::sProperties[] = {
   1.226 +  JS_PSGS("size", GetSize, GetterOnlyJSNative, JSPROP_ENUMERATE),
   1.227 +  JS_PSGS("type", GetType, GetterOnlyJSNative, JSPROP_ENUMERATE),
   1.228 +  JS_PS_END
   1.229 +};
   1.230 +
   1.231 +const JSFunctionSpec Blob::sFunctions[] = {
   1.232 +  JS_FN("slice", Slice, 1, JSPROP_ENUMERATE),
   1.233 +  JS_FS_END
   1.234 +};
   1.235 +
   1.236 +class File : public Blob
   1.237 +{
   1.238 +  // File should never be instantiated.
   1.239 +  File();
   1.240 +  ~File();
   1.241 +
   1.242 +  static const JSClass sClass;
   1.243 +  static const JSPropertySpec sProperties[];
   1.244 +
   1.245 +public:
   1.246 +  static JSObject*
   1.247 +  InitClass(JSContext* aCx, JS::Handle<JSObject*> aObj, JS::Handle<JSObject*> aParentProto)
   1.248 +  {
   1.249 +    return JS_InitClass(aCx, aObj, aParentProto, &sClass, Construct, 0,
   1.250 +                        sProperties, nullptr, nullptr, nullptr);
   1.251 +  }
   1.252 +
   1.253 +  static JSObject*
   1.254 +  Create(JSContext* aCx, nsIDOMFile* aFile)
   1.255 +  {
   1.256 +    MOZ_ASSERT(SameCOMIdentity(static_cast<nsISupports*>(aFile), aFile));
   1.257 +
   1.258 +    JSObject* obj = JS_NewObject(aCx, &sClass, JS::NullPtr(), JS::NullPtr());
   1.259 +    if (obj) {
   1.260 +      JS_SetPrivate(obj, aFile);
   1.261 +      NS_ADDREF(aFile);
   1.262 +    }
   1.263 +    return obj;
   1.264 +  }
   1.265 +
   1.266 +  static nsIDOMFile*
   1.267 +  GetPrivate(JSObject* aObj)
   1.268 +  {
   1.269 +    if (aObj) {
   1.270 +      const JSClass* classPtr = JS_GetClass(aObj);
   1.271 +      if (classPtr == &sClass) {
   1.272 +        nsISupports* priv = static_cast<nsISupports*>(JS_GetPrivate(aObj));
   1.273 +        nsCOMPtr<nsIDOMFile> file = do_QueryInterface(priv);
   1.274 +        MOZ_ASSERT_IF(priv, file);
   1.275 +        return file;
   1.276 +      }
   1.277 +    }
   1.278 +    return nullptr;
   1.279 +  }
   1.280 +
   1.281 +  static const JSClass*
   1.282 +  Class()
   1.283 +  {
   1.284 +    return &sClass;
   1.285 +  }
   1.286 +
   1.287 +private:
   1.288 +  static nsIDOMFile*
   1.289 +  GetInstancePrivate(JSContext* aCx, JS::Handle<JSObject*> aObj, const char* aFunctionName)
   1.290 +  {
   1.291 +    nsIDOMFile* file = GetPrivate(aObj);
   1.292 +    if (file) {
   1.293 +      return file;
   1.294 +    }
   1.295 +
   1.296 +    JS_ReportErrorNumber(aCx, js_GetErrorMessage, nullptr,
   1.297 +                         JSMSG_INCOMPATIBLE_PROTO, sClass.name, aFunctionName,
   1.298 +                         JS_GetClass(aObj)->name);
   1.299 +    return nullptr;
   1.300 +  }
   1.301 +
   1.302 +  static bool
   1.303 +  Construct(JSContext* aCx, unsigned aArgc, jsval* aVp)
   1.304 +  {
   1.305 +    JS_ReportErrorNumber(aCx, js_GetErrorMessage, nullptr,
   1.306 +                         JSMSG_WRONG_CONSTRUCTOR,
   1.307 +                         sClass.name);
   1.308 +    return false;
   1.309 +  }
   1.310 +
   1.311 +  static void
   1.312 +  Finalize(JSFreeOp* aFop, JSObject* aObj)
   1.313 +  {
   1.314 +    MOZ_ASSERT(JS_GetClass(aObj) == &sClass);
   1.315 +
   1.316 +    nsIDOMFile* file = GetPrivate(aObj);
   1.317 +    NS_IF_RELEASE(file);
   1.318 +  }
   1.319 +
   1.320 +  static bool
   1.321 +  IsFile(JS::Handle<JS::Value> v)
   1.322 +  {
   1.323 +    return v.isObject() && GetPrivate(&v.toObject()) != nullptr;
   1.324 +  }
   1.325 +
   1.326 +  static bool
   1.327 +  GetMozFullPathImpl(JSContext* aCx, JS::CallArgs aArgs)
   1.328 +  {
   1.329 +    JS::Rooted<JSObject*> obj(aCx, &aArgs.thisv().toObject());
   1.330 +    nsIDOMFile* file = GetInstancePrivate(aCx, obj, "mozFullPath");
   1.331 +    MOZ_ASSERT(file);
   1.332 +
   1.333 +    nsString fullPath;
   1.334 +
   1.335 +    if (GetWorkerPrivateFromContext(aCx)->UsesSystemPrincipal() &&
   1.336 +        NS_FAILED(file->GetMozFullPathInternal(fullPath))) {
   1.337 +      return Throw(aCx, NS_ERROR_DOM_FILE_NOT_READABLE_ERR);
   1.338 +    }
   1.339 +
   1.340 +    JSString* jsFullPath = JS_NewUCStringCopyN(aCx, fullPath.get(),
   1.341 +                                               fullPath.Length());
   1.342 +    if (!jsFullPath) {
   1.343 +      return false;
   1.344 +    }
   1.345 +
   1.346 +    aArgs.rval().setString(jsFullPath);
   1.347 +    return true;
   1.348 +  }
   1.349 +
   1.350 +  static bool
   1.351 +  GetMozFullPath(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
   1.352 +  {
   1.353 +    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
   1.354 +    return JS::CallNonGenericMethod<IsFile, GetMozFullPathImpl>(aCx, args);
   1.355 +  }
   1.356 +
   1.357 +  static bool
   1.358 +  GetNameImpl(JSContext* aCx, JS::CallArgs aArgs)
   1.359 +  {
   1.360 +    JS::Rooted<JSObject*> obj(aCx, &aArgs.thisv().toObject());
   1.361 +    nsIDOMFile* file = GetInstancePrivate(aCx, obj, "name");
   1.362 +    MOZ_ASSERT(file);
   1.363 +
   1.364 +    nsString name;
   1.365 +    if (NS_FAILED(file->GetName(name))) {
   1.366 +      name.Truncate();
   1.367 +    }
   1.368 +
   1.369 +    JSString* jsName = JS_NewUCStringCopyN(aCx, name.get(), name.Length());
   1.370 +    if (!jsName) {
   1.371 +      return false;
   1.372 +    }
   1.373 +
   1.374 +    aArgs.rval().setString(jsName);
   1.375 +    return true;
   1.376 +  }
   1.377 +
   1.378 +  static bool
   1.379 +  GetName(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
   1.380 +  {
   1.381 +    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
   1.382 +    return JS::CallNonGenericMethod<IsFile, GetNameImpl>(aCx, args);
   1.383 +  }
   1.384 +
   1.385 +  static bool
   1.386 +  GetPathImpl(JSContext* aCx, JS::CallArgs aArgs)
   1.387 +  {
   1.388 +    JS::Rooted<JSObject*> obj(aCx, &aArgs.thisv().toObject());
   1.389 +    nsIDOMFile* file = GetInstancePrivate(aCx, obj, "path");
   1.390 +    MOZ_ASSERT(file);
   1.391 +
   1.392 +    nsString path;
   1.393 +    if (NS_FAILED(file->GetPath(path))) {
   1.394 +      path.Truncate();
   1.395 +    }
   1.396 +
   1.397 +    JSString* jsPath = JS_NewUCStringCopyN(aCx, path.get(), path.Length());
   1.398 +    if (!jsPath) {
   1.399 +      return false;
   1.400 +    }
   1.401 +
   1.402 +    aArgs.rval().setString(jsPath);
   1.403 +    return true;
   1.404 +  }
   1.405 +
   1.406 +  static bool
   1.407 +  GetPath(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
   1.408 +  {
   1.409 +    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
   1.410 +    return JS::CallNonGenericMethod<IsFile, GetPathImpl>(aCx, args);
   1.411 +  }
   1.412 +
   1.413 +  static bool
   1.414 +  GetLastModifiedDateImpl(JSContext* aCx, JS::CallArgs aArgs)
   1.415 +  {
   1.416 +    JS::Rooted<JSObject*> obj(aCx, &aArgs.thisv().toObject());
   1.417 +    nsIDOMFile* file = GetInstancePrivate(aCx, obj, "lastModifiedDate");
   1.418 +    MOZ_ASSERT(file);
   1.419 +
   1.420 +    if (NS_FAILED(file->GetLastModifiedDate(aCx, aArgs.rval()))) {
   1.421 +      return false;
   1.422 +    }
   1.423 +    return true;
   1.424 +  }
   1.425 +
   1.426 +  static bool
   1.427 +  GetLastModifiedDate(JSContext* aCx, unsigned aArgc, JS::Value* aVp)
   1.428 +  {
   1.429 +    JS::CallArgs args = JS::CallArgsFromVp(aArgc, aVp);
   1.430 +    return JS::CallNonGenericMethod<IsFile, GetLastModifiedDateImpl>(aCx, args);
   1.431 +  }
   1.432 +};
   1.433 +
   1.434 +const JSClass File::sClass = {
   1.435 +  "File",
   1.436 +  JSCLASS_HAS_PRIVATE,
   1.437 +  JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   1.438 +  JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, Finalize
   1.439 +};
   1.440 +
   1.441 +const JSPropertySpec File::sProperties[] = {
   1.442 +  JS_PSGS("name", GetName, GetterOnlyJSNative, JSPROP_ENUMERATE),
   1.443 +  JS_PSGS("path", GetPath, GetterOnlyJSNative, JSPROP_ENUMERATE),
   1.444 +  JS_PSGS("lastModifiedDate", GetLastModifiedDate, GetterOnlyJSNative,
   1.445 +          JSPROP_ENUMERATE),
   1.446 +  JS_PSGS("mozFullPath", GetMozFullPath, GetterOnlyJSNative, JSPROP_ENUMERATE),
   1.447 +  JS_PS_END
   1.448 +};
   1.449 +
   1.450 +nsIDOMBlob*
   1.451 +Blob::GetPrivate(JSObject* aObj)
   1.452 +{
   1.453 +  if (aObj) {
   1.454 +    const JSClass* classPtr = JS_GetClass(aObj);
   1.455 +    if (classPtr == &sClass || classPtr == File::Class()) {
   1.456 +      nsISupports* priv = static_cast<nsISupports*>(JS_GetPrivate(aObj));
   1.457 +      nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(priv);
   1.458 +      MOZ_ASSERT_IF(priv, blob);
   1.459 +      return blob;
   1.460 +    }
   1.461 +  }
   1.462 +  return nullptr;
   1.463 +}
   1.464 +
   1.465 +} // anonymous namespace
   1.466 +
   1.467 +BEGIN_WORKERS_NAMESPACE
   1.468 +
   1.469 +namespace file {
   1.470 +
   1.471 +JSObject*
   1.472 +CreateBlob(JSContext* aCx, nsIDOMBlob* aBlob)
   1.473 +{
   1.474 +  return Blob::Create(aCx, aBlob);
   1.475 +}
   1.476 +
   1.477 +bool
   1.478 +InitClasses(JSContext* aCx, JS::Handle<JSObject*> aGlobal)
   1.479 +{
   1.480 +  JS::Rooted<JSObject*> blobProto(aCx, Blob::InitClass(aCx, aGlobal));
   1.481 +  return blobProto && File::InitClass(aCx, aGlobal, blobProto);
   1.482 +}
   1.483 +
   1.484 +nsIDOMBlob*
   1.485 +GetDOMBlobFromJSObject(JSObject* aObj)
   1.486 +{
   1.487 +  return Blob::GetPrivate(aObj);
   1.488 +}
   1.489 +
   1.490 +JSObject*
   1.491 +CreateFile(JSContext* aCx, nsIDOMFile* aFile)
   1.492 +{
   1.493 +  return File::Create(aCx, aFile);
   1.494 +}
   1.495 +
   1.496 +nsIDOMFile*
   1.497 +GetDOMFileFromJSObject(JSObject* aObj)
   1.498 +{
   1.499 +  return File::GetPrivate(aObj);
   1.500 +}
   1.501 +
   1.502 +} // namespace file
   1.503 +
   1.504 +END_WORKERS_NAMESPACE

mercurial