js/xpconnect/src/XPCVariant.cpp

changeset 0
6474c204b198
     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 +

mercurial