js/xpconnect/src/XPCVariant.cpp

Thu, 15 Jan 2015 15:55:04 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 15 Jan 2015 15:55:04 +0100
branch
TOR_BUG_9701
changeset 9
a63d609f5ebe
permissions
-rw-r--r--

Back out 97036ab72558 which inappropriately compared turds to third parties.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
michael@0 2 /* vim: set ts=8 sts=4 et sw=4 tw=99: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 /* nsIVariant implementation for xpconnect. */
michael@0 8
michael@0 9 #include "xpcprivate.h"
michael@0 10 #include "nsCxPusher.h"
michael@0 11
michael@0 12 #include "jsfriendapi.h"
michael@0 13 #include "jsprf.h"
michael@0 14 #include "jswrapper.h"
michael@0 15
michael@0 16 using namespace JS;
michael@0 17 using namespace mozilla;
michael@0 18
michael@0 19 NS_IMPL_CLASSINFO(XPCVariant, nullptr, 0, XPCVARIANT_CID)
michael@0 20 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XPCVariant)
michael@0 21 NS_INTERFACE_MAP_ENTRY(XPCVariant)
michael@0 22 NS_INTERFACE_MAP_ENTRY(nsIVariant)
michael@0 23 NS_INTERFACE_MAP_ENTRY(nsISupports)
michael@0 24 NS_IMPL_QUERY_CLASSINFO(XPCVariant)
michael@0 25 NS_INTERFACE_MAP_END
michael@0 26 NS_IMPL_CI_INTERFACE_GETTER(XPCVariant, XPCVariant, nsIVariant)
michael@0 27
michael@0 28 NS_IMPL_CYCLE_COLLECTING_ADDREF(XPCVariant)
michael@0 29 NS_IMPL_CYCLE_COLLECTING_RELEASE(XPCVariant)
michael@0 30
michael@0 31 XPCVariant::XPCVariant(JSContext* cx, jsval aJSVal)
michael@0 32 : mJSVal(aJSVal), mCCGeneration(0)
michael@0 33 {
michael@0 34 nsVariant::Initialize(&mData);
michael@0 35 if (!mJSVal.isPrimitive()) {
michael@0 36 // XXXbholley - The innerization here was from bug 638026. Blake says
michael@0 37 // the basic problem was that we were storing the C++ inner but the JS
michael@0 38 // outer, which meant that, after navigation, the JS inner could be
michael@0 39 // collected, which would cause us to try to recreate the JS inner at
michael@0 40 // some later point after teardown, which would crash. This is shouldn't
michael@0 41 // be a problem anymore because SetParentToWindow will do the right
michael@0 42 // thing, but I'm saving the cleanup here for another day. Blake thinks
michael@0 43 // that we should just not store the WN if we're creating a variant for
michael@0 44 // an outer window.
michael@0 45 JS::RootedObject obj(cx, &mJSVal.toObject());
michael@0 46 obj = JS_ObjectToInnerObject(cx, obj);
michael@0 47 mJSVal = JS::ObjectValue(*obj);
michael@0 48
michael@0 49 JSObject *unwrapped = js::CheckedUnwrap(obj, /* stopAtOuter = */ false);
michael@0 50 mReturnRawObject = !(unwrapped && IS_WN_REFLECTOR(unwrapped));
michael@0 51 } else
michael@0 52 mReturnRawObject = false;
michael@0 53 }
michael@0 54
michael@0 55 XPCTraceableVariant::~XPCTraceableVariant()
michael@0 56 {
michael@0 57 jsval val = GetJSValPreserveColor();
michael@0 58
michael@0 59 MOZ_ASSERT(JSVAL_IS_GCTHING(val), "Must be traceable or unlinked");
michael@0 60
michael@0 61 // If val is JSVAL_STRING, we don't need to clean anything up; simply
michael@0 62 // removing the string from the root set is good.
michael@0 63 if (!JSVAL_IS_STRING(val))
michael@0 64 nsVariant::Cleanup(&mData);
michael@0 65
michael@0 66 if (!JSVAL_IS_NULL(val))
michael@0 67 RemoveFromRootSet();
michael@0 68 }
michael@0 69
michael@0 70 void XPCTraceableVariant::TraceJS(JSTracer* trc)
michael@0 71 {
michael@0 72 MOZ_ASSERT(mJSVal.isMarkable());
michael@0 73 trc->setTracingDetails(GetTraceName, this, 0);
michael@0 74 JS_CallHeapValueTracer(trc, &mJSVal, "XPCTraceableVariant::mJSVal");
michael@0 75 }
michael@0 76
michael@0 77 // static
michael@0 78 void
michael@0 79 XPCTraceableVariant::GetTraceName(JSTracer* trc, char *buf, size_t bufsize)
michael@0 80 {
michael@0 81 JS_snprintf(buf, bufsize, "XPCVariant[0x%p].mJSVal", trc->debugPrintArg());
michael@0 82 }
michael@0 83
michael@0 84 NS_IMPL_CYCLE_COLLECTION_CLASS(XPCVariant)
michael@0 85
michael@0 86 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XPCVariant)
michael@0 87 JS::Value val = tmp->GetJSValPreserveColor();
michael@0 88 if (val.isObjectOrNull()) {
michael@0 89 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mJSVal");
michael@0 90 cb.NoteJSChild(JSVAL_TO_OBJECT(val));
michael@0 91 }
michael@0 92
michael@0 93 nsVariant::Traverse(tmp->mData, cb);
michael@0 94 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
michael@0 95
michael@0 96 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XPCVariant)
michael@0 97 JS::Value val = tmp->GetJSValPreserveColor();
michael@0 98
michael@0 99 // We're sharing val's buffer, clear the pointer to it so Cleanup() won't
michael@0 100 // try to delete it
michael@0 101 if (val.isString())
michael@0 102 tmp->mData.u.wstr.mWStringValue = nullptr;
michael@0 103 nsVariant::Cleanup(&tmp->mData);
michael@0 104
michael@0 105 if (val.isMarkable()) {
michael@0 106 XPCTraceableVariant *v = static_cast<XPCTraceableVariant*>(tmp);
michael@0 107 v->RemoveFromRootSet();
michael@0 108 }
michael@0 109 tmp->mJSVal = JS::NullValue();
michael@0 110 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
michael@0 111
michael@0 112 // static
michael@0 113 already_AddRefed<XPCVariant>
michael@0 114 XPCVariant::newVariant(JSContext* cx, jsval aJSVal)
michael@0 115 {
michael@0 116 nsRefPtr<XPCVariant> variant;
michael@0 117
michael@0 118 if (!aJSVal.isMarkable())
michael@0 119 variant = new XPCVariant(cx, aJSVal);
michael@0 120 else
michael@0 121 variant = new XPCTraceableVariant(cx, aJSVal);
michael@0 122
michael@0 123 if (!variant->InitializeData(cx))
michael@0 124 return nullptr;
michael@0 125
michael@0 126 return variant.forget();
michael@0 127 }
michael@0 128
michael@0 129 // Helper class to give us a namespace for the table based code below.
michael@0 130 class XPCArrayHomogenizer
michael@0 131 {
michael@0 132 private:
michael@0 133 enum Type
michael@0 134 {
michael@0 135 tNull = 0 , // null value
michael@0 136 tInt , // Integer
michael@0 137 tDbl , // Double
michael@0 138 tBool , // Boolean
michael@0 139 tStr , // String
michael@0 140 tID , // ID
michael@0 141 tArr , // Array
michael@0 142 tISup , // nsISupports (really just a plain JSObject)
michael@0 143 tUnk , // Unknown. Used only for initial state.
michael@0 144
michael@0 145 tTypeCount , // Just a count for table dimensioning.
michael@0 146
michael@0 147 tVar , // nsVariant - last ditch if no other common type found.
michael@0 148 tErr // No valid state or type has this value.
michael@0 149 };
michael@0 150
michael@0 151 // Table has tUnk as a state (column) but not as a type (row).
michael@0 152 static const Type StateTable[tTypeCount][tTypeCount-1];
michael@0 153
michael@0 154 public:
michael@0 155 static bool GetTypeForArray(JSContext* cx, HandleObject array,
michael@0 156 uint32_t length,
michael@0 157 nsXPTType* resultType, nsID* resultID);
michael@0 158 };
michael@0 159
michael@0 160
michael@0 161 // Current state is the column down the side.
michael@0 162 // Current type is the row along the top.
michael@0 163 // New state is in the box at the intersection.
michael@0 164
michael@0 165 const XPCArrayHomogenizer::Type
michael@0 166 XPCArrayHomogenizer::StateTable[tTypeCount][tTypeCount-1] = {
michael@0 167 /* tNull,tInt ,tDbl ,tBool,tStr ,tID ,tArr ,tISup */
michael@0 168 /* tNull */{tNull,tVar ,tVar ,tVar ,tStr ,tID ,tVar ,tISup },
michael@0 169 /* tInt */{tVar ,tInt ,tDbl ,tVar ,tVar ,tVar ,tVar ,tVar },
michael@0 170 /* tDbl */{tVar ,tDbl ,tDbl ,tVar ,tVar ,tVar ,tVar ,tVar },
michael@0 171 /* tBool */{tVar ,tVar ,tVar ,tBool,tVar ,tVar ,tVar ,tVar },
michael@0 172 /* tStr */{tStr ,tVar ,tVar ,tVar ,tStr ,tVar ,tVar ,tVar },
michael@0 173 /* tID */{tID ,tVar ,tVar ,tVar ,tVar ,tID ,tVar ,tVar },
michael@0 174 /* tArr */{tErr ,tErr ,tErr ,tErr ,tErr ,tErr ,tErr ,tErr },
michael@0 175 /* tISup */{tISup,tVar ,tVar ,tVar ,tVar ,tVar ,tVar ,tISup },
michael@0 176 /* tUnk */{tNull,tInt ,tDbl ,tBool,tStr ,tID ,tVar ,tISup }};
michael@0 177
michael@0 178 // static
michael@0 179 bool
michael@0 180 XPCArrayHomogenizer::GetTypeForArray(JSContext* cx, HandleObject array,
michael@0 181 uint32_t length,
michael@0 182 nsXPTType* resultType, nsID* resultID)
michael@0 183 {
michael@0 184 Type state = tUnk;
michael@0 185 Type type;
michael@0 186
michael@0 187 RootedValue val(cx);
michael@0 188 RootedObject jsobj(cx);
michael@0 189 for (uint32_t i = 0; i < length; i++) {
michael@0 190 if (!JS_GetElement(cx, array, i, &val))
michael@0 191 return false;
michael@0 192
michael@0 193 if (val.isInt32()) {
michael@0 194 type = tInt;
michael@0 195 } else if (val.isDouble()) {
michael@0 196 type = tDbl;
michael@0 197 } else if (val.isBoolean()) {
michael@0 198 type = tBool;
michael@0 199 } else if (val.isUndefined()) {
michael@0 200 state = tVar;
michael@0 201 break;
michael@0 202 } else if (val.isNull()) {
michael@0 203 type = tNull;
michael@0 204 } else if (val.isString()) {
michael@0 205 type = tStr;
michael@0 206 } else {
michael@0 207 MOZ_ASSERT(val.isObject(), "invalid type of jsval!");
michael@0 208 jsobj = &val.toObject();
michael@0 209 if (JS_IsArrayObject(cx, jsobj))
michael@0 210 type = tArr;
michael@0 211 else if (xpc_JSObjectIsID(cx, jsobj))
michael@0 212 type = tID;
michael@0 213 else
michael@0 214 type = tISup;
michael@0 215 }
michael@0 216
michael@0 217 MOZ_ASSERT(state != tErr, "bad state table!");
michael@0 218 MOZ_ASSERT(type != tErr, "bad type!");
michael@0 219 MOZ_ASSERT(type != tVar, "bad type!");
michael@0 220 MOZ_ASSERT(type != tUnk, "bad type!");
michael@0 221
michael@0 222 state = StateTable[state][type];
michael@0 223
michael@0 224 MOZ_ASSERT(state != tErr, "bad state table!");
michael@0 225 MOZ_ASSERT(state != tUnk, "bad state table!");
michael@0 226
michael@0 227 if (state == tVar)
michael@0 228 break;
michael@0 229 }
michael@0 230
michael@0 231 switch (state) {
michael@0 232 case tInt :
michael@0 233 *resultType = nsXPTType((uint8_t)TD_INT32);
michael@0 234 break;
michael@0 235 case tDbl :
michael@0 236 *resultType = nsXPTType((uint8_t)TD_DOUBLE);
michael@0 237 break;
michael@0 238 case tBool:
michael@0 239 *resultType = nsXPTType((uint8_t)TD_BOOL);
michael@0 240 break;
michael@0 241 case tStr :
michael@0 242 *resultType = nsXPTType((uint8_t)TD_PWSTRING);
michael@0 243 break;
michael@0 244 case tID :
michael@0 245 *resultType = nsXPTType((uint8_t)TD_PNSIID);
michael@0 246 break;
michael@0 247 case tISup:
michael@0 248 *resultType = nsXPTType((uint8_t)TD_INTERFACE_IS_TYPE);
michael@0 249 *resultID = NS_GET_IID(nsISupports);
michael@0 250 break;
michael@0 251 case tNull:
michael@0 252 // FALL THROUGH
michael@0 253 case tVar :
michael@0 254 *resultType = nsXPTType((uint8_t)TD_INTERFACE_IS_TYPE);
michael@0 255 *resultID = NS_GET_IID(nsIVariant);
michael@0 256 break;
michael@0 257 case tArr :
michael@0 258 // FALL THROUGH
michael@0 259 case tUnk :
michael@0 260 // FALL THROUGH
michael@0 261 case tErr :
michael@0 262 // FALL THROUGH
michael@0 263 default:
michael@0 264 NS_ERROR("bad state");
michael@0 265 return false;
michael@0 266 }
michael@0 267 return true;
michael@0 268 }
michael@0 269
michael@0 270 bool XPCVariant::InitializeData(JSContext* cx)
michael@0 271 {
michael@0 272 JS_CHECK_RECURSION(cx, return false);
michael@0 273
michael@0 274 RootedValue val(cx, GetJSVal());
michael@0 275
michael@0 276 if (val.isInt32())
michael@0 277 return NS_SUCCEEDED(nsVariant::SetFromInt32(&mData, val.toInt32()));
michael@0 278 if (val.isDouble())
michael@0 279 return NS_SUCCEEDED(nsVariant::SetFromDouble(&mData, val.toDouble()));
michael@0 280 if (val.isBoolean())
michael@0 281 return NS_SUCCEEDED(nsVariant::SetFromBool(&mData, val.toBoolean()));
michael@0 282 if (val.isUndefined())
michael@0 283 return NS_SUCCEEDED(nsVariant::SetToVoid(&mData));
michael@0 284 if (val.isNull())
michael@0 285 return NS_SUCCEEDED(nsVariant::SetToEmpty(&mData));
michael@0 286 if (val.isString()) {
michael@0 287 JSString* str = val.toString();
michael@0 288 if (!str)
michael@0 289 return false;
michael@0 290
michael@0 291 // Don't use nsVariant::SetFromWStringWithSize, because that will copy
michael@0 292 // the data. Just handle this ourselves. Note that it's ok to not
michael@0 293 // copy because we added mJSVal as a GC root.
michael@0 294 MOZ_ASSERT(mData.mType == nsIDataType::VTYPE_EMPTY,
michael@0 295 "Why do we already have data?");
michael@0 296
michael@0 297 // Despite the fact that the variant holds the length, there are
michael@0 298 // implicit assumptions that mWStringValue[mWStringLength] == 0
michael@0 299 size_t length;
michael@0 300 const jschar *chars = JS_GetStringCharsZAndLength(cx, str, &length);
michael@0 301 if (!chars)
michael@0 302 return false;
michael@0 303
michael@0 304 mData.u.wstr.mWStringValue = const_cast<jschar *>(chars);
michael@0 305 // Use C-style cast, because reinterpret cast from size_t to
michael@0 306 // uint32_t is not valid on some platforms.
michael@0 307 mData.u.wstr.mWStringLength = (uint32_t)length;
michael@0 308 mData.mType = nsIDataType::VTYPE_WSTRING_SIZE_IS;
michael@0 309
michael@0 310 return true;
michael@0 311 }
michael@0 312
michael@0 313 // leaving only JSObject...
michael@0 314 MOZ_ASSERT(val.isObject(), "invalid type of jsval!");
michael@0 315
michael@0 316 RootedObject jsobj(cx, &val.toObject());
michael@0 317
michael@0 318 // Let's see if it is a xpcJSID.
michael@0 319
michael@0 320 const nsID* id = xpc_JSObjectToID(cx, jsobj);
michael@0 321 if (id)
michael@0 322 return NS_SUCCEEDED(nsVariant::SetFromID(&mData, *id));
michael@0 323
michael@0 324 // Let's see if it is a js array object.
michael@0 325
michael@0 326 uint32_t len;
michael@0 327
michael@0 328 if (JS_IsArrayObject(cx, jsobj) && JS_GetArrayLength(cx, jsobj, &len)) {
michael@0 329 if (!len) {
michael@0 330 // Zero length array
michael@0 331 nsVariant::SetToEmptyArray(&mData);
michael@0 332 return true;
michael@0 333 }
michael@0 334
michael@0 335 nsXPTType type;
michael@0 336 nsID id;
michael@0 337
michael@0 338 if (!XPCArrayHomogenizer::GetTypeForArray(cx, jsobj, len, &type, &id))
michael@0 339 return false;
michael@0 340
michael@0 341 if (!XPCConvert::JSArray2Native(&mData.u.array.mArrayValue,
michael@0 342 val, len, type, &id, nullptr))
michael@0 343 return false;
michael@0 344
michael@0 345 mData.mType = nsIDataType::VTYPE_ARRAY;
michael@0 346 if (type.IsInterfacePointer())
michael@0 347 mData.u.array.mArrayInterfaceID = id;
michael@0 348 mData.u.array.mArrayCount = len;
michael@0 349 mData.u.array.mArrayType = type.TagPart();
michael@0 350
michael@0 351 return true;
michael@0 352 }
michael@0 353
michael@0 354 // XXX This could be smarter and pick some more interesting iface.
michael@0 355
michael@0 356 nsXPConnect* xpc = nsXPConnect::XPConnect();
michael@0 357 nsCOMPtr<nsISupports> wrapper;
michael@0 358 const nsIID& iid = NS_GET_IID(nsISupports);
michael@0 359
michael@0 360 return NS_SUCCEEDED(xpc->WrapJS(cx, jsobj,
michael@0 361 iid, getter_AddRefs(wrapper))) &&
michael@0 362 NS_SUCCEEDED(nsVariant::SetFromInterface(&mData, iid, wrapper));
michael@0 363 }
michael@0 364
michael@0 365 NS_IMETHODIMP
michael@0 366 XPCVariant::GetAsJSVal(MutableHandleValue result)
michael@0 367 {
michael@0 368 result.set(GetJSVal());
michael@0 369 return NS_OK;
michael@0 370 }
michael@0 371
michael@0 372 // static
michael@0 373 bool
michael@0 374 XPCVariant::VariantDataToJS(nsIVariant* variant,
michael@0 375 nsresult* pErr, MutableHandleValue pJSVal)
michael@0 376 {
michael@0 377 // Get the type early because we might need to spoof it below.
michael@0 378 uint16_t type;
michael@0 379 if (NS_FAILED(variant->GetDataType(&type)))
michael@0 380 return false;
michael@0 381
michael@0 382 AutoJSContext cx;
michael@0 383 RootedValue realVal(cx);
michael@0 384 nsresult rv = variant->GetAsJSVal(&realVal);
michael@0 385
michael@0 386 if (NS_SUCCEEDED(rv) &&
michael@0 387 (JSVAL_IS_PRIMITIVE(realVal) ||
michael@0 388 type == nsIDataType::VTYPE_ARRAY ||
michael@0 389 type == nsIDataType::VTYPE_EMPTY_ARRAY ||
michael@0 390 type == nsIDataType::VTYPE_ID)) {
michael@0 391 if (!JS_WrapValue(cx, &realVal))
michael@0 392 return false;
michael@0 393 pJSVal.set(realVal);
michael@0 394 return true;
michael@0 395 }
michael@0 396
michael@0 397 nsCOMPtr<XPCVariant> xpcvariant = do_QueryInterface(variant);
michael@0 398 if (xpcvariant && xpcvariant->mReturnRawObject) {
michael@0 399 MOZ_ASSERT(type == nsIDataType::VTYPE_INTERFACE ||
michael@0 400 type == nsIDataType::VTYPE_INTERFACE_IS,
michael@0 401 "Weird variant");
michael@0 402
michael@0 403 if (!JS_WrapValue(cx, &realVal))
michael@0 404 return false;
michael@0 405 pJSVal.set(realVal);
michael@0 406 return true;
michael@0 407 }
michael@0 408
michael@0 409 // else, it's an object and we really need to double wrap it if we've
michael@0 410 // already decided that its 'natural' type is as some sort of interface.
michael@0 411
michael@0 412 // We just fall through to the code below and let it do what it does.
michael@0 413
michael@0 414 // The nsIVariant is not a XPCVariant (or we act like it isn't).
michael@0 415 // So we extract the data and do the Right Thing.
michael@0 416
michael@0 417 // We ASSUME that the variant implementation can do these conversions...
michael@0 418
michael@0 419 nsID iid;
michael@0 420
michael@0 421 switch (type) {
michael@0 422 case nsIDataType::VTYPE_INT8:
michael@0 423 case nsIDataType::VTYPE_INT16:
michael@0 424 case nsIDataType::VTYPE_INT32:
michael@0 425 case nsIDataType::VTYPE_INT64:
michael@0 426 case nsIDataType::VTYPE_UINT8:
michael@0 427 case nsIDataType::VTYPE_UINT16:
michael@0 428 case nsIDataType::VTYPE_UINT32:
michael@0 429 case nsIDataType::VTYPE_UINT64:
michael@0 430 case nsIDataType::VTYPE_FLOAT:
michael@0 431 case nsIDataType::VTYPE_DOUBLE:
michael@0 432 {
michael@0 433 double d;
michael@0 434 if (NS_FAILED(variant->GetAsDouble(&d)))
michael@0 435 return false;
michael@0 436 pJSVal.setNumber(d);
michael@0 437 return true;
michael@0 438 }
michael@0 439 case nsIDataType::VTYPE_BOOL:
michael@0 440 {
michael@0 441 bool b;
michael@0 442 if (NS_FAILED(variant->GetAsBool(&b)))
michael@0 443 return false;
michael@0 444 pJSVal.setBoolean(b);
michael@0 445 return true;
michael@0 446 }
michael@0 447 case nsIDataType::VTYPE_CHAR:
michael@0 448 {
michael@0 449 char c;
michael@0 450 if (NS_FAILED(variant->GetAsChar(&c)))
michael@0 451 return false;
michael@0 452 return XPCConvert::NativeData2JS(pJSVal, (const void*)&c, TD_CHAR, &iid, pErr);
michael@0 453 }
michael@0 454 case nsIDataType::VTYPE_WCHAR:
michael@0 455 {
michael@0 456 char16_t wc;
michael@0 457 if (NS_FAILED(variant->GetAsWChar(&wc)))
michael@0 458 return false;
michael@0 459 return XPCConvert::NativeData2JS(pJSVal, (const void*)&wc, TD_WCHAR, &iid, pErr);
michael@0 460 }
michael@0 461 case nsIDataType::VTYPE_ID:
michael@0 462 {
michael@0 463 if (NS_FAILED(variant->GetAsID(&iid)))
michael@0 464 return false;
michael@0 465 nsID *v = &iid;
michael@0 466 return XPCConvert::NativeData2JS(pJSVal, (const void*)&v, TD_PNSIID, &iid, pErr);
michael@0 467 }
michael@0 468 case nsIDataType::VTYPE_ASTRING:
michael@0 469 {
michael@0 470 nsAutoString astring;
michael@0 471 if (NS_FAILED(variant->GetAsAString(astring)))
michael@0 472 return false;
michael@0 473 nsAutoString *v = &astring;
michael@0 474 return XPCConvert::NativeData2JS(pJSVal, (const void*)&v, TD_ASTRING, &iid, pErr);
michael@0 475 }
michael@0 476 case nsIDataType::VTYPE_DOMSTRING:
michael@0 477 {
michael@0 478 nsAutoString astring;
michael@0 479 if (NS_FAILED(variant->GetAsAString(astring)))
michael@0 480 return false;
michael@0 481 nsAutoString *v = &astring;
michael@0 482 return XPCConvert::NativeData2JS(pJSVal, (const void*)&v,
michael@0 483 TD_DOMSTRING, &iid, pErr);
michael@0 484 }
michael@0 485 case nsIDataType::VTYPE_CSTRING:
michael@0 486 {
michael@0 487 nsAutoCString cString;
michael@0 488 if (NS_FAILED(variant->GetAsACString(cString)))
michael@0 489 return false;
michael@0 490 nsAutoCString *v = &cString;
michael@0 491 return XPCConvert::NativeData2JS(pJSVal, (const void*)&v,
michael@0 492 TD_CSTRING, &iid, pErr);
michael@0 493 }
michael@0 494 case nsIDataType::VTYPE_UTF8STRING:
michael@0 495 {
michael@0 496 nsUTF8String utf8String;
michael@0 497 if (NS_FAILED(variant->GetAsAUTF8String(utf8String)))
michael@0 498 return false;
michael@0 499 nsUTF8String *v = &utf8String;
michael@0 500 return XPCConvert::NativeData2JS(pJSVal, (const void*)&v,
michael@0 501 TD_UTF8STRING, &iid, pErr);
michael@0 502 }
michael@0 503 case nsIDataType::VTYPE_CHAR_STR:
michael@0 504 {
michael@0 505 char *pc;
michael@0 506 if (NS_FAILED(variant->GetAsString(&pc)))
michael@0 507 return false;
michael@0 508 bool success = XPCConvert::NativeData2JS(pJSVal, (const void*)&pc,
michael@0 509 TD_PSTRING, &iid, pErr);
michael@0 510 nsMemory::Free(pc);
michael@0 511 return success;
michael@0 512 }
michael@0 513 case nsIDataType::VTYPE_STRING_SIZE_IS:
michael@0 514 {
michael@0 515 char *pc;
michael@0 516 uint32_t size;
michael@0 517 if (NS_FAILED(variant->GetAsStringWithSize(&size, &pc)))
michael@0 518 return false;
michael@0 519 bool success = XPCConvert::NativeStringWithSize2JS(pJSVal, (const void*)&pc,
michael@0 520 TD_PSTRING_SIZE_IS, size, pErr);
michael@0 521 nsMemory::Free(pc);
michael@0 522 return success;
michael@0 523 }
michael@0 524 case nsIDataType::VTYPE_WCHAR_STR:
michael@0 525 {
michael@0 526 char16_t *pwc;
michael@0 527 if (NS_FAILED(variant->GetAsWString(&pwc)))
michael@0 528 return false;
michael@0 529 bool success = XPCConvert::NativeData2JS(pJSVal, (const void*)&pwc,
michael@0 530 TD_PSTRING, &iid, pErr);
michael@0 531 nsMemory::Free(pwc);
michael@0 532 return success;
michael@0 533 }
michael@0 534 case nsIDataType::VTYPE_WSTRING_SIZE_IS:
michael@0 535 {
michael@0 536 char16_t *pwc;
michael@0 537 uint32_t size;
michael@0 538 if (NS_FAILED(variant->GetAsWStringWithSize(&size, &pwc)))
michael@0 539 return false;
michael@0 540 bool success = XPCConvert::NativeStringWithSize2JS(pJSVal, (const void*)&pwc,
michael@0 541 TD_PWSTRING_SIZE_IS, size, pErr);
michael@0 542 nsMemory::Free(pwc);
michael@0 543 return success;
michael@0 544 }
michael@0 545 case nsIDataType::VTYPE_INTERFACE:
michael@0 546 case nsIDataType::VTYPE_INTERFACE_IS:
michael@0 547 {
michael@0 548 nsISupports *pi;
michael@0 549 nsID* piid;
michael@0 550 if (NS_FAILED(variant->GetAsInterface(&piid, (void **)&pi)))
michael@0 551 return false;
michael@0 552
michael@0 553 iid = *piid;
michael@0 554 nsMemory::Free((char*)piid);
michael@0 555
michael@0 556 bool success = XPCConvert::NativeData2JS(pJSVal, (const void*)&pi,
michael@0 557 TD_INTERFACE_IS_TYPE, &iid, pErr);
michael@0 558 if (pi)
michael@0 559 pi->Release();
michael@0 560 return success;
michael@0 561 }
michael@0 562 case nsIDataType::VTYPE_ARRAY:
michael@0 563 {
michael@0 564 nsDiscriminatedUnion du;
michael@0 565 nsVariant::Initialize(&du);
michael@0 566 nsresult rv;
michael@0 567
michael@0 568 rv = variant->GetAsArray(&du.u.array.mArrayType,
michael@0 569 &du.u.array.mArrayInterfaceID,
michael@0 570 &du.u.array.mArrayCount,
michael@0 571 &du.u.array.mArrayValue);
michael@0 572 if (NS_FAILED(rv))
michael@0 573 return false;
michael@0 574
michael@0 575 // must exit via VARIANT_DONE from here on...
michael@0 576 du.mType = nsIDataType::VTYPE_ARRAY;
michael@0 577 bool success = false;
michael@0 578
michael@0 579 nsXPTType conversionType;
michael@0 580 uint16_t elementType = du.u.array.mArrayType;
michael@0 581 const nsID* pid = nullptr;
michael@0 582
michael@0 583 switch (elementType) {
michael@0 584 case nsIDataType::VTYPE_INT8:
michael@0 585 case nsIDataType::VTYPE_INT16:
michael@0 586 case nsIDataType::VTYPE_INT32:
michael@0 587 case nsIDataType::VTYPE_INT64:
michael@0 588 case nsIDataType::VTYPE_UINT8:
michael@0 589 case nsIDataType::VTYPE_UINT16:
michael@0 590 case nsIDataType::VTYPE_UINT32:
michael@0 591 case nsIDataType::VTYPE_UINT64:
michael@0 592 case nsIDataType::VTYPE_FLOAT:
michael@0 593 case nsIDataType::VTYPE_DOUBLE:
michael@0 594 case nsIDataType::VTYPE_BOOL:
michael@0 595 case nsIDataType::VTYPE_CHAR:
michael@0 596 case nsIDataType::VTYPE_WCHAR:
michael@0 597 conversionType = nsXPTType((uint8_t)elementType);
michael@0 598 break;
michael@0 599
michael@0 600 case nsIDataType::VTYPE_ID:
michael@0 601 case nsIDataType::VTYPE_CHAR_STR:
michael@0 602 case nsIDataType::VTYPE_WCHAR_STR:
michael@0 603 conversionType = nsXPTType((uint8_t)elementType);
michael@0 604 break;
michael@0 605
michael@0 606 case nsIDataType::VTYPE_INTERFACE:
michael@0 607 pid = &NS_GET_IID(nsISupports);
michael@0 608 conversionType = nsXPTType((uint8_t)elementType);
michael@0 609 break;
michael@0 610
michael@0 611 case nsIDataType::VTYPE_INTERFACE_IS:
michael@0 612 pid = &du.u.array.mArrayInterfaceID;
michael@0 613 conversionType = nsXPTType((uint8_t)elementType);
michael@0 614 break;
michael@0 615
michael@0 616 // The rest are illegal.
michael@0 617 case nsIDataType::VTYPE_VOID:
michael@0 618 case nsIDataType::VTYPE_ASTRING:
michael@0 619 case nsIDataType::VTYPE_DOMSTRING:
michael@0 620 case nsIDataType::VTYPE_CSTRING:
michael@0 621 case nsIDataType::VTYPE_UTF8STRING:
michael@0 622 case nsIDataType::VTYPE_WSTRING_SIZE_IS:
michael@0 623 case nsIDataType::VTYPE_STRING_SIZE_IS:
michael@0 624 case nsIDataType::VTYPE_ARRAY:
michael@0 625 case nsIDataType::VTYPE_EMPTY_ARRAY:
michael@0 626 case nsIDataType::VTYPE_EMPTY:
michael@0 627 default:
michael@0 628 NS_ERROR("bad type in array!");
michael@0 629 goto VARIANT_DONE;
michael@0 630 }
michael@0 631
michael@0 632 success =
michael@0 633 XPCConvert::NativeArray2JS(pJSVal,
michael@0 634 (const void**)&du.u.array.mArrayValue,
michael@0 635 conversionType, pid,
michael@0 636 du.u.array.mArrayCount, pErr);
michael@0 637
michael@0 638 VARIANT_DONE:
michael@0 639 nsVariant::Cleanup(&du);
michael@0 640 return success;
michael@0 641 }
michael@0 642 case nsIDataType::VTYPE_EMPTY_ARRAY:
michael@0 643 {
michael@0 644 JSObject* array = JS_NewArrayObject(cx, 0);
michael@0 645 if (!array)
michael@0 646 return false;
michael@0 647 pJSVal.setObject(*array);
michael@0 648 return true;
michael@0 649 }
michael@0 650 case nsIDataType::VTYPE_VOID:
michael@0 651 pJSVal.setUndefined();
michael@0 652 return true;
michael@0 653 case nsIDataType::VTYPE_EMPTY:
michael@0 654 pJSVal.setNull();
michael@0 655 return true;
michael@0 656 default:
michael@0 657 NS_ERROR("bad type in variant!");
michael@0 658 return false;
michael@0 659 }
michael@0 660 }
michael@0 661
michael@0 662 /***************************************************************************/
michael@0 663 /***************************************************************************/
michael@0 664 // XXX These default implementations need to be improved to allow for
michael@0 665 // some more interesting conversions.
michael@0 666
michael@0 667
michael@0 668 /* readonly attribute uint16_t dataType; */
michael@0 669 NS_IMETHODIMP XPCVariant::GetDataType(uint16_t *aDataType)
michael@0 670 {
michael@0 671 *aDataType = mData.mType;
michael@0 672 return NS_OK;
michael@0 673 }
michael@0 674
michael@0 675 /* uint8_t getAsInt8 (); */
michael@0 676 NS_IMETHODIMP XPCVariant::GetAsInt8(uint8_t *_retval)
michael@0 677 {
michael@0 678 return nsVariant::ConvertToInt8(mData, _retval);
michael@0 679 }
michael@0 680
michael@0 681 /* int16_t getAsInt16 (); */
michael@0 682 NS_IMETHODIMP XPCVariant::GetAsInt16(int16_t *_retval)
michael@0 683 {
michael@0 684 return nsVariant::ConvertToInt16(mData, _retval);
michael@0 685 }
michael@0 686
michael@0 687 /* int32_t getAsInt32 (); */
michael@0 688 NS_IMETHODIMP XPCVariant::GetAsInt32(int32_t *_retval)
michael@0 689 {
michael@0 690 return nsVariant::ConvertToInt32(mData, _retval);
michael@0 691 }
michael@0 692
michael@0 693 /* int64_t getAsInt64 (); */
michael@0 694 NS_IMETHODIMP XPCVariant::GetAsInt64(int64_t *_retval)
michael@0 695 {
michael@0 696 return nsVariant::ConvertToInt64(mData, _retval);
michael@0 697 }
michael@0 698
michael@0 699 /* uint8_t getAsUint8 (); */
michael@0 700 NS_IMETHODIMP XPCVariant::GetAsUint8(uint8_t *_retval)
michael@0 701 {
michael@0 702 return nsVariant::ConvertToUint8(mData, _retval);
michael@0 703 }
michael@0 704
michael@0 705 /* uint16_t getAsUint16 (); */
michael@0 706 NS_IMETHODIMP XPCVariant::GetAsUint16(uint16_t *_retval)
michael@0 707 {
michael@0 708 return nsVariant::ConvertToUint16(mData, _retval);
michael@0 709 }
michael@0 710
michael@0 711 /* uint32_t getAsUint32 (); */
michael@0 712 NS_IMETHODIMP XPCVariant::GetAsUint32(uint32_t *_retval)
michael@0 713 {
michael@0 714 return nsVariant::ConvertToUint32(mData, _retval);
michael@0 715 }
michael@0 716
michael@0 717 /* uint64_t getAsUint64 (); */
michael@0 718 NS_IMETHODIMP XPCVariant::GetAsUint64(uint64_t *_retval)
michael@0 719 {
michael@0 720 return nsVariant::ConvertToUint64(mData, _retval);
michael@0 721 }
michael@0 722
michael@0 723 /* float getAsFloat (); */
michael@0 724 NS_IMETHODIMP XPCVariant::GetAsFloat(float *_retval)
michael@0 725 {
michael@0 726 return nsVariant::ConvertToFloat(mData, _retval);
michael@0 727 }
michael@0 728
michael@0 729 /* double getAsDouble (); */
michael@0 730 NS_IMETHODIMP XPCVariant::GetAsDouble(double *_retval)
michael@0 731 {
michael@0 732 return nsVariant::ConvertToDouble(mData, _retval);
michael@0 733 }
michael@0 734
michael@0 735 /* bool getAsBool (); */
michael@0 736 NS_IMETHODIMP XPCVariant::GetAsBool(bool *_retval)
michael@0 737 {
michael@0 738 return nsVariant::ConvertToBool(mData, _retval);
michael@0 739 }
michael@0 740
michael@0 741 /* char getAsChar (); */
michael@0 742 NS_IMETHODIMP XPCVariant::GetAsChar(char *_retval)
michael@0 743 {
michael@0 744 return nsVariant::ConvertToChar(mData, _retval);
michael@0 745 }
michael@0 746
michael@0 747 /* wchar getAsWChar (); */
michael@0 748 NS_IMETHODIMP XPCVariant::GetAsWChar(char16_t *_retval)
michael@0 749 {
michael@0 750 return nsVariant::ConvertToWChar(mData, _retval);
michael@0 751 }
michael@0 752
michael@0 753 /* [notxpcom] nsresult getAsID (out nsID retval); */
michael@0 754 NS_IMETHODIMP_(nsresult) XPCVariant::GetAsID(nsID *retval)
michael@0 755 {
michael@0 756 return nsVariant::ConvertToID(mData, retval);
michael@0 757 }
michael@0 758
michael@0 759 /* AString getAsAString (); */
michael@0 760 NS_IMETHODIMP XPCVariant::GetAsAString(nsAString & _retval)
michael@0 761 {
michael@0 762 return nsVariant::ConvertToAString(mData, _retval);
michael@0 763 }
michael@0 764
michael@0 765 /* DOMString getAsDOMString (); */
michael@0 766 NS_IMETHODIMP XPCVariant::GetAsDOMString(nsAString & _retval)
michael@0 767 {
michael@0 768 // A DOMString maps to an AString internally, so we can re-use
michael@0 769 // ConvertToAString here.
michael@0 770 return nsVariant::ConvertToAString(mData, _retval);
michael@0 771 }
michael@0 772
michael@0 773 /* ACString getAsACString (); */
michael@0 774 NS_IMETHODIMP XPCVariant::GetAsACString(nsACString & _retval)
michael@0 775 {
michael@0 776 return nsVariant::ConvertToACString(mData, _retval);
michael@0 777 }
michael@0 778
michael@0 779 /* AUTF8String getAsAUTF8String (); */
michael@0 780 NS_IMETHODIMP XPCVariant::GetAsAUTF8String(nsAUTF8String & _retval)
michael@0 781 {
michael@0 782 return nsVariant::ConvertToAUTF8String(mData, _retval);
michael@0 783 }
michael@0 784
michael@0 785 /* string getAsString (); */
michael@0 786 NS_IMETHODIMP XPCVariant::GetAsString(char **_retval)
michael@0 787 {
michael@0 788 return nsVariant::ConvertToString(mData, _retval);
michael@0 789 }
michael@0 790
michael@0 791 /* wstring getAsWString (); */
michael@0 792 NS_IMETHODIMP XPCVariant::GetAsWString(char16_t **_retval)
michael@0 793 {
michael@0 794 return nsVariant::ConvertToWString(mData, _retval);
michael@0 795 }
michael@0 796
michael@0 797 /* nsISupports getAsISupports (); */
michael@0 798 NS_IMETHODIMP XPCVariant::GetAsISupports(nsISupports **_retval)
michael@0 799 {
michael@0 800 return nsVariant::ConvertToISupports(mData, _retval);
michael@0 801 }
michael@0 802
michael@0 803 /* void getAsInterface (out nsIIDPtr iid, [iid_is (iid), retval] out nsQIResult iface); */
michael@0 804 NS_IMETHODIMP XPCVariant::GetAsInterface(nsIID * *iid, void * *iface)
michael@0 805 {
michael@0 806 return nsVariant::ConvertToInterface(mData, iid, iface);
michael@0 807 }
michael@0 808
michael@0 809
michael@0 810 /* [notxpcom] nsresult getAsArray (out uint16_t type, out nsIID iid, out uint32_t count, out voidPtr ptr); */
michael@0 811 NS_IMETHODIMP_(nsresult) XPCVariant::GetAsArray(uint16_t *type, nsIID *iid, uint32_t *count, void * *ptr)
michael@0 812 {
michael@0 813 return nsVariant::ConvertToArray(mData, type, iid, count, ptr);
michael@0 814 }
michael@0 815
michael@0 816 /* void getAsStringWithSize (out uint32_t size, [size_is (size), retval] out string str); */
michael@0 817 NS_IMETHODIMP XPCVariant::GetAsStringWithSize(uint32_t *size, char **str)
michael@0 818 {
michael@0 819 return nsVariant::ConvertToStringWithSize(mData, size, str);
michael@0 820 }
michael@0 821
michael@0 822 /* void getAsWStringWithSize (out uint32_t size, [size_is (size), retval] out wstring str); */
michael@0 823 NS_IMETHODIMP XPCVariant::GetAsWStringWithSize(uint32_t *size, char16_t **str)
michael@0 824 {
michael@0 825 return nsVariant::ConvertToWStringWithSize(mData, size, str);
michael@0 826 }
michael@0 827
michael@0 828

mercurial