tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

XPCVariant.cpp (23028B)


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