1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/js/xpconnect/src/XPCVariant.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,828 @@ 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 +/* nsIVariant implementation for xpconnect. */ 1.11 + 1.12 +#include "xpcprivate.h" 1.13 +#include "nsCxPusher.h" 1.14 + 1.15 +#include "jsfriendapi.h" 1.16 +#include "jsprf.h" 1.17 +#include "jswrapper.h" 1.18 + 1.19 +using namespace JS; 1.20 +using namespace mozilla; 1.21 + 1.22 +NS_IMPL_CLASSINFO(XPCVariant, nullptr, 0, XPCVARIANT_CID) 1.23 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XPCVariant) 1.24 + NS_INTERFACE_MAP_ENTRY(XPCVariant) 1.25 + NS_INTERFACE_MAP_ENTRY(nsIVariant) 1.26 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.27 + NS_IMPL_QUERY_CLASSINFO(XPCVariant) 1.28 +NS_INTERFACE_MAP_END 1.29 +NS_IMPL_CI_INTERFACE_GETTER(XPCVariant, XPCVariant, nsIVariant) 1.30 + 1.31 +NS_IMPL_CYCLE_COLLECTING_ADDREF(XPCVariant) 1.32 +NS_IMPL_CYCLE_COLLECTING_RELEASE(XPCVariant) 1.33 + 1.34 +XPCVariant::XPCVariant(JSContext* cx, jsval aJSVal) 1.35 + : mJSVal(aJSVal), mCCGeneration(0) 1.36 +{ 1.37 + nsVariant::Initialize(&mData); 1.38 + if (!mJSVal.isPrimitive()) { 1.39 + // XXXbholley - The innerization here was from bug 638026. Blake says 1.40 + // the basic problem was that we were storing the C++ inner but the JS 1.41 + // outer, which meant that, after navigation, the JS inner could be 1.42 + // collected, which would cause us to try to recreate the JS inner at 1.43 + // some later point after teardown, which would crash. This is shouldn't 1.44 + // be a problem anymore because SetParentToWindow will do the right 1.45 + // thing, but I'm saving the cleanup here for another day. Blake thinks 1.46 + // that we should just not store the WN if we're creating a variant for 1.47 + // an outer window. 1.48 + JS::RootedObject obj(cx, &mJSVal.toObject()); 1.49 + obj = JS_ObjectToInnerObject(cx, obj); 1.50 + mJSVal = JS::ObjectValue(*obj); 1.51 + 1.52 + JSObject *unwrapped = js::CheckedUnwrap(obj, /* stopAtOuter = */ false); 1.53 + mReturnRawObject = !(unwrapped && IS_WN_REFLECTOR(unwrapped)); 1.54 + } else 1.55 + mReturnRawObject = false; 1.56 +} 1.57 + 1.58 +XPCTraceableVariant::~XPCTraceableVariant() 1.59 +{ 1.60 + jsval val = GetJSValPreserveColor(); 1.61 + 1.62 + MOZ_ASSERT(JSVAL_IS_GCTHING(val), "Must be traceable or unlinked"); 1.63 + 1.64 + // If val is JSVAL_STRING, we don't need to clean anything up; simply 1.65 + // removing the string from the root set is good. 1.66 + if (!JSVAL_IS_STRING(val)) 1.67 + nsVariant::Cleanup(&mData); 1.68 + 1.69 + if (!JSVAL_IS_NULL(val)) 1.70 + RemoveFromRootSet(); 1.71 +} 1.72 + 1.73 +void XPCTraceableVariant::TraceJS(JSTracer* trc) 1.74 +{ 1.75 + MOZ_ASSERT(mJSVal.isMarkable()); 1.76 + trc->setTracingDetails(GetTraceName, this, 0); 1.77 + JS_CallHeapValueTracer(trc, &mJSVal, "XPCTraceableVariant::mJSVal"); 1.78 +} 1.79 + 1.80 +// static 1.81 +void 1.82 +XPCTraceableVariant::GetTraceName(JSTracer* trc, char *buf, size_t bufsize) 1.83 +{ 1.84 + JS_snprintf(buf, bufsize, "XPCVariant[0x%p].mJSVal", trc->debugPrintArg()); 1.85 +} 1.86 + 1.87 +NS_IMPL_CYCLE_COLLECTION_CLASS(XPCVariant) 1.88 + 1.89 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XPCVariant) 1.90 + JS::Value val = tmp->GetJSValPreserveColor(); 1.91 + if (val.isObjectOrNull()) { 1.92 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mJSVal"); 1.93 + cb.NoteJSChild(JSVAL_TO_OBJECT(val)); 1.94 + } 1.95 + 1.96 + nsVariant::Traverse(tmp->mData, cb); 1.97 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.98 + 1.99 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XPCVariant) 1.100 + JS::Value val = tmp->GetJSValPreserveColor(); 1.101 + 1.102 + // We're sharing val's buffer, clear the pointer to it so Cleanup() won't 1.103 + // try to delete it 1.104 + if (val.isString()) 1.105 + tmp->mData.u.wstr.mWStringValue = nullptr; 1.106 + nsVariant::Cleanup(&tmp->mData); 1.107 + 1.108 + if (val.isMarkable()) { 1.109 + XPCTraceableVariant *v = static_cast<XPCTraceableVariant*>(tmp); 1.110 + v->RemoveFromRootSet(); 1.111 + } 1.112 + tmp->mJSVal = JS::NullValue(); 1.113 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.114 + 1.115 +// static 1.116 +already_AddRefed<XPCVariant> 1.117 +XPCVariant::newVariant(JSContext* cx, jsval aJSVal) 1.118 +{ 1.119 + nsRefPtr<XPCVariant> variant; 1.120 + 1.121 + if (!aJSVal.isMarkable()) 1.122 + variant = new XPCVariant(cx, aJSVal); 1.123 + else 1.124 + variant = new XPCTraceableVariant(cx, aJSVal); 1.125 + 1.126 + if (!variant->InitializeData(cx)) 1.127 + return nullptr; 1.128 + 1.129 + return variant.forget(); 1.130 +} 1.131 + 1.132 +// Helper class to give us a namespace for the table based code below. 1.133 +class XPCArrayHomogenizer 1.134 +{ 1.135 +private: 1.136 + enum Type 1.137 + { 1.138 + tNull = 0 , // null value 1.139 + tInt , // Integer 1.140 + tDbl , // Double 1.141 + tBool , // Boolean 1.142 + tStr , // String 1.143 + tID , // ID 1.144 + tArr , // Array 1.145 + tISup , // nsISupports (really just a plain JSObject) 1.146 + tUnk , // Unknown. Used only for initial state. 1.147 + 1.148 + tTypeCount , // Just a count for table dimensioning. 1.149 + 1.150 + tVar , // nsVariant - last ditch if no other common type found. 1.151 + tErr // No valid state or type has this value. 1.152 + }; 1.153 + 1.154 + // Table has tUnk as a state (column) but not as a type (row). 1.155 + static const Type StateTable[tTypeCount][tTypeCount-1]; 1.156 + 1.157 +public: 1.158 + static bool GetTypeForArray(JSContext* cx, HandleObject array, 1.159 + uint32_t length, 1.160 + nsXPTType* resultType, nsID* resultID); 1.161 +}; 1.162 + 1.163 + 1.164 +// Current state is the column down the side. 1.165 +// Current type is the row along the top. 1.166 +// New state is in the box at the intersection. 1.167 + 1.168 +const XPCArrayHomogenizer::Type 1.169 +XPCArrayHomogenizer::StateTable[tTypeCount][tTypeCount-1] = { 1.170 +/* tNull,tInt ,tDbl ,tBool,tStr ,tID ,tArr ,tISup */ 1.171 +/* tNull */{tNull,tVar ,tVar ,tVar ,tStr ,tID ,tVar ,tISup }, 1.172 +/* tInt */{tVar ,tInt ,tDbl ,tVar ,tVar ,tVar ,tVar ,tVar }, 1.173 +/* tDbl */{tVar ,tDbl ,tDbl ,tVar ,tVar ,tVar ,tVar ,tVar }, 1.174 +/* tBool */{tVar ,tVar ,tVar ,tBool,tVar ,tVar ,tVar ,tVar }, 1.175 +/* tStr */{tStr ,tVar ,tVar ,tVar ,tStr ,tVar ,tVar ,tVar }, 1.176 +/* tID */{tID ,tVar ,tVar ,tVar ,tVar ,tID ,tVar ,tVar }, 1.177 +/* tArr */{tErr ,tErr ,tErr ,tErr ,tErr ,tErr ,tErr ,tErr }, 1.178 +/* tISup */{tISup,tVar ,tVar ,tVar ,tVar ,tVar ,tVar ,tISup }, 1.179 +/* tUnk */{tNull,tInt ,tDbl ,tBool,tStr ,tID ,tVar ,tISup }}; 1.180 + 1.181 +// static 1.182 +bool 1.183 +XPCArrayHomogenizer::GetTypeForArray(JSContext* cx, HandleObject array, 1.184 + uint32_t length, 1.185 + nsXPTType* resultType, nsID* resultID) 1.186 +{ 1.187 + Type state = tUnk; 1.188 + Type type; 1.189 + 1.190 + RootedValue val(cx); 1.191 + RootedObject jsobj(cx); 1.192 + for (uint32_t i = 0; i < length; i++) { 1.193 + if (!JS_GetElement(cx, array, i, &val)) 1.194 + return false; 1.195 + 1.196 + if (val.isInt32()) { 1.197 + type = tInt; 1.198 + } else if (val.isDouble()) { 1.199 + type = tDbl; 1.200 + } else if (val.isBoolean()) { 1.201 + type = tBool; 1.202 + } else if (val.isUndefined()) { 1.203 + state = tVar; 1.204 + break; 1.205 + } else if (val.isNull()) { 1.206 + type = tNull; 1.207 + } else if (val.isString()) { 1.208 + type = tStr; 1.209 + } else { 1.210 + MOZ_ASSERT(val.isObject(), "invalid type of jsval!"); 1.211 + jsobj = &val.toObject(); 1.212 + if (JS_IsArrayObject(cx, jsobj)) 1.213 + type = tArr; 1.214 + else if (xpc_JSObjectIsID(cx, jsobj)) 1.215 + type = tID; 1.216 + else 1.217 + type = tISup; 1.218 + } 1.219 + 1.220 + MOZ_ASSERT(state != tErr, "bad state table!"); 1.221 + MOZ_ASSERT(type != tErr, "bad type!"); 1.222 + MOZ_ASSERT(type != tVar, "bad type!"); 1.223 + MOZ_ASSERT(type != tUnk, "bad type!"); 1.224 + 1.225 + state = StateTable[state][type]; 1.226 + 1.227 + MOZ_ASSERT(state != tErr, "bad state table!"); 1.228 + MOZ_ASSERT(state != tUnk, "bad state table!"); 1.229 + 1.230 + if (state == tVar) 1.231 + break; 1.232 + } 1.233 + 1.234 + switch (state) { 1.235 + case tInt : 1.236 + *resultType = nsXPTType((uint8_t)TD_INT32); 1.237 + break; 1.238 + case tDbl : 1.239 + *resultType = nsXPTType((uint8_t)TD_DOUBLE); 1.240 + break; 1.241 + case tBool: 1.242 + *resultType = nsXPTType((uint8_t)TD_BOOL); 1.243 + break; 1.244 + case tStr : 1.245 + *resultType = nsXPTType((uint8_t)TD_PWSTRING); 1.246 + break; 1.247 + case tID : 1.248 + *resultType = nsXPTType((uint8_t)TD_PNSIID); 1.249 + break; 1.250 + case tISup: 1.251 + *resultType = nsXPTType((uint8_t)TD_INTERFACE_IS_TYPE); 1.252 + *resultID = NS_GET_IID(nsISupports); 1.253 + break; 1.254 + case tNull: 1.255 + // FALL THROUGH 1.256 + case tVar : 1.257 + *resultType = nsXPTType((uint8_t)TD_INTERFACE_IS_TYPE); 1.258 + *resultID = NS_GET_IID(nsIVariant); 1.259 + break; 1.260 + case tArr : 1.261 + // FALL THROUGH 1.262 + case tUnk : 1.263 + // FALL THROUGH 1.264 + case tErr : 1.265 + // FALL THROUGH 1.266 + default: 1.267 + NS_ERROR("bad state"); 1.268 + return false; 1.269 + } 1.270 + return true; 1.271 +} 1.272 + 1.273 +bool XPCVariant::InitializeData(JSContext* cx) 1.274 +{ 1.275 + JS_CHECK_RECURSION(cx, return false); 1.276 + 1.277 + RootedValue val(cx, GetJSVal()); 1.278 + 1.279 + if (val.isInt32()) 1.280 + return NS_SUCCEEDED(nsVariant::SetFromInt32(&mData, val.toInt32())); 1.281 + if (val.isDouble()) 1.282 + return NS_SUCCEEDED(nsVariant::SetFromDouble(&mData, val.toDouble())); 1.283 + if (val.isBoolean()) 1.284 + return NS_SUCCEEDED(nsVariant::SetFromBool(&mData, val.toBoolean())); 1.285 + if (val.isUndefined()) 1.286 + return NS_SUCCEEDED(nsVariant::SetToVoid(&mData)); 1.287 + if (val.isNull()) 1.288 + return NS_SUCCEEDED(nsVariant::SetToEmpty(&mData)); 1.289 + if (val.isString()) { 1.290 + JSString* str = val.toString(); 1.291 + if (!str) 1.292 + return false; 1.293 + 1.294 + // Don't use nsVariant::SetFromWStringWithSize, because that will copy 1.295 + // the data. Just handle this ourselves. Note that it's ok to not 1.296 + // copy because we added mJSVal as a GC root. 1.297 + MOZ_ASSERT(mData.mType == nsIDataType::VTYPE_EMPTY, 1.298 + "Why do we already have data?"); 1.299 + 1.300 + // Despite the fact that the variant holds the length, there are 1.301 + // implicit assumptions that mWStringValue[mWStringLength] == 0 1.302 + size_t length; 1.303 + const jschar *chars = JS_GetStringCharsZAndLength(cx, str, &length); 1.304 + if (!chars) 1.305 + return false; 1.306 + 1.307 + mData.u.wstr.mWStringValue = const_cast<jschar *>(chars); 1.308 + // Use C-style cast, because reinterpret cast from size_t to 1.309 + // uint32_t is not valid on some platforms. 1.310 + mData.u.wstr.mWStringLength = (uint32_t)length; 1.311 + mData.mType = nsIDataType::VTYPE_WSTRING_SIZE_IS; 1.312 + 1.313 + return true; 1.314 + } 1.315 + 1.316 + // leaving only JSObject... 1.317 + MOZ_ASSERT(val.isObject(), "invalid type of jsval!"); 1.318 + 1.319 + RootedObject jsobj(cx, &val.toObject()); 1.320 + 1.321 + // Let's see if it is a xpcJSID. 1.322 + 1.323 + const nsID* id = xpc_JSObjectToID(cx, jsobj); 1.324 + if (id) 1.325 + return NS_SUCCEEDED(nsVariant::SetFromID(&mData, *id)); 1.326 + 1.327 + // Let's see if it is a js array object. 1.328 + 1.329 + uint32_t len; 1.330 + 1.331 + if (JS_IsArrayObject(cx, jsobj) && JS_GetArrayLength(cx, jsobj, &len)) { 1.332 + if (!len) { 1.333 + // Zero length array 1.334 + nsVariant::SetToEmptyArray(&mData); 1.335 + return true; 1.336 + } 1.337 + 1.338 + nsXPTType type; 1.339 + nsID id; 1.340 + 1.341 + if (!XPCArrayHomogenizer::GetTypeForArray(cx, jsobj, len, &type, &id)) 1.342 + return false; 1.343 + 1.344 + if (!XPCConvert::JSArray2Native(&mData.u.array.mArrayValue, 1.345 + val, len, type, &id, nullptr)) 1.346 + return false; 1.347 + 1.348 + mData.mType = nsIDataType::VTYPE_ARRAY; 1.349 + if (type.IsInterfacePointer()) 1.350 + mData.u.array.mArrayInterfaceID = id; 1.351 + mData.u.array.mArrayCount = len; 1.352 + mData.u.array.mArrayType = type.TagPart(); 1.353 + 1.354 + return true; 1.355 + } 1.356 + 1.357 + // XXX This could be smarter and pick some more interesting iface. 1.358 + 1.359 + nsXPConnect* xpc = nsXPConnect::XPConnect(); 1.360 + nsCOMPtr<nsISupports> wrapper; 1.361 + const nsIID& iid = NS_GET_IID(nsISupports); 1.362 + 1.363 + return NS_SUCCEEDED(xpc->WrapJS(cx, jsobj, 1.364 + iid, getter_AddRefs(wrapper))) && 1.365 + NS_SUCCEEDED(nsVariant::SetFromInterface(&mData, iid, wrapper)); 1.366 +} 1.367 + 1.368 +NS_IMETHODIMP 1.369 +XPCVariant::GetAsJSVal(MutableHandleValue result) 1.370 +{ 1.371 + result.set(GetJSVal()); 1.372 + return NS_OK; 1.373 +} 1.374 + 1.375 +// static 1.376 +bool 1.377 +XPCVariant::VariantDataToJS(nsIVariant* variant, 1.378 + nsresult* pErr, MutableHandleValue pJSVal) 1.379 +{ 1.380 + // Get the type early because we might need to spoof it below. 1.381 + uint16_t type; 1.382 + if (NS_FAILED(variant->GetDataType(&type))) 1.383 + return false; 1.384 + 1.385 + AutoJSContext cx; 1.386 + RootedValue realVal(cx); 1.387 + nsresult rv = variant->GetAsJSVal(&realVal); 1.388 + 1.389 + if (NS_SUCCEEDED(rv) && 1.390 + (JSVAL_IS_PRIMITIVE(realVal) || 1.391 + type == nsIDataType::VTYPE_ARRAY || 1.392 + type == nsIDataType::VTYPE_EMPTY_ARRAY || 1.393 + type == nsIDataType::VTYPE_ID)) { 1.394 + if (!JS_WrapValue(cx, &realVal)) 1.395 + return false; 1.396 + pJSVal.set(realVal); 1.397 + return true; 1.398 + } 1.399 + 1.400 + nsCOMPtr<XPCVariant> xpcvariant = do_QueryInterface(variant); 1.401 + if (xpcvariant && xpcvariant->mReturnRawObject) { 1.402 + MOZ_ASSERT(type == nsIDataType::VTYPE_INTERFACE || 1.403 + type == nsIDataType::VTYPE_INTERFACE_IS, 1.404 + "Weird variant"); 1.405 + 1.406 + if (!JS_WrapValue(cx, &realVal)) 1.407 + return false; 1.408 + pJSVal.set(realVal); 1.409 + return true; 1.410 + } 1.411 + 1.412 + // else, it's an object and we really need to double wrap it if we've 1.413 + // already decided that its 'natural' type is as some sort of interface. 1.414 + 1.415 + // We just fall through to the code below and let it do what it does. 1.416 + 1.417 + // The nsIVariant is not a XPCVariant (or we act like it isn't). 1.418 + // So we extract the data and do the Right Thing. 1.419 + 1.420 + // We ASSUME that the variant implementation can do these conversions... 1.421 + 1.422 + nsID iid; 1.423 + 1.424 + switch (type) { 1.425 + case nsIDataType::VTYPE_INT8: 1.426 + case nsIDataType::VTYPE_INT16: 1.427 + case nsIDataType::VTYPE_INT32: 1.428 + case nsIDataType::VTYPE_INT64: 1.429 + case nsIDataType::VTYPE_UINT8: 1.430 + case nsIDataType::VTYPE_UINT16: 1.431 + case nsIDataType::VTYPE_UINT32: 1.432 + case nsIDataType::VTYPE_UINT64: 1.433 + case nsIDataType::VTYPE_FLOAT: 1.434 + case nsIDataType::VTYPE_DOUBLE: 1.435 + { 1.436 + double d; 1.437 + if (NS_FAILED(variant->GetAsDouble(&d))) 1.438 + return false; 1.439 + pJSVal.setNumber(d); 1.440 + return true; 1.441 + } 1.442 + case nsIDataType::VTYPE_BOOL: 1.443 + { 1.444 + bool b; 1.445 + if (NS_FAILED(variant->GetAsBool(&b))) 1.446 + return false; 1.447 + pJSVal.setBoolean(b); 1.448 + return true; 1.449 + } 1.450 + case nsIDataType::VTYPE_CHAR: 1.451 + { 1.452 + char c; 1.453 + if (NS_FAILED(variant->GetAsChar(&c))) 1.454 + return false; 1.455 + return XPCConvert::NativeData2JS(pJSVal, (const void*)&c, TD_CHAR, &iid, pErr); 1.456 + } 1.457 + case nsIDataType::VTYPE_WCHAR: 1.458 + { 1.459 + char16_t wc; 1.460 + if (NS_FAILED(variant->GetAsWChar(&wc))) 1.461 + return false; 1.462 + return XPCConvert::NativeData2JS(pJSVal, (const void*)&wc, TD_WCHAR, &iid, pErr); 1.463 + } 1.464 + case nsIDataType::VTYPE_ID: 1.465 + { 1.466 + if (NS_FAILED(variant->GetAsID(&iid))) 1.467 + return false; 1.468 + nsID *v = &iid; 1.469 + return XPCConvert::NativeData2JS(pJSVal, (const void*)&v, TD_PNSIID, &iid, pErr); 1.470 + } 1.471 + case nsIDataType::VTYPE_ASTRING: 1.472 + { 1.473 + nsAutoString astring; 1.474 + if (NS_FAILED(variant->GetAsAString(astring))) 1.475 + return false; 1.476 + nsAutoString *v = &astring; 1.477 + return XPCConvert::NativeData2JS(pJSVal, (const void*)&v, TD_ASTRING, &iid, pErr); 1.478 + } 1.479 + case nsIDataType::VTYPE_DOMSTRING: 1.480 + { 1.481 + nsAutoString astring; 1.482 + if (NS_FAILED(variant->GetAsAString(astring))) 1.483 + return false; 1.484 + nsAutoString *v = &astring; 1.485 + return XPCConvert::NativeData2JS(pJSVal, (const void*)&v, 1.486 + TD_DOMSTRING, &iid, pErr); 1.487 + } 1.488 + case nsIDataType::VTYPE_CSTRING: 1.489 + { 1.490 + nsAutoCString cString; 1.491 + if (NS_FAILED(variant->GetAsACString(cString))) 1.492 + return false; 1.493 + nsAutoCString *v = &cString; 1.494 + return XPCConvert::NativeData2JS(pJSVal, (const void*)&v, 1.495 + TD_CSTRING, &iid, pErr); 1.496 + } 1.497 + case nsIDataType::VTYPE_UTF8STRING: 1.498 + { 1.499 + nsUTF8String utf8String; 1.500 + if (NS_FAILED(variant->GetAsAUTF8String(utf8String))) 1.501 + return false; 1.502 + nsUTF8String *v = &utf8String; 1.503 + return XPCConvert::NativeData2JS(pJSVal, (const void*)&v, 1.504 + TD_UTF8STRING, &iid, pErr); 1.505 + } 1.506 + case nsIDataType::VTYPE_CHAR_STR: 1.507 + { 1.508 + char *pc; 1.509 + if (NS_FAILED(variant->GetAsString(&pc))) 1.510 + return false; 1.511 + bool success = XPCConvert::NativeData2JS(pJSVal, (const void*)&pc, 1.512 + TD_PSTRING, &iid, pErr); 1.513 + nsMemory::Free(pc); 1.514 + return success; 1.515 + } 1.516 + case nsIDataType::VTYPE_STRING_SIZE_IS: 1.517 + { 1.518 + char *pc; 1.519 + uint32_t size; 1.520 + if (NS_FAILED(variant->GetAsStringWithSize(&size, &pc))) 1.521 + return false; 1.522 + bool success = XPCConvert::NativeStringWithSize2JS(pJSVal, (const void*)&pc, 1.523 + TD_PSTRING_SIZE_IS, size, pErr); 1.524 + nsMemory::Free(pc); 1.525 + return success; 1.526 + } 1.527 + case nsIDataType::VTYPE_WCHAR_STR: 1.528 + { 1.529 + char16_t *pwc; 1.530 + if (NS_FAILED(variant->GetAsWString(&pwc))) 1.531 + return false; 1.532 + bool success = XPCConvert::NativeData2JS(pJSVal, (const void*)&pwc, 1.533 + TD_PSTRING, &iid, pErr); 1.534 + nsMemory::Free(pwc); 1.535 + return success; 1.536 + } 1.537 + case nsIDataType::VTYPE_WSTRING_SIZE_IS: 1.538 + { 1.539 + char16_t *pwc; 1.540 + uint32_t size; 1.541 + if (NS_FAILED(variant->GetAsWStringWithSize(&size, &pwc))) 1.542 + return false; 1.543 + bool success = XPCConvert::NativeStringWithSize2JS(pJSVal, (const void*)&pwc, 1.544 + TD_PWSTRING_SIZE_IS, size, pErr); 1.545 + nsMemory::Free(pwc); 1.546 + return success; 1.547 + } 1.548 + case nsIDataType::VTYPE_INTERFACE: 1.549 + case nsIDataType::VTYPE_INTERFACE_IS: 1.550 + { 1.551 + nsISupports *pi; 1.552 + nsID* piid; 1.553 + if (NS_FAILED(variant->GetAsInterface(&piid, (void **)&pi))) 1.554 + return false; 1.555 + 1.556 + iid = *piid; 1.557 + nsMemory::Free((char*)piid); 1.558 + 1.559 + bool success = XPCConvert::NativeData2JS(pJSVal, (const void*)&pi, 1.560 + TD_INTERFACE_IS_TYPE, &iid, pErr); 1.561 + if (pi) 1.562 + pi->Release(); 1.563 + return success; 1.564 + } 1.565 + case nsIDataType::VTYPE_ARRAY: 1.566 + { 1.567 + nsDiscriminatedUnion du; 1.568 + nsVariant::Initialize(&du); 1.569 + nsresult rv; 1.570 + 1.571 + rv = variant->GetAsArray(&du.u.array.mArrayType, 1.572 + &du.u.array.mArrayInterfaceID, 1.573 + &du.u.array.mArrayCount, 1.574 + &du.u.array.mArrayValue); 1.575 + if (NS_FAILED(rv)) 1.576 + return false; 1.577 + 1.578 + // must exit via VARIANT_DONE from here on... 1.579 + du.mType = nsIDataType::VTYPE_ARRAY; 1.580 + bool success = false; 1.581 + 1.582 + nsXPTType conversionType; 1.583 + uint16_t elementType = du.u.array.mArrayType; 1.584 + const nsID* pid = nullptr; 1.585 + 1.586 + switch (elementType) { 1.587 + case nsIDataType::VTYPE_INT8: 1.588 + case nsIDataType::VTYPE_INT16: 1.589 + case nsIDataType::VTYPE_INT32: 1.590 + case nsIDataType::VTYPE_INT64: 1.591 + case nsIDataType::VTYPE_UINT8: 1.592 + case nsIDataType::VTYPE_UINT16: 1.593 + case nsIDataType::VTYPE_UINT32: 1.594 + case nsIDataType::VTYPE_UINT64: 1.595 + case nsIDataType::VTYPE_FLOAT: 1.596 + case nsIDataType::VTYPE_DOUBLE: 1.597 + case nsIDataType::VTYPE_BOOL: 1.598 + case nsIDataType::VTYPE_CHAR: 1.599 + case nsIDataType::VTYPE_WCHAR: 1.600 + conversionType = nsXPTType((uint8_t)elementType); 1.601 + break; 1.602 + 1.603 + case nsIDataType::VTYPE_ID: 1.604 + case nsIDataType::VTYPE_CHAR_STR: 1.605 + case nsIDataType::VTYPE_WCHAR_STR: 1.606 + conversionType = nsXPTType((uint8_t)elementType); 1.607 + break; 1.608 + 1.609 + case nsIDataType::VTYPE_INTERFACE: 1.610 + pid = &NS_GET_IID(nsISupports); 1.611 + conversionType = nsXPTType((uint8_t)elementType); 1.612 + break; 1.613 + 1.614 + case nsIDataType::VTYPE_INTERFACE_IS: 1.615 + pid = &du.u.array.mArrayInterfaceID; 1.616 + conversionType = nsXPTType((uint8_t)elementType); 1.617 + break; 1.618 + 1.619 + // The rest are illegal. 1.620 + case nsIDataType::VTYPE_VOID: 1.621 + case nsIDataType::VTYPE_ASTRING: 1.622 + case nsIDataType::VTYPE_DOMSTRING: 1.623 + case nsIDataType::VTYPE_CSTRING: 1.624 + case nsIDataType::VTYPE_UTF8STRING: 1.625 + case nsIDataType::VTYPE_WSTRING_SIZE_IS: 1.626 + case nsIDataType::VTYPE_STRING_SIZE_IS: 1.627 + case nsIDataType::VTYPE_ARRAY: 1.628 + case nsIDataType::VTYPE_EMPTY_ARRAY: 1.629 + case nsIDataType::VTYPE_EMPTY: 1.630 + default: 1.631 + NS_ERROR("bad type in array!"); 1.632 + goto VARIANT_DONE; 1.633 + } 1.634 + 1.635 + success = 1.636 + XPCConvert::NativeArray2JS(pJSVal, 1.637 + (const void**)&du.u.array.mArrayValue, 1.638 + conversionType, pid, 1.639 + du.u.array.mArrayCount, pErr); 1.640 + 1.641 +VARIANT_DONE: 1.642 + nsVariant::Cleanup(&du); 1.643 + return success; 1.644 + } 1.645 + case nsIDataType::VTYPE_EMPTY_ARRAY: 1.646 + { 1.647 + JSObject* array = JS_NewArrayObject(cx, 0); 1.648 + if (!array) 1.649 + return false; 1.650 + pJSVal.setObject(*array); 1.651 + return true; 1.652 + } 1.653 + case nsIDataType::VTYPE_VOID: 1.654 + pJSVal.setUndefined(); 1.655 + return true; 1.656 + case nsIDataType::VTYPE_EMPTY: 1.657 + pJSVal.setNull(); 1.658 + return true; 1.659 + default: 1.660 + NS_ERROR("bad type in variant!"); 1.661 + return false; 1.662 + } 1.663 +} 1.664 + 1.665 +/***************************************************************************/ 1.666 +/***************************************************************************/ 1.667 +// XXX These default implementations need to be improved to allow for 1.668 +// some more interesting conversions. 1.669 + 1.670 + 1.671 +/* readonly attribute uint16_t dataType; */ 1.672 +NS_IMETHODIMP XPCVariant::GetDataType(uint16_t *aDataType) 1.673 +{ 1.674 + *aDataType = mData.mType; 1.675 + return NS_OK; 1.676 +} 1.677 + 1.678 +/* uint8_t getAsInt8 (); */ 1.679 +NS_IMETHODIMP XPCVariant::GetAsInt8(uint8_t *_retval) 1.680 +{ 1.681 + return nsVariant::ConvertToInt8(mData, _retval); 1.682 +} 1.683 + 1.684 +/* int16_t getAsInt16 (); */ 1.685 +NS_IMETHODIMP XPCVariant::GetAsInt16(int16_t *_retval) 1.686 +{ 1.687 + return nsVariant::ConvertToInt16(mData, _retval); 1.688 +} 1.689 + 1.690 +/* int32_t getAsInt32 (); */ 1.691 +NS_IMETHODIMP XPCVariant::GetAsInt32(int32_t *_retval) 1.692 +{ 1.693 + return nsVariant::ConvertToInt32(mData, _retval); 1.694 +} 1.695 + 1.696 +/* int64_t getAsInt64 (); */ 1.697 +NS_IMETHODIMP XPCVariant::GetAsInt64(int64_t *_retval) 1.698 +{ 1.699 + return nsVariant::ConvertToInt64(mData, _retval); 1.700 +} 1.701 + 1.702 +/* uint8_t getAsUint8 (); */ 1.703 +NS_IMETHODIMP XPCVariant::GetAsUint8(uint8_t *_retval) 1.704 +{ 1.705 + return nsVariant::ConvertToUint8(mData, _retval); 1.706 +} 1.707 + 1.708 +/* uint16_t getAsUint16 (); */ 1.709 +NS_IMETHODIMP XPCVariant::GetAsUint16(uint16_t *_retval) 1.710 +{ 1.711 + return nsVariant::ConvertToUint16(mData, _retval); 1.712 +} 1.713 + 1.714 +/* uint32_t getAsUint32 (); */ 1.715 +NS_IMETHODIMP XPCVariant::GetAsUint32(uint32_t *_retval) 1.716 +{ 1.717 + return nsVariant::ConvertToUint32(mData, _retval); 1.718 +} 1.719 + 1.720 +/* uint64_t getAsUint64 (); */ 1.721 +NS_IMETHODIMP XPCVariant::GetAsUint64(uint64_t *_retval) 1.722 +{ 1.723 + return nsVariant::ConvertToUint64(mData, _retval); 1.724 +} 1.725 + 1.726 +/* float getAsFloat (); */ 1.727 +NS_IMETHODIMP XPCVariant::GetAsFloat(float *_retval) 1.728 +{ 1.729 + return nsVariant::ConvertToFloat(mData, _retval); 1.730 +} 1.731 + 1.732 +/* double getAsDouble (); */ 1.733 +NS_IMETHODIMP XPCVariant::GetAsDouble(double *_retval) 1.734 +{ 1.735 + return nsVariant::ConvertToDouble(mData, _retval); 1.736 +} 1.737 + 1.738 +/* bool getAsBool (); */ 1.739 +NS_IMETHODIMP XPCVariant::GetAsBool(bool *_retval) 1.740 +{ 1.741 + return nsVariant::ConvertToBool(mData, _retval); 1.742 +} 1.743 + 1.744 +/* char getAsChar (); */ 1.745 +NS_IMETHODIMP XPCVariant::GetAsChar(char *_retval) 1.746 +{ 1.747 + return nsVariant::ConvertToChar(mData, _retval); 1.748 +} 1.749 + 1.750 +/* wchar getAsWChar (); */ 1.751 +NS_IMETHODIMP XPCVariant::GetAsWChar(char16_t *_retval) 1.752 +{ 1.753 + return nsVariant::ConvertToWChar(mData, _retval); 1.754 +} 1.755 + 1.756 +/* [notxpcom] nsresult getAsID (out nsID retval); */ 1.757 +NS_IMETHODIMP_(nsresult) XPCVariant::GetAsID(nsID *retval) 1.758 +{ 1.759 + return nsVariant::ConvertToID(mData, retval); 1.760 +} 1.761 + 1.762 +/* AString getAsAString (); */ 1.763 +NS_IMETHODIMP XPCVariant::GetAsAString(nsAString & _retval) 1.764 +{ 1.765 + return nsVariant::ConvertToAString(mData, _retval); 1.766 +} 1.767 + 1.768 +/* DOMString getAsDOMString (); */ 1.769 +NS_IMETHODIMP XPCVariant::GetAsDOMString(nsAString & _retval) 1.770 +{ 1.771 + // A DOMString maps to an AString internally, so we can re-use 1.772 + // ConvertToAString here. 1.773 + return nsVariant::ConvertToAString(mData, _retval); 1.774 +} 1.775 + 1.776 +/* ACString getAsACString (); */ 1.777 +NS_IMETHODIMP XPCVariant::GetAsACString(nsACString & _retval) 1.778 +{ 1.779 + return nsVariant::ConvertToACString(mData, _retval); 1.780 +} 1.781 + 1.782 +/* AUTF8String getAsAUTF8String (); */ 1.783 +NS_IMETHODIMP XPCVariant::GetAsAUTF8String(nsAUTF8String & _retval) 1.784 +{ 1.785 + return nsVariant::ConvertToAUTF8String(mData, _retval); 1.786 +} 1.787 + 1.788 +/* string getAsString (); */ 1.789 +NS_IMETHODIMP XPCVariant::GetAsString(char **_retval) 1.790 +{ 1.791 + return nsVariant::ConvertToString(mData, _retval); 1.792 +} 1.793 + 1.794 +/* wstring getAsWString (); */ 1.795 +NS_IMETHODIMP XPCVariant::GetAsWString(char16_t **_retval) 1.796 +{ 1.797 + return nsVariant::ConvertToWString(mData, _retval); 1.798 +} 1.799 + 1.800 +/* nsISupports getAsISupports (); */ 1.801 +NS_IMETHODIMP XPCVariant::GetAsISupports(nsISupports **_retval) 1.802 +{ 1.803 + return nsVariant::ConvertToISupports(mData, _retval); 1.804 +} 1.805 + 1.806 +/* void getAsInterface (out nsIIDPtr iid, [iid_is (iid), retval] out nsQIResult iface); */ 1.807 +NS_IMETHODIMP XPCVariant::GetAsInterface(nsIID * *iid, void * *iface) 1.808 +{ 1.809 + return nsVariant::ConvertToInterface(mData, iid, iface); 1.810 +} 1.811 + 1.812 + 1.813 +/* [notxpcom] nsresult getAsArray (out uint16_t type, out nsIID iid, out uint32_t count, out voidPtr ptr); */ 1.814 +NS_IMETHODIMP_(nsresult) XPCVariant::GetAsArray(uint16_t *type, nsIID *iid, uint32_t *count, void * *ptr) 1.815 +{ 1.816 + return nsVariant::ConvertToArray(mData, type, iid, count, ptr); 1.817 +} 1.818 + 1.819 +/* void getAsStringWithSize (out uint32_t size, [size_is (size), retval] out string str); */ 1.820 +NS_IMETHODIMP XPCVariant::GetAsStringWithSize(uint32_t *size, char **str) 1.821 +{ 1.822 + return nsVariant::ConvertToStringWithSize(mData, size, str); 1.823 +} 1.824 + 1.825 +/* void getAsWStringWithSize (out uint32_t size, [size_is (size), retval] out wstring str); */ 1.826 +NS_IMETHODIMP XPCVariant::GetAsWStringWithSize(uint32_t *size, char16_t **str) 1.827 +{ 1.828 + return nsVariant::ConvertToWStringWithSize(mData, size, str); 1.829 +} 1.830 + 1.831 +