зеркало из https://github.com/mozilla/pjs.git
2604 строки
86 KiB
C++
2604 строки
86 KiB
C++
/*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with the
|
|
* License. You may obtain a copy of the License at http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
|
|
* the specific language governing rights and limitations under the License.
|
|
*
|
|
* The Original Code is the Python XPCOM language bindings.
|
|
*
|
|
* The Initial Developer of the Original Code is ActiveState Tool Corp.
|
|
* Portions created by ActiveState Tool Corp. are Copyright (C) 2000, 2001
|
|
* ActiveState Tool Corp. All Rights Reserved.
|
|
*
|
|
* Contributor(s): Mark Hammond <mhammond@skippinet.com.au> (original author)
|
|
*
|
|
*/
|
|
|
|
//
|
|
// This code is part of the XPCOM extensions for Python.
|
|
//
|
|
// Written May 2000 by Mark Hammond.
|
|
//
|
|
// Based heavily on the Python COM support, which is
|
|
// (c) Mark Hammond and Greg Stein.
|
|
//
|
|
// (c) 2000, ActiveState corp.
|
|
|
|
#include "PyXPCOM_std.h"
|
|
#include <nsIInterfaceInfoManager.h>
|
|
#include <nsAString.h>
|
|
#include <nsString.h>
|
|
#include <nsReadableUtils.h>
|
|
|
|
// ------------------------------------------------------------------------
|
|
// nsString utilities
|
|
// ------------------------------------------------------------------------
|
|
// one day we may know what they look like.
|
|
inline
|
|
PRBool
|
|
IsNullDOMString( const nsAString& aString )
|
|
{
|
|
return PR_FALSE;
|
|
}
|
|
|
|
inline
|
|
PRBool
|
|
IsNullDOMString( const nsACString& aString )
|
|
{
|
|
return PR_FALSE;
|
|
}
|
|
|
|
PyObject *PyObject_FromNSString( const nsACString &s, PRBool bAssumeUTF8 = PR_FALSE )
|
|
{
|
|
PyObject *ret;
|
|
if (IsNullDOMString(s)) {
|
|
ret = Py_None;
|
|
Py_INCREF(Py_None);
|
|
} else {
|
|
if (bAssumeUTF8) {
|
|
char *temp = ToNewCString(s);
|
|
ret = PyUnicode_DecodeUTF8(temp, s.Length(), NULL);
|
|
nsMemory::Free(temp);
|
|
} else {
|
|
ret = PyString_FromStringAndSize(NULL, s.Length());
|
|
// Need "CopyAsciiTo"!?
|
|
nsACString::const_iterator fromBegin, fromEnd;
|
|
char* dest = PyString_AS_STRING(ret);
|
|
copy_string(s.BeginReading(fromBegin), s.EndReading(fromEnd), dest);
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
PyObject *PyObject_FromNSString( const nsAString &s )
|
|
{
|
|
PyObject *ret;
|
|
if (IsNullDOMString(s)) {
|
|
ret = Py_None;
|
|
Py_INCREF(Py_None);
|
|
} else {
|
|
ret = PyUnicodeUCS2_FromUnicode( NULL, s.Length() );
|
|
CopyUnicodeTo(s, 0, PyUnicodeUCS2_AsUnicode(ret), s.Length());
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// Array utilities
|
|
static PRUint32 GetArrayElementSize( PRUint8 t)
|
|
{
|
|
PRUint32 ret;
|
|
switch (t & XPT_TDP_TAGMASK) {
|
|
case nsXPTType::T_U8:
|
|
case nsXPTType::T_I8:
|
|
ret = sizeof(PRInt8);
|
|
break;
|
|
case nsXPTType::T_I16:
|
|
case nsXPTType::T_U16:
|
|
ret = sizeof(PRInt16);
|
|
break;
|
|
case nsXPTType::T_I32:
|
|
case nsXPTType::T_U32:
|
|
ret = sizeof(PRInt32);
|
|
break;
|
|
case nsXPTType::T_I64:
|
|
case nsXPTType::T_U64:
|
|
ret = sizeof(PRInt64);
|
|
break;
|
|
case nsXPTType::T_FLOAT:
|
|
ret = sizeof(float);
|
|
break;
|
|
case nsXPTType::T_DOUBLE:
|
|
ret = sizeof(double);
|
|
break;
|
|
case nsXPTType::T_BOOL:
|
|
ret = sizeof(PRBool);
|
|
break;
|
|
case nsXPTType::T_CHAR:
|
|
ret = sizeof(char);
|
|
break;
|
|
case nsXPTType::T_WCHAR:
|
|
ret = sizeof(PRUnichar);
|
|
break;
|
|
case nsXPTType::T_IID:
|
|
case nsXPTType::T_CHAR_STR:
|
|
case nsXPTType::T_WCHAR_STR:
|
|
case nsXPTType::T_INTERFACE:
|
|
case nsXPTType::T_DOMSTRING:
|
|
case nsXPTType::T_INTERFACE_IS:
|
|
case nsXPTType::T_PSTRING_SIZE_IS:
|
|
case nsXPTType::T_CSTRING:
|
|
case nsXPTType::T_ASTRING:
|
|
case nsXPTType::T_UTF8STRING:
|
|
|
|
ret = sizeof( void * );
|
|
break;
|
|
default:
|
|
NS_ABORT_IF_FALSE(0, "Unknown array type code!");
|
|
ret = 0;
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
void FreeSingleArray(void *array_ptr, PRUint32 sequence_size, PRUint8 array_type)
|
|
{
|
|
// Free each array element - NOT the array itself
|
|
// Thus, we only need to free arrays or pointers.
|
|
void **p = (void **)array_ptr;
|
|
PRUint32 i;
|
|
switch(array_type & XPT_TDP_TAGMASK) {
|
|
case nsXPTType::T_IID:
|
|
case nsXPTType::T_CHAR_STR:
|
|
case nsXPTType::T_WCHAR_STR:
|
|
for (i=0; i<sequence_size; i++)
|
|
if (p[i]) nsMemory::Free(p[i]);
|
|
break;
|
|
case nsXPTType::T_INTERFACE:
|
|
case nsXPTType::T_INTERFACE_IS:
|
|
for (i=0; i<sequence_size; i++)
|
|
if (p[i]) {
|
|
Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
|
|
((nsISupports *)p[i])->Release();
|
|
Py_END_ALLOW_THREADS;
|
|
}
|
|
break;
|
|
|
|
// Ones we know need no deallocation
|
|
case nsXPTType::T_U8:
|
|
case nsXPTType::T_I8:
|
|
case nsXPTType::T_I16:
|
|
case nsXPTType::T_U16:
|
|
case nsXPTType::T_I32:
|
|
case nsXPTType::T_U32:
|
|
case nsXPTType::T_I64:
|
|
case nsXPTType::T_U64:
|
|
case nsXPTType::T_FLOAT:
|
|
case nsXPTType::T_DOUBLE:
|
|
case nsXPTType::T_BOOL:
|
|
case nsXPTType::T_CHAR:
|
|
case nsXPTType::T_WCHAR:
|
|
break;
|
|
|
|
// And a warning should new type codes appear, as they may need deallocation.
|
|
default:
|
|
PyXPCOM_LogWarning("Deallocating unknown type %d (0x%x) - possible memory leak\n");
|
|
break;
|
|
}
|
|
}
|
|
|
|
#define FILL_SIMPLE_POINTER( type, val ) *((type *)pthis) = (type)(val);
|
|
#define BREAK_FALSE {rc=PR_FALSE;break;}
|
|
|
|
|
|
PRBool FillSingleArray(void *array_ptr, PyObject *sequence_ob, PRUint32 sequence_size, PRUint32 array_element_size, PRUint8 array_type)
|
|
{
|
|
PRUint8 *pthis = (PRUint8 *)array_ptr;
|
|
NS_ABORT_IF_FALSE(pthis, "Don't have a valid array to fill!");
|
|
PRBool rc = PR_TRUE;
|
|
// We handle T_U8 specially as a string/Unicode.
|
|
// If it is NOT a string, we just fall through and allow the standard
|
|
// sequence unpack code process it (just slower!)
|
|
if ( array_type == nsXPTType::T_U8 &&
|
|
(PyString_Check(sequence_ob) || PyUnicode_Check(sequence_ob))) {
|
|
|
|
PRBool release_seq;
|
|
if (PyUnicode_Check(sequence_ob)) {
|
|
release_seq = PR_TRUE;
|
|
sequence_ob = PyObject_Str(sequence_ob);
|
|
} else
|
|
release_seq = PR_FALSE;
|
|
if (!sequence_ob) // presumably a memory error, or Unicode encoding error.
|
|
return PR_FALSE;
|
|
memcpy(pthis, PyString_AS_STRING(sequence_ob), sequence_size);
|
|
if (release_seq)
|
|
Py_DECREF(sequence_ob);
|
|
return PR_TRUE;
|
|
}
|
|
|
|
for (PRUint32 i=0; rc && i<sequence_size; i++,pthis += array_element_size) {
|
|
PyObject *val = PySequence_GetItem(sequence_ob, i);
|
|
PyObject *val_use = NULL;
|
|
if (val==NULL)
|
|
return PR_FALSE;
|
|
switch(array_type) {
|
|
case nsXPTType::T_I8:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
|
|
FILL_SIMPLE_POINTER( PRInt8, PyInt_AsLong(val_use) );
|
|
break;
|
|
case nsXPTType::T_I16:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
|
|
FILL_SIMPLE_POINTER( PRInt16, PyInt_AsLong(val_use) );
|
|
break;
|
|
case nsXPTType::T_I32:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
|
|
FILL_SIMPLE_POINTER( PRInt32, PyInt_AsLong(val_use) );
|
|
break;
|
|
case nsXPTType::T_I64:
|
|
if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE;
|
|
FILL_SIMPLE_POINTER( PRInt64, PyLong_AsLongLong(val_use) );
|
|
break;
|
|
case nsXPTType::T_U8:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
|
|
FILL_SIMPLE_POINTER( PRUint8, PyInt_AsLong(val_use) );
|
|
break;
|
|
case nsXPTType::T_U16:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
|
|
FILL_SIMPLE_POINTER( PRUint16, PyInt_AsLong(val_use) );
|
|
break;
|
|
case nsXPTType::T_U32:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
|
|
FILL_SIMPLE_POINTER( PRUint32, PyInt_AsLong(val_use) );
|
|
break;
|
|
case nsXPTType::T_U64:
|
|
if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE;
|
|
FILL_SIMPLE_POINTER( PRUint64, PyLong_AsUnsignedLongLong(val_use) );
|
|
break;
|
|
case nsXPTType::T_FLOAT:
|
|
if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
|
|
FILL_SIMPLE_POINTER( float, PyFloat_AsDouble(val_use) );
|
|
break;
|
|
case nsXPTType::T_DOUBLE:
|
|
if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
|
|
FILL_SIMPLE_POINTER( double, PyFloat_AsDouble(val_use) );
|
|
break;
|
|
case nsXPTType::T_BOOL:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
|
|
FILL_SIMPLE_POINTER( PRBool, PyInt_AsLong(val_use) );
|
|
break;
|
|
case nsXPTType::T_CHAR:
|
|
if (!PyString_Check(val) && !PyUnicode_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
|
|
BREAK_FALSE;
|
|
}
|
|
if ((val_use = PyObject_Str(val))==NULL)
|
|
BREAK_FALSE;
|
|
// Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
|
|
NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
|
|
FILL_SIMPLE_POINTER( char, *PyString_AS_STRING(val_use) );
|
|
break;
|
|
|
|
case nsXPTType::T_WCHAR:
|
|
if (!PyString_Check(val) && !PyUnicode_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
|
|
BREAK_FALSE;
|
|
}
|
|
if ((val_use = PyUnicodeUCS2_FromObject(val))==NULL)
|
|
BREAK_FALSE;
|
|
NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicodeUCS2_FromObject didnt return a Unicode object!");
|
|
FILL_SIMPLE_POINTER( PRUnichar, *PyUnicode_AS_UNICODE(val_use) );
|
|
break;
|
|
|
|
case nsXPTType::T_IID: {
|
|
nsIID iid;
|
|
if (!Py_nsIID::IIDFromPyObject(val, &iid))
|
|
BREAK_FALSE;
|
|
nsIID **pp = (nsIID **)pthis;
|
|
// If there is an existing IID, free it.
|
|
if (*pp)
|
|
nsMemory::Free(*pp);
|
|
*pp = (nsIID *)nsMemory::Alloc(sizeof(nsIID));
|
|
if (*pp==NULL) {
|
|
PyErr_NoMemory();
|
|
BREAK_FALSE;
|
|
}
|
|
memcpy(*pp, &iid, sizeof(iid));
|
|
break;
|
|
}
|
|
|
|
// case nsXPTType::T_BSTR:
|
|
|
|
case nsXPTType::T_CHAR_STR: {
|
|
// If it is an existing string, free it.
|
|
char **pp = (char **)pthis;
|
|
if (*pp)
|
|
nsMemory::Free(*pp);
|
|
*pp = nsnull;
|
|
|
|
if (val == Py_None)
|
|
break; // Remains NULL.
|
|
if (!PyString_Check(val) && !PyUnicode_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
|
|
BREAK_FALSE;
|
|
}
|
|
if ((val_use = PyObject_Str(val))==NULL)
|
|
BREAK_FALSE;
|
|
// Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
|
|
NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
|
|
|
|
const char *sz = PyString_AS_STRING(val_use);
|
|
int nch = PyString_GET_SIZE(val_use);
|
|
|
|
*pp = (char *)nsMemory::Alloc(nch+1);
|
|
if (*pp==NULL) {
|
|
PyErr_NoMemory();
|
|
BREAK_FALSE;
|
|
}
|
|
strncpy(*pp, sz, nch+1);
|
|
break;
|
|
}
|
|
case nsXPTType::T_WCHAR_STR: {
|
|
// If it is an existing string, free it.
|
|
PRUnichar **pp = (PRUnichar **)pthis;
|
|
if (*pp)
|
|
nsMemory::Free(*pp);
|
|
*pp = nsnull;
|
|
if (val == Py_None)
|
|
break; // Remains NULL.
|
|
if (!PyString_Check(val) && !PyUnicode_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
|
|
BREAK_FALSE;
|
|
}
|
|
if ((val_use = PyUnicodeUCS2_FromObject(val))==NULL)
|
|
BREAK_FALSE;
|
|
NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicodeUCS2_FromObject didnt return a Unicode object!");
|
|
const PRUnichar *sz = PyUnicode_AS_UNICODE(val_use);
|
|
int nch = PyUnicode_GET_SIZE(val_use);
|
|
|
|
*pp = (PRUnichar *)nsMemory::Alloc(sizeof(PRUnichar) * (nch+1));
|
|
if (*pp==NULL) {
|
|
PyErr_NoMemory();
|
|
BREAK_FALSE;
|
|
}
|
|
memcpy(*pp, sz, sizeof(PRUnichar) * (nch + 1));
|
|
break;
|
|
}
|
|
case nsXPTType::T_INTERFACE_IS: // hmm - ignoring the IID can't be good :(
|
|
case nsXPTType::T_INTERFACE: {
|
|
// We do allow NULL here, even tho doing so will no-doubt crash some objects.
|
|
// (but there will certainly be objects out there that will allow NULL :-(
|
|
nsISupports *pnew;
|
|
if (!Py_nsISupports::InterfaceFromPyObject(val, NS_GET_IID(nsISupports), &pnew, PR_TRUE))
|
|
BREAK_FALSE;
|
|
nsISupports **pp = (nsISupports **)pthis;
|
|
if (*pp) {
|
|
Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
|
|
(*pp)->Release();
|
|
Py_END_ALLOW_THREADS;
|
|
}
|
|
*pp = pnew; // ref-count added by InterfaceFromPyObject
|
|
break;
|
|
}
|
|
default:
|
|
// try and limp along in this case.
|
|
// leave rc TRUE
|
|
PyXPCOM_LogWarning("Converting Python object for an array element - The object type (0x%x) is unknown - leaving param alone!\n", array_type);
|
|
break;
|
|
}
|
|
Py_XDECREF(val_use);
|
|
Py_DECREF(val);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
PyObject *UnpackSingleArray(void *array_ptr, PRUint32 sequence_size, PRUint8 array_type, nsIID *iid)
|
|
{
|
|
if (array_ptr==NULL) {
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
if (array_type == nsXPTType::T_U8)
|
|
return PyString_FromStringAndSize( (char *)array_ptr, sequence_size );
|
|
|
|
PRUint32 array_element_size = GetArrayElementSize(array_type);
|
|
PyObject *list_ret = PyList_New(sequence_size);
|
|
PRUint8 *pthis = (PRUint8 *)array_ptr;
|
|
for (PRUint32 i=0; i<sequence_size; i++,pthis += array_element_size) {
|
|
PyObject *val = NULL;
|
|
switch(array_type) {
|
|
case nsXPTType::T_I8:
|
|
val = PyInt_FromLong( *((PRInt8 *)pthis) );
|
|
break;
|
|
case nsXPTType::T_I16:
|
|
val = PyInt_FromLong( *((PRInt16 *)pthis) );
|
|
break;
|
|
case nsXPTType::T_I32:
|
|
val = PyInt_FromLong( *((PRInt32 *)pthis) );
|
|
break;
|
|
case nsXPTType::T_I64:
|
|
val = PyLong_FromLongLong( *((PRInt64 *)pthis) );
|
|
break;
|
|
// case nsXPTType::T_U8 - handled above!
|
|
case nsXPTType::T_U16:
|
|
val = PyInt_FromLong( *((PRUint16 *)pthis) );
|
|
break;
|
|
case nsXPTType::T_U32:
|
|
val = PyInt_FromLong( *((PRUint32 *)pthis) );
|
|
break;
|
|
case nsXPTType::T_U64:
|
|
val = PyLong_FromUnsignedLongLong( *((PRUint64 *)pthis) );
|
|
break;
|
|
case nsXPTType::T_FLOAT:
|
|
val = PyFloat_FromDouble( *((float*)pthis) );
|
|
break;
|
|
case nsXPTType::T_DOUBLE:
|
|
val = PyFloat_FromDouble( *((double*)pthis) );
|
|
break;
|
|
case nsXPTType::T_BOOL:
|
|
val = (*((PRBool *)pthis)) ? Py_True : Py_False;
|
|
Py_INCREF(val);
|
|
break;
|
|
case nsXPTType::T_IID:
|
|
val = Py_nsIID::PyObjectFromIID( **((nsIID **)pthis) );
|
|
break;
|
|
|
|
case nsXPTType::T_CHAR_STR: {
|
|
char **pp = (char **)pthis;
|
|
if (*pp==NULL) {
|
|
Py_INCREF(Py_None);
|
|
val = Py_None;
|
|
} else
|
|
val = PyString_FromString(*pp);
|
|
break;
|
|
}
|
|
case nsXPTType::T_WCHAR_STR: {
|
|
PRUnichar **pp = (PRUnichar **)pthis;
|
|
if (*pp==NULL) {
|
|
Py_INCREF(Py_None);
|
|
val = Py_None;
|
|
} else
|
|
val = PyUnicodeUCS2_FromUnicode( *pp, nsCRT::strlen(*pp) );
|
|
break;
|
|
}
|
|
case nsXPTType::T_INTERFACE_IS:
|
|
case nsXPTType::T_INTERFACE: {
|
|
nsISupports **pp = (nsISupports **)pthis;
|
|
val = Py_nsISupports::PyObjectFromInterface(*pp, iid ? *iid : NS_GET_IID(nsISupports), PR_TRUE);
|
|
break;
|
|
}
|
|
default: {
|
|
char buf[128];
|
|
sprintf(buf, "Unknown XPCOM array type flags (0x%x)", array_type);
|
|
PyXPCOM_LogWarning("%s - returning a string object with this message!\n", buf);
|
|
val = PyString_FromString(buf);
|
|
break;
|
|
}
|
|
}
|
|
if (val==NULL) {
|
|
NS_ABORT_IF_FALSE(PyErr_Occurred(), "NULL result in array conversion, but no error set!");
|
|
return NULL;
|
|
}
|
|
PyList_SET_ITEM(list_ret, i, val); // ref-count consumed.
|
|
}
|
|
return list_ret;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------------------------
|
|
// nsIVariant utilities
|
|
// ------------------------------------------------------------------------
|
|
struct BVFTResult {
|
|
BVFTResult() {pis = NULL;iid=Py_nsIID_NULL;}
|
|
nsISupports *pis;
|
|
nsIID iid;
|
|
};
|
|
|
|
static PRUint16 BestVariantTypeForPyObject( PyObject *ob, BVFTResult *pdata = NULL)
|
|
{
|
|
nsISupports *ps = NULL;
|
|
nsIID iid;
|
|
// start with some fast concrete checks.
|
|
if (ob==Py_None)
|
|
return nsIDataType::VTYPE_EMPTY;
|
|
if (ob==Py_True || ob == Py_False)
|
|
return nsIDataType::VTYPE_BOOL;
|
|
if (PyInt_Check(ob))
|
|
return nsIDataType::VTYPE_INT32;
|
|
if (PyLong_Check(ob))
|
|
return nsIDataType::VTYPE_INT64;
|
|
if (PyFloat_Check(ob))
|
|
return nsIDataType::VTYPE_DOUBLE;
|
|
if (PyString_Check(ob))
|
|
return nsIDataType::VTYPE_STRING_SIZE_IS;
|
|
if (PyUnicode_Check(ob))
|
|
return nsIDataType::VTYPE_WSTRING_SIZE_IS;
|
|
if (PyTuple_Check(ob) || PyList_Check(ob))
|
|
return PySequence_Length(ob) ? nsIDataType::VTYPE_ARRAY : nsIDataType::VTYPE_EMPTY_ARRAY;
|
|
// Now do expensive or abstract checks.
|
|
if (Py_nsISupports::InterfaceFromPyObject(ob, NS_GET_IID(nsISupports), &ps, PR_TRUE)) {
|
|
if (pdata) {
|
|
pdata->pis = ps;
|
|
pdata->iid = NS_GET_IID(nsISupports);
|
|
} else
|
|
ps->Release();
|
|
return nsIDataType::VTYPE_INTERFACE_IS;
|
|
} else
|
|
PyErr_Clear();
|
|
if (Py_nsIID::IIDFromPyObject(ob, &iid)) {
|
|
if (pdata)
|
|
pdata->iid = iid;
|
|
return nsIDataType::VTYPE_ID;
|
|
} else
|
|
PyErr_Clear();
|
|
if (PySequence_Check(ob))
|
|
return PySequence_Length(ob) ? nsIDataType::VTYPE_ARRAY : nsIDataType::VTYPE_EMPTY_ARRAY;
|
|
return (PRUint16)-1;
|
|
}
|
|
|
|
nsIVariant *PyObject_AsVariant( PyObject *ob)
|
|
{
|
|
nsresult nr = NS_ERROR_UNEXPECTED;
|
|
nsCOMPtr<nsIWritableVariant> v = do_CreateInstance("@mozilla.org/variant;1", &nr);
|
|
if (NS_FAILED(nr)) {
|
|
PyXPCOM_BuildPyException(nr);
|
|
return NULL;
|
|
}
|
|
// *sigh* - I tried the abstract API (PyNumber_Check, etc)
|
|
// but our COM instances too often qualify.
|
|
BVFTResult cvt_result;
|
|
PRUint16 dt = BestVariantTypeForPyObject(ob, &cvt_result);
|
|
switch (dt) {
|
|
case nsIDataType::VTYPE_BOOL:
|
|
nr = v->SetAsBool(ob==Py_True);
|
|
break;
|
|
case nsIDataType::VTYPE_INT32:
|
|
nr = v->SetAsInt32(PyInt_AsLong(ob));
|
|
break;
|
|
case nsIDataType::VTYPE_INT64:
|
|
nr = v->SetAsInt64(PyLong_AsLongLong(ob));
|
|
break;
|
|
case nsIDataType::VTYPE_DOUBLE:
|
|
nr = v->SetAsDouble(PyFloat_AsDouble(ob));
|
|
break;
|
|
case nsIDataType::VTYPE_STRING_SIZE_IS:
|
|
nr = v->SetAsStringWithSize(PyString_Size(ob), PyString_AsString(ob));
|
|
break;
|
|
case nsIDataType::VTYPE_WSTRING_SIZE_IS:
|
|
nr = v->SetAsWStringWithSize(PyUnicodeUCS2_GetSize(ob), PyUnicodeUCS2_AsUnicode(ob));
|
|
break;
|
|
case nsIDataType::VTYPE_INTERFACE_IS:
|
|
{
|
|
nsISupports *ps = cvt_result.pis;
|
|
nr = v->SetAsInterface(cvt_result.iid, ps);
|
|
if (ps) {
|
|
Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
|
|
ps->Release();
|
|
Py_END_ALLOW_THREADS;
|
|
}
|
|
break;
|
|
}
|
|
case nsIDataType::VTYPE_ID:
|
|
nr = v->SetAsID(cvt_result.iid);
|
|
break;
|
|
case nsIDataType::VTYPE_ARRAY:
|
|
{
|
|
int seq_length = PySequence_Length(ob);
|
|
NS_ABORT_IF_FALSE(seq_length!=0, "VTYPE_ARRAY assumes at least one element!");
|
|
PyObject *first = PySequence_GetItem(ob, 0);
|
|
if (!first) break;
|
|
int array_type = BestVariantTypeForPyObject(first);
|
|
Py_DECREF(first);
|
|
// Arrays can't handle all types. This means we lost embedded NULLs.
|
|
// This should really be fixed in XPCOM.
|
|
if (array_type == nsIDataType::VTYPE_STRING_SIZE_IS) array_type = nsIDataType::VTYPE_CHAR_STR;
|
|
if (array_type == nsIDataType::VTYPE_WSTRING_SIZE_IS) array_type = nsIDataType::VTYPE_WCHAR_STR;
|
|
PRUint32 element_size = GetArrayElementSize(array_type);
|
|
int cb_buffer_pointer = seq_length * element_size;
|
|
void *buffer_pointer;
|
|
if ((buffer_pointer = (void *)nsMemory::Alloc(cb_buffer_pointer)) == nsnull) {
|
|
PyErr_NoMemory();
|
|
nr = NS_ERROR_UNEXPECTED;
|
|
break;
|
|
}
|
|
memset(buffer_pointer, 0, cb_buffer_pointer);
|
|
if (FillSingleArray(buffer_pointer, ob, seq_length, element_size, array_type)) {
|
|
nr = v->SetAsArray(array_type, &NS_GET_IID(nsISupports), seq_length, buffer_pointer);
|
|
FreeSingleArray(buffer_pointer, seq_length, array_type);
|
|
} else
|
|
nr = NS_ERROR_UNEXPECTED;
|
|
nsMemory::Free(buffer_pointer);
|
|
break;
|
|
}
|
|
case nsIDataType::VTYPE_EMPTY:
|
|
v->SetAsEmpty();
|
|
break;
|
|
case nsIDataType::VTYPE_EMPTY_ARRAY:
|
|
v->SetAsEmptyArray();
|
|
break;
|
|
case (PRUint16)-1:
|
|
PyErr_Format(PyExc_TypeError, "Objects of type '%s' can not be converted to an nsIVariant", ob->ob_type->tp_name);
|
|
return NULL;
|
|
default:
|
|
NS_ABORT_IF_FALSE(0, "BestVariantTypeForPyObject() returned a variant type not handled here!");
|
|
PyErr_Format(PyExc_TypeError, "Objects of type '%s' can not be converted to an nsIVariant", ob->ob_type->tp_name);
|
|
return NULL;
|
|
}
|
|
nsIVariant *ret;
|
|
v->QueryInterface(NS_GET_IID(nsIVariant), (void **)&ret);
|
|
return ret;
|
|
}
|
|
|
|
static PyObject *MyBool_FromBool(PRBool v)
|
|
{
|
|
PyObject *ret = v ? Py_True : Py_False;
|
|
Py_INCREF(ret);
|
|
return ret;
|
|
}
|
|
static PyObject *MyObject_FromInterface(nsISupports *p)
|
|
{
|
|
return Py_nsISupports::PyObjectFromInterface(p, NS_GET_IID(nsISupports), PR_FALSE);
|
|
}
|
|
|
|
#define GET_FROM_V(Type, FuncGet, FuncConvert) { \
|
|
Type t; \
|
|
if (NS_FAILED(nr = FuncGet( &t ))) goto done;\
|
|
ret = FuncConvert(t);\
|
|
break; \
|
|
}
|
|
|
|
PyObject *PyObject_FromVariantArray( nsIVariant *v)
|
|
{
|
|
nsresult nr;
|
|
NS_PRECONDITION(v, "NULL variant!");
|
|
if (!v)
|
|
return PyXPCOM_BuildPyException(NS_ERROR_INVALID_POINTER);
|
|
#ifdef NS_DEBUG
|
|
PRUint16 dt;
|
|
nr = v->GetDataType(&dt);
|
|
NS_ABORT_IF_FALSE(dt == nsIDataType::VTYPE_ARRAY, "expected an array variant");
|
|
#endif
|
|
nsIID iid;
|
|
void *p;
|
|
PRUint16 type;
|
|
PRUint32 count;
|
|
nr = v->GetAsArray(&type, &iid, &count, &p);
|
|
if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr);
|
|
PyObject *ret = UnpackSingleArray(p, count, (PRUint8)type, &iid);
|
|
FreeSingleArray(p, count, (PRUint8)type);
|
|
nsMemory::Free(p);
|
|
return ret;
|
|
}
|
|
|
|
PyObject *PyObject_FromVariant( nsIVariant *v)
|
|
{
|
|
if (!v) {
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
PRUint16 dt;
|
|
nsresult nr;
|
|
PyObject *ret = NULL;
|
|
nr = v->GetDataType(&dt);
|
|
if (NS_FAILED(nr)) goto done;
|
|
switch (dt) {
|
|
case nsIDataType::VTYPE_VOID:
|
|
case nsIDataType::VTYPE_EMPTY:
|
|
case nsIDataType::VTYPE_EMPTY_ARRAY:
|
|
ret = Py_None;
|
|
Py_INCREF(Py_None);
|
|
break;
|
|
case nsIDataType::VTYPE_ARRAY:
|
|
ret = PyObject_FromVariantArray(v);
|
|
break;
|
|
case nsIDataType::VTYPE_INT8:
|
|
case nsIDataType::VTYPE_INT16:
|
|
case nsIDataType::VTYPE_INT32:
|
|
GET_FROM_V(PRInt32, v->GetAsInt32, PyInt_FromLong);
|
|
case nsIDataType::VTYPE_UINT8:
|
|
case nsIDataType::VTYPE_UINT16:
|
|
case nsIDataType::VTYPE_UINT32:
|
|
GET_FROM_V(PRUint32, v->GetAsUint32, PyLong_FromUnsignedLong);
|
|
case nsIDataType::VTYPE_INT64:
|
|
GET_FROM_V(PRInt64, v->GetAsInt64, PyLong_FromLongLong);
|
|
case nsIDataType::VTYPE_UINT64:
|
|
GET_FROM_V(PRUint64, v->GetAsUint64, PyLong_FromUnsignedLongLong);
|
|
case nsIDataType::VTYPE_FLOAT:
|
|
case nsIDataType::VTYPE_DOUBLE:
|
|
GET_FROM_V(double, v->GetAsDouble, PyFloat_FromDouble);
|
|
case nsIDataType::VTYPE_BOOL:
|
|
GET_FROM_V(PRBool, v->GetAsBool, MyBool_FromBool);
|
|
default:
|
|
PyXPCOM_LogWarning("Converting variant to Python object - variant type '%d' unknown - using string.\n", dt);
|
|
// Fall through to the string case
|
|
case nsIDataType::VTYPE_CHAR:
|
|
case nsIDataType::VTYPE_CHAR_STR:
|
|
case nsIDataType::VTYPE_STRING_SIZE_IS:
|
|
case nsIDataType::VTYPE_CSTRING: {
|
|
nsCAutoString s;
|
|
if (NS_FAILED(nr=v->GetAsACString(s))) goto done;
|
|
ret = PyObject_FromNSString(s);
|
|
break;
|
|
}
|
|
case nsIDataType::VTYPE_WCHAR:
|
|
case nsIDataType::VTYPE_DOMSTRING:
|
|
case nsIDataType::VTYPE_WSTRING_SIZE_IS:
|
|
case nsIDataType::VTYPE_ASTRING: {
|
|
nsAutoString s;
|
|
if (NS_FAILED(nr=v->GetAsAString(s))) goto done;
|
|
ret = PyObject_FromNSString(s);
|
|
break;
|
|
}
|
|
case nsIDataType::VTYPE_ID:
|
|
GET_FROM_V(nsIID, v->GetAsID, Py_nsIID::PyObjectFromIID);
|
|
case nsIDataType::VTYPE_INTERFACE:
|
|
GET_FROM_V(nsISupports *, v->GetAsISupports, MyObject_FromInterface);
|
|
case nsIDataType::VTYPE_INTERFACE_IS: {
|
|
nsISupports *p;
|
|
nsIID *iid;
|
|
if (NS_FAILED(nr=v->GetAsInterface(&iid, (void **)&p))) goto done;
|
|
ret = Py_nsISupports::PyObjectFromInterface(p, *iid, PR_FALSE);
|
|
break;
|
|
}
|
|
}
|
|
done:
|
|
if (NS_FAILED(nr)) {
|
|
NS_ABORT_IF_FALSE(ret==NULL, "Have an error, but also a return val!");
|
|
PyXPCOM_BuildPyException(nr);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
// ------------------------------------------------------------------------
|
|
// TypeDescriptor helper class
|
|
// ------------------------------------------------------------------------
|
|
class PythonTypeDescriptor {
|
|
public:
|
|
PythonTypeDescriptor() {
|
|
param_flags = type_flags = argnum = argnum2 = 0;
|
|
extra = NULL;
|
|
is_auto_out = PR_FALSE;
|
|
is_auto_in = PR_FALSE;
|
|
have_set_auto = PR_FALSE;
|
|
}
|
|
~PythonTypeDescriptor() {
|
|
Py_XDECREF(extra);
|
|
}
|
|
PRUint8 param_flags;
|
|
PRUint8 type_flags;
|
|
PRUint8 argnum; /* used for iid_is and size_is */
|
|
PRUint8 argnum2; /* used for length_is */
|
|
PyObject *extra; // The IID object, or the type of the array.
|
|
// Extra items to help our processing.
|
|
// Is this auto-filled by some other "in" param?
|
|
PRBool is_auto_in;
|
|
// Is this auto-filled by some other "out" param?
|
|
PRBool is_auto_out;
|
|
// If is_auto_out, have I already filled it? Used when multiple
|
|
// params share a size_is fields - first time sets it, subsequent
|
|
// time check it.
|
|
PRBool have_set_auto;
|
|
};
|
|
|
|
static int ProcessPythonTypeDescriptors(PythonTypeDescriptor *pdescs, int num)
|
|
{
|
|
// Loop over the array, checking all the params marked as having an arg.
|
|
// If these args nominate another arg as the size_is param, then
|
|
// we reset the size_is param to _not_ requiring an arg.
|
|
int i;
|
|
for (i=0;i<num;i++) {
|
|
PythonTypeDescriptor &ptd = pdescs[i];
|
|
// Can't use XPT_TDP_TAG() - it uses a ".flags" reference in the macro.
|
|
switch (ptd.type_flags & XPT_TDP_TAGMASK) {
|
|
case nsXPTType::T_ARRAY:
|
|
NS_ABORT_IF_FALSE(ptd.argnum < num, "Bad dependent index");
|
|
if (ptd.argnum2 < num) {
|
|
if (XPT_PD_IS_IN(ptd.param_flags))
|
|
pdescs[ptd.argnum2].is_auto_in = PR_TRUE;
|
|
if (XPT_PD_IS_OUT(ptd.param_flags))
|
|
pdescs[ptd.argnum2].is_auto_out = PR_TRUE;
|
|
}
|
|
break;
|
|
case nsXPTType::T_PSTRING_SIZE_IS:
|
|
case nsXPTType::T_PWSTRING_SIZE_IS:
|
|
NS_ABORT_IF_FALSE(ptd.argnum < num, "Bad dependent index");
|
|
if (ptd.argnum < num) {
|
|
if (XPT_PD_IS_IN(ptd.param_flags))
|
|
pdescs[ptd.argnum].is_auto_in = PR_TRUE;
|
|
if (XPT_PD_IS_OUT(ptd.param_flags))
|
|
pdescs[ptd.argnum].is_auto_out = PR_TRUE;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
int total_params_needed = 0;
|
|
for (i=0;i<num;i++)
|
|
if (XPT_PD_IS_IN(pdescs[i].param_flags) && !pdescs[i].is_auto_in && !XPT_PD_IS_DIPPER(pdescs[i].param_flags))
|
|
total_params_needed++;
|
|
|
|
return total_params_needed;
|
|
}
|
|
|
|
/*************************************************************************
|
|
**************************************************************************
|
|
|
|
Helpers when CALLING interfaces.
|
|
|
|
**************************************************************************
|
|
*************************************************************************/
|
|
|
|
PyXPCOM_InterfaceVariantHelper::PyXPCOM_InterfaceVariantHelper()
|
|
{
|
|
m_var_array=nsnull;
|
|
m_buffer_array=nsnull;
|
|
m_pyparams=nsnull;
|
|
m_num_array = 0;
|
|
}
|
|
|
|
PyXPCOM_InterfaceVariantHelper::~PyXPCOM_InterfaceVariantHelper()
|
|
{
|
|
Py_XDECREF(m_pyparams);
|
|
for (int i=0;i<m_num_array;i++) {
|
|
if (m_var_array) {
|
|
nsXPTCVariant &ns_v = m_var_array[i];
|
|
if (ns_v.IsValInterface()) {
|
|
if (ns_v.val.p) {
|
|
Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
|
|
((nsISupports *)ns_v.val.p)->Release();
|
|
Py_END_ALLOW_THREADS;
|
|
}
|
|
}
|
|
if (ns_v.IsValDOMString() && ns_v.val.p) {
|
|
delete (const nsAString *)ns_v.val.p;
|
|
}
|
|
if (ns_v.IsValCString() && ns_v.val.p) {
|
|
delete (const nsACString *)ns_v.val.p;
|
|
}
|
|
if (ns_v.IsValUTF8String() && ns_v.val.p) {
|
|
delete (const nsACString *)ns_v.val.p;
|
|
}
|
|
if (ns_v.IsValArray()) {
|
|
nsXPTCVariant &ns_v = m_var_array[i];
|
|
if (ns_v.val.p) {
|
|
PRUint8 array_type = (PRUint8)PyInt_AsLong(m_python_type_desc_array[i].extra);
|
|
PRUint32 seq_size = GetSizeIs(i, PR_FALSE);
|
|
FreeSingleArray(ns_v.val.p, seq_size, array_type);
|
|
}
|
|
}
|
|
// IsOwned must be the last check of the loop, as
|
|
// this frees the underlying data used above (eg, by the array free process)
|
|
if (ns_v.IsValAllocated() && !ns_v.IsValInterface() && !ns_v.IsValDOMString()) {
|
|
NS_ABORT_IF_FALSE(ns_v.IsPtrData(), "expecting a pointer to free");
|
|
nsMemory::Free(ns_v.val.p);
|
|
}
|
|
}
|
|
if (m_buffer_array && m_buffer_array[i])
|
|
nsMemory::Free(m_buffer_array[i]);
|
|
}
|
|
delete [] m_python_type_desc_array;
|
|
delete [] m_buffer_array;
|
|
delete [] m_var_array;
|
|
}
|
|
|
|
PRBool PyXPCOM_InterfaceVariantHelper::Init(PyObject *obParams)
|
|
{
|
|
PRBool ok = PR_FALSE;
|
|
int i;
|
|
int total_params_needed = 0;
|
|
if (!PySequence_Check(obParams) || PySequence_Length(obParams)!=2) {
|
|
PyErr_Format(PyExc_TypeError, "Param descriptors must be a sequence of exactly length 2");
|
|
return PR_FALSE;
|
|
}
|
|
PyObject *typedescs = PySequence_GetItem(obParams, 0);
|
|
if (typedescs==NULL)
|
|
return PR_FALSE;
|
|
// NOTE: The length of the typedescs may be different than the
|
|
// args actually passed. The typedescs always include all
|
|
// hidden params (such as "size_is"), while the actual
|
|
// args never include this.
|
|
m_num_array = PySequence_Length(typedescs);
|
|
if (PyErr_Occurred()) goto done;
|
|
|
|
m_pyparams = PySequence_GetItem(obParams, 1);
|
|
if (m_pyparams==NULL) goto done;
|
|
|
|
m_python_type_desc_array = new PythonTypeDescriptor[m_num_array];
|
|
if (!m_python_type_desc_array) goto done;
|
|
|
|
// Pull apart the type descs and stash them.
|
|
for (i=0;i<m_num_array;i++) {
|
|
PyObject *desc_object = PySequence_GetItem(typedescs, i);
|
|
if (desc_object==NULL)
|
|
goto done;
|
|
|
|
// Pull apart the typedesc tuple back into a structure we can work with.
|
|
PythonTypeDescriptor &ptd = m_python_type_desc_array[i];
|
|
PRBool this_ok = PyArg_ParseTuple(desc_object, "bbbbO:type_desc",
|
|
&ptd.param_flags, &ptd.type_flags, &ptd.argnum, &ptd.argnum2, &ptd.extra);
|
|
Py_DECREF(desc_object);
|
|
if (!this_ok) goto done;
|
|
Py_INCREF(ptd.extra);
|
|
|
|
}
|
|
total_params_needed = ProcessPythonTypeDescriptors(m_python_type_desc_array, m_num_array);
|
|
// OK - check we got the number of args we expected.
|
|
// If not, its really an internal error rather than the user.
|
|
if (PySequence_Length(m_pyparams) != total_params_needed) {
|
|
PyErr_Format(PyExc_ValueError, "The type descriptions indicate %d args are needed, but %d were provided",
|
|
total_params_needed, PySequence_Length(m_pyparams));
|
|
goto done;
|
|
}
|
|
|
|
// Init the other arrays.
|
|
m_var_array = new nsXPTCVariant[m_num_array];
|
|
if (!m_var_array) goto done;
|
|
memset(m_var_array, 0, m_num_array * sizeof(m_var_array[0]));
|
|
|
|
m_buffer_array = new void *[m_num_array];
|
|
if (!m_buffer_array) goto done;
|
|
memset(m_buffer_array, 0, m_num_array * sizeof(m_buffer_array[0]));
|
|
|
|
ok = PR_TRUE;
|
|
done:
|
|
if (!ok && !PyErr_Occurred())
|
|
PyErr_NoMemory();
|
|
|
|
Py_XDECREF(typedescs);
|
|
return ok;
|
|
}
|
|
|
|
|
|
PRBool PyXPCOM_InterfaceVariantHelper::FillArray()
|
|
{
|
|
int param_index = 0;
|
|
int i;
|
|
for (i=0;i<m_num_array;i++) {
|
|
PythonTypeDescriptor &ptd = m_python_type_desc_array[i];
|
|
// stash the type_flags into the variant, and remember how many extra bits of info we have.
|
|
m_var_array[i].type = ptd.type_flags;
|
|
if (XPT_PD_IS_IN(ptd.param_flags) && !ptd.is_auto_in && !XPT_PD_IS_DIPPER(ptd.param_flags)) {
|
|
if (!FillInVariant(ptd, i, param_index))
|
|
return PR_FALSE;
|
|
param_index++;
|
|
}
|
|
if ((XPT_PD_IS_OUT(ptd.param_flags) && !ptd.is_auto_out) || XPT_PD_IS_DIPPER(ptd.param_flags)) {
|
|
if (!PrepareOutVariant(ptd, i))
|
|
return PR_FALSE;
|
|
}
|
|
}
|
|
// There may be out "size_is" params we havent touched yet
|
|
// (ie, as the param itself is marked "out", we never got to
|
|
// touch the associated "size_is".
|
|
// Final loop to handle this.
|
|
for (i=0;i<m_num_array;i++) {
|
|
PythonTypeDescriptor &ptd = m_python_type_desc_array[i];
|
|
if (ptd.is_auto_out && !ptd.have_set_auto) {
|
|
// Call PrepareOutVariant to ensure buffers etc setup.
|
|
if (!PrepareOutVariant(ptd, i))
|
|
return PR_FALSE;
|
|
}
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
|
|
|
|
PRBool PyXPCOM_InterfaceVariantHelper::SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size)
|
|
{
|
|
NS_ABORT_IF_FALSE(var_index < m_num_array, "var_index param is invalid");
|
|
PRUint8 argnum = is_arg1 ?
|
|
m_python_type_desc_array[var_index].argnum :
|
|
m_python_type_desc_array[var_index].argnum2;
|
|
NS_ABORT_IF_FALSE(argnum < m_num_array, "size_is param is invalid");
|
|
PythonTypeDescriptor &td_size = m_python_type_desc_array[argnum];
|
|
NS_ABORT_IF_FALSE(td_size.is_auto_in || td_size.is_auto_out, "Setting size_is, but param is not marked as auto!");
|
|
NS_ABORT_IF_FALSE( (td_size.type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32");
|
|
nsXPTCVariant &ns_v = m_var_array[argnum];
|
|
|
|
if (!td_size.have_set_auto) {
|
|
ns_v.type = td_size.type_flags;
|
|
ns_v.val.u32 = new_size;
|
|
// In case it is "out", setup the necessary pointers.
|
|
PrepareOutVariant(td_size, argnum);
|
|
td_size.have_set_auto = PR_TRUE;
|
|
} else {
|
|
if (ns_v.val.u32 != new_size) {
|
|
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);
|
|
return PR_FALSE;
|
|
}
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
|
|
PRUint32 PyXPCOM_InterfaceVariantHelper::GetSizeIs( int var_index, PRBool is_arg1)
|
|
{
|
|
NS_ABORT_IF_FALSE(var_index < m_num_array, "var_index param is invalid");
|
|
PRUint8 argnum = is_arg1 ?
|
|
m_python_type_desc_array[var_index].argnum :
|
|
m_python_type_desc_array[var_index].argnum2;
|
|
NS_ABORT_IF_FALSE(argnum < m_num_array, "size_is param is invalid");
|
|
NS_ABORT_IF_FALSE( (m_python_type_desc_array[argnum].type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32");
|
|
PRBool is_out = XPT_PD_IS_OUT(m_python_type_desc_array[argnum].param_flags);
|
|
nsXPTCVariant &ns_v = m_var_array[argnum];
|
|
return is_out ? *((PRUint32 *)ns_v.ptr) : ns_v.val.u32;
|
|
}
|
|
|
|
#define MAKE_VALUE_BUFFER(size) \
|
|
if ((this_buffer_pointer = (void *)nsMemory::Alloc((size))) == nsnull) { \
|
|
PyErr_NoMemory(); \
|
|
BREAK_FALSE; \
|
|
}
|
|
|
|
PRBool PyXPCOM_InterfaceVariantHelper::FillInVariant(const PythonTypeDescriptor &td, int value_index, int param_index)
|
|
{
|
|
PRBool rc = PR_TRUE;
|
|
// Get a reference to the variant we are filling for convenience.
|
|
nsXPTCVariant &ns_v = m_var_array[value_index];
|
|
NS_ABORT_IF_FALSE(ns_v.type == td.type_flags, "Expecting variant all setup for us");
|
|
|
|
// We used to avoid passing internal buffers to PyString etc objects
|
|
// for 2 reasons: paranoia (so incorrect external components couldn't break
|
|
// Python) and simplicity (in vs in-out issues, etc)
|
|
// However, at least one C++ implemented component (nsITimelineService)
|
|
// uses a "char *", and keys on the address (assuming that the same
|
|
// *pointer* is passed rather than value. Therefore, we have a special case
|
|
// - T_CHAR_STR that is "in" gets the Python string pointer passed.
|
|
void *&this_buffer_pointer = m_buffer_array[value_index]; // Freed at object destruction with PyMem_Free()
|
|
NS_ABORT_IF_FALSE(this_buffer_pointer==nsnull, "We appear to already have a buffer");
|
|
int cb_this_buffer_pointer = 0;
|
|
if (XPT_PD_IS_IN(td.param_flags)) {
|
|
NS_ABORT_IF_FALSE(!td.is_auto_in, "Param is 'auto-in', but we are filling it normally!");
|
|
PyObject *val_use = NULL; // a temp object converters can use, and will be DECREF'd
|
|
PyObject *val = PySequence_GetItem(m_pyparams, param_index);
|
|
NS_WARN_IF_FALSE(val, "Have an 'in' param, but no Python value!");
|
|
if (val==NULL) {
|
|
PyErr_Format(PyExc_ValueError, "Param %d is marked as 'in', but no value was given", value_index);
|
|
return PR_FALSE;
|
|
}
|
|
switch (XPT_TDP_TAG(ns_v.type)) {
|
|
case nsXPTType::T_I8:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
|
|
ns_v.val.i8 = (PRInt8)PyInt_AsLong(val_use);
|
|
break;
|
|
case nsXPTType::T_I16:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
|
|
ns_v.val.i16 = (PRInt16)PyInt_AsLong(val_use);
|
|
break;
|
|
case nsXPTType::T_I32:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
|
|
ns_v.val.i32 = (PRInt32)PyInt_AsLong(val_use);
|
|
break;
|
|
case nsXPTType::T_I64:
|
|
if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE
|
|
ns_v.val.i64 = (PRInt64)PyLong_AsLongLong(val_use);
|
|
break;
|
|
case nsXPTType::T_U8:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
|
|
ns_v.val.u8 = (PRUint8)PyInt_AsLong(val_use);
|
|
break;
|
|
case nsXPTType::T_U16:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
|
|
ns_v.val.u16 = (PRUint16)PyInt_AsLong(val_use);
|
|
break;
|
|
case nsXPTType::T_U32:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
|
|
ns_v.val.u32 = (PRUint32)PyInt_AsLong(val_use);
|
|
break;
|
|
case nsXPTType::T_U64:
|
|
if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE
|
|
ns_v.val.u64 = (PRUint64)PyLong_AsUnsignedLongLong(val_use);
|
|
break;
|
|
case nsXPTType::T_FLOAT:
|
|
if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
|
|
ns_v.val.f = (float)PyFloat_AsDouble(val_use);
|
|
break;
|
|
case nsXPTType::T_DOUBLE:
|
|
if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
|
|
ns_v.val.d = PyFloat_AsDouble(val_use);
|
|
break;
|
|
case nsXPTType::T_BOOL:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
|
|
ns_v.val.b = (PRBool)PyInt_AsLong(val_use);
|
|
break;
|
|
case nsXPTType::T_CHAR:{
|
|
if (!PyString_Check(val) && !PyUnicode_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
|
|
BREAK_FALSE;
|
|
}
|
|
if ((val_use = PyObject_Str(val))==NULL)
|
|
BREAK_FALSE;
|
|
// Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
|
|
NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
|
|
if (PyString_GET_SIZE(val_use) != 1) {
|
|
PyErr_SetString(PyExc_ValueError, "Must specify a one character string for a character");
|
|
BREAK_FALSE;
|
|
}
|
|
|
|
ns_v.val.c = *PyString_AS_STRING(val_use);
|
|
break;
|
|
}
|
|
|
|
case nsXPTType::T_WCHAR: {
|
|
if (!PyString_Check(val) && !PyUnicode_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
|
|
BREAK_FALSE;
|
|
}
|
|
if ((val_use = PyUnicodeUCS2_FromObject(val))==NULL)
|
|
BREAK_FALSE;
|
|
// Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
|
|
NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicodeUCS2_FromObject didnt return a unicode object!");
|
|
if (PyUnicode_GET_SIZE(val_use) != 1) {
|
|
PyErr_SetString(PyExc_ValueError, "Must specify a one character string for a character");
|
|
BREAK_FALSE;
|
|
}
|
|
ns_v.val.wc = *PyUnicode_AS_UNICODE(val_use);
|
|
break;
|
|
}
|
|
// case nsXPTType::T_VOID: /* fall through */
|
|
case nsXPTType::T_IID:
|
|
nsIID iid;
|
|
MAKE_VALUE_BUFFER(sizeof(nsIID));
|
|
if (!Py_nsIID::IIDFromPyObject(val, &iid))
|
|
BREAK_FALSE;
|
|
memcpy(this_buffer_pointer, &iid, sizeof(iid));
|
|
ns_v.val.p = this_buffer_pointer;
|
|
break;
|
|
case nsXPTType::T_ASTRING:
|
|
case nsXPTType::T_DOMSTRING: {
|
|
if (val==Py_None) {
|
|
ns_v.val.p = new nsString(nsnull);
|
|
} else {
|
|
if (!PyString_Check(val) && !PyUnicode_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
|
|
BREAK_FALSE;
|
|
}
|
|
if ((val_use = PyUnicodeUCS2_FromObject(val))==NULL)
|
|
BREAK_FALSE;
|
|
// Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
|
|
NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicodeUCS2_FromObject didnt return a unicode object!");
|
|
ns_v.val.p = new nsString(PyUnicode_AS_UNICODE(val_use),
|
|
PyUnicode_GET_SIZE(val_use));
|
|
}
|
|
if (!ns_v.val.p) {
|
|
PyErr_NoMemory();
|
|
BREAK_FALSE;
|
|
}
|
|
// We created it - flag as such for cleanup.
|
|
ns_v.flags |= nsXPTCVariant::VAL_IS_DOMSTR;
|
|
break;
|
|
}
|
|
case nsXPTType::T_CSTRING:
|
|
case nsXPTType::T_UTF8STRING: {
|
|
PRBool bIsUTF8 = XPT_TDP_TAG(ns_v.type) == nsXPTType::T_UTF8STRING;
|
|
if (val==Py_None) {
|
|
ns_v.val.p = new nsCString();
|
|
} else {
|
|
// strings are assumed to already be UTF8 encoded.
|
|
if (PyString_Check(val)) {
|
|
val_use = val;
|
|
Py_INCREF(val);
|
|
// Unicode objects are encoded by us.
|
|
} else if (PyUnicode_Check(val)) {
|
|
if (bIsUTF8)
|
|
val_use = PyUnicode_AsUTF8String(val);
|
|
else
|
|
val_use = PyObject_Str(val);
|
|
} else {
|
|
PyErr_SetString(PyExc_TypeError, "UTF8 parameters must be string or Unicode objects");
|
|
BREAK_FALSE;
|
|
}
|
|
if (!val_use)
|
|
BREAK_FALSE;
|
|
ns_v.val.p = new nsCString(PyString_AS_STRING(val_use),
|
|
PyString_GET_SIZE(val_use));
|
|
}
|
|
|
|
if (!ns_v.val.p) {
|
|
PyErr_NoMemory();
|
|
BREAK_FALSE;
|
|
}
|
|
// We created it - flag as such for cleanup.
|
|
ns_v.flags |= bIsUTF8 ? nsXPTCVariant::VAL_IS_UTF8STR : nsXPTCVariant::VAL_IS_CSTR;
|
|
break;
|
|
}
|
|
case nsXPTType::T_CHAR_STR: {
|
|
if (val==Py_None) {
|
|
ns_v.val.p = nsnull;
|
|
break;
|
|
}
|
|
// If an "in" char *, and we have a PyString, then pass the
|
|
// pointer (hoping everyone else plays by the rules too.
|
|
if (!XPT_PD_IS_OUT(td.param_flags) && PyString_Check(val)) {
|
|
ns_v.val.p = PyString_AS_STRING(val);
|
|
break;
|
|
}
|
|
|
|
if (!PyString_Check(val) && !PyUnicode_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
|
|
BREAK_FALSE;
|
|
}
|
|
if ((val_use = PyObject_Str(val))==NULL)
|
|
BREAK_FALSE;
|
|
// Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
|
|
NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
|
|
|
|
cb_this_buffer_pointer = PyString_GET_SIZE(val_use)+1;
|
|
MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
|
|
memcpy(this_buffer_pointer, PyString_AS_STRING(val_use), cb_this_buffer_pointer);
|
|
ns_v.val.p = this_buffer_pointer;
|
|
break;
|
|
}
|
|
|
|
case nsXPTType::T_WCHAR_STR: {
|
|
if (val==Py_None) {
|
|
ns_v.val.p = nsnull;
|
|
break;
|
|
}
|
|
// If an "in" char *, and we have a PyString, then pass the
|
|
// pointer (hoping everyone else plays by the rules too.
|
|
if (!XPT_PD_IS_OUT(td.param_flags) && PyUnicode_Check(val)) {
|
|
ns_v.val.p = PyUnicode_AS_UNICODE(val);
|
|
break;
|
|
}
|
|
if (!PyString_Check(val) && !PyUnicode_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
|
|
BREAK_FALSE;
|
|
}
|
|
if ((val_use = PyUnicodeUCS2_FromObject(val))==NULL)
|
|
BREAK_FALSE;
|
|
NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicodeUCS2_FromObject didnt return a Unicode object!");
|
|
cb_this_buffer_pointer = (PyUnicode_GET_SIZE(val_use)+1) * sizeof(Py_UNICODE);
|
|
MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
|
|
memcpy(this_buffer_pointer, PyUnicode_AS_UNICODE(val_use), cb_this_buffer_pointer);
|
|
ns_v.val.p = this_buffer_pointer;
|
|
break;
|
|
}
|
|
case nsXPTType::T_INTERFACE: {
|
|
nsIID iid;
|
|
if (!Py_nsIID::IIDFromPyObject(td.extra, &iid))
|
|
BREAK_FALSE;
|
|
if (!Py_nsISupports::InterfaceFromPyObject(
|
|
val,
|
|
iid,
|
|
(nsISupports **)&ns_v.val.p,
|
|
PR_TRUE))
|
|
BREAK_FALSE;
|
|
// We have added a reference - flag as such for cleanup.
|
|
ns_v.flags |= nsXPTCVariant::VAL_IS_IFACE;
|
|
break;
|
|
}
|
|
case nsXPTType::T_INTERFACE_IS: {
|
|
nsIID iid;
|
|
nsXPTCVariant &ns_viid = m_var_array[td.argnum];
|
|
NS_WARN_IF_FALSE(XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID, "The INTERFACE_IS iid describer isnt an IID!");
|
|
// This is a pretty serious problem, but not Python's fault!
|
|
// Just return an nsISupports and hope the caller does whatever
|
|
// QI they need before using it.
|
|
if (XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID &&
|
|
XPT_PD_IS_IN(ns_viid.type)) {
|
|
nsIID *piid = (nsIID *)ns_viid.val.p;
|
|
if (piid==NULL)
|
|
// Also serious, but like below, not our fault!
|
|
iid = NS_GET_IID(nsISupports);
|
|
else
|
|
iid = *piid;
|
|
} else
|
|
// Use NULL IID to avoid a QI in this case.
|
|
iid = Py_nsIID_NULL;
|
|
if (!Py_nsISupports::InterfaceFromPyObject(
|
|
val,
|
|
iid,
|
|
(nsISupports **)&ns_v.val.p,
|
|
PR_TRUE))
|
|
BREAK_FALSE;
|
|
// We have added a reference - flag as such for cleanup.
|
|
ns_v.flags |= nsXPTCVariant::VAL_IS_IFACE;
|
|
break;
|
|
}
|
|
case nsXPTType::T_PSTRING_SIZE_IS: {
|
|
if (val==Py_None) {
|
|
ns_v.val.p = nsnull;
|
|
break;
|
|
}
|
|
if (!PyString_Check(val) && !PyUnicode_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
|
|
BREAK_FALSE;
|
|
}
|
|
if ((val_use = PyObject_Str(val))==NULL)
|
|
BREAK_FALSE;
|
|
// Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
|
|
NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
|
|
|
|
cb_this_buffer_pointer = PyString_GET_SIZE(val_use);
|
|
MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
|
|
memcpy(this_buffer_pointer, PyString_AS_STRING(val_use), cb_this_buffer_pointer);
|
|
ns_v.val.p = this_buffer_pointer;
|
|
rc = SetSizeIs(value_index, PR_TRUE, cb_this_buffer_pointer);
|
|
break;
|
|
}
|
|
|
|
case nsXPTType::T_PWSTRING_SIZE_IS: {
|
|
if (val==Py_None) {
|
|
ns_v.val.p = nsnull;
|
|
break;
|
|
}
|
|
if (!PyString_Check(val) && !PyUnicode_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
|
|
BREAK_FALSE;
|
|
}
|
|
if ((val_use = PyUnicodeUCS2_FromObject(val))==NULL)
|
|
BREAK_FALSE;
|
|
// Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
|
|
NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyObject_Unicode didnt return a unicode object!");
|
|
|
|
cb_this_buffer_pointer = PyUnicode_GET_SIZE(val_use) * sizeof(PRUnichar);
|
|
MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
|
|
memcpy(this_buffer_pointer, PyUnicode_AS_UNICODE(val_use), cb_this_buffer_pointer);
|
|
ns_v.val.p = this_buffer_pointer;
|
|
rc = SetSizeIs(value_index, PR_TRUE, PyUnicode_GET_SIZE(val_use) );
|
|
break;
|
|
}
|
|
case nsXPTType::T_ARRAY: {
|
|
if (val==Py_None) {
|
|
ns_v.val.p = nsnull;
|
|
break;
|
|
}
|
|
if (!PyInt_Check(td.extra)) {
|
|
PyErr_SetString(PyExc_TypeError, "The array info is not valid");
|
|
BREAK_FALSE;
|
|
}
|
|
if (!PySequence_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a sequence");
|
|
BREAK_FALSE;
|
|
}
|
|
int array_type = PyInt_AsLong(td.extra);
|
|
PRUint32 element_size = GetArrayElementSize(array_type);
|
|
int seq_length = PySequence_Length(val);
|
|
cb_this_buffer_pointer = seq_length * element_size;
|
|
if (cb_this_buffer_pointer==0)
|
|
// prevent assertions allocing zero bytes. Can't use NULL.
|
|
cb_this_buffer_pointer = 1;
|
|
MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
|
|
memset(this_buffer_pointer, 0, cb_this_buffer_pointer);
|
|
rc = FillSingleArray(this_buffer_pointer, val, seq_length, element_size, array_type&XPT_TDP_TAGMASK);
|
|
if (!rc) break;
|
|
rc = SetSizeIs(value_index, PR_FALSE, seq_length);
|
|
if (!rc) break;
|
|
ns_v.flags |= nsXPTCVariant::VAL_IS_ARRAY;
|
|
ns_v.val.p = this_buffer_pointer;
|
|
break;
|
|
}
|
|
default:
|
|
PyErr_Format(PyExc_TypeError, "The object type (0x%x) is unknown", XPT_TDP_TAG(ns_v.type));
|
|
rc = PR_FALSE;
|
|
break;
|
|
}
|
|
Py_DECREF(val); // Cant be NULL!
|
|
Py_XDECREF(val_use);
|
|
}
|
|
return rc && !PyErr_Occurred();
|
|
}
|
|
|
|
PRBool PyXPCOM_InterfaceVariantHelper::PrepareOutVariant(const PythonTypeDescriptor &td, int value_index)
|
|
{
|
|
PRBool rc = PR_TRUE;
|
|
nsXPTCVariant &ns_v = m_var_array[value_index];
|
|
void *&this_buffer_pointer = m_buffer_array[value_index]; // Freed at object destruction with PyMem_Free()
|
|
// Do the out param thang...
|
|
if (XPT_PD_IS_OUT(td.param_flags) || XPT_PD_IS_DIPPER(td.param_flags)) {
|
|
NS_ABORT_IF_FALSE(ns_v.ptr == NULL, "already have a pointer!");
|
|
ns_v.ptr = &ns_v;
|
|
ns_v.flags |= nsXPTCVariant::PTR_IS_DATA;
|
|
|
|
// Special flags based on the data type
|
|
switch (XPT_TDP_TAG(ns_v.type)) {
|
|
case nsXPTType::T_I8:
|
|
case nsXPTType::T_I16:
|
|
case nsXPTType::T_I32:
|
|
case nsXPTType::T_I64:
|
|
case nsXPTType::T_U8:
|
|
case nsXPTType::T_U16:
|
|
case nsXPTType::T_U32:
|
|
case nsXPTType::T_U64:
|
|
case nsXPTType::T_FLOAT:
|
|
case nsXPTType::T_DOUBLE:
|
|
case nsXPTType::T_BOOL:
|
|
case nsXPTType::T_CHAR:
|
|
case nsXPTType::T_WCHAR:
|
|
case nsXPTType::T_VOID:
|
|
break;
|
|
|
|
case nsXPTType::T_INTERFACE:
|
|
case nsXPTType::T_INTERFACE_IS:
|
|
NS_ABORT_IF_FALSE(this_buffer_pointer==NULL, "Can't have an interface and a buffer pointer!");
|
|
ns_v.flags |= nsXPTCVariant::VAL_IS_IFACE;
|
|
ns_v.flags |= nsXPTCVariant::VAL_IS_ALLOCD;
|
|
break;
|
|
case nsXPTType::T_ARRAY:
|
|
ns_v.flags |= nsXPTCVariant::VAL_IS_ARRAY;
|
|
ns_v.flags |= nsXPTCVariant::VAL_IS_ALLOCD;
|
|
// Even if ns_val.p already setup as part of "in" processing,
|
|
// we need to ensure setup for out.
|
|
NS_ABORT_IF_FALSE(ns_v.val.p==nsnull || ns_v.val.p==this_buffer_pointer, "Garbage in our pointer?");
|
|
ns_v.val.p = this_buffer_pointer;
|
|
this_buffer_pointer = nsnull;
|
|
break;
|
|
case nsXPTType::T_PWSTRING_SIZE_IS:
|
|
case nsXPTType::T_PSTRING_SIZE_IS:
|
|
case nsXPTType::T_WCHAR_STR:
|
|
case nsXPTType::T_CHAR_STR:
|
|
case nsXPTType::T_IID:
|
|
// If we stashed a value in the this_buffer_pointer, and
|
|
// we are passing it as an OUT param, we do _not_ want to
|
|
// treat it as a temporary buffer.
|
|
// For example, if we pass an IID or string as an IN param,
|
|
// we allocate a buffer for the value, but this is NOT cleaned up
|
|
// via normal VARIANT cleanup rules - hence we clean it up ourselves.
|
|
// If the param is IN/OUT, then the buffer falls under the normal variant
|
|
// rules (ie, is flagged as VAL_IS_ALLOCD), so we dont clean it as a temporary.
|
|
// (it may have been changed under us - we free the _new_ value.
|
|
// Even if ns_val.p already setup as part of "in" processing,
|
|
// we need to ensure setup for out.
|
|
NS_ABORT_IF_FALSE(ns_v.val.p==nsnull || ns_v.val.p==this_buffer_pointer, "Garbage in our pointer?");
|
|
ns_v.val.p = this_buffer_pointer;
|
|
ns_v.flags |= nsXPTCVariant::VAL_IS_ALLOCD;
|
|
this_buffer_pointer = nsnull;
|
|
break;
|
|
case nsXPTType::T_DOMSTRING:
|
|
case nsXPTType::T_ASTRING: {
|
|
NS_ABORT_IF_FALSE(ns_v.val.p==nsnull, "T_DOMTSTRINGS cant be out and have a value (ie, no in/outs are allowed!");
|
|
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!");
|
|
ns_v.flags |= nsXPTCVariant::VAL_IS_DOMSTR;
|
|
// Dippers are really treated like "in" params.
|
|
ns_v.ptr = new nsString();
|
|
ns_v.val.p = ns_v.ptr; // VAL_IS_* says the .p is what gets freed
|
|
if (!ns_v.ptr) {
|
|
PyErr_NoMemory();
|
|
rc = PR_FALSE;
|
|
}
|
|
break;
|
|
}
|
|
case nsXPTType::T_CSTRING:
|
|
case nsXPTType::T_UTF8STRING: {
|
|
NS_ABORT_IF_FALSE(ns_v.val.p==nsnull, "T_DOMTSTRINGS cant be out and have a value (ie, no in/outs are allowed!");
|
|
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!");
|
|
ns_v.flags |= ( XPT_TDP_TAG(ns_v.type)==nsXPTType::T_CSTRING ? nsXPTCVariant::VAL_IS_CSTR : nsXPTCVariant::VAL_IS_UTF8STR);
|
|
ns_v.ptr = new nsCString();
|
|
ns_v.val.p = ns_v.ptr; // VAL_IS_* says the .p is what gets freed
|
|
if (!ns_v.ptr) {
|
|
PyErr_NoMemory();
|
|
rc = PR_FALSE;
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
NS_ABORT_IF_FALSE(0, "Unknown type - don't know how to prepare the output value");
|
|
break; // Nothing to do!
|
|
}
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
PyObject *PyXPCOM_InterfaceVariantHelper::MakeSinglePythonResult(int index)
|
|
{
|
|
nsXPTCVariant &ns_v = m_var_array[index];
|
|
PyObject *ret = nsnull;
|
|
NS_ABORT_IF_FALSE(ns_v.IsPtrData() || ns_v.IsValDOMString(), "expecting a pointer if you want a result!");
|
|
|
|
// Re-fetch the type descriptor.
|
|
PythonTypeDescriptor &td = m_python_type_desc_array[index];
|
|
// Make sure the type tag of the variant hasnt changed on us.
|
|
NS_ABORT_IF_FALSE(ns_v.type==td.type_flags, "variant type has changed under us!");
|
|
|
|
// If the pointer is NULL, we can get out now!
|
|
if (ns_v.ptr==nsnull) {
|
|
Py_INCREF(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
switch (XPT_TDP_TAG(ns_v.type)) {
|
|
case nsXPTType::T_I8:
|
|
ret = PyInt_FromLong( *((PRInt8 *)ns_v.ptr) );
|
|
break;
|
|
case nsXPTType::T_I16:
|
|
ret = PyInt_FromLong( *((PRInt16 *)ns_v.ptr) );
|
|
break;
|
|
case nsXPTType::T_I32:
|
|
ret = PyInt_FromLong( *((PRInt32 *)ns_v.ptr) );
|
|
break;
|
|
case nsXPTType::T_I64:
|
|
ret = PyLong_FromLongLong( *((PRInt64 *)ns_v.ptr) );
|
|
break;
|
|
case nsXPTType::T_U8:
|
|
ret = PyInt_FromLong( *((PRUint8 *)ns_v.ptr) );
|
|
break;
|
|
case nsXPTType::T_U16:
|
|
ret = PyInt_FromLong( *((PRUint16 *)ns_v.ptr) );
|
|
break;
|
|
case nsXPTType::T_U32:
|
|
ret = PyInt_FromLong( *((PRUint32 *)ns_v.ptr) );
|
|
break;
|
|
case nsXPTType::T_U64:
|
|
ret = PyLong_FromUnsignedLongLong( *((PRUint64 *)ns_v.ptr) );
|
|
break;
|
|
case nsXPTType::T_FLOAT:
|
|
ret = PyFloat_FromDouble( *((float *)ns_v.ptr) );
|
|
break;
|
|
case nsXPTType::T_DOUBLE:
|
|
ret = PyFloat_FromDouble( *((double *)ns_v.ptr) );
|
|
break;
|
|
case nsXPTType::T_BOOL:
|
|
ret = *((PRBool *)ns_v.ptr) ? Py_True : Py_False;
|
|
Py_INCREF(ret);
|
|
break;
|
|
case nsXPTType::T_CHAR:
|
|
ret = PyString_FromStringAndSize( ((char *)ns_v.ptr), 1 );
|
|
break;
|
|
|
|
case nsXPTType::T_WCHAR:
|
|
ret = PyUnicodeUCS2_FromUnicode( ((PRUnichar *)ns_v.ptr), 1 );
|
|
break;
|
|
// case nsXPTType::T_VOID:
|
|
case nsXPTType::T_IID:
|
|
ret = Py_nsIID::PyObjectFromIID( **((nsIID **)ns_v.ptr) );
|
|
break;
|
|
case nsXPTType::T_ASTRING:
|
|
case nsXPTType::T_DOMSTRING: {
|
|
nsAString *rs = (nsAString *)ns_v.ptr;
|
|
ret = PyObject_FromNSString(*rs);
|
|
break;
|
|
}
|
|
case nsXPTType::T_UTF8STRING:
|
|
case nsXPTType::T_CSTRING: {
|
|
nsCString *rs = (nsCString *)ns_v.ptr;
|
|
ret = PyObject_FromNSString(*rs, XPT_TDP_TAG(ns_v.type)==nsXPTType::T_UTF8STRING);
|
|
break;
|
|
}
|
|
|
|
case nsXPTType::T_CHAR_STR:
|
|
if (*((char **)ns_v.ptr) == NULL) {
|
|
ret = Py_None;
|
|
Py_INCREF(Py_None);
|
|
} else
|
|
ret = PyString_FromString( *((char **)ns_v.ptr) );
|
|
break;
|
|
|
|
case nsXPTType::T_WCHAR_STR: {
|
|
PRUnichar *us = *((PRUnichar **)ns_v.ptr);
|
|
if (us == NULL) {
|
|
ret = Py_None;
|
|
Py_INCREF(Py_None);
|
|
} else
|
|
ret = PyUnicodeUCS2_FromUnicode( us, nsCRT::strlen(us));
|
|
break;
|
|
}
|
|
case nsXPTType::T_INTERFACE: {
|
|
nsIID iid;
|
|
if (!Py_nsIID::IIDFromPyObject(td.extra, &iid))
|
|
break;
|
|
nsISupports *iret = *((nsISupports **)ns_v.ptr);
|
|
// We _do_ add a reference here, as our cleanup code will
|
|
// remove this reference should we own it.
|
|
ret = Py_nsISupports::PyObjectFromInterfaceOrVariant(iret, iid, PR_TRUE);
|
|
break;
|
|
}
|
|
case nsXPTType::T_INTERFACE_IS: {
|
|
nsIID iid;
|
|
nsXPTCVariant &ns_viid = m_var_array[td.argnum];
|
|
NS_WARN_IF_FALSE(XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID, "The INTERFACE_IS iid describer isnt an IID!");
|
|
if (XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID) {
|
|
nsIID *piid = (nsIID *)ns_viid.val.p;
|
|
if (piid==NULL)
|
|
// Also serious, but like below, not our fault!
|
|
iid = NS_GET_IID(nsISupports);
|
|
else
|
|
iid = *piid;
|
|
} else
|
|
// This is a pretty serious problem, but not Python's fault!
|
|
// Just return an nsISupports and hope the caller does whatever
|
|
// QI they need before using it.
|
|
iid = NS_GET_IID(nsISupports);
|
|
nsISupports *iret = *((nsISupports **)ns_v.ptr);
|
|
// We _do_ add a reference here, as our cleanup code will
|
|
// remove this reference should we own it.
|
|
ret = Py_nsISupports::PyObjectFromInterfaceOrVariant(iret, iid, PR_TRUE);
|
|
break;
|
|
}
|
|
case nsXPTType::T_ARRAY: {
|
|
if ( (* ((void **)ns_v.ptr)) == NULL) {
|
|
ret = Py_None;
|
|
Py_INCREF(Py_None);
|
|
}
|
|
if (!PyInt_Check(td.extra)) {
|
|
PyErr_SetString(PyExc_TypeError, "The array info is not valid");
|
|
break;
|
|
}
|
|
PRUint8 array_type = (PRUint8)PyInt_AsLong(td.extra);
|
|
PRUint32 seq_size = GetSizeIs(index, PR_FALSE);
|
|
ret = UnpackSingleArray(* ((void **)ns_v.ptr), seq_size, array_type&XPT_TDP_TAGMASK, NULL);
|
|
break;
|
|
}
|
|
|
|
case nsXPTType::T_PSTRING_SIZE_IS:
|
|
if (*((char **)ns_v.ptr) == NULL) {
|
|
ret = Py_None;
|
|
Py_INCREF(Py_None);
|
|
} else {
|
|
PRUint32 string_size = GetSizeIs(index, PR_TRUE);
|
|
ret = PyString_FromStringAndSize( *((char **)ns_v.ptr), string_size );
|
|
}
|
|
break;
|
|
|
|
case nsXPTType::T_PWSTRING_SIZE_IS:
|
|
if (*((PRUnichar **)ns_v.ptr) == NULL) {
|
|
ret = Py_None;
|
|
Py_INCREF(Py_None);
|
|
} else {
|
|
PRUint32 string_size = GetSizeIs(index, PR_TRUE);
|
|
ret = PyUnicodeUCS2_FromUnicode( *((PRUnichar **)ns_v.ptr), string_size );
|
|
}
|
|
break;
|
|
default:
|
|
PyErr_Format(PyExc_ValueError, "Unknown XPCOM type code (0x%x)", XPT_TDP_TAG(ns_v.type));
|
|
/* ret remains nsnull */
|
|
break;
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
|
|
PyObject *PyXPCOM_InterfaceVariantHelper::MakePythonResult()
|
|
{
|
|
// First we count the results.
|
|
int i = 0;
|
|
int n_results = 0;
|
|
PyObject *ret = NULL;
|
|
PRBool have_retval = PR_FALSE;
|
|
for (i=0;i<m_num_array;i++) {
|
|
PythonTypeDescriptor &td = m_python_type_desc_array[i];
|
|
if (!td.is_auto_out) {
|
|
if (XPT_PD_IS_OUT(td.param_flags) || XPT_PD_IS_DIPPER(td.param_flags))
|
|
n_results++;
|
|
if (XPT_PD_IS_RETVAL(td.param_flags))
|
|
have_retval = PR_TRUE;
|
|
}
|
|
}
|
|
if (n_results==0) {
|
|
ret = Py_None;
|
|
Py_INCREF(ret);
|
|
} else {
|
|
if (n_results > 1) {
|
|
ret = PyTuple_New(n_results);
|
|
if (ret==NULL)
|
|
return NULL;
|
|
}
|
|
int ret_index = 0;
|
|
int max_index = m_num_array;
|
|
// Stick the retval at the front if we have have
|
|
if (have_retval && n_results > 1) {
|
|
PyObject *val = MakeSinglePythonResult(m_num_array-1);
|
|
if (val==NULL) {
|
|
Py_DECREF(ret);
|
|
return NULL;
|
|
}
|
|
PyTuple_SET_ITEM(ret, 0, val);
|
|
max_index--;
|
|
ret_index++;
|
|
|
|
}
|
|
for (i=0;ret_index < n_results && i < max_index;i++) {
|
|
if (!m_python_type_desc_array[i].is_auto_out) {
|
|
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)) {
|
|
PyObject *val = MakeSinglePythonResult(i);
|
|
if (val==NULL) {
|
|
Py_XDECREF(ret);
|
|
return NULL;
|
|
}
|
|
if (n_results > 1) {
|
|
PyTuple_SET_ITEM(ret, ret_index, val);
|
|
ret_index++;
|
|
} else {
|
|
NS_ABORT_IF_FALSE(ret==NULL, "shouldnt already have a ret!");
|
|
ret = val;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
/*************************************************************************
|
|
**************************************************************************
|
|
|
|
Helpers when IMPLEMENTING interfaces.
|
|
|
|
**************************************************************************
|
|
*************************************************************************/
|
|
|
|
PyXPCOM_GatewayVariantHelper::PyXPCOM_GatewayVariantHelper( PyG_Base *gw, int method_index, const nsXPTMethodInfo *info, nsXPTCMiniVariant* params )
|
|
{
|
|
m_params = params;
|
|
m_info = info;
|
|
// no references added - this class is only alive for
|
|
// a single gateway invocation
|
|
m_gateway = gw;
|
|
m_method_index = method_index;
|
|
m_python_type_desc_array = NULL;
|
|
m_num_type_descs = 0;
|
|
}
|
|
|
|
PyXPCOM_GatewayVariantHelper::~PyXPCOM_GatewayVariantHelper()
|
|
{
|
|
delete [] m_python_type_desc_array;
|
|
}
|
|
|
|
PyObject *PyXPCOM_GatewayVariantHelper::MakePyArgs()
|
|
{
|
|
NS_PRECONDITION(sizeof(XPTParamDescriptor) == sizeof(nsXPTParamInfo), "We depend on nsXPTParamInfo being a wrapper over the XPTParamDescriptor struct");
|
|
// Setup our array of Python typedescs, and determine the number of objects we
|
|
// pass to Python.
|
|
m_num_type_descs = m_info->num_args;
|
|
m_python_type_desc_array = new PythonTypeDescriptor[m_num_type_descs];
|
|
if (m_python_type_desc_array==nsnull)
|
|
return PyErr_NoMemory();
|
|
|
|
// First loop to count the number of objects
|
|
// we pass to Python
|
|
int i;
|
|
for (i=0;i<m_info->num_args;i++) {
|
|
nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+i;
|
|
PythonTypeDescriptor &td = m_python_type_desc_array[i];
|
|
td.param_flags = pi->flags;
|
|
td.type_flags = pi->type.prefix.flags;
|
|
td.argnum = pi->type.argnum;
|
|
td.argnum2 = pi->type.argnum2;
|
|
}
|
|
int num_args = ProcessPythonTypeDescriptors(m_python_type_desc_array, m_num_type_descs);
|
|
PyObject *ret = PyTuple_New(num_args);
|
|
if (ret==NULL)
|
|
return NULL;
|
|
int this_arg = 0;
|
|
for (i=0;i<m_num_type_descs;i++) {
|
|
PythonTypeDescriptor &td = m_python_type_desc_array[i];
|
|
if (XPT_PD_IS_IN(td.param_flags) && !td.is_auto_in && !XPT_PD_IS_DIPPER(td.param_flags)) {
|
|
PyObject *sub = MakeSingleParam( i, td );
|
|
if (sub==NULL) {
|
|
Py_DECREF(ret);
|
|
return NULL;
|
|
}
|
|
NS_ABORT_IF_FALSE(this_arg>=0 && this_arg<num_args, "We are going off the end of the array!");
|
|
PyTuple_SET_ITEM(ret, this_arg, sub);
|
|
this_arg++;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
PRBool PyXPCOM_GatewayVariantHelper::CanSetSizeIs( int var_index, PRBool is_arg1 )
|
|
{
|
|
NS_ABORT_IF_FALSE(var_index < m_num_type_descs, "var_index param is invalid");
|
|
PRUint8 argnum = is_arg1 ?
|
|
m_python_type_desc_array[var_index].argnum :
|
|
m_python_type_desc_array[var_index].argnum2;
|
|
NS_ABORT_IF_FALSE(argnum < m_num_type_descs, "size_is param is invalid");
|
|
return XPT_PD_IS_OUT(m_python_type_desc_array[argnum].param_flags);
|
|
}
|
|
|
|
PRBool PyXPCOM_GatewayVariantHelper::SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size)
|
|
{
|
|
NS_ABORT_IF_FALSE(var_index < m_num_type_descs, "var_index param is invalid");
|
|
PRUint8 argnum = is_arg1 ?
|
|
m_python_type_desc_array[var_index].argnum :
|
|
m_python_type_desc_array[var_index].argnum2;
|
|
NS_ABORT_IF_FALSE(argnum < m_num_type_descs, "size_is param is invalid");
|
|
PythonTypeDescriptor &td_size = m_python_type_desc_array[argnum];
|
|
NS_ABORT_IF_FALSE( XPT_PD_IS_OUT(td_size.param_flags), "size param must be out if we want to set it!");
|
|
NS_ABORT_IF_FALSE(td_size.is_auto_out, "Setting size_is, but param is not marked as auto!");
|
|
|
|
nsXPTCMiniVariant &ns_v = m_params[argnum];
|
|
NS_ABORT_IF_FALSE( (td_size.type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32");
|
|
NS_ABORT_IF_FALSE(ns_v.val.p, "NULL pointer for size_is value!");
|
|
if (ns_v.val.p) {
|
|
if (!td_size.have_set_auto) {
|
|
*((PRUint32 *)ns_v.val.p) = new_size;
|
|
td_size.have_set_auto = PR_TRUE;
|
|
} else {
|
|
if (*((PRUint32 *)ns_v.val.p) != new_size ) {
|
|
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);
|
|
return PR_FALSE;
|
|
}
|
|
}
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
|
|
PRUint32 PyXPCOM_GatewayVariantHelper::GetSizeIs( int var_index, PRBool is_arg1)
|
|
{
|
|
NS_ABORT_IF_FALSE(var_index < m_num_type_descs, "var_index param is invalid");
|
|
PRUint8 argnum = is_arg1 ?
|
|
m_python_type_desc_array[var_index].argnum :
|
|
m_python_type_desc_array[var_index].argnum2;
|
|
NS_ABORT_IF_FALSE(argnum < m_num_type_descs, "size_is param is invalid");
|
|
if (argnum >= m_num_type_descs) {
|
|
PyErr_SetString(PyExc_ValueError, "dont have a valid size_is indicator for this param");
|
|
return PR_FALSE;
|
|
}
|
|
PRBool is_out = XPT_PD_IS_OUT(m_python_type_desc_array[argnum].param_flags);
|
|
nsXPTCMiniVariant &ns_v = m_params[argnum];
|
|
NS_ABORT_IF_FALSE( (m_python_type_desc_array[argnum].type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32");
|
|
return is_out ? *((PRUint32 *)ns_v.val.p) : ns_v.val.u32;
|
|
}
|
|
|
|
#undef DEREF_IN_OR_OUT
|
|
#define DEREF_IN_OR_OUT( element, ret_type ) (ret_type)(is_out ? *((ret_type *)ns_v.val.p) : (ret_type)(element))
|
|
|
|
PyObject *PyXPCOM_GatewayVariantHelper::MakeSingleParam(int index, PythonTypeDescriptor &td)
|
|
{
|
|
NS_PRECONDITION(XPT_PD_IS_IN(td.param_flags), "Must be an [in] param!");
|
|
nsXPTCMiniVariant &ns_v = m_params[index];
|
|
PyObject *ret = NULL;
|
|
PRBool is_out = XPT_PD_IS_OUT(td.param_flags);
|
|
|
|
switch (td.type_flags & XPT_TDP_TAGMASK) {
|
|
case nsXPTType::T_I8:
|
|
ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.i8, PRInt8 ) );
|
|
break;
|
|
case nsXPTType::T_I16:
|
|
ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.i16, PRInt16) );
|
|
break;
|
|
case nsXPTType::T_I32:
|
|
ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.i32, PRInt32) );
|
|
break;
|
|
case nsXPTType::T_I64:
|
|
ret = PyLong_FromLongLong( DEREF_IN_OR_OUT(ns_v.val.i64, PRInt64) );
|
|
break;
|
|
case nsXPTType::T_U8:
|
|
ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.u8, PRUint8) );
|
|
break;
|
|
case nsXPTType::T_U16:
|
|
ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.u16, PRUint16) );
|
|
break;
|
|
case nsXPTType::T_U32:
|
|
ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.u32, PRUint32) );
|
|
break;
|
|
case nsXPTType::T_U64:
|
|
ret = PyLong_FromUnsignedLongLong( DEREF_IN_OR_OUT(ns_v.val.u64, PRUint64) );
|
|
break;
|
|
case nsXPTType::T_FLOAT:
|
|
ret = PyFloat_FromDouble( DEREF_IN_OR_OUT(ns_v.val.f, float) );
|
|
break;
|
|
case nsXPTType::T_DOUBLE:
|
|
ret = PyFloat_FromDouble( DEREF_IN_OR_OUT(ns_v.val.d, double) );
|
|
break;
|
|
case nsXPTType::T_BOOL: {
|
|
PRBool temp = DEREF_IN_OR_OUT(ns_v.val.b, PRBool);
|
|
ret = temp ? Py_True : Py_False;
|
|
Py_INCREF(ret);
|
|
break;
|
|
}
|
|
case nsXPTType::T_CHAR: {
|
|
char temp = DEREF_IN_OR_OUT(ns_v.val.c, char);
|
|
ret = PyString_FromStringAndSize(&temp, 1);
|
|
break;
|
|
}
|
|
case nsXPTType::T_WCHAR: {
|
|
PRUnichar temp = (PRUnichar)DEREF_IN_OR_OUT(ns_v.val.wc, PRUnichar);
|
|
ret = PyUnicodeUCS2_FromUnicode(&temp, 1);
|
|
break;
|
|
}
|
|
// case nsXPTType::T_VOID:
|
|
case nsXPTType::T_IID: {
|
|
ret = Py_nsIID::PyObjectFromIID( * DEREF_IN_OR_OUT(ns_v.val.p, const nsIID *) );
|
|
break;
|
|
}
|
|
case nsXPTType::T_ASTRING:
|
|
case nsXPTType::T_DOMSTRING: {
|
|
NS_ABORT_IF_FALSE(is_out || !XPT_PD_IS_DIPPER(td.param_flags), "DOMStrings can't be inout");
|
|
const nsAString *rs = (const nsAString *)ns_v.val.p;
|
|
ret = PyObject_FromNSString(*rs);
|
|
break;
|
|
}
|
|
case nsXPTType::T_CSTRING:
|
|
case nsXPTType::T_UTF8STRING: {
|
|
NS_ABORT_IF_FALSE(is_out || !XPT_PD_IS_DIPPER(td.param_flags), "DOMStrings can't be inout");
|
|
const nsCString *rs = (const nsCString *)ns_v.val.p;
|
|
ret = PyObject_FromNSString(*rs, (td.type_flags & XPT_TDP_TAGMASK)==nsXPTType::T_UTF8STRING);
|
|
break;
|
|
}
|
|
case nsXPTType::T_CHAR_STR: {
|
|
char *t = DEREF_IN_OR_OUT(ns_v.val.p, char *);
|
|
if (t==NULL) {
|
|
ret = Py_None;
|
|
Py_INCREF(Py_None);
|
|
} else
|
|
ret = PyString_FromString(t);
|
|
break;
|
|
}
|
|
|
|
case nsXPTType::T_WCHAR_STR: {
|
|
PRUnichar *us = DEREF_IN_OR_OUT(ns_v.val.p, PRUnichar *);
|
|
if (us==NULL) {
|
|
ret = Py_None;
|
|
Py_INCREF(Py_None);
|
|
} else
|
|
ret = PyUnicodeUCS2_FromUnicode( us, nsCRT::strlen(us));
|
|
break;
|
|
}
|
|
case nsXPTType::T_INTERFACE_IS: // our Python code does it :-)
|
|
case nsXPTType::T_INTERFACE: {
|
|
nsISupports *iret = DEREF_IN_OR_OUT(ns_v.val.p, nsISupports *);
|
|
nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index;
|
|
ret = m_gateway->MakeInterfaceParam(iret, NULL, m_method_index, pi, index);
|
|
break;
|
|
}
|
|
/***
|
|
nsISupports *iret = DEREF_IN_OR_OUT(ns_v.val.p, nsISupports *);
|
|
nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index;
|
|
nsXPTCMiniVariant &ns_viid = m_params[td.argnum];
|
|
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!");
|
|
const nsIID * iid = NULL;
|
|
if (XPT_PD_IS_IN(m_python_type_desc_array[td.argnum].param_flags))
|
|
// may still be inout!
|
|
iid = DEREF_IN_OR_OUT(ns_v.val.p, const nsIID *);
|
|
|
|
ret = m_gateway->MakeInterfaceParam(iret, iid, m_method_index, pi, index);
|
|
break;
|
|
}
|
|
****/
|
|
case nsXPTType::T_ARRAY: {
|
|
void *t = DEREF_IN_OR_OUT(ns_v.val.p, void *);
|
|
if (t==NULL) {
|
|
ret = Py_None;
|
|
Py_INCREF(Py_None);
|
|
} else {
|
|
PRUint8 array_type;
|
|
nsresult ns = GetArrayType(index, &array_type);
|
|
if (NS_FAILED(ns)) {
|
|
PyXPCOM_BuildPyException(ns);
|
|
break;
|
|
}
|
|
PRUint32 seq_size = GetSizeIs(index, PR_FALSE);
|
|
ret = UnpackSingleArray(t, seq_size, array_type&XPT_TDP_TAGMASK, NULL);
|
|
}
|
|
break;
|
|
}
|
|
case nsXPTType::T_PSTRING_SIZE_IS: {
|
|
char *t = DEREF_IN_OR_OUT(ns_v.val.p, char *);
|
|
PRUint32 string_size = GetSizeIs(index, PR_TRUE);
|
|
if (t==NULL) {
|
|
ret = Py_None;
|
|
Py_INCREF(Py_None);
|
|
} else
|
|
ret = PyString_FromStringAndSize(t, string_size);
|
|
break;
|
|
}
|
|
case nsXPTType::T_PWSTRING_SIZE_IS: {
|
|
PRUnichar *t = DEREF_IN_OR_OUT(ns_v.val.p, PRUnichar *);
|
|
PRUint32 string_size = GetSizeIs(index, PR_TRUE);
|
|
if (t==NULL) {
|
|
ret = Py_None;
|
|
Py_INCREF(Py_None);
|
|
} else
|
|
ret = PyUnicodeUCS2_FromUnicode(t, string_size);
|
|
break;
|
|
}
|
|
default:
|
|
// As this is called by external components,
|
|
// we return _something_ rather than failing before any user code has run!
|
|
{
|
|
char buf[128];
|
|
sprintf(buf, "Unknown XPCOM type flags (0x%x)", td.type_flags);
|
|
PyXPCOM_LogWarning("%s - returning a string object with this message!\n", buf);
|
|
ret = PyString_FromString(buf);
|
|
break;
|
|
}
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
nsresult PyXPCOM_GatewayVariantHelper::GetArrayType(PRUint8 index, PRUint8 *ret)
|
|
{
|
|
nsCOMPtr<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager();
|
|
NS_ABORT_IF_FALSE(iim != nsnull, "Cant get interface from IIM!");
|
|
if (iim==nsnull)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
nsCOMPtr<nsIInterfaceInfo> ii;
|
|
nsresult rc = iim->GetInfoForIID( &m_gateway->m_iid, getter_AddRefs(ii));
|
|
if (NS_FAILED(rc))
|
|
return rc;
|
|
nsXPTType datumType;
|
|
const nsXPTParamInfo& param_info = m_info->GetParam((PRUint8)index);
|
|
rc = ii->GetTypeForParam(m_method_index, ¶m_info, 1, &datumType);
|
|
if (NS_FAILED(rc))
|
|
return rc;
|
|
*ret = datumType.flags;
|
|
return NS_OK;
|
|
}
|
|
|
|
PRBool PyXPCOM_GatewayVariantHelper::GetIIDForINTERFACE_ID(int index, const nsIID **ppret)
|
|
{
|
|
// Not sure if the IID pointed at by by this is allows to be
|
|
// in or out, so we will allow it.
|
|
nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index;
|
|
nsXPTType typ = pi->GetType();
|
|
NS_WARN_IF_FALSE(XPT_TDP_TAG(typ) == nsXPTType::T_IID, "INTERFACE_IS IID param isnt an IID!");
|
|
NS_ABORT_IF_FALSE(typ.IsPointer(), "Expecting to re-fill a pointer value.");
|
|
if (XPT_TDP_TAG(typ) != nsXPTType::T_IID)
|
|
*ppret = &NS_GET_IID(nsISupports);
|
|
else {
|
|
nsXPTCMiniVariant &ns_v = m_params[index];
|
|
if (pi->IsOut()) {
|
|
nsIID **pp = (nsIID **)ns_v.val.p;
|
|
if (pp && *pp)
|
|
*ppret = *pp;
|
|
else
|
|
*ppret = &NS_GET_IID(nsISupports);
|
|
} else if (pi->IsIn()) {
|
|
nsIID *p = (nsIID *)ns_v.val.p;
|
|
if (p)
|
|
*ppret = p;
|
|
else
|
|
*ppret = &NS_GET_IID(nsISupports);
|
|
} else {
|
|
NS_ERROR("Param is not in or out!");
|
|
*ppret = &NS_GET_IID(nsISupports);
|
|
}
|
|
}
|
|
return PR_TRUE;
|
|
}
|
|
|
|
nsIInterfaceInfo *PyXPCOM_GatewayVariantHelper::GetInterfaceInfo()
|
|
{
|
|
if (!m_interface_info) {
|
|
nsCOMPtr<nsIInterfaceInfoManager> iim =
|
|
dont_AddRef(XPTI_GetInterfaceInfoManager());
|
|
if (iim)
|
|
iim->GetInfoForIID(&m_gateway->m_iid, getter_AddRefs(m_interface_info));
|
|
}
|
|
return m_interface_info;
|
|
}
|
|
|
|
#undef FILL_SIMPLE_POINTER
|
|
#define FILL_SIMPLE_POINTER( type, ob ) *((type *)ns_v.val.p) = (type)(ob);
|
|
|
|
nsresult PyXPCOM_GatewayVariantHelper::BackFillVariant( PyObject *val, int index)
|
|
{
|
|
nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index;
|
|
NS_ABORT_IF_FALSE(pi->IsOut() || pi->IsDipper(), "The value must be marked as [out] (or a dipper) to be back-filled!");
|
|
NS_ABORT_IF_FALSE(!pi->IsShared(), "Dont know how to back-fill a shared out param");
|
|
nsXPTCMiniVariant &ns_v = m_params[index];
|
|
|
|
nsXPTType typ = pi->GetType();
|
|
PyObject* val_use = NULL;
|
|
|
|
NS_ABORT_IF_FALSE(pi->IsDipper() || ns_v.val.p, "No space for result!");
|
|
if (!pi->IsDipper() && !ns_v.val.p) return NS_ERROR_INVALID_POINTER;
|
|
|
|
PRBool rc = PR_TRUE;
|
|
switch (XPT_TDP_TAG(typ)) {
|
|
case nsXPTType::T_I8:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
|
|
FILL_SIMPLE_POINTER( PRInt8, PyInt_AsLong(val_use) );
|
|
break;
|
|
case nsXPTType::T_I16:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
|
|
FILL_SIMPLE_POINTER( PRInt16, PyInt_AsLong(val_use) );
|
|
break;
|
|
case nsXPTType::T_I32:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
|
|
FILL_SIMPLE_POINTER( PRInt32, PyInt_AsLong(val_use) );
|
|
break;
|
|
case nsXPTType::T_I64:
|
|
if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE;
|
|
FILL_SIMPLE_POINTER( PRInt64, PyLong_AsLongLong(val_use) );
|
|
break;
|
|
case nsXPTType::T_U8:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
|
|
FILL_SIMPLE_POINTER( PRUint8, PyInt_AsLong(val_use) );
|
|
break;
|
|
case nsXPTType::T_U16:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
|
|
FILL_SIMPLE_POINTER( PRUint16, PyInt_AsLong(val_use) );
|
|
break;
|
|
case nsXPTType::T_U32:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
|
|
FILL_SIMPLE_POINTER( PRUint32, PyInt_AsLong(val_use) );
|
|
break;
|
|
case nsXPTType::T_U64:
|
|
if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE;
|
|
FILL_SIMPLE_POINTER( PRUint64, PyLong_AsUnsignedLongLong(val_use) );
|
|
break;
|
|
case nsXPTType::T_FLOAT:
|
|
if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
|
|
FILL_SIMPLE_POINTER( float, PyFloat_AsDouble(val_use) );
|
|
break;
|
|
case nsXPTType::T_DOUBLE:
|
|
if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
|
|
FILL_SIMPLE_POINTER( double, PyFloat_AsDouble(val_use) );
|
|
break;
|
|
case nsXPTType::T_BOOL:
|
|
if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
|
|
FILL_SIMPLE_POINTER( PRBool, PyInt_AsLong(val_use) );
|
|
break;
|
|
case nsXPTType::T_CHAR:
|
|
if (!PyString_Check(val) && !PyUnicode_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
|
|
BREAK_FALSE;
|
|
}
|
|
if ((val_use = PyObject_Str(val))==NULL)
|
|
BREAK_FALSE;
|
|
// Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
|
|
NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
|
|
FILL_SIMPLE_POINTER( char, *PyString_AS_STRING(val_use) );
|
|
break;
|
|
|
|
case nsXPTType::T_WCHAR:
|
|
if (!PyString_Check(val) && !PyUnicode_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
|
|
BREAK_FALSE;
|
|
}
|
|
if ((val_use = PyUnicodeUCS2_FromObject(val))==NULL)
|
|
BREAK_FALSE;
|
|
NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicodeUCS2_FromObject didnt return a Unicode object!");
|
|
FILL_SIMPLE_POINTER( PRUnichar, *PyUnicode_AS_UNICODE(val_use) );
|
|
break;
|
|
|
|
// case nsXPTType::T_VOID:
|
|
case nsXPTType::T_IID: {
|
|
nsIID iid;
|
|
if (!Py_nsIID::IIDFromPyObject(val, &iid))
|
|
BREAK_FALSE;
|
|
nsIID **pp = (nsIID **)ns_v.val.p;
|
|
// If there is an existing [in] IID, free it.
|
|
if (*pp && pi->IsIn())
|
|
nsMemory::Free(*pp);
|
|
*pp = (nsIID *)nsMemory::Alloc(sizeof(nsIID));
|
|
if (*pp==NULL) {
|
|
PyErr_NoMemory();
|
|
BREAK_FALSE;
|
|
}
|
|
memcpy(*pp, &iid, sizeof(iid));
|
|
break;
|
|
}
|
|
|
|
case nsXPTType::T_ASTRING:
|
|
case nsXPTType::T_DOMSTRING: {
|
|
nsAString *ws = (nsAString *)ns_v.val.p;
|
|
NS_ABORT_IF_FALSE(ws->Length() == 0, "Why does this writable string already have chars??");
|
|
if (val == Py_None) {
|
|
(*ws) = (PRUnichar *)nsnull;
|
|
} else {
|
|
if (!PyString_Check(val) && !PyUnicode_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
|
|
BREAK_FALSE;
|
|
}
|
|
val_use = PyUnicodeUCS2_FromObject(val);
|
|
NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicodeUCS2_FromObject didnt return a Unicode object!");
|
|
const PRUnichar *sz = PyUnicode_AS_UNICODE(val_use);
|
|
ws->Assign(sz, PyUnicode_GET_SIZE(val_use));
|
|
}
|
|
break;
|
|
}
|
|
case nsXPTType::T_CSTRING: {
|
|
nsCString *ws = (nsCString *)ns_v.val.p;
|
|
NS_ABORT_IF_FALSE(ws->Length() == 0, "Why does this writable string already have chars??");
|
|
if (val == Py_None) {
|
|
NS_ABORT_IF_FALSE(0, "dont handle None here yet");
|
|
} else {
|
|
if (!PyString_Check(val) && !PyUnicode_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
|
|
BREAK_FALSE;
|
|
}
|
|
val_use = PyObject_Str(val);
|
|
NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
|
|
const char *sz = PyString_AS_STRING(val_use);
|
|
ws->Assign(sz, PyString_Size(val_use));
|
|
}
|
|
break;
|
|
}
|
|
case nsXPTType::T_UTF8STRING: {
|
|
nsCString *ws = (nsCString *)ns_v.val.p;
|
|
NS_ABORT_IF_FALSE(ws->Length() == 0, "Why does this writable string already have chars??");
|
|
if (val == Py_None) {
|
|
NS_ABORT_IF_FALSE(0, "dont handle None here yet");
|
|
} else {
|
|
if (PyString_Check(val)) {
|
|
val_use = val;
|
|
Py_INCREF(val);
|
|
} else if (PyUnicode_Check(val)) {
|
|
val_use = PyUnicode_AsUTF8String(val);
|
|
} else {
|
|
PyErr_SetString(PyExc_TypeError, "UTF8 parameters must be string or Unicode objects");
|
|
BREAK_FALSE;
|
|
}
|
|
NS_ABORT_IF_FALSE(PyString_Check(val_use), "must have a string object!");
|
|
const char *sz = PyString_AS_STRING(val_use);
|
|
ws->Assign(sz, PyString_Size(val_use));
|
|
}
|
|
break;
|
|
}
|
|
|
|
case nsXPTType::T_CHAR_STR: {
|
|
// If it is an existing string, free it.
|
|
char **pp = (char **)ns_v.val.p;
|
|
if (*pp && pi->IsIn())
|
|
nsMemory::Free(*pp);
|
|
*pp = nsnull;
|
|
|
|
if (val == Py_None)
|
|
break; // Remains NULL.
|
|
if (!PyString_Check(val) && !PyUnicode_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
|
|
BREAK_FALSE;
|
|
}
|
|
if ((val_use = PyObject_Str(val))==NULL)
|
|
BREAK_FALSE;
|
|
// Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
|
|
NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
|
|
|
|
const char *sz = PyString_AS_STRING(val_use);
|
|
int nch = PyString_GET_SIZE(val_use);
|
|
|
|
*pp = (char *)nsMemory::Alloc(nch+1);
|
|
if (*pp==NULL) {
|
|
PyErr_NoMemory();
|
|
BREAK_FALSE;
|
|
}
|
|
strncpy(*pp, sz, nch+1);
|
|
break;
|
|
}
|
|
case nsXPTType::T_WCHAR_STR: {
|
|
// If it is an existing string, free it.
|
|
PRUnichar **pp = (PRUnichar **)ns_v.val.p;
|
|
if (*pp && pi->IsIn())
|
|
nsMemory::Free(*pp);
|
|
*pp = nsnull;
|
|
if (val == Py_None)
|
|
break; // Remains NULL.
|
|
if (!PyString_Check(val) && !PyUnicode_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
|
|
BREAK_FALSE;
|
|
}
|
|
val_use = PyUnicodeUCS2_FromObject(val);
|
|
NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicodeUCS2_FromObject didnt return a Unicode object!");
|
|
const PRUnichar *sz = PyUnicode_AS_UNICODE(val_use);
|
|
int nch = PyUnicode_GET_SIZE(val_use);
|
|
|
|
*pp = (PRUnichar *)nsMemory::Alloc(sizeof(PRUnichar) * (nch+1));
|
|
if (*pp==NULL) {
|
|
PyErr_NoMemory();
|
|
BREAK_FALSE;
|
|
}
|
|
memcpy(*pp, sz, sizeof(PRUnichar) * (nch + 1));
|
|
break;
|
|
}
|
|
case nsXPTType::T_INTERFACE: {
|
|
nsISupports *pnew = nsnull;
|
|
// Find out what IID we are declared to use.
|
|
nsIID *iid;
|
|
nsIInterfaceInfo *ii = GetInterfaceInfo();
|
|
if (ii)
|
|
ii->GetIIDForParam(m_method_index, pi, &iid);
|
|
|
|
// Get it the "standard" way.
|
|
// We do allow NULL here, even tho doing so will no-doubt crash some objects.
|
|
// (but there will certainly be objects out there that will allow NULL :-(
|
|
nsIID iid_use = iid ? *iid : NS_GET_IID(nsISupports);
|
|
if (!Py_nsISupports::InterfaceFromPyObject(val, iid_use, &pnew, PR_TRUE))
|
|
BREAK_FALSE;
|
|
nsISupports **pp = (nsISupports **)ns_v.val.p;
|
|
if (*pp && pi->IsIn()) {
|
|
Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
|
|
(*pp)->Release();
|
|
Py_END_ALLOW_THREADS;
|
|
}
|
|
|
|
*pp = pnew; // ref-count added by InterfaceFromPyObject
|
|
break;
|
|
}
|
|
case nsXPTType::T_INTERFACE_IS: {
|
|
// We do allow NULL here, even tho doing so will no-doubt crash some objects.
|
|
// (but there will certainly be objects out there that will allow NULL :-(
|
|
const nsIID *piid;
|
|
if (!GetIIDForINTERFACE_ID(pi->type.argnum, &piid))
|
|
BREAK_FALSE;
|
|
|
|
nsISupports *pnew = nsnull;
|
|
// Get it the "standard" way.
|
|
// We do allow NULL here, even tho doing so will no-doubt crash some objects.
|
|
// (but there will certainly be objects out there that will allow NULL :-(
|
|
if (!Py_nsISupports::InterfaceFromPyObject(val, *piid, &pnew, PR_TRUE))
|
|
BREAK_FALSE;
|
|
nsISupports **pp = (nsISupports **)ns_v.val.p;
|
|
if (*pp && pi->IsIn()) {
|
|
Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
|
|
(*pp)->Release();
|
|
Py_END_ALLOW_THREADS;
|
|
}
|
|
|
|
*pp = pnew; // ref-count added by InterfaceFromPyObject
|
|
break;
|
|
}
|
|
|
|
case nsXPTType::T_PSTRING_SIZE_IS: {
|
|
const char *sz = nsnull;
|
|
PRUint32 nch = 0;
|
|
if (val != Py_None) {
|
|
if (!PyString_Check(val) && !PyUnicode_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
|
|
BREAK_FALSE;
|
|
}
|
|
if ((val_use = PyObject_Str(val))==NULL)
|
|
BREAK_FALSE;
|
|
// Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
|
|
NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
|
|
|
|
sz = PyString_AS_STRING(val_use);
|
|
nch = PyString_GET_SIZE(val_use);
|
|
}
|
|
PRBool bBackFill = PR_FALSE;
|
|
PRBool bCanSetSizeIs = CanSetSizeIs(index, PR_TRUE);
|
|
// If we can not change the size, check our sequence is correct.
|
|
if (!bCanSetSizeIs) {
|
|
PRUint32 existing_size = GetSizeIs(index, PR_TRUE);
|
|
if (nch != existing_size) {
|
|
PyErr_Format(PyExc_ValueError, "This function is expecting a string of exactly length %d - %d characters were passed", existing_size, nch);
|
|
BREAK_FALSE;
|
|
}
|
|
// It we have an "inout" param, but an "in" count, then
|
|
// it is probably a buffer the caller expects us to
|
|
// fill in-place!
|
|
bBackFill = pi->IsIn();
|
|
}
|
|
if (bBackFill) {
|
|
memcpy(*(char **)ns_v.val.p, sz, nch);
|
|
} else {
|
|
// If we have an existing string, free it!
|
|
char **pp = (char **)ns_v.val.p;
|
|
if (*pp && pi->IsIn())
|
|
nsMemory::Free(*pp);
|
|
*pp = nsnull;
|
|
if (sz==nsnull) // None specified.
|
|
break; // Remains NULL.
|
|
*pp = (char *)nsMemory::Alloc(nch);
|
|
if (*pp==NULL) {
|
|
PyErr_NoMemory();
|
|
BREAK_FALSE;
|
|
}
|
|
memcpy(*pp, sz, nch);
|
|
if (bCanSetSizeIs)
|
|
rc = SetSizeIs(index, PR_TRUE, nch);
|
|
else {
|
|
NS_ABORT_IF_FALSE(GetSizeIs(index, PR_TRUE) == nch, "Can't set sizeis, but string isnt correct size");
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
case nsXPTType::T_PWSTRING_SIZE_IS: {
|
|
const PRUnichar *sz = nsnull;
|
|
PRUint32 nch = 0;
|
|
PRUint32 nbytes = 0;
|
|
|
|
if (val != Py_None) {
|
|
if (!PyString_Check(val) && !PyUnicode_Check(val)) {
|
|
PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
|
|
BREAK_FALSE;
|
|
}
|
|
val_use = PyUnicodeUCS2_FromObject(val);
|
|
NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicodeUCS2_FromObject didnt return a Unicode object!");
|
|
sz = PyUnicode_AS_UNICODE(val_use);
|
|
nch = PyUnicode_GET_SIZE(val_use);
|
|
nbytes = sizeof(PRUnichar) * nch;
|
|
}
|
|
PRBool bBackFill = PR_FALSE;
|
|
PRBool bCanSetSizeIs = CanSetSizeIs(index, PR_TRUE);
|
|
// If we can not change the size, check our sequence is correct.
|
|
if (!bCanSetSizeIs) {
|
|
// It is a buffer the caller prolly wants us to fill in-place!
|
|
PRUint32 existing_size = GetSizeIs(index, PR_TRUE);
|
|
if (nch != existing_size) {
|
|
PyErr_Format(PyExc_ValueError, "This function is expecting a string of exactly length %d - %d characters were passed", existing_size, nch);
|
|
BREAK_FALSE;
|
|
}
|
|
// It we have an "inout" param, but an "in" count, then
|
|
// it is probably a buffer the caller expects us to
|
|
// fill in-place!
|
|
bBackFill = pi->IsIn();
|
|
}
|
|
if (bBackFill) {
|
|
memcpy(*(PRUnichar **)ns_v.val.p, sz, nbytes);
|
|
} else {
|
|
// If it is an existing string, free it.
|
|
PRUnichar **pp = (PRUnichar **)ns_v.val.p;
|
|
if (*pp && pi->IsIn())
|
|
nsMemory::Free(*pp);
|
|
*pp = nsnull;
|
|
|
|
if (val == Py_None)
|
|
break; // Remains NULL.
|
|
*pp = (PRUnichar *)nsMemory::Alloc(nbytes);
|
|
if (*pp==NULL) {
|
|
PyErr_NoMemory();
|
|
BREAK_FALSE;
|
|
}
|
|
memcpy(*pp, sz, nbytes);
|
|
if (bCanSetSizeIs)
|
|
rc = SetSizeIs(index, PR_TRUE, nch);
|
|
else {
|
|
NS_ABORT_IF_FALSE(GetSizeIs(index, PR_TRUE) == nch, "Can't set sizeis, but string isnt correct size");
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case nsXPTType::T_ARRAY: {
|
|
// If it is an existing array of the correct size, keep it.
|
|
PRUint32 sequence_size = 0;
|
|
PRUint8 array_type;
|
|
nsresult ns = GetArrayType(index, &array_type);
|
|
if (NS_FAILED(ns))
|
|
return ns;
|
|
PRUint32 element_size = GetArrayElementSize(array_type);
|
|
if (val != Py_None) {
|
|
if (!PySequence_Check(val)) {
|
|
PyErr_Format(PyExc_TypeError, "Object for xpcom array must be a sequence, not type '%s'", val->ob_type->tp_name);
|
|
BREAK_FALSE;
|
|
}
|
|
sequence_size = PySequence_Length(val);
|
|
}
|
|
PRUint32 existing_size = GetSizeIs(index, PR_FALSE);
|
|
PRBool bBackFill = PR_FALSE;
|
|
PRBool bCanSetSizeIs = CanSetSizeIs(index, PR_FALSE);
|
|
// If we can not change the size, check our sequence is correct.
|
|
if (!bCanSetSizeIs) {
|
|
// It is a buffer the caller prolly wants us to fill in-place!
|
|
if (sequence_size != existing_size) {
|
|
PyErr_Format(PyExc_ValueError, "This function is expecting a sequence of exactly length %d - %d items were passed", existing_size, sequence_size);
|
|
BREAK_FALSE;
|
|
}
|
|
// It we have an "inout" param, but an "in" count, then
|
|
// it is probably a buffer the caller expects us to
|
|
// fill in-place!
|
|
bBackFill = pi->IsIn();
|
|
}
|
|
if (bBackFill)
|
|
rc = FillSingleArray(*(void **)ns_v.val.p, val, sequence_size, element_size, array_type&XPT_TDP_TAGMASK);
|
|
else {
|
|
// If it is an existing array, free it.
|
|
void **pp = (void **)ns_v.val.p;
|
|
if (*pp && pi->IsIn()) {
|
|
FreeSingleArray(*pp, existing_size, array_type);
|
|
nsMemory::Free(*pp);
|
|
}
|
|
*pp = nsnull;
|
|
if (val == Py_None)
|
|
break; // Remains NULL.
|
|
size_t nbytes = sequence_size * element_size;
|
|
if (nbytes==0) nbytes = 1; // avoid assertion about 0 bytes
|
|
*pp = (void *)nsMemory::Alloc(nbytes);
|
|
memset(*pp, 0, nbytes);
|
|
rc = FillSingleArray(*pp, val, sequence_size, element_size, array_type&XPT_TDP_TAGMASK);
|
|
if (!rc) break;
|
|
if (bCanSetSizeIs)
|
|
rc = SetSizeIs(index, PR_FALSE, sequence_size);
|
|
else {
|
|
NS_ABORT_IF_FALSE(GetSizeIs(index, PR_FALSE) == sequence_size, "Can't set sizeis, but string isnt correct size");
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
// try and limp along in this case.
|
|
// leave rc TRUE
|
|
PyXPCOM_LogWarning("Converting Python object for an [out] param - The object type (0x%x) is unknown - leaving param alone!\n", XPT_TDP_TAG(typ));
|
|
break;
|
|
}
|
|
Py_XDECREF(val_use);
|
|
if (!rc)
|
|
return NS_ERROR_FAILURE;
|
|
return NS_OK;
|
|
}
|
|
|
|
nsresult PyXPCOM_GatewayVariantHelper::ProcessPythonResult(PyObject *ret_ob)
|
|
{
|
|
// NOTE - although we return an nresult, if we leave a Python
|
|
// exception set, then our caller may take additional action
|
|
// (ie, translating our nsresult to a more appropriate nsresult
|
|
// for the Python exception.)
|
|
NS_PRECONDITION(!PyErr_Occurred(), "Expecting no Python exception to be pending when processing the return result");
|
|
|
|
nsresult rc = NS_OK;
|
|
// If we dont get a tuple back, then the result is only
|
|
// an int nresult for the underlying function.
|
|
// (ie, the policy is expected to return (NS_OK, user_retval),
|
|
// but can also return (say), NS_ERROR_FAILURE
|
|
if (PyInt_Check(ret_ob))
|
|
return PyInt_AsLong(ret_ob);
|
|
// Now it must be the tuple.
|
|
if (!PyTuple_Check(ret_ob) ||
|
|
PyTuple_Size(ret_ob)!=2 ||
|
|
!PyInt_Check(PyTuple_GET_ITEM(ret_ob, 0))) {
|
|
PyErr_SetString(PyExc_TypeError, "The Python result must be a single integer or a tuple of length==2 and first item an int.");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
PyObject *user_result = PyTuple_GET_ITEM(ret_ob, 1);
|
|
// Count up how many results our function needs.
|
|
int i;
|
|
int num_results = 0;
|
|
int last_result = -1; // optimization if we only have one - this is it!
|
|
int index_retval = -1;
|
|
for (i=0;i<m_num_type_descs;i++) {
|
|
nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+i;
|
|
if (!m_python_type_desc_array[i].is_auto_out) {
|
|
if (pi->IsOut() || pi->IsDipper()) {
|
|
num_results++;
|
|
last_result = i;
|
|
}
|
|
if (pi->IsRetval())
|
|
index_retval = i;
|
|
}
|
|
}
|
|
|
|
if (num_results==0) {
|
|
; // do nothing
|
|
} else if (num_results==1) {
|
|
// May or may not be the nominated retval - who cares!
|
|
NS_ABORT_IF_FALSE(last_result >=0 && last_result < m_num_type_descs, "Have one result, but dont know its index!");
|
|
rc = BackFillVariant( user_result, last_result );
|
|
} else {
|
|
// Loop over each one, filling as we go.
|
|
// We allow arbitary sequences here, but _not_ strings
|
|
// or Unicode!
|
|
// NOTE - We ALWAYS do the nominated retval first.
|
|
// The Python pattern is always:
|
|
// return retval [, byref1 [, byref2 ...] ]
|
|
// But the retval is often the last param described in the info.
|
|
if (!PySequence_Check(user_result) ||
|
|
PyString_Check(user_result) ||
|
|
PyUnicode_Check(user_result)) {
|
|
PyErr_SetString(PyExc_TypeError, "This function has multiple results, but a sequence was not given to fill them");
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
int num_user_results = PySequence_Length(user_result);
|
|
// If they havent given enough, we dont really care.
|
|
// although a warning is probably appropriate.
|
|
if (num_user_results != num_results) {
|
|
const char *method_name = m_info->GetName();
|
|
PyXPCOM_LogWarning("The method '%s' has %d out params, but %d were supplied by the Python code\n",
|
|
method_name,
|
|
num_results,
|
|
num_user_results);
|
|
}
|
|
int this_py_index = 0;
|
|
if (index_retval != -1) {
|
|
// We always return the nominated result first!
|
|
PyObject *sub = PySequence_GetItem(user_result, 0);
|
|
if (sub==NULL)
|
|
return NS_ERROR_FAILURE;
|
|
rc = BackFillVariant(sub, index_retval);
|
|
Py_DECREF(sub);
|
|
this_py_index = 1;
|
|
}
|
|
for (i=0;NS_SUCCEEDED(rc) && i<m_info->GetParamCount();i++) {
|
|
// If weve already done it, or dont need to do it!
|
|
if (i==index_retval || m_python_type_desc_array[i].is_auto_out)
|
|
continue;
|
|
nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+i;
|
|
if (pi->IsOut()) {
|
|
PyObject *sub = PySequence_GetItem(user_result, this_py_index);
|
|
if (sub==NULL)
|
|
return NS_ERROR_FAILURE;
|
|
rc = BackFillVariant(sub, i);
|
|
Py_DECREF(sub);
|
|
this_py_index++;
|
|
}
|
|
}
|
|
}
|
|
return rc;
|
|
}
|