Back to index

lightning-sunbird  0.9+nobinonly
VariantUtils.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is the Python XPCOM language bindings.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * ActiveState Tool Corp.
00018  * Portions created by the Initial Developer are Copyright (C) 2000
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Mark Hammond <mhammond@skippinet.com.au> (original author)
00023  *
00024  *   Unicode corrections by Shane Hathaway (http://hathawaymix.org),
00025  *     inspired by Mikhail Sobolev
00026  *
00027  * Alternatively, the contents of this file may be used under the terms of
00028  * either the GNU General Public License Version 2 or later (the "GPL"), or
00029  * 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 //
00042 // This code is part of the XPCOM extensions for Python.
00043 //
00044 // Written May 2000 by Mark Hammond.
00045 //
00046 // Based heavily on the Python COM support, which is
00047 // (c) Mark Hammond and Greg Stein.
00048 //
00049 // (c) 2000, ActiveState corp.
00050 
00051 #include "PyXPCOM_std.h"
00052 #include <nsIInterfaceInfoManager.h>
00053 #include <nsAString.h>
00054 #include <nsString.h>
00055 #include <nsReadableUtils.h>
00056 
00057 // ------------------------------------------------------------------------
00058 // nsString utilities
00059 // ------------------------------------------------------------------------
00060 // one day we may know what they look like.
00061 inline
00062 PRBool
00063 IsNullDOMString( const nsAString& aString )
00064 {
00065        return PR_FALSE;
00066 }
00067 
00068 inline
00069 PRBool
00070 IsNullDOMString( const nsACString& aString )
00071 {
00072        return PR_FALSE;
00073 }
00074 
00075 // Create a zero-terminated PRUnichar buffer from a Python unicode.
00076 // On success, returns 0.  On failure, returns -1 and sets an exception.
00077 // dest_out must not be null.  size_out may be null.
00078 static int
00079 PyUnicode_AsPRUnichar(PyObject *obj, PRUnichar **dest_out, PRUint32 *size_out)
00080 {
00081        PRUint32 size;
00082        PyObject *s;
00083        PRUnichar *dest;
00084 
00085        s = PyUnicode_AsUTF16String(obj);
00086        if (!s)
00087               return -1;
00088        size = (PyString_GET_SIZE(s) - 2) / sizeof(PRUnichar);
00089        dest = (PRUnichar *)nsMemory::Alloc(sizeof(PRUnichar) * (size + 1));
00090        if (!dest) {
00091               PyErr_NoMemory();
00092               Py_DECREF(s);
00093               return -1;
00094        }
00095        // Drop the UTF-16 byte order mark at the beginning of
00096        // the string.  (See the docs on PyUnicode_AsUTF16String.)
00097        // Some Mozilla libraries don't like the mark.
00098        memcpy(dest, PyString_AS_STRING(s) + 2, sizeof(PRUnichar) * size);
00099        Py_DECREF(s);
00100        dest[size] = 0;
00101        *dest_out = dest;
00102        if (size_out)
00103               *size_out = size;
00104        return 0;
00105 }
00106 
00107 PyObject *PyObject_FromNSString( const nsACString &s, PRBool bAssumeUTF8 = PR_FALSE )
00108 {
00109        PyObject *ret;
00110        if (IsNullDOMString(s)) {
00111               ret = Py_None;
00112               Py_INCREF(Py_None);
00113        } else {
00114               if (bAssumeUTF8) {
00115                         const nsPromiseFlatCString& temp = PromiseFlatCString(s);
00116                         ret = PyUnicode_DecodeUTF8(temp.get(), temp.Length(), NULL);
00117               } else {
00118                      ret = PyString_FromStringAndSize(NULL, s.Length());
00119                      if (!ret)
00120                             return NULL;
00121                      // Need "CopyAsciiTo"!?
00122                      nsACString::const_iterator fromBegin, fromEnd;
00123                      char* dest = PyString_AS_STRING(ret);
00124                      copy_string(s.BeginReading(fromBegin), s.EndReading(fromEnd), dest);
00125               }
00126        }
00127        return ret;
00128 }
00129 
00130 PyObject *PyObject_FromNSString( const nsAString &s )
00131 {
00132        PyObject *ret;
00133        if (IsNullDOMString(s)) {
00134               ret = Py_None;
00135               Py_INCREF(Py_None);
00136        } else {
00137                 const nsPromiseFlatString& temp = PromiseFlatString(s);
00138                 ret = PyUnicode_FromPRUnichar(temp.get(), temp.Length());
00139        }
00140        return ret;
00141 }
00142 
00143 // Array utilities
00144 static PRUint32 GetArrayElementSize( PRUint8 t)
00145 {
00146        PRUint32 ret;
00147        switch (t & XPT_TDP_TAGMASK) {
00148               case nsXPTType::T_U8:
00149               case nsXPTType::T_I8:
00150                      ret = sizeof(PRInt8); 
00151                      break;
00152               case nsXPTType::T_I16:
00153               case nsXPTType::T_U16:
00154                      ret = sizeof(PRInt16); 
00155                      break;
00156               case nsXPTType::T_I32:
00157               case nsXPTType::T_U32:
00158                      ret = sizeof(PRInt32); 
00159                      break;
00160               case nsXPTType::T_I64:
00161               case nsXPTType::T_U64:
00162                      ret = sizeof(PRInt64); 
00163                      break;
00164               case nsXPTType::T_FLOAT:
00165                      ret = sizeof(float); 
00166                      break;
00167               case nsXPTType::T_DOUBLE:
00168                      ret = sizeof(double); 
00169                      break;
00170               case nsXPTType::T_BOOL:
00171                      ret = sizeof(PRBool); 
00172                      break;
00173               case nsXPTType::T_CHAR:
00174                      ret = sizeof(char); 
00175                      break;
00176               case nsXPTType::T_WCHAR:
00177                      ret = sizeof(PRUnichar); 
00178                      break;
00179               case nsXPTType::T_IID:
00180               case nsXPTType::T_CHAR_STR:
00181               case nsXPTType::T_WCHAR_STR:
00182               case nsXPTType::T_INTERFACE:
00183               case nsXPTType::T_DOMSTRING:
00184               case nsXPTType::T_INTERFACE_IS:
00185               case nsXPTType::T_PSTRING_SIZE_IS:
00186               case nsXPTType::T_CSTRING:
00187               case nsXPTType::T_ASTRING:
00188               case nsXPTType::T_UTF8STRING:
00189 
00190                      ret = sizeof( void * );
00191                      break;
00192        default:
00193               NS_ABORT_IF_FALSE(0, "Unknown array type code!");
00194               ret = 0;
00195               break;
00196        }
00197        return ret;
00198 }
00199 
00200 void FreeSingleArray(void *array_ptr, PRUint32 sequence_size, PRUint8 array_type)
00201 {
00202        // Free each array element - NOT the array itself
00203        // Thus, we only need to free arrays or pointers.
00204        void **p = (void **)array_ptr;
00205        PRUint32 i;
00206        switch(array_type & XPT_TDP_TAGMASK) {
00207               case nsXPTType::T_IID:
00208               case nsXPTType::T_CHAR_STR:
00209               case nsXPTType::T_WCHAR_STR:
00210                      for (i=0; i<sequence_size; i++)
00211                             if (p[i]) nsMemory::Free(p[i]);
00212                      break;
00213               case nsXPTType::T_INTERFACE:
00214               case nsXPTType::T_INTERFACE_IS:
00215                      for (i=0; i<sequence_size; i++)
00216                             if (p[i]) {
00217                                    Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
00218                                    ((nsISupports *)p[i])->Release();
00219                                    Py_END_ALLOW_THREADS;
00220                             }
00221                      break;
00222 
00223               // Ones we know need no deallocation
00224               case nsXPTType::T_U8:
00225               case nsXPTType::T_I8:
00226               case nsXPTType::T_I16:
00227               case nsXPTType::T_U16:
00228               case nsXPTType::T_I32:
00229               case nsXPTType::T_U32:
00230               case nsXPTType::T_I64:
00231               case nsXPTType::T_U64:
00232               case nsXPTType::T_FLOAT:
00233               case nsXPTType::T_DOUBLE:
00234               case nsXPTType::T_BOOL:
00235               case nsXPTType::T_CHAR:
00236               case nsXPTType::T_WCHAR:
00237                      break;
00238 
00239               // And a warning should new type codes appear, as they may need deallocation.
00240               default:
00241                      PyXPCOM_LogWarning("Deallocating unknown type %d (0x%x) - possible memory leak\n");
00242                      break;
00243        }
00244 }
00245 
00246 #define FILL_SIMPLE_POINTER( type, val ) *((type *)pthis) = (type)(val)
00247 #define BREAK_FALSE {rc=PR_FALSE;break;}
00248 
00249 
00250 PRBool FillSingleArray(void *array_ptr, PyObject *sequence_ob, PRUint32 sequence_size, PRUint32 array_element_size, PRUint8 array_type)
00251 {
00252        PRUint8 *pthis = (PRUint8 *)array_ptr;
00253        NS_ABORT_IF_FALSE(pthis, "Don't have a valid array to fill!");
00254        PRBool rc = PR_TRUE;
00255        // We handle T_U8 specially as a string/Unicode.
00256        // If it is NOT a string, we just fall through and allow the standard
00257        // sequence unpack code process it (just slower!)
00258        if ( array_type == nsXPTType::T_U8 && 
00259               (PyString_Check(sequence_ob) || PyUnicode_Check(sequence_ob))) {
00260 
00261               PRBool release_seq;
00262               if (PyUnicode_Check(sequence_ob)) {
00263                      release_seq = PR_TRUE;
00264                      sequence_ob = PyObject_Str(sequence_ob);
00265               } else
00266                      release_seq = PR_FALSE;
00267               if (!sequence_ob) // presumably a memory error, or Unicode encoding error.
00268                      return PR_FALSE;
00269               memcpy(pthis, PyString_AS_STRING(sequence_ob), sequence_size);
00270               if (release_seq)
00271                      Py_DECREF(sequence_ob);
00272               return PR_TRUE;
00273        }
00274 
00275        for (PRUint32 i=0; rc && i<sequence_size; i++,pthis += array_element_size) {
00276               PyObject *val = PySequence_GetItem(sequence_ob, i);
00277               PyObject *val_use = NULL;
00278               if (val==NULL)
00279                      return PR_FALSE;
00280               switch(array_type) {
00281                        case nsXPTType::T_I8:
00282                             if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
00283                             FILL_SIMPLE_POINTER( PRInt8, PyInt_AsLong(val_use) );
00284                             break;
00285                        case nsXPTType::T_I16:
00286                             if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
00287                             FILL_SIMPLE_POINTER( PRInt16, PyInt_AsLong(val_use) );
00288                             break;
00289                        case nsXPTType::T_I32:
00290                             if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
00291                             FILL_SIMPLE_POINTER( PRInt32, PyInt_AsLong(val_use) );
00292                             break;
00293                        case nsXPTType::T_I64:
00294                             if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE;
00295                             FILL_SIMPLE_POINTER( PRInt64, PyLong_AsLongLong(val_use) );
00296                             break;
00297                        case nsXPTType::T_U8:
00298                             if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
00299                             FILL_SIMPLE_POINTER( PRUint8, PyInt_AsLong(val_use) );
00300                             break;
00301                        case nsXPTType::T_U16:
00302                             if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
00303                             FILL_SIMPLE_POINTER( PRUint16, PyInt_AsLong(val_use) );
00304                             break;
00305                        case nsXPTType::T_U32:
00306                             if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
00307                             FILL_SIMPLE_POINTER( PRUint32, PyInt_AsLong(val_use) );
00308                             break;
00309                        case nsXPTType::T_U64:
00310                             if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE;
00311                             FILL_SIMPLE_POINTER( PRUint64, PyLong_AsUnsignedLongLong(val_use) );
00312                             break;
00313                        case nsXPTType::T_FLOAT:
00314                             if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
00315                             FILL_SIMPLE_POINTER( float, PyFloat_AsDouble(val_use) );
00316                             break;
00317                        case nsXPTType::T_DOUBLE:
00318                             if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
00319                             FILL_SIMPLE_POINTER( double, PyFloat_AsDouble(val_use) );
00320                             break;
00321                        case nsXPTType::T_BOOL:
00322                             if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
00323                             FILL_SIMPLE_POINTER( PRBool, PyInt_AsLong(val_use) );
00324                             break;
00325                        case nsXPTType::T_CHAR:
00326                             if (!PyString_Check(val) && !PyUnicode_Check(val)) {
00327                                    PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
00328                                    BREAK_FALSE;
00329                             }
00330                             if ((val_use = PyObject_Str(val))==NULL)
00331                                    BREAK_FALSE;
00332                             // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
00333                             NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
00334                             FILL_SIMPLE_POINTER( char, *PyString_AS_STRING(val_use) );
00335                             break;
00336 
00337                        case nsXPTType::T_WCHAR:
00338                             if (!PyString_Check(val) && !PyUnicode_Check(val)) {
00339                                    PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
00340                                    BREAK_FALSE;
00341                             }
00342                             if ((val_use = PyUnicode_FromObject(val)) == NULL)
00343                                    BREAK_FALSE;
00344                             NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!");
00345                             // Lossy!
00346                             FILL_SIMPLE_POINTER( PRUnichar, *PyUnicode_AS_UNICODE(val_use) );
00347                             break;
00348 
00349                        case nsXPTType::T_IID: {
00350                             nsIID iid;
00351                             if (!Py_nsIID::IIDFromPyObject(val, &iid))
00352                                    BREAK_FALSE;
00353                             nsIID **pp = (nsIID **)pthis;
00354                             // If there is an existing IID, free it.
00355                             if (*pp)
00356                                    nsMemory::Free(*pp);
00357                             *pp = (nsIID *)nsMemory::Alloc(sizeof(nsIID));
00358                             if (*pp==NULL) {
00359                                    PyErr_NoMemory();
00360                                    BREAK_FALSE;
00361                             }
00362                             memcpy(*pp, &iid, sizeof(iid));
00363                             break;
00364                             }
00365 
00366               //          case nsXPTType::T_BSTR:
00367 
00368                        case nsXPTType::T_CHAR_STR: {
00369                             // If it is an existing string, free it.
00370                             char **pp = (char **)pthis;
00371                             if (*pp)
00372                                    nsMemory::Free(*pp);
00373                             *pp = nsnull;
00374 
00375                             if (val == Py_None)
00376                                    break; // Remains NULL.
00377                             if (!PyString_Check(val) && !PyUnicode_Check(val)) {
00378                                    PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
00379                                    BREAK_FALSE;
00380                             }
00381                             if ((val_use = PyObject_Str(val))==NULL)
00382                                    BREAK_FALSE;
00383                             // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
00384                             NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
00385 
00386                             const char *sz = PyString_AS_STRING(val_use);
00387                             int nch = PyString_GET_SIZE(val_use);
00388 
00389                             *pp = (char *)nsMemory::Alloc(nch+1);
00390                             if (*pp==NULL) {
00391                                    PyErr_NoMemory();
00392                                    BREAK_FALSE;
00393                             }
00394                             strncpy(*pp, sz, nch+1);
00395                             break;
00396                             }
00397                        case nsXPTType::T_WCHAR_STR: {
00398                             // If it is an existing string, free it.
00399                             PRUnichar **pp = (PRUnichar **)pthis;
00400                             if (*pp)
00401                                    nsMemory::Free(*pp);
00402                             *pp = nsnull;
00403                             if (val == Py_None)
00404                                    break; // Remains NULL.
00405                             if (!PyString_Check(val) && !PyUnicode_Check(val)) {
00406                                    PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
00407                                    BREAK_FALSE;
00408                             }
00409                             if ((val_use = PyUnicode_FromObject(val))==NULL)
00410                                    BREAK_FALSE;
00411                             NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!");
00412                             if (PyUnicode_AsPRUnichar(val_use, pp, NULL) < 0)
00413                                    BREAK_FALSE;
00414                             break;
00415                             }
00416                        case nsXPTType::T_INTERFACE_IS: // hmm - ignoring the IID can't be good :(
00417                        case nsXPTType::T_INTERFACE:  {
00418                             // We do allow NULL here, even tho doing so will no-doubt crash some objects.
00419                             // (but there will certainly be objects out there that will allow NULL :-(
00420                             nsISupports *pnew;
00421                             if (!Py_nsISupports::InterfaceFromPyObject(val, NS_GET_IID(nsISupports), &pnew, PR_TRUE))
00422                                    BREAK_FALSE;
00423                             nsISupports **pp = (nsISupports **)pthis;
00424                             if (*pp) {
00425                                    Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
00426                                    (*pp)->Release();
00427                                    Py_END_ALLOW_THREADS;
00428                             }
00429                             *pp = pnew; // ref-count added by InterfaceFromPyObject
00430                             break;
00431                             }
00432                      default:
00433                             // try and limp along in this case.
00434                             // leave rc TRUE
00435                             PyXPCOM_LogWarning("Converting Python object for an array element - The object type (0x%x) is unknown - leaving param alone!\n", array_type);
00436                             break;
00437               }
00438               Py_XDECREF(val_use);
00439               Py_DECREF(val);
00440        }
00441        return rc;    
00442 }
00443 
00444 PyObject *UnpackSingleArray(void *array_ptr, PRUint32 sequence_size, PRUint8 array_type, nsIID *iid)
00445 {
00446        if (array_ptr==NULL) {
00447               Py_INCREF(Py_None);
00448               return Py_None;
00449        }
00450        if (array_type == nsXPTType::T_U8)
00451               return PyString_FromStringAndSize( (char *)array_ptr, sequence_size );
00452 
00453        PRUint32 array_element_size = GetArrayElementSize(array_type);
00454        PyObject *list_ret = PyList_New(sequence_size);
00455        PRUint8 *pthis = (PRUint8 *)array_ptr;
00456        for (PRUint32 i=0; i<sequence_size; i++,pthis += array_element_size) {
00457               PyObject *val = NULL;
00458               switch(array_type) {
00459                        case nsXPTType::T_I8:
00460                             val = PyInt_FromLong( *((PRInt8 *)pthis) );
00461                             break;
00462                        case nsXPTType::T_I16:
00463                             val = PyInt_FromLong( *((PRInt16 *)pthis) );
00464                             break;
00465                        case nsXPTType::T_I32:
00466                             val = PyInt_FromLong( *((PRInt32 *)pthis) );
00467                             break;
00468                        case nsXPTType::T_I64:
00469                             val = PyLong_FromLongLong( *((PRInt64 *)pthis) );
00470                             break;
00471                        // case nsXPTType::T_U8 - handled above!
00472                        case nsXPTType::T_U16:
00473                             val = PyInt_FromLong( *((PRUint16 *)pthis) );
00474                             break;
00475                        case nsXPTType::T_U32:
00476                             val = PyInt_FromLong( *((PRUint32 *)pthis) );
00477                             break;
00478                        case nsXPTType::T_U64:
00479                             val = PyLong_FromUnsignedLongLong( *((PRUint64 *)pthis) );
00480                             break;
00481                        case nsXPTType::T_FLOAT:
00482                             val = PyFloat_FromDouble( *((float*)pthis) );
00483                             break;
00484                        case nsXPTType::T_DOUBLE:
00485                             val = PyFloat_FromDouble( *((double*)pthis) );
00486                             break;
00487                        case nsXPTType::T_BOOL:
00488                             val = (*((PRBool *)pthis)) ? Py_True : Py_False;
00489                             Py_INCREF(val);
00490                             break;
00491                        case nsXPTType::T_IID:
00492                             val = Py_nsIID::PyObjectFromIID( **((nsIID **)pthis) );
00493                             break;
00494 
00495                        case nsXPTType::T_CHAR_STR: {
00496                             char **pp = (char **)pthis;
00497                             if (*pp==NULL) {
00498                                    Py_INCREF(Py_None);
00499                                    val = Py_None;
00500                             } else
00501                                    val = PyString_FromString(*pp);
00502                             break;
00503                             }
00504                        case nsXPTType::T_WCHAR_STR: {
00505                             PRUnichar **pp = (PRUnichar **)pthis;
00506                             if (*pp==NULL) {
00507                                    Py_INCREF(Py_None);
00508                                    val = Py_None;
00509                             } else {
00510                                    val = PyUnicode_FromPRUnichar( *pp, nsCRT::strlen(*pp) );
00511                             }
00512                             break;
00513                             }
00514                        case nsXPTType::T_INTERFACE_IS:
00515                        case nsXPTType::T_INTERFACE: {
00516                             nsISupports **pp = (nsISupports **)pthis;
00517                             val = Py_nsISupports::PyObjectFromInterface(*pp, iid ? *iid : NS_GET_IID(nsISupports), PR_TRUE);
00518                             break;
00519                             }
00520                        default: {
00521                             char buf[128];
00522                             sprintf(buf, "Unknown XPCOM array type flags (0x%x)", array_type);
00523                             PyXPCOM_LogWarning("%s - returning a string object with this message!\n", buf);
00524                             val = PyString_FromString(buf);
00525                             break;
00526                             }
00527               }
00528               if (val==NULL) {
00529                      NS_ABORT_IF_FALSE(PyErr_Occurred(), "NULL result in array conversion, but no error set!");
00530                      return NULL;
00531               }
00532               PyList_SET_ITEM(list_ret, i, val); // ref-count consumed.
00533        }
00534        return list_ret;
00535 }
00536 
00537 
00538 // ------------------------------------------------------------------------
00539 // nsIVariant utilities
00540 // ------------------------------------------------------------------------
00541 struct BVFTResult {
00542        BVFTResult() {pis = NULL;iid=Py_nsIID_NULL;}
00543        nsISupports *pis;
00544        nsIID iid;
00545 };
00546 
00547 static PRUint16 BestVariantTypeForPyObject( PyObject *ob, BVFTResult *pdata = NULL) 
00548 {
00549        nsISupports *ps = NULL;
00550        nsIID iid;
00551        // start with some fast concrete checks.
00552        if (ob==Py_None)
00553               return nsIDataType::VTYPE_EMPTY;
00554        if (ob==Py_True || ob == Py_False)
00555               return nsIDataType::VTYPE_BOOL;
00556        if (PyInt_Check(ob))
00557               return nsIDataType::VTYPE_INT32;
00558        if (PyLong_Check(ob))
00559               return nsIDataType::VTYPE_INT64;
00560        if (PyFloat_Check(ob))
00561               return nsIDataType::VTYPE_DOUBLE;
00562        if (PyString_Check(ob))
00563               return nsIDataType::VTYPE_STRING_SIZE_IS;
00564        if (PyUnicode_Check(ob))
00565               return nsIDataType::VTYPE_WSTRING_SIZE_IS;
00566        if (PyTuple_Check(ob) || PyList_Check(ob)) {
00567               if (PySequence_Length(ob))
00568                      return nsIDataType::VTYPE_ARRAY;
00569               return nsIDataType::VTYPE_EMPTY_ARRAY;
00570        }
00571        // Now do expensive or abstract checks.
00572        if (Py_nsISupports::InterfaceFromPyObject(ob, NS_GET_IID(nsISupports), &ps, PR_TRUE)) {
00573               if (pdata) {
00574                      pdata->pis = ps;
00575                      pdata->iid = NS_GET_IID(nsISupports);
00576               } else
00577                      ps->Release();
00578               return nsIDataType::VTYPE_INTERFACE_IS;
00579        } else
00580               PyErr_Clear();
00581        if (Py_nsIID::IIDFromPyObject(ob, &iid)) {
00582               if (pdata)
00583                      pdata->iid = iid;
00584               return nsIDataType::VTYPE_ID;
00585        } else
00586               PyErr_Clear();
00587        if (PySequence_Check(ob)) {
00588               if (PySequence_Length(ob))
00589                      return nsIDataType::VTYPE_ARRAY;
00590               return nsIDataType::VTYPE_EMPTY_ARRAY;
00591        }
00592        return (PRUint16)-1;
00593 }
00594 
00595 nsIVariant *PyObject_AsVariant( PyObject *ob)
00596 {
00597        nsresult nr = NS_ERROR_UNEXPECTED;
00598        nsCOMPtr<nsIWritableVariant> v = do_CreateInstance("@mozilla.org/variant;1", &nr); 
00599        if (NS_FAILED(nr)) {
00600               PyXPCOM_BuildPyException(nr);
00601               return NULL;
00602        }
00603        // *sigh* - I tried the abstract API (PyNumber_Check, etc)
00604        // but our COM instances too often qualify.
00605        BVFTResult cvt_result;
00606        PRUint16 dt = BestVariantTypeForPyObject(ob, &cvt_result);
00607        switch (dt) {
00608               case nsIDataType::VTYPE_BOOL:
00609                      nr = v->SetAsBool(ob==Py_True);
00610                      break;
00611               case nsIDataType::VTYPE_INT32:
00612                      nr = v->SetAsInt32(PyInt_AsLong(ob));
00613                      break;
00614               case nsIDataType::VTYPE_INT64:
00615                      nr = v->SetAsInt64(PyLong_AsLongLong(ob));
00616                      break;
00617               case nsIDataType::VTYPE_DOUBLE:
00618                      nr = v->SetAsDouble(PyFloat_AsDouble(ob));
00619                      break;
00620               case nsIDataType::VTYPE_STRING_SIZE_IS:
00621                      nr = v->SetAsStringWithSize(PyString_Size(ob), PyString_AsString(ob));
00622                      break;
00623               case nsIDataType::VTYPE_WSTRING_SIZE_IS:
00624                      if (PyUnicode_GetSize(ob) == 0) {
00625                             nr = v->SetAsWStringWithSize(0, (PRUnichar*)NULL);
00626                      }
00627                      else {
00628                             PRUint32 nch;
00629                             PRUnichar *p;
00630                             if (PyUnicode_AsPRUnichar(ob, &p, &nch) < 0) {
00631                                    nr = NS_ERROR_UNEXPECTED;
00632                                    break;
00633                             }
00634                             nr = v->SetAsWStringWithSize(nch, p);
00635                             nsMemory::Free(p);
00636                      }
00637                      break;
00638               case nsIDataType::VTYPE_INTERFACE_IS:
00639               {
00640                      nsISupports *ps = cvt_result.pis;
00641                      nr = v->SetAsInterface(cvt_result.iid, ps);
00642                      if (ps) {
00643                             Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
00644                             ps->Release();
00645                             Py_END_ALLOW_THREADS;
00646                      }
00647                      break;
00648               }
00649               case nsIDataType::VTYPE_ID:
00650                      nr = v->SetAsID(cvt_result.iid);
00651                      break;
00652               case nsIDataType::VTYPE_ARRAY:
00653               {
00654                      int seq_length = PySequence_Length(ob);
00655                      NS_ABORT_IF_FALSE(seq_length!=0, "VTYPE_ARRAY assumes at least one element!");
00656                      PyObject *first = PySequence_GetItem(ob, 0);
00657                      if (!first) break;
00658                      int array_type = BestVariantTypeForPyObject(first);
00659                      Py_DECREF(first);
00660                      // Arrays can't handle all types.  This means we lost embedded NULLs.
00661                      // This should really be fixed in XPCOM.
00662                      if (array_type == nsIDataType::VTYPE_STRING_SIZE_IS) array_type = nsIDataType::VTYPE_CHAR_STR;
00663                      if (array_type == nsIDataType::VTYPE_WSTRING_SIZE_IS) array_type = nsIDataType::VTYPE_WCHAR_STR;
00664                      PRUint32 element_size = GetArrayElementSize(array_type);
00665                      int cb_buffer_pointer = seq_length * element_size;
00666                      void *buffer_pointer;
00667                      if ((buffer_pointer = (void *)nsMemory::Alloc(cb_buffer_pointer)) == nsnull) {
00668                             PyErr_NoMemory();
00669                             nr = NS_ERROR_UNEXPECTED;
00670                             break;
00671                      }
00672                      memset(buffer_pointer, 0, cb_buffer_pointer);
00673                      if (FillSingleArray(buffer_pointer, ob, seq_length, element_size, array_type)) {
00674                             nr = v->SetAsArray(array_type, &NS_GET_IID(nsISupports), seq_length, buffer_pointer);
00675                             FreeSingleArray(buffer_pointer, seq_length, array_type);
00676                      } else
00677                             nr = NS_ERROR_UNEXPECTED;
00678                      nsMemory::Free(buffer_pointer);
00679                      break;
00680               }
00681               case nsIDataType::VTYPE_EMPTY:
00682                      v->SetAsEmpty();
00683                      break;
00684               case nsIDataType::VTYPE_EMPTY_ARRAY:
00685                      v->SetAsEmptyArray();
00686                      break;
00687               case (PRUint16)-1:
00688                      PyErr_Format(PyExc_TypeError, "Objects of type '%s' can not be converted to an nsIVariant", ob->ob_type->tp_name);
00689                      return NULL;
00690               default:
00691                      NS_ABORT_IF_FALSE(0, "BestVariantTypeForPyObject() returned a variant type not handled here!");
00692                      PyErr_Format(PyExc_TypeError, "Objects of type '%s' can not be converted to an nsIVariant", ob->ob_type->tp_name);
00693                      return NULL;
00694        }
00695        nsIVariant *ret;
00696        v->QueryInterface(NS_GET_IID(nsIVariant), (void **)&ret);
00697        return ret;
00698 }
00699 
00700 static PyObject *MyBool_FromBool(PRBool v)
00701 {
00702        PyObject *ret = v ? Py_True : Py_False;
00703        Py_INCREF(ret);
00704        return ret;
00705 }
00706 static PyObject *MyObject_FromInterface(nsISupports *p)
00707 {
00708        return Py_nsISupports::PyObjectFromInterface(p, NS_GET_IID(nsISupports), PR_FALSE);
00709 }
00710 
00711 #define GET_FROM_V(Type, FuncGet, FuncConvert) { \
00712        Type t; \
00713        if (NS_FAILED(nr = FuncGet( &t ))) goto done;\
00714        ret = FuncConvert(t);\
00715        break; \
00716 }
00717 
00718 PyObject *PyObject_FromVariantArray( nsIVariant *v)
00719 {
00720        nsresult nr;
00721        NS_PRECONDITION(v, "NULL variant!");
00722        if (!v)
00723               return PyXPCOM_BuildPyException(NS_ERROR_INVALID_POINTER);
00724 #ifdef NS_DEBUG
00725        PRUint16 dt;
00726        nr = v->GetDataType(&dt);
00727        NS_ABORT_IF_FALSE(dt == nsIDataType::VTYPE_ARRAY, "expected an array variant");
00728 #endif
00729        nsIID iid;
00730        void *p;
00731        PRUint16 type;
00732        PRUint32 count;
00733        nr = v->GetAsArray(&type, &iid, &count, &p);
00734        if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr);
00735        PyObject *ret = UnpackSingleArray(p, count, (PRUint8)type, &iid);
00736        FreeSingleArray(p, count, (PRUint8)type);
00737        nsMemory::Free(p);
00738        return ret;
00739 }
00740 
00741 PyObject *PyObject_FromVariant( nsIVariant *v)
00742 {
00743        if (!v) {
00744               Py_INCREF(Py_None);
00745               return Py_None;
00746        }
00747        PRUint16 dt;
00748        nsresult nr;
00749        PyObject *ret = NULL;
00750        nr = v->GetDataType(&dt);
00751        if (NS_FAILED(nr)) goto done;
00752        switch (dt) {
00753               case nsIDataType::VTYPE_VOID:
00754               case nsIDataType::VTYPE_EMPTY:
00755               case nsIDataType::VTYPE_EMPTY_ARRAY:
00756                      ret = Py_None;
00757                      Py_INCREF(Py_None);
00758                      break;
00759               case nsIDataType::VTYPE_ARRAY:
00760                      ret = PyObject_FromVariantArray(v);
00761                      break;
00762               case nsIDataType::VTYPE_INT8:
00763               case nsIDataType::VTYPE_INT16:
00764               case nsIDataType::VTYPE_INT32:
00765                      GET_FROM_V(PRInt32, v->GetAsInt32, PyInt_FromLong);
00766               case nsIDataType::VTYPE_UINT8:
00767               case nsIDataType::VTYPE_UINT16:
00768               case nsIDataType::VTYPE_UINT32:
00769                      GET_FROM_V(PRUint32, v->GetAsUint32, PyLong_FromUnsignedLong);
00770               case nsIDataType::VTYPE_INT64:
00771                      GET_FROM_V(PRInt64, v->GetAsInt64, PyLong_FromLongLong);
00772               case nsIDataType::VTYPE_UINT64:
00773                      GET_FROM_V(PRUint64, v->GetAsUint64, PyLong_FromUnsignedLongLong);
00774               case nsIDataType::VTYPE_FLOAT:
00775               case nsIDataType::VTYPE_DOUBLE:
00776                      GET_FROM_V(double, v->GetAsDouble, PyFloat_FromDouble);
00777               case nsIDataType::VTYPE_BOOL:
00778                      GET_FROM_V(PRBool, v->GetAsBool, MyBool_FromBool);
00779               default:
00780                      PyXPCOM_LogWarning("Converting variant to Python object - variant type '%d' unknown - using string.\n", dt);
00781               // Fall through to the string case
00782               case nsIDataType::VTYPE_CHAR:
00783               case nsIDataType::VTYPE_CHAR_STR:
00784               case nsIDataType::VTYPE_STRING_SIZE_IS:
00785               case nsIDataType::VTYPE_CSTRING: {
00786                      nsCAutoString s;
00787                      if (NS_FAILED(nr=v->GetAsACString(s))) goto done;
00788                      ret = PyObject_FromNSString(s);
00789                      break;
00790               }
00791               case nsIDataType::VTYPE_WCHAR:
00792               case nsIDataType::VTYPE_DOMSTRING:
00793               case nsIDataType::VTYPE_WSTRING_SIZE_IS:
00794               case nsIDataType::VTYPE_ASTRING: {
00795                      nsAutoString s;
00796                      if (NS_FAILED(nr=v->GetAsAString(s))) goto done;
00797                      ret = PyObject_FromNSString(s);
00798                      break;
00799               }
00800               case nsIDataType::VTYPE_ID:
00801                      GET_FROM_V(nsIID, v->GetAsID, Py_nsIID::PyObjectFromIID);
00802               case nsIDataType::VTYPE_INTERFACE:
00803                      GET_FROM_V(nsISupports *, v->GetAsISupports, MyObject_FromInterface);
00804               case nsIDataType::VTYPE_INTERFACE_IS: {
00805                      nsISupports *p;
00806                      nsIID *iid;
00807                      if (NS_FAILED(nr=v->GetAsInterface(&iid, (void **)&p))) goto done;
00808                      ret = Py_nsISupports::PyObjectFromInterface(p, *iid, PR_FALSE);
00809                      break;
00810               // case nsIDataType::VTYPE_WCHAR_STR
00811               // case nsIDataType::VTYPE_UTF8STRING
00812               }
00813        }
00814 done:
00815        if (NS_FAILED(nr)) {
00816               NS_ABORT_IF_FALSE(ret==NULL, "Have an error, but also a return val!");
00817               PyXPCOM_BuildPyException(nr);
00818        }
00819        return ret;
00820 }
00821 
00822 // ------------------------------------------------------------------------
00823 // TypeDescriptor helper class
00824 // ------------------------------------------------------------------------
00825 class PythonTypeDescriptor {
00826 public:
00827        PythonTypeDescriptor() {
00828               param_flags = type_flags = argnum = argnum2 = 0;
00829               extra = NULL;
00830               is_auto_out = PR_FALSE;
00831               is_auto_in = PR_FALSE;
00832               have_set_auto = PR_FALSE;
00833        }
00834        ~PythonTypeDescriptor() {
00835               Py_XDECREF(extra);
00836        }
00837        PRUint8 param_flags;
00838        PRUint8 type_flags;
00839        PRUint8 argnum;                 /* used for iid_is and size_is */
00840        PRUint8 argnum2;                /* used for length_is */
00841        PyObject *extra; // The IID object, or the type of the array.
00842        // Extra items to help our processing.
00843        // Is this auto-filled by some other "in" param?
00844        PRBool is_auto_in;
00845        // Is this auto-filled by some other "out" param?
00846        PRBool is_auto_out;
00847        // If is_auto_out, have I already filled it?  Used when multiple
00848        // params share a size_is fields - first time sets it, subsequent
00849        // time check it.
00850        PRBool have_set_auto; 
00851 };
00852 
00853 static int ProcessPythonTypeDescriptors(PythonTypeDescriptor *pdescs, int num)
00854 {
00855        // Loop over the array, checking all the params marked as having an arg.
00856        // If these args nominate another arg as the size_is param, then
00857        // we reset the size_is param to _not_ requiring an arg.
00858        int i;
00859        for (i=0;i<num;i++) {
00860               PythonTypeDescriptor &ptd = pdescs[i];
00861               // Can't use XPT_TDP_TAG() - it uses a ".flags" reference in the macro.
00862               switch (ptd.type_flags & XPT_TDP_TAGMASK) {
00863                      case nsXPTType::T_ARRAY:
00864                             NS_ABORT_IF_FALSE(ptd.argnum < num, "Bad dependent index");
00865                             if (ptd.argnum2 < num) {
00866                                    if (XPT_PD_IS_IN(ptd.param_flags))
00867                                           pdescs[ptd.argnum2].is_auto_in = PR_TRUE;
00868                                    if (XPT_PD_IS_OUT(ptd.param_flags))
00869                                           pdescs[ptd.argnum2].is_auto_out = PR_TRUE;
00870                             }
00871                             break;
00872                      case nsXPTType::T_PSTRING_SIZE_IS:
00873                      case nsXPTType::T_PWSTRING_SIZE_IS:
00874                             NS_ABORT_IF_FALSE(ptd.argnum < num, "Bad dependent index");
00875                             if (ptd.argnum < num) {
00876                                    if (XPT_PD_IS_IN(ptd.param_flags))
00877                                           pdescs[ptd.argnum].is_auto_in = PR_TRUE;
00878                                    if (XPT_PD_IS_OUT(ptd.param_flags))
00879                                           pdescs[ptd.argnum].is_auto_out = PR_TRUE;
00880                             }
00881                             break;
00882                      default:
00883                             break;
00884               }
00885        }
00886        int total_params_needed = 0;
00887        for (i=0;i<num;i++)
00888               if (XPT_PD_IS_IN(pdescs[i].param_flags) && !pdescs[i].is_auto_in && !XPT_PD_IS_DIPPER(pdescs[i].param_flags))
00889                      total_params_needed++;
00890 
00891        return total_params_needed;
00892 }
00893 
00894 /*************************************************************************
00895 **************************************************************************
00896 
00897 Helpers when CALLING interfaces.
00898 
00899 **************************************************************************
00900 *************************************************************************/
00901 
00902 PyXPCOM_InterfaceVariantHelper::PyXPCOM_InterfaceVariantHelper()
00903 {
00904        m_var_array=nsnull;
00905        m_buffer_array=nsnull;
00906        m_pyparams=nsnull;
00907        m_num_array = 0;
00908 }
00909 
00910 PyXPCOM_InterfaceVariantHelper::~PyXPCOM_InterfaceVariantHelper()
00911 {
00912        Py_XDECREF(m_pyparams);
00913        for (int i=0;i<m_num_array;i++) {
00914               if (m_var_array) {
00915                      nsXPTCVariant &ns_v = m_var_array[i];
00916                      if (ns_v.IsValInterface()) {
00917                             if (ns_v.val.p) {
00918                                    Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
00919                                    ((nsISupports *)ns_v.val.p)->Release();
00920                                    Py_END_ALLOW_THREADS;
00921                             }
00922                      }
00923                      if (ns_v.IsValDOMString() && ns_v.val.p) {
00924                             delete (const nsAString *)ns_v.val.p;
00925                      }
00926                      if (ns_v.IsValCString() && ns_v.val.p) {
00927                             delete (const nsACString *)ns_v.val.p;
00928                      }
00929                      if (ns_v.IsValUTF8String() && ns_v.val.p) {
00930                             delete (const nsACString *)ns_v.val.p;
00931                      }
00932                      if (ns_v.IsValArray()) {
00933                             nsXPTCVariant &ns_v = m_var_array[i];
00934                             if (ns_v.val.p) {
00935                                    PRUint8 array_type = (PRUint8)PyInt_AsLong(m_python_type_desc_array[i].extra);
00936                                    PRUint32 seq_size = GetSizeIs(i, PR_FALSE);
00937                                    FreeSingleArray(ns_v.val.p, seq_size, array_type);
00938                             }
00939                      }
00940                      // IsOwned must be the last check of the loop, as
00941                      // this frees the underlying data used above (eg, by the array free process)
00942                      if (ns_v.IsValAllocated() && !ns_v.IsValInterface() && !ns_v.IsValDOMString()) {
00943                             NS_ABORT_IF_FALSE(ns_v.IsPtrData(), "expecting a pointer to free");
00944                             nsMemory::Free(ns_v.val.p);
00945                      }
00946               }
00947               if (m_buffer_array && m_buffer_array[i])
00948                      nsMemory::Free(m_buffer_array[i]);
00949        }
00950        delete [] m_python_type_desc_array;
00951        delete [] m_buffer_array;
00952        delete [] m_var_array;
00953 }
00954 
00955 PRBool PyXPCOM_InterfaceVariantHelper::Init(PyObject *obParams)
00956 {
00957        PRBool ok = PR_FALSE;
00958        int i;
00959        int total_params_needed = 0;
00960        if (!PySequence_Check(obParams) || PySequence_Length(obParams)!=2) {
00961               PyErr_Format(PyExc_TypeError, "Param descriptors must be a sequence of exactly length 2");
00962               return PR_FALSE;
00963        }
00964        PyObject *typedescs = PySequence_GetItem(obParams, 0);
00965        if (typedescs==NULL)
00966               return PR_FALSE;
00967        // NOTE: The length of the typedescs may be different than the
00968        // args actually passed.  The typedescs always include all
00969        // hidden params (such as "size_is"), while the actual 
00970        // args never include this.
00971        m_num_array = PySequence_Length(typedescs);
00972        if (PyErr_Occurred()) goto done;
00973 
00974        m_pyparams = PySequence_GetItem(obParams, 1);
00975        if (m_pyparams==NULL) goto done;
00976 
00977        m_python_type_desc_array = new PythonTypeDescriptor[m_num_array];
00978        if (!m_python_type_desc_array) goto done;
00979 
00980        // Pull apart the type descs and stash them.
00981        for (i=0;i<m_num_array;i++) {
00982               PyObject *desc_object = PySequence_GetItem(typedescs, i);
00983               if (desc_object==NULL)
00984                      goto done;
00985 
00986               // Pull apart the typedesc tuple back into a structure we can work with.
00987               PythonTypeDescriptor &ptd = m_python_type_desc_array[i];
00988               PRBool this_ok = PyArg_ParseTuple(desc_object, "bbbbO:type_desc", 
00989                                    &ptd.param_flags, &ptd.type_flags, &ptd.argnum, &ptd.argnum2, &ptd.extra);
00990               Py_DECREF(desc_object);
00991               if (!this_ok) goto done;
00992               Py_INCREF(ptd.extra);
00993 
00994        }
00995        total_params_needed = ProcessPythonTypeDescriptors(m_python_type_desc_array, m_num_array);
00996        // OK - check we got the number of args we expected.
00997        // If not, its really an internal error rather than the user.
00998        if (PySequence_Length(m_pyparams) != total_params_needed) {
00999               PyErr_Format(PyExc_ValueError, "The type descriptions indicate %d args are needed, but %d were provided",
01000                      total_params_needed, PySequence_Length(m_pyparams));
01001               goto done;
01002        }
01003 
01004        // Init the other arrays.
01005        m_var_array = new nsXPTCVariant[m_num_array];
01006        if (!m_var_array) goto done;
01007        memset(m_var_array, 0, m_num_array * sizeof(m_var_array[0]));
01008 
01009        m_buffer_array = new void *[m_num_array];
01010        if (!m_buffer_array) goto done;
01011        memset(m_buffer_array, 0, m_num_array * sizeof(m_buffer_array[0]));
01012 
01013        ok = PR_TRUE;
01014 done:
01015        if (!ok && !PyErr_Occurred())
01016               PyErr_NoMemory();
01017 
01018        Py_XDECREF(typedescs);
01019        return ok;
01020 }
01021 
01022 
01023 PRBool PyXPCOM_InterfaceVariantHelper::FillArray()
01024 {
01025        int param_index = 0;
01026        int i;
01027        for (i=0;i<m_num_array;i++) {
01028               PythonTypeDescriptor &ptd = m_python_type_desc_array[i];
01029               // stash the type_flags into the variant, and remember how many extra bits of info we have.
01030               m_var_array[i].type = ptd.type_flags;
01031               if (XPT_PD_IS_IN(ptd.param_flags) && !ptd.is_auto_in && !XPT_PD_IS_DIPPER(ptd.param_flags)) {
01032                      if (!FillInVariant(ptd, i, param_index))
01033                             return PR_FALSE;
01034                      param_index++;
01035               }
01036               if ((XPT_PD_IS_OUT(ptd.param_flags) && !ptd.is_auto_out) || XPT_PD_IS_DIPPER(ptd.param_flags)) {
01037                      if (!PrepareOutVariant(ptd, i))
01038                             return PR_FALSE;
01039               }
01040        }
01041        // There may be out "size_is" params we havent touched yet
01042        // (ie, as the param itself is marked "out", we never got to
01043        // touch the associated "size_is".
01044        // Final loop to handle this.
01045        for (i=0;i<m_num_array;i++) {
01046               PythonTypeDescriptor &ptd = m_python_type_desc_array[i];
01047               if (ptd.is_auto_out && !ptd.have_set_auto) {
01048                      // Call PrepareOutVariant to ensure buffers etc setup.
01049                      if (!PrepareOutVariant(ptd, i))
01050                             return PR_FALSE;
01051               }
01052        }
01053        return PR_TRUE;
01054 }
01055 
01056 
01057 PRBool PyXPCOM_InterfaceVariantHelper::SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size)
01058 {
01059        NS_ABORT_IF_FALSE(var_index < m_num_array, "var_index param is invalid");
01060        PRUint8 argnum = is_arg1 ? 
01061               m_python_type_desc_array[var_index].argnum :
01062               m_python_type_desc_array[var_index].argnum2;
01063        NS_ABORT_IF_FALSE(argnum < m_num_array, "size_is param is invalid");
01064        PythonTypeDescriptor &td_size = m_python_type_desc_array[argnum];
01065        NS_ABORT_IF_FALSE(td_size.is_auto_in || td_size.is_auto_out, "Setting size_is, but param is not marked as auto!");
01066        NS_ABORT_IF_FALSE( (td_size.type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32");
01067        nsXPTCVariant &ns_v = m_var_array[argnum];
01068 
01069        if (!td_size.have_set_auto) {
01070               ns_v.type = td_size.type_flags;
01071               ns_v.val.u32 = new_size;
01072               // In case it is "out", setup the necessary pointers.
01073               PrepareOutVariant(td_size, argnum);
01074               td_size.have_set_auto = PR_TRUE;
01075        } else {
01076               if (ns_v.val.u32 != new_size) {
01077                      PyErr_Format(PyExc_ValueError, "Array lengths inconsistent; array size previously set to %d, but second array is of size %d", ns_v.val.u32, new_size);
01078                      return PR_FALSE;
01079               }
01080        }
01081        return PR_TRUE;
01082 }
01083 
01084 PRUint32 PyXPCOM_InterfaceVariantHelper::GetSizeIs( int var_index, PRBool is_arg1)
01085 {
01086        NS_ABORT_IF_FALSE(var_index < m_num_array, "var_index param is invalid");
01087        PRUint8 argnum = is_arg1 ? 
01088               m_python_type_desc_array[var_index].argnum :
01089               m_python_type_desc_array[var_index].argnum2;
01090        NS_ABORT_IF_FALSE(argnum < m_num_array, "size_is param is invalid");
01091        NS_ABORT_IF_FALSE( (m_python_type_desc_array[argnum].type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32");
01092        PRBool is_out = XPT_PD_IS_OUT(m_python_type_desc_array[argnum].param_flags);
01093        nsXPTCVariant &ns_v = m_var_array[argnum];
01094        return is_out ? *((PRUint32 *)ns_v.ptr) : ns_v.val.u32;
01095 }
01096 
01097 #define MAKE_VALUE_BUFFER(size) \
01098        if ((this_buffer_pointer = (void *)nsMemory::Alloc((size))) == nsnull) { \
01099               PyErr_NoMemory(); \
01100               BREAK_FALSE; \
01101        }
01102 
01103 PRBool PyXPCOM_InterfaceVariantHelper::FillInVariant(const PythonTypeDescriptor &td, int value_index, int param_index)
01104 {
01105        PRBool rc = PR_TRUE;
01106        // Get a reference to the variant we are filling for convenience.
01107        nsXPTCVariant &ns_v = m_var_array[value_index];
01108        NS_ABORT_IF_FALSE(ns_v.type == td.type_flags, "Expecting variant all setup for us");
01109 
01110        // We used to avoid passing internal buffers to PyString etc objects
01111        // for 2 reasons: paranoia (so incorrect external components couldn't break
01112        // Python) and simplicity (in vs in-out issues, etc)
01113        // However, at least one C++ implemented component (nsITimelineService)
01114        // uses a "char *", and keys on the address (assuming that the same
01115        // *pointer* is passed rather than value.  Therefore, we have a special case
01116        // - T_CHAR_STR that is "in" gets the Python string pointer passed.
01117        void *&this_buffer_pointer = m_buffer_array[value_index]; // Freed at object destruction with PyMem_Free()
01118        NS_ABORT_IF_FALSE(this_buffer_pointer==nsnull, "We appear to already have a buffer");
01119        int cb_this_buffer_pointer = 0;
01120        if (XPT_PD_IS_IN(td.param_flags)) {
01121               NS_ABORT_IF_FALSE(!td.is_auto_in, "Param is 'auto-in', but we are filling it normally!");
01122               PyObject *val_use = NULL; // a temp object converters can use, and will be DECREF'd
01123               PyObject *val = PySequence_GetItem(m_pyparams, param_index);
01124               NS_WARN_IF_FALSE(val, "Have an 'in' param, but no Python value!");
01125               if (val==NULL) {
01126                      PyErr_Format(PyExc_ValueError, "Param %d is marked as 'in', but no value was given", value_index);
01127                      return PR_FALSE;
01128               }
01129               switch (XPT_TDP_TAG(ns_v.type)) {
01130                 case nsXPTType::T_I8:
01131                      if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
01132                      ns_v.val.i8 = (PRInt8)PyInt_AsLong(val_use);
01133                      break;
01134                 case nsXPTType::T_I16:
01135                      if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
01136                      ns_v.val.i16 = (PRInt16)PyInt_AsLong(val_use);
01137                      break;
01138                 case nsXPTType::T_I32:
01139                      if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
01140                      ns_v.val.i32 = (PRInt32)PyInt_AsLong(val_use);
01141                      break;
01142                 case nsXPTType::T_I64:
01143                      if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE
01144                      ns_v.val.i64 = (PRInt64)PyLong_AsLongLong(val_use);
01145                      break;
01146                 case nsXPTType::T_U8:
01147                      if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
01148                      ns_v.val.u8 = (PRUint8)PyInt_AsLong(val_use);
01149                      break;
01150                 case nsXPTType::T_U16:
01151                      if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
01152                      ns_v.val.u16 = (PRUint16)PyInt_AsLong(val_use);
01153                      break;
01154                 case nsXPTType::T_U32:
01155                      if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
01156                      ns_v.val.u32 = (PRUint32)PyInt_AsLong(val_use);
01157                      break;
01158                 case nsXPTType::T_U64:
01159                      if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE
01160                      ns_v.val.u64 = (PRUint64)PyLong_AsUnsignedLongLong(val_use);
01161                      break;
01162                 case nsXPTType::T_FLOAT:
01163                      if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
01164                      ns_v.val.f = (float)PyFloat_AsDouble(val_use);
01165                      break;
01166                 case nsXPTType::T_DOUBLE:
01167                      if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
01168                      ns_v.val.d = PyFloat_AsDouble(val_use);
01169                      break;
01170                 case nsXPTType::T_BOOL:
01171                      if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
01172                      ns_v.val.b = (PRBool)PyInt_AsLong(val_use);
01173                      break;
01174                 case nsXPTType::T_CHAR:{
01175                      if (!PyString_Check(val) && !PyUnicode_Check(val)) {
01176                             PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
01177                             BREAK_FALSE;
01178                      }
01179                      if ((val_use = PyObject_Str(val))==NULL)
01180                             BREAK_FALSE;
01181                      // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
01182                      NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
01183                      if (PyString_GET_SIZE(val_use) != 1) {
01184                             PyErr_SetString(PyExc_ValueError, "Must specify a one character string for a character");
01185                             BREAK_FALSE;
01186                      }
01187 
01188                      ns_v.val.c = *PyString_AS_STRING(val_use);
01189                      break;
01190                      }
01191 
01192                 case nsXPTType::T_WCHAR: {
01193                      if (!PyString_Check(val) && !PyUnicode_Check(val)) {
01194                             PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
01195                             BREAK_FALSE;
01196                      }
01197                      if ((val_use = PyUnicode_FromObject(val))==NULL)
01198                             BREAK_FALSE;
01199                      // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
01200                      NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a unicode object!");
01201                      if (PyUnicode_GetSize(val_use) != 1) {
01202                             PyErr_SetString(PyExc_ValueError, "Must specify a one character string for a character");
01203                             BREAK_FALSE;
01204                      }
01205                      // Lossy!
01206                      ns_v.val.wc = *PyUnicode_AS_UNICODE(val_use);
01207                      break;
01208                      }
01209        //          case nsXPTType::T_VOID:              /* fall through */
01210                 case nsXPTType::T_IID:
01211                      nsIID iid;
01212                      MAKE_VALUE_BUFFER(sizeof(nsIID));
01213                      if (!Py_nsIID::IIDFromPyObject(val, &iid))
01214                             BREAK_FALSE;
01215                      memcpy(this_buffer_pointer, &iid, sizeof(iid));
01216                      ns_v.val.p = this_buffer_pointer;
01217                      break;
01218                 case nsXPTType::T_ASTRING:
01219                 case nsXPTType::T_DOMSTRING: {
01220                      if (val==Py_None) {
01221                             ns_v.val.p = new nsString();
01222                      } else {
01223                             if (!PyString_Check(val) && !PyUnicode_Check(val)) {
01224                                    PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
01225                                    BREAK_FALSE;
01226                             }
01227                             if ((val_use = PyUnicode_FromObject(val))==NULL)
01228                                    BREAK_FALSE;
01229                             // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
01230                             NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a unicode object!");
01231                             if (PyUnicode_GET_SIZE(val_use) == 0) {
01232                                    ns_v.val.p = new nsString();
01233                             }
01234                             else {
01235                                    PRUint32 nch;
01236                                    PRUnichar *tempo;
01237                                    if (PyUnicode_AsPRUnichar(val_use, &tempo, &nch) < 0)
01238                                           BREAK_FALSE;
01239                                    ns_v.val.p = new nsString(tempo, nch);
01240                                    nsMemory::Free(tempo);
01241                             }
01242                      }
01243                      if (!ns_v.val.p) {
01244                             PyErr_NoMemory();
01245                             BREAK_FALSE;
01246                      }
01247                      // We created it - flag as such for cleanup.
01248                      ns_v.flags |= nsXPTCVariant::VAL_IS_DOMSTR;
01249                      break;
01250                 }
01251                 case nsXPTType::T_CSTRING:
01252                 case nsXPTType::T_UTF8STRING: {
01253                      PRBool bIsUTF8 = XPT_TDP_TAG(ns_v.type) == nsXPTType::T_UTF8STRING;
01254                      if (val==Py_None) {
01255                             ns_v.val.p = new nsCString();
01256                      } else {
01257                             // strings are assumed to already be UTF8 encoded.
01258                             if (PyString_Check(val)) {
01259                                    val_use = val;
01260                                    Py_INCREF(val);
01261                             // Unicode objects are encoded by us.
01262                             } else if (PyUnicode_Check(val)) {
01263                                    if (bIsUTF8)
01264                                           val_use = PyUnicode_AsUTF8String(val);
01265                                    else
01266                                           val_use = PyObject_Str(val);
01267                             } else {
01268                                    PyErr_SetString(PyExc_TypeError, "UTF8 parameters must be string or Unicode objects");
01269                                    BREAK_FALSE;
01270                             }
01271                             if (!val_use)
01272                                    BREAK_FALSE;
01273                             ns_v.val.p = new nsCString(PyString_AS_STRING(val_use), 
01274                                                        PyString_GET_SIZE(val_use));
01275                      }
01276 
01277                      if (!ns_v.val.p) {
01278                             PyErr_NoMemory();
01279                             BREAK_FALSE;
01280                      }
01281                      // We created it - flag as such for cleanup.
01282                      ns_v.flags |= bIsUTF8 ? nsXPTCVariant::VAL_IS_UTF8STR : nsXPTCVariant::VAL_IS_CSTR;
01283                      break;
01284                      }
01285                 case nsXPTType::T_CHAR_STR: {
01286                      if (val==Py_None) {
01287                             ns_v.val.p = nsnull;
01288                             break;
01289                      }
01290                      // If an "in" char *, and we have a PyString, then pass the
01291                      // pointer (hoping everyone else plays by the rules too.
01292                      if (!XPT_PD_IS_OUT(td.param_flags) && PyString_Check(val)) {
01293                             ns_v.val.p = PyString_AS_STRING(val);
01294                             break;
01295                      }
01296                         
01297                      if (!PyString_Check(val) && !PyUnicode_Check(val)) {
01298                             PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
01299                             BREAK_FALSE;
01300                      }
01301                      if ((val_use = PyObject_Str(val))==NULL)
01302                             BREAK_FALSE;
01303                      // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
01304                      NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
01305 
01306                      cb_this_buffer_pointer = PyString_GET_SIZE(val_use)+1;
01307                      MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
01308                      memcpy(this_buffer_pointer, PyString_AS_STRING(val_use), cb_this_buffer_pointer);
01309                      ns_v.val.p = this_buffer_pointer;
01310                      break;
01311                      }
01312 
01313                 case nsXPTType::T_WCHAR_STR: {
01314                      if (val==Py_None) {
01315                             ns_v.val.p = nsnull;
01316                             break;
01317                      }
01318                      if (!PyString_Check(val) && !PyUnicode_Check(val)) {
01319                             PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
01320                             BREAK_FALSE;
01321                      }
01322                      if ((val_use = PyUnicode_FromObject(val))==NULL)
01323                             BREAK_FALSE;
01324                      NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!");
01325                      PRUnichar *sv;
01326                      PRUint32 nch;
01327                      if (PyUnicode_AsPRUnichar(val_use, &sv, &nch) < 0)
01328                             BREAK_FALSE;
01329                      cb_this_buffer_pointer = (nch + 1) * sizeof(PRUnichar);
01330                      this_buffer_pointer = sv;
01331                      ns_v.val.p = this_buffer_pointer;
01332                      break;
01333                      }
01334                 case nsXPTType::T_INTERFACE:  {
01335                      nsIID iid;
01336                      if (!Py_nsIID::IIDFromPyObject(td.extra, &iid))
01337                             BREAK_FALSE;
01338                      if (!Py_nsISupports::InterfaceFromPyObject(
01339                                             val, 
01340                                             iid, 
01341                                             (nsISupports **)&ns_v.val.p, 
01342                                             PR_TRUE))
01343                             BREAK_FALSE;
01344                      // We have added a reference - flag as such for cleanup.
01345                      ns_v.flags |= nsXPTCVariant::VAL_IS_IFACE;
01346                      break;
01347                      }
01348                 case nsXPTType::T_INTERFACE_IS: {
01349                      nsIID iid;
01350                      nsXPTCVariant &ns_viid = m_var_array[td.argnum];
01351                      NS_WARN_IF_FALSE(XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID, "The INTERFACE_IS iid describer isnt an IID!");
01352                      // This is a pretty serious problem, but not Python's fault!
01353                      // Just return an nsISupports and hope the caller does whatever
01354                      // QI they need before using it.
01355                      if (XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID &&
01356                          XPT_PD_IS_IN(ns_viid.type)) {
01357                             nsIID *piid = (nsIID *)ns_viid.val.p;
01358                             if (piid==NULL)
01359                                    // Also serious, but like below, not our fault!
01360                                    iid = NS_GET_IID(nsISupports);
01361                             else
01362                                    iid = *piid;
01363                      } else
01364                             // Use NULL IID to avoid a QI in this case.
01365                             iid = Py_nsIID_NULL;
01366                      if (!Py_nsISupports::InterfaceFromPyObject(
01367                                            val, 
01368                                            iid, 
01369                                             (nsISupports **)&ns_v.val.p, 
01370                                             PR_TRUE))
01371                             BREAK_FALSE;
01372                      // We have added a reference - flag as such for cleanup.
01373                      ns_v.flags |= nsXPTCVariant::VAL_IS_IFACE;
01374                      break;
01375                      }
01376                 case nsXPTType::T_PSTRING_SIZE_IS: {
01377                      if (val==Py_None) {
01378                             ns_v.val.p = nsnull;
01379                             break;
01380                      }
01381                      if (!PyString_Check(val) && !PyUnicode_Check(val)) {
01382                             PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
01383                             BREAK_FALSE;
01384                      }
01385                      if ((val_use = PyObject_Str(val))==NULL)
01386                             BREAK_FALSE;
01387                      // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
01388                      NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
01389 
01390                      cb_this_buffer_pointer = PyString_GET_SIZE(val_use);
01391                      MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
01392                      memcpy(this_buffer_pointer, PyString_AS_STRING(val_use), cb_this_buffer_pointer);
01393                      ns_v.val.p = this_buffer_pointer;
01394                      rc = SetSizeIs(value_index, PR_TRUE, cb_this_buffer_pointer);
01395                      break;
01396                      }
01397 
01398               case nsXPTType::T_PWSTRING_SIZE_IS: {
01399                      if (val==Py_None) {
01400                             ns_v.val.p = nsnull;
01401                             break;
01402                      }
01403                      if (!PyString_Check(val) && !PyUnicode_Check(val)) {
01404                             PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
01405                             BREAK_FALSE;
01406                      }
01407                      if ((val_use = PyUnicode_FromObject(val))==NULL)
01408                             BREAK_FALSE;
01409                      // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
01410                      NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyObject_Unicode didnt return a unicode object!");
01411                      PRUnichar *sv;
01412                      PRUint32 nch;
01413                      if (PyUnicode_AsPRUnichar(val_use, &sv, &nch) < 0)
01414                             BREAK_FALSE;
01415                      cb_this_buffer_pointer = (nch + 1) * sizeof(PRUnichar);
01416                      this_buffer_pointer = sv;
01417                      ns_v.val.p = this_buffer_pointer;
01418                      rc = SetSizeIs(value_index, PR_TRUE, nch);
01419                      break;
01420                      }
01421               case nsXPTType::T_ARRAY: {
01422                      if (val==Py_None) {
01423                             ns_v.val.p = nsnull;
01424                             break;
01425                      }
01426                      if (!PyInt_Check(td.extra)) {
01427                             PyErr_SetString(PyExc_TypeError, "The array info is not valid");
01428                             BREAK_FALSE;
01429                      }
01430                      if (!PySequence_Check(val)) {
01431                             PyErr_SetString(PyExc_TypeError, "This parameter must be a sequence");
01432                             BREAK_FALSE;
01433                      }
01434                      int array_type = PyInt_AsLong(td.extra);
01435                      PRUint32 element_size = GetArrayElementSize(array_type);
01436                      int seq_length = PySequence_Length(val);
01437                      cb_this_buffer_pointer = seq_length * element_size;
01438                      if (cb_this_buffer_pointer==0) 
01439                             // prevent assertions allocing zero bytes.  Can't use NULL.
01440                             cb_this_buffer_pointer = 1; 
01441                      MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
01442                      memset(this_buffer_pointer, 0, cb_this_buffer_pointer);
01443                      rc = FillSingleArray(this_buffer_pointer, val, seq_length, element_size, array_type&XPT_TDP_TAGMASK);
01444                      if (!rc) break;
01445                      rc = SetSizeIs(value_index, PR_FALSE, seq_length);
01446                      if (!rc) break;
01447                      ns_v.flags |= nsXPTCVariant::VAL_IS_ARRAY;
01448                      ns_v.val.p = this_buffer_pointer;
01449                      break;
01450                      }
01451               default:
01452                      PyErr_Format(PyExc_TypeError, "The object type (0x%x) is unknown", XPT_TDP_TAG(ns_v.type));
01453                      rc = PR_FALSE;
01454                      break;
01455               }
01456               Py_DECREF(val); // Cant be NULL!
01457               Py_XDECREF(val_use);
01458        }
01459        return rc && !PyErr_Occurred();
01460 }
01461 
01462 PRBool PyXPCOM_InterfaceVariantHelper::PrepareOutVariant(const PythonTypeDescriptor &td, int value_index)
01463 {
01464        PRBool rc = PR_TRUE;
01465        nsXPTCVariant &ns_v = m_var_array[value_index];
01466        void *&this_buffer_pointer = m_buffer_array[value_index]; // Freed at object destruction with PyMem_Free()
01467        // Do the out param thang...
01468        if (XPT_PD_IS_OUT(td.param_flags) || XPT_PD_IS_DIPPER(td.param_flags)) {
01469               NS_ABORT_IF_FALSE(ns_v.ptr == NULL, "already have a pointer!");
01470               ns_v.ptr = &ns_v;
01471               ns_v.flags |= nsXPTCVariant::PTR_IS_DATA;
01472 
01473               // Special flags based on the data type
01474               switch (XPT_TDP_TAG(ns_v.type)) {
01475                 case nsXPTType::T_I8:
01476                 case nsXPTType::T_I16:
01477                 case nsXPTType::T_I32:
01478                 case nsXPTType::T_I64:
01479                 case nsXPTType::T_U8:
01480                 case nsXPTType::T_U16:
01481                 case nsXPTType::T_U32:
01482                 case nsXPTType::T_U64:
01483                 case nsXPTType::T_FLOAT:
01484                 case nsXPTType::T_DOUBLE:
01485                 case nsXPTType::T_BOOL:
01486                 case nsXPTType::T_CHAR:
01487                 case nsXPTType::T_WCHAR:
01488                 case nsXPTType::T_VOID:
01489                      break;
01490 
01491                 case nsXPTType::T_INTERFACE:
01492                 case nsXPTType::T_INTERFACE_IS:
01493                      NS_ABORT_IF_FALSE(this_buffer_pointer==NULL, "Can't have an interface and a buffer pointer!");
01494                      ns_v.flags |= nsXPTCVariant::VAL_IS_IFACE;
01495                      ns_v.flags |= nsXPTCVariant::VAL_IS_ALLOCD;
01496                      break;
01497                 case nsXPTType::T_ARRAY:
01498                      ns_v.flags |= nsXPTCVariant::VAL_IS_ARRAY;
01499                      ns_v.flags |= nsXPTCVariant::VAL_IS_ALLOCD;
01500                      // Even if ns_val.p already setup as part of "in" processing,
01501                      // we need to ensure setup for out.
01502                      NS_ABORT_IF_FALSE(ns_v.val.p==nsnull || ns_v.val.p==this_buffer_pointer, "Garbage in our pointer?");
01503                      ns_v.val.p = this_buffer_pointer;
01504                      this_buffer_pointer = nsnull;
01505                      break;
01506                 case nsXPTType::T_PWSTRING_SIZE_IS:
01507                 case nsXPTType::T_PSTRING_SIZE_IS:
01508                 case nsXPTType::T_WCHAR_STR:
01509                 case nsXPTType::T_CHAR_STR:
01510                 case nsXPTType::T_IID:
01511                      // If we stashed a value in the this_buffer_pointer, and
01512                      // we are passing it as an OUT param, we do _not_ want to
01513                      // treat it as a temporary buffer.
01514                      // For example, if we pass an IID or string as an IN param,
01515                      // we allocate a buffer for the value, but this is NOT cleaned up
01516                      // via normal VARIANT cleanup rules - hence we clean it up ourselves.
01517                      // If the param is IN/OUT, then the buffer falls under the normal variant
01518                      // rules (ie, is flagged as VAL_IS_ALLOCD), so we dont clean it as a temporary.
01519                      // (it may have been changed under us - we free the _new_ value.
01520                      // Even if ns_val.p already setup as part of "in" processing,
01521                      // we need to ensure setup for out.
01522                      NS_ABORT_IF_FALSE(ns_v.val.p==nsnull || ns_v.val.p==this_buffer_pointer, "Garbage in our pointer?");
01523                      ns_v.val.p = this_buffer_pointer;
01524                      ns_v.flags |= nsXPTCVariant::VAL_IS_ALLOCD;
01525                      this_buffer_pointer = nsnull;
01526                      break;
01527                 case nsXPTType::T_DOMSTRING:
01528                 case nsXPTType::T_ASTRING: {
01529                        NS_ABORT_IF_FALSE(ns_v.val.p==nsnull, "T_DOMTSTRINGS cant be out and have a value (ie, no in/outs are allowed!");
01530                        NS_ABORT_IF_FALSE(XPT_PD_IS_DIPPER(td.param_flags) && XPT_PD_IS_IN(td.param_flags), "out DOMStrings must really be in dippers!");
01531                        ns_v.flags |= nsXPTCVariant::VAL_IS_DOMSTR;
01532                        // Dippers are really treated like "in" params.
01533                        ns_v.ptr = new nsString();
01534                        ns_v.val.p = ns_v.ptr; // VAL_IS_* says the .p is what gets freed
01535                        if (!ns_v.ptr) {
01536                               PyErr_NoMemory();
01537                               rc = PR_FALSE;
01538                        }
01539                        break;
01540                      }
01541                 case nsXPTType::T_CSTRING:
01542                 case nsXPTType::T_UTF8STRING: {
01543                        NS_ABORT_IF_FALSE(ns_v.val.p==nsnull, "T_DOMTSTRINGS cant be out and have a value (ie, no in/outs are allowed!");
01544                        NS_ABORT_IF_FALSE(XPT_PD_IS_DIPPER(td.param_flags) && XPT_PD_IS_IN(td.param_flags), "out DOMStrings must really be in dippers!");
01545                        ns_v.flags |= ( XPT_TDP_TAG(ns_v.type)==nsXPTType::T_CSTRING ? nsXPTCVariant::VAL_IS_CSTR : nsXPTCVariant::VAL_IS_UTF8STR);
01546                        ns_v.ptr = new nsCString();
01547                        ns_v.val.p = ns_v.ptr; // VAL_IS_* says the .p is what gets freed
01548                        if (!ns_v.ptr) {
01549                               PyErr_NoMemory();
01550                               rc = PR_FALSE;
01551                        }
01552                        break;
01553                      }
01554                 default:
01555                      NS_ABORT_IF_FALSE(0, "Unknown type - don't know how to prepare the output value");
01556                      break; // Nothing to do!
01557               }
01558        }
01559        return rc;
01560 }
01561 
01562 PyObject *PyXPCOM_InterfaceVariantHelper::MakeSinglePythonResult(int index)
01563 {
01564        nsXPTCVariant &ns_v = m_var_array[index];
01565        PyObject *ret = nsnull;
01566        NS_ABORT_IF_FALSE(ns_v.IsPtrData() || ns_v.IsValDOMString(), "expecting a pointer if you want a result!");
01567 
01568        // Re-fetch the type descriptor.
01569        PythonTypeDescriptor &td = m_python_type_desc_array[index];
01570        // Make sure the type tag of the variant hasnt changed on us.
01571        NS_ABORT_IF_FALSE(ns_v.type==td.type_flags, "variant type has changed under us!");
01572 
01573        // If the pointer is NULL, we can get out now!
01574        if (ns_v.ptr==nsnull) {
01575               Py_INCREF(Py_None);
01576               return Py_None;
01577        }
01578 
01579        switch (XPT_TDP_TAG(ns_v.type)) {
01580          case nsXPTType::T_I8:
01581               ret = PyInt_FromLong( *((PRInt8 *)ns_v.ptr) );
01582               break;
01583          case nsXPTType::T_I16:
01584               ret = PyInt_FromLong( *((PRInt16 *)ns_v.ptr) );
01585               break;
01586          case nsXPTType::T_I32:
01587               ret = PyInt_FromLong( *((PRInt32 *)ns_v.ptr) );
01588               break;
01589          case nsXPTType::T_I64:
01590               ret = PyLong_FromLongLong( *((PRInt64 *)ns_v.ptr) );
01591               break;
01592          case nsXPTType::T_U8:
01593               ret = PyInt_FromLong( *((PRUint8 *)ns_v.ptr) );
01594               break;
01595          case nsXPTType::T_U16:
01596               ret = PyInt_FromLong( *((PRUint16 *)ns_v.ptr) );
01597               break;
01598          case nsXPTType::T_U32:
01599               ret = PyInt_FromLong( *((PRUint32 *)ns_v.ptr) );
01600               break;
01601          case nsXPTType::T_U64:
01602               ret = PyLong_FromUnsignedLongLong( *((PRUint64 *)ns_v.ptr) );
01603               break;
01604          case nsXPTType::T_FLOAT:
01605               ret = PyFloat_FromDouble( *((float *)ns_v.ptr) );
01606               break;
01607          case nsXPTType::T_DOUBLE:
01608               ret = PyFloat_FromDouble( *((double *)ns_v.ptr) );
01609               break;
01610          case nsXPTType::T_BOOL:
01611               ret = *((PRBool *)ns_v.ptr) ? Py_True : Py_False;
01612               Py_INCREF(ret);
01613               break;
01614          case nsXPTType::T_CHAR:
01615               ret = PyString_FromStringAndSize( ((char *)ns_v.ptr), 1 );
01616               break;
01617 
01618          case nsXPTType::T_WCHAR:
01619               ret = PyUnicode_FromPRUnichar( ((PRUnichar *)ns_v.ptr), 1 );
01620               break;
01621 //       case nsXPTType::T_VOID:
01622          case nsXPTType::T_IID: 
01623               ret = Py_nsIID::PyObjectFromIID( **((nsIID **)ns_v.ptr) );
01624               break;
01625          case nsXPTType::T_ASTRING:
01626          case nsXPTType::T_DOMSTRING: {
01627               nsAString *rs = (nsAString *)ns_v.ptr;
01628               ret = PyObject_FromNSString(*rs);
01629               break;
01630               }
01631          case nsXPTType::T_UTF8STRING:
01632          case nsXPTType::T_CSTRING: {
01633               nsCString *rs = (nsCString *)ns_v.ptr;
01634               ret = PyObject_FromNSString(*rs, XPT_TDP_TAG(ns_v.type)==nsXPTType::T_UTF8STRING);
01635               break;
01636               }
01637 
01638          case nsXPTType::T_CHAR_STR:
01639               if (*((char **)ns_v.ptr) == NULL) {
01640                      ret = Py_None;
01641                      Py_INCREF(Py_None);
01642               } else
01643                      ret = PyString_FromString( *((char **)ns_v.ptr) );
01644               break;
01645 
01646          case nsXPTType::T_WCHAR_STR: {
01647               PRUnichar *us = *((PRUnichar **)ns_v.ptr);
01648               if (us == NULL) {
01649                      ret = Py_None;
01650                      Py_INCREF(Py_None);
01651               } else {
01652                      ret = PyUnicode_FromPRUnichar( us, nsCRT::strlen(us));
01653               }
01654               break;
01655               }
01656          case nsXPTType::T_INTERFACE: {
01657               nsIID iid;
01658               if (!Py_nsIID::IIDFromPyObject(td.extra, &iid))
01659                      break;
01660               nsISupports *iret = *((nsISupports **)ns_v.ptr);
01661               // We _do_ add a reference here, as our cleanup code will
01662               // remove this reference should we own it.
01663               ret = Py_nsISupports::PyObjectFromInterfaceOrVariant(iret, iid, PR_TRUE);
01664               break;
01665               }
01666          case nsXPTType::T_INTERFACE_IS: {
01667               nsIID iid;
01668               nsXPTCVariant &ns_viid = m_var_array[td.argnum];
01669               NS_WARN_IF_FALSE(XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID, "The INTERFACE_IS iid describer isnt an IID!");
01670               if (XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID) {
01671                      nsIID *piid = (nsIID *)ns_viid.val.p;
01672                      if (piid==NULL)
01673                             // Also serious, but like below, not our fault!
01674                             iid = NS_GET_IID(nsISupports);
01675                      else
01676                             iid = *piid;
01677               } else
01678                      // This is a pretty serious problem, but not Python's fault!
01679                      // Just return an nsISupports and hope the caller does whatever
01680                      // QI they need before using it.
01681                      iid = NS_GET_IID(nsISupports);
01682               nsISupports *iret = *((nsISupports **)ns_v.ptr);
01683               // We _do_ add a reference here, as our cleanup code will
01684               // remove this reference should we own it.
01685               ret = Py_nsISupports::PyObjectFromInterfaceOrVariant(iret, iid, PR_TRUE);
01686               break;
01687               }
01688          case nsXPTType::T_ARRAY: {
01689               if ( (* ((void **)ns_v.ptr)) == NULL) {
01690                      ret = Py_None;
01691                      Py_INCREF(Py_None);
01692               }
01693               if (!PyInt_Check(td.extra)) {
01694                      PyErr_SetString(PyExc_TypeError, "The array info is not valid");
01695                      break;
01696               }
01697               PRUint8 array_type = (PRUint8)PyInt_AsLong(td.extra);
01698               PRUint32 seq_size = GetSizeIs(index, PR_FALSE);
01699               ret = UnpackSingleArray(* ((void **)ns_v.ptr), seq_size, array_type&XPT_TDP_TAGMASK, NULL);
01700               break;
01701               }
01702 
01703          case nsXPTType::T_PSTRING_SIZE_IS:
01704               if (*((char **)ns_v.ptr) == NULL) {
01705                      ret = Py_None;
01706                      Py_INCREF(Py_None);
01707               } else {
01708                      PRUint32 string_size = GetSizeIs(index, PR_TRUE);
01709                      ret = PyString_FromStringAndSize( *((char **)ns_v.ptr), string_size );
01710               }
01711               break;
01712 
01713          case nsXPTType::T_PWSTRING_SIZE_IS:
01714               if (*((PRUnichar **)ns_v.ptr) == NULL) {
01715                      ret = Py_None;
01716                      Py_INCREF(Py_None);
01717               } else {
01718                      PRUint32 string_size = GetSizeIs(index, PR_TRUE);
01719                      ret = PyUnicode_FromPRUnichar( *((PRUnichar **)ns_v.ptr), string_size );
01720               }
01721               break;
01722        default:
01723               PyErr_Format(PyExc_ValueError, "Unknown XPCOM type code (0x%x)", XPT_TDP_TAG(ns_v.type));
01724               /* ret remains nsnull */
01725               break;
01726        }
01727        return ret;
01728 }
01729 
01730 
01731 PyObject *PyXPCOM_InterfaceVariantHelper::MakePythonResult()
01732 {
01733        // First we count the results.
01734        int i = 0;
01735        int n_results = 0;
01736        PyObject *ret = NULL;
01737        PRBool have_retval = PR_FALSE;
01738        for (i=0;i<m_num_array;i++) {
01739               PythonTypeDescriptor &td = m_python_type_desc_array[i];
01740               if (!td.is_auto_out) {
01741                      if (XPT_PD_IS_OUT(td.param_flags) || XPT_PD_IS_DIPPER(td.param_flags))
01742                             n_results++;
01743                      if (XPT_PD_IS_RETVAL(td.param_flags))
01744                             have_retval = PR_TRUE;
01745               }
01746        }
01747        if (n_results==0) {
01748               ret = Py_None;
01749               Py_INCREF(ret);
01750        } else {
01751               if (n_results > 1) {
01752                      ret = PyTuple_New(n_results);
01753                      if (ret==NULL)
01754                             return NULL;
01755               }
01756               int ret_index = 0;
01757               int max_index = m_num_array;
01758               // Stick the retval at the front if we have have
01759               if (have_retval && n_results > 1) {
01760                      PyObject *val = MakeSinglePythonResult(m_num_array-1);
01761                      if (val==NULL) {
01762                             Py_DECREF(ret);
01763                             return NULL;
01764                      }
01765                      PyTuple_SET_ITEM(ret, 0, val);
01766                      max_index--;
01767                      ret_index++;
01768 
01769               }
01770               for (i=0;ret_index < n_results && i < max_index;i++) {
01771                      if (!m_python_type_desc_array[i].is_auto_out) {
01772                             if (XPT_PD_IS_OUT(m_python_type_desc_array[i].param_flags) || XPT_PD_IS_DIPPER(m_python_type_desc_array[i].param_flags)) {
01773                                    PyObject *val = MakeSinglePythonResult(i);
01774                                    if (val==NULL) {
01775                                           Py_XDECREF(ret);
01776                                           return NULL;
01777                                    }
01778                                    if (n_results > 1) {
01779                                           PyTuple_SET_ITEM(ret, ret_index, val);
01780                                           ret_index++;
01781                                    } else {
01782                                           NS_ABORT_IF_FALSE(ret==NULL, "shouldnt already have a ret!");
01783                                           ret = val;
01784                                    }
01785                             }
01786                      }
01787               }
01788 
01789        }
01790        return ret;
01791 }
01792 
01793 /*************************************************************************
01794 **************************************************************************
01795 
01796  Helpers when IMPLEMENTING interfaces.
01797 
01798 **************************************************************************
01799 *************************************************************************/
01800 
01801 PyXPCOM_GatewayVariantHelper::PyXPCOM_GatewayVariantHelper( PyG_Base *gw, int method_index, const nsXPTMethodInfo *info, nsXPTCMiniVariant* params )
01802 {
01803        m_params = params;
01804        m_info = info;
01805        // no references added - this class is only alive for
01806        // a single gateway invocation
01807        m_gateway = gw; 
01808        m_method_index = method_index;
01809        m_python_type_desc_array = NULL;
01810        m_num_type_descs = 0;
01811 }
01812 
01813 PyXPCOM_GatewayVariantHelper::~PyXPCOM_GatewayVariantHelper()
01814 {
01815        delete [] m_python_type_desc_array;
01816 }
01817 
01818 PyObject *PyXPCOM_GatewayVariantHelper::MakePyArgs()
01819 {
01820        NS_PRECONDITION(sizeof(XPTParamDescriptor) == sizeof(nsXPTParamInfo), "We depend on nsXPTParamInfo being a wrapper over the XPTParamDescriptor struct");
01821        // Setup our array of Python typedescs, and determine the number of objects we
01822        // pass to Python.
01823        m_num_type_descs = m_info->num_args;
01824        m_python_type_desc_array = new PythonTypeDescriptor[m_num_type_descs];
01825        if (m_python_type_desc_array==nsnull)
01826               return PyErr_NoMemory();
01827 
01828        // First loop to count the number of objects
01829        // we pass to Python
01830        int i;
01831        for (i=0;i<m_info->num_args;i++) {
01832               nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+i;
01833               PythonTypeDescriptor &td = m_python_type_desc_array[i];
01834               td.param_flags = pi->flags;
01835               td.type_flags = pi->type.prefix.flags;
01836               td.argnum = pi->type.argnum;
01837               td.argnum2 = pi->type.argnum2;
01838        }
01839        int num_args = ProcessPythonTypeDescriptors(m_python_type_desc_array, m_num_type_descs);
01840        PyObject *ret = PyTuple_New(num_args);
01841        if (ret==NULL)
01842               return NULL;
01843        int this_arg = 0;
01844        for (i=0;i<m_num_type_descs;i++) {
01845               PythonTypeDescriptor &td = m_python_type_desc_array[i];
01846               if (XPT_PD_IS_IN(td.param_flags) && !td.is_auto_in && !XPT_PD_IS_DIPPER(td.param_flags)) {
01847                      PyObject *sub = MakeSingleParam( i, td );
01848                      if (sub==NULL) {
01849                             Py_DECREF(ret);
01850                             return NULL;
01851                      }
01852                      NS_ABORT_IF_FALSE(this_arg>=0 && this_arg<num_args, "We are going off the end of the array!");
01853                      PyTuple_SET_ITEM(ret, this_arg, sub);
01854                      this_arg++;
01855               }
01856        }
01857        return ret;
01858 }
01859 
01860 PRBool PyXPCOM_GatewayVariantHelper::CanSetSizeIs( int var_index, PRBool is_arg1 )
01861 {
01862        NS_ABORT_IF_FALSE(var_index < m_num_type_descs, "var_index param is invalid");
01863        PRUint8 argnum = is_arg1 ? 
01864               m_python_type_desc_array[var_index].argnum :
01865               m_python_type_desc_array[var_index].argnum2;
01866        NS_ABORT_IF_FALSE(argnum < m_num_type_descs, "size_is param is invalid");
01867        return XPT_PD_IS_OUT(m_python_type_desc_array[argnum].param_flags);
01868 }
01869 
01870 PRBool PyXPCOM_GatewayVariantHelper::SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size)
01871 {
01872        NS_ABORT_IF_FALSE(var_index < m_num_type_descs, "var_index param is invalid");
01873        PRUint8 argnum = is_arg1 ? 
01874               m_python_type_desc_array[var_index].argnum :
01875               m_python_type_desc_array[var_index].argnum2;
01876        NS_ABORT_IF_FALSE(argnum < m_num_type_descs, "size_is param is invalid");
01877        PythonTypeDescriptor &td_size = m_python_type_desc_array[argnum];
01878        NS_ABORT_IF_FALSE( XPT_PD_IS_OUT(td_size.param_flags), "size param must be out if we want to set it!");
01879        NS_ABORT_IF_FALSE(td_size.is_auto_out, "Setting size_is, but param is not marked as auto!");
01880 
01881        nsXPTCMiniVariant &ns_v = m_params[argnum];
01882        NS_ABORT_IF_FALSE( (td_size.type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32");
01883        NS_ABORT_IF_FALSE(ns_v.val.p, "NULL pointer for size_is value!");
01884        if (ns_v.val.p) {
01885               if (!td_size.have_set_auto) {
01886                      *((PRUint32 *)ns_v.val.p) = new_size;
01887                      td_size.have_set_auto = PR_TRUE;
01888               } else {
01889                      if (*((PRUint32 *)ns_v.val.p) != new_size ) {
01890                             PyErr_Format(PyExc_ValueError, "Array lengths inconsistent; array size previously set to %d, but second array is of size %d", ns_v.val.u32, new_size);
01891                             return PR_FALSE;
01892                      }
01893               }
01894        }
01895        return PR_TRUE;
01896 }
01897 
01898 PRUint32 PyXPCOM_GatewayVariantHelper::GetSizeIs( int var_index, PRBool is_arg1)
01899 {
01900        NS_ABORT_IF_FALSE(var_index < m_num_type_descs, "var_index param is invalid");
01901        PRUint8 argnum = is_arg1 ? 
01902               m_python_type_desc_array[var_index].argnum :
01903               m_python_type_desc_array[var_index].argnum2;
01904        NS_ABORT_IF_FALSE(argnum < m_num_type_descs, "size_is param is invalid");
01905        if (argnum >= m_num_type_descs) {
01906               PyErr_SetString(PyExc_ValueError, "dont have a valid size_is indicator for this param");
01907               return PR_FALSE;
01908        }
01909        PRBool is_out = XPT_PD_IS_OUT(m_python_type_desc_array[argnum].param_flags);
01910        nsXPTCMiniVariant &ns_v = m_params[argnum];
01911        NS_ABORT_IF_FALSE( (m_python_type_desc_array[argnum].type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32");
01912        return is_out ? *((PRUint32 *)ns_v.val.p) : ns_v.val.u32;
01913 }
01914 
01915 #undef DEREF_IN_OR_OUT
01916 #define DEREF_IN_OR_OUT( element, ret_type ) (ret_type)(is_out ? *((ret_type *)ns_v.val.p) : (ret_type)(element))
01917 
01918 PyObject *PyXPCOM_GatewayVariantHelper::MakeSingleParam(int index, PythonTypeDescriptor &td)
01919 {
01920        NS_PRECONDITION(XPT_PD_IS_IN(td.param_flags), "Must be an [in] param!");
01921        nsXPTCMiniVariant &ns_v = m_params[index];
01922        PyObject *ret = NULL;
01923        PRBool is_out = XPT_PD_IS_OUT(td.param_flags);
01924 
01925        switch (td.type_flags & XPT_TDP_TAGMASK) {
01926          case nsXPTType::T_I8:
01927               ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.i8, PRInt8 ) );
01928               break;
01929          case nsXPTType::T_I16:
01930               ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.i16, PRInt16) );
01931               break;
01932          case nsXPTType::T_I32:
01933               ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.i32, PRInt32) );
01934               break;
01935          case nsXPTType::T_I64:
01936               ret = PyLong_FromLongLong( DEREF_IN_OR_OUT(ns_v.val.i64, PRInt64) );
01937               break;
01938          case nsXPTType::T_U8:
01939               ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.u8, PRUint8) );
01940               break;
01941          case nsXPTType::T_U16:
01942               ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.u16, PRUint16) );
01943               break;
01944          case nsXPTType::T_U32:
01945               ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.u32, PRUint32) );
01946               break;
01947          case nsXPTType::T_U64:
01948               ret = PyLong_FromUnsignedLongLong( DEREF_IN_OR_OUT(ns_v.val.u64, PRUint64) );
01949               break;
01950          case nsXPTType::T_FLOAT:
01951               ret = PyFloat_FromDouble(  DEREF_IN_OR_OUT(ns_v.val.f, float) );
01952               break;
01953          case nsXPTType::T_DOUBLE:
01954               ret = PyFloat_FromDouble(  DEREF_IN_OR_OUT(ns_v.val.d, double) );
01955               break;
01956          case nsXPTType::T_BOOL: {
01957               PRBool temp = DEREF_IN_OR_OUT(ns_v.val.b, PRBool);
01958               ret = temp ? Py_True : Py_False;
01959               Py_INCREF(ret);
01960               break;
01961               }
01962          case nsXPTType::T_CHAR: {
01963               char temp = DEREF_IN_OR_OUT(ns_v.val.c, char);
01964               ret = PyString_FromStringAndSize(&temp, 1);
01965               break;
01966               }
01967          case nsXPTType::T_WCHAR: {
01968               PRUnichar temp = (PRUnichar)DEREF_IN_OR_OUT(ns_v.val.wc, PRUnichar);
01969               ret = PyUnicode_FromPRUnichar(&temp, 1);
01970               break;
01971               }
01972 //       case nsXPTType::T_VOID:
01973          case nsXPTType::T_IID: {
01974                 ret = Py_nsIID::PyObjectFromIID( * DEREF_IN_OR_OUT(ns_v.val.p, const nsIID *) );
01975                 break;
01976               }
01977          case nsXPTType::T_ASTRING:
01978          case nsXPTType::T_DOMSTRING: {
01979               NS_ABORT_IF_FALSE(is_out || !XPT_PD_IS_DIPPER(td.param_flags), "DOMStrings can't be inout");
01980               const nsAString *rs = (const nsAString *)ns_v.val.p;
01981               ret = PyObject_FromNSString(*rs);
01982               break;
01983               }
01984          case nsXPTType::T_CSTRING:
01985          case nsXPTType::T_UTF8STRING: {
01986               NS_ABORT_IF_FALSE(is_out || !XPT_PD_IS_DIPPER(td.param_flags), "DOMStrings can't be inout");
01987               const nsCString *rs = (const nsCString *)ns_v.val.p;
01988               ret = PyObject_FromNSString(*rs, (td.type_flags & XPT_TDP_TAGMASK)==nsXPTType::T_UTF8STRING);
01989               break;
01990               }
01991          case nsXPTType::T_CHAR_STR: {
01992               char *t = DEREF_IN_OR_OUT(ns_v.val.p, char *);
01993               if (t==NULL) {
01994                      ret = Py_None;
01995                      Py_INCREF(Py_None);
01996               } else
01997                      ret = PyString_FromString(t);
01998               break;
01999               }
02000 
02001          case nsXPTType::T_WCHAR_STR: {
02002               PRUnichar *us = DEREF_IN_OR_OUT(ns_v.val.p, PRUnichar *);
02003               if (us==NULL) {
02004                      ret = Py_None;
02005                      Py_INCREF(Py_None);
02006               } else {
02007                      ret = PyUnicode_FromPRUnichar( us, nsCRT::strlen(us));
02008               }
02009               break;
02010               }
02011          case nsXPTType::T_INTERFACE_IS: // our Python code does it :-)
02012          case nsXPTType::T_INTERFACE: {
02013               nsISupports *iret = DEREF_IN_OR_OUT(ns_v.val.p, nsISupports *);
02014               nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index;
02015               ret = m_gateway->MakeInterfaceParam(iret, NULL, m_method_index, pi, index);
02016               break;
02017               }
02018 /***
02019               nsISupports *iret = DEREF_IN_OR_OUT(ns_v.val.p, nsISupports *);
02020               nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index;
02021               nsXPTCMiniVariant &ns_viid = m_params[td.argnum];
02022               NS_ABORT_IF_FALSE((m_python_type_desc_array[td.argnum].type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_IID, "The INTERFACE_IS iid describer isnt an IID!");
02023               const nsIID * iid = NULL;
02024               if (XPT_PD_IS_IN(m_python_type_desc_array[td.argnum].param_flags))
02025                      // may still be inout!
02026                      iid = DEREF_IN_OR_OUT(ns_v.val.p, const nsIID *);
02027 
02028               ret = m_gateway->MakeInterfaceParam(iret, iid, m_method_index, pi, index);
02029               break;
02030               }
02031 ****/
02032          case nsXPTType::T_ARRAY: {
02033               void *t = DEREF_IN_OR_OUT(ns_v.val.p, void *);
02034               if (t==NULL) {
02035                      ret = Py_None;
02036                      Py_INCREF(Py_None);
02037               } else {
02038                      PRUint8 array_type;
02039                      nsresult ns = GetArrayType(index, &array_type);
02040                      if (NS_FAILED(ns)) {
02041                             PyXPCOM_BuildPyException(ns);
02042                             break;
02043                      }
02044                      PRUint32 seq_size = GetSizeIs(index, PR_FALSE);
02045                      ret = UnpackSingleArray(t, seq_size, array_type&XPT_TDP_TAGMASK, NULL);
02046               }
02047               break;
02048               }
02049          case nsXPTType::T_PSTRING_SIZE_IS: {
02050               char *t = DEREF_IN_OR_OUT(ns_v.val.p, char *);
02051               PRUint32 string_size = GetSizeIs(index, PR_TRUE);
02052               if (t==NULL) {
02053                      ret = Py_None;
02054                      Py_INCREF(Py_None);
02055               } else
02056                      ret = PyString_FromStringAndSize(t, string_size);
02057               break;
02058               }
02059          case nsXPTType::T_PWSTRING_SIZE_IS: {
02060               PRUnichar *t = DEREF_IN_OR_OUT(ns_v.val.p, PRUnichar *);
02061               PRUint32 string_size = GetSizeIs(index, PR_TRUE);
02062               if (t==NULL) {
02063                      ret = Py_None;
02064                      Py_INCREF(Py_None);
02065               } else {
02066                      ret = PyUnicode_FromPRUnichar(t, string_size);
02067               }
02068               break;
02069               }
02070        default:
02071               // As this is called by external components,
02072               // we return _something_ rather than failing before any user code has run!
02073               {
02074               char buf[128];
02075               sprintf(buf, "Unknown XPCOM type flags (0x%x)", td.type_flags);
02076               PyXPCOM_LogWarning("%s - returning a string object with this message!\n", buf);
02077               ret = PyString_FromString(buf);
02078               break;
02079               }
02080        }
02081        return ret;
02082 }
02083 
02084 nsresult PyXPCOM_GatewayVariantHelper::GetArrayType(PRUint8 index, PRUint8 *ret)
02085 {
02086        nsCOMPtr<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager();
02087        NS_ABORT_IF_FALSE(iim != nsnull, "Cant get interface from IIM!");
02088        if (iim==nsnull)
02089               return NS_ERROR_FAILURE;
02090 
02091        nsCOMPtr<nsIInterfaceInfo> ii;
02092        nsresult rc = iim->GetInfoForIID( &m_gateway->m_iid, getter_AddRefs(ii));
02093        if (NS_FAILED(rc))
02094               return rc;
02095        nsXPTType datumType;
02096        const nsXPTParamInfo& param_info = m_info->GetParam((PRUint8)index);
02097        rc = ii->GetTypeForParam(m_method_index, &param_info, 1, &datumType);
02098        if (NS_FAILED(rc))
02099               return rc;
02100        *ret = datumType.flags;
02101        return NS_OK;
02102 }
02103 
02104 PRBool PyXPCOM_GatewayVariantHelper::GetIIDForINTERFACE_ID(int index, const nsIID **ppret)
02105 {
02106        // Not sure if the IID pointed at by by this is allows to be
02107        // in or out, so we will allow it.
02108        nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index;
02109        nsXPTType typ = pi->GetType();
02110        NS_WARN_IF_FALSE(XPT_TDP_TAG(typ) == nsXPTType::T_IID, "INTERFACE_IS IID param isnt an IID!");
02111        NS_ABORT_IF_FALSE(typ.IsPointer(), "Expecting to re-fill a pointer value.");
02112        if (XPT_TDP_TAG(typ) != nsXPTType::T_IID)
02113               *ppret = &NS_GET_IID(nsISupports);
02114        else {
02115               nsXPTCMiniVariant &ns_v = m_params[index];
02116               if (pi->IsOut()) {
02117                      nsIID **pp = (nsIID **)ns_v.val.p;
02118                      if (pp && *pp)
02119                             *ppret = *pp;
02120                      else
02121                             *ppret = &NS_GET_IID(nsISupports);
02122               } else if (pi->IsIn()) {
02123                      nsIID *p = (nsIID *)ns_v.val.p;
02124                      if (p)
02125                             *ppret = p;
02126                      else
02127                             *ppret = &NS_GET_IID(nsISupports);
02128               } else {
02129                      NS_ERROR("Param is not in or out!");
02130                      *ppret = &NS_GET_IID(nsISupports);
02131               }
02132        }
02133        return PR_TRUE;
02134 }
02135 
02136 nsIInterfaceInfo *PyXPCOM_GatewayVariantHelper::GetInterfaceInfo()
02137 {
02138        if (!m_interface_info) {
02139               nsCOMPtr<nsIInterfaceInfoManager> iim = 
02140                             dont_AddRef(XPTI_GetInterfaceInfoManager());
02141               if (iim)
02142                      iim->GetInfoForIID(&m_gateway->m_iid, getter_AddRefs(m_interface_info));
02143        }
02144        return m_interface_info;
02145 }
02146 
02147 #undef FILL_SIMPLE_POINTER
02148 #define FILL_SIMPLE_POINTER( type, ob ) *((type *)ns_v.val.p) = (type)(ob)
02149 
02150 nsresult PyXPCOM_GatewayVariantHelper::BackFillVariant( PyObject *val, int index)
02151 {
02152        nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index;
02153        NS_ABORT_IF_FALSE(pi->IsOut() || pi->IsDipper(), "The value must be marked as [out] (or a dipper) to be back-filled!");
02154        NS_ABORT_IF_FALSE(!pi->IsShared(), "Dont know how to back-fill a shared out param");
02155        nsXPTCMiniVariant &ns_v = m_params[index];
02156 
02157        nsXPTType typ = pi->GetType();
02158        PyObject* val_use = NULL;
02159 
02160        NS_ABORT_IF_FALSE(pi->IsDipper() || ns_v.val.p, "No space for result!");
02161        if (!pi->IsDipper() && !ns_v.val.p) return NS_ERROR_INVALID_POINTER;
02162 
02163        PRBool rc = PR_TRUE;
02164        switch (XPT_TDP_TAG(typ)) {
02165          case nsXPTType::T_I8:
02166               if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
02167               FILL_SIMPLE_POINTER( PRInt8, PyInt_AsLong(val_use) );
02168               break;
02169          case nsXPTType::T_I16:
02170               if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
02171               FILL_SIMPLE_POINTER( PRInt16, PyInt_AsLong(val_use) );
02172               break;
02173          case nsXPTType::T_I32:
02174               if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
02175               FILL_SIMPLE_POINTER( PRInt32, PyInt_AsLong(val_use) );
02176               break;
02177          case nsXPTType::T_I64:
02178               if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE;
02179               FILL_SIMPLE_POINTER( PRInt64, PyLong_AsLongLong(val_use) );
02180               break;
02181          case nsXPTType::T_U8:
02182               if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
02183               FILL_SIMPLE_POINTER( PRUint8, PyInt_AsLong(val_use) );
02184               break;
02185          case nsXPTType::T_U16:
02186               if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
02187               FILL_SIMPLE_POINTER( PRUint16, PyInt_AsLong(val_use) );
02188               break;
02189          case nsXPTType::T_U32:
02190               if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
02191               FILL_SIMPLE_POINTER( PRUint32, PyInt_AsLong(val_use) );
02192               break;
02193          case nsXPTType::T_U64:
02194               if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE;
02195               FILL_SIMPLE_POINTER( PRUint64, PyLong_AsUnsignedLongLong(val_use) );
02196               break;
02197          case nsXPTType::T_FLOAT:
02198               if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
02199               FILL_SIMPLE_POINTER( float, PyFloat_AsDouble(val_use) );
02200               break;
02201          case nsXPTType::T_DOUBLE:
02202               if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
02203               FILL_SIMPLE_POINTER( double, PyFloat_AsDouble(val_use) );
02204               break;
02205          case nsXPTType::T_BOOL:
02206               if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
02207               FILL_SIMPLE_POINTER( PRBool, PyInt_AsLong(val_use) );
02208               break;
02209          case nsXPTType::T_CHAR:
02210               if (!PyString_Check(val) && !PyUnicode_Check(val)) {
02211                      PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
02212                      BREAK_FALSE;
02213               }
02214               if ((val_use = PyObject_Str(val))==NULL)
02215                      BREAK_FALSE;
02216               // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
02217               NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
02218               FILL_SIMPLE_POINTER( char, *PyString_AS_STRING(val_use) );
02219               break;
02220 
02221          case nsXPTType::T_WCHAR:
02222               if (!PyString_Check(val) && !PyUnicode_Check(val)) {
02223                      PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
02224                      BREAK_FALSE;
02225               }
02226               if ((val_use = PyUnicode_FromObject(val))==NULL)
02227                      BREAK_FALSE;
02228               NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!");
02229               // Lossy!
02230               FILL_SIMPLE_POINTER( PRUnichar, *PyUnicode_AS_UNICODE(val_use) );
02231               break;
02232 
02233 //       case nsXPTType::T_VOID:
02234          case nsXPTType::T_IID: {
02235               nsIID iid;
02236               if (!Py_nsIID::IIDFromPyObject(val, &iid))
02237                      BREAK_FALSE;
02238               nsIID **pp = (nsIID **)ns_v.val.p;
02239               // If there is an existing [in] IID, free it.
02240               if (*pp && pi->IsIn())
02241                      nsMemory::Free(*pp);
02242               *pp = (nsIID *)nsMemory::Alloc(sizeof(nsIID));
02243               if (*pp==NULL) {
02244                      PyErr_NoMemory();
02245                      BREAK_FALSE;
02246               }
02247               memcpy(*pp, &iid, sizeof(iid));
02248               break;
02249               }
02250 
02251          case nsXPTType::T_ASTRING:
02252          case nsXPTType::T_DOMSTRING: {
02253               nsAString *ws = (nsAString *)ns_v.val.p;
02254               NS_ABORT_IF_FALSE(ws->Length() == 0, "Why does this writable string already have chars??");
02255               if (val == Py_None) {
02256                      (*ws) = (PRUnichar *)nsnull;
02257               } else {
02258                      if (!PyString_Check(val) && !PyUnicode_Check(val)) {
02259                             PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
02260                             BREAK_FALSE;
02261                      }
02262                      val_use = PyUnicode_FromObject(val);
02263                      if (!val_use)
02264                             BREAK_FALSE;
02265                      NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didn't return a Unicode object!");
02266                      if (PyUnicode_GET_SIZE(val_use) == 0) {
02267                             ws->Assign((PRUnichar*)NULL, 0);
02268                      }
02269                      else {
02270                             PRUint32 nch;
02271                             PRUnichar *sz;
02272                             if (PyUnicode_AsPRUnichar(val_use, &sz, &nch) < 0)
02273                                    BREAK_FALSE;
02274                             ws->Assign(sz, nch);
02275                             nsMemory::Free(sz);
02276                      }
02277               }
02278               break;
02279               }
02280          case nsXPTType::T_CSTRING: {
02281               nsCString *ws = (nsCString *)ns_v.val.p;
02282               NS_ABORT_IF_FALSE(ws->Length() == 0, "Why does this writable string already have chars??");
02283               if (val == Py_None) {
02284                      NS_ABORT_IF_FALSE(0, "dont handle None here yet");
02285               } else {
02286                      if (!PyString_Check(val) && !PyUnicode_Check(val)) {
02287                             PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
02288                             BREAK_FALSE;
02289                      }
02290                      val_use = PyObject_Str(val);
02291                      NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
02292                      const char *sz = PyString_AS_STRING(val_use);
02293                      ws->Assign(sz, PyString_Size(val_use));
02294               }
02295               break;
02296               }
02297          case nsXPTType::T_UTF8STRING: {
02298               nsCString *ws = (nsCString *)ns_v.val.p;
02299               NS_ABORT_IF_FALSE(ws->Length() == 0, "Why does this writable string already have chars??");
02300               if (val == Py_None) {
02301                      NS_ABORT_IF_FALSE(0, "dont handle None here yet");
02302               } else {
02303                      if (PyString_Check(val)) {
02304                             val_use = val;
02305                             Py_INCREF(val);
02306                      } else if (PyUnicode_Check(val)) {
02307                             val_use = PyUnicode_AsUTF8String(val);
02308                      } else {
02309                             PyErr_SetString(PyExc_TypeError, "UTF8 parameters must be string or Unicode objects");
02310                             BREAK_FALSE;
02311                      }
02312                      NS_ABORT_IF_FALSE(PyString_Check(val_use), "must have a string object!");
02313                      const char *sz = PyString_AS_STRING(val_use);
02314                      ws->Assign(sz, PyString_Size(val_use));
02315               }
02316               break;
02317               }
02318 
02319          case nsXPTType::T_CHAR_STR: {
02320               // If it is an existing string, free it.
02321               char **pp = (char **)ns_v.val.p;
02322               if (*pp && pi->IsIn())
02323                      nsMemory::Free(*pp);
02324               *pp = nsnull;
02325 
02326               if (val == Py_None)
02327                      break; // Remains NULL.
02328               if (!PyString_Check(val) && !PyUnicode_Check(val)) {
02329                      PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
02330                      BREAK_FALSE;
02331               }
02332               if ((val_use = PyObject_Str(val))==NULL)
02333                      BREAK_FALSE;
02334               // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
02335               NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
02336 
02337               const char *sz = PyString_AS_STRING(val_use);
02338               int nch = PyString_GET_SIZE(val_use);
02339 
02340               *pp = (char *)nsMemory::Alloc(nch+1);
02341               if (*pp==NULL) {
02342                      PyErr_NoMemory();
02343                      BREAK_FALSE;
02344               }
02345               strncpy(*pp, sz, nch+1);
02346               break;
02347               }
02348          case nsXPTType::T_WCHAR_STR: {
02349               // If it is an existing string, free it.
02350               PRUnichar **pp = (PRUnichar **)ns_v.val.p;
02351               if (*pp && pi->IsIn())
02352                      nsMemory::Free(*pp);
02353               *pp = nsnull;
02354               if (val == Py_None)
02355                      break; // Remains NULL.
02356               if (!PyString_Check(val) && !PyUnicode_Check(val)) {
02357                      PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
02358                      BREAK_FALSE;
02359               }
02360               val_use = PyUnicode_FromObject(val);
02361               NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!");
02362               if (PyUnicode_AsPRUnichar(val_use, pp, NULL) < 0)
02363                      BREAK_FALSE;
02364               break;
02365               }
02366          case nsXPTType::T_INTERFACE:  {
02367               nsISupports *pnew = nsnull;
02368               // Find out what IID we are declared to use.
02369               nsIID *iid;
02370               nsIInterfaceInfo *ii = GetInterfaceInfo();
02371               if (ii)
02372                      ii->GetIIDForParam(m_method_index, pi, &iid);
02373 
02374               // Get it the "standard" way.
02375               // We do allow NULL here, even tho doing so will no-doubt crash some objects.
02376               // (but there will certainly be objects out there that will allow NULL :-(
02377               nsIID iid_use = iid ? *iid : NS_GET_IID(nsISupports);
02378               if (!Py_nsISupports::InterfaceFromPyObject(val, iid_use, &pnew, PR_TRUE))
02379                      BREAK_FALSE;
02380               nsISupports **pp = (nsISupports **)ns_v.val.p;
02381               if (*pp && pi->IsIn()) {
02382                      Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
02383                      (*pp)->Release();
02384                      Py_END_ALLOW_THREADS;
02385               }
02386 
02387               *pp = pnew; // ref-count added by InterfaceFromPyObject
02388               break;
02389               }
02390          case nsXPTType::T_INTERFACE_IS: {
02391               // We do allow NULL here, even tho doing so will no-doubt crash some objects.
02392               // (but there will certainly be objects out there that will allow NULL :-(
02393               const nsIID *piid;
02394               if (!GetIIDForINTERFACE_ID(pi->type.argnum, &piid))
02395                      BREAK_FALSE;
02396 
02397               nsISupports *pnew = nsnull;
02398               // Get it the "standard" way.
02399               // We do allow NULL here, even tho doing so will no-doubt crash some objects.
02400               // (but there will certainly be objects out there that will allow NULL :-(
02401               if (!Py_nsISupports::InterfaceFromPyObject(val, *piid, &pnew, PR_TRUE))
02402                      BREAK_FALSE;
02403               nsISupports **pp = (nsISupports **)ns_v.val.p;
02404               if (*pp && pi->IsIn()) {
02405                      Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
02406                      (*pp)->Release();
02407                      Py_END_ALLOW_THREADS;
02408               }
02409 
02410               *pp = pnew; // ref-count added by InterfaceFromPyObject
02411               break;
02412               }
02413 
02414          case nsXPTType::T_PSTRING_SIZE_IS: {
02415               const char *sz = nsnull;
02416               PRUint32 nch = 0;
02417               if (val != Py_None) {
02418                      if (!PyString_Check(val) && !PyUnicode_Check(val)) {
02419                             PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
02420                             BREAK_FALSE;
02421                      }
02422                      if ((val_use = PyObject_Str(val))==NULL)
02423                             BREAK_FALSE;
02424                      // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
02425                      NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
02426 
02427                      sz = PyString_AS_STRING(val_use);
02428                      nch = PyString_GET_SIZE(val_use);
02429               }
02430               PRBool bBackFill = PR_FALSE;
02431               PRBool bCanSetSizeIs = CanSetSizeIs(index, PR_TRUE);
02432               // If we can not change the size, check our sequence is correct.
02433               if (!bCanSetSizeIs) {
02434                      PRUint32 existing_size = GetSizeIs(index, PR_TRUE);
02435                      if (nch != existing_size) {
02436                             PyErr_Format(PyExc_ValueError, "This function is expecting a string of exactly length %d - %d characters were passed", existing_size, nch);
02437                             BREAK_FALSE;
02438                      }
02439                      // It we have an "inout" param, but an "in" count, then
02440                      // it is probably a buffer the caller expects us to 
02441                      // fill in-place!
02442                      bBackFill = pi->IsIn();
02443               }
02444               if (bBackFill) {
02445                      memcpy(*(char **)ns_v.val.p, sz, nch);
02446               } else {
02447                      // If we have an existing string, free it!
02448                      char **pp = (char **)ns_v.val.p;
02449                      if (*pp && pi->IsIn())
02450                             nsMemory::Free(*pp);
02451                      *pp = nsnull;
02452                      if (sz==nsnull) // None specified.
02453                             break; // Remains NULL.
02454                      *pp = (char *)nsMemory::Alloc(nch);
02455                      if (*pp==NULL) {
02456                             PyErr_NoMemory();
02457                             BREAK_FALSE;
02458                      }
02459                      memcpy(*pp, sz, nch);
02460                      if (bCanSetSizeIs)
02461                             rc = SetSizeIs(index, PR_TRUE, nch);
02462                      else {
02463                             NS_ABORT_IF_FALSE(GetSizeIs(index, PR_TRUE) == nch, "Can't set sizeis, but string isnt correct size");
02464                      }
02465               }
02466               break;
02467               }
02468 
02469          case nsXPTType::T_PWSTRING_SIZE_IS: {
02470               PRUnichar *sz = nsnull;
02471               PRUint32 nch = 0;
02472               PRUint32 nbytes = 0;
02473 
02474               if (val != Py_None) {
02475                      if (!PyString_Check(val) && !PyUnicode_Check(val)) {
02476                             PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
02477                             BREAK_FALSE;
02478                      }
02479                      val_use = PyUnicode_FromObject(val);
02480                      NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!");
02481                      if (PyUnicode_AsPRUnichar(val_use, &sz, &nch) < 0)
02482                             BREAK_FALSE;
02483                      nbytes = sizeof(PRUnichar) * nch;
02484               }
02485               PRBool bBackFill = PR_FALSE;
02486               PRBool bCanSetSizeIs = CanSetSizeIs(index, PR_TRUE);
02487               // If we can not change the size, check our sequence is correct.
02488               if (!bCanSetSizeIs) {
02489                      // It is a buffer the caller prolly wants us to fill in-place!
02490                      PRUint32 existing_size = GetSizeIs(index, PR_TRUE);
02491                      if (nch != existing_size) {
02492                             PyErr_Format(PyExc_ValueError, "This function is expecting a string of exactly length %d - %d characters were passed", existing_size, nch);
02493                             BREAK_FALSE;
02494                      }
02495                      // It we have an "inout" param, but an "in" count, then
02496                      // it is probably a buffer the caller expects us to 
02497                      // fill in-place!
02498                      bBackFill = pi->IsIn();
02499               }
02500               if (bBackFill) {
02501                      memcpy(*(PRUnichar **)ns_v.val.p, sz, nbytes);
02502               } else {
02503                      // If it is an existing string, free it.
02504                      PRUnichar **pp = (PRUnichar **)ns_v.val.p;
02505                      if (*pp && pi->IsIn())
02506                             nsMemory::Free(*pp);
02507                      *pp = sz;
02508                      sz = nsnull;
02509                      if (bCanSetSizeIs)
02510                             rc = SetSizeIs(index, PR_TRUE, nch);
02511                      else {
02512                             NS_ABORT_IF_FALSE(GetSizeIs(index, PR_TRUE) == nch, "Can't set sizeis, but string isnt correct size");
02513                      }
02514               }
02515               if (sz)
02516                      nsMemory::Free(sz);
02517               break;
02518               }
02519          case nsXPTType::T_ARRAY: {
02520               // If it is an existing array of the correct size, keep it.
02521               PRUint32 sequence_size = 0;
02522               PRUint8 array_type;
02523               nsresult ns = GetArrayType(index, &array_type);
02524               if (NS_FAILED(ns))
02525                      return ns;
02526               PRUint32 element_size = GetArrayElementSize(array_type);
02527               if (val != Py_None) {
02528                      if (!PySequence_Check(val)) {
02529                             PyErr_Format(PyExc_TypeError, "Object for xpcom array must be a sequence, not type '%s'", val->ob_type->tp_name);
02530                             BREAK_FALSE;
02531                      }
02532                      sequence_size = PySequence_Length(val);
02533               }
02534               PRUint32 existing_size = GetSizeIs(index, PR_FALSE);
02535               PRBool bBackFill = PR_FALSE;
02536               PRBool bCanSetSizeIs = CanSetSizeIs(index, PR_FALSE);
02537               // If we can not change the size, check our sequence is correct.
02538               if (!bCanSetSizeIs) {
02539                      // It is a buffer the caller prolly wants us to fill in-place!
02540                      if (sequence_size != existing_size) {
02541                             PyErr_Format(PyExc_ValueError, "This function is expecting a sequence of exactly length %d - %d items were passed", existing_size, sequence_size);
02542                             BREAK_FALSE;
02543                      }
02544                      // It we have an "inout" param, but an "in" count, then
02545                      // it is probably a buffer the caller expects us to 
02546                      // fill in-place!
02547                      bBackFill = pi->IsIn();
02548               }
02549               if (bBackFill)
02550                      rc = FillSingleArray(*(void **)ns_v.val.p, val, sequence_size, element_size, array_type&XPT_TDP_TAGMASK);
02551               else {
02552                      // If it is an existing array, free it.
02553                      void **pp = (void **)ns_v.val.p;
02554                      if (*pp && pi->IsIn()) {
02555                             FreeSingleArray(*pp, existing_size, array_type);
02556                             nsMemory::Free(*pp);
02557                      }
02558                      *pp = nsnull;
02559                      if (val == Py_None)
02560                             break; // Remains NULL.
02561                      size_t nbytes = sequence_size * element_size;
02562                      if (nbytes==0) nbytes = 1; // avoid assertion about 0 bytes
02563                      *pp = (void *)nsMemory::Alloc(nbytes);
02564                      memset(*pp, 0, nbytes);
02565                      rc = FillSingleArray(*pp, val, sequence_size, element_size, array_type&XPT_TDP_TAGMASK);
02566                      if (!rc) break;
02567                      if (bCanSetSizeIs)
02568                             rc = SetSizeIs(index, PR_FALSE, sequence_size);
02569                      else {
02570                             NS_ABORT_IF_FALSE(GetSizeIs(index, PR_FALSE) == sequence_size, "Can't set sizeis, but string isnt correct size");
02571                      }
02572               }
02573               break;
02574               }
02575          default:
02576               // try and limp along in this case.
02577               // leave rc TRUE
02578               PyXPCOM_LogWarning("Converting Python object for an [out] param - The object type (0x%x) is unknown - leaving param alone!\n", XPT_TDP_TAG(typ));
02579               break;
02580        }
02581        Py_XDECREF(val_use);
02582        if (!rc)
02583               return NS_ERROR_FAILURE;
02584        return NS_OK;
02585 }
02586 
02587 nsresult PyXPCOM_GatewayVariantHelper::ProcessPythonResult(PyObject *ret_ob)
02588 {
02589        // NOTE - although we return an nresult, if we leave a Python
02590        // exception set, then our caller may take additional action
02591        // (ie, translating our nsresult to a more appropriate nsresult
02592        // for the Python exception.)
02593        NS_PRECONDITION(!PyErr_Occurred(), "Expecting no Python exception to be pending when processing the return result");
02594 
02595        nsresult rc = NS_OK;
02596        // If we dont get a tuple back, then the result is only
02597        // an int nresult for the underlying function.
02598        // (ie, the policy is expected to return (NS_OK, user_retval),
02599        // but can also return (say), NS_ERROR_FAILURE
02600        if (PyInt_Check(ret_ob))
02601               return PyInt_AsLong(ret_ob);
02602        // Now it must be the tuple.
02603        if (!PyTuple_Check(ret_ob) ||
02604            PyTuple_Size(ret_ob)!=2 ||
02605            !PyInt_Check(PyTuple_GET_ITEM(ret_ob, 0))) {
02606               PyErr_SetString(PyExc_TypeError, "The Python result must be a single integer or a tuple of length==2 and first item an int.");
02607               return NS_ERROR_FAILURE;
02608        }
02609        PyObject *user_result = PyTuple_GET_ITEM(ret_ob, 1);
02610        // Count up how many results our function needs.
02611        int i;
02612        int num_results = 0;
02613        int last_result = -1; // optimization if we only have one - this is it!
02614        int index_retval = -1;
02615        for (i=0;i<m_num_type_descs;i++) {
02616               nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+i;
02617               if (!m_python_type_desc_array[i].is_auto_out) {
02618                      if (pi->IsOut() || pi->IsDipper()) {
02619                             num_results++;
02620                             last_result = i;
02621                      }
02622                      if (pi->IsRetval())
02623                             index_retval = i;
02624               }
02625        }
02626 
02627        if (num_results==0) {
02628               ; // do nothing
02629        } else if (num_results==1) {
02630               // May or may not be the nominated retval - who cares!
02631               NS_ABORT_IF_FALSE(last_result >=0 && last_result < m_num_type_descs, "Have one result, but dont know its index!");
02632               rc = BackFillVariant( user_result, last_result );
02633        } else {
02634               // Loop over each one, filling as we go.
02635               // We allow arbitary sequences here, but _not_ strings
02636               // or Unicode!
02637               // NOTE - We ALWAYS do the nominated retval first.
02638               // The Python pattern is always:
02639               // return retval [, byref1 [, byref2 ...] ]
02640               // But the retval is often the last param described in the info.
02641               if (!PySequence_Check(user_result) ||
02642                    PyString_Check(user_result) ||
02643                    PyUnicode_Check(user_result)) {
02644                      PyErr_SetString(PyExc_TypeError, "This function has multiple results, but a sequence was not given to fill them");
02645                      return NS_ERROR_FAILURE;
02646               }
02647               int num_user_results = PySequence_Length(user_result);
02648               // If they havent given enough, we dont really care.
02649               // although a warning is probably appropriate.
02650               if (num_user_results != num_results) {
02651                      const char *method_name = m_info->GetName();
02652                      PyXPCOM_LogWarning("The method '%s' has %d out params, but %d were supplied by the Python code\n",
02653                             method_name,
02654                             num_results,
02655                             num_user_results);
02656               }
02657               int this_py_index = 0;
02658               if (index_retval != -1) {
02659                      // We always return the nominated result first!
02660                      PyObject *sub = PySequence_GetItem(user_result, 0);
02661                      if (sub==NULL)
02662                             return NS_ERROR_FAILURE;
02663                      rc = BackFillVariant(sub, index_retval);
02664                      Py_DECREF(sub);
02665                      this_py_index = 1;
02666               }
02667               for (i=0;NS_SUCCEEDED(rc) && i<m_info->GetParamCount();i++) {
02668                      // If weve already done it, or dont need to do it!
02669                      if (i==index_retval || m_python_type_desc_array[i].is_auto_out) 
02670                             continue;
02671                      nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+i;
02672                      if (pi->IsOut()) {
02673                             PyObject *sub = PySequence_GetItem(user_result, this_py_index);
02674                             if (sub==NULL)
02675                                    return NS_ERROR_FAILURE;
02676                             rc = BackFillVariant(sub, i);
02677                             Py_DECREF(sub);
02678                             this_py_index++;
02679                      }
02680               }
02681        }
02682        return rc;
02683 }