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