Back to index

lightning-sunbird  0.9+nobinonly
xpcconvert.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  *   Pierre Phaneuf <pp@ludusdesign.com>
00027  *   Mike Shaver <shaver@mozilla.org>
00028  *
00029  * Alternatively, the contents of this file may be used under the terms of
00030  * either of the GNU General Public License Version 2 or later (the "GPL"),
00031  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00032  * in which case the provisions of the GPL or the LGPL are applicable instead
00033  * of those above. If you wish to allow use of your version of this file only
00034  * under the terms of either the GPL or the LGPL, and not to allow others to
00035  * use your version of this file under the terms of the MPL, indicate your
00036  * decision by deleting the provisions above and replace them with the notice
00037  * and other provisions required by the GPL or the LGPL. If you do not delete
00038  * the provisions above, a recipient may use your version of this file under
00039  * the terms of any one of the MPL, the GPL or the LGPL.
00040  *
00041  * ***** END LICENSE BLOCK ***** */
00042 
00043 /* Data conversion between native and JavaScript types. */
00044 
00045 #include "xpcprivate.h"
00046 #include "nsString.h"
00047 #include "XPCNativeWrapper.h"
00048 
00049 //#define STRICT_CHECK_OF_UNICODE
00050 #ifdef STRICT_CHECK_OF_UNICODE
00051 #define ILLEGAL_RANGE(c) (0!=((c) & 0xFF80))
00052 #else // STRICT_CHECK_OF_UNICODE
00053 #define ILLEGAL_RANGE(c) (0!=((c) & 0xFF00))
00054 #endif // STRICT_CHECK_OF_UNICODE
00055 
00056 #define ILLEGAL_CHAR_RANGE(c) (0!=((c) & 0x80))
00057 /*
00058 * This is a table driven scheme to determine if the types of the params of the
00059 * given method exclude that method from being reflected via XPConnect.
00060 *
00061 * The table can be appended and modified as requirements change. However...
00062 *
00063 * The table ASSUMES that all the type idenetifiers are contiguous starting
00064 * at ZERO. And, it also ASSUMES that the additional criteria of whether or
00065 * not a give type is reflectable are its use as a pointer and/or 'out' type.
00066 *
00067 * The table has a row for each type and columns for the combinations of
00068 * that type being used as a pointer type and/or as an 'out' param.
00069 */
00070 
00071 #define XPC_MK_BIT(p,o) (1 << (((p)?1:0)+((o)?2:0)))
00072 #define XPC_IS_REFLECTABLE(f, p, o) ((f) & XPC_MK_BIT((p),(o)))
00073 #define XPC_MK_FLAG(np_no,p_no,np_o,p_o) \
00074         ((uint8)((np_no) | ((p_no) << 1) | ((np_o) << 2) | ((p_o) << 3)))
00075 
00076 /***********************************************************/
00077 // xpt uses 5 bits for this info. We deal with the possibility that
00078 // some new types might exist that we don't know about.
00079 
00080 #define XPC_FLAG_COUNT (1 << 5)
00081 
00082 /* '1' means 'reflectable'. '0' means 'not reflectable'.        */
00083 static uint8 xpc_reflectable_flags[XPC_FLAG_COUNT] = {
00084     /* 'p' stands for 'pointer' and 'o' stands for 'out'        */
00085     /*          !p&!o, p&!o, !p&o, p&o                          */
00086     XPC_MK_FLAG(  1  ,  1  ,   1 ,  0 ), /* T_I8                */
00087     XPC_MK_FLAG(  1  ,  1  ,   1 ,  0 ), /* T_I16               */
00088     XPC_MK_FLAG(  1  ,  1  ,   1 ,  0 ), /* T_I32               */
00089     XPC_MK_FLAG(  1  ,  1  ,   1 ,  0 ), /* T_I64               */
00090     XPC_MK_FLAG(  1  ,  1  ,   1 ,  0 ), /* T_U8                */
00091     XPC_MK_FLAG(  1  ,  1  ,   1 ,  0 ), /* T_U16               */
00092     XPC_MK_FLAG(  1  ,  1  ,   1 ,  0 ), /* T_U32               */
00093     XPC_MK_FLAG(  1  ,  1  ,   1 ,  0 ), /* T_U64               */
00094     XPC_MK_FLAG(  1  ,  1  ,   1 ,  0 ), /* T_FLOAT             */
00095     XPC_MK_FLAG(  1  ,  1  ,   1 ,  0 ), /* T_DOUBLE            */
00096     XPC_MK_FLAG(  1  ,  1  ,   1 ,  0 ), /* T_BOOL              */
00097     XPC_MK_FLAG(  1  ,  1  ,   1 ,  0 ), /* T_CHAR              */
00098     XPC_MK_FLAG(  1  ,  1  ,   1 ,  0 ), /* T_WCHAR             */
00099     XPC_MK_FLAG(  0  ,  0  ,   0 ,  0 ), /* T_VOID              */
00100     XPC_MK_FLAG(  0  ,  1  ,   0 ,  1 ), /* T_IID               */
00101     XPC_MK_FLAG(  0  ,  1  ,   0 ,  0 ), /* T_DOMSTRING         */
00102     XPC_MK_FLAG(  0  ,  1  ,   0 ,  1 ), /* T_CHAR_STR          */
00103     XPC_MK_FLAG(  0  ,  1  ,   0 ,  1 ), /* T_WCHAR_STR         */
00104     XPC_MK_FLAG(  0  ,  1  ,   0 ,  1 ), /* T_INTERFACE         */
00105     XPC_MK_FLAG(  0  ,  1  ,   0 ,  1 ), /* T_INTERFACE_IS      */
00106     XPC_MK_FLAG(  0  ,  1  ,   0 ,  1 ), /* T_ARRAY             */
00107     XPC_MK_FLAG(  0  ,  1  ,   0 ,  1 ), /* T_PSTRING_SIZE_IS   */
00108     XPC_MK_FLAG(  0  ,  1  ,   0 ,  1 ), /* T_PWSTRING_SIZE_IS  */
00109     XPC_MK_FLAG(  0  ,  1  ,   0 ,  0 ), /* T_UTF8STRING        */
00110     XPC_MK_FLAG(  0  ,  1  ,   0 ,  0 ), /* T_CSTRING           */
00111     XPC_MK_FLAG(  0  ,  1  ,   0 ,  0 ), /* T_ASTRING           */
00112     XPC_MK_FLAG(  0  ,  0  ,   0 ,  0 ), /* 26 - reserved       */
00113     XPC_MK_FLAG(  0  ,  0  ,   0 ,  0 ), /* 27 - reserved       */
00114     XPC_MK_FLAG(  0  ,  0  ,   0 ,  0 ), /* 28 - reserved       */
00115     XPC_MK_FLAG(  0  ,  0  ,   0 ,  0 ), /* 29 - reserved       */
00116     XPC_MK_FLAG(  0  ,  0  ,   0 ,  0 ), /* 30 - reserved       */
00117     XPC_MK_FLAG(  0  ,  0  ,   0 ,  0 )  /* 31 - reserved       */
00118     };
00119 
00120 static intN sXPCOMUCStringFinalizerIndex = -1;
00121 
00122 /***********************************************************/
00123 
00124 // static
00125 JSBool
00126 XPCConvert::IsMethodReflectable(const nsXPTMethodInfo& info)
00127 {
00128     if(info.IsNotXPCOM() || info.IsHidden())
00129         return JS_FALSE;
00130 
00131     for(int i = info.GetParamCount()-1; i >= 0; i--)
00132     {
00133         const nsXPTParamInfo& param = info.GetParam(i);
00134         const nsXPTType& type = param.GetType();
00135 
00136         uint8 base_type = type.TagPart();
00137         NS_ASSERTION(base_type < XPC_FLAG_COUNT, "BAD TYPE");
00138 
00139         if(!XPC_IS_REFLECTABLE(xpc_reflectable_flags[base_type],
00140                                type.IsPointer(), param.IsOut()))
00141             return JS_FALSE;
00142     }
00143     return JS_TRUE;
00144 }
00145 
00146 /***************************************************************************/
00147 
00148 static JSBool
00149 GetISupportsFromJSObject(JSContext* cx, JSObject* obj, nsISupports** iface)
00150 {
00151     JSClass* jsclass = JS_GET_CLASS(cx, obj);
00152     NS_ASSERTION(jsclass, "obj has no class");
00153     if(jsclass &&
00154        (jsclass->flags & JSCLASS_HAS_PRIVATE) &&
00155        (jsclass->flags & JSCLASS_PRIVATE_IS_NSISUPPORTS))
00156     {
00157         *iface = (nsISupports*) JS_GetPrivate(cx, obj);
00158         return JS_TRUE;
00159     }
00160     return JS_FALSE;
00161 }
00162 
00163 /***************************************************************************/
00164 
00165 /*
00166 * Support for 64 bit conversions where 'long long' not supported.
00167 * (from John Fairhurst <mjf35@cam.ac.uk>)
00168 */
00169 
00170 #ifdef HAVE_LONG_LONG
00171 
00172 #define JAM_DOUBLE(cx,v,d) (d = JS_NewDouble(cx, (jsdouble)v) , \
00173                             d ? DOUBLE_TO_JSVAL(d) : JSVAL_ZERO)
00174 // Win32 can't handle uint64 to double conversion
00175 #define JAM_DOUBLE_U64(cx,v,d) JAM_DOUBLE(cx,((int64)v),d)
00176 
00177 #else
00178 
00179 inline jsval
00180 JAM_DOUBLE(JSContext *cx, const int64 &v, jsdouble *dbl)
00181 {
00182     jsdouble d;
00183     LL_L2D(d, v);
00184     dbl = JS_NewDouble(cx, d);
00185     if(!dbl)
00186         return JSVAL_ZERO;
00187     return DOUBLE_TO_JSVAL(dbl);
00188 }
00189 
00190 inline jsval
00191 JAM_DOUBLE(JSContext *cx, double v, jsdouble *dbl)
00192 {
00193     dbl = JS_NewDouble(cx, (jsdouble)v);
00194     if(!dbl)
00195         return JSVAL_ZERO;
00196     return DOUBLE_TO_JSVAL(dbl);
00197 }
00198 
00199 // if !HAVE_LONG_LONG, then uint64 is a typedef of int64
00200 #define JAM_DOUBLE_U64(cx,v,d) JAM_DOUBLE(cx,v,d)
00201 
00202 #endif
00203 
00204 #define FIT_32(cx,i,d) (INT_FITS_IN_JSVAL(i) ? \
00205                         INT_TO_JSVAL(i) : JAM_DOUBLE(cx,i,d))
00206 
00207 // XXX will this break backwards compatability???
00208 #define FIT_U32(cx,i,d) ((i) <= JSVAL_INT_MAX ? \
00209                          INT_TO_JSVAL(i) : JAM_DOUBLE(cx,i,d))
00210 
00211 JS_STATIC_DLL_CALLBACK(void)
00212 FinalizeXPCOMUCString(JSContext *cx, JSString *str)
00213 {
00214     NS_ASSERTION(sXPCOMUCStringFinalizerIndex != -1,
00215                  "XPCConvert: XPCOM Unicode string finalizer called uninitialized!");
00216 
00217     jschar* buffer = JS_GetStringChars(str);
00218     nsMemory::Free(buffer);
00219 }
00220 
00221 
00222 static JSBool
00223 AddXPCOMUCStringFinalizer()
00224 {
00225 
00226     sXPCOMUCStringFinalizerIndex =
00227         JS_AddExternalStringFinalizer(FinalizeXPCOMUCString);
00228 
00229     if(sXPCOMUCStringFinalizerIndex == -1)
00230     {        
00231         return JS_FALSE;
00232     }
00233 
00234     return JS_TRUE;
00235 }
00236 
00237 //static
00238 void
00239 XPCConvert::RemoveXPCOMUCStringFinalizer()
00240 {
00241     JS_RemoveExternalStringFinalizer(FinalizeXPCOMUCString);
00242     sXPCOMUCStringFinalizerIndex = -1;
00243 }
00244 
00245 // static
00246 JSBool
00247 XPCConvert::NativeData2JS(XPCCallContext& ccx, jsval* d, const void* s,
00248                           const nsXPTType& type, const nsID* iid,
00249                           JSObject* scope, nsresult* pErr)
00250 {
00251     NS_PRECONDITION(s, "bad param");
00252     NS_PRECONDITION(d, "bad param");
00253 
00254     JSContext* cx = ccx.GetJSContext();
00255 
00256     jsdouble* dbl = nsnull;
00257 
00258     if(pErr)
00259         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
00260 
00261     switch(type.TagPart())
00262     {
00263     case nsXPTType::T_I8    : *d = INT_TO_JSVAL((int32)*((int8*)s));     break;
00264     case nsXPTType::T_I16   : *d = INT_TO_JSVAL((int32)*((int16*)s));    break;
00265     case nsXPTType::T_I32   : *d = FIT_32(cx,*((int32*)s),dbl);          break;
00266     case nsXPTType::T_I64   : *d = JAM_DOUBLE(cx,*((int64*)s),dbl);      break;
00267     case nsXPTType::T_U8    : *d = INT_TO_JSVAL((int32)*((uint8*)s));    break;
00268     case nsXPTType::T_U16   : *d = INT_TO_JSVAL((int32)*((uint16*)s));   break;
00269     case nsXPTType::T_U32   : *d = FIT_U32(cx,*((uint32*)s),dbl);        break;
00270     case nsXPTType::T_U64   : *d = JAM_DOUBLE_U64(cx,*((uint64*)s),dbl); break;
00271     case nsXPTType::T_FLOAT : *d = JAM_DOUBLE(cx,*((float*)s),dbl);      break;
00272     case nsXPTType::T_DOUBLE: *d = JAM_DOUBLE(cx,*((double*)s),dbl);     break;
00273     case nsXPTType::T_BOOL  : *d = *((PRBool*)s)?JSVAL_TRUE:JSVAL_FALSE; break;
00274     case nsXPTType::T_CHAR  :
00275         {
00276             char* p = (char*)s;
00277             if(!p)
00278                 return JS_FALSE;
00279 
00280 #ifdef STRICT_CHECK_OF_UNICODE
00281             NS_ASSERTION(! ILLEGAL_CHAR_RANGE(p) , "passing non ASCII data");
00282 #endif // STRICT_CHECK_OF_UNICODE
00283 
00284             JSString* str;
00285             if(!(str = JS_NewStringCopyN(cx, p, 1)))
00286                 return JS_FALSE;
00287             *d = STRING_TO_JSVAL(str);
00288             break;
00289         }
00290     case nsXPTType::T_WCHAR :
00291         {
00292             jschar* p = (jschar*)s;
00293             if(!p)
00294                 return JS_FALSE;
00295             JSString* str;
00296             if(!(str = JS_NewUCStringCopyN(cx, p, 1)))
00297                 return JS_FALSE;
00298             *d = STRING_TO_JSVAL(str);
00299             break;
00300         }
00301     default:
00302         if(!type.IsPointer())
00303         {
00304             XPC_LOG_ERROR(("XPCConvert::NativeData2JS : unsupported type"));
00305             return JS_FALSE;
00306         }
00307 
00308         // set the default result
00309         *d = JSVAL_NULL;
00310 
00311         switch(type.TagPart())
00312         {
00313         case nsXPTType::T_VOID:
00314             XPC_LOG_ERROR(("XPCConvert::NativeData2JS : void* params not supported"));
00315             return JS_FALSE;
00316 
00317         case nsXPTType::T_IID:
00318             {
00319                 nsID* iid2 = *((nsID**)s);
00320                 if(!iid2)
00321                     break;
00322                 JSObject* obj;
00323                 if(!(obj = xpc_NewIDObject(cx, scope, *iid2)))
00324                     return JS_FALSE;
00325                 *d = OBJECT_TO_JSVAL(obj);
00326                 break;
00327             }
00328 
00329         case nsXPTType::T_ASTRING:
00330             // Fall through to T_DOMSTRING case
00331 
00332         case nsXPTType::T_DOMSTRING:
00333             {
00334                 const nsAString* p = *((const nsAString**)s);
00335                 if(!p)
00336                     break;
00337 
00338                 if(!p->IsVoid()) {
00339                     JSString *str =
00340                         XPCStringConvert::ReadableToJSString(cx, *p);
00341                     if(!str)
00342                         return JS_FALSE;
00343 
00344                     *d = STRING_TO_JSVAL(str);
00345                 }
00346 
00347                 // *d is defaulted to JSVAL_NULL so no need to set it
00348                 // again if p is a "void" string
00349 
00350                 break;
00351             }
00352 
00353         case nsXPTType::T_CHAR_STR:
00354             {
00355                 char* p = *((char**)s);
00356                 if(!p)
00357                     break;
00358 
00359 #ifdef STRICT_CHECK_OF_UNICODE
00360                 PRBool isAscii = PR_TRUE;
00361                 char* t;
00362                 for(t=p; *t && isAscii ; t++) {
00363                   if(ILLEGAL_CHAR_RANGE(*t))
00364                       isAscii = PR_FALSE;
00365                 }
00366                 NS_ASSERTION(isAscii, "passing non ASCII data");
00367 #endif // STRICT_CHECK_OF_UNICODE
00368                 JSString* str;
00369                 if(!(str = JS_NewStringCopyZ(cx, p)))
00370                     return JS_FALSE;
00371                 *d = STRING_TO_JSVAL(str);
00372                 break;
00373             }
00374 
00375         case nsXPTType::T_WCHAR_STR:
00376             {
00377                 jschar* p = *((jschar**)s);
00378                 if(!p)
00379                     break;
00380                 JSString* str;
00381                 if(!(str = JS_NewUCStringCopyZ(cx, p)))
00382                     return JS_FALSE;
00383                 *d = STRING_TO_JSVAL(str);
00384                 break;
00385             }
00386         case nsXPTType::T_UTF8STRING:
00387             {                          
00388                 const nsACString* cString = *((const nsACString**)s);
00389 
00390                 if(!cString)
00391                     break;
00392                 
00393                 if(!cString->IsVoid()) 
00394                 {
00395                     PRUint32 len;
00396                     jschar *p = (jschar *)UTF8ToNewUnicode(*cString, &len);
00397 
00398                     if(!p)
00399                         return JS_FALSE;
00400 
00401                     JSString* jsString = JS_NewUCString(cx, p, len);
00402 
00403                     if(!jsString) {
00404                         nsMemory::Free(p); 
00405                         return JS_FALSE; 
00406                     }
00407 
00408                     *d = STRING_TO_JSVAL(jsString);
00409                 }
00410 
00411                 break;
00412 
00413             }
00414         case nsXPTType::T_CSTRING:
00415             {                          
00416                 const nsACString* cString = *((const nsACString**)s);
00417 
00418                 if(!cString)
00419                     break;
00420                 
00421                 if(!cString->IsVoid()) 
00422                 {
00423                     PRUnichar* unicodeString = ToNewUnicode(*cString);
00424                     if(!unicodeString)
00425                         return JS_FALSE;
00426 
00427                     if(sXPCOMUCStringFinalizerIndex == -1 && 
00428                        !AddXPCOMUCStringFinalizer())
00429                         return JS_FALSE;
00430 
00431                     JSString* jsString = JS_NewExternalString(cx,
00432                                              (jschar*)unicodeString,
00433                                              cString->Length(),
00434                                              sXPCOMUCStringFinalizerIndex);
00435 
00436                     if(!jsString)
00437                     {
00438                         nsMemory::Free(unicodeString);
00439                         return JS_FALSE;
00440                     }
00441 
00442                     *d = STRING_TO_JSVAL(jsString);
00443                 }
00444 
00445                 break;
00446             }
00447 
00448         case nsXPTType::T_INTERFACE:
00449         case nsXPTType::T_INTERFACE_IS:
00450             {
00451                 nsISupports* iface = *((nsISupports**)s);
00452                 if(iface)
00453                 {
00454                     if(iid->Equals(NS_GET_IID(nsIVariant)))
00455                     {
00456                         nsCOMPtr<nsIVariant> variant = do_QueryInterface(iface);
00457                         if(!variant)
00458                             return JS_FALSE;
00459 
00460                         return XPCVariant::VariantDataToJS(ccx, variant, 
00461                                                            scope, pErr, d);
00462                     }
00463                     // else...
00464                     
00465                     // XXX The OBJ_IS_NOT_GLOBAL here is not really right. In
00466                     // fact, this code is depending on the fact that the
00467                     // global object will not have been collected, and
00468                     // therefore this NativeInterface2JSObject will not end up
00469                     // creating a new XPCNativeScriptableShared.
00470                     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
00471                     if(!NativeInterface2JSObject(ccx, getter_AddRefs(holder),
00472                                                  iface, iid, scope, PR_TRUE,
00473                                                  OBJ_IS_NOT_GLOBAL, pErr))
00474                         return JS_FALSE;
00475 
00476                     if(holder)
00477                     {
00478                         JSObject* jsobj;
00479                         if(NS_FAILED(holder->GetJSObject(&jsobj)))
00480                             return JS_FALSE;
00481 #ifdef DEBUG
00482                         if(!JS_GetParent(ccx, jsobj))
00483                             NS_ASSERTION(JS_GET_CLASS(ccx, jsobj)->flags & JSCLASS_IS_GLOBAL,
00484                                          "Why did we recreate this wrapper?");
00485 #endif
00486                         *d = OBJECT_TO_JSVAL(jsobj);
00487                     }
00488                 }
00489                 break;
00490             }
00491         default:
00492             NS_ASSERTION(0, "bad type");
00493             return JS_FALSE;
00494         }
00495     }
00496     return JS_TRUE;
00497 }
00498 
00499 /***************************************************************************/
00500 
00501 // static
00502 JSBool
00503 XPCConvert::JSData2Native(XPCCallContext& ccx, void* d, jsval s,
00504                           const nsXPTType& type,
00505                           JSBool useAllocator, const nsID* iid,
00506                           nsresult* pErr)
00507 {
00508     NS_PRECONDITION(d, "bad param");
00509 
00510     JSContext* cx = ccx.GetJSContext();
00511 
00512     int32    ti;
00513     uint32   tu;
00514     jsdouble td;
00515     JSBool isDOMString = JS_TRUE;
00516 
00517     if(pErr)
00518         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
00519 
00520     switch(type.TagPart())
00521     {
00522     case nsXPTType::T_I8     :
00523         if(!JS_ValueToECMAInt32(cx, s, &ti))
00524             return JS_FALSE;
00525         *((int8*)d)  = (int8) ti;
00526         break;
00527     case nsXPTType::T_I16    :
00528         if(!JS_ValueToECMAInt32(cx, s, &ti))
00529             return JS_FALSE;
00530         *((int16*)d)  = (int16) ti;
00531         break;
00532     case nsXPTType::T_I32    :
00533         if(!JS_ValueToECMAInt32(cx, s, (int32*)d))
00534             return JS_FALSE;
00535         break;
00536     case nsXPTType::T_I64    :
00537         if(JSVAL_IS_INT(s))
00538         {
00539             if(!JS_ValueToECMAInt32(cx, s, &ti))
00540                 return JS_FALSE;
00541             LL_I2L(*((int64*)d),ti);
00542 
00543         }
00544         else
00545         {
00546             if(!JS_ValueToNumber(cx, s, &td))
00547                 return JS_FALSE;
00548             LL_D2L(*((int64*)d),td);
00549         }
00550         break;
00551     case nsXPTType::T_U8     :
00552         if(!JS_ValueToECMAUint32(cx, s, &tu))
00553             return JS_FALSE;
00554         *((uint8*)d)  = (uint8) tu;
00555         break;
00556     case nsXPTType::T_U16    :
00557         if(!JS_ValueToECMAUint32(cx, s, &tu))
00558             return JS_FALSE;
00559         *((uint16*)d)  = (uint16) tu;
00560         break;
00561     case nsXPTType::T_U32    :
00562         if(!JS_ValueToECMAUint32(cx, s, (uint32*)d))
00563             return JS_FALSE;
00564         break;
00565     case nsXPTType::T_U64    :
00566         if(JSVAL_IS_INT(s))
00567         {
00568             if(!JS_ValueToECMAUint32(cx, s, &tu))
00569                 return JS_FALSE;
00570             LL_UI2L(*((int64*)d),tu);
00571         }
00572         else
00573         {
00574             if(!JS_ValueToNumber(cx, s, &td))
00575                 return JS_FALSE;
00576 #ifdef XP_WIN
00577             // Note: Win32 can't handle double to uint64 directly
00578             *((uint64*)d) = (uint64)((int64) td);
00579 #else
00580             LL_D2L(*((uint64*)d),td);
00581 #endif
00582         }
00583         break;
00584     case nsXPTType::T_FLOAT  :
00585         if(!JS_ValueToNumber(cx, s, &td))
00586             return JS_FALSE;
00587         *((float*)d) = (float) td;
00588         break;
00589     case nsXPTType::T_DOUBLE :
00590         if(!JS_ValueToNumber(cx, s, (double*)d))
00591             return JS_FALSE;
00592         break;
00593     case nsXPTType::T_BOOL   :
00594         if(!JS_ValueToBoolean(cx, s, (JSBool*)d))
00595             return JS_FALSE;
00596         break;
00597     case nsXPTType::T_CHAR   :
00598         {
00599             char* bytes=nsnull;
00600             JSString* str;
00601 
00602             if(!(str = JS_ValueToString(cx, s))||
00603                !(bytes = JS_GetStringBytes(str)))
00604             {
00605                 return JS_FALSE;
00606             }
00607 #ifdef DEBUG
00608             jschar* chars=nsnull;
00609             if(nsnull!=(chars = JS_GetStringChars(str)))
00610             {
00611                 NS_ASSERTION((! ILLEGAL_RANGE(chars[0])),"U+0080/U+0100 - U+FFFF data lost");
00612             }
00613 #endif // DEBUG
00614             *((char*)d) = bytes[0];
00615             break;
00616         }
00617     case nsXPTType::T_WCHAR  :
00618         {
00619             jschar* chars=nsnull;
00620             JSString* str;
00621             if(!(str = JS_ValueToString(cx, s))||
00622                !(chars = JS_GetStringChars(str)))
00623             {
00624                 return JS_FALSE;
00625             }
00626             *((uint16*)d)  = (uint16) chars[0];
00627             break;
00628         }
00629     default:
00630         if(!type.IsPointer())
00631         {
00632             NS_ASSERTION(0,"unsupported type");
00633             return JS_FALSE;
00634         }
00635 
00636         switch(type.TagPart())
00637         {
00638         case nsXPTType::T_VOID:
00639             XPC_LOG_ERROR(("XPCConvert::JSData2Native : void* params not supported"));
00640             NS_ASSERTION(0,"void* params not supported");
00641             return JS_FALSE;
00642         case nsXPTType::T_IID:
00643         {
00644             NS_ASSERTION(useAllocator,"trying to convert a JSID to nsID without allocator : this would leak");
00645 
00646             JSObject* obj;
00647             const nsID* pid=nsnull;
00648 
00649             if(JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s))
00650             {
00651                 if(type.IsReference())
00652                 {
00653                     if(pErr)
00654                         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_NULL_REF;
00655                     return JS_FALSE;
00656                 }
00657                 // else ...
00658                 *((const nsID**)d) = nsnull;
00659                 return JS_TRUE;
00660             }
00661 
00662             if(!JSVAL_IS_OBJECT(s) ||
00663                (!(obj = JSVAL_TO_OBJECT(s))) ||
00664                (!(pid = xpc_JSObjectToID(cx, obj))))
00665             {
00666                 return JS_FALSE;
00667             }
00668             *((const nsID**)d) = pid;
00669             return JS_TRUE;
00670         }
00671 
00672         case nsXPTType::T_ASTRING:        
00673         {            
00674             isDOMString = JS_FALSE;
00675             // Fall through to T_DOMSTRING case.
00676         }
00677         case nsXPTType::T_DOMSTRING:
00678         {
00679             static const PRUnichar EMPTY_STRING[] = { '\0' };
00680             static const PRUnichar VOID_STRING[] = { 'u', 'n', 'd', 'e', 'f', 'i', 'n', 'e', 'd', '\0' };
00681 
00682             const PRUnichar* chars;
00683             JSString* str = nsnull;
00684             JSBool isNewString = JS_FALSE;
00685             PRUint32 length;
00686 
00687             if(JSVAL_IS_VOID(s))
00688             {
00689                 if(isDOMString) 
00690                 {
00691                     chars  = VOID_STRING;
00692                     length = NS_ARRAY_LENGTH(VOID_STRING) - 1;
00693                 }
00694                 else
00695                 {
00696                     chars = EMPTY_STRING;
00697                     length = 0;
00698                 }
00699             }
00700             else if(!JSVAL_IS_NULL(s))
00701             {
00702                 str = JS_ValueToString(cx, s);
00703                 if(!str)
00704                     return JS_FALSE;
00705 
00706                 length = (PRUint32) JS_GetStringLength(str);
00707                 if(length)
00708                 {
00709                     chars = (const PRUnichar*) JS_GetStringChars(str);
00710                     if(!chars)
00711                         return JS_FALSE;
00712                     if(STRING_TO_JSVAL(str) != s)
00713                         isNewString = JS_TRUE;
00714                 }
00715                 else
00716                 {
00717                     str = nsnull;
00718                     chars = EMPTY_STRING;
00719                 }
00720             }
00721 
00722             if(useAllocator)
00723             {
00724                 // XXX extra string copy when isNewString
00725                 if(str && !isNewString)
00726                 {
00727                     XPCReadableJSStringWrapper *wrapper =
00728                         XPCStringConvert::JSStringToReadable(str);
00729                     if(!wrapper)
00730                         return JS_FALSE;
00731 
00732                     *((const nsAString**)d) = wrapper;
00733                 }
00734                 else if(JSVAL_IS_NULL(s))
00735                 {
00736                     XPCReadableJSStringWrapper *wrapper =
00737                         new XPCReadableJSStringWrapper();
00738                     if(!wrapper)
00739                         return JS_FALSE;
00740 
00741                     *((const nsAString**)d) = wrapper;
00742                 }
00743                 else
00744                 {
00745                     // use nsString to encourage sharing
00746                     const nsAString *rs = new nsString(chars, length);
00747                     if(!rs)
00748                         return JS_FALSE;
00749                     *((const nsAString**)d) = rs;
00750                 }
00751             }
00752             else
00753             {
00754                 nsAString* ws = *((nsAString**)d);
00755 
00756                 if(JSVAL_IS_NULL(s) || (!isDOMString && JSVAL_IS_VOID(s)))
00757                 {
00758                     ws->Truncate();
00759                     ws->SetIsVoid(PR_TRUE);
00760                 }
00761                 else
00762                     ws->Assign(chars, length);
00763             }
00764             return JS_TRUE;
00765         }
00766 
00767         case nsXPTType::T_CHAR_STR:
00768         {
00769             char* bytes=nsnull;
00770             JSString* str;
00771 
00772             if(JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s))
00773             {
00774                 if(type.IsReference())
00775                 {
00776                     if(pErr)
00777                         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_NULL_REF;
00778                     return JS_FALSE;
00779                 }
00780                 // else ...
00781                 *((char**)d) = nsnull;
00782                 return JS_TRUE;
00783             }
00784 
00785             if(!(str = JS_ValueToString(cx, s))||
00786                !(bytes = JS_GetStringBytes(str)))
00787             {
00788                 return JS_FALSE;
00789             }
00790 #ifdef DEBUG
00791             jschar* chars=nsnull;
00792             if(nsnull != (chars = JS_GetStringChars(str)))
00793             {
00794                 PRBool legalRange = PR_TRUE;
00795                 int len = JS_GetStringLength(str);
00796                 jschar* t;
00797                 PRInt32 i=0;
00798                 for(t=chars; (i< len) && legalRange ; i++,t++) {
00799                   if(ILLEGAL_RANGE(*t))
00800                       legalRange = PR_FALSE;
00801                 }
00802                 NS_ASSERTION(legalRange,"U+0080/U+0100 - U+FFFF data lost");
00803             }
00804 #endif // DEBUG
00805             if(useAllocator)
00806             {
00807                 int len = (JS_GetStringLength(str) + 1) * sizeof(char);
00808                 if(!(*((void**)d) = nsMemory::Alloc(len)))
00809                 {
00810                     return JS_FALSE;
00811                 }
00812                 memcpy(*((void**)d), bytes, len);
00813             }
00814             else
00815                 *((char**)d) = bytes;
00816 
00817             return JS_TRUE;
00818         }
00819 
00820         case nsXPTType::T_WCHAR_STR:
00821         {
00822             jschar* chars=nsnull;
00823             JSString* str;
00824 
00825             if(JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s))
00826             {
00827                 if(type.IsReference())
00828                 {
00829                     if(pErr)
00830                         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_NULL_REF;
00831                     return JS_FALSE;
00832                 }
00833                 // else ...
00834                 *((jschar**)d) = nsnull;
00835                 return JS_TRUE;
00836             }
00837 
00838             if(!(str = JS_ValueToString(cx, s))||
00839                !(chars = JS_GetStringChars(str)))
00840             {
00841                 return JS_FALSE;
00842             }
00843             if(useAllocator)
00844             {
00845                 int byte_len = (JS_GetStringLength(str)+1)*sizeof(jschar);
00846                 if(!(*((void**)d) = nsMemory::Alloc(byte_len)))
00847                 {
00848                     // XXX should report error
00849                     return JS_FALSE;
00850                 }
00851                 memcpy(*((void**)d), chars, byte_len);
00852             }
00853             else
00854                 *((jschar**)d) = chars;
00855 
00856             return JS_TRUE;
00857         }
00858 
00859         case nsXPTType::T_UTF8STRING:            
00860         {
00861             jschar* chars;
00862             PRUint32 length;
00863             JSString* str;
00864 
00865             if(JSVAL_IS_NULL(s) || JSVAL_IS_VOID(s))
00866             {
00867                 if(useAllocator) 
00868                 {
00869                     nsACString *rs = new nsCString();
00870                     if(!rs) 
00871                         return JS_FALSE;
00872 
00873                     rs->SetIsVoid(PR_TRUE);
00874                     *((nsACString**)d) = rs;
00875                 }
00876                 else
00877                 {
00878                     nsCString* rs = *((nsCString**)d);
00879                     rs->Truncate();
00880                     rs->SetIsVoid(PR_TRUE);
00881                 }
00882                 return JS_TRUE;
00883             }
00884 
00885             // The JS val is neither null nor void...
00886 
00887             if(!(str = JS_ValueToString(cx, s))||
00888                !(chars = JS_GetStringChars(str)))
00889             {
00890                 return JS_FALSE;
00891             }
00892 
00893             length = JS_GetStringLength(str);
00894 
00895             nsCString *rs;
00896             if(useAllocator)
00897             {                
00898                 // Use nsCString to enable sharing
00899                 rs = new nsCString();
00900                 if(!rs)
00901                     return JS_FALSE;
00902 
00903                 *((const nsCString**)d) = rs;
00904             }
00905             else
00906             {
00907                 rs = *((nsCString**)d);
00908             }
00909             CopyUTF16toUTF8(nsDependentString((const PRUnichar*)chars, length),
00910                             *rs);
00911             return JS_TRUE;
00912         }
00913 
00914         case nsXPTType::T_CSTRING:
00915         {
00916             const char* chars;            
00917             PRUint32 length;
00918             JSString* str;
00919 
00920             if(JSVAL_IS_NULL(s) || JSVAL_IS_VOID(s))
00921             {
00922                 if(useAllocator)
00923                 {
00924                     nsACString *rs = new nsCString();
00925                     if(!rs) 
00926                         return JS_FALSE;
00927 
00928                     rs->SetIsVoid(PR_TRUE);
00929                     *((nsACString**)d) = rs;
00930                 }
00931                 else
00932                 {
00933                     nsACString* rs = *((nsACString**)d);
00934                     rs->Truncate();
00935                     rs->SetIsVoid(PR_TRUE);
00936                 }
00937                 return JS_TRUE;
00938             }
00939 
00940             // The JS val is neither null nor void...
00941 
00942             if(!(str = JS_ValueToString(cx, s)) ||
00943                !(chars = JS_GetStringBytes(str)))
00944             {
00945                 return JS_FALSE;
00946             }
00947 
00948             length = JS_GetStringLength(str);
00949 
00950             if(useAllocator)
00951             {
00952                 const nsACString *rs = new nsCString(chars, length);
00953 
00954                 if(!rs)
00955                     return JS_FALSE;
00956 
00957                 *((const nsACString**)d) = rs;
00958             }
00959             else
00960             {
00961                 nsACString* rs = *((nsACString**)d);
00962 
00963                 rs->Assign(nsDependentCString(chars, length));
00964             }
00965             return JS_TRUE;
00966         }
00967 
00968         case nsXPTType::T_INTERFACE:
00969         case nsXPTType::T_INTERFACE_IS:
00970         {
00971             JSObject* obj;
00972             NS_ASSERTION(iid,"can't do interface conversions without iid");
00973 
00974             if(iid->Equals(NS_GET_IID(nsIVariant)))
00975             {
00976                 XPCVariant* variant = XPCVariant::newVariant(ccx, s);
00977                 if(!variant)
00978                     return JS_FALSE;
00979                 *((nsISupports**)d) = NS_STATIC_CAST(nsIVariant*, variant);
00980                 return JS_TRUE;
00981             }
00982             //else ...
00983 
00984             if(JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s))
00985             {
00986                 if(type.IsReference())
00987                 {
00988                     if(pErr)
00989                         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_NULL_REF;
00990                     return JS_FALSE;
00991                 }
00992                 // else ...
00993                 *((nsISupports**)d) = nsnull;
00994                 return JS_TRUE;
00995             }
00996 
00997             // only wrap JSObjects
00998             if(!JSVAL_IS_OBJECT(s) || !(obj = JSVAL_TO_OBJECT(s)))
00999             {
01000                 if(pErr && JSVAL_IS_INT(s) && 0 == JSVAL_TO_INT(s))
01001                     *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_ZERO_ISNOT_NULL;
01002                 return JS_FALSE;
01003             }
01004 
01005             return JSObject2NativeInterface(ccx, (void**)d, obj, iid,
01006                                             nsnull, pErr);
01007         }
01008         default:
01009             NS_ASSERTION(0, "bad type");
01010             return JS_FALSE;
01011         }
01012     }
01013     return JS_TRUE;
01014 }
01015 
01016 /***************************************************************************/
01017 // static
01018 JSBool
01019 XPCConvert::NativeInterface2JSObject(XPCCallContext& ccx,
01020                                      nsIXPConnectJSObjectHolder** dest,
01021                                      nsISupports* src,
01022                                      const nsID* iid,
01023                                      JSObject* scope,
01024                                      PRBool allowNativeWrapper,
01025                                      PRBool isGlobal,
01026                                      nsresult* pErr)
01027 {
01028     NS_ASSERTION(dest, "bad param");
01029     NS_ASSERTION(iid, "bad param");
01030     NS_ASSERTION(scope, "bad param");
01031 
01032     *dest = nsnull;
01033     if(!src)
01034         return JS_TRUE;
01035     if(pErr)
01036         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
01037 
01038 // #define this if we want to 'double wrap' of JSObjects.
01039 // This is for the case where we have a JSObject wrapped for native use
01040 // which needs to be converted to a JSObject. Originally, we were unwrapping
01041 // and just exposing the underlying JSObject. This causes anomolies when
01042 // JSComponents are accessed from other JS code - they don't act like
01043 // other xpconnect wrapped components. Eventually we want to build a new
01044 // kind of wrapper especially for JS <-> JS. For now we are building a wrapper
01045 // around a wrapper. This is not optimal, but good enough for now.
01046 #define XPC_DO_DOUBLE_WRAP 1
01047 
01048 #ifndef XPC_DO_DOUBLE_WRAP
01049     // is this a wrapped JS object?
01050     if(nsXPCWrappedJSClass::IsWrappedJS(src))
01051     {
01052         NS_ASSERTION(!isGlobal, "The global object must be native");
01053 
01054         // verify that this wrapper is for the right interface
01055         nsCOMPtr<nsISupports> wrapper;
01056         if(NS_FAILED(src->QueryInterface(*iid,(void**)getter_AddRefs(wrapper))))
01057             return JS_FALSE;
01058         return NS_SUCCEEDED(wrapper->QueryInterface(
01059                                         NS_GET_IID(nsIXPConnectJSObjectHolder),
01060                                         (void**) dest));
01061     }
01062     else
01063 #endif /* XPC_DO_DOUBLE_WRAP */
01064     {
01065         XPCWrappedNativeScope* xpcscope =
01066             XPCWrappedNativeScope::FindInJSObjectScope(ccx, scope);
01067         if(!xpcscope)
01068             return JS_FALSE;
01069 
01070         AutoMarkingNativeInterfacePtr iface(ccx);
01071         iface = XPCNativeInterface::GetNewOrUsed(ccx, iid);
01072         if(!iface)
01073             return JS_FALSE;
01074 
01075         XPCWrappedNative* wrapper;
01076         nsresult rv = XPCWrappedNative::GetNewOrUsed(ccx, src, xpcscope,
01077                                                      iface, isGlobal,
01078                                                      &wrapper);
01079         if(pErr)
01080             *pErr = rv;
01081         if(NS_SUCCEEDED(rv) && wrapper)
01082         {
01083             if (allowNativeWrapper && wrapper->GetScope() != xpcscope)
01084             {
01085                 // Cross scope access detected. Check if chrome code
01086                 // is accessing non-chrome objects, and if so, wrap
01087                 // the XPCWrappedNative with an XPCNativeWrapper to
01088                 // prevent user-defined properties from shadowing DOM
01089                 // properties from chrome code.
01090 
01091                 // printf("Wrapped native accessed across scope boundary\n");
01092 
01093                 JSScript* script = nsnull;
01094                 JSObject* callee = nsnull;
01095                 if(ccx.GetXPCContext()->CallerTypeIsJavaScript())
01096                 {
01097                     // Called from JS.  We're going to hand the resulting
01098                     // JSObject to said JS, so look for the script we want on
01099                     // the stack.
01100                     JSContext* cx = ccx;
01101                     JSStackFrame* fp = cx->fp;
01102                     while(fp)
01103                     {
01104                         script = fp->script;
01105                         if(script)
01106                         {
01107                             callee = fp->callee;
01108                             break;
01109                         }
01110                         fp = fp->down;
01111                     }
01112                 }
01113                 else if(ccx.GetXPCContext()->CallerTypeIsNative())
01114                 {
01115                     callee = ccx.GetCallee();
01116                     if(callee && JS_ObjectIsFunction(ccx, callee))
01117                     {
01118                         // Called from c++, and calling out to |callee|, which
01119                         // is a JS function object.  Look for the script for
01120                         // this function.
01121                         JSFunction* fun =
01122                             (JSFunction*) JS_GetPrivate(ccx, callee);
01123                         NS_ASSERTION(fun,
01124                                      "Must have JSFunction for a Function "
01125                                      "object");
01126                         script = JS_GetFunctionScript(ccx, fun);
01127                     }
01128                     else
01129                     {
01130                         // Else we don't know whom we're calling, so don't
01131                         // create XPCNativeWrappers.
01132                         callee = nsnull;
01133                     }
01134                 }
01135                 // else don't create XPCNativeWrappers, since we have
01136                 // no idea what's calling what here.
01137                 
01138                 uint32 flags = script ? JS_GetScriptFilenameFlags(script) : 0;
01139                 NS_ASSERTION(flags != JSFILENAME_NULL, "null script filename");
01140 
01141                 if((flags & JSFILENAME_SYSTEM) &&
01142                    !JS_IsSystemObject(ccx, wrapper->GetFlatJSObject()))
01143                 {
01144 #ifdef DEBUG_XPCNativeWrapper
01145                     {
01146                         char *s = wrapper->ToString(ccx);
01147                         printf("Content accessed from chrome, wrapping wrapper (%s) in XPCNativeWrapper\n", s);
01148                         if (s)
01149                             JS_smprintf_free(s);
01150                     }
01151 #endif
01152 
01153                     JSObject *nativeWrapper =
01154                         XPCNativeWrapper::GetNewOrUsed(ccx, wrapper, callee);
01155 
01156                     if (nativeWrapper)
01157                     {
01158                         XPCJSObjectHolder *objHolder =
01159                             XPCJSObjectHolder::newHolder(ccx, nativeWrapper);
01160 
01161                         if (objHolder)
01162                         {
01163                             NS_ADDREF(objHolder);
01164                             NS_RELEASE(wrapper);
01165 
01166                             *dest = objHolder;
01167                             return JS_TRUE;
01168                         }
01169                     }
01170 
01171                     // Out of memory or other failure that already
01172                     // threw a JS exception.
01173                     NS_RELEASE(wrapper);
01174                     return JS_FALSE;
01175                 }
01176             }
01177 
01178             *dest = NS_STATIC_CAST(nsIXPConnectJSObjectHolder*, wrapper);
01179             return JS_TRUE;
01180         }
01181         
01182     }
01183     return JS_FALSE;
01184 }
01185 
01186 /***************************************************************************/
01187 
01188 // static
01189 JSBool
01190 XPCConvert::JSObject2NativeInterface(XPCCallContext& ccx,
01191                                      void** dest, JSObject* src,
01192                                      const nsID* iid,
01193                                      nsISupports* aOuter,
01194                                      nsresult* pErr)
01195 {
01196     NS_ASSERTION(dest, "bad param");
01197     NS_ASSERTION(src, "bad param");
01198     NS_ASSERTION(iid, "bad param");
01199 
01200     JSContext* cx = ccx.GetJSContext();
01201 
01202     *dest = nsnull;
01203      if(pErr)
01204         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
01205 
01206     nsISupports* iface;
01207 
01208     if(!aOuter)
01209     {
01210         // Note that if we have a non-null aOuter then it means that we are
01211         // forcing the creation of a wrapper even if the object *is* a 
01212         // wrappedNative or other wise has 'nsISupportness'. 
01213         // This allows wrapJSAggregatedToNative to work.
01214 
01215         // Is this really a native xpcom object with a wrapper?
01216         XPCWrappedNative* wrappedNative =
01217                     XPCWrappedNative::GetWrappedNativeOfJSObject(cx, src);
01218         if(wrappedNative)
01219         {
01220             iface = wrappedNative->GetIdentityObject();
01221             // is the underlying object the right interface?
01222             if(wrappedNative->GetIID().Equals(*iid))
01223             {
01224                 NS_ADDREF(iface);
01225                 *dest = iface;
01226                 return JS_TRUE;
01227             }
01228             return NS_SUCCEEDED(iface->QueryInterface(*iid, dest));
01229         }
01230         // else...
01231         
01232         // XXX E4X breaks the world. Don't try wrapping E4X objects!
01233         // This hack can be removed (or changed accordingly) when the
01234         // DOM <-> E4X bindings are complete, see bug 270553
01235         if(JS_TypeOfValue(cx, OBJECT_TO_JSVAL(src)) == JSTYPE_XML)
01236             return JS_FALSE;
01237 
01238         // Does the JSObject have 'nsISupportness'?
01239         // XXX hmm, I wonder if this matters anymore with no 
01240         // oldstyle DOM objects around.
01241         if(GetISupportsFromJSObject(cx, src, &iface))
01242         {
01243             if(iface)
01244                 return NS_SUCCEEDED(iface->QueryInterface(*iid, dest));
01245 
01246             return JS_FALSE;
01247         }
01248     }
01249 
01250     // else...
01251 
01252     nsXPCWrappedJS* wrapper;
01253     nsresult rv = nsXPCWrappedJS::GetNewOrUsed(ccx, src, *iid, aOuter, &wrapper);
01254     if(pErr)
01255         *pErr = rv;
01256     if(NS_SUCCEEDED(rv) && wrapper)
01257     {
01258         // We need to go through the QueryInterface logic to make this return
01259         // the right thing for the various 'special' interfaces; e.g. 
01260         // nsIPropertyBag. We must use AggregatedQueryInterface in cases where 
01261         // there is an outer to avoid nasty recursion.
01262         rv = aOuter ? wrapper->AggregatedQueryInterface(*iid, dest) :
01263                       wrapper->QueryInterface(*iid, dest);
01264         if(pErr)
01265             *pErr = rv;
01266         NS_RELEASE(wrapper);
01267         return NS_SUCCEEDED(rv);        
01268     }
01269 
01270     // else...
01271     return JS_FALSE;
01272 }
01273 
01274 /***************************************************************************/
01275 /***************************************************************************/
01276 
01277 // static
01278 nsresult
01279 XPCConvert::ConstructException(nsresult rv, const char* message,
01280                                const char* ifaceName, const char* methodName,
01281                                nsISupports* data,
01282                                nsIException** exceptn)
01283 {
01284     static const char format[] = "\'%s\' when calling method: [%s::%s]";
01285     const char * msg = message;
01286     char* sz = nsnull;
01287 
01288     if(!msg)
01289         if(!nsXPCException::NameAndFormatForNSResult(rv, nsnull, &msg) || ! msg)
01290             msg = "<error>";
01291 
01292     if(ifaceName && methodName)
01293         sz = JS_smprintf(format, msg, ifaceName, methodName);
01294     else
01295         sz = (char*) msg; // I promise to play nice after casting away const
01296 
01297     nsresult res = nsXPCException::NewException(sz, rv, nsnull, data, exceptn);
01298 
01299     if(sz && sz != msg)
01300         JS_smprintf_free(sz);
01301     return res;
01302 }
01303 
01304 /********************************/
01305 
01306 // static
01307 nsresult
01308 XPCConvert::JSValToXPCException(XPCCallContext& ccx,
01309                                 jsval s,
01310                                 const char* ifaceName,
01311                                 const char* methodName,
01312                                 nsIException** exceptn)
01313 {
01314     JSContext* cx = ccx.GetJSContext();
01315 
01316     if(!JSVAL_IS_PRIMITIVE(s))
01317     {
01318         // we have a JSObject
01319         JSObject* obj = JSVAL_TO_OBJECT(s);
01320 
01321         if(!obj)
01322         {
01323             NS_ASSERTION(0, "when is an object not an object?");
01324             return NS_ERROR_FAILURE;
01325         }
01326 
01327         // is this really a native xpcom object with a wrapper?
01328         XPCWrappedNative* wrapper;
01329         if(nsnull != (wrapper =
01330            XPCWrappedNative::GetWrappedNativeOfJSObject(cx,obj)))
01331         {
01332             nsISupports* supports = wrapper->GetIdentityObject();
01333             nsCOMPtr<nsIException> iface = do_QueryInterface(supports);
01334             if(iface)
01335             {
01336                 // just pass through the exception (with extra ref and all)
01337                 nsIException* temp = iface;
01338                 NS_ADDREF(temp);
01339                 *exceptn = temp;
01340                 return NS_OK;
01341             }
01342             else
01343             {
01344                 // it is a wrapped native, but not an exception!
01345                 return ConstructException(NS_ERROR_XPC_JS_THREW_NATIVE_OBJECT,
01346                                           nsnull, ifaceName, methodName, supports,
01347                                           exceptn);
01348             }
01349         }
01350         else
01351         {
01352             // It is a JSObject, but not a wrapped native...
01353 
01354             // If it is an engine Error with an error report then let's
01355             // extract the report and build an xpcexception from that
01356             const JSErrorReport* report;
01357             if(nsnull != (report = JS_ErrorFromException(cx, s)))
01358             {
01359                 const char* message = nsnull;
01360                 JSString* str;
01361                 if(nsnull != (str = JS_ValueToString(cx, s)))
01362                     message = JS_GetStringBytes(str);
01363                 return JSErrorToXPCException(ccx, message, ifaceName,
01364                                              methodName, report, exceptn);
01365             }
01366 
01367 
01368             uintN ignored;
01369             JSBool found;
01370 
01371             // heuristic to see if it might be usable as an xpcexception
01372             if(JS_GetPropertyAttributes(cx, obj, "message", &ignored, &found) &&
01373                found &&
01374                JS_GetPropertyAttributes(cx, obj, "result", &ignored, &found) &&
01375                found)
01376             {
01377                 // lets try to build a wrapper around the JSObject
01378                 XPCContext* xpcc;
01379                 if(nsnull != (xpcc = nsXPConnect::GetContext(cx)))
01380                 {
01381                     nsXPCWrappedJS* jswrapper;
01382                     nsresult rv =
01383                         nsXPCWrappedJS::GetNewOrUsed(ccx, obj,
01384                                                 NS_GET_IID(nsIException),
01385                                                 nsnull, &jswrapper);
01386                     if(NS_FAILED(rv))
01387                         return rv;
01388                     *exceptn = NS_REINTERPRET_CAST(nsIException*,
01389                                                    jswrapper);
01390                     return NS_OK;
01391                 }
01392             }
01393 
01394 
01395             // XXX we should do a check against 'js_ErrorClass' here and
01396             // do the right thing - even though it has no JSErrorReport,
01397             // The fact that it is a JSError exceptions means we can extract
01398             // particular info and our 'result' should reflect that.
01399 
01400             // otherwise we'll just try to convert it to a string
01401 
01402             JSString* str = JS_ValueToString(cx, s);
01403             if(!str)
01404                 return NS_ERROR_FAILURE;
01405 
01406             return ConstructException(NS_ERROR_XPC_JS_THREW_JS_OBJECT,
01407                                       JS_GetStringBytes(str),
01408                                       ifaceName, methodName, nsnull,
01409                                       exceptn);
01410         }
01411     }
01412 
01413     if(JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s))
01414     {
01415         return ConstructException(NS_ERROR_XPC_JS_THREW_NULL,
01416                                   nsnull, ifaceName, methodName, nsnull,
01417                                   exceptn);
01418     }
01419 
01420     if(JSVAL_IS_NUMBER(s))
01421     {
01422         // lets see if it looks like an nsresult
01423         nsresult rv;
01424         double number;
01425         JSBool isResult = JS_FALSE;
01426 
01427         if(JSVAL_IS_INT(s))
01428         {
01429             rv = (nsresult) JSVAL_TO_INT(s);
01430             if(NS_FAILED(rv))
01431                 isResult = JS_TRUE;
01432             else
01433                 number = (double) JSVAL_TO_INT(s);
01434         }
01435         else
01436         {
01437             if(JSVAL_TO_DOUBLE(s))
01438             {
01439                 number = *(JSVAL_TO_DOUBLE(s));
01440                 if(number > 0.0 &&
01441                    number < (double)0xffffffff &&
01442                    0.0 == fmod(number,1))
01443                 {
01444                     rv = (nsresult) number;
01445                     if(NS_FAILED(rv))
01446                         isResult = JS_TRUE;
01447                 }
01448             }
01449         }
01450 
01451         if(isResult)
01452             return ConstructException(rv, nsnull, ifaceName, methodName,
01453                                       nsnull, exceptn);
01454         else
01455         {
01456             nsISupportsDouble* data;
01457             nsCOMPtr<nsIComponentManager> cm;
01458             if(NS_FAILED(NS_GetComponentManager(getter_AddRefs(cm))) || !cm ||
01459                NS_FAILED(cm->CreateInstanceByContractID(
01460                                 NS_SUPPORTS_DOUBLE_CONTRACTID,
01461                                 nsnull,
01462                                 NS_GET_IID(nsISupportsDouble),
01463                                 (void**)&data)))
01464                 return NS_ERROR_FAILURE;
01465             data->SetData(number);
01466             rv = ConstructException(NS_ERROR_XPC_JS_THREW_NUMBER, nsnull,
01467                                     ifaceName, methodName, data, exceptn);
01468             NS_RELEASE(data);
01469             return rv;
01470         }
01471     }
01472 
01473     // otherwise we'll just try to convert it to a string
01474 
01475     JSString* str = JS_ValueToString(cx, s);
01476     if(str)
01477         return ConstructException(NS_ERROR_XPC_JS_THREW_STRING,
01478                                   JS_GetStringBytes(str),
01479                                   ifaceName, methodName, nsnull,
01480                                   exceptn);
01481     return NS_ERROR_FAILURE;
01482 }
01483 
01484 /********************************/
01485 
01486 // static
01487 nsresult
01488 XPCConvert::JSErrorToXPCException(XPCCallContext& ccx,
01489                                   const char* message,
01490                                   const char* ifaceName,
01491                                   const char* methodName,
01492                                   const JSErrorReport* report,
01493                                   nsIException** exceptn)
01494 {
01495     nsresult rv = NS_ERROR_FAILURE;
01496     nsScriptError* data;
01497     if(report)
01498     {
01499         nsAutoString bestMessage;
01500         if(report && report->ucmessage)
01501         {
01502             bestMessage = (const PRUnichar *)report->ucmessage;
01503         }
01504         else if(message)
01505         {
01506             bestMessage.AssignWithConversion(message);
01507         }
01508         else
01509         {
01510             bestMessage.AssignLiteral("JavaScript Error");
01511         }
01512 
01513         data = new nsScriptError();
01514         if(!data)
01515             return NS_ERROR_OUT_OF_MEMORY;
01516 
01517         NS_ADDREF(data);
01518         data->Init(bestMessage.get(),
01519                    NS_ConvertASCIItoUCS2(report->filename).get(),
01520                    (const PRUnichar *)report->uclinebuf, report->lineno,
01521                    report->uctokenptr - report->uclinebuf, report->flags,
01522                    "XPConnect JavaScript");
01523     }
01524     else
01525         data = nsnull;
01526 
01527     if(data)
01528     {
01529         nsCAutoString formattedMsg;
01530         data->ToString(formattedMsg);
01531 
01532         rv = ConstructException(NS_ERROR_XPC_JAVASCRIPT_ERROR_WITH_DETAILS,
01533                                 formattedMsg.get(), ifaceName, methodName, data,
01534                                 exceptn);
01535 
01536         NS_RELEASE(data);
01537     }
01538     else
01539     {
01540         rv = ConstructException(NS_ERROR_XPC_JAVASCRIPT_ERROR,
01541                                 nsnull, ifaceName, methodName, nsnull,
01542                                 exceptn);
01543     }
01544     return rv;
01545 }
01546 
01547 
01548 /***************************************************************************/
01549 
01550 /*
01551 ** Note: on some platforms va_list is defined as an array,
01552 ** and requires array notation.
01553 */
01554 #ifdef HAVE_VA_COPY
01555 #define VARARGS_ASSIGN(foo, bar)   VA_COPY(foo,bar)
01556 #elif defined(HAVE_VA_LIST_AS_ARRAY)
01557 #define VARARGS_ASSIGN(foo, bar)   foo[0] = bar[0]
01558 #else
01559 #define VARARGS_ASSIGN(foo, bar)   (foo) = (bar)
01560 #endif
01561 
01562 // We assert below that these formats all begin with "%i".
01563 const char* XPC_ARG_FORMATTER_FORMAT_STRINGS[] = {"%ip", "%iv", "%is", nsnull};
01564 
01565 JSBool JS_DLL_CALLBACK
01566 XPC_JSArgumentFormatter(JSContext *cx, const char *format,
01567                         JSBool fromJS, jsval **vpp, va_list *app)
01568 {
01569     XPCCallContext ccx(NATIVE_CALLER, cx);
01570     if(!ccx.IsValid())
01571         return JS_FALSE;
01572 
01573     jsval *vp;
01574     va_list ap;
01575 
01576     vp = *vpp;
01577     VARARGS_ASSIGN(ap, *app);
01578 
01579     nsXPTType type;
01580     const nsIID* iid;
01581     void* p;
01582 
01583     NS_ASSERTION(format[0] == '%' && format[1] == 'i', "bad format!");
01584     char which = format[2];
01585 
01586     if(fromJS)
01587     {
01588         switch(which)
01589         {
01590             case 'p':
01591                 type = nsXPTType((uint8)(TD_INTERFACE_TYPE | XPT_TDP_POINTER));                
01592                 iid = &NS_GET_IID(nsISupports);
01593                 break;
01594             case 'v':
01595                 type = nsXPTType((uint8)(TD_INTERFACE_TYPE | XPT_TDP_POINTER));                
01596                 iid = &NS_GET_IID(nsIVariant);
01597                 break;
01598             case 's':
01599                 type = nsXPTType((uint8)(TD_DOMSTRING | XPT_TDP_POINTER));                
01600                 iid = nsnull;
01601                 p = va_arg(ap, void *);
01602                 break;
01603             default:
01604                 NS_ERROR("bad format!");
01605                 return JS_FALSE;
01606         }
01607 
01608         if(!XPCConvert::JSData2Native(ccx, &p, vp[0], type, JS_FALSE,
01609                                       iid, nsnull))
01610             return JS_FALSE;
01611         
01612         if(which != 's')
01613             *va_arg(ap, void **) = p;
01614     }
01615     else
01616     {
01617         switch(which)
01618         {
01619             case 'p':
01620                 type = nsXPTType((uint8)(TD_INTERFACE_TYPE | XPT_TDP_POINTER));                
01621                 iid  = va_arg(ap, const nsIID*);
01622                 break;
01623             case 'v':
01624                 type = nsXPTType((uint8)(TD_INTERFACE_TYPE | XPT_TDP_POINTER));                
01625                 iid = &NS_GET_IID(nsIVariant);
01626                 break;
01627             case 's':
01628                 type = nsXPTType((uint8)(TD_DOMSTRING | XPT_TDP_POINTER));                
01629                 iid = nsnull;
01630                 break;
01631             default:
01632                 NS_ERROR("bad format!");
01633                 return JS_FALSE;
01634         }
01635 
01636         // NOTE: MUST be retrieved *after* the iid in the 'p' case above.
01637         p = va_arg(ap, void *);
01638 
01639         if(!XPCConvert::NativeData2JS(ccx, &vp[0], &p, type, iid,
01640                                       JS_GetGlobalObject(cx), nsnull))
01641             return JS_FALSE;
01642     }
01643     *vpp = vp + 1;
01644     VARARGS_ASSIGN(*app, ap);
01645     return JS_TRUE;
01646 }
01647 
01648 /***************************************************************************/
01649 
01650 // array fun...
01651 
01652 #ifdef POPULATE
01653 #undef POPULATE
01654 #endif
01655 
01656 // static
01657 JSBool
01658 XPCConvert::NativeArray2JS(XPCCallContext& ccx,
01659                            jsval* d, const void** s,
01660                            const nsXPTType& type, const nsID* iid,
01661                            JSUint32 count, JSObject* scope,
01662                            nsresult* pErr)
01663 {
01664     NS_PRECONDITION(s, "bad param");
01665     NS_PRECONDITION(d, "bad param");
01666 
01667     JSContext* cx = ccx.GetJSContext();
01668 
01669     // XXX add support for putting chars in a string rather than an array
01670 
01671     // XXX add support to indicate *which* array element was not convertable
01672 
01673     JSObject *array = JS_NewArrayObject(cx, count, nsnull);
01674 
01675     if(!array)
01676         return JS_FALSE;
01677 
01678     // root this early
01679     *d = OBJECT_TO_JSVAL(array);
01680     AUTO_MARK_JSVAL(ccx, d);
01681 
01682     if(pErr)
01683         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
01684 
01685     JSUint32 i;
01686     jsval current = JSVAL_NULL;
01687     AUTO_MARK_JSVAL(ccx, &current);
01688 
01689 #define POPULATE(_t)                                                         \
01690     PR_BEGIN_MACRO                                                           \
01691         for(i = 0; i < count; i++)                                           \
01692         {                                                                    \
01693             if(!NativeData2JS(ccx, &current, ((_t*)*s)+i, type, iid,         \
01694                               scope, pErr) ||                                \
01695                !JS_SetElement(cx, array, i, &current))                       \
01696                 goto failure;                                                \
01697         }                                                                    \
01698     PR_END_MACRO
01699 
01700     // XXX check IsPtr - esp. to handle array of nsID (as opposed to nsID*)
01701 
01702     switch(type.TagPart())
01703     {
01704     case nsXPTType::T_I8            : POPULATE(int8);           break;
01705     case nsXPTType::T_I16           : POPULATE(int16);          break;
01706     case nsXPTType::T_I32           : POPULATE(int32);          break;
01707     case nsXPTType::T_I64           : POPULATE(int64);          break;
01708     case nsXPTType::T_U8            : POPULATE(uint8);          break;
01709     case nsXPTType::T_U16           : POPULATE(uint16);         break;
01710     case nsXPTType::T_U32           : POPULATE(uint32);         break;
01711     case nsXPTType::T_U64           : POPULATE(uint64);         break;
01712     case nsXPTType::T_FLOAT         : POPULATE(float);          break;
01713     case nsXPTType::T_DOUBLE        : POPULATE(double);         break;
01714     case nsXPTType::T_BOOL          : POPULATE(PRBool);         break;
01715     case nsXPTType::T_CHAR          : POPULATE(char);           break;
01716     case nsXPTType::T_WCHAR         : POPULATE(jschar);         break;
01717     case nsXPTType::T_VOID          : NS_ASSERTION(0,"bad type"); goto failure;
01718     case nsXPTType::T_IID           : POPULATE(nsID*);          break;
01719     case nsXPTType::T_DOMSTRING     : NS_ASSERTION(0,"bad type"); goto failure;
01720     case nsXPTType::T_CHAR_STR      : POPULATE(char*);          break;
01721     case nsXPTType::T_WCHAR_STR     : POPULATE(jschar*);        break;
01722     case nsXPTType::T_INTERFACE     : POPULATE(nsISupports*);   break;
01723     case nsXPTType::T_INTERFACE_IS  : POPULATE(nsISupports*);   break;
01724     case nsXPTType::T_UTF8STRING    : NS_ASSERTION(0,"bad type"); goto failure;
01725     case nsXPTType::T_CSTRING       : NS_ASSERTION(0,"bad type"); goto failure;
01726     case nsXPTType::T_ASTRING       : NS_ASSERTION(0,"bad type"); goto failure;
01727     default                         : NS_ASSERTION(0,"bad type"); goto failure;
01728     }
01729 
01730     if(pErr)
01731         *pErr = NS_OK;
01732     return JS_TRUE;
01733 
01734 failure:
01735     return JS_FALSE;
01736 
01737 #undef POPULATE
01738 }
01739 
01740 // static
01741 JSBool
01742 XPCConvert::JSArray2Native(XPCCallContext& ccx, void** d, jsval s,
01743                            JSUint32 count, JSUint32 capacity,
01744                            const nsXPTType& type,
01745                            JSBool useAllocator, const nsID* iid,
01746                            uintN* pErr)
01747 {
01748     NS_PRECONDITION(d, "bad param");
01749 
01750     JSContext* cx = ccx.GetJSContext();
01751 
01752     // No Action, FRee memory, RElease object
01753     enum CleanupMode {na, fr, re};
01754 
01755     CleanupMode cleanupMode;
01756 
01757     JSObject* jsarray = nsnull;
01758     void* array = nsnull;
01759     JSUint32 initedCount;
01760     jsval current;
01761 
01762     // XXX add support for getting chars from strings
01763 
01764     // XXX add support to indicate *which* array element was not convertable
01765 
01766     if(JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s))
01767     {
01768         if(0 != count)
01769         {
01770             if(pErr)
01771                 *pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
01772             return JS_FALSE;
01773         }
01774 
01775         // If a non-zero capacity was indicated then we build an
01776         // empty array rather than return nsnull.
01777         if(0 != capacity)
01778             goto fill_array;
01779 
01780         *d = nsnull;
01781         return JS_TRUE;
01782     }
01783 
01784     if(!JSVAL_IS_OBJECT(s))
01785     {
01786         if(pErr)
01787             *pErr = NS_ERROR_XPC_CANT_CONVERT_PRIMITIVE_TO_ARRAY;
01788         return JS_FALSE;
01789     }
01790 
01791     jsarray = JSVAL_TO_OBJECT(s);
01792     if(!JS_IsArrayObject(cx, jsarray))
01793     {
01794         if(pErr)
01795             *pErr = NS_ERROR_XPC_CANT_CONVERT_OBJECT_TO_ARRAY;
01796         return JS_FALSE;
01797     }
01798 
01799     jsuint len;
01800     if(!JS_GetArrayLength(cx, jsarray, &len) || len < count || capacity < count)
01801     {
01802         if(pErr)
01803             *pErr = NS_ERROR_XPC_NOT_ENOUGH_ELEMENTS_IN_ARRAY;
01804         return JS_FALSE;
01805     }
01806 
01807     if(pErr)
01808         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS;
01809 
01810 #define POPULATE(_mode, _t)                                                  \
01811     PR_BEGIN_MACRO                                                           \
01812         cleanupMode = _mode;                                                 \
01813         if (capacity > ~(size_t)0 / sizeof(_t) ||                            \
01814             nsnull == (array = nsMemory::Alloc(capacity * sizeof(_t))))      \
01815         {                                                                    \
01816             if(pErr)                                                         \
01817                 *pErr = NS_ERROR_OUT_OF_MEMORY;                              \
01818             goto failure;                                                    \
01819         }                                                                    \
01820         for(initedCount = 0; initedCount < count; initedCount++)             \
01821         {                                                                    \
01822             if(!JS_GetElement(cx, jsarray, initedCount, &current) ||         \
01823                !JSData2Native(ccx, ((_t*)array)+initedCount, current, type,  \
01824                               useAllocator, iid, pErr))                      \
01825                 goto failure;                                                \
01826         }                                                                    \
01827     PR_END_MACRO
01828 
01829 
01830     // XXX check IsPtr - esp. to handle array of nsID (as opposed to nsID*)
01831 
01832     // XXX make extra space at end of char* and wchar* and null termintate
01833 
01834 fill_array:
01835     switch(type.TagPart())
01836     {
01837     case nsXPTType::T_I8            : POPULATE(na, int8);           break;
01838     case nsXPTType::T_I16           : POPULATE(na, int16);          break;
01839     case nsXPTType::T_I32           : POPULATE(na, int32);          break;
01840     case nsXPTType::T_I64           : POPULATE(na, int64);          break;
01841     case nsXPTType::T_U8            : POPULATE(na, uint8);          break;
01842     case nsXPTType::T_U16           : POPULATE(na, uint16);         break;
01843     case nsXPTType::T_U32           : POPULATE(na, uint32);         break;
01844     case nsXPTType::T_U64           : POPULATE(na, uint64);         break;
01845     case nsXPTType::T_FLOAT         : POPULATE(na, float);          break;
01846     case nsXPTType::T_DOUBLE        : POPULATE(na, double);         break;
01847     case nsXPTType::T_BOOL          : POPULATE(na, PRBool);         break;
01848     case nsXPTType::T_CHAR          : POPULATE(na, char);           break;
01849     case nsXPTType::T_WCHAR         : POPULATE(na, jschar);         break;
01850     case nsXPTType::T_VOID          : NS_ASSERTION(0,"bad type"); goto failure;
01851     case nsXPTType::T_IID           : POPULATE(fr, nsID*);          break;
01852     case nsXPTType::T_DOMSTRING     : NS_ASSERTION(0,"bad type"); goto failure;
01853     case nsXPTType::T_CHAR_STR      : POPULATE(fr, char*);          break;
01854     case nsXPTType::T_WCHAR_STR     : POPULATE(fr, jschar*);        break;
01855     case nsXPTType::T_INTERFACE     : POPULATE(re, nsISupports*);   break;
01856     case nsXPTType::T_INTERFACE_IS  : POPULATE(re, nsISupports*);   break;
01857     case nsXPTType::T_UTF8STRING    : NS_ASSERTION(0,"bad type"); goto failure;
01858     case nsXPTType::T_CSTRING       : NS_ASSERTION(0,"bad type"); goto failure;
01859     case nsXPTType::T_ASTRING       : NS_ASSERTION(0,"bad type"); goto failure;
01860     default                         : NS_ASSERTION(0,"bad type"); goto failure;
01861     }
01862 
01863     *d = array;
01864     if(pErr)
01865         *pErr = NS_OK;
01866     return JS_TRUE;
01867 
01868 failure:
01869     // we may need to cleanup the partially filled array of converted stuff
01870     if(array)
01871     {
01872         if(cleanupMode == re)
01873         {
01874             nsISupports** a = (nsISupports**) array;
01875             for(PRUint32 i = 0; i < initedCount; i++)
01876             {
01877                 nsISupports* p = a[i];
01878                 NS_IF_RELEASE(p);
01879             }
01880         }
01881         else if(cleanupMode == fr && useAllocator)
01882         {
01883             void** a = (void**) array;
01884             for(PRUint32 i = 0; i < initedCount; i++)
01885             {
01886                 void* p = a[i];
01887                 if(p) nsMemory::Free(p);
01888             }
01889         }
01890         nsMemory::Free(array);
01891     }
01892 
01893     return JS_FALSE;
01894 
01895 #undef POPULATE
01896 }
01897 
01898 // static
01899 JSBool
01900 XPCConvert::NativeStringWithSize2JS(XPCCallContext& ccx,
01901                                     jsval* d, const void* s,
01902                                     const nsXPTType& type,
01903                                     JSUint32 count,
01904                                     nsresult* pErr)
01905 {
01906     NS_PRECONDITION(s, "bad param");
01907     NS_PRECONDITION(d, "bad param");
01908 
01909     JSContext* cx = ccx.GetJSContext();
01910 
01911     if(pErr)
01912         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
01913 
01914     if(!type.IsPointer())
01915     {
01916         XPC_LOG_ERROR(("XPCConvert::NativeStringWithSize2JS : unsupported type"));
01917         return JS_FALSE;
01918     }
01919     switch(type.TagPart())
01920     {
01921         case nsXPTType::T_PSTRING_SIZE_IS:
01922         {
01923             char* p = *((char**)s);
01924             if(!p)
01925                 break;
01926             JSString* str;
01927             if(!(str = JS_NewStringCopyN(cx, p, count)))
01928                 return JS_FALSE;
01929             *d = STRING_TO_JSVAL(str);
01930             break;
01931         }
01932         case nsXPTType::T_PWSTRING_SIZE_IS:
01933         {
01934             jschar* p = *((jschar**)s);
01935             if(!p)
01936                 break;
01937             JSString* str;
01938             if(!(str = JS_NewUCStringCopyN(cx, p, count)))
01939                 return JS_FALSE;
01940             *d = STRING_TO_JSVAL(str);
01941             break;
01942         }
01943         default:
01944             XPC_LOG_ERROR(("XPCConvert::NativeStringWithSize2JS : unsupported type"));
01945             return JS_FALSE;
01946     }
01947     return JS_TRUE;
01948 }
01949 
01950 // static
01951 JSBool
01952 XPCConvert::JSStringWithSize2Native(XPCCallContext& ccx, void* d, jsval s,
01953                                     JSUint32 count, JSUint32 capacity,
01954                                     const nsXPTType& type,
01955                                     JSBool useAllocator,
01956                                     uintN* pErr)
01957 {
01958     NS_PRECONDITION(s, "bad param");
01959     NS_PRECONDITION(d, "bad param");
01960 
01961     JSContext* cx = ccx.GetJSContext();
01962 
01963     JSUint32 len;
01964 
01965     if(pErr)
01966         *pErr = NS_ERROR_XPC_BAD_CONVERT_NATIVE;
01967 
01968     if(capacity < count)
01969     {
01970         if(pErr)
01971             *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING;
01972         return JS_FALSE;
01973     }
01974 
01975     if(!type.IsPointer())
01976     {
01977         XPC_LOG_ERROR(("XPCConvert::JSStringWithSize2Native : unsupported type"));
01978         return JS_FALSE;
01979     }
01980     switch(type.TagPart())
01981     {
01982         case nsXPTType::T_PSTRING_SIZE_IS:
01983         {
01984             char* bytes=nsnull;
01985             JSString* str;
01986 
01987             if(JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s))
01988             {
01989                 if(0 != count)
01990                 {
01991                     if(pErr)
01992                         *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING;
01993                     return JS_FALSE;
01994                 }
01995                 if(type.IsReference())
01996                 {
01997                     if(pErr)
01998                         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_NULL_REF;
01999                     return JS_FALSE;
02000                 }
02001 
02002                 if(useAllocator && 0 != capacity)
02003                 {
02004                     len = (capacity + 1) * sizeof(char);
02005                     if(!(*((void**)d) = nsMemory::Alloc(len)))
02006                         return JS_FALSE;
02007                     return JS_TRUE;
02008                 }
02009                 // else ...
02010 
02011                 *((char**)d) = nsnull;
02012                 return JS_TRUE;
02013             }
02014 
02015             if(!(str = JS_ValueToString(cx, s))||
02016                !(bytes = JS_GetStringBytes(str)))
02017             {
02018                 return JS_FALSE;
02019             }
02020 
02021             len = JS_GetStringLength(str);
02022             if(len > count)
02023             {
02024                 if(pErr)
02025                     *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING;
02026                 return JS_FALSE;
02027             }
02028 
02029             if(len < capacity)
02030                 len = capacity;
02031 
02032             if(useAllocator)
02033             {
02034                 JSUint32 alloc_len = (len + 1) * sizeof(char);
02035                 if(!(*((void**)d) = nsMemory::Alloc(alloc_len)))
02036                 {
02037                     return JS_FALSE;
02038                 }
02039                 memcpy(*((char**)d), bytes, count);
02040                 (*((char**)d))[count] = 0;
02041             }
02042             else
02043                 *((char**)d) = bytes;
02044 
02045             return JS_TRUE;
02046         }
02047 
02048         case nsXPTType::T_PWSTRING_SIZE_IS:
02049         {
02050             jschar* chars=nsnull;
02051             JSString* str;
02052 
02053             if(JSVAL_IS_VOID(s) || JSVAL_IS_NULL(s))
02054             {
02055                 if(0 != count)
02056                 {
02057                     if(pErr)
02058                         *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING;
02059                     return JS_FALSE;
02060                 }
02061                 if(type.IsReference())
02062                 {
02063                     if(pErr)
02064                         *pErr = NS_ERROR_XPC_BAD_CONVERT_JS_NULL_REF;
02065                     return JS_FALSE;
02066                 }
02067 
02068                 if(useAllocator && 0 != capacity)
02069                 {
02070                     len = (capacity + 1) * sizeof(jschar);
02071                     if(!(*((void**)d) = nsMemory::Alloc(len)))
02072                         return JS_FALSE;
02073                     return JS_TRUE;
02074                 }
02075 
02076                 // else ...
02077                 *((jschar**)d) = nsnull;
02078                 return JS_TRUE;
02079             }
02080 
02081             if(!(str = JS_ValueToString(cx, s))||
02082                !(chars = JS_GetStringChars(str)))
02083             {
02084                 return JS_FALSE;
02085             }
02086 
02087             len = JS_GetStringLength(str);
02088             if(len > count)
02089             {
02090                 if(pErr)
02091                     *pErr = NS_ERROR_XPC_NOT_ENOUGH_CHARS_IN_STRING;
02092                 return JS_FALSE;
02093             }
02094             if(len < capacity)
02095                 len = capacity;
02096 
02097             if(useAllocator)
02098             {
02099                 JSUint32 alloc_len = (len + 1) * sizeof(jschar);
02100                 if(!(*((void**)d) = nsMemory::Alloc(alloc_len)))
02101                 {
02102                     // XXX should report error
02103                     return JS_FALSE;
02104                 }
02105                 memcpy(*((jschar**)d), chars, alloc_len);
02106                 (*((jschar**)d))[count] = 0;
02107             }
02108             else
02109                 *((jschar**)d) = chars;
02110 
02111             return JS_TRUE;
02112         }
02113         default:
02114             XPC_LOG_ERROR(("XPCConvert::JSStringWithSize2Native : unsupported type"));
02115             return JS_FALSE;
02116     }
02117 }
02118