summaryrefslogtreecommitdiffstats
path: root/xpcom/ds/nsVariant.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--xpcom/ds/nsVariant.cpp1881
1 files changed, 1881 insertions, 0 deletions
diff --git a/xpcom/ds/nsVariant.cpp b/xpcom/ds/nsVariant.cpp
new file mode 100644
index 0000000000..3ccfc7fa31
--- /dev/null
+++ b/xpcom/ds/nsVariant.cpp
@@ -0,0 +1,1881 @@
+/* -*- 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/. */
+
+#include "nsVariant.h"
+#include "prprf.h"
+#include "prdtoa.h"
+#include <math.h>
+#include "nsCycleCollectionParticipant.h"
+#include "xptinfo.h"
+#include "nsReadableUtils.h"
+#include "nsString.h"
+#include "nsCRTGlue.h"
+#include "mozilla/FloatingPoint.h"
+#include "mozilla/IntegerPrintfMacros.h"
+#include "mozilla/Printf.h"
+
+/***************************************************************************/
+// Helpers for static convert functions...
+
+static nsresult String2Double(const char* aString, double* aResult) {
+ char* next;
+ double value = PR_strtod(aString, &next);
+ if (next == aString) {
+ return NS_ERROR_CANNOT_CONVERT_DATA;
+ }
+ *aResult = value;
+ return NS_OK;
+}
+
+static nsresult AString2Double(const nsAString& aString, double* aResult) {
+ char* pChars = ToNewCString(aString, mozilla::fallible);
+ if (!pChars) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ nsresult rv = String2Double(pChars, aResult);
+ free(pChars);
+ return rv;
+}
+
+static nsresult AUTF8String2Double(const nsAUTF8String& aString,
+ double* aResult) {
+ return String2Double(PromiseFlatUTF8String(aString).get(), aResult);
+}
+
+static nsresult ACString2Double(const nsACString& aString, double* aResult) {
+ return String2Double(PromiseFlatCString(aString).get(), aResult);
+}
+
+// Fills aOutData with double, uint32_t, or int32_t.
+// Returns NS_OK, an error code, or a non-NS_OK success code
+nsresult nsDiscriminatedUnion::ToManageableNumber(
+ nsDiscriminatedUnion* aOutData) const {
+ nsresult rv;
+
+ switch (mType) {
+ // This group results in a int32_t...
+
+#define CASE__NUMBER_INT32(type_, member_) \
+ case nsIDataType::type_: \
+ aOutData->u.mInt32Value = u.member_; \
+ aOutData->mType = nsIDataType::VTYPE_INT32; \
+ return NS_OK;
+
+ CASE__NUMBER_INT32(VTYPE_INT8, mInt8Value)
+ CASE__NUMBER_INT32(VTYPE_INT16, mInt16Value)
+ CASE__NUMBER_INT32(VTYPE_INT32, mInt32Value)
+ CASE__NUMBER_INT32(VTYPE_UINT8, mUint8Value)
+ CASE__NUMBER_INT32(VTYPE_UINT16, mUint16Value)
+ CASE__NUMBER_INT32(VTYPE_BOOL, mBoolValue)
+ CASE__NUMBER_INT32(VTYPE_CHAR, mCharValue)
+ CASE__NUMBER_INT32(VTYPE_WCHAR, mWCharValue)
+
+#undef CASE__NUMBER_INT32
+
+ // This group results in a uint32_t...
+
+ case nsIDataType::VTYPE_UINT32:
+ aOutData->u.mUint32Value = u.mUint32Value;
+ aOutData->mType = nsIDataType::VTYPE_UINT32;
+ return NS_OK;
+
+ // This group results in a double...
+
+ case nsIDataType::VTYPE_INT64:
+ case nsIDataType::VTYPE_UINT64:
+ // XXX Need boundary checking here.
+ // We may need to return NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA
+ aOutData->u.mDoubleValue = double(u.mInt64Value);
+ aOutData->mType = nsIDataType::VTYPE_DOUBLE;
+ return NS_OK;
+ case nsIDataType::VTYPE_FLOAT:
+ aOutData->u.mDoubleValue = u.mFloatValue;
+ aOutData->mType = nsIDataType::VTYPE_DOUBLE;
+ return NS_OK;
+ case nsIDataType::VTYPE_DOUBLE:
+ aOutData->u.mDoubleValue = u.mDoubleValue;
+ aOutData->mType = nsIDataType::VTYPE_DOUBLE;
+ return NS_OK;
+ case nsIDataType::VTYPE_CHAR_STR:
+ case nsIDataType::VTYPE_STRING_SIZE_IS:
+ rv = String2Double(u.str.mStringValue, &aOutData->u.mDoubleValue);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ aOutData->mType = nsIDataType::VTYPE_DOUBLE;
+ return NS_OK;
+ case nsIDataType::VTYPE_ASTRING:
+ rv = AString2Double(*u.mAStringValue, &aOutData->u.mDoubleValue);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ aOutData->mType = nsIDataType::VTYPE_DOUBLE;
+ return NS_OK;
+ case nsIDataType::VTYPE_UTF8STRING:
+ rv = AUTF8String2Double(*u.mUTF8StringValue, &aOutData->u.mDoubleValue);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ aOutData->mType = nsIDataType::VTYPE_DOUBLE;
+ return NS_OK;
+ case nsIDataType::VTYPE_CSTRING:
+ rv = ACString2Double(*u.mCStringValue, &aOutData->u.mDoubleValue);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ aOutData->mType = nsIDataType::VTYPE_DOUBLE;
+ return NS_OK;
+ case nsIDataType::VTYPE_WCHAR_STR:
+ case nsIDataType::VTYPE_WSTRING_SIZE_IS:
+ rv = AString2Double(nsDependentString(u.wstr.mWStringValue),
+ &aOutData->u.mDoubleValue);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ aOutData->mType = nsIDataType::VTYPE_DOUBLE;
+ return NS_OK;
+
+ // This group fails...
+
+ case nsIDataType::VTYPE_VOID:
+ case nsIDataType::VTYPE_ID:
+ case nsIDataType::VTYPE_INTERFACE:
+ case nsIDataType::VTYPE_INTERFACE_IS:
+ case nsIDataType::VTYPE_ARRAY:
+ case nsIDataType::VTYPE_EMPTY_ARRAY:
+ case nsIDataType::VTYPE_EMPTY:
+ default:
+ return NS_ERROR_CANNOT_CONVERT_DATA;
+ }
+}
+
+/***************************************************************************/
+// Array helpers...
+
+void nsDiscriminatedUnion::FreeArray() {
+ NS_ASSERTION(mType == nsIDataType::VTYPE_ARRAY, "bad FreeArray call");
+ NS_ASSERTION(u.array.mArrayValue, "bad array");
+ NS_ASSERTION(u.array.mArrayCount, "bad array count");
+
+#define CASE__FREE_ARRAY_PTR(type_, ctype_) \
+ case nsIDataType::type_: { \
+ ctype_** p = (ctype_**)u.array.mArrayValue; \
+ for (uint32_t i = u.array.mArrayCount; i > 0; p++, i--) \
+ if (*p) free((char*)*p); \
+ break; \
+ }
+
+#define CASE__FREE_ARRAY_IFACE(type_, ctype_) \
+ case nsIDataType::type_: { \
+ ctype_** p = (ctype_**)u.array.mArrayValue; \
+ for (uint32_t i = u.array.mArrayCount; i > 0; p++, i--) \
+ if (*p) (*p)->Release(); \
+ break; \
+ }
+
+ switch (u.array.mArrayType) {
+ 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:
+ case nsIDataType::VTYPE_BOOL:
+ case nsIDataType::VTYPE_CHAR:
+ case nsIDataType::VTYPE_WCHAR:
+ break;
+
+ // XXX We ASSUME that "array of nsID" means "array of pointers to nsID".
+ CASE__FREE_ARRAY_PTR(VTYPE_ID, nsID)
+ CASE__FREE_ARRAY_PTR(VTYPE_CHAR_STR, char)
+ CASE__FREE_ARRAY_PTR(VTYPE_WCHAR_STR, char16_t)
+ CASE__FREE_ARRAY_IFACE(VTYPE_INTERFACE, nsISupports)
+ CASE__FREE_ARRAY_IFACE(VTYPE_INTERFACE_IS, nsISupports)
+
+ // The rest are illegal.
+ case nsIDataType::VTYPE_VOID:
+ case nsIDataType::VTYPE_ASTRING:
+ case nsIDataType::VTYPE_UTF8STRING:
+ case nsIDataType::VTYPE_CSTRING:
+ 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!");
+ break;
+ }
+
+ // Free the array memory.
+ free((char*)u.array.mArrayValue);
+
+#undef CASE__FREE_ARRAY_PTR
+#undef CASE__FREE_ARRAY_IFACE
+}
+
+static nsresult CloneArray(uint16_t aInType, const nsIID* aInIID,
+ uint32_t aInCount, void* aInValue,
+ uint16_t* aOutType, nsIID* aOutIID,
+ uint32_t* aOutCount, void** aOutValue) {
+ NS_ASSERTION(aInCount, "bad param");
+ NS_ASSERTION(aInValue, "bad param");
+ NS_ASSERTION(aOutType, "bad param");
+ NS_ASSERTION(aOutCount, "bad param");
+ NS_ASSERTION(aOutValue, "bad param");
+
+ uint32_t i;
+
+ // First we figure out the size of the elements for the new u.array.
+
+ size_t elementSize;
+ size_t allocSize;
+
+ switch (aInType) {
+ case nsIDataType::VTYPE_INT8:
+ elementSize = sizeof(int8_t);
+ break;
+ case nsIDataType::VTYPE_INT16:
+ elementSize = sizeof(int16_t);
+ break;
+ case nsIDataType::VTYPE_INT32:
+ elementSize = sizeof(int32_t);
+ break;
+ case nsIDataType::VTYPE_INT64:
+ elementSize = sizeof(int64_t);
+ break;
+ case nsIDataType::VTYPE_UINT8:
+ elementSize = sizeof(uint8_t);
+ break;
+ case nsIDataType::VTYPE_UINT16:
+ elementSize = sizeof(uint16_t);
+ break;
+ case nsIDataType::VTYPE_UINT32:
+ elementSize = sizeof(uint32_t);
+ break;
+ case nsIDataType::VTYPE_UINT64:
+ elementSize = sizeof(uint64_t);
+ break;
+ case nsIDataType::VTYPE_FLOAT:
+ elementSize = sizeof(float);
+ break;
+ case nsIDataType::VTYPE_DOUBLE:
+ elementSize = sizeof(double);
+ break;
+ case nsIDataType::VTYPE_BOOL:
+ elementSize = sizeof(bool);
+ break;
+ case nsIDataType::VTYPE_CHAR:
+ elementSize = sizeof(char);
+ break;
+ case nsIDataType::VTYPE_WCHAR:
+ elementSize = sizeof(char16_t);
+ break;
+
+ // XXX We ASSUME that "array of nsID" means "array of pointers to nsID".
+ case nsIDataType::VTYPE_ID:
+ case nsIDataType::VTYPE_CHAR_STR:
+ case nsIDataType::VTYPE_WCHAR_STR:
+ case nsIDataType::VTYPE_INTERFACE:
+ case nsIDataType::VTYPE_INTERFACE_IS:
+ elementSize = sizeof(void*);
+ break;
+
+ // The rest are illegal.
+ case nsIDataType::VTYPE_ASTRING:
+ case nsIDataType::VTYPE_UTF8STRING:
+ case nsIDataType::VTYPE_CSTRING:
+ case nsIDataType::VTYPE_STRING_SIZE_IS:
+ case nsIDataType::VTYPE_WSTRING_SIZE_IS:
+ case nsIDataType::VTYPE_VOID:
+ case nsIDataType::VTYPE_ARRAY:
+ case nsIDataType::VTYPE_EMPTY_ARRAY:
+ case nsIDataType::VTYPE_EMPTY:
+ default:
+ NS_ERROR("bad type in array!");
+ return NS_ERROR_CANNOT_CONVERT_DATA;
+ }
+
+ // Alloc the u.array.
+
+ allocSize = aInCount * elementSize;
+ *aOutValue = moz_xmalloc(allocSize);
+
+ // Clone the elements.
+
+ switch (aInType) {
+ 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:
+ case nsIDataType::VTYPE_BOOL:
+ case nsIDataType::VTYPE_CHAR:
+ case nsIDataType::VTYPE_WCHAR:
+ memcpy(*aOutValue, aInValue, allocSize);
+ break;
+
+ case nsIDataType::VTYPE_INTERFACE_IS:
+ if (aOutIID) {
+ *aOutIID = *aInIID;
+ }
+ [[fallthrough]];
+
+ case nsIDataType::VTYPE_INTERFACE: {
+ memcpy(*aOutValue, aInValue, allocSize);
+
+ nsISupports** p = (nsISupports**)*aOutValue;
+ for (i = aInCount; i > 0; ++p, --i)
+ if (*p) {
+ (*p)->AddRef();
+ }
+ break;
+ }
+
+ // XXX We ASSUME that "array of nsID" means "array of pointers to nsID".
+ case nsIDataType::VTYPE_ID: {
+ nsID** inp = (nsID**)aInValue;
+ nsID** outp = (nsID**)*aOutValue;
+ for (i = aInCount; i > 0; --i) {
+ nsID* idp = *(inp++);
+ if (idp) {
+ *(outp++) = idp->Clone();
+ } else {
+ *(outp++) = nullptr;
+ }
+ }
+ break;
+ }
+
+ case nsIDataType::VTYPE_CHAR_STR: {
+ char** inp = (char**)aInValue;
+ char** outp = (char**)*aOutValue;
+ for (i = aInCount; i > 0; i--) {
+ char* str = *(inp++);
+ if (str) {
+ *(outp++) = moz_xstrdup(str);
+ } else {
+ *(outp++) = nullptr;
+ }
+ }
+ break;
+ }
+
+ case nsIDataType::VTYPE_WCHAR_STR: {
+ char16_t** inp = (char16_t**)aInValue;
+ char16_t** outp = (char16_t**)*aOutValue;
+ for (i = aInCount; i > 0; i--) {
+ char16_t* str = *(inp++);
+ if (str) {
+ *(outp++) = NS_xstrdup(str);
+ } else {
+ *(outp++) = nullptr;
+ }
+ }
+ break;
+ }
+
+ // The rest are illegal.
+ case nsIDataType::VTYPE_VOID:
+ case nsIDataType::VTYPE_ARRAY:
+ case nsIDataType::VTYPE_EMPTY_ARRAY:
+ case nsIDataType::VTYPE_EMPTY:
+ case nsIDataType::VTYPE_ASTRING:
+ case nsIDataType::VTYPE_UTF8STRING:
+ case nsIDataType::VTYPE_CSTRING:
+ case nsIDataType::VTYPE_STRING_SIZE_IS:
+ case nsIDataType::VTYPE_WSTRING_SIZE_IS:
+ default:
+ NS_ERROR("bad type in array!");
+ return NS_ERROR_CANNOT_CONVERT_DATA;
+ }
+
+ *aOutType = aInType;
+ *aOutCount = aInCount;
+ return NS_OK;
+}
+
+/***************************************************************************/
+
+#define TRIVIAL_DATA_CONVERTER(type_, member_, retval_) \
+ if (mType == nsIDataType::type_) { \
+ *retval_ = u.member_; \
+ return NS_OK; \
+ }
+
+#define NUMERIC_CONVERSION_METHOD_BEGIN(type_, Ctype_, name_) \
+ nsresult nsDiscriminatedUnion::ConvertTo##name_(Ctype_* aResult) const { \
+ TRIVIAL_DATA_CONVERTER(type_, m##name_##Value, aResult) \
+ nsDiscriminatedUnion tempData; \
+ nsresult rv = ToManageableNumber(&tempData); \
+ /* */ \
+ /* NOTE: rv may indicate a success code that we want to preserve */ \
+ /* For the final return. So all the return cases below should return */ \
+ /* this rv when indicating success. */ \
+ /* */ \
+ if (NS_FAILED(rv)) return rv; \
+ switch (tempData.mType) {
+#define CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(Ctype_) \
+ case nsIDataType::VTYPE_INT32: \
+ *aResult = (Ctype_)tempData.u.mInt32Value; \
+ return rv;
+
+#define CASE__NUMERIC_CONVERSION_INT32_MIN_MAX(Ctype_, min_, max_) \
+ case nsIDataType::VTYPE_INT32: { \
+ int32_t value = tempData.u.mInt32Value; \
+ if (value < (min_) || value > (max_)) { \
+ return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; \
+ } \
+ *aResult = (Ctype_)value; \
+ return rv; \
+ }
+
+#define CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(Ctype_) \
+ case nsIDataType::VTYPE_UINT32: \
+ *aResult = (Ctype_)tempData.u.mUint32Value; \
+ return rv;
+
+#define CASE__NUMERIC_CONVERSION_UINT32_MAX(Ctype_, max_) \
+ case nsIDataType::VTYPE_UINT32: { \
+ uint32_t value = tempData.u.mUint32Value; \
+ if (value > (max_)) return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; \
+ *aResult = (Ctype_)value; \
+ return rv; \
+ }
+
+#define CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(Ctype_) \
+ case nsIDataType::VTYPE_DOUBLE: \
+ *aResult = (Ctype_)tempData.u.mDoubleValue; \
+ return rv;
+
+#define CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(Ctype_, min_, max_) \
+ case nsIDataType::VTYPE_DOUBLE: { \
+ double value = tempData.u.mDoubleValue; \
+ if (mozilla::IsNaN(value) || value < (min_) || value > (max_)) { \
+ return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; \
+ } \
+ *aResult = (Ctype_)value; \
+ return (0.0 == fmod(value, 1.0)) ? rv \
+ : NS_SUCCESS_LOSS_OF_INSIGNIFICANT_DATA; \
+ }
+
+#define CASES__NUMERIC_CONVERSION_NORMAL(Ctype_, min_, max_) \
+ CASE__NUMERIC_CONVERSION_INT32_MIN_MAX(Ctype_, min_, max_) \
+ CASE__NUMERIC_CONVERSION_UINT32_MAX(Ctype_, max_) \
+ CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(Ctype_, min_, max_)
+
+#define NUMERIC_CONVERSION_METHOD_END \
+ default: \
+ NS_ERROR("bad type returned from ToManageableNumber"); \
+ return NS_ERROR_CANNOT_CONVERT_DATA; \
+ } \
+ }
+
+#define NUMERIC_CONVERSION_METHOD_NORMAL(type_, Ctype_, name_, min_, max_) \
+ NUMERIC_CONVERSION_METHOD_BEGIN(type_, Ctype_, name_) \
+ CASES__NUMERIC_CONVERSION_NORMAL(Ctype_, min_, max_) \
+ NUMERIC_CONVERSION_METHOD_END
+
+/***************************************************************************/
+// These expand into full public methods...
+
+NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_INT8, uint8_t, Int8, (-127 - 1), 127)
+NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_INT16, int16_t, Int16, (-32767 - 1),
+ 32767)
+
+NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_INT32, int32_t, Int32)
+CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(int32_t)
+CASE__NUMERIC_CONVERSION_UINT32_MAX(int32_t, 2147483647)
+CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(int32_t, (-2147483647 - 1),
+ 2147483647)
+NUMERIC_CONVERSION_METHOD_END
+
+NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_UINT8, uint8_t, Uint8, 0, 255)
+NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_UINT16, uint16_t, Uint16, 0, 65535)
+
+NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_UINT32, uint32_t, Uint32)
+CASE__NUMERIC_CONVERSION_INT32_MIN_MAX(uint32_t, 0, 2147483647)
+CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(uint32_t)
+CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(uint32_t, 0, 4294967295U)
+NUMERIC_CONVERSION_METHOD_END
+
+// XXX toFloat conversions need to be fixed!
+NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_FLOAT, float, Float)
+CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(float)
+CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(float)
+CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(float)
+NUMERIC_CONVERSION_METHOD_END
+
+NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_DOUBLE, double, Double)
+CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(double)
+CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(double)
+CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(double)
+NUMERIC_CONVERSION_METHOD_END
+
+// XXX toChar conversions need to be fixed!
+NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_CHAR, char, Char, CHAR_MIN, CHAR_MAX)
+
+// XXX toWChar conversions need to be fixed!
+NUMERIC_CONVERSION_METHOD_NORMAL(VTYPE_WCHAR, char16_t, WChar, 0,
+ std::numeric_limits<char16_t>::max())
+
+#undef NUMERIC_CONVERSION_METHOD_BEGIN
+#undef CASE__NUMERIC_CONVERSION_INT32_JUST_CAST
+#undef CASE__NUMERIC_CONVERSION_INT32_MIN_MAX
+#undef CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST
+#undef CASE__NUMERIC_CONVERSION_UINT32_MIN_MAX
+#undef CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST
+#undef CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX
+#undef CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT
+#undef CASES__NUMERIC_CONVERSION_NORMAL
+#undef NUMERIC_CONVERSION_METHOD_END
+#undef NUMERIC_CONVERSION_METHOD_NORMAL
+
+/***************************************************************************/
+
+// Just leverage a numeric converter for bool (but restrict the values).
+// XXX Is this really what we want to do?
+
+nsresult nsDiscriminatedUnion::ConvertToBool(bool* aResult) const {
+ TRIVIAL_DATA_CONVERTER(VTYPE_BOOL, mBoolValue, aResult)
+
+ double val;
+ nsresult rv = ConvertToDouble(&val);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ // NaN is falsy in JS, so we might as well make it false here.
+ if (mozilla::IsNaN(val)) {
+ *aResult = false;
+ } else {
+ *aResult = 0.0 != val;
+ }
+ return rv;
+}
+
+/***************************************************************************/
+
+nsresult nsDiscriminatedUnion::ConvertToInt64(int64_t* aResult) const {
+ TRIVIAL_DATA_CONVERTER(VTYPE_INT64, mInt64Value, aResult)
+ TRIVIAL_DATA_CONVERTER(VTYPE_UINT64, mUint64Value, aResult)
+
+ nsDiscriminatedUnion tempData;
+ nsresult rv = ToManageableNumber(&tempData);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ switch (tempData.mType) {
+ case nsIDataType::VTYPE_INT32:
+ *aResult = tempData.u.mInt32Value;
+ return rv;
+ case nsIDataType::VTYPE_UINT32:
+ *aResult = tempData.u.mUint32Value;
+ return rv;
+ case nsIDataType::VTYPE_DOUBLE: {
+ double value = tempData.u.mDoubleValue;
+ if (mozilla::IsNaN(value)) {
+ return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA;
+ }
+ // XXX should check for data loss here!
+ *aResult = value;
+ return rv;
+ }
+ default:
+ NS_ERROR("bad type returned from ToManageableNumber");
+ return NS_ERROR_CANNOT_CONVERT_DATA;
+ }
+}
+
+nsresult nsDiscriminatedUnion::ConvertToUint64(uint64_t* aResult) const {
+ return ConvertToInt64((int64_t*)aResult);
+}
+
+/***************************************************************************/
+
+bool nsDiscriminatedUnion::String2ID(nsID* aPid) const {
+ nsAutoString tempString;
+ nsAString* pString;
+
+ switch (mType) {
+ case nsIDataType::VTYPE_CHAR_STR:
+ case nsIDataType::VTYPE_STRING_SIZE_IS:
+ return aPid->Parse(u.str.mStringValue);
+ case nsIDataType::VTYPE_CSTRING:
+ return aPid->Parse(PromiseFlatCString(*u.mCStringValue).get());
+ case nsIDataType::VTYPE_UTF8STRING:
+ return aPid->Parse(PromiseFlatUTF8String(*u.mUTF8StringValue).get());
+ case nsIDataType::VTYPE_ASTRING:
+ pString = u.mAStringValue;
+ break;
+ case nsIDataType::VTYPE_WCHAR_STR:
+ case nsIDataType::VTYPE_WSTRING_SIZE_IS:
+ tempString.Assign(u.wstr.mWStringValue);
+ pString = &tempString;
+ break;
+ default:
+ NS_ERROR("bad type in call to String2ID");
+ return false;
+ }
+
+ char* pChars = ToNewCString(*pString, mozilla::fallible);
+ if (!pChars) {
+ return false;
+ }
+ bool result = aPid->Parse(pChars);
+ free(pChars);
+ return result;
+}
+
+nsresult nsDiscriminatedUnion::ConvertToID(nsID* aResult) const {
+ nsID id;
+
+ switch (mType) {
+ case nsIDataType::VTYPE_ID:
+ *aResult = u.mIDValue;
+ return NS_OK;
+ case nsIDataType::VTYPE_INTERFACE:
+ *aResult = NS_GET_IID(nsISupports);
+ return NS_OK;
+ case nsIDataType::VTYPE_INTERFACE_IS:
+ *aResult = u.iface.mInterfaceID;
+ return NS_OK;
+ case nsIDataType::VTYPE_ASTRING:
+ case nsIDataType::VTYPE_UTF8STRING:
+ case nsIDataType::VTYPE_CSTRING:
+ case nsIDataType::VTYPE_CHAR_STR:
+ case nsIDataType::VTYPE_WCHAR_STR:
+ case nsIDataType::VTYPE_STRING_SIZE_IS:
+ case nsIDataType::VTYPE_WSTRING_SIZE_IS:
+ if (!String2ID(&id)) {
+ return NS_ERROR_CANNOT_CONVERT_DATA;
+ }
+ *aResult = id;
+ return NS_OK;
+ default:
+ return NS_ERROR_CANNOT_CONVERT_DATA;
+ }
+}
+
+/***************************************************************************/
+
+nsresult nsDiscriminatedUnion::ToString(nsACString& aOutString) const {
+ mozilla::SmprintfPointer pptr;
+
+ switch (mType) {
+ // all the stuff we don't handle...
+ case nsIDataType::VTYPE_ASTRING:
+ case nsIDataType::VTYPE_UTF8STRING:
+ case nsIDataType::VTYPE_CSTRING:
+ case nsIDataType::VTYPE_CHAR_STR:
+ case nsIDataType::VTYPE_WCHAR_STR:
+ case nsIDataType::VTYPE_STRING_SIZE_IS:
+ case nsIDataType::VTYPE_WSTRING_SIZE_IS:
+ case nsIDataType::VTYPE_WCHAR:
+ NS_ERROR("ToString being called for a string type - screwy logic!");
+ [[fallthrough]];
+
+ // XXX We might want stringified versions of these... ???
+
+ case nsIDataType::VTYPE_VOID:
+ case nsIDataType::VTYPE_EMPTY:
+ aOutString.SetIsVoid(true);
+ return NS_OK;
+
+ case nsIDataType::VTYPE_EMPTY_ARRAY:
+ case nsIDataType::VTYPE_ARRAY:
+ case nsIDataType::VTYPE_INTERFACE:
+ case nsIDataType::VTYPE_INTERFACE_IS:
+ default:
+ return NS_ERROR_CANNOT_CONVERT_DATA;
+
+ // nsID has its own text formatter.
+
+ case nsIDataType::VTYPE_ID: {
+ char* ptr = u.mIDValue.ToString();
+ if (!ptr) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ aOutString.Assign(ptr);
+ free(ptr);
+ return NS_OK;
+ }
+
+ // Can't use Smprintf for floats, since it's locale-dependent
+#define CASE__APPENDFLOAT_NUMBER(type_, member_) \
+ case nsIDataType::type_: { \
+ nsAutoCString str; \
+ str.AppendFloat(u.member_); \
+ aOutString.Assign(str); \
+ return NS_OK; \
+ }
+
+ CASE__APPENDFLOAT_NUMBER(VTYPE_FLOAT, mFloatValue)
+ CASE__APPENDFLOAT_NUMBER(VTYPE_DOUBLE, mDoubleValue)
+
+#undef CASE__APPENDFLOAT_NUMBER
+
+ // the rest can be Smprintf'd and use common code.
+
+#define CASE__SMPRINTF_NUMBER(type_, format_, cast_, member_) \
+ case nsIDataType::type_: \
+ static_assert(sizeof(cast_) >= sizeof(u.member_), \
+ "size of type should be at least as big as member"); \
+ pptr = mozilla::Smprintf(format_, (cast_)u.member_); \
+ break;
+
+ CASE__SMPRINTF_NUMBER(VTYPE_INT8, "%d", int, mInt8Value)
+ CASE__SMPRINTF_NUMBER(VTYPE_INT16, "%d", int, mInt16Value)
+ CASE__SMPRINTF_NUMBER(VTYPE_INT32, "%d", int, mInt32Value)
+ CASE__SMPRINTF_NUMBER(VTYPE_INT64, "%" PRId64, int64_t, mInt64Value)
+
+ CASE__SMPRINTF_NUMBER(VTYPE_UINT8, "%u", unsigned, mUint8Value)
+ CASE__SMPRINTF_NUMBER(VTYPE_UINT16, "%u", unsigned, mUint16Value)
+ CASE__SMPRINTF_NUMBER(VTYPE_UINT32, "%u", unsigned, mUint32Value)
+ CASE__SMPRINTF_NUMBER(VTYPE_UINT64, "%" PRIu64, int64_t, mUint64Value)
+
+ // XXX Would we rather print "true" / "false" ?
+ CASE__SMPRINTF_NUMBER(VTYPE_BOOL, "%d", int, mBoolValue)
+
+ CASE__SMPRINTF_NUMBER(VTYPE_CHAR, "%c", char, mCharValue)
+
+#undef CASE__SMPRINTF_NUMBER
+ }
+
+ if (!pptr) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ aOutString.Assign(pptr.get());
+ return NS_OK;
+}
+
+nsresult nsDiscriminatedUnion::ConvertToAString(nsAString& aResult) const {
+ switch (mType) {
+ case nsIDataType::VTYPE_ASTRING:
+ aResult.Assign(*u.mAStringValue);
+ return NS_OK;
+ case nsIDataType::VTYPE_CSTRING:
+ CopyASCIItoUTF16(*u.mCStringValue, aResult);
+ return NS_OK;
+ case nsIDataType::VTYPE_UTF8STRING:
+ CopyUTF8toUTF16(*u.mUTF8StringValue, aResult);
+ return NS_OK;
+ case nsIDataType::VTYPE_CHAR_STR:
+ CopyASCIItoUTF16(mozilla::MakeStringSpan(u.str.mStringValue), aResult);
+ return NS_OK;
+ case nsIDataType::VTYPE_WCHAR_STR:
+ aResult.Assign(u.wstr.mWStringValue);
+ return NS_OK;
+ case nsIDataType::VTYPE_STRING_SIZE_IS:
+ CopyASCIItoUTF16(
+ nsDependentCString(u.str.mStringValue, u.str.mStringLength), aResult);
+ return NS_OK;
+ case nsIDataType::VTYPE_WSTRING_SIZE_IS:
+ aResult.Assign(u.wstr.mWStringValue, u.wstr.mWStringLength);
+ return NS_OK;
+ case nsIDataType::VTYPE_WCHAR:
+ aResult.Assign(u.mWCharValue);
+ return NS_OK;
+ default: {
+ nsAutoCString tempCString;
+ nsresult rv = ToString(tempCString);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ CopyASCIItoUTF16(tempCString, aResult);
+ return NS_OK;
+ }
+ }
+}
+
+nsresult nsDiscriminatedUnion::ConvertToACString(nsACString& aResult) const {
+ switch (mType) {
+ case nsIDataType::VTYPE_ASTRING:
+ LossyCopyUTF16toASCII(*u.mAStringValue, aResult);
+ return NS_OK;
+ case nsIDataType::VTYPE_CSTRING:
+ aResult.Assign(*u.mCStringValue);
+ return NS_OK;
+ case nsIDataType::VTYPE_UTF8STRING:
+ // XXX This is an extra copy that should be avoided
+ // once Jag lands support for UTF8String and associated
+ // conversion methods.
+ LossyCopyUTF16toASCII(NS_ConvertUTF8toUTF16(*u.mUTF8StringValue),
+ aResult);
+ return NS_OK;
+ case nsIDataType::VTYPE_CHAR_STR:
+ aResult.Assign(*u.str.mStringValue);
+ return NS_OK;
+ case nsIDataType::VTYPE_WCHAR_STR:
+ LossyCopyUTF16toASCII(nsDependentString(u.wstr.mWStringValue), aResult);
+ return NS_OK;
+ case nsIDataType::VTYPE_STRING_SIZE_IS:
+ aResult.Assign(u.str.mStringValue, u.str.mStringLength);
+ return NS_OK;
+ case nsIDataType::VTYPE_WSTRING_SIZE_IS:
+ LossyCopyUTF16toASCII(
+ nsDependentString(u.wstr.mWStringValue, u.wstr.mWStringLength),
+ aResult);
+ return NS_OK;
+ case nsIDataType::VTYPE_WCHAR: {
+ const char16_t* str = &u.mWCharValue;
+ LossyCopyUTF16toASCII(Substring(str, 1), aResult);
+ return NS_OK;
+ }
+ default:
+ return ToString(aResult);
+ }
+}
+
+nsresult nsDiscriminatedUnion::ConvertToAUTF8String(
+ nsAUTF8String& aResult) const {
+ switch (mType) {
+ case nsIDataType::VTYPE_ASTRING:
+ CopyUTF16toUTF8(*u.mAStringValue, aResult);
+ return NS_OK;
+ case nsIDataType::VTYPE_CSTRING:
+ // XXX Extra copy, can be removed if we're sure CSTRING can
+ // only contain ASCII.
+ CopyUTF16toUTF8(NS_ConvertASCIItoUTF16(*u.mCStringValue), aResult);
+ return NS_OK;
+ case nsIDataType::VTYPE_UTF8STRING:
+ aResult.Assign(*u.mUTF8StringValue);
+ return NS_OK;
+ case nsIDataType::VTYPE_CHAR_STR:
+ // XXX Extra copy, can be removed if we're sure CHAR_STR can
+ // only contain ASCII.
+ CopyUTF16toUTF8(NS_ConvertASCIItoUTF16(u.str.mStringValue), aResult);
+ return NS_OK;
+ case nsIDataType::VTYPE_WCHAR_STR:
+ CopyUTF16toUTF8(mozilla::MakeStringSpan(u.wstr.mWStringValue), aResult);
+ return NS_OK;
+ case nsIDataType::VTYPE_STRING_SIZE_IS:
+ // XXX Extra copy, can be removed if we're sure CHAR_STR can
+ // only contain ASCII.
+ CopyUTF16toUTF8(NS_ConvertASCIItoUTF16(nsDependentCString(
+ u.str.mStringValue, u.str.mStringLength)),
+ aResult);
+ return NS_OK;
+ case nsIDataType::VTYPE_WSTRING_SIZE_IS:
+ CopyUTF16toUTF8(
+ nsDependentString(u.wstr.mWStringValue, u.wstr.mWStringLength),
+ aResult);
+ return NS_OK;
+ case nsIDataType::VTYPE_WCHAR: {
+ const char16_t* str = &u.mWCharValue;
+ CopyUTF16toUTF8(Substring(str, 1), aResult);
+ return NS_OK;
+ }
+ default: {
+ nsAutoCString tempCString;
+ nsresult rv = ToString(tempCString);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ // XXX Extra copy, can be removed if we're sure tempCString can
+ // only contain ASCII.
+ CopyUTF16toUTF8(NS_ConvertASCIItoUTF16(tempCString), aResult);
+ return NS_OK;
+ }
+ }
+}
+
+nsresult nsDiscriminatedUnion::ConvertToString(char** aResult) const {
+ uint32_t ignored;
+ return ConvertToStringWithSize(&ignored, aResult);
+}
+
+nsresult nsDiscriminatedUnion::ConvertToWString(char16_t** aResult) const {
+ uint32_t ignored;
+ return ConvertToWStringWithSize(&ignored, aResult);
+}
+
+nsresult nsDiscriminatedUnion::ConvertToStringWithSize(uint32_t* aSize,
+ char** aStr) const {
+ nsAutoString tempString;
+ nsAutoCString tempCString;
+ nsresult rv;
+
+ switch (mType) {
+ case nsIDataType::VTYPE_ASTRING:
+ *aSize = u.mAStringValue->Length();
+ *aStr = ToNewCString(*u.mAStringValue);
+ break;
+ case nsIDataType::VTYPE_CSTRING:
+ *aSize = u.mCStringValue->Length();
+ *aStr = ToNewCString(*u.mCStringValue);
+ break;
+ case nsIDataType::VTYPE_UTF8STRING: {
+ // XXX This is doing 1 extra copy. Need to fix this
+ // when Jag lands UTF8String
+ // we want:
+ // *aSize = *mUTF8StringValue->Length();
+ // *aStr = ToNewCString(*mUTF8StringValue);
+ // But this will have to do for now.
+ const NS_ConvertUTF8toUTF16 tempString16(*u.mUTF8StringValue);
+ *aSize = tempString16.Length();
+ *aStr = ToNewCString(tempString16);
+ break;
+ }
+ case nsIDataType::VTYPE_CHAR_STR: {
+ nsDependentCString cString(u.str.mStringValue);
+ *aSize = cString.Length();
+ *aStr = ToNewCString(cString);
+ break;
+ }
+ case nsIDataType::VTYPE_WCHAR_STR: {
+ nsDependentString string(u.wstr.mWStringValue);
+ *aSize = string.Length();
+ *aStr = ToNewCString(string);
+ break;
+ }
+ case nsIDataType::VTYPE_STRING_SIZE_IS: {
+ nsDependentCString cString(u.str.mStringValue, u.str.mStringLength);
+ *aSize = cString.Length();
+ *aStr = ToNewCString(cString);
+ break;
+ }
+ case nsIDataType::VTYPE_WSTRING_SIZE_IS: {
+ nsDependentString string(u.wstr.mWStringValue, u.wstr.mWStringLength);
+ *aSize = string.Length();
+ *aStr = ToNewCString(string);
+ break;
+ }
+ case nsIDataType::VTYPE_WCHAR:
+ tempString.Assign(u.mWCharValue);
+ *aSize = tempString.Length();
+ *aStr = ToNewCString(tempString);
+ break;
+ default:
+ rv = ToString(tempCString);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ *aSize = tempCString.Length();
+ *aStr = ToNewCString(tempCString);
+ break;
+ }
+
+ return *aStr ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+}
+nsresult nsDiscriminatedUnion::ConvertToWStringWithSize(uint32_t* aSize,
+ char16_t** aStr) const {
+ nsAutoString tempString;
+ nsAutoCString tempCString;
+ nsresult rv;
+
+ switch (mType) {
+ case nsIDataType::VTYPE_ASTRING:
+ *aSize = u.mAStringValue->Length();
+ *aStr = ToNewUnicode(*u.mAStringValue);
+ break;
+ case nsIDataType::VTYPE_CSTRING:
+ *aSize = u.mCStringValue->Length();
+ *aStr = ToNewUnicode(*u.mCStringValue);
+ break;
+ case nsIDataType::VTYPE_UTF8STRING: {
+ *aStr = UTF8ToNewUnicode(*u.mUTF8StringValue, aSize);
+ break;
+ }
+ case nsIDataType::VTYPE_CHAR_STR: {
+ nsDependentCString cString(u.str.mStringValue);
+ *aSize = cString.Length();
+ *aStr = ToNewUnicode(cString);
+ break;
+ }
+ case nsIDataType::VTYPE_WCHAR_STR: {
+ nsDependentString string(u.wstr.mWStringValue);
+ *aSize = string.Length();
+ *aStr = ToNewUnicode(string);
+ break;
+ }
+ case nsIDataType::VTYPE_STRING_SIZE_IS: {
+ nsDependentCString cString(u.str.mStringValue, u.str.mStringLength);
+ *aSize = cString.Length();
+ *aStr = ToNewUnicode(cString);
+ break;
+ }
+ case nsIDataType::VTYPE_WSTRING_SIZE_IS: {
+ nsDependentString string(u.wstr.mWStringValue, u.wstr.mWStringLength);
+ *aSize = string.Length();
+ *aStr = ToNewUnicode(string);
+ break;
+ }
+ case nsIDataType::VTYPE_WCHAR:
+ tempString.Assign(u.mWCharValue);
+ *aSize = tempString.Length();
+ *aStr = ToNewUnicode(tempString);
+ break;
+ default:
+ rv = ToString(tempCString);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ *aSize = tempCString.Length();
+ *aStr = ToNewUnicode(tempCString);
+ break;
+ }
+
+ return *aStr ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+}
+
+nsresult nsDiscriminatedUnion::ConvertToISupports(nsISupports** aResult) const {
+ switch (mType) {
+ case nsIDataType::VTYPE_INTERFACE:
+ case nsIDataType::VTYPE_INTERFACE_IS:
+ if (u.iface.mInterfaceValue) {
+ return u.iface.mInterfaceValue->QueryInterface(NS_GET_IID(nsISupports),
+ (void**)aResult);
+ } else {
+ *aResult = nullptr;
+ return NS_OK;
+ }
+ default:
+ return NS_ERROR_CANNOT_CONVERT_DATA;
+ }
+}
+
+nsresult nsDiscriminatedUnion::ConvertToInterface(nsIID** aIID,
+ void** aInterface) const {
+ const nsIID* piid;
+
+ switch (mType) {
+ case nsIDataType::VTYPE_INTERFACE:
+ piid = &NS_GET_IID(nsISupports);
+ break;
+ case nsIDataType::VTYPE_INTERFACE_IS:
+ piid = &u.iface.mInterfaceID;
+ break;
+ default:
+ return NS_ERROR_CANNOT_CONVERT_DATA;
+ }
+
+ *aIID = piid->Clone();
+
+ if (u.iface.mInterfaceValue) {
+ return u.iface.mInterfaceValue->QueryInterface(*piid, aInterface);
+ }
+
+ *aInterface = nullptr;
+ return NS_OK;
+}
+
+nsresult nsDiscriminatedUnion::ConvertToArray(uint16_t* aType, nsIID* aIID,
+ uint32_t* aCount,
+ void** aPtr) const {
+ // XXX perhaps we'd like to add support for converting each of the various
+ // types into an array containing one element of that type. We can leverage
+ // CloneArray to do this if we want to support this.
+
+ if (mType == nsIDataType::VTYPE_ARRAY) {
+ return CloneArray(u.array.mArrayType, &u.array.mArrayInterfaceID,
+ u.array.mArrayCount, u.array.mArrayValue, aType, aIID,
+ aCount, aPtr);
+ }
+ return NS_ERROR_CANNOT_CONVERT_DATA;
+}
+
+/***************************************************************************/
+// static setter functions...
+
+#define DATA_SETTER_PROLOGUE Cleanup()
+
+#define DATA_SETTER_EPILOGUE(type_) mType = nsIDataType::type_;
+
+#define DATA_SETTER(type_, member_, value_) \
+ DATA_SETTER_PROLOGUE; \
+ u.member_ = value_; \
+ DATA_SETTER_EPILOGUE(type_)
+
+#define DATA_SETTER_WITH_CAST(type_, member_, cast_, value_) \
+ DATA_SETTER_PROLOGUE; \
+ u.member_ = cast_ value_; \
+ DATA_SETTER_EPILOGUE(type_)
+
+/********************************************/
+
+#define CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(type_) {
+#define CASE__SET_FROM_VARIANT_VTYPE__GETTER(member_, name_) \
+ rv = aValue->GetAs##name_(&(u.member_));
+
+#define CASE__SET_FROM_VARIANT_VTYPE__GETTER_CAST(cast_, member_, name_) \
+ rv = aValue->GetAs##name_(cast_ & (u.member_));
+
+#define CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(type_) \
+ if (NS_SUCCEEDED(rv)) { \
+ mType = nsIDataType::type_; \
+ } \
+ break; \
+ }
+
+#define CASE__SET_FROM_VARIANT_TYPE(type_, member_, name_) \
+ case nsIDataType::type_: \
+ CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(type_) \
+ CASE__SET_FROM_VARIANT_VTYPE__GETTER(member_, name_) \
+ CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(type_)
+
+#define CASE__SET_FROM_VARIANT_VTYPE_CAST(type_, cast_, member_, name_) \
+ case nsIDataType::type_: \
+ CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(type_) \
+ CASE__SET_FROM_VARIANT_VTYPE__GETTER_CAST(cast_, member_, name_) \
+ CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(type_)
+
+nsresult nsDiscriminatedUnion::SetFromVariant(nsIVariant* aValue) {
+ nsresult rv = NS_OK;
+
+ Cleanup();
+
+ uint16_t type = aValue->GetDataType();
+
+ switch (type) {
+ CASE__SET_FROM_VARIANT_VTYPE_CAST(VTYPE_INT8, (uint8_t*), mInt8Value, Int8)
+ CASE__SET_FROM_VARIANT_TYPE(VTYPE_INT16, mInt16Value, Int16)
+ CASE__SET_FROM_VARIANT_TYPE(VTYPE_INT32, mInt32Value, Int32)
+ CASE__SET_FROM_VARIANT_TYPE(VTYPE_UINT8, mUint8Value, Uint8)
+ CASE__SET_FROM_VARIANT_TYPE(VTYPE_UINT16, mUint16Value, Uint16)
+ CASE__SET_FROM_VARIANT_TYPE(VTYPE_UINT32, mUint32Value, Uint32)
+ CASE__SET_FROM_VARIANT_TYPE(VTYPE_FLOAT, mFloatValue, Float)
+ CASE__SET_FROM_VARIANT_TYPE(VTYPE_DOUBLE, mDoubleValue, Double)
+ CASE__SET_FROM_VARIANT_TYPE(VTYPE_BOOL, mBoolValue, Bool)
+ CASE__SET_FROM_VARIANT_TYPE(VTYPE_CHAR, mCharValue, Char)
+ CASE__SET_FROM_VARIANT_TYPE(VTYPE_WCHAR, mWCharValue, WChar)
+ CASE__SET_FROM_VARIANT_TYPE(VTYPE_ID, mIDValue, ID)
+
+ case nsIDataType::VTYPE_ASTRING:
+ case nsIDataType::VTYPE_WCHAR_STR:
+ case nsIDataType::VTYPE_WSTRING_SIZE_IS:
+ CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_ASTRING);
+ u.mAStringValue = new nsString();
+
+ rv = aValue->GetAsAString(*u.mAStringValue);
+ if (NS_FAILED(rv)) {
+ delete u.mAStringValue;
+ }
+ CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_ASTRING)
+
+ case nsIDataType::VTYPE_CSTRING:
+ CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_CSTRING);
+ u.mCStringValue = new nsCString();
+
+ rv = aValue->GetAsACString(*u.mCStringValue);
+ if (NS_FAILED(rv)) {
+ delete u.mCStringValue;
+ }
+ CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_CSTRING)
+
+ case nsIDataType::VTYPE_UTF8STRING:
+ CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_UTF8STRING);
+ u.mUTF8StringValue = new nsUTF8String();
+
+ rv = aValue->GetAsAUTF8String(*u.mUTF8StringValue);
+ if (NS_FAILED(rv)) {
+ delete u.mUTF8StringValue;
+ }
+ CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_UTF8STRING)
+
+ case nsIDataType::VTYPE_CHAR_STR:
+ case nsIDataType::VTYPE_STRING_SIZE_IS:
+ CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_STRING_SIZE_IS);
+ rv = aValue->GetAsStringWithSize(&u.str.mStringLength,
+ &u.str.mStringValue);
+ CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_STRING_SIZE_IS)
+
+ case nsIDataType::VTYPE_INTERFACE:
+ case nsIDataType::VTYPE_INTERFACE_IS:
+ CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_INTERFACE_IS);
+ // XXX This iid handling is ugly!
+ nsIID* iid;
+ rv = aValue->GetAsInterface(&iid, (void**)&u.iface.mInterfaceValue);
+ if (NS_SUCCEEDED(rv)) {
+ u.iface.mInterfaceID = *iid;
+ free((char*)iid);
+ }
+ CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_INTERFACE_IS)
+
+ case nsIDataType::VTYPE_ARRAY:
+ CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_ARRAY);
+ rv = aValue->GetAsArray(&u.array.mArrayType, &u.array.mArrayInterfaceID,
+ &u.array.mArrayCount, &u.array.mArrayValue);
+ CASE__SET_FROM_VARIANT_VTYPE_EPILOGUE(VTYPE_ARRAY)
+
+ case nsIDataType::VTYPE_VOID:
+ SetToVoid();
+ rv = NS_OK;
+ break;
+ case nsIDataType::VTYPE_EMPTY_ARRAY:
+ SetToEmptyArray();
+ rv = NS_OK;
+ break;
+ case nsIDataType::VTYPE_EMPTY:
+ SetToEmpty();
+ rv = NS_OK;
+ break;
+ default:
+ NS_ERROR("bad type in variant!");
+ rv = NS_ERROR_FAILURE;
+ break;
+ }
+ return rv;
+}
+
+void nsDiscriminatedUnion::SetFromInt8(uint8_t aValue) {
+ DATA_SETTER_WITH_CAST(VTYPE_INT8, mInt8Value, (uint8_t), aValue);
+}
+void nsDiscriminatedUnion::SetFromInt16(int16_t aValue) {
+ DATA_SETTER(VTYPE_INT16, mInt16Value, aValue);
+}
+void nsDiscriminatedUnion::SetFromInt32(int32_t aValue) {
+ DATA_SETTER(VTYPE_INT32, mInt32Value, aValue);
+}
+void nsDiscriminatedUnion::SetFromInt64(int64_t aValue) {
+ DATA_SETTER(VTYPE_INT64, mInt64Value, aValue);
+}
+void nsDiscriminatedUnion::SetFromUint8(uint8_t aValue) {
+ DATA_SETTER(VTYPE_UINT8, mUint8Value, aValue);
+}
+void nsDiscriminatedUnion::SetFromUint16(uint16_t aValue) {
+ DATA_SETTER(VTYPE_UINT16, mUint16Value, aValue);
+}
+void nsDiscriminatedUnion::SetFromUint32(uint32_t aValue) {
+ DATA_SETTER(VTYPE_UINT32, mUint32Value, aValue);
+}
+void nsDiscriminatedUnion::SetFromUint64(uint64_t aValue) {
+ DATA_SETTER(VTYPE_UINT64, mUint64Value, aValue);
+}
+void nsDiscriminatedUnion::SetFromFloat(float aValue) {
+ DATA_SETTER(VTYPE_FLOAT, mFloatValue, aValue);
+}
+void nsDiscriminatedUnion::SetFromDouble(double aValue) {
+ DATA_SETTER(VTYPE_DOUBLE, mDoubleValue, aValue);
+}
+void nsDiscriminatedUnion::SetFromBool(bool aValue) {
+ DATA_SETTER(VTYPE_BOOL, mBoolValue, aValue);
+}
+void nsDiscriminatedUnion::SetFromChar(char aValue) {
+ DATA_SETTER(VTYPE_CHAR, mCharValue, aValue);
+}
+void nsDiscriminatedUnion::SetFromWChar(char16_t aValue) {
+ DATA_SETTER(VTYPE_WCHAR, mWCharValue, aValue);
+}
+void nsDiscriminatedUnion::SetFromID(const nsID& aValue) {
+ DATA_SETTER(VTYPE_ID, mIDValue, aValue);
+}
+void nsDiscriminatedUnion::SetFromAString(const nsAString& aValue) {
+ DATA_SETTER_PROLOGUE;
+ u.mAStringValue = new nsString(aValue);
+ DATA_SETTER_EPILOGUE(VTYPE_ASTRING);
+}
+
+void nsDiscriminatedUnion::SetFromACString(const nsACString& aValue) {
+ DATA_SETTER_PROLOGUE;
+ u.mCStringValue = new nsCString(aValue);
+ DATA_SETTER_EPILOGUE(VTYPE_CSTRING);
+}
+
+void nsDiscriminatedUnion::SetFromAUTF8String(const nsAUTF8String& aValue) {
+ DATA_SETTER_PROLOGUE;
+ u.mUTF8StringValue = new nsUTF8String(aValue);
+ DATA_SETTER_EPILOGUE(VTYPE_UTF8STRING);
+}
+
+nsresult nsDiscriminatedUnion::SetFromString(const char* aValue) {
+ DATA_SETTER_PROLOGUE;
+ if (!aValue) {
+ return NS_ERROR_NULL_POINTER;
+ }
+ return SetFromStringWithSize(strlen(aValue), aValue);
+}
+nsresult nsDiscriminatedUnion::SetFromWString(const char16_t* aValue) {
+ DATA_SETTER_PROLOGUE;
+ if (!aValue) {
+ return NS_ERROR_NULL_POINTER;
+ }
+ return SetFromWStringWithSize(NS_strlen(aValue), aValue);
+}
+void nsDiscriminatedUnion::SetFromISupports(nsISupports* aValue) {
+ return SetFromInterface(NS_GET_IID(nsISupports), aValue);
+}
+void nsDiscriminatedUnion::SetFromInterface(const nsIID& aIID,
+ nsISupports* aValue) {
+ DATA_SETTER_PROLOGUE;
+ NS_IF_ADDREF(aValue);
+ u.iface.mInterfaceValue = aValue;
+ u.iface.mInterfaceID = aIID;
+ DATA_SETTER_EPILOGUE(VTYPE_INTERFACE_IS);
+}
+nsresult nsDiscriminatedUnion::SetFromArray(uint16_t aType, const nsIID* aIID,
+ uint32_t aCount, void* aValue) {
+ DATA_SETTER_PROLOGUE;
+ if (!aValue || !aCount) {
+ return NS_ERROR_NULL_POINTER;
+ }
+
+ nsresult rv = CloneArray(aType, aIID, aCount, aValue, &u.array.mArrayType,
+ &u.array.mArrayInterfaceID, &u.array.mArrayCount,
+ &u.array.mArrayValue);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ DATA_SETTER_EPILOGUE(VTYPE_ARRAY);
+ return NS_OK;
+}
+nsresult nsDiscriminatedUnion::SetFromStringWithSize(uint32_t aSize,
+ const char* aValue) {
+ DATA_SETTER_PROLOGUE;
+ if (!aValue) {
+ return NS_ERROR_NULL_POINTER;
+ }
+ u.str.mStringValue = (char*)moz_xmemdup(aValue, (aSize + 1) * sizeof(char));
+ u.str.mStringLength = aSize;
+ DATA_SETTER_EPILOGUE(VTYPE_STRING_SIZE_IS);
+ return NS_OK;
+}
+nsresult nsDiscriminatedUnion::SetFromWStringWithSize(uint32_t aSize,
+ const char16_t* aValue) {
+ DATA_SETTER_PROLOGUE;
+ if (!aValue) {
+ return NS_ERROR_NULL_POINTER;
+ }
+ u.wstr.mWStringValue =
+ (char16_t*)moz_xmemdup(aValue, (aSize + 1) * sizeof(char16_t));
+ u.wstr.mWStringLength = aSize;
+ DATA_SETTER_EPILOGUE(VTYPE_WSTRING_SIZE_IS);
+ return NS_OK;
+}
+void nsDiscriminatedUnion::AllocateWStringWithSize(uint32_t aSize) {
+ DATA_SETTER_PROLOGUE;
+ u.wstr.mWStringValue = (char16_t*)moz_xmalloc((aSize + 1) * sizeof(char16_t));
+ u.wstr.mWStringValue[aSize] = '\0';
+ u.wstr.mWStringLength = aSize;
+ DATA_SETTER_EPILOGUE(VTYPE_WSTRING_SIZE_IS);
+}
+void nsDiscriminatedUnion::SetToVoid() {
+ DATA_SETTER_PROLOGUE;
+ DATA_SETTER_EPILOGUE(VTYPE_VOID);
+}
+void nsDiscriminatedUnion::SetToEmpty() {
+ DATA_SETTER_PROLOGUE;
+ DATA_SETTER_EPILOGUE(VTYPE_EMPTY);
+}
+void nsDiscriminatedUnion::SetToEmptyArray() {
+ DATA_SETTER_PROLOGUE;
+ DATA_SETTER_EPILOGUE(VTYPE_EMPTY_ARRAY);
+}
+
+/***************************************************************************/
+
+void nsDiscriminatedUnion::Cleanup() {
+ switch (mType) {
+ 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:
+ case nsIDataType::VTYPE_BOOL:
+ case nsIDataType::VTYPE_CHAR:
+ case nsIDataType::VTYPE_WCHAR:
+ case nsIDataType::VTYPE_VOID:
+ case nsIDataType::VTYPE_ID:
+ break;
+ case nsIDataType::VTYPE_ASTRING:
+ delete u.mAStringValue;
+ break;
+ case nsIDataType::VTYPE_CSTRING:
+ delete u.mCStringValue;
+ break;
+ case nsIDataType::VTYPE_UTF8STRING:
+ delete u.mUTF8StringValue;
+ break;
+ case nsIDataType::VTYPE_CHAR_STR:
+ case nsIDataType::VTYPE_STRING_SIZE_IS:
+ free((char*)u.str.mStringValue);
+ break;
+ case nsIDataType::VTYPE_WCHAR_STR:
+ case nsIDataType::VTYPE_WSTRING_SIZE_IS:
+ free((char*)u.wstr.mWStringValue);
+ break;
+ case nsIDataType::VTYPE_INTERFACE:
+ case nsIDataType::VTYPE_INTERFACE_IS:
+ NS_IF_RELEASE(u.iface.mInterfaceValue);
+ break;
+ case nsIDataType::VTYPE_ARRAY:
+ FreeArray();
+ break;
+ case nsIDataType::VTYPE_EMPTY_ARRAY:
+ case nsIDataType::VTYPE_EMPTY:
+ break;
+ default:
+ NS_ERROR("bad type in variant!");
+ break;
+ }
+
+ mType = nsIDataType::VTYPE_EMPTY;
+}
+
+void nsDiscriminatedUnion::Traverse(
+ nsCycleCollectionTraversalCallback& aCb) const {
+ switch (mType) {
+ case nsIDataType::VTYPE_INTERFACE:
+ case nsIDataType::VTYPE_INTERFACE_IS:
+ NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mData");
+ aCb.NoteXPCOMChild(u.iface.mInterfaceValue);
+ break;
+ case nsIDataType::VTYPE_ARRAY:
+ switch (u.array.mArrayType) {
+ case nsIDataType::VTYPE_INTERFACE:
+ case nsIDataType::VTYPE_INTERFACE_IS: {
+ nsISupports** p = (nsISupports**)u.array.mArrayValue;
+ for (uint32_t i = u.array.mArrayCount; i > 0; ++p, --i) {
+ NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(aCb, "mData[i]");
+ aCb.NoteXPCOMChild(*p);
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/***************************************************************************/
+/***************************************************************************/
+// members...
+
+nsVariantBase::nsVariantBase() : mWritable(true) {}
+
+// For all the data getters we just forward to the static (and sharable)
+// 'ConvertTo' functions.
+
+uint16_t nsVariantBase::GetDataType() { return mData.GetType(); }
+
+NS_IMETHODIMP
+nsVariantBase::GetAsInt8(uint8_t* aResult) {
+ return mData.ConvertToInt8(aResult);
+}
+
+NS_IMETHODIMP
+nsVariantBase::GetAsInt16(int16_t* aResult) {
+ return mData.ConvertToInt16(aResult);
+}
+
+NS_IMETHODIMP
+nsVariantBase::GetAsInt32(int32_t* aResult) {
+ return mData.ConvertToInt32(aResult);
+}
+
+NS_IMETHODIMP
+nsVariantBase::GetAsInt64(int64_t* aResult) {
+ return mData.ConvertToInt64(aResult);
+}
+
+NS_IMETHODIMP
+nsVariantBase::GetAsUint8(uint8_t* aResult) {
+ return mData.ConvertToUint8(aResult);
+}
+
+NS_IMETHODIMP
+nsVariantBase::GetAsUint16(uint16_t* aResult) {
+ return mData.ConvertToUint16(aResult);
+}
+
+NS_IMETHODIMP
+nsVariantBase::GetAsUint32(uint32_t* aResult) {
+ return mData.ConvertToUint32(aResult);
+}
+
+NS_IMETHODIMP
+nsVariantBase::GetAsUint64(uint64_t* aResult) {
+ return mData.ConvertToUint64(aResult);
+}
+
+NS_IMETHODIMP
+nsVariantBase::GetAsFloat(float* aResult) {
+ return mData.ConvertToFloat(aResult);
+}
+
+NS_IMETHODIMP
+nsVariantBase::GetAsDouble(double* aResult) {
+ return mData.ConvertToDouble(aResult);
+}
+
+NS_IMETHODIMP
+nsVariantBase::GetAsBool(bool* aResult) { return mData.ConvertToBool(aResult); }
+
+NS_IMETHODIMP
+nsVariantBase::GetAsChar(char* aResult) { return mData.ConvertToChar(aResult); }
+
+NS_IMETHODIMP
+nsVariantBase::GetAsWChar(char16_t* aResult) {
+ return mData.ConvertToWChar(aResult);
+}
+
+NS_IMETHODIMP_(nsresult)
+nsVariantBase::GetAsID(nsID* aResult) { return mData.ConvertToID(aResult); }
+
+NS_IMETHODIMP
+nsVariantBase::GetAsAString(nsAString& aResult) {
+ return mData.ConvertToAString(aResult);
+}
+
+NS_IMETHODIMP
+nsVariantBase::GetAsACString(nsACString& aResult) {
+ return mData.ConvertToACString(aResult);
+}
+
+NS_IMETHODIMP
+nsVariantBase::GetAsAUTF8String(nsAUTF8String& aResult) {
+ return mData.ConvertToAUTF8String(aResult);
+}
+
+NS_IMETHODIMP
+nsVariantBase::GetAsString(char** aResult) {
+ return mData.ConvertToString(aResult);
+}
+
+NS_IMETHODIMP
+nsVariantBase::GetAsWString(char16_t** aResult) {
+ return mData.ConvertToWString(aResult);
+}
+
+NS_IMETHODIMP
+nsVariantBase::GetAsISupports(nsISupports** aResult) {
+ return mData.ConvertToISupports(aResult);
+}
+
+NS_IMETHODIMP
+nsVariantBase::GetAsJSVal(JS::MutableHandleValue) {
+ // Can only get the jsval from an XPCVariant.
+ return NS_ERROR_CANNOT_CONVERT_DATA;
+}
+
+NS_IMETHODIMP
+nsVariantBase::GetAsInterface(nsIID** aIID, void** aInterface) {
+ return mData.ConvertToInterface(aIID, aInterface);
+}
+
+NS_IMETHODIMP_(nsresult)
+nsVariantBase::GetAsArray(uint16_t* aType, nsIID* aIID, uint32_t* aCount,
+ void** aPtr) {
+ return mData.ConvertToArray(aType, aIID, aCount, aPtr);
+}
+
+NS_IMETHODIMP
+nsVariantBase::GetAsStringWithSize(uint32_t* aSize, char** aStr) {
+ return mData.ConvertToStringWithSize(aSize, aStr);
+}
+
+NS_IMETHODIMP
+nsVariantBase::GetAsWStringWithSize(uint32_t* aSize, char16_t** aStr) {
+ return mData.ConvertToWStringWithSize(aSize, aStr);
+}
+
+/***************************************************************************/
+
+NS_IMETHODIMP
+nsVariantBase::GetWritable(bool* aWritable) {
+ *aWritable = mWritable;
+ return NS_OK;
+}
+NS_IMETHODIMP
+nsVariantBase::SetWritable(bool aWritable) {
+ if (!mWritable && aWritable) {
+ return NS_ERROR_FAILURE;
+ }
+ mWritable = aWritable;
+ return NS_OK;
+}
+
+/***************************************************************************/
+
+// For all the data setters we just forward to the static (and sharable)
+// 'SetFrom' functions.
+
+NS_IMETHODIMP
+nsVariantBase::SetAsInt8(uint8_t aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetFromInt8(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsInt16(int16_t aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetFromInt16(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsInt32(int32_t aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetFromInt32(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsInt64(int64_t aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetFromInt64(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsUint8(uint8_t aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetFromUint8(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsUint16(uint16_t aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetFromUint16(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsUint32(uint32_t aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetFromUint32(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsUint64(uint64_t aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetFromUint64(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsFloat(float aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetFromFloat(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsDouble(double aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetFromDouble(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsBool(bool aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetFromBool(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsChar(char aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetFromChar(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsWChar(char16_t aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetFromWChar(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsID(const nsID& aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetFromID(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsAString(const nsAString& aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetFromAString(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsACString(const nsACString& aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetFromACString(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsAUTF8String(const nsAUTF8String& aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetFromAUTF8String(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsString(const char* aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ return mData.SetFromString(aValue);
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsWString(const char16_t* aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ return mData.SetFromWString(aValue);
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsISupports(nsISupports* aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetFromISupports(aValue);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsInterface(const nsIID& aIID, void* aInterface) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetFromInterface(aIID, (nsISupports*)aInterface);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsArray(uint16_t aType, const nsIID* aIID, uint32_t aCount,
+ void* aPtr) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ return mData.SetFromArray(aType, aIID, aCount, aPtr);
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsStringWithSize(uint32_t aSize, const char* aStr) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ return mData.SetFromStringWithSize(aSize, aStr);
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsWStringWithSize(uint32_t aSize, const char16_t* aStr) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ return mData.SetFromWStringWithSize(aSize, aStr);
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsVoid() {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetToVoid();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsEmpty() {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetToEmpty();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetAsEmptyArray() {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ mData.SetToEmptyArray();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsVariantBase::SetFromVariant(nsIVariant* aValue) {
+ if (!mWritable) {
+ return NS_ERROR_OBJECT_IS_IMMUTABLE;
+ }
+ return mData.SetFromVariant(aValue);
+}
+
+/* nsVariant implementation */
+
+NS_IMPL_ISUPPORTS(nsVariant, nsIVariant, nsIWritableVariant)
+
+/* nsVariantCC implementation */
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsVariantCC)
+ NS_INTERFACE_MAP_ENTRY(nsISupports)
+ NS_INTERFACE_MAP_ENTRY(nsIVariant)
+ NS_INTERFACE_MAP_ENTRY(nsIWritableVariant)
+NS_INTERFACE_MAP_END
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(nsVariantCC)
+
+NS_IMPL_CYCLE_COLLECTING_ADDREF(nsVariantCC)
+NS_IMPL_CYCLE_COLLECTING_RELEASE(nsVariantCC)
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsVariantCC)
+ tmp->mData.Traverse(cb);
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsVariantCC)
+ tmp->mData.Cleanup();
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END