1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/xpconnect/src/XPCConvert.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1878 @@ 1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* vim: set ts=8 sts=4 et sw=4 tw=99: */ 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 +/* Data conversion between native and JavaScript types. */ 1.11 + 1.12 +#include "mozilla/ArrayUtils.h" 1.13 + 1.14 +#include "xpcprivate.h" 1.15 +#include "nsIAtom.h" 1.16 +#include "nsWrapperCache.h" 1.17 +#include "nsJSUtils.h" 1.18 +#include "WrapperFactory.h" 1.19 + 1.20 +#include "nsWrapperCacheInlines.h" 1.21 + 1.22 +#include "jsapi.h" 1.23 +#include "jsfriendapi.h" 1.24 +#include "jsprf.h" 1.25 +#include "JavaScriptParent.h" 1.26 + 1.27 +#include "mozilla/dom/BindingUtils.h" 1.28 +#include "mozilla/dom/DOMException.h" 1.29 +#include "mozilla/dom/PrimitiveConversions.h" 1.30 + 1.31 +using namespace xpc; 1.32 +using namespace mozilla; 1.33 +using namespace mozilla::dom; 1.34 +using namespace JS; 1.35 + 1.36 +//#define STRICT_CHECK_OF_UNICODE 1.37 +#ifdef STRICT_CHECK_OF_UNICODE 1.38 +#define ILLEGAL_RANGE(c) (0!=((c) & 0xFF80)) 1.39 +#else // STRICT_CHECK_OF_UNICODE 1.40 +#define ILLEGAL_RANGE(c) (0!=((c) & 0xFF00)) 1.41 +#endif // STRICT_CHECK_OF_UNICODE 1.42 + 1.43 +#define ILLEGAL_CHAR_RANGE(c) (0!=((c) & 0x80)) 1.44 + 1.45 +/***********************************************************/ 1.46 + 1.47 +// static 1.48 +bool 1.49 +XPCConvert::IsMethodReflectable(const XPTMethodDescriptor& info) 1.50 +{ 1.51 + if (XPT_MD_IS_NOTXPCOM(info.flags) || XPT_MD_IS_HIDDEN(info.flags)) 1.52 + return false; 1.53 + 1.54 + for (int i = info.num_args-1; i >= 0; i--) { 1.55 + const nsXPTParamInfo& param = info.params[i]; 1.56 + const nsXPTType& type = param.GetType(); 1.57 + 1.58 + // Reflected methods can't use native types. All native types end up 1.59 + // getting tagged as void*, so this check is easy. 1.60 + if (type.TagPart() == nsXPTType::T_VOID) 1.61 + return false; 1.62 + } 1.63 + return true; 1.64 +} 1.65 + 1.66 +static JSObject* 1.67 +UnwrapNativeCPOW(nsISupports* wrapper) 1.68 +{ 1.69 + nsCOMPtr<nsIXPConnectWrappedJS> underware = do_QueryInterface(wrapper); 1.70 + if (underware) { 1.71 + JSObject* mainObj = underware->GetJSObject(); 1.72 + if (mainObj && mozilla::jsipc::JavaScriptParent::IsCPOW(mainObj)) 1.73 + return mainObj; 1.74 + } 1.75 + return nullptr; 1.76 +} 1.77 + 1.78 +/***************************************************************************/ 1.79 + 1.80 +// static 1.81 +bool 1.82 +XPCConvert::GetISupportsFromJSObject(JSObject* obj, nsISupports** iface) 1.83 +{ 1.84 + const JSClass* jsclass = js::GetObjectJSClass(obj); 1.85 + MOZ_ASSERT(jsclass, "obj has no class"); 1.86 + if (jsclass && 1.87 + (jsclass->flags & JSCLASS_HAS_PRIVATE) && 1.88 + (jsclass->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS)) { 1.89 + *iface = (nsISupports*) xpc_GetJSPrivate(obj); 1.90 + return true; 1.91 + } 1.92 + *iface = UnwrapDOMObjectToISupports(obj); 1.93 + return !!*iface; 1.94 +} 1.95 + 1.96 +/***************************************************************************/ 1.97 + 1.98 +// static 1.99 +bool 1.100 +XPCConvert::NativeData2JS(MutableHandleValue d, const void* s, 1.101 + const nsXPTType& type, const nsID* iid, nsresult* pErr) 1.102 +{ 1.103 + NS_PRECONDITION(s, "bad param"); 1.104 + 1.105 + AutoJSContext cx; 1.106 + if (pErr) 1.107 + *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE; 1.108 + 1.109 + switch (type.TagPart()) { 1.110 + case nsXPTType::T_I8 : 1.111 + d.setInt32(*static_cast<const int8_t*>(s)); 1.112 + return true; 1.113 + case nsXPTType::T_I16 : 1.114 + d.setInt32(*static_cast<const int16_t*>(s)); 1.115 + return true; 1.116 + case nsXPTType::T_I32 : 1.117 + d.setInt32(*static_cast<const int32_t*>(s)); 1.118 + return true; 1.119 + case nsXPTType::T_I64 : 1.120 + d.setNumber(static_cast<double>(*static_cast<const int64_t*>(s))); 1.121 + return true; 1.122 + case nsXPTType::T_U8 : 1.123 + d.setInt32(*static_cast<const uint8_t*>(s)); 1.124 + return true; 1.125 + case nsXPTType::T_U16 : 1.126 + d.setInt32(*static_cast<const uint16_t*>(s)); 1.127 + return true; 1.128 + case nsXPTType::T_U32 : 1.129 + d.setNumber(*static_cast<const uint32_t*>(s)); 1.130 + return true; 1.131 + case nsXPTType::T_U64 : 1.132 + d.setNumber(static_cast<double>(*static_cast<const uint64_t*>(s))); 1.133 + return true; 1.134 + case nsXPTType::T_FLOAT : 1.135 + d.setNumber(*static_cast<const float*>(s)); 1.136 + return true; 1.137 + case nsXPTType::T_DOUBLE: 1.138 + d.setNumber(*static_cast<const double*>(s)); 1.139 + return true; 1.140 + case nsXPTType::T_BOOL : 1.141 + d.setBoolean(*static_cast<const bool*>(s)); 1.142 + return true; 1.143 + case nsXPTType::T_CHAR : 1.144 + { 1.145 + char p = *static_cast<const char*>(s); 1.146 + 1.147 +#ifdef STRICT_CHECK_OF_UNICODE 1.148 + MOZ_ASSERT(! ILLEGAL_CHAR_RANGE(p) , "passing non ASCII data"); 1.149 +#endif // STRICT_CHECK_OF_UNICODE 1.150 + 1.151 + JSString* str = JS_NewStringCopyN(cx, &p, 1); 1.152 + if (!str) 1.153 + return false; 1.154 + 1.155 + d.setString(str); 1.156 + return true; 1.157 + } 1.158 + case nsXPTType::T_WCHAR : 1.159 + { 1.160 + jschar p = *static_cast<const jschar*>(s); 1.161 + 1.162 + JSString* str = JS_NewUCStringCopyN(cx, &p, 1); 1.163 + if (!str) 1.164 + return false; 1.165 + 1.166 + d.setString(str); 1.167 + return true; 1.168 + } 1.169 + 1.170 + case nsXPTType::T_JSVAL : 1.171 + { 1.172 + d.set(*static_cast<const Value*>(s)); 1.173 + return JS_WrapValue(cx, d); 1.174 + } 1.175 + 1.176 + case nsXPTType::T_VOID: 1.177 + XPC_LOG_ERROR(("XPCConvert::NativeData2JS : void* params not supported")); 1.178 + return false; 1.179 + 1.180 + case nsXPTType::T_IID: 1.181 + { 1.182 + nsID* iid2 = *static_cast<nsID* const *>(s); 1.183 + if (!iid2) { 1.184 + d.setNull(); 1.185 + return true; 1.186 + } 1.187 + 1.188 + RootedObject scope(cx, JS::CurrentGlobalOrNull(cx)); 1.189 + JSObject* obj = xpc_NewIDObject(cx, scope, *iid2); 1.190 + if (!obj) 1.191 + return false; 1.192 + 1.193 + d.setObject(*obj); 1.194 + return true; 1.195 + } 1.196 + 1.197 + case nsXPTType::T_ASTRING: 1.198 + // Fall through to T_DOMSTRING case 1.199 + 1.200 + case nsXPTType::T_DOMSTRING: 1.201 + { 1.202 + const nsAString* p = *static_cast<const nsAString* const *>(s); 1.203 + if (!p || p->IsVoid()) { 1.204 + d.setNull(); 1.205 + return true; 1.206 + } 1.207 + 1.208 + nsStringBuffer* buf; 1.209 + if (!XPCStringConvert::ReadableToJSVal(cx, *p, &buf, d)) 1.210 + return false; 1.211 + if (buf) 1.212 + buf->AddRef(); 1.213 + return true; 1.214 + } 1.215 + 1.216 + case nsXPTType::T_CHAR_STR: 1.217 + { 1.218 + const char* p = *static_cast<const char* const *>(s); 1.219 + if (!p) { 1.220 + d.setNull(); 1.221 + return true; 1.222 + } 1.223 + 1.224 +#ifdef STRICT_CHECK_OF_UNICODE 1.225 + bool isAscii = true; 1.226 + for (char* t = p; *t && isAscii; t++) { 1.227 + if (ILLEGAL_CHAR_RANGE(*t)) 1.228 + isAscii = false; 1.229 + } 1.230 + MOZ_ASSERT(isAscii, "passing non ASCII data"); 1.231 +#endif // STRICT_CHECK_OF_UNICODE 1.232 + 1.233 + JSString* str = JS_NewStringCopyZ(cx, p); 1.234 + if (!str) 1.235 + return false; 1.236 + 1.237 + d.setString(str); 1.238 + return true; 1.239 + } 1.240 + 1.241 + case nsXPTType::T_WCHAR_STR: 1.242 + { 1.243 + const jschar* p = *static_cast<const jschar* const *>(s); 1.244 + if (!p) { 1.245 + d.setNull(); 1.246 + return true; 1.247 + } 1.248 + 1.249 + JSString* str = JS_NewUCStringCopyZ(cx, p); 1.250 + if (!str) 1.251 + return false; 1.252 + 1.253 + d.setString(str); 1.254 + return true; 1.255 + } 1.256 + case nsXPTType::T_UTF8STRING: 1.257 + { 1.258 + const nsACString* utf8String = *static_cast<const nsACString* const *>(s); 1.259 + 1.260 + if (!utf8String || utf8String->IsVoid()) { 1.261 + d.setNull(); 1.262 + return true; 1.263 + } 1.264 + 1.265 + if (utf8String->IsEmpty()) { 1.266 + d.set(JS_GetEmptyStringValue(cx)); 1.267 + return true; 1.268 + } 1.269 + 1.270 + const uint32_t len = CalcUTF8ToUnicodeLength(*utf8String); 1.271 + // The cString is not empty at this point, but the calculated 1.272 + // UTF-16 length is zero, meaning no valid conversion exists. 1.273 + if (!len) 1.274 + return false; 1.275 + 1.276 + const size_t buffer_size = (len + 1) * sizeof(char16_t); 1.277 + char16_t* buffer = 1.278 + static_cast<char16_t*>(JS_malloc(cx, buffer_size)); 1.279 + if (!buffer) 1.280 + return false; 1.281 + 1.282 + uint32_t copied; 1.283 + if (!UTF8ToUnicodeBuffer(*utf8String, buffer, &copied) || 1.284 + len != copied) { 1.285 + // Copy or conversion during copy failed. Did not copy the 1.286 + // whole string. 1.287 + JS_free(cx, buffer); 1.288 + return false; 1.289 + } 1.290 + 1.291 + // JS_NewUCString takes ownership on success, i.e. a 1.292 + // successful call will make it the responsiblity of the JS VM 1.293 + // to free the buffer. 1.294 + JSString* str = JS_NewUCString(cx, buffer, len); 1.295 + if (!str) { 1.296 + JS_free(cx, buffer); 1.297 + return false; 1.298 + } 1.299 + 1.300 + d.setString(str); 1.301 + return true; 1.302 + } 1.303 + case nsXPTType::T_CSTRING: 1.304 + { 1.305 + const nsACString* cString = *static_cast<const nsACString* const *>(s); 1.306 + 1.307 + if (!cString || cString->IsVoid()) { 1.308 + d.setNull(); 1.309 + return true; 1.310 + } 1.311 + 1.312 + // c-strings (binary blobs) are deliberately not converted from 1.313 + // UTF-8 to UTF-16. T_UTF8Sting is for UTF-8 encoded strings 1.314 + // with automatic conversion. 1.315 + JSString* str = JS_NewStringCopyN(cx, cString->Data(), 1.316 + cString->Length()); 1.317 + if (!str) 1.318 + return false; 1.319 + 1.320 + d.setString(str); 1.321 + return true; 1.322 + } 1.323 + 1.324 + case nsXPTType::T_INTERFACE: 1.325 + case nsXPTType::T_INTERFACE_IS: 1.326 + { 1.327 + nsISupports* iface = *static_cast<nsISupports* const *>(s); 1.328 + if (!iface) { 1.329 + d.setNull(); 1.330 + return true; 1.331 + } 1.332 + 1.333 + if (iid->Equals(NS_GET_IID(nsIVariant))) { 1.334 + nsCOMPtr<nsIVariant> variant = do_QueryInterface(iface); 1.335 + if (!variant) 1.336 + return false; 1.337 + 1.338 + return XPCVariant::VariantDataToJS(variant, 1.339 + pErr, d); 1.340 + } 1.341 + 1.342 + xpcObjectHelper helper(iface); 1.343 + return NativeInterface2JSObject(d, nullptr, helper, iid, nullptr, true, pErr); 1.344 + } 1.345 + 1.346 + default: 1.347 + NS_ERROR("bad type"); 1.348 + return false; 1.349 + } 1.350 + return true; 1.351 +} 1.352 + 1.353 +/***************************************************************************/ 1.354 + 1.355 +#ifdef DEBUG 1.356 +static bool 1.357 +CheckJSCharInCharRange(jschar c) 1.358 +{ 1.359 + if (ILLEGAL_RANGE(c)) { 1.360 + /* U+0080/U+0100 - U+FFFF data lost. */ 1.361 + static const size_t MSG_BUF_SIZE = 64; 1.362 + char msg[MSG_BUF_SIZE]; 1.363 + JS_snprintf(msg, MSG_BUF_SIZE, "jschar out of char range; high bits of data lost: 0x%x", c); 1.364 + NS_WARNING(msg); 1.365 + return false; 1.366 + } 1.367 + 1.368 + return true; 1.369 +} 1.370 +#endif 1.371 + 1.372 +template<typename T> 1.373 +bool ConvertToPrimitive(JSContext *cx, HandleValue v, T *retval) 1.374 +{ 1.375 + return ValueToPrimitive<T, eDefault>(cx, v, retval); 1.376 +} 1.377 + 1.378 +// static 1.379 +bool 1.380 +XPCConvert::JSData2Native(void* d, HandleValue s, 1.381 + const nsXPTType& type, 1.382 + bool useAllocator, const nsID* iid, 1.383 + nsresult* pErr) 1.384 +{ 1.385 + NS_PRECONDITION(d, "bad param"); 1.386 + 1.387 + AutoJSContext cx; 1.388 + if (pErr) 1.389 + *pErr = NS_ERROR_XPC_BAD_CONVERT_JS; 1.390 + 1.391 + switch (type.TagPart()) { 1.392 + case nsXPTType::T_I8 : 1.393 + return ConvertToPrimitive(cx, s, static_cast<int8_t*>(d)); 1.394 + case nsXPTType::T_I16 : 1.395 + return ConvertToPrimitive(cx, s, static_cast<int16_t*>(d)); 1.396 + case nsXPTType::T_I32 : 1.397 + return ConvertToPrimitive(cx, s, static_cast<int32_t*>(d)); 1.398 + case nsXPTType::T_I64 : 1.399 + return ConvertToPrimitive(cx, s, static_cast<int64_t*>(d)); 1.400 + case nsXPTType::T_U8 : 1.401 + return ConvertToPrimitive(cx, s, static_cast<uint8_t*>(d)); 1.402 + case nsXPTType::T_U16 : 1.403 + return ConvertToPrimitive(cx, s, static_cast<uint16_t*>(d)); 1.404 + case nsXPTType::T_U32 : 1.405 + return ConvertToPrimitive(cx, s, static_cast<uint32_t*>(d)); 1.406 + case nsXPTType::T_U64 : 1.407 + return ConvertToPrimitive(cx, s, static_cast<uint64_t*>(d)); 1.408 + case nsXPTType::T_FLOAT : 1.409 + return ConvertToPrimitive(cx, s, static_cast<float*>(d)); 1.410 + case nsXPTType::T_DOUBLE : 1.411 + return ConvertToPrimitive(cx, s, static_cast<double*>(d)); 1.412 + case nsXPTType::T_BOOL : 1.413 + return ConvertToPrimitive(cx, s, static_cast<bool*>(d)); 1.414 + case nsXPTType::T_CHAR : 1.415 + { 1.416 + JSString* str = ToString(cx, s); 1.417 + if (!str) { 1.418 + return false; 1.419 + } 1.420 + size_t length; 1.421 + const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length); 1.422 + if (!chars) { 1.423 + return false; 1.424 + } 1.425 + jschar ch = length ? chars[0] : 0; 1.426 +#ifdef DEBUG 1.427 + CheckJSCharInCharRange(ch); 1.428 +#endif 1.429 + *((char*)d) = char(ch); 1.430 + break; 1.431 + } 1.432 + case nsXPTType::T_WCHAR : 1.433 + { 1.434 + JSString* str; 1.435 + if (!(str = ToString(cx, s))) { 1.436 + return false; 1.437 + } 1.438 + size_t length; 1.439 + const jschar* chars = JS_GetStringCharsAndLength(cx, str, &length); 1.440 + if (!chars) { 1.441 + return false; 1.442 + } 1.443 + if (length == 0) { 1.444 + *((uint16_t*)d) = 0; 1.445 + break; 1.446 + } 1.447 + *((uint16_t*)d) = uint16_t(chars[0]); 1.448 + break; 1.449 + } 1.450 + case nsXPTType::T_JSVAL : 1.451 + *((jsval*)d) = s; 1.452 + break; 1.453 + case nsXPTType::T_VOID: 1.454 + XPC_LOG_ERROR(("XPCConvert::JSData2Native : void* params not supported")); 1.455 + NS_ERROR("void* params not supported"); 1.456 + return false; 1.457 + case nsXPTType::T_IID: 1.458 + { 1.459 + const nsID* pid = nullptr; 1.460 + 1.461 + // There's no good reason to pass a null IID. 1.462 + if (s.isNullOrUndefined()) { 1.463 + if (pErr) 1.464 + *pErr = NS_ERROR_XPC_BAD_CONVERT_JS; 1.465 + return false; 1.466 + } 1.467 + 1.468 + if (!s.isObject() || 1.469 + (!(pid = xpc_JSObjectToID(cx, &s.toObject()))) || 1.470 + (!(pid = (const nsID*) nsMemory::Clone(pid, sizeof(nsID))))) { 1.471 + return false; 1.472 + } 1.473 + *((const nsID**)d) = pid; 1.474 + return true; 1.475 + } 1.476 + 1.477 + case nsXPTType::T_ASTRING: 1.478 + { 1.479 + if (JSVAL_IS_VOID(s)) { 1.480 + if (useAllocator) 1.481 + *((const nsAString**)d) = &NullString(); 1.482 + else 1.483 + (**((nsAString**)d)).SetIsVoid(true); 1.484 + return true; 1.485 + } 1.486 + // Fall through to T_DOMSTRING case. 1.487 + } 1.488 + case nsXPTType::T_DOMSTRING: 1.489 + { 1.490 + if (JSVAL_IS_NULL(s)) { 1.491 + if (useAllocator) 1.492 + *((const nsAString**)d) = &NullString(); 1.493 + else 1.494 + (**((nsAString**)d)).SetIsVoid(true); 1.495 + return true; 1.496 + } 1.497 + size_t length = 0; 1.498 + const char16_t* chars = nullptr; 1.499 + JSString* str = nullptr; 1.500 + if (!JSVAL_IS_VOID(s)) { 1.501 + str = ToString(cx, s); 1.502 + if (!str) 1.503 + return false; 1.504 + 1.505 + chars = useAllocator ? JS_GetStringCharsZAndLength(cx, str, &length) 1.506 + : JS_GetStringCharsAndLength(cx, str, &length); 1.507 + if (!chars) 1.508 + return false; 1.509 + 1.510 + if (!length) { 1.511 + if (useAllocator) 1.512 + *((const nsAString**)d) = &EmptyString(); 1.513 + else 1.514 + (**((nsAString**)d)).Truncate(); 1.515 + return true; 1.516 + } 1.517 + } 1.518 + 1.519 + nsString* ws; 1.520 + if (useAllocator) { 1.521 + ws = nsXPConnect::GetRuntimeInstance()->NewShortLivedString(); 1.522 + *((const nsString**)d) = ws; 1.523 + } else { 1.524 + ws = *((nsString**)d); 1.525 + } 1.526 + 1.527 + if (!str) { 1.528 + ws->AssignLiteral(MOZ_UTF16("undefined")); 1.529 + } else if (XPCStringConvert::IsDOMString(str)) { 1.530 + // The characters represent an existing nsStringBuffer that 1.531 + // was shared by XPCStringConvert::ReadableToJSVal. 1.532 + nsStringBuffer::FromData((void *)chars)->ToString(length, *ws); 1.533 + } else if (XPCStringConvert::IsLiteral(str)) { 1.534 + // The characters represent a literal char16_t string constant 1.535 + // compiled into libxul, such as the string "undefined" above. 1.536 + ws->AssignLiteral(chars, length); 1.537 + } else if (useAllocator && STRING_TO_JSVAL(str) == s) { 1.538 + // The JS string will exist over the function call. 1.539 + // We don't need to copy the characters in this case. 1.540 + ws->Rebind(chars, length); 1.541 + } else { 1.542 + ws->Assign(chars, length); 1.543 + } 1.544 + return true; 1.545 + } 1.546 + 1.547 + case nsXPTType::T_CHAR_STR: 1.548 + { 1.549 + if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) { 1.550 + *((char**)d) = nullptr; 1.551 + return true; 1.552 + } 1.553 + 1.554 + JSString* str = ToString(cx, s); 1.555 + if (!str) { 1.556 + return false; 1.557 + } 1.558 +#ifdef DEBUG 1.559 + const jschar* chars=nullptr; 1.560 + if (nullptr != (chars = JS_GetStringCharsZ(cx, str))) { 1.561 + bool legalRange = true; 1.562 + int len = JS_GetStringLength(str); 1.563 + const jschar* t; 1.564 + int32_t i=0; 1.565 + for (t=chars; (i< len) && legalRange ; i++,t++) { 1.566 + if (!CheckJSCharInCharRange(*t)) 1.567 + break; 1.568 + } 1.569 + } 1.570 +#endif // DEBUG 1.571 + size_t length = JS_GetStringEncodingLength(cx, str); 1.572 + if (length == size_t(-1)) { 1.573 + return false; 1.574 + } 1.575 + char *buffer = static_cast<char *>(nsMemory::Alloc(length + 1)); 1.576 + if (!buffer) { 1.577 + return false; 1.578 + } 1.579 + JS_EncodeStringToBuffer(cx, str, buffer, length); 1.580 + buffer[length] = '\0'; 1.581 + *((void**)d) = buffer; 1.582 + return true; 1.583 + } 1.584 + 1.585 + case nsXPTType::T_WCHAR_STR: 1.586 + { 1.587 + const jschar* chars=nullptr; 1.588 + JSString* str; 1.589 + 1.590 + if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) { 1.591 + *((jschar**)d) = nullptr; 1.592 + return true; 1.593 + } 1.594 + 1.595 + if (!(str = ToString(cx, s))) { 1.596 + return false; 1.597 + } 1.598 + if (!(chars = JS_GetStringCharsZ(cx, str))) { 1.599 + return false; 1.600 + } 1.601 + int len = JS_GetStringLength(str); 1.602 + int byte_len = (len+1)*sizeof(jschar); 1.603 + if (!(*((void**)d) = nsMemory::Alloc(byte_len))) { 1.604 + // XXX should report error 1.605 + return false; 1.606 + } 1.607 + jschar* destchars = *((jschar**)d); 1.608 + memcpy(destchars, chars, byte_len); 1.609 + destchars[len] = 0; 1.610 + 1.611 + return true; 1.612 + } 1.613 + 1.614 + case nsXPTType::T_UTF8STRING: 1.615 + { 1.616 + const jschar* chars; 1.617 + size_t length; 1.618 + JSString* str; 1.619 + 1.620 + if (JSVAL_IS_NULL(s) || JSVAL_IS_VOID(s)) { 1.621 + if (useAllocator) { 1.622 + *((const nsACString**)d) = &NullCString(); 1.623 + } else { 1.624 + nsCString* rs = *((nsCString**)d); 1.625 + rs->SetIsVoid(true); 1.626 + } 1.627 + return true; 1.628 + } 1.629 + 1.630 + // The JS val is neither null nor void... 1.631 + 1.632 + if (!(str = ToString(cx, s))|| 1.633 + !(chars = JS_GetStringCharsAndLength(cx, str, &length))) { 1.634 + return false; 1.635 + } 1.636 + 1.637 + if (!length) { 1.638 + if (useAllocator) { 1.639 + *((const nsACString**)d) = &EmptyCString(); 1.640 + } else { 1.641 + nsCString* rs = *((nsCString**)d); 1.642 + rs->Truncate(); 1.643 + } 1.644 + return true; 1.645 + } 1.646 + 1.647 + nsCString *rs; 1.648 + if (useAllocator) { 1.649 + // Use nsCString to enable sharing 1.650 + rs = new nsCString(); 1.651 + if (!rs) 1.652 + return false; 1.653 + 1.654 + *((const nsCString**)d) = rs; 1.655 + } else { 1.656 + rs = *((nsCString**)d); 1.657 + } 1.658 + CopyUTF16toUTF8(Substring(chars, length), *rs); 1.659 + return true; 1.660 + } 1.661 + 1.662 + case nsXPTType::T_CSTRING: 1.663 + { 1.664 + if (JSVAL_IS_NULL(s) || JSVAL_IS_VOID(s)) { 1.665 + if (useAllocator) { 1.666 + nsACString *rs = new nsCString(); 1.667 + if (!rs) 1.668 + return false; 1.669 + 1.670 + rs->SetIsVoid(true); 1.671 + *((nsACString**)d) = rs; 1.672 + } else { 1.673 + nsACString* rs = *((nsACString**)d); 1.674 + rs->Truncate(); 1.675 + rs->SetIsVoid(true); 1.676 + } 1.677 + return true; 1.678 + } 1.679 + 1.680 + // The JS val is neither null nor void... 1.681 + JSString* str = ToString(cx, s); 1.682 + if (!str) { 1.683 + return false; 1.684 + } 1.685 + 1.686 + size_t length = JS_GetStringEncodingLength(cx, str); 1.687 + if (length == size_t(-1)) { 1.688 + return false; 1.689 + } 1.690 + 1.691 + if (!length) { 1.692 + if (useAllocator) { 1.693 + *((const nsACString**)d) = &EmptyCString(); 1.694 + } else { 1.695 + nsCString* rs = *((nsCString**)d); 1.696 + rs->Truncate(); 1.697 + } 1.698 + return true; 1.699 + } 1.700 + 1.701 + nsACString *rs; 1.702 + if (useAllocator) { 1.703 + rs = new nsCString(); 1.704 + if (!rs) 1.705 + return false; 1.706 + *((const nsACString**)d) = rs; 1.707 + } else { 1.708 + rs = *((nsACString**)d); 1.709 + } 1.710 + 1.711 + rs->SetLength(uint32_t(length)); 1.712 + if (rs->Length() != uint32_t(length)) { 1.713 + return false; 1.714 + } 1.715 + JS_EncodeStringToBuffer(cx, str, rs->BeginWriting(), length); 1.716 + 1.717 + return true; 1.718 + } 1.719 + 1.720 + case nsXPTType::T_INTERFACE: 1.721 + case nsXPTType::T_INTERFACE_IS: 1.722 + { 1.723 + MOZ_ASSERT(iid,"can't do interface conversions without iid"); 1.724 + 1.725 + if (iid->Equals(NS_GET_IID(nsIVariant))) { 1.726 + nsCOMPtr<nsIVariant> variant = XPCVariant::newVariant(cx, s); 1.727 + if (!variant) 1.728 + return false; 1.729 + 1.730 + variant.forget(static_cast<nsISupports**>(d)); 1.731 + return true; 1.732 + } else if (iid->Equals(NS_GET_IID(nsIAtom)) && 1.733 + JSVAL_IS_STRING(s)) { 1.734 + // We're trying to pass a string as an nsIAtom. Let's atomize! 1.735 + JSString* str = JSVAL_TO_STRING(s); 1.736 + const char16_t* chars = JS_GetStringCharsZ(cx, str); 1.737 + if (!chars) { 1.738 + if (pErr) 1.739 + *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_NULL_REF; 1.740 + return false; 1.741 + } 1.742 + uint32_t length = JS_GetStringLength(str); 1.743 + nsCOMPtr<nsIAtom> atom = 1.744 + NS_NewAtom(nsDependentSubstring(chars, chars + length)); 1.745 + atom.forget((nsISupports**)d); 1.746 + return true; 1.747 + } 1.748 + //else ... 1.749 + 1.750 + if (s.isNullOrUndefined()) { 1.751 + *((nsISupports**)d) = nullptr; 1.752 + return true; 1.753 + } 1.754 + 1.755 + // only wrap JSObjects 1.756 + if (!s.isObject()) { 1.757 + if (pErr && s.isInt32() && 0 == s.toInt32()) 1.758 + *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_ZERO_ISNOT_NULL; 1.759 + return false; 1.760 + } 1.761 + 1.762 + RootedObject src(cx, &s.toObject()); 1.763 + return JSObject2NativeInterface((void**)d, src, iid, nullptr, pErr); 1.764 + } 1.765 + default: 1.766 + NS_ERROR("bad type"); 1.767 + return false; 1.768 + } 1.769 + return true; 1.770 +} 1.771 + 1.772 +static inline bool 1.773 +CreateHolderIfNeeded(HandleObject obj, MutableHandleValue d, 1.774 + nsIXPConnectJSObjectHolder** dest) 1.775 +{ 1.776 + if (dest) { 1.777 + nsRefPtr<XPCJSObjectHolder> objHolder = XPCJSObjectHolder::newHolder(obj); 1.778 + if (!objHolder) 1.779 + return false; 1.780 + 1.781 + objHolder.forget(dest); 1.782 + } 1.783 + 1.784 + d.setObjectOrNull(obj); 1.785 + 1.786 + return true; 1.787 +} 1.788 + 1.789 +/***************************************************************************/ 1.790 +// static 1.791 +bool 1.792 +XPCConvert::NativeInterface2JSObject(MutableHandleValue d, 1.793 + nsIXPConnectJSObjectHolder** dest, 1.794 + xpcObjectHelper& aHelper, 1.795 + const nsID* iid, 1.796 + XPCNativeInterface** Interface, 1.797 + bool allowNativeWrapper, 1.798 + nsresult* pErr) 1.799 +{ 1.800 + MOZ_ASSERT_IF(Interface, iid); 1.801 + if (!iid) 1.802 + iid = &NS_GET_IID(nsISupports); 1.803 + 1.804 + d.setNull(); 1.805 + if (dest) 1.806 + *dest = nullptr; 1.807 + if (!aHelper.Object()) 1.808 + return true; 1.809 + if (pErr) 1.810 + *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE; 1.811 + 1.812 + // We used to have code here that unwrapped and simply exposed the 1.813 + // underlying JSObject. That caused anomolies when JSComponents were 1.814 + // accessed from other JS code - they didn't act like other xpconnect 1.815 + // wrapped components. So, instead, we create "double wrapped" objects 1.816 + // (that means an XPCWrappedNative around an nsXPCWrappedJS). This isn't 1.817 + // optimal -- we could detect this and roll the functionality into a 1.818 + // single wrapper, but the current solution is good enough for now. 1.819 + AutoJSContext cx; 1.820 + XPCWrappedNativeScope* xpcscope = GetObjectScope(JS::CurrentGlobalOrNull(cx)); 1.821 + if (!xpcscope) 1.822 + return false; 1.823 + 1.824 + // First, see if this object supports the wrapper cache. 1.825 + // Note: If |cache->IsDOMBinding()| is true, then it means that the object 1.826 + // implementing it doesn't want a wrapped native as its JS Object, but 1.827 + // instead it provides its own proxy object. In that case, the object 1.828 + // to use is found as cache->GetWrapper(). If that is null, then the 1.829 + // object will create (and fill the cache) from its WrapObject call. 1.830 + nsWrapperCache *cache = aHelper.GetWrapperCache(); 1.831 + 1.832 + RootedObject flat(cx, cache ? cache->GetWrapper() : nullptr); 1.833 + if (!flat && cache && cache->IsDOMBinding()) { 1.834 + RootedObject global(cx, xpcscope->GetGlobalJSObject()); 1.835 + js::AssertSameCompartment(cx, global); 1.836 + flat = cache->WrapObject(cx); 1.837 + if (!flat) 1.838 + return false; 1.839 + } 1.840 + if (flat) { 1.841 + if (allowNativeWrapper && !JS_WrapObject(cx, &flat)) 1.842 + return false; 1.843 + return CreateHolderIfNeeded(flat, d, dest); 1.844 + } 1.845 + 1.846 + // Don't double wrap CPOWs. This is a temporary measure for compatibility 1.847 + // with objects that don't provide necessary QIs (such as objects under 1.848 + // the new DOM bindings). We expect the other side of the CPOW to have 1.849 + // the appropriate wrappers in place. 1.850 + RootedObject cpow(cx, UnwrapNativeCPOW(aHelper.Object())); 1.851 + if (cpow) { 1.852 + if (!JS_WrapObject(cx, &cpow)) 1.853 + return false; 1.854 + d.setObject(*cpow); 1.855 + return true; 1.856 + } 1.857 + 1.858 + // We can't simply construct a slim wrapper. Go ahead and create an 1.859 + // XPCWrappedNative for this object. At this point, |flat| could be 1.860 + // non-null, meaning that either we already have a wrapped native from 1.861 + // the cache (which might need to be QI'd to the new interface) or that 1.862 + // we found a slim wrapper that we'll have to morph. 1.863 + AutoMarkingNativeInterfacePtr iface(cx); 1.864 + if (iid) { 1.865 + if (Interface) 1.866 + iface = *Interface; 1.867 + 1.868 + if (!iface) { 1.869 + iface = XPCNativeInterface::GetNewOrUsed(iid); 1.870 + if (!iface) 1.871 + return false; 1.872 + 1.873 + if (Interface) 1.874 + *Interface = iface; 1.875 + } 1.876 + } 1.877 + 1.878 + MOZ_ASSERT(!flat || IS_WN_REFLECTOR(flat), "What kind of wrapper is this?"); 1.879 + 1.880 + nsresult rv; 1.881 + XPCWrappedNative* wrapper; 1.882 + nsRefPtr<XPCWrappedNative> strongWrapper; 1.883 + if (!flat) { 1.884 + rv = XPCWrappedNative::GetNewOrUsed(aHelper, xpcscope, iface, 1.885 + getter_AddRefs(strongWrapper)); 1.886 + 1.887 + wrapper = strongWrapper; 1.888 + } else { 1.889 + MOZ_ASSERT(IS_WN_REFLECTOR(flat)); 1.890 + 1.891 + wrapper = XPCWrappedNative::Get(flat); 1.892 + 1.893 + // If asked to return the wrapper we'll return a strong reference, 1.894 + // otherwise we'll just return its JSObject in d (which should be 1.895 + // rooted in that case). 1.896 + if (dest) 1.897 + strongWrapper = wrapper; 1.898 + if (iface) 1.899 + wrapper->FindTearOff(iface, false, &rv); 1.900 + else 1.901 + rv = NS_OK; 1.902 + } 1.903 + 1.904 + if (NS_FAILED(rv) && pErr) 1.905 + *pErr = rv; 1.906 + 1.907 + // If creating the wrapped native failed, then return early. 1.908 + if (NS_FAILED(rv) || !wrapper) 1.909 + return false; 1.910 + 1.911 + // If we're not creating security wrappers, we can return the 1.912 + // XPCWrappedNative as-is here. 1.913 + flat = wrapper->GetFlatJSObject(); 1.914 + jsval v = OBJECT_TO_JSVAL(flat); 1.915 + if (!allowNativeWrapper) { 1.916 + d.set(v); 1.917 + if (dest) 1.918 + strongWrapper.forget(dest); 1.919 + if (pErr) 1.920 + *pErr = NS_OK; 1.921 + return true; 1.922 + } 1.923 + 1.924 + // The call to wrap here handles both cross-compartment and same-compartment 1.925 + // security wrappers. 1.926 + RootedObject original(cx, flat); 1.927 + if (!JS_WrapObject(cx, &flat)) 1.928 + return false; 1.929 + 1.930 + d.setObjectOrNull(flat); 1.931 + 1.932 + if (dest) { 1.933 + // The strongWrapper still holds the original flat object. 1.934 + if (flat == original) { 1.935 + strongWrapper.forget(dest); 1.936 + } else { 1.937 + nsRefPtr<XPCJSObjectHolder> objHolder = 1.938 + XPCJSObjectHolder::newHolder(flat); 1.939 + if (!objHolder) 1.940 + return false; 1.941 + 1.942 + objHolder.forget(dest); 1.943 + } 1.944 + } 1.945 + 1.946 + if (pErr) 1.947 + *pErr = NS_OK; 1.948 + 1.949 + return true; 1.950 +} 1.951 + 1.952 +/***************************************************************************/ 1.953 + 1.954 +// static 1.955 +bool 1.956 +XPCConvert::JSObject2NativeInterface(void** dest, HandleObject src, 1.957 + const nsID* iid, 1.958 + nsISupports* aOuter, 1.959 + nsresult* pErr) 1.960 +{ 1.961 + MOZ_ASSERT(dest, "bad param"); 1.962 + MOZ_ASSERT(src, "bad param"); 1.963 + MOZ_ASSERT(iid, "bad param"); 1.964 + 1.965 + AutoJSContext cx; 1.966 + JSAutoCompartment ac(cx, src); 1.967 + 1.968 + *dest = nullptr; 1.969 + if (pErr) 1.970 + *pErr = NS_ERROR_XPC_BAD_CONVERT_JS; 1.971 + 1.972 + nsISupports* iface; 1.973 + 1.974 + if (!aOuter) { 1.975 + // Note that if we have a non-null aOuter then it means that we are 1.976 + // forcing the creation of a wrapper even if the object *is* a 1.977 + // wrappedNative or other wise has 'nsISupportness'. 1.978 + // This allows wrapJSAggregatedToNative to work. 1.979 + 1.980 + // If we're looking at a security wrapper, see now if we're allowed to 1.981 + // pass it to C++. If we are, then fall through to the code below. If 1.982 + // we aren't, throw an exception eagerly. 1.983 + // 1.984 + // NB: It's very important that we _don't_ unwrap in the aOuter case, 1.985 + // because the caller may explicitly want to create the XPCWrappedJS 1.986 + // around a security wrapper. XBL does this with Xrays from the XBL 1.987 + // scope - see nsBindingManager::GetBindingImplementation. 1.988 + JSObject* inner = js::CheckedUnwrap(src, /* stopAtOuter = */ false); 1.989 + 1.990 + // Hack - For historical reasons, wrapped chrome JS objects have been 1.991 + // passable as native interfaces. We'd like to fix this, but it 1.992 + // involves fixing the contacts API and PeerConnection to stop using 1.993 + // COWs. This needs to happen, but for now just preserve the old 1.994 + // behavior. 1.995 + // 1.996 + // Note that there is an identical hack in getWrapper which should be 1.997 + // removed if this one is. 1.998 + if (!inner && MOZ_UNLIKELY(xpc::WrapperFactory::IsCOW(src))) 1.999 + inner = js::UncheckedUnwrap(src); 1.1000 + if (!inner) { 1.1001 + if (pErr) 1.1002 + *pErr = NS_ERROR_XPC_SECURITY_MANAGER_VETO; 1.1003 + return false; 1.1004 + } 1.1005 + 1.1006 + // Is this really a native xpcom object with a wrapper? 1.1007 + XPCWrappedNative* wrappedNative = nullptr; 1.1008 + if (IS_WN_REFLECTOR(inner)) 1.1009 + wrappedNative = XPCWrappedNative::Get(inner); 1.1010 + if (wrappedNative) { 1.1011 + iface = wrappedNative->GetIdentityObject(); 1.1012 + return NS_SUCCEEDED(iface->QueryInterface(*iid, dest)); 1.1013 + } 1.1014 + // else... 1.1015 + 1.1016 + // Deal with slim wrappers here. 1.1017 + if (GetISupportsFromJSObject(inner ? inner : src, &iface)) { 1.1018 + if (iface) 1.1019 + return NS_SUCCEEDED(iface->QueryInterface(*iid, dest)); 1.1020 + 1.1021 + return false; 1.1022 + } 1.1023 + } 1.1024 + 1.1025 + // else... 1.1026 + 1.1027 + nsXPCWrappedJS* wrapper; 1.1028 + nsresult rv = nsXPCWrappedJS::GetNewOrUsed(src, *iid, &wrapper); 1.1029 + if (pErr) 1.1030 + *pErr = rv; 1.1031 + if (NS_SUCCEEDED(rv) && wrapper) { 1.1032 + // If the caller wanted to aggregate this JS object to a native, 1.1033 + // attach it to the wrapper. Note that we allow a maximum of one 1.1034 + // aggregated native for a given XPCWrappedJS. 1.1035 + if (aOuter) 1.1036 + wrapper->SetAggregatedNativeObject(aOuter); 1.1037 + 1.1038 + // We need to go through the QueryInterface logic to make this return 1.1039 + // the right thing for the various 'special' interfaces; e.g. 1.1040 + // nsIPropertyBag. We must use AggregatedQueryInterface in cases where 1.1041 + // there is an outer to avoid nasty recursion. 1.1042 + rv = aOuter ? wrapper->AggregatedQueryInterface(*iid, dest) : 1.1043 + wrapper->QueryInterface(*iid, dest); 1.1044 + if (pErr) 1.1045 + *pErr = rv; 1.1046 + NS_RELEASE(wrapper); 1.1047 + return NS_SUCCEEDED(rv); 1.1048 + } 1.1049 + 1.1050 + // else... 1.1051 + return false; 1.1052 +} 1.1053 + 1.1054 +/***************************************************************************/ 1.1055 +/***************************************************************************/ 1.1056 + 1.1057 +// static 1.1058 +nsresult 1.1059 +XPCConvert::ConstructException(nsresult rv, const char* message, 1.1060 + const char* ifaceName, const char* methodName, 1.1061 + nsISupports* data, 1.1062 + nsIException** exceptn, 1.1063 + JSContext* cx, 1.1064 + jsval* jsExceptionPtr) 1.1065 +{ 1.1066 + MOZ_ASSERT(!cx == !jsExceptionPtr, "Expected cx and jsExceptionPtr to cooccur."); 1.1067 + 1.1068 + static const char format[] = "\'%s\' when calling method: [%s::%s]"; 1.1069 + const char * msg = message; 1.1070 + nsXPIDLString xmsg; 1.1071 + nsAutoCString sxmsg; 1.1072 + 1.1073 + nsCOMPtr<nsIScriptError> errorObject = do_QueryInterface(data); 1.1074 + if (errorObject) { 1.1075 + if (NS_SUCCEEDED(errorObject->GetMessageMoz(getter_Copies(xmsg)))) { 1.1076 + CopyUTF16toUTF8(xmsg, sxmsg); 1.1077 + msg = sxmsg.get(); 1.1078 + } 1.1079 + } 1.1080 + if (!msg) 1.1081 + if (!nsXPCException::NameAndFormatForNSResult(rv, nullptr, &msg) || ! msg) 1.1082 + msg = "<error>"; 1.1083 + 1.1084 + nsCString msgStr(msg); 1.1085 + if (ifaceName && methodName) 1.1086 + msgStr.AppendPrintf(format, msg, ifaceName, methodName); 1.1087 + 1.1088 + nsRefPtr<Exception> e = new Exception(msgStr, rv, EmptyCString(), nullptr, data); 1.1089 + 1.1090 + if (cx && jsExceptionPtr) { 1.1091 + e->StowJSVal(*jsExceptionPtr); 1.1092 + } 1.1093 + 1.1094 + e.forget(exceptn); 1.1095 + return NS_OK; 1.1096 +} 1.1097 + 1.1098 +/********************************/ 1.1099 + 1.1100 +class MOZ_STACK_CLASS AutoExceptionRestorer 1.1101 +{ 1.1102 +public: 1.1103 + AutoExceptionRestorer(JSContext *cx, Value v) 1.1104 + : mContext(cx), tvr(cx, v) 1.1105 + { 1.1106 + JS_ClearPendingException(mContext); 1.1107 + } 1.1108 + 1.1109 + ~AutoExceptionRestorer() 1.1110 + { 1.1111 + JS_SetPendingException(mContext, tvr); 1.1112 + } 1.1113 + 1.1114 +private: 1.1115 + JSContext * const mContext; 1.1116 + RootedValue tvr; 1.1117 +}; 1.1118 + 1.1119 +// static 1.1120 +nsresult 1.1121 +XPCConvert::JSValToXPCException(MutableHandleValue s, 1.1122 + const char* ifaceName, 1.1123 + const char* methodName, 1.1124 + nsIException** exceptn) 1.1125 +{ 1.1126 + AutoJSContext cx; 1.1127 + AutoExceptionRestorer aer(cx, s); 1.1128 + 1.1129 + if (!JSVAL_IS_PRIMITIVE(s)) { 1.1130 + // we have a JSObject 1.1131 + RootedObject obj(cx, JSVAL_TO_OBJECT(s)); 1.1132 + 1.1133 + if (!obj) { 1.1134 + NS_ERROR("when is an object not an object?"); 1.1135 + return NS_ERROR_FAILURE; 1.1136 + } 1.1137 + 1.1138 + // is this really a native xpcom object with a wrapper? 1.1139 + JSObject *unwrapped = js::CheckedUnwrap(obj, /* stopAtOuter = */ false); 1.1140 + if (!unwrapped) 1.1141 + return NS_ERROR_XPC_SECURITY_MANAGER_VETO; 1.1142 + XPCWrappedNative* wrapper = IS_WN_REFLECTOR(unwrapped) ? XPCWrappedNative::Get(unwrapped) 1.1143 + : nullptr; 1.1144 + if (wrapper) { 1.1145 + nsISupports* supports = wrapper->GetIdentityObject(); 1.1146 + nsCOMPtr<nsIException> iface = do_QueryInterface(supports); 1.1147 + if (iface) { 1.1148 + // just pass through the exception (with extra ref and all) 1.1149 + nsCOMPtr<nsIException> temp = iface; 1.1150 + temp.forget(exceptn); 1.1151 + return NS_OK; 1.1152 + } else { 1.1153 + // it is a wrapped native, but not an exception! 1.1154 + return ConstructException(NS_ERROR_XPC_JS_THREW_NATIVE_OBJECT, 1.1155 + nullptr, ifaceName, methodName, supports, 1.1156 + exceptn, nullptr, nullptr); 1.1157 + } 1.1158 + } else { 1.1159 + // It is a JSObject, but not a wrapped native... 1.1160 + 1.1161 + // If it is an engine Error with an error report then let's 1.1162 + // extract the report and build an xpcexception from that 1.1163 + const JSErrorReport* report; 1.1164 + if (nullptr != (report = JS_ErrorFromException(cx, obj))) { 1.1165 + JSAutoByteString message; 1.1166 + JSString* str; 1.1167 + if (nullptr != (str = ToString(cx, s))) 1.1168 + message.encodeLatin1(cx, str); 1.1169 + return JSErrorToXPCException(message.ptr(), ifaceName, 1.1170 + methodName, report, exceptn); 1.1171 + } 1.1172 + 1.1173 + 1.1174 + bool found; 1.1175 + 1.1176 + // heuristic to see if it might be usable as an xpcexception 1.1177 + if (!JS_HasProperty(cx, obj, "message", &found)) 1.1178 + return NS_ERROR_FAILURE; 1.1179 + 1.1180 + if (found && !JS_HasProperty(cx, obj, "result", &found)) 1.1181 + return NS_ERROR_FAILURE; 1.1182 + 1.1183 + if (found) { 1.1184 + // lets try to build a wrapper around the JSObject 1.1185 + nsXPCWrappedJS* jswrapper; 1.1186 + nsresult rv = 1.1187 + nsXPCWrappedJS::GetNewOrUsed(obj, NS_GET_IID(nsIException), &jswrapper); 1.1188 + if (NS_FAILED(rv)) 1.1189 + return rv; 1.1190 + 1.1191 + *exceptn = static_cast<nsIException *>(jswrapper->GetXPTCStub()); 1.1192 + return NS_OK; 1.1193 + } 1.1194 + 1.1195 + 1.1196 + // XXX we should do a check against 'js_ErrorClass' here and 1.1197 + // do the right thing - even though it has no JSErrorReport, 1.1198 + // The fact that it is a JSError exceptions means we can extract 1.1199 + // particular info and our 'result' should reflect that. 1.1200 + 1.1201 + // otherwise we'll just try to convert it to a string 1.1202 + 1.1203 + JSString* str = ToString(cx, s); 1.1204 + if (!str) 1.1205 + return NS_ERROR_FAILURE; 1.1206 + 1.1207 + JSAutoByteString strBytes(cx, str); 1.1208 + if (!strBytes) 1.1209 + return NS_ERROR_FAILURE; 1.1210 + 1.1211 + return ConstructException(NS_ERROR_XPC_JS_THREW_JS_OBJECT, 1.1212 + strBytes.ptr(), ifaceName, methodName, 1.1213 + nullptr, exceptn, cx, s.address()); 1.1214 + } 1.1215 + } 1.1216 + 1.1217 + if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) { 1.1218 + return ConstructException(NS_ERROR_XPC_JS_THREW_NULL, 1.1219 + nullptr, ifaceName, methodName, nullptr, 1.1220 + exceptn, cx, s.address()); 1.1221 + } 1.1222 + 1.1223 + if (JSVAL_IS_NUMBER(s)) { 1.1224 + // lets see if it looks like an nsresult 1.1225 + nsresult rv; 1.1226 + double number; 1.1227 + bool isResult = false; 1.1228 + 1.1229 + if (JSVAL_IS_INT(s)) { 1.1230 + rv = (nsresult) JSVAL_TO_INT(s); 1.1231 + if (NS_FAILED(rv)) 1.1232 + isResult = true; 1.1233 + else 1.1234 + number = (double) JSVAL_TO_INT(s); 1.1235 + } else { 1.1236 + number = JSVAL_TO_DOUBLE(s); 1.1237 + if (number > 0.0 && 1.1238 + number < (double)0xffffffff && 1.1239 + 0.0 == fmod(number,1)) { 1.1240 + // Visual Studio 9 doesn't allow casting directly from a 1.1241 + // double to an enumeration type, contrary to 5.2.9(10) of 1.1242 + // C++11, so add an intermediate cast. 1.1243 + rv = (nsresult)(uint32_t) number; 1.1244 + if (NS_FAILED(rv)) 1.1245 + isResult = true; 1.1246 + } 1.1247 + } 1.1248 + 1.1249 + if (isResult) 1.1250 + return ConstructException(rv, nullptr, ifaceName, methodName, 1.1251 + nullptr, exceptn, cx, s.address()); 1.1252 + else { 1.1253 + // XXX all this nsISupportsDouble code seems a little redundant 1.1254 + // now that we're storing the jsval in the exception... 1.1255 + nsISupportsDouble* data; 1.1256 + nsCOMPtr<nsIComponentManager> cm; 1.1257 + if (NS_FAILED(NS_GetComponentManager(getter_AddRefs(cm))) || !cm || 1.1258 + NS_FAILED(cm->CreateInstanceByContractID(NS_SUPPORTS_DOUBLE_CONTRACTID, 1.1259 + nullptr, 1.1260 + NS_GET_IID(nsISupportsDouble), 1.1261 + (void**)&data))) 1.1262 + return NS_ERROR_FAILURE; 1.1263 + data->SetData(number); 1.1264 + rv = ConstructException(NS_ERROR_XPC_JS_THREW_NUMBER, nullptr, 1.1265 + ifaceName, methodName, data, exceptn, cx, s.address()); 1.1266 + NS_RELEASE(data); 1.1267 + return rv; 1.1268 + } 1.1269 + } 1.1270 + 1.1271 + // otherwise we'll just try to convert it to a string 1.1272 + // Note: e.g., bools get converted to JSStrings by this code. 1.1273 + 1.1274 + JSString* str = ToString(cx, s); 1.1275 + if (str) { 1.1276 + JSAutoByteString strBytes(cx, str); 1.1277 + if (!!strBytes) { 1.1278 + return ConstructException(NS_ERROR_XPC_JS_THREW_STRING, 1.1279 + strBytes.ptr(), ifaceName, methodName, 1.1280 + nullptr, exceptn, cx, s.address()); 1.1281 + } 1.1282 + } 1.1283 + return NS_ERROR_FAILURE; 1.1284 +} 1.1285 + 1.1286 +/********************************/ 1.1287 + 1.1288 +// static 1.1289 +nsresult 1.1290 +XPCConvert::JSErrorToXPCException(const char* message, 1.1291 + const char* ifaceName, 1.1292 + const char* methodName, 1.1293 + const JSErrorReport* report, 1.1294 + nsIException** exceptn) 1.1295 +{ 1.1296 + AutoJSContext cx; 1.1297 + nsresult rv = NS_ERROR_FAILURE; 1.1298 + nsRefPtr<nsScriptError> data; 1.1299 + if (report) { 1.1300 + nsAutoString bestMessage; 1.1301 + if (report && report->ucmessage) { 1.1302 + bestMessage = static_cast<const char16_t*>(report->ucmessage); 1.1303 + } else if (message) { 1.1304 + CopyASCIItoUTF16(message, bestMessage); 1.1305 + } else { 1.1306 + bestMessage.AssignLiteral("JavaScript Error"); 1.1307 + } 1.1308 + 1.1309 + const char16_t* uclinebuf = 1.1310 + static_cast<const char16_t*>(report->uclinebuf); 1.1311 + 1.1312 + data = new nsScriptError(); 1.1313 + data->InitWithWindowID( 1.1314 + bestMessage, 1.1315 + NS_ConvertASCIItoUTF16(report->filename), 1.1316 + uclinebuf ? nsDependentString(uclinebuf) : EmptyString(), 1.1317 + report->lineno, 1.1318 + report->uctokenptr - report->uclinebuf, report->flags, 1.1319 + NS_LITERAL_CSTRING("XPConnect JavaScript"), 1.1320 + nsJSUtils::GetCurrentlyRunningCodeInnerWindowID(cx)); 1.1321 + } 1.1322 + 1.1323 + if (data) { 1.1324 + nsAutoCString formattedMsg; 1.1325 + data->ToString(formattedMsg); 1.1326 + 1.1327 + rv = ConstructException(NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS, 1.1328 + formattedMsg.get(), ifaceName, methodName, 1.1329 + static_cast<nsIScriptError*>(data.get()), 1.1330 + exceptn, nullptr, nullptr); 1.1331 + } else { 1.1332 + rv = ConstructException(NS_ERROR_XPC_JAVASCRIPT_ERROR, 1.1333 + nullptr, ifaceName, methodName, nullptr, 1.1334 + exceptn, nullptr, nullptr); 1.1335 + } 1.1336 + return rv; 1.1337 +} 1.1338 + 1.1339 +/***************************************************************************/ 1.1340 + 1.1341 +// array fun... 1.1342 + 1.1343 +#ifdef POPULATE 1.1344 +#undef POPULATE 1.1345 +#endif 1.1346 + 1.1347 +// static 1.1348 +bool 1.1349 +XPCConvert::NativeArray2JS(MutableHandleValue d, const void** s, 1.1350 + const nsXPTType& type, const nsID* iid, 1.1351 + uint32_t count, nsresult* pErr) 1.1352 +{ 1.1353 + NS_PRECONDITION(s, "bad param"); 1.1354 + 1.1355 + AutoJSContext cx; 1.1356 + 1.1357 + // XXX add support for putting chars in a string rather than an array 1.1358 + 1.1359 + // XXX add support to indicate *which* array element was not convertable 1.1360 + 1.1361 + RootedObject array(cx, JS_NewArrayObject(cx, count)); 1.1362 + if (!array) 1.1363 + return false; 1.1364 + 1.1365 + if (pErr) 1.1366 + *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE; 1.1367 + 1.1368 + uint32_t i; 1.1369 + RootedValue current(cx, JSVAL_NULL); 1.1370 + 1.1371 +#define POPULATE(_t) \ 1.1372 + PR_BEGIN_MACRO \ 1.1373 + for (i = 0; i < count; i++) { \ 1.1374 + if (!NativeData2JS(¤t, ((_t*)*s)+i, type, iid, pErr) || \ 1.1375 + !JS_SetElement(cx, array, i, current)) \ 1.1376 + goto failure; \ 1.1377 + } \ 1.1378 + PR_END_MACRO 1.1379 + 1.1380 + // XXX check IsPtr - esp. to handle array of nsID (as opposed to nsID*) 1.1381 + 1.1382 + switch (type.TagPart()) { 1.1383 + case nsXPTType::T_I8 : POPULATE(int8_t); break; 1.1384 + case nsXPTType::T_I16 : POPULATE(int16_t); break; 1.1385 + case nsXPTType::T_I32 : POPULATE(int32_t); break; 1.1386 + case nsXPTType::T_I64 : POPULATE(int64_t); break; 1.1387 + case nsXPTType::T_U8 : POPULATE(uint8_t); break; 1.1388 + case nsXPTType::T_U16 : POPULATE(uint16_t); break; 1.1389 + case nsXPTType::T_U32 : POPULATE(uint32_t); break; 1.1390 + case nsXPTType::T_U64 : POPULATE(uint64_t); break; 1.1391 + case nsXPTType::T_FLOAT : POPULATE(float); break; 1.1392 + case nsXPTType::T_DOUBLE : POPULATE(double); break; 1.1393 + case nsXPTType::T_BOOL : POPULATE(bool); break; 1.1394 + case nsXPTType::T_CHAR : POPULATE(char); break; 1.1395 + case nsXPTType::T_WCHAR : POPULATE(jschar); break; 1.1396 + case nsXPTType::T_VOID : NS_ERROR("bad type"); goto failure; 1.1397 + case nsXPTType::T_IID : POPULATE(nsID*); break; 1.1398 + case nsXPTType::T_DOMSTRING : NS_ERROR("bad type"); goto failure; 1.1399 + case nsXPTType::T_CHAR_STR : POPULATE(char*); break; 1.1400 + case nsXPTType::T_WCHAR_STR : POPULATE(jschar*); break; 1.1401 + case nsXPTType::T_INTERFACE : POPULATE(nsISupports*); break; 1.1402 + case nsXPTType::T_INTERFACE_IS : POPULATE(nsISupports*); break; 1.1403 + case nsXPTType::T_UTF8STRING : NS_ERROR("bad type"); goto failure; 1.1404 + case nsXPTType::T_CSTRING : NS_ERROR("bad type"); goto failure; 1.1405 + case nsXPTType::T_ASTRING : NS_ERROR("bad type"); goto failure; 1.1406 + default : NS_ERROR("bad type"); goto failure; 1.1407 + } 1.1408 + 1.1409 + if (pErr) 1.1410 + *pErr = NS_OK; 1.1411 + d.setObject(*array); 1.1412 + return true; 1.1413 + 1.1414 +failure: 1.1415 + return false; 1.1416 + 1.1417 +#undef POPULATE 1.1418 +} 1.1419 + 1.1420 + 1.1421 + 1.1422 +// Check that the tag part of the type matches the type 1.1423 +// of the array. If the check succeeds, check that the size 1.1424 +// of the output does not exceed UINT32_MAX bytes. Allocate 1.1425 +// the memory and copy the elements by memcpy. 1.1426 +static bool 1.1427 +CheckTargetAndPopulate(const nsXPTType& type, 1.1428 + uint8_t requiredType, 1.1429 + size_t typeSize, 1.1430 + uint32_t count, 1.1431 + JSObject* tArr, 1.1432 + void** output, 1.1433 + nsresult* pErr) 1.1434 +{ 1.1435 + // Check that the element type expected by the interface matches 1.1436 + // the type of the elements in the typed array exactly, including 1.1437 + // signedness. 1.1438 + if (type.TagPart() != requiredType) { 1.1439 + if (pErr) 1.1440 + *pErr = NS_ERROR_XPC_BAD_CONVERT_JS; 1.1441 + 1.1442 + return false; 1.1443 + } 1.1444 + 1.1445 + // Calulate the maximum number of elements that can fit in 1.1446 + // UINT32_MAX bytes. 1.1447 + size_t max = UINT32_MAX / typeSize; 1.1448 + 1.1449 + // This could overflow on 32-bit systems so check max first. 1.1450 + size_t byteSize = count * typeSize; 1.1451 + if (count > max || !(*output = nsMemory::Alloc(byteSize))) { 1.1452 + if (pErr) 1.1453 + *pErr = NS_ERROR_OUT_OF_MEMORY; 1.1454 + 1.1455 + return false; 1.1456 + } 1.1457 + 1.1458 + memcpy(*output, JS_GetArrayBufferViewData(tArr), byteSize); 1.1459 + return true; 1.1460 +} 1.1461 + 1.1462 +// Fast conversion of typed arrays to native using memcpy. 1.1463 +// No float or double canonicalization is done. Called by 1.1464 +// JSarray2Native whenever a TypedArray is met. ArrayBuffers 1.1465 +// are not accepted; create a properly typed array view on them 1.1466 +// first. The element type of array must match the XPCOM 1.1467 +// type in size, type and signedness exactly. As an exception, 1.1468 +// Uint8ClampedArray is allowed for arrays of uint8_t. DataViews 1.1469 +// are not supported. 1.1470 + 1.1471 +// static 1.1472 +bool 1.1473 +XPCConvert::JSTypedArray2Native(void** d, 1.1474 + JSObject* jsArray, 1.1475 + uint32_t count, 1.1476 + const nsXPTType& type, 1.1477 + nsresult* pErr) 1.1478 +{ 1.1479 + MOZ_ASSERT(jsArray, "bad param"); 1.1480 + MOZ_ASSERT(d, "bad param"); 1.1481 + MOZ_ASSERT(JS_IsTypedArrayObject(jsArray), "not a typed array"); 1.1482 + 1.1483 + // Check the actual length of the input array against the 1.1484 + // given size_is. 1.1485 + uint32_t len = JS_GetTypedArrayLength(jsArray); 1.1486 + if (len < count) { 1.1487 + if (pErr) 1.1488 + *pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY; 1.1489 + 1.1490 + return false; 1.1491 + } 1.1492 + 1.1493 + void* output = nullptr; 1.1494 + 1.1495 + switch (JS_GetArrayBufferViewType(jsArray)) { 1.1496 + case js::ArrayBufferView::TYPE_INT8: 1.1497 + if (!CheckTargetAndPopulate(nsXPTType::T_I8, type, 1.1498 + sizeof(int8_t), count, 1.1499 + jsArray, &output, pErr)) { 1.1500 + return false; 1.1501 + } 1.1502 + break; 1.1503 + 1.1504 + case js::ArrayBufferView::TYPE_UINT8: 1.1505 + case js::ArrayBufferView::TYPE_UINT8_CLAMPED: 1.1506 + if (!CheckTargetAndPopulate(nsXPTType::T_U8, type, 1.1507 + sizeof(uint8_t), count, 1.1508 + jsArray, &output, pErr)) { 1.1509 + return false; 1.1510 + } 1.1511 + break; 1.1512 + 1.1513 + case js::ArrayBufferView::TYPE_INT16: 1.1514 + if (!CheckTargetAndPopulate(nsXPTType::T_I16, type, 1.1515 + sizeof(int16_t), count, 1.1516 + jsArray, &output, pErr)) { 1.1517 + return false; 1.1518 + } 1.1519 + break; 1.1520 + 1.1521 + case js::ArrayBufferView::TYPE_UINT16: 1.1522 + if (!CheckTargetAndPopulate(nsXPTType::T_U16, type, 1.1523 + sizeof(uint16_t), count, 1.1524 + jsArray, &output, pErr)) { 1.1525 + return false; 1.1526 + } 1.1527 + break; 1.1528 + 1.1529 + case js::ArrayBufferView::TYPE_INT32: 1.1530 + if (!CheckTargetAndPopulate(nsXPTType::T_I32, type, 1.1531 + sizeof(int32_t), count, 1.1532 + jsArray, &output, pErr)) { 1.1533 + return false; 1.1534 + } 1.1535 + break; 1.1536 + 1.1537 + case js::ArrayBufferView::TYPE_UINT32: 1.1538 + if (!CheckTargetAndPopulate(nsXPTType::T_U32, type, 1.1539 + sizeof(uint32_t), count, 1.1540 + jsArray, &output, pErr)) { 1.1541 + return false; 1.1542 + } 1.1543 + break; 1.1544 + 1.1545 + case js::ArrayBufferView::TYPE_FLOAT32: 1.1546 + if (!CheckTargetAndPopulate(nsXPTType::T_FLOAT, type, 1.1547 + sizeof(float), count, 1.1548 + jsArray, &output, pErr)) { 1.1549 + return false; 1.1550 + } 1.1551 + break; 1.1552 + 1.1553 + case js::ArrayBufferView::TYPE_FLOAT64: 1.1554 + if (!CheckTargetAndPopulate(nsXPTType::T_DOUBLE, type, 1.1555 + sizeof(double), count, 1.1556 + jsArray, &output, pErr)) { 1.1557 + return false; 1.1558 + } 1.1559 + break; 1.1560 + 1.1561 + // Yet another array type was defined? It is not supported yet... 1.1562 + default: 1.1563 + if (pErr) 1.1564 + *pErr = NS_ERROR_XPC_BAD_CONVERT_JS; 1.1565 + 1.1566 + return false; 1.1567 + } 1.1568 + 1.1569 + *d = output; 1.1570 + if (pErr) 1.1571 + *pErr = NS_OK; 1.1572 + 1.1573 + return true; 1.1574 +} 1.1575 + 1.1576 +// static 1.1577 +bool 1.1578 +XPCConvert::JSArray2Native(void** d, HandleValue s, 1.1579 + uint32_t count, const nsXPTType& type, 1.1580 + const nsID* iid, nsresult* pErr) 1.1581 +{ 1.1582 + MOZ_ASSERT(d, "bad param"); 1.1583 + 1.1584 + AutoJSContext cx; 1.1585 + 1.1586 + // XXX add support for getting chars from strings 1.1587 + 1.1588 + // XXX add support to indicate *which* array element was not convertable 1.1589 + 1.1590 + if (s.isNullOrUndefined()) { 1.1591 + if (0 != count) { 1.1592 + if (pErr) 1.1593 + *pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY; 1.1594 + return false; 1.1595 + } 1.1596 + 1.1597 + *d = nullptr; 1.1598 + return true; 1.1599 + } 1.1600 + 1.1601 + if (!s.isObject()) { 1.1602 + if (pErr) 1.1603 + *pErr = NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY; 1.1604 + return false; 1.1605 + } 1.1606 + 1.1607 + RootedObject jsarray(cx, &s.toObject()); 1.1608 + 1.1609 + // If this is a typed array, then try a fast conversion with memcpy. 1.1610 + if (JS_IsTypedArrayObject(jsarray)) { 1.1611 + return JSTypedArray2Native(d, jsarray, count, type, pErr); 1.1612 + } 1.1613 + 1.1614 + if (!JS_IsArrayObject(cx, jsarray)) { 1.1615 + if (pErr) 1.1616 + *pErr = NS_ERROR_XPC_CANT_CONVERT_OBJECT_TO_ARRAY; 1.1617 + return false; 1.1618 + } 1.1619 + 1.1620 + uint32_t len; 1.1621 + if (!JS_GetArrayLength(cx, jsarray, &len) || len < count) { 1.1622 + if (pErr) 1.1623 + *pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY; 1.1624 + return false; 1.1625 + } 1.1626 + 1.1627 + if (pErr) 1.1628 + *pErr = NS_ERROR_XPC_BAD_CONVERT_JS; 1.1629 + 1.1630 +#define POPULATE(_mode, _t) \ 1.1631 + PR_BEGIN_MACRO \ 1.1632 + cleanupMode = _mode; \ 1.1633 + size_t max = UINT32_MAX / sizeof(_t); \ 1.1634 + if (count > max || \ 1.1635 + nullptr == (array = nsMemory::Alloc(count * sizeof(_t)))) { \ 1.1636 + if (pErr) \ 1.1637 + *pErr = NS_ERROR_OUT_OF_MEMORY; \ 1.1638 + goto failure; \ 1.1639 + } \ 1.1640 + for (initedCount = 0; initedCount < count; initedCount++) { \ 1.1641 + if (!JS_GetElement(cx, jsarray, initedCount, ¤t) || \ 1.1642 + !JSData2Native(((_t*)array)+initedCount, current, type, \ 1.1643 + true, iid, pErr)) \ 1.1644 + goto failure; \ 1.1645 + } \ 1.1646 + PR_END_MACRO 1.1647 + 1.1648 + // No Action, FRee memory, RElease object 1.1649 + enum CleanupMode {na, fr, re}; 1.1650 + 1.1651 + CleanupMode cleanupMode; 1.1652 + 1.1653 + void *array = nullptr; 1.1654 + uint32_t initedCount; 1.1655 + RootedValue current(cx); 1.1656 + 1.1657 + // XXX check IsPtr - esp. to handle array of nsID (as opposed to nsID*) 1.1658 + // XXX make extra space at end of char* and wchar* and null termintate 1.1659 + 1.1660 + switch (type.TagPart()) { 1.1661 + case nsXPTType::T_I8 : POPULATE(na, int8_t); break; 1.1662 + case nsXPTType::T_I16 : POPULATE(na, int16_t); break; 1.1663 + case nsXPTType::T_I32 : POPULATE(na, int32_t); break; 1.1664 + case nsXPTType::T_I64 : POPULATE(na, int64_t); break; 1.1665 + case nsXPTType::T_U8 : POPULATE(na, uint8_t); break; 1.1666 + case nsXPTType::T_U16 : POPULATE(na, uint16_t); break; 1.1667 + case nsXPTType::T_U32 : POPULATE(na, uint32_t); break; 1.1668 + case nsXPTType::T_U64 : POPULATE(na, uint64_t); break; 1.1669 + case nsXPTType::T_FLOAT : POPULATE(na, float); break; 1.1670 + case nsXPTType::T_DOUBLE : POPULATE(na, double); break; 1.1671 + case nsXPTType::T_BOOL : POPULATE(na, bool); break; 1.1672 + case nsXPTType::T_CHAR : POPULATE(na, char); break; 1.1673 + case nsXPTType::T_WCHAR : POPULATE(na, jschar); break; 1.1674 + case nsXPTType::T_VOID : NS_ERROR("bad type"); goto failure; 1.1675 + case nsXPTType::T_IID : POPULATE(fr, nsID*); break; 1.1676 + case nsXPTType::T_DOMSTRING : NS_ERROR("bad type"); goto failure; 1.1677 + case nsXPTType::T_CHAR_STR : POPULATE(fr, char*); break; 1.1678 + case nsXPTType::T_WCHAR_STR : POPULATE(fr, jschar*); break; 1.1679 + case nsXPTType::T_INTERFACE : POPULATE(re, nsISupports*); break; 1.1680 + case nsXPTType::T_INTERFACE_IS : POPULATE(re, nsISupports*); break; 1.1681 + case nsXPTType::T_UTF8STRING : NS_ERROR("bad type"); goto failure; 1.1682 + case nsXPTType::T_CSTRING : NS_ERROR("bad type"); goto failure; 1.1683 + case nsXPTType::T_ASTRING : NS_ERROR("bad type"); goto failure; 1.1684 + default : NS_ERROR("bad type"); goto failure; 1.1685 + } 1.1686 + 1.1687 + *d = array; 1.1688 + if (pErr) 1.1689 + *pErr = NS_OK; 1.1690 + return true; 1.1691 + 1.1692 +failure: 1.1693 + // we may need to cleanup the partially filled array of converted stuff 1.1694 + if (array) { 1.1695 + if (cleanupMode == re) { 1.1696 + nsISupports** a = (nsISupports**) array; 1.1697 + for (uint32_t i = 0; i < initedCount; i++) { 1.1698 + nsISupports* p = a[i]; 1.1699 + NS_IF_RELEASE(p); 1.1700 + } 1.1701 + } else if (cleanupMode == fr) { 1.1702 + void** a = (void**) array; 1.1703 + for (uint32_t i = 0; i < initedCount; i++) { 1.1704 + void* p = a[i]; 1.1705 + if (p) nsMemory::Free(p); 1.1706 + } 1.1707 + } 1.1708 + nsMemory::Free(array); 1.1709 + } 1.1710 + 1.1711 + return false; 1.1712 + 1.1713 +#undef POPULATE 1.1714 +} 1.1715 + 1.1716 +// static 1.1717 +bool 1.1718 +XPCConvert::NativeStringWithSize2JS(MutableHandleValue d, const void* s, 1.1719 + const nsXPTType& type, 1.1720 + uint32_t count, 1.1721 + nsresult* pErr) 1.1722 +{ 1.1723 + NS_PRECONDITION(s, "bad param"); 1.1724 + 1.1725 + AutoJSContext cx; 1.1726 + if (pErr) 1.1727 + *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE; 1.1728 + 1.1729 + switch (type.TagPart()) { 1.1730 + case nsXPTType::T_PSTRING_SIZE_IS: 1.1731 + { 1.1732 + char* p = *((char**)s); 1.1733 + if (!p) 1.1734 + break; 1.1735 + JSString* str; 1.1736 + if (!(str = JS_NewStringCopyN(cx, p, count))) 1.1737 + return false; 1.1738 + d.setString(str); 1.1739 + break; 1.1740 + } 1.1741 + case nsXPTType::T_PWSTRING_SIZE_IS: 1.1742 + { 1.1743 + jschar* p = *((jschar**)s); 1.1744 + if (!p) 1.1745 + break; 1.1746 + JSString* str; 1.1747 + if (!(str = JS_NewUCStringCopyN(cx, p, count))) 1.1748 + return false; 1.1749 + d.setString(str); 1.1750 + break; 1.1751 + } 1.1752 + default: 1.1753 + XPC_LOG_ERROR(("XPCConvert::NativeStringWithSize2JS : unsupported type")); 1.1754 + return false; 1.1755 + } 1.1756 + return true; 1.1757 +} 1.1758 + 1.1759 +// static 1.1760 +bool 1.1761 +XPCConvert::JSStringWithSize2Native(void* d, HandleValue s, 1.1762 + uint32_t count, const nsXPTType& type, 1.1763 + nsresult* pErr) 1.1764 +{ 1.1765 + NS_PRECONDITION(!JSVAL_IS_NULL(s), "bad param"); 1.1766 + NS_PRECONDITION(d, "bad param"); 1.1767 + 1.1768 + AutoJSContext cx; 1.1769 + uint32_t len; 1.1770 + 1.1771 + if (pErr) 1.1772 + *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE; 1.1773 + 1.1774 + switch (type.TagPart()) { 1.1775 + case nsXPTType::T_PSTRING_SIZE_IS: 1.1776 + { 1.1777 + if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) { 1.1778 + if (0 != count) { 1.1779 + if (pErr) 1.1780 + *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING; 1.1781 + return false; 1.1782 + } 1.1783 + if (0 != count) { 1.1784 + len = (count + 1) * sizeof(char); 1.1785 + if (!(*((void**)d) = nsMemory::Alloc(len))) 1.1786 + return false; 1.1787 + return true; 1.1788 + } 1.1789 + // else ... 1.1790 + 1.1791 + *((char**)d) = nullptr; 1.1792 + return true; 1.1793 + } 1.1794 + 1.1795 + JSString* str = ToString(cx, s); 1.1796 + if (!str) { 1.1797 + return false; 1.1798 + } 1.1799 + 1.1800 + size_t length = JS_GetStringEncodingLength(cx, str); 1.1801 + if (length == size_t(-1)) { 1.1802 + return false; 1.1803 + } 1.1804 + if (length > count) { 1.1805 + if (pErr) 1.1806 + *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING; 1.1807 + return false; 1.1808 + } 1.1809 + len = uint32_t(length); 1.1810 + 1.1811 + if (len < count) 1.1812 + len = count; 1.1813 + 1.1814 + uint32_t alloc_len = (len + 1) * sizeof(char); 1.1815 + char *buffer = static_cast<char *>(nsMemory::Alloc(alloc_len)); 1.1816 + if (!buffer) { 1.1817 + return false; 1.1818 + } 1.1819 + JS_EncodeStringToBuffer(cx, str, buffer, len); 1.1820 + buffer[len] = '\0'; 1.1821 + *((char**)d) = buffer; 1.1822 + 1.1823 + return true; 1.1824 + } 1.1825 + 1.1826 + case nsXPTType::T_PWSTRING_SIZE_IS: 1.1827 + { 1.1828 + const jschar* chars=nullptr; 1.1829 + JSString* str; 1.1830 + 1.1831 + if (JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s)) { 1.1832 + if (0 != count) { 1.1833 + if (pErr) 1.1834 + *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING; 1.1835 + return false; 1.1836 + } 1.1837 + 1.1838 + if (0 != count) { 1.1839 + len = (count + 1) * sizeof(jschar); 1.1840 + if (!(*((void**)d) = nsMemory::Alloc(len))) 1.1841 + return false; 1.1842 + return true; 1.1843 + } 1.1844 + 1.1845 + // else ... 1.1846 + *((const jschar**)d) = nullptr; 1.1847 + return true; 1.1848 + } 1.1849 + 1.1850 + if (!(str = ToString(cx, s))) { 1.1851 + return false; 1.1852 + } 1.1853 + 1.1854 + len = JS_GetStringLength(str); 1.1855 + if (len > count) { 1.1856 + if (pErr) 1.1857 + *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING; 1.1858 + return false; 1.1859 + } 1.1860 + if (len < count) 1.1861 + len = count; 1.1862 + 1.1863 + if (!(chars = JS_GetStringCharsZ(cx, str))) { 1.1864 + return false; 1.1865 + } 1.1866 + uint32_t alloc_len = (len + 1) * sizeof(jschar); 1.1867 + if (!(*((void**)d) = nsMemory::Alloc(alloc_len))) { 1.1868 + // XXX should report error 1.1869 + return false; 1.1870 + } 1.1871 + memcpy(*((jschar**)d), chars, alloc_len); 1.1872 + (*((jschar**)d))[count] = 0; 1.1873 + 1.1874 + return true; 1.1875 + } 1.1876 + default: 1.1877 + XPC_LOG_ERROR(("XPCConvert::JSStringWithSize2Native : unsupported type")); 1.1878 + return false; 1.1879 + } 1.1880 +} 1.1881 +