Back to index

lightning-sunbird  0.9+nobinonly
xpcvariant.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002  *
00003  * ***** BEGIN LICENSE BLOCK *****
00004  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00005  *
00006  * The contents of this file are subject to the Mozilla Public License Version
00007  * 1.1 (the "License"); you may not use this file except in compliance with
00008  * the License. You may obtain a copy of the License at
00009  * http://www.mozilla.org/MPL/
00010  *
00011  * Software distributed under the License is distributed on an "AS IS" basis,
00012  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00013  * for the specific language governing rights and limitations under the
00014  * License.
00015  *
00016  * The Original Code is Mozilla Communicator client code, released
00017  * March 31, 1998.
00018  *
00019  * The Initial Developer of the Original Code is
00020  * Netscape Communications Corporation.
00021  * Portions created by the Initial Developer are Copyright (C) 1998
00022  * the Initial Developer. All Rights Reserved.
00023  *
00024  * Contributor(s):
00025  *   John Bandhauer <jband@netscape.com> (original author)
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either of the GNU General Public License Version 2 or later (the "GPL"),
00029  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00030  * in which case the provisions of the GPL or the LGPL are applicable instead
00031  * of those above. If you wish to allow use of your version of this file only
00032  * under the terms of either the GPL or the LGPL, and not to allow others to
00033  * use your version of this file under the terms of the MPL, indicate your
00034  * decision by deleting the provisions above and replace them with the notice
00035  * and other provisions required by the GPL or the LGPL. If you do not delete
00036  * the provisions above, a recipient may use your version of this file under
00037  * the terms of any one of the MPL, the GPL or the LGPL.
00038  *
00039  * ***** END LICENSE BLOCK ***** */
00040 
00041 /* nsIVariant implementation for xpconnect. */
00042 
00043 #include "xpcprivate.h"
00044 
00045 NS_IMPL_ISUPPORTS2_CI(XPCVariant, XPCVariant, nsIVariant)
00046 
00047 XPCVariant::XPCVariant()
00048     : mJSVal(JSVAL_VOID)
00049 {
00050     nsVariant::Initialize(&mData);
00051 }
00052 
00053 XPCVariant::~XPCVariant()
00054 {
00055     nsVariant::Cleanup(&mData);
00056     
00057     if(JSVAL_IS_GCTHING(mJSVal))
00058     {
00059         JSRuntime* rt;
00060         nsIJSRuntimeService* rtsrvc = nsXPConnect::GetJSRuntimeService();
00061 
00062         if(rtsrvc && NS_SUCCEEDED(rtsrvc->GetRuntime(&rt)))
00063             JS_RemoveRootRT(rt, &mJSVal);
00064     }
00065 }
00066 
00067 // static 
00068 XPCVariant* XPCVariant::newVariant(XPCCallContext& ccx, jsval aJSVal)
00069 {
00070     XPCVariant* variant = new XPCVariant();
00071     if(!variant)
00072         return nsnull;
00073     
00074     NS_ADDREF(variant);
00075 
00076     variant->mJSVal = aJSVal;
00077 
00078     if(JSVAL_IS_GCTHING(variant->mJSVal))
00079     {
00080         JSRuntime* rt;
00081         if(NS_FAILED(ccx.GetRuntime()->GetJSRuntimeService()->GetRuntime(&rt))||
00082            !JS_AddNamedRootRT(rt, &variant->mJSVal, "XPCVariant::mJSVal"))
00083         {
00084             NS_RELEASE(variant); // Also sets variant to nsnull.
00085         }
00086     }
00087 
00088     if(variant && !variant->InitializeData(ccx))
00089         NS_RELEASE(variant);     // Also sets variant to nsnull.
00090 
00091     return variant;
00092 }
00093 
00094 
00095 // Helper class to give us a namespace for the table based code below.
00096 class XPCArrayHomogenizer
00097 {
00098 private:
00099     enum Type
00100     {
00101         tNull  = 0 ,  // null value
00102         tInt       ,  // Integer
00103         tDbl       ,  // Double
00104         tBool      ,  // Boolean
00105         tStr       ,  // String
00106         tID        ,  // ID
00107         tArr       ,  // Array
00108         tISup      ,  // nsISupports (really just a plain JSObject)
00109         tUnk       ,  // Unknown. Used only for initial state.
00110 
00111         tTypeCount ,  // Just a count for table dimensioning.
00112 
00113         tVar       ,  // nsVariant - last ditch if no other common type found.
00114         tErr          // No valid state or type has this value. 
00115     };
00116 
00117     // Table has tUnk as a state (column) but not as a type (row).
00118     static Type StateTable[tTypeCount][tTypeCount-1];
00119 
00120 public:
00121     static JSBool GetTypeForArray(XPCCallContext& ccx, JSObject* array, 
00122                                   jsuint length, 
00123                                   nsXPTType* resultType, nsID* resultID);
00124 };
00125 
00126 
00127 // Current state is the column down the side. 
00128 // Current type is the row along the top. 
00129 // New state is in the box at the intersection.
00130 
00131 XPCArrayHomogenizer::Type 
00132 XPCArrayHomogenizer::StateTable[tTypeCount][tTypeCount-1] = {
00133 /*          tNull,tInt ,tDbl ,tBool,tStr ,tID  ,tArr ,tISup */
00134 /* tNull */{tNull,tVar ,tVar ,tVar ,tStr ,tID  ,tVar ,tISup },
00135 /* tInt  */{tVar ,tInt ,tDbl ,tVar ,tVar ,tVar ,tVar ,tVar  },
00136 /* tDbl  */{tVar ,tDbl ,tDbl ,tVar ,tVar ,tVar ,tVar ,tVar  },
00137 /* tBool */{tVar ,tVar ,tVar ,tBool,tVar ,tVar ,tVar ,tVar  },
00138 /* tStr  */{tStr ,tVar ,tVar ,tVar ,tStr ,tVar ,tVar ,tVar  },
00139 /* tID   */{tID  ,tVar ,tVar ,tVar ,tVar ,tID  ,tVar ,tVar  },
00140 /* tArr  */{tErr ,tErr ,tErr ,tErr ,tErr ,tErr ,tErr ,tErr  },
00141 /* tISup */{tISup,tVar ,tVar ,tVar ,tVar ,tVar ,tVar ,tISup },
00142 /* tUnk  */{tNull,tInt ,tDbl ,tBool,tStr ,tID  ,tVar ,tISup }};
00143 
00144 // static
00145 JSBool
00146 XPCArrayHomogenizer::GetTypeForArray(XPCCallContext& ccx, JSObject* array,
00147                                      jsuint length, 
00148                                      nsXPTType* resultType, nsID* resultID)    
00149 {
00150     Type state = tUnk;
00151     Type type;
00152        
00153     for(jsuint i = 0; i < length; i++)
00154     {
00155         jsval val;
00156         if(!JS_GetElement(ccx, array, i, &val))
00157             return JS_FALSE;
00158            
00159         if(JSVAL_IS_INT(val))
00160             type = tInt;
00161         else if(JSVAL_IS_DOUBLE(val))
00162             type = tDbl;
00163         else if(JSVAL_IS_BOOLEAN(val))
00164             type = tBool;
00165         else if(JSVAL_IS_VOID(val))
00166         {
00167             state = tVar;
00168             break;
00169         }
00170         else if(JSVAL_IS_NULL(val))
00171             type = tNull;
00172         else if(JSVAL_IS_STRING(val))
00173             type = tStr;
00174         else
00175         {
00176             NS_ASSERTION(JSVAL_IS_OBJECT(val), "invalid type of jsval!");
00177             JSObject* jsobj = JSVAL_TO_OBJECT(val);
00178             if(JS_IsArrayObject(ccx, jsobj))
00179                 type = tArr;
00180             else if(xpc_JSObjectIsID(ccx, jsobj))
00181                 type = tID;
00182             else
00183                 type = tISup;
00184         }
00185 
00186         NS_ASSERTION(state != tErr, "bad state table!");
00187         NS_ASSERTION(type  != tErr, "bad type!");
00188         NS_ASSERTION(type  != tVar, "bad type!");
00189         NS_ASSERTION(type  != tUnk, "bad type!");
00190 
00191         state = StateTable[state][type];
00192         
00193         NS_ASSERTION(state != tErr, "bad state table!");
00194         NS_ASSERTION(state != tUnk, "bad state table!");
00195         
00196         if(state == tVar)
00197             break;
00198     }
00199 
00200     switch(state)
00201     {
00202         case tInt : 
00203             *resultType = nsXPTType((uint8)TD_INT32);
00204             break;
00205         case tDbl : 
00206             *resultType = nsXPTType((uint8)TD_DOUBLE);
00207             break;
00208         case tBool:
00209             *resultType = nsXPTType((uint8)TD_BOOL);
00210             break;
00211         case tStr : 
00212             *resultType = nsXPTType((uint8)(TD_PWSTRING | XPT_TDP_POINTER));
00213             break;
00214         case tID  : 
00215             *resultType = nsXPTType((uint8)(TD_PNSIID | XPT_TDP_POINTER));
00216             break;
00217         case tISup: 
00218             *resultType = nsXPTType((uint8)(TD_INTERFACE_IS_TYPE | XPT_TDP_POINTER));
00219             *resultID = NS_GET_IID(nsISupports);
00220             break;
00221         case tNull: 
00222             // FALL THROUGH
00223         case tVar :
00224             *resultType = nsXPTType((uint8)(TD_INTERFACE_IS_TYPE | XPT_TDP_POINTER));
00225             *resultID = NS_GET_IID(nsIVariant);
00226             break;
00227         case tArr : 
00228             // FALL THROUGH
00229         case tUnk : 
00230             // FALL THROUGH
00231         case tErr : 
00232             // FALL THROUGH
00233         default:
00234             NS_ERROR("bad state");
00235             return JS_FALSE;
00236     }
00237     return JS_TRUE;
00238 }
00239 
00240 JSBool XPCVariant::InitializeData(XPCCallContext& ccx)
00241 {
00242     if(JSVAL_IS_INT(mJSVal))
00243         return NS_SUCCEEDED(nsVariant::SetFromInt32(&mData, 
00244                                                    JSVAL_TO_INT(mJSVal)));
00245     if(JSVAL_IS_DOUBLE(mJSVal))
00246         return NS_SUCCEEDED(nsVariant::SetFromDouble(&mData, 
00247                                                      *JSVAL_TO_DOUBLE(mJSVal)));
00248     if(JSVAL_IS_BOOLEAN(mJSVal))
00249         return NS_SUCCEEDED(nsVariant::SetFromBool(&mData, 
00250                                                    JSVAL_TO_BOOLEAN(mJSVal)));
00251     if(JSVAL_IS_VOID(mJSVal))
00252         return NS_SUCCEEDED(nsVariant::SetToEmpty(&mData));
00253     if(JSVAL_IS_NULL(mJSVal))
00254         return NS_SUCCEEDED(nsVariant::SetToEmpty(&mData));
00255     if(JSVAL_IS_STRING(mJSVal))
00256     {
00257         return NS_SUCCEEDED(nsVariant::SetFromWStringWithSize(&mData, 
00258                     (PRUint32)JS_GetStringLength(JSVAL_TO_STRING(mJSVal)),
00259                     (PRUnichar*)JS_GetStringChars(JSVAL_TO_STRING(mJSVal))));
00260     }
00261 
00262     // leaving only JSObject...
00263     NS_ASSERTION(JSVAL_IS_OBJECT(mJSVal), "invalid type of jsval!");
00264     
00265     JSObject* jsobj = JSVAL_TO_OBJECT(mJSVal);
00266 
00267     // Let's see if it is a xpcJSID.
00268 
00269     // XXX It might be nice to have a non-allocing version of xpc_JSObjectToID.
00270     nsID* id = xpc_JSObjectToID(ccx, jsobj);
00271     if(id)
00272     {
00273         JSBool success = NS_SUCCEEDED(nsVariant::SetFromID(&mData, *id));
00274         nsMemory::Free((char*)id);
00275         return success;
00276     }
00277     
00278     // Let's see if it is a js array object.
00279 
00280     jsuint len;
00281 
00282     if(JS_IsArrayObject(ccx, jsobj) && JS_GetArrayLength(ccx, jsobj, &len))
00283     {
00284         if(!len) 
00285         {
00286             // Zero length array
00287             nsVariant::SetToEmptyArray(&mData);
00288             return JS_TRUE;
00289         }
00290         
00291         nsXPTType type;
00292         nsID id;
00293 
00294         if(!XPCArrayHomogenizer::GetTypeForArray(ccx, jsobj, len, &type, &id))
00295             return JS_FALSE; 
00296 
00297         if(!XPCConvert::JSArray2Native(ccx, &mData.u.array.mArrayValue, 
00298                                        mJSVal, len, len,
00299                                        type, type.IsPointer(),
00300                                        &id, nsnull))
00301             return JS_FALSE;
00302 
00303         mData.mType = nsIDataType::VTYPE_ARRAY;
00304         if(type.IsInterfacePointer())
00305             mData.u.array.mArrayInterfaceID = id;
00306         mData.u.array.mArrayCount = len;
00307         mData.u.array.mArrayType = type.TagPart();
00308         
00309         return JS_TRUE;
00310     }    
00311 
00312     // XXX This could be smarter and pick some more interesting iface.
00313 
00314     nsXPConnect*  xpc;
00315     nsCOMPtr<nsISupports> wrapper;
00316     const nsIID& iid = NS_GET_IID(nsISupports);
00317 
00318     return nsnull != (xpc = nsXPConnect::GetXPConnect()) &&
00319            NS_SUCCEEDED(xpc->WrapJS(ccx, jsobj,
00320                         iid, getter_AddRefs(wrapper))) &&
00321            NS_SUCCEEDED(nsVariant::SetFromInterface(&mData, iid, wrapper));
00322 }
00323 
00324 // static 
00325 JSBool 
00326 XPCVariant::VariantDataToJS(XPCCallContext& ccx, 
00327                             nsIVariant* variant,
00328                             JSObject* scope, nsresult* pErr,
00329                             jsval* pJSVal)
00330 {
00331     // Get the type early because we might need to spoof it below.
00332     PRUint16 type;
00333     if(NS_FAILED(variant->GetDataType(&type)))
00334         return JS_FALSE;
00335 
00336     nsCOMPtr<XPCVariant> xpcvariant = do_QueryInterface(variant);
00337     if(xpcvariant)
00338     {
00339         jsval realVal = xpcvariant->GetJSVal();
00340         if(JSVAL_IS_PRIMITIVE(realVal) || 
00341            type == nsIDataType::VTYPE_ARRAY ||
00342            type == nsIDataType::VTYPE_ID)
00343         {
00344             // Not a JSObject (or is a JSArray or is a JSObject representing 
00345             // an nsID),.
00346             // So, just pass through the underlying data.
00347             *pJSVal = realVal;
00348             return JS_TRUE;
00349         }
00350 
00351         // else, it's an object and we really need to double wrap it if we've 
00352         // already decided that its 'natural' type is as some sort of interface.
00353         
00354         // We just fall through to the code below and let it do what it does.
00355     }
00356 
00357     // The nsIVariant is not a XPCVariant (or we act like it isn't).
00358     // So we extract the data and do the Right Thing.
00359     
00360     // We ASSUME that the variant implementation can do these conversions...
00361 
00362     nsXPTCVariant xpctvar;
00363     nsID iid;
00364     nsAutoString astring;
00365     nsCAutoString cString;
00366     nsUTF8String utf8String;
00367     PRUint32 size;
00368     xpctvar.flags = 0;
00369     JSBool success;
00370 
00371     switch(type)
00372     {
00373         case nsIDataType::VTYPE_INT8:        
00374         case nsIDataType::VTYPE_INT16:        
00375         case nsIDataType::VTYPE_INT32:        
00376         case nsIDataType::VTYPE_INT64:        
00377         case nsIDataType::VTYPE_UINT8:        
00378         case nsIDataType::VTYPE_UINT16:        
00379         case nsIDataType::VTYPE_UINT32:        
00380         case nsIDataType::VTYPE_UINT64:        
00381         case nsIDataType::VTYPE_FLOAT:        
00382         case nsIDataType::VTYPE_DOUBLE:        
00383         {
00384             // Easy. Handle inline.
00385             if(NS_FAILED(variant->GetAsDouble(&xpctvar.val.d)))
00386                 return JS_FALSE;
00387             return JS_NewNumberValue(ccx, xpctvar.val.d, pJSVal);
00388         }
00389         case nsIDataType::VTYPE_BOOL:        
00390         {
00391             // Easy. Handle inline.
00392             if(NS_FAILED(variant->GetAsBool(&xpctvar.val.b)))
00393                 return JS_FALSE;
00394             *pJSVal = BOOLEAN_TO_JSVAL(xpctvar.val.b);
00395             return JS_TRUE;
00396         }
00397         case nsIDataType::VTYPE_CHAR: 
00398             if(NS_FAILED(variant->GetAsChar(&xpctvar.val.c)))
00399                 return JS_FALSE;
00400             xpctvar.type = (uint8)TD_CHAR;
00401             break;
00402         case nsIDataType::VTYPE_WCHAR:        
00403             if(NS_FAILED(variant->GetAsWChar(&xpctvar.val.wc)))
00404                 return JS_FALSE;
00405             xpctvar.type = (uint8)TD_WCHAR;
00406             break;
00407         case nsIDataType::VTYPE_ID:        
00408             if(NS_FAILED(variant->GetAsID(&iid)))
00409                 return JS_FALSE;
00410             xpctvar.type = (uint8)(TD_PNSIID | XPT_TDP_POINTER);
00411             xpctvar.val.p = &iid;
00412             break;
00413         case nsIDataType::VTYPE_ASTRING:        
00414             if(NS_FAILED(variant->GetAsAString(astring)))
00415                 return JS_FALSE;
00416             xpctvar.type = (uint8)(TD_ASTRING | XPT_TDP_POINTER);
00417             xpctvar.val.p = &astring;
00418             break;
00419         case nsIDataType::VTYPE_DOMSTRING:
00420             if(NS_FAILED(variant->GetAsAString(astring)))
00421                 return JS_FALSE;
00422             xpctvar.type = (uint8)(TD_DOMSTRING | XPT_TDP_POINTER);
00423             xpctvar.val.p = &astring;
00424             break;
00425         case nsIDataType::VTYPE_CSTRING:            
00426             if(NS_FAILED(variant->GetAsACString(cString)))
00427                 return JS_FALSE;
00428             xpctvar.type = (uint8)(TD_CSTRING | XPT_TDP_POINTER);
00429             xpctvar.val.p = &cString;
00430             break;
00431         case nsIDataType::VTYPE_UTF8STRING:            
00432             if(NS_FAILED(variant->GetAsAUTF8String(utf8String)))
00433                 return JS_FALSE;
00434             xpctvar.type = (uint8)(TD_UTF8STRING | XPT_TDP_POINTER);
00435             xpctvar.val.p = &utf8String;
00436             break;       
00437         case nsIDataType::VTYPE_CHAR_STR:       
00438             if(NS_FAILED(variant->GetAsString((char**)&xpctvar.val.p)))
00439                 return JS_FALSE;
00440             xpctvar.type = (uint8)(TD_PSTRING | XPT_TDP_POINTER);
00441             xpctvar.SetValIsAllocated();
00442             break;
00443         case nsIDataType::VTYPE_STRING_SIZE_IS:
00444             if(NS_FAILED(variant->GetAsStringWithSize(&size, 
00445                                                       (char**)&xpctvar.val.p)))
00446                 return JS_FALSE;
00447             xpctvar.type = (uint8)(TD_PSTRING_SIZE_IS | XPT_TDP_POINTER);
00448             break;
00449         case nsIDataType::VTYPE_WCHAR_STR:        
00450             if(NS_FAILED(variant->GetAsWString((PRUnichar**)&xpctvar.val.p)))
00451                 return JS_FALSE;
00452             xpctvar.type = (uint8)(TD_PWSTRING | XPT_TDP_POINTER);
00453             xpctvar.SetValIsAllocated();
00454             break;
00455         case nsIDataType::VTYPE_WSTRING_SIZE_IS:        
00456             if(NS_FAILED(variant->GetAsWStringWithSize(&size, 
00457                                                       (PRUnichar**)&xpctvar.val.p)))
00458                 return JS_FALSE;
00459             xpctvar.type = (uint8)(TD_PWSTRING_SIZE_IS | XPT_TDP_POINTER);
00460             break;
00461         case nsIDataType::VTYPE_INTERFACE:        
00462         case nsIDataType::VTYPE_INTERFACE_IS:        
00463         {
00464             nsID* piid;
00465             if(NS_FAILED(variant->GetAsInterface(&piid, &xpctvar.val.p)))
00466                 return JS_FALSE;
00467 
00468             iid = *piid;
00469             nsMemory::Free((char*)piid);
00470 
00471             xpctvar.type = (uint8)(TD_INTERFACE_IS_TYPE | XPT_TDP_POINTER);
00472             if(xpctvar.val.p)
00473                 xpctvar.SetValIsInterface();
00474             break;
00475         }
00476         case nsIDataType::VTYPE_ARRAY:
00477         {
00478             nsDiscriminatedUnion du;
00479             nsVariant::Initialize(&du);
00480             nsresult rv;
00481 
00482             rv = variant->GetAsArray(&du.u.array.mArrayType,
00483                                      &du.u.array.mArrayInterfaceID,
00484                                      &du.u.array.mArrayCount,
00485                                      &du.u.array.mArrayValue);
00486             if(NS_FAILED(rv))
00487                 return JS_FALSE;
00488         
00489             // must exit via VARIANT_DONE from here on...
00490             du.mType = nsIDataType::VTYPE_ARRAY;
00491             success = JS_FALSE;
00492 
00493             nsXPTType conversionType;
00494             PRUint16 elementType = du.u.array.mArrayType;
00495             const nsID* pid = nsnull;
00496 
00497             switch(elementType)
00498             {
00499                 case nsIDataType::VTYPE_INT8:        
00500                 case nsIDataType::VTYPE_INT16:        
00501                 case nsIDataType::VTYPE_INT32:        
00502                 case nsIDataType::VTYPE_INT64:        
00503                 case nsIDataType::VTYPE_UINT8:        
00504                 case nsIDataType::VTYPE_UINT16:        
00505                 case nsIDataType::VTYPE_UINT32:        
00506                 case nsIDataType::VTYPE_UINT64:        
00507                 case nsIDataType::VTYPE_FLOAT:        
00508                 case nsIDataType::VTYPE_DOUBLE:        
00509                 case nsIDataType::VTYPE_BOOL:        
00510                 case nsIDataType::VTYPE_CHAR:        
00511                 case nsIDataType::VTYPE_WCHAR:        
00512                     conversionType = nsXPTType((uint8)elementType);
00513                     break;
00514 
00515                 case nsIDataType::VTYPE_ID:        
00516                 case nsIDataType::VTYPE_CHAR_STR:        
00517                 case nsIDataType::VTYPE_WCHAR_STR:        
00518                     conversionType = nsXPTType((uint8)elementType | XPT_TDP_POINTER);
00519                     break;
00520 
00521                 case nsIDataType::VTYPE_INTERFACE:        
00522                     pid = &NS_GET_IID(nsISupports);
00523                     conversionType = nsXPTType((uint8)elementType | XPT_TDP_POINTER);
00524                     break;
00525 
00526                 case nsIDataType::VTYPE_INTERFACE_IS:        
00527                     pid = &du.u.array.mArrayInterfaceID;
00528                     conversionType = nsXPTType((uint8)elementType | XPT_TDP_POINTER);
00529                     break;
00530 
00531                 // The rest are illegal.
00532                 case nsIDataType::VTYPE_VOID:        
00533                 case nsIDataType::VTYPE_ASTRING:        
00534                 case nsIDataType::VTYPE_DOMSTRING:        
00535                 case nsIDataType::VTYPE_CSTRING:        
00536                 case nsIDataType::VTYPE_UTF8STRING:        
00537                 case nsIDataType::VTYPE_WSTRING_SIZE_IS:        
00538                 case nsIDataType::VTYPE_STRING_SIZE_IS:        
00539                 case nsIDataType::VTYPE_ARRAY:
00540                 case nsIDataType::VTYPE_EMPTY_ARRAY:
00541                 case nsIDataType::VTYPE_EMPTY:
00542                 default:
00543                     NS_ERROR("bad type in array!");
00544                     goto VARIANT_DONE;
00545             }
00546 
00547             success = 
00548                 XPCConvert::NativeArray2JS(ccx, pJSVal, 
00549                                            (const void**)&du.u.array.mArrayValue,
00550                                            conversionType, pid,
00551                                            du.u.array.mArrayCount, 
00552                                            scope, pErr);
00553 
00554 VARIANT_DONE:                                
00555             nsVariant::Cleanup(&du);
00556             return success;
00557         }        
00558         case nsIDataType::VTYPE_EMPTY_ARRAY: 
00559         {
00560             JSObject* array = JS_NewArrayObject(ccx, 0, nsnull);
00561             if(!array) 
00562                 return JS_FALSE;
00563             *pJSVal = OBJECT_TO_JSVAL(array);
00564             return JS_TRUE;
00565         }
00566         case nsIDataType::VTYPE_VOID:        
00567         case nsIDataType::VTYPE_EMPTY:
00568             *pJSVal = JSVAL_VOID;
00569             return JS_TRUE;
00570         default:
00571             NS_ERROR("bad type in variant!");
00572             return JS_FALSE;
00573     }
00574 
00575     // If we are here then we need to convert the data in the xpctvar.
00576     
00577     if(xpctvar.type.TagPart() == TD_PSTRING_SIZE_IS ||
00578        xpctvar.type.TagPart() == TD_PWSTRING_SIZE_IS)
00579     {
00580         success = XPCConvert::NativeStringWithSize2JS(ccx, pJSVal,
00581                                                       (const void*)&xpctvar.val,
00582                                                       xpctvar.type,
00583                                                       size, pErr);
00584     }
00585     else
00586     {
00587         success = XPCConvert::NativeData2JS(ccx, pJSVal,
00588                                             (const void*)&xpctvar.val,
00589                                             xpctvar.type,
00590                                             &iid, scope, pErr);
00591     }
00592 
00593     if(xpctvar.IsValAllocated())
00594         nsMemory::Free((char*)xpctvar.val.p);
00595     else if(xpctvar.IsValInterface())
00596         ((nsISupports*)xpctvar.val.p)->Release();
00597 
00598     return success;
00599 }
00600 
00601 /***************************************************************************/
00602 /***************************************************************************/
00603 // XXX These default implementations need to be improved to allow for
00604 // some more interesting conversions.
00605 
00606 
00607 /* readonly attribute PRUint16 dataType; */
00608 NS_IMETHODIMP XPCVariant::GetDataType(PRUint16 *aDataType)
00609 {
00610     *aDataType = mData.mType;
00611     return NS_OK;
00612 }
00613 
00614 /* PRUint8 getAsInt8 (); */
00615 NS_IMETHODIMP XPCVariant::GetAsInt8(PRUint8 *_retval)
00616 {
00617     return nsVariant::ConvertToInt8(mData, _retval);
00618 }
00619 
00620 /* PRInt16 getAsInt16 (); */
00621 NS_IMETHODIMP XPCVariant::GetAsInt16(PRInt16 *_retval)
00622 {
00623     return nsVariant::ConvertToInt16(mData, _retval);
00624 }
00625 
00626 /* PRInt32 getAsInt32 (); */
00627 NS_IMETHODIMP XPCVariant::GetAsInt32(PRInt32 *_retval)
00628 {
00629     return nsVariant::ConvertToInt32(mData, _retval);
00630 }
00631 
00632 /* PRInt64 getAsInt64 (); */
00633 NS_IMETHODIMP XPCVariant::GetAsInt64(PRInt64 *_retval)
00634 {
00635     return nsVariant::ConvertToInt64(mData, _retval);
00636 }
00637 
00638 /* PRUint8 getAsUint8 (); */
00639 NS_IMETHODIMP XPCVariant::GetAsUint8(PRUint8 *_retval)
00640 {
00641     return nsVariant::ConvertToUint8(mData, _retval);
00642 }
00643 
00644 /* PRUint16 getAsUint16 (); */
00645 NS_IMETHODIMP XPCVariant::GetAsUint16(PRUint16 *_retval)
00646 {
00647     return nsVariant::ConvertToUint16(mData, _retval);
00648 }
00649 
00650 /* PRUint32 getAsUint32 (); */
00651 NS_IMETHODIMP XPCVariant::GetAsUint32(PRUint32 *_retval)
00652 {
00653     return nsVariant::ConvertToUint32(mData, _retval);
00654 }
00655 
00656 /* PRUint64 getAsUint64 (); */
00657 NS_IMETHODIMP XPCVariant::GetAsUint64(PRUint64 *_retval)
00658 {
00659     return nsVariant::ConvertToUint64(mData, _retval);
00660 }
00661 
00662 /* float getAsFloat (); */
00663 NS_IMETHODIMP XPCVariant::GetAsFloat(float *_retval)
00664 {
00665     return nsVariant::ConvertToFloat(mData, _retval);
00666 }
00667 
00668 /* double getAsDouble (); */
00669 NS_IMETHODIMP XPCVariant::GetAsDouble(double *_retval)
00670 {
00671     return nsVariant::ConvertToDouble(mData, _retval);
00672 }
00673 
00674 /* PRBool getAsBool (); */
00675 NS_IMETHODIMP XPCVariant::GetAsBool(PRBool *_retval)
00676 {
00677     return nsVariant::ConvertToBool(mData, _retval);
00678 }
00679 
00680 /* char getAsChar (); */
00681 NS_IMETHODIMP XPCVariant::GetAsChar(char *_retval)
00682 {
00683     return nsVariant::ConvertToChar(mData, _retval);
00684 }
00685 
00686 /* wchar getAsWChar (); */
00687 NS_IMETHODIMP XPCVariant::GetAsWChar(PRUnichar *_retval)
00688 {
00689     return nsVariant::ConvertToWChar(mData, _retval);
00690 }
00691 
00692 /* [notxpcom] nsresult getAsID (out nsID retval); */
00693 NS_IMETHODIMP_(nsresult) XPCVariant::GetAsID(nsID *retval)
00694 {
00695     return nsVariant::ConvertToID(mData, retval);
00696 }
00697 
00698 /* AString getAsAString (); */
00699 NS_IMETHODIMP XPCVariant::GetAsAString(nsAString & _retval)
00700 {
00701     return nsVariant::ConvertToAString(mData, _retval);
00702 }
00703 
00704 /* DOMString getAsDOMString (); */
00705 NS_IMETHODIMP XPCVariant::GetAsDOMString(nsAString & _retval)
00706 {
00707     // A DOMString maps to an AString internally, so we can re-use
00708     // ConvertToAString here.
00709     return nsVariant::ConvertToAString(mData, _retval);
00710 }
00711 
00712 /* ACString getAsACString (); */
00713 NS_IMETHODIMP XPCVariant::GetAsACString(nsACString & _retval)
00714 {
00715     return nsVariant::ConvertToACString(mData, _retval);
00716 }
00717 
00718 /* AUTF8String getAsAUTF8String (); */
00719 NS_IMETHODIMP XPCVariant::GetAsAUTF8String(nsAUTF8String & _retval)
00720 {
00721     return nsVariant::ConvertToAUTF8String(mData, _retval);
00722 }
00723 
00724 /* string getAsString (); */
00725 NS_IMETHODIMP XPCVariant::GetAsString(char **_retval)
00726 {
00727     return nsVariant::ConvertToString(mData, _retval);
00728 }
00729 
00730 /* wstring getAsWString (); */
00731 NS_IMETHODIMP XPCVariant::GetAsWString(PRUnichar **_retval)
00732 {
00733     return nsVariant::ConvertToWString(mData, _retval);
00734 }
00735 
00736 /* nsISupports getAsISupports (); */
00737 NS_IMETHODIMP XPCVariant::GetAsISupports(nsISupports **_retval)
00738 {
00739     return nsVariant::ConvertToISupports(mData, _retval);
00740 }
00741 
00742 /* void getAsInterface (out nsIIDPtr iid, [iid_is (iid), retval] out nsQIResult iface); */
00743 NS_IMETHODIMP XPCVariant::GetAsInterface(nsIID * *iid, void * *iface)
00744 {
00745     return nsVariant::ConvertToInterface(mData, iid, iface);
00746 }
00747 
00748 
00749 /* [notxpcom] nsresult getAsArray (out PRUint16 type, out nsIID iid, out PRUint32 count, out voidPtr ptr); */
00750 NS_IMETHODIMP_(nsresult) XPCVariant::GetAsArray(PRUint16 *type, nsIID *iid, PRUint32 *count, void * *ptr)
00751 {
00752     return nsVariant::ConvertToArray(mData, type, iid, count, ptr);
00753 }
00754 
00755 /* void getAsStringWithSize (out PRUint32 size, [size_is (size), retval] out string str); */
00756 NS_IMETHODIMP XPCVariant::GetAsStringWithSize(PRUint32 *size, char **str)
00757 {
00758     return nsVariant::ConvertToStringWithSize(mData, size, str);
00759 }
00760 
00761 /* void getAsWStringWithSize (out PRUint32 size, [size_is (size), retval] out wstring str); */
00762 NS_IMETHODIMP XPCVariant::GetAsWStringWithSize(PRUint32 *size, PRUnichar **str)
00763 {
00764     return nsVariant::ConvertToWStringWithSize(mData, size, str);
00765 }
00766 
00767