diff options
Diffstat (limited to '')
-rw-r--r-- | js/xpconnect/src/XPCVariant.cpp | 780 |
1 files changed, 780 insertions, 0 deletions
diff --git a/js/xpconnect/src/XPCVariant.cpp b/js/xpconnect/src/XPCVariant.cpp new file mode 100644 index 0000000000..e47ef527de --- /dev/null +++ b/js/xpconnect/src/XPCVariant.cpp @@ -0,0 +1,780 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* nsIVariant implementation for xpconnect. */ + +#include "mozilla/Range.h" + +#include "xpcprivate.h" + +#include "jsfriendapi.h" +#include "js/Array.h" // JS::GetArrayLength, JS::IsArrayObject, JS::NewArrayObject +#include "js/friend/StackLimits.h" // js::CheckRecursionLimit +#include "js/friend/WindowProxy.h" // js::ToWindowIfWindowProxy +#include "js/Wrapper.h" + +using namespace JS; +using namespace mozilla; + +NS_IMPL_CLASSINFO(XPCVariant, nullptr, 0, XPCVARIANT_CID) +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(XPCVariant) + NS_INTERFACE_MAP_ENTRY(XPCVariant) + NS_INTERFACE_MAP_ENTRY(nsIVariant) + NS_INTERFACE_MAP_ENTRY(nsISupports) + NS_IMPL_QUERY_CLASSINFO(XPCVariant) +NS_INTERFACE_MAP_END +NS_IMPL_CI_INTERFACE_GETTER(XPCVariant, XPCVariant, nsIVariant) + +NS_IMPL_CYCLE_COLLECTING_ADDREF(XPCVariant) +NS_IMPL_CYCLE_COLLECTING_RELEASE(XPCVariant) + +XPCVariant::XPCVariant(JSContext* cx, const Value& aJSVal) : mJSVal(aJSVal) { + if (!mJSVal.isPrimitive()) { + // XXXbholley - The innerization here was from bug 638026. Blake says + // the basic problem was that we were storing the C++ inner but the JS + // outer, which meant that, after navigation, the JS inner could be + // collected, which would cause us to try to recreate the JS inner at + // some later point after teardown, which would crash. This is shouldn't + // be a problem anymore because SetParentToWindow will do the right + // thing, but I'm saving the cleanup here for another day. Blake thinks + // that we should just not store the WN if we're creating a variant for + // an outer window. + JSObject* obj = js::ToWindowIfWindowProxy(&mJSVal.toObject()); + mJSVal = JS::ObjectValue(*obj); + + JSObject* unwrapped = + js::CheckedUnwrapDynamic(obj, cx, /* stopAtWindowProxy = */ false); + mReturnRawObject = !(unwrapped && IS_WN_REFLECTOR(unwrapped)); + } else { + mReturnRawObject = false; + } +} + +XPCTraceableVariant::~XPCTraceableVariant() { + Value val = GetJSValPreserveColor(); + + MOZ_ASSERT(val.isGCThing() || val.isNull(), "Must be traceable or unlinked"); + bool unroot = val.isGCThing(); + + mData.Cleanup(); + + if (unroot) { + RemoveFromRootSet(); + } +} + +void XPCTraceableVariant::TraceJS(JSTracer* trc) { + MOZ_ASSERT(GetJSValPreserveColor().isGCThing()); + JS::TraceEdge(trc, &mJSVal, "XPCTraceableVariant::mJSVal"); +} + +NS_IMPL_CYCLE_COLLECTION_CLASS(XPCVariant) + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(XPCVariant) + JS::Value val = tmp->GetJSValPreserveColor(); + if (val.isObject()) { + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mJSVal"); + cb.NoteJSChild(JS::GCCellPtr(val)); + } + + tmp->mData.Traverse(cb); +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(XPCVariant) + JS::Value val = tmp->GetJSValPreserveColor(); + bool unroot = val.isGCThing(); + + tmp->mData.Cleanup(); + + if (unroot) { + XPCTraceableVariant* v = static_cast<XPCTraceableVariant*>(tmp); + v->RemoveFromRootSet(); + } + tmp->mJSVal = JS::NullValue(); +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +// static +already_AddRefed<XPCVariant> XPCVariant::newVariant(JSContext* cx, + const Value& aJSVal) { + RefPtr<XPCVariant> variant; + + if (!aJSVal.isGCThing()) { + variant = new XPCVariant(cx, aJSVal); + } else { + variant = new XPCTraceableVariant(cx, aJSVal); + } + + if (!variant->InitializeData(cx)) { + return nullptr; + } + + return variant.forget(); +} + +// Helper class to give us a namespace for the table based code below. +class XPCArrayHomogenizer { + private: + enum Type { + tNull = 0, // null value + tInt, // Integer + tDbl, // Double + tBool, // Boolean + tStr, // String + tID, // ID + tArr, // Array + tISup, // nsISupports (really just a plain JSObject) + tUnk, // Unknown. Used only for initial state. + + tTypeCount, // Just a count for table dimensioning. + + tVar, // nsVariant - last ditch if no other common type found. + tErr // No valid state or type has this value. + }; + + // Table has tUnk as a state (column) but not as a type (row). + static const Type StateTable[tTypeCount][tTypeCount - 1]; + + public: + static bool GetTypeForArray(JSContext* cx, HandleObject array, + uint32_t length, nsXPTType* resultType, + nsID* resultID); +}; + +// Current state is the column down the side. +// Current type is the row along the top. +// New state is in the box at the intersection. + +const XPCArrayHomogenizer::Type + XPCArrayHomogenizer::StateTable[tTypeCount][tTypeCount - 1] = { + /* tNull,tInt ,tDbl ,tBool,tStr ,tID ,tArr ,tISup */ + /* tNull */ {tNull, tVar, tVar, tVar, tStr, tID, tVar, tISup}, + /* tInt */ {tVar, tInt, tDbl, tVar, tVar, tVar, tVar, tVar}, + /* tDbl */ {tVar, tDbl, tDbl, tVar, tVar, tVar, tVar, tVar}, + /* tBool */ {tVar, tVar, tVar, tBool, tVar, tVar, tVar, tVar}, + /* tStr */ {tStr, tVar, tVar, tVar, tStr, tVar, tVar, tVar}, + /* tID */ {tID, tVar, tVar, tVar, tVar, tID, tVar, tVar}, + /* tArr */ {tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr}, + /* tISup */ {tISup, tVar, tVar, tVar, tVar, tVar, tVar, tISup}, + /* tUnk */ {tNull, tInt, tDbl, tBool, tStr, tID, tVar, tISup}}; + +// static +bool XPCArrayHomogenizer::GetTypeForArray(JSContext* cx, HandleObject array, + uint32_t length, + nsXPTType* resultType, + nsID* resultID) { + Type state = tUnk; + Type type; + + RootedValue val(cx); + RootedObject jsobj(cx); + for (uint32_t i = 0; i < length; i++) { + if (!JS_GetElement(cx, array, i, &val)) { + return false; + } + + if (val.isInt32()) { + type = tInt; + } else if (val.isDouble()) { + type = tDbl; + } else if (val.isBoolean()) { + type = tBool; + } else if (val.isUndefined() || val.isSymbol() || val.isBigInt()) { + state = tVar; + break; + } else if (val.isNull()) { + type = tNull; + } else if (val.isString()) { + type = tStr; + } else { + MOZ_RELEASE_ASSERT(val.isObject(), "invalid type of jsval!"); + jsobj = &val.toObject(); + + bool isArray; + if (!JS::IsArrayObject(cx, jsobj, &isArray)) { + return false; + } + + if (isArray) { + type = tArr; + } else if (xpc::JSValue2ID(cx, val)) { + type = tID; + } else { + type = tISup; + } + } + + MOZ_ASSERT(state != tErr, "bad state table!"); + MOZ_ASSERT(type != tErr, "bad type!"); + MOZ_ASSERT(type != tVar, "bad type!"); + MOZ_ASSERT(type != tUnk, "bad type!"); + + state = StateTable[state][type]; + + MOZ_ASSERT(state != tErr, "bad state table!"); + MOZ_ASSERT(state != tUnk, "bad state table!"); + + if (state == tVar) { + break; + } + } + + switch (state) { + case tInt: + *resultType = nsXPTType::MkArrayType(nsXPTType::Idx::INT32); + break; + case tDbl: + *resultType = nsXPTType::MkArrayType(nsXPTType::Idx::DOUBLE); + break; + case tBool: + *resultType = nsXPTType::MkArrayType(nsXPTType::Idx::BOOL); + break; + case tStr: + *resultType = nsXPTType::MkArrayType(nsXPTType::Idx::PWSTRING); + break; + case tID: + *resultType = nsXPTType::MkArrayType(nsXPTType::Idx::NSIDPTR); + break; + case tISup: + *resultType = nsXPTType::MkArrayType(nsXPTType::Idx::INTERFACE_IS_TYPE); + *resultID = NS_GET_IID(nsISupports); + break; + case tNull: + // FALL THROUGH + case tVar: + *resultType = nsXPTType::MkArrayType(nsXPTType::Idx::INTERFACE_IS_TYPE); + *resultID = NS_GET_IID(nsIVariant); + break; + case tArr: + // FALL THROUGH + case tUnk: + // FALL THROUGH + case tErr: + // FALL THROUGH + default: + NS_ERROR("bad state"); + return false; + } + return true; +} + +bool XPCVariant::InitializeData(JSContext* cx) { + if (!js::CheckRecursionLimit(cx)) { + return false; + } + + RootedValue val(cx, GetJSVal()); + + if (val.isInt32()) { + mData.SetFromInt32(val.toInt32()); + return true; + } + if (val.isDouble()) { + mData.SetFromDouble(val.toDouble()); + return true; + } + if (val.isBoolean()) { + mData.SetFromBool(val.toBoolean()); + return true; + } + // We can't represent symbol or BigInt on C++ side, so pretend it is void. + if (val.isUndefined() || val.isSymbol() || val.isBigInt()) { + mData.SetToVoid(); + return true; + } + if (val.isNull()) { + mData.SetToEmpty(); + return true; + } + if (val.isString()) { + RootedString str(cx, val.toString()); + if (!str) { + return false; + } + + MOZ_ASSERT(mData.GetType() == nsIDataType::VTYPE_EMPTY, + "Why do we already have data?"); + + size_t length = JS_GetStringLength(str); + mData.AllocateWStringWithSize(length); + + mozilla::Range<char16_t> destChars(mData.u.wstr.mWStringValue, length); + if (!JS_CopyStringChars(cx, destChars, str)) { + return false; + } + + MOZ_ASSERT(mData.u.wstr.mWStringValue[length] == '\0'); + return true; + } + if (Maybe<nsID> id = xpc::JSValue2ID(cx, val)) { + mData.SetFromID(id.ref()); + return true; + } + + // leaving only JSObject... + MOZ_RELEASE_ASSERT(val.isObject(), "invalid type of jsval!"); + + RootedObject jsobj(cx, &val.toObject()); + + // Let's see if it is a js array object. + + uint32_t len; + + bool isArray; + if (!JS::IsArrayObject(cx, jsobj, &isArray) || + (isArray && !JS::GetArrayLength(cx, jsobj, &len))) { + return false; + } + + if (isArray) { + if (!len) { + // Zero length array + mData.SetToEmptyArray(); + return true; + } + + nsXPTType type; + nsID id; + + if (!XPCArrayHomogenizer::GetTypeForArray(cx, jsobj, len, &type, &id)) { + return false; + } + + if (!XPCConvert::JSData2Native(cx, &mData.u.array.mArrayValue, val, type, + &id, len, nullptr)) + return false; + + const nsXPTType& elty = type.ArrayElementType(); + mData.mType = nsIDataType::VTYPE_ARRAY; + if (elty.IsInterfacePointer()) { + mData.u.array.mArrayInterfaceID = id; + } + mData.u.array.mArrayCount = len; + mData.u.array.mArrayType = elty.Tag(); + + return true; + } + + // XXX This could be smarter and pick some more interesting iface. + + nsIXPConnect* xpc = nsIXPConnect::XPConnect(); + nsCOMPtr<nsISupports> wrapper; + const nsIID& iid = NS_GET_IID(nsISupports); + + if (NS_FAILED(xpc->WrapJS(cx, jsobj, iid, getter_AddRefs(wrapper)))) { + return false; + } + + mData.SetFromInterface(iid, wrapper); + return true; +} + +NS_IMETHODIMP +XPCVariant::GetAsJSVal(MutableHandleValue result) { + result.set(GetJSVal()); + return NS_OK; +} + +// static +bool XPCVariant::VariantDataToJS(JSContext* cx, nsIVariant* variant, + nsresult* pErr, MutableHandleValue pJSVal) { + // Get the type early because we might need to spoof it below. + uint16_t type = variant->GetDataType(); + + RootedValue realVal(cx); + nsresult rv = variant->GetAsJSVal(&realVal); + + if (NS_SUCCEEDED(rv) && + (realVal.isPrimitive() || type == nsIDataType::VTYPE_ARRAY || + type == nsIDataType::VTYPE_EMPTY_ARRAY || + type == nsIDataType::VTYPE_ID)) { + if (!JS_WrapValue(cx, &realVal)) { + return false; + } + pJSVal.set(realVal); + return true; + } + + nsCOMPtr<XPCVariant> xpcvariant = do_QueryInterface(variant); + if (xpcvariant && xpcvariant->mReturnRawObject) { + MOZ_ASSERT(type == nsIDataType::VTYPE_INTERFACE || + type == nsIDataType::VTYPE_INTERFACE_IS, + "Weird variant"); + + if (!JS_WrapValue(cx, &realVal)) { + return false; + } + pJSVal.set(realVal); + return true; + } + + // else, it's an object and we really need to double wrap it if we've + // already decided that its 'natural' type is as some sort of interface. + + // We just fall through to the code below and let it do what it does. + + // The nsIVariant is not a XPCVariant (or we act like it isn't). + // So we extract the data and do the Right Thing. + + // We ASSUME that the variant implementation can do these conversions... + + nsID iid; + + switch (type) { + case nsIDataType::VTYPE_INT8: + case nsIDataType::VTYPE_INT16: + case nsIDataType::VTYPE_INT32: + case nsIDataType::VTYPE_INT64: + case nsIDataType::VTYPE_UINT8: + case nsIDataType::VTYPE_UINT16: + case nsIDataType::VTYPE_UINT32: + case nsIDataType::VTYPE_UINT64: + case nsIDataType::VTYPE_FLOAT: + case nsIDataType::VTYPE_DOUBLE: { + double d; + if (NS_FAILED(variant->GetAsDouble(&d))) { + return false; + } + pJSVal.setNumber(d); + return true; + } + case nsIDataType::VTYPE_BOOL: { + bool b; + if (NS_FAILED(variant->GetAsBool(&b))) { + return false; + } + pJSVal.setBoolean(b); + return true; + } + case nsIDataType::VTYPE_CHAR: { + char c; + if (NS_FAILED(variant->GetAsChar(&c))) { + return false; + } + return XPCConvert::NativeData2JS(cx, pJSVal, (const void*)&c, {TD_CHAR}, + &iid, 0, pErr); + } + case nsIDataType::VTYPE_WCHAR: { + char16_t wc; + if (NS_FAILED(variant->GetAsWChar(&wc))) { + return false; + } + return XPCConvert::NativeData2JS(cx, pJSVal, (const void*)&wc, {TD_WCHAR}, + &iid, 0, pErr); + } + case nsIDataType::VTYPE_ID: { + if (NS_FAILED(variant->GetAsID(&iid))) { + return false; + } + nsID* v = &iid; + return XPCConvert::NativeData2JS(cx, pJSVal, (const void*)&v, + {TD_NSIDPTR}, &iid, 0, pErr); + } + case nsIDataType::VTYPE_ASTRING: { + nsAutoString astring; + if (NS_FAILED(variant->GetAsAString(astring))) { + return false; + } + return XPCConvert::NativeData2JS(cx, pJSVal, &astring, {TD_ASTRING}, &iid, + 0, pErr); + } + case nsIDataType::VTYPE_CSTRING: { + nsAutoCString cString; + if (NS_FAILED(variant->GetAsACString(cString))) { + return false; + } + return XPCConvert::NativeData2JS(cx, pJSVal, &cString, {TD_CSTRING}, &iid, + 0, pErr); + } + case nsIDataType::VTYPE_UTF8STRING: { + nsUTF8String utf8String; + if (NS_FAILED(variant->GetAsAUTF8String(utf8String))) { + return false; + } + return XPCConvert::NativeData2JS(cx, pJSVal, &utf8String, {TD_UTF8STRING}, + &iid, 0, pErr); + } + case nsIDataType::VTYPE_CHAR_STR: { + char* pc; + if (NS_FAILED(variant->GetAsString(&pc))) { + return false; + } + bool success = XPCConvert::NativeData2JS(cx, pJSVal, (const void*)&pc, + {TD_PSTRING}, &iid, 0, pErr); + free(pc); + return success; + } + case nsIDataType::VTYPE_STRING_SIZE_IS: { + char* pc; + uint32_t size; + if (NS_FAILED(variant->GetAsStringWithSize(&size, &pc))) { + return false; + } + bool success = XPCConvert::NativeData2JS( + cx, pJSVal, (const void*)&pc, {TD_PSTRING_SIZE_IS}, &iid, size, pErr); + free(pc); + return success; + } + case nsIDataType::VTYPE_WCHAR_STR: { + char16_t* pwc; + if (NS_FAILED(variant->GetAsWString(&pwc))) { + return false; + } + bool success = XPCConvert::NativeData2JS(cx, pJSVal, (const void*)&pwc, + {TD_PSTRING}, &iid, 0, pErr); + free(pwc); + return success; + } + case nsIDataType::VTYPE_WSTRING_SIZE_IS: { + char16_t* pwc; + uint32_t size; + if (NS_FAILED(variant->GetAsWStringWithSize(&size, &pwc))) { + return false; + } + bool success = + XPCConvert::NativeData2JS(cx, pJSVal, (const void*)&pwc, + {TD_PWSTRING_SIZE_IS}, &iid, size, pErr); + free(pwc); + return success; + } + case nsIDataType::VTYPE_INTERFACE: + case nsIDataType::VTYPE_INTERFACE_IS: { + nsISupports* pi; + nsID* piid; + if (NS_FAILED(variant->GetAsInterface(&piid, (void**)&pi))) { + return false; + } + + iid = *piid; + free((char*)piid); + + bool success = XPCConvert::NativeData2JS( + cx, pJSVal, (const void*)&pi, {TD_INTERFACE_IS_TYPE}, &iid, 0, pErr); + if (pi) { + pi->Release(); + } + return success; + } + case nsIDataType::VTYPE_ARRAY: { + nsDiscriminatedUnion du; + nsresult rv; + + rv = variant->GetAsArray( + &du.u.array.mArrayType, &du.u.array.mArrayInterfaceID, + &du.u.array.mArrayCount, &du.u.array.mArrayValue); + if (NS_FAILED(rv)) { + return false; + } + + // must exit via VARIANT_DONE from here on... + du.mType = nsIDataType::VTYPE_ARRAY; + + uint16_t elementType = du.u.array.mArrayType; + const nsID* pid = nullptr; + + nsXPTType::Idx xptIndex; + switch (elementType) { + case nsIDataType::VTYPE_INT8: + xptIndex = nsXPTType::Idx::INT8; + break; + case nsIDataType::VTYPE_INT16: + xptIndex = nsXPTType::Idx::INT16; + break; + case nsIDataType::VTYPE_INT32: + xptIndex = nsXPTType::Idx::INT32; + break; + case nsIDataType::VTYPE_INT64: + xptIndex = nsXPTType::Idx::INT64; + break; + case nsIDataType::VTYPE_UINT8: + xptIndex = nsXPTType::Idx::UINT8; + break; + case nsIDataType::VTYPE_UINT16: + xptIndex = nsXPTType::Idx::UINT16; + break; + case nsIDataType::VTYPE_UINT32: + xptIndex = nsXPTType::Idx::UINT32; + break; + case nsIDataType::VTYPE_UINT64: + xptIndex = nsXPTType::Idx::UINT64; + break; + case nsIDataType::VTYPE_FLOAT: + xptIndex = nsXPTType::Idx::FLOAT; + break; + case nsIDataType::VTYPE_DOUBLE: + xptIndex = nsXPTType::Idx::DOUBLE; + break; + case nsIDataType::VTYPE_BOOL: + xptIndex = nsXPTType::Idx::BOOL; + break; + case nsIDataType::VTYPE_CHAR: + xptIndex = nsXPTType::Idx::CHAR; + break; + case nsIDataType::VTYPE_WCHAR: + xptIndex = nsXPTType::Idx::WCHAR; + break; + case nsIDataType::VTYPE_ID: + xptIndex = nsXPTType::Idx::NSIDPTR; + break; + case nsIDataType::VTYPE_CHAR_STR: + xptIndex = nsXPTType::Idx::PSTRING; + break; + case nsIDataType::VTYPE_WCHAR_STR: + xptIndex = nsXPTType::Idx::PWSTRING; + break; + case nsIDataType::VTYPE_INTERFACE: + pid = &NS_GET_IID(nsISupports); + xptIndex = nsXPTType::Idx::INTERFACE_IS_TYPE; + break; + case nsIDataType::VTYPE_INTERFACE_IS: + pid = &du.u.array.mArrayInterfaceID; + xptIndex = nsXPTType::Idx::INTERFACE_IS_TYPE; + break; + + // The rest are illegal. + case nsIDataType::VTYPE_VOID: + case nsIDataType::VTYPE_ASTRING: + case nsIDataType::VTYPE_CSTRING: + case nsIDataType::VTYPE_UTF8STRING: + case nsIDataType::VTYPE_WSTRING_SIZE_IS: + case nsIDataType::VTYPE_STRING_SIZE_IS: + case nsIDataType::VTYPE_ARRAY: + case nsIDataType::VTYPE_EMPTY_ARRAY: + case nsIDataType::VTYPE_EMPTY: + default: + NS_ERROR("bad type in array!"); + return false; + } + + bool success = XPCConvert::NativeData2JS( + cx, pJSVal, (const void*)&du.u.array.mArrayValue, + nsXPTType::MkArrayType(xptIndex), pid, du.u.array.mArrayCount, pErr); + + return success; + } + case nsIDataType::VTYPE_EMPTY_ARRAY: { + JSObject* array = JS::NewArrayObject(cx, 0); + if (!array) { + return false; + } + pJSVal.setObject(*array); + return true; + } + case nsIDataType::VTYPE_VOID: + pJSVal.setUndefined(); + return true; + case nsIDataType::VTYPE_EMPTY: + pJSVal.setNull(); + return true; + default: + NS_ERROR("bad type in variant!"); + return false; + } +} + +/***************************************************************************/ +/***************************************************************************/ +// XXX These default implementations need to be improved to allow for +// some more interesting conversions. + +uint16_t XPCVariant::GetDataType() { return mData.GetType(); } + +NS_IMETHODIMP XPCVariant::GetAsInt8(uint8_t* _retval) { + return mData.ConvertToInt8(_retval); +} + +NS_IMETHODIMP XPCVariant::GetAsInt16(int16_t* _retval) { + return mData.ConvertToInt16(_retval); +} + +NS_IMETHODIMP XPCVariant::GetAsInt32(int32_t* _retval) { + return mData.ConvertToInt32(_retval); +} + +NS_IMETHODIMP XPCVariant::GetAsInt64(int64_t* _retval) { + return mData.ConvertToInt64(_retval); +} + +NS_IMETHODIMP XPCVariant::GetAsUint8(uint8_t* _retval) { + return mData.ConvertToUint8(_retval); +} + +NS_IMETHODIMP XPCVariant::GetAsUint16(uint16_t* _retval) { + return mData.ConvertToUint16(_retval); +} + +NS_IMETHODIMP XPCVariant::GetAsUint32(uint32_t* _retval) { + return mData.ConvertToUint32(_retval); +} + +NS_IMETHODIMP XPCVariant::GetAsUint64(uint64_t* _retval) { + return mData.ConvertToUint64(_retval); +} + +NS_IMETHODIMP XPCVariant::GetAsFloat(float* _retval) { + return mData.ConvertToFloat(_retval); +} + +NS_IMETHODIMP XPCVariant::GetAsDouble(double* _retval) { + return mData.ConvertToDouble(_retval); +} + +NS_IMETHODIMP XPCVariant::GetAsBool(bool* _retval) { + return mData.ConvertToBool(_retval); +} + +NS_IMETHODIMP XPCVariant::GetAsChar(char* _retval) { + return mData.ConvertToChar(_retval); +} + +NS_IMETHODIMP XPCVariant::GetAsWChar(char16_t* _retval) { + return mData.ConvertToWChar(_retval); +} + +NS_IMETHODIMP_(nsresult) XPCVariant::GetAsID(nsID* retval) { + return mData.ConvertToID(retval); +} + +NS_IMETHODIMP XPCVariant::GetAsAString(nsAString& _retval) { + return mData.ConvertToAString(_retval); +} + +NS_IMETHODIMP XPCVariant::GetAsACString(nsACString& _retval) { + return mData.ConvertToACString(_retval); +} + +NS_IMETHODIMP XPCVariant::GetAsAUTF8String(nsAUTF8String& _retval) { + return mData.ConvertToAUTF8String(_retval); +} + +NS_IMETHODIMP XPCVariant::GetAsString(char** _retval) { + return mData.ConvertToString(_retval); +} + +NS_IMETHODIMP XPCVariant::GetAsWString(char16_t** _retval) { + return mData.ConvertToWString(_retval); +} + +NS_IMETHODIMP XPCVariant::GetAsISupports(nsISupports** _retval) { + return mData.ConvertToISupports(_retval); +} + +NS_IMETHODIMP XPCVariant::GetAsInterface(nsIID** iid, void** iface) { + return mData.ConvertToInterface(iid, iface); +} + +NS_IMETHODIMP_(nsresult) +XPCVariant::GetAsArray(uint16_t* type, nsIID* iid, uint32_t* count, + void** ptr) { + return mData.ConvertToArray(type, iid, count, ptr); +} + +NS_IMETHODIMP XPCVariant::GetAsStringWithSize(uint32_t* size, char** str) { + return mData.ConvertToStringWithSize(size, str); +} + +NS_IMETHODIMP XPCVariant::GetAsWStringWithSize(uint32_t* size, char16_t** str) { + return mData.ConvertToWStringWithSize(size, str); +} |