gecko-dev/xpcom/ds/nsVariant.cpp
Henri Sivonen 3edc601325 Bug 1402247 - Use encoding_rs for XPCOM string encoding conversions. r=Nika,erahm,froydnj.
Correctness improvements:

 * UTF errors are handled safely per spec instead of dangerously truncating
   strings.

 * There are fewer converter implementations.

Performance improvements:

 * The old code did exact buffer length math, which meant doing UTF math twice
   on each input string (once for length calculation and another time for
   conversion). Exact length math is more complicated when handling errors
   properly, which the old code didn't do. The new code does UTF math on the
   string content only once (when converting) but risks allocating more than
   once. There are heuristics in place to lower the probability of
   reallocation in cases where the double math avoidance isn't enough of a
   saving to absorb an allocation and memcpy.

 * Previously, in UTF-16 <-> UTF-8 conversions, an ASCII prefix was optimized
   but a single non-ASCII code point pessimized the rest of the string. The
   new code tries to get back on the fast ASCII path.

 * UTF-16 to Latin1 conversion guarantees less about handling of out-of-range
   input to eliminate an operation from the inner loop on x86/x86_64.

 * When assigning to a pre-existing string, the new code tries to reuse the
   old buffer instead of first releasing the old buffer and then allocating a
   new one.

 * When reallocating from the new code, the memcpy covers only the data that
   is part of the logical length of the old string instead of memcpying the
   whole capacity. (For old callers old excess memcpy behavior is preserved
   due to bogus callers. See bug 1472113.)

 * UTF-8 strings in XPConnect that are in the Latin1 range are passed to
   SpiderMonkey as Latin1.

New features:

 * Conversion between UTF-8 and Latin1 is added in order to enable faster
   future interop between Rust code (or otherwise UTF-8-using code) and text
   node and SpiderMonkey code that uses Latin1.

MozReview-Commit-ID: JaJuExfILM9
2018-08-14 14:43:42 +03:00

2150 lines
63 KiB
C++

/* -*- 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 "nsMemory.h"
#include "nsString.h"
#include "nsCRTGlue.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);
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.mInt32Value = u.mUint32Value;
aOutData->mType = nsIDataType::VTYPE_INT32;
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_DOMSTRING:
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_DOMSTRING:
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_DOMSTRING:
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);
if (!*aOutValue) {
return NS_ERROR_OUT_OF_MEMORY;
}
// 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;
}
MOZ_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_strdup(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_DOMSTRING:
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(Ctype_, min_, max_) \
case nsIDataType::VTYPE_DOUBLE: \
{ \
double value = tempData.u.mDoubleValue; \
if (value < min_ || value > max_) \
return NS_ERROR_LOSS_OF_SIGNIFICANT_DATA; \
*aResult = ( Ctype_ ) value; \
return rv; \
}
#define CASE__NUMERIC_CONVERSION_DOUBLE_MIN_MAX_INT(Ctype_, min_, max_) \
case nsIDataType::VTYPE_DOUBLE: \
{ \
double value = tempData.u.mDoubleValue; \
if (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 convertions 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 convertions need to be fixed!
NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_CHAR, char, Char)
CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(char)
CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(char)
CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(char)
NUMERIC_CONVERSION_METHOD_END
// XXX toWChar convertions need to be fixed!
NUMERIC_CONVERSION_METHOD_BEGIN(VTYPE_WCHAR, char16_t, WChar)
CASE__NUMERIC_CONVERSION_INT32_JUST_CAST(char16_t)
CASE__NUMERIC_CONVERSION_UINT32_JUST_CAST(char16_t)
CASE__NUMERIC_CONVERSION_DOUBLE_JUST_CAST(char16_t)
NUMERIC_CONVERSION_METHOD_END
#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;
}
*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:
// XXX should check for data loss here!
*aResult = tempData.u.mDoubleValue;
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:
case nsIDataType::VTYPE_DOMSTRING:
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);
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_DOMSTRING:
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_DOMSTRING:
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!");
MOZ_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:
case nsIDataType::VTYPE_DOMSTRING:
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:
case nsIDataType::VTYPE_DOMSTRING:
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:
case nsIDataType::VTYPE_DOMSTRING:
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:
case nsIDataType::VTYPE_DOMSTRING:
*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:
case nsIDataType::VTYPE_DOMSTRING:
*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)
{
uint16_t type;
nsresult rv;
Cleanup();
rv = aValue->GetDataType(&type);
if (NS_FAILED(rv)) {
return rv;
}
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_DOMSTRING:
case nsIDataType::VTYPE_WCHAR_STR:
case nsIDataType::VTYPE_WSTRING_SIZE_IS:
CASE__SET_FROM_VARIANT_VTYPE_PROLOGUE(VTYPE_ASTRING);
u.mAStringValue = new nsString();
if (!u.mAStringValue) {
return NS_ERROR_OUT_OF_MEMORY;
}
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();
if (!u.mCStringValue) {
return NS_ERROR_OUT_OF_MEMORY;
}
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();
if (!u.mUTF8StringValue) {
return NS_ERROR_OUT_OF_MEMORY;
}
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::SetFromDOMString(const nsAString& aValue)
{
DATA_SETTER_PROLOGUE;
u.mAStringValue = new nsString(aValue);
DATA_SETTER_EPILOGUE(VTYPE_DOMSTRING);
}
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;
}
if (!(u.str.mStringValue =
(char*)nsMemory::Clone(aValue, (aSize + 1) * sizeof(char)))) {
return NS_ERROR_OUT_OF_MEMORY;
}
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;
}
if (!(u.wstr.mWStringValue =
(char16_t*)nsMemory::Clone(aValue, (aSize + 1) * sizeof(char16_t)))) {
return NS_ERROR_OUT_OF_MEMORY;
}
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:
case nsIDataType::VTYPE_DOMSTRING:
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.
NS_IMETHODIMP
nsVariantBase::GetDataType(uint16_t* aDataType)
{
*aDataType = mData.GetType();
return NS_OK;
}
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::GetAsDOMString(nsAString& aResult)
{
// A DOMString maps to an AString internally, so we can re-use
// ConvertToAString here.
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::SetAsDOMString(const nsAString& aValue)
{
if (!mWritable) {
return NS_ERROR_OBJECT_IS_IMMUTABLE;
}
mData.SetFromDOMString(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