When passing arrays of interfaces to an XPCOM method, we didn't know the

declared IID to obtain.  This prevented us detecting arrays of variants
and giving them the same special treatment normal Variants get.  Fix that.
Not part of the build.
This commit is contained in:
mhammond%skippinet.com.au 2006-11-09 04:31:13 +00:00
parent 122f837072
commit 70c4d673c8
3 changed files with 50 additions and 33 deletions

View File

@ -294,7 +294,8 @@ void FreeSingleArray(void *array_ptr, PRUint32 sequence_size, PRUint8 array_type
PRBool FillSingleArray(void *array_ptr, PyObject *sequence_ob, PRUint32 sequence_size,
PRUint32 array_element_size, PRUint8 array_type)
PRUint32 array_element_size, PRUint8 array_type,
const nsIID &iid)
{
PRUint8 *pthis = (PRUint8 *)array_ptr;
NS_ABORT_IF_FALSE(pthis, "Don't have a valid array to fill!");
@ -460,12 +461,12 @@ PRBool FillSingleArray(void *array_ptr, PyObject *sequence_ob, PRUint32 sequence
BREAK_FALSE;
break;
}
case nsXPTType::T_INTERFACE_IS: // hmm - ignoring the IID can't be good :(
case nsXPTType::T_INTERFACE_IS:
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))
if (!Py_nsISupports::InterfaceFromPyObject(val, iid, &pnew, PR_TRUE))
BREAK_FALSE;
nsISupports **pp = (nsISupports **)pthis;
if (*pp) {
@ -898,19 +899,20 @@ class PythonTypeDescriptor {
public:
PythonTypeDescriptor() {
param_flags = type_flags = argnum = argnum2 = 0;
extra = NULL;
iid = NS_GET_IID(nsISupports); // always a valid IID
array_type = 0;
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.
PRUint8 array_type; // The type of the array.
nsID iid; // The IID of the object or each elt of the array.
// Extra items to help our processing.
// Is this auto-filled by some other "in" param?
PRBool is_auto_in;
@ -1008,7 +1010,7 @@ PyXPCOM_InterfaceVariantHelper::~PyXPCOM_InterfaceVariantHelper()
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);
PRUint8 array_type = m_python_type_desc_array[i].array_type;
PRUint32 seq_size = GetSizeIs(i, PR_FALSE);
FreeSingleArray(ns_v.val.p, seq_size, array_type);
}
@ -1060,13 +1062,20 @@ PRBool PyXPCOM_InterfaceVariantHelper::Init(PyObject *obParams)
goto done;
// Pull apart the typedesc tuple back into a structure we can work with.
PyObject *obIID;
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);
ptd.array_type = 0;
PRBool this_ok = PyArg_ParseTuple(desc_object, "bbbbO|b:type_desc",
&ptd.param_flags, &ptd.type_flags, &ptd.argnum, &ptd.argnum2,
&obIID, &ptd.array_type);
Py_DECREF(desc_object);
if (!this_ok) goto done;
Py_INCREF(ptd.extra);
// The .py code may send a 0 as the IID!
if (obIID != Py_None && !PyInt_Check(obIID)) {
if (!Py_nsIID::IIDFromPyObject(obIID, &ptd.iid))
goto done;
}
}
total_params_needed = ProcessPythonTypeDescriptors(m_python_type_desc_array, m_num_array);
// OK - check we got the number of args we expected.
@ -1390,12 +1399,9 @@ PRBool PyXPCOM_InterfaceVariantHelper::FillInVariant(const PythonTypeDescriptor
break;
}
case nsXPTType::T_INTERFACE: {
nsIID iid;
if (!Py_nsIID::IIDFromPyObject(td.extra, &iid))
BREAK_FALSE;
if (!Py_nsISupports::InterfaceFromPyObject(
val,
iid,
td.iid,
(nsISupports **)&ns_v.val.p,
PR_TRUE))
BREAK_FALSE;
@ -1481,7 +1487,7 @@ PRBool PyXPCOM_InterfaceVariantHelper::FillInVariant(const PythonTypeDescriptor
ns_v.val.p = nsnull;
break;
}
if (!PyInt_Check(td.extra)) {
if (!td.array_type) {
PyErr_SetString(PyExc_TypeError, "The array info is not valid");
BREAK_FALSE;
}
@ -1489,7 +1495,9 @@ PRBool PyXPCOM_InterfaceVariantHelper::FillInVariant(const PythonTypeDescriptor
PyErr_SetString(PyExc_TypeError, "This parameter must be a sequence");
BREAK_FALSE;
}
int array_type = PyInt_AsLong(td.extra);
int array_type = td.array_type;
int type_tag = array_type&XPT_TDP_TAGMASK;
PRUint32 element_size = GetArrayElementSize(array_type);
int seq_length = PySequence_Length(val);
cb_this_buffer_pointer = seq_length * element_size;
@ -1498,7 +1506,9 @@ PRBool PyXPCOM_InterfaceVariantHelper::FillInVariant(const PythonTypeDescriptor
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);
rc = FillSingleArray(this_buffer_pointer, val, seq_length,
element_size, array_type&XPT_TDP_TAGMASK,
td.iid);
if (!rc) break;
rc = SetSizeIs(value_index, PR_FALSE, seq_length);
if (!rc) break;
@ -1712,16 +1722,13 @@ PyObject *PyXPCOM_InterfaceVariantHelper::MakeSinglePythonResult(int index)
break;
}
case nsXPTType::T_INTERFACE: {
nsIID iid;
if (!Py_nsIID::IIDFromPyObject(td.extra, &iid))
break;
nsISupports *iret = *((nsISupports **)ns_v.ptr);
// Our cleanup code manages iret reference ownership, and our
// new object takes its own.
if (iid.Equals(NS_GET_IID(nsIVariant)))
if (td.iid.Equals(NS_GET_IID(nsIVariant)))
ret = PyObject_FromVariant(m_parent, (nsIVariant *)iret);
else
ret = m_parent->MakeInterfaceResult(iret, iid);
ret = m_parent->MakeInterfaceResult(iret, td.iid);
break;
}
case nsXPTType::T_INTERFACE_IS: {
@ -1754,11 +1761,7 @@ PyObject *PyXPCOM_InterfaceVariantHelper::MakeSinglePythonResult(int index)
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);
PRUint8 array_type = (PRUint8)td.array_type;
PRUint32 seq_size = GetSizeIs(index, PR_FALSE);
ret = UnpackSingleArray(m_parent, * ((void **)ns_v.ptr), seq_size, array_type&XPT_TDP_TAGMASK, NULL);
break;
@ -2578,9 +2581,12 @@ nsresult PyXPCOM_GatewayVariantHelper::BackFillVariant( PyObject *val, int index
// 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, NULL);
nsIID iid, *piid;
nsresult ns = GetArrayType(index, &array_type, &piid);
if (NS_FAILED(ns))
return ns;
iid = *piid;
nsMemory::Free(piid);
PRUint32 element_size = GetArrayElementSize(array_type);
if (val != Py_None) {
if (!PySequence_Check(val)) {
@ -2605,7 +2611,9 @@ nsresult PyXPCOM_GatewayVariantHelper::BackFillVariant( PyObject *val, int index
bBackFill = pi->IsIn();
}
if (bBackFill)
rc = FillSingleArray(*(void **)ns_v.val.p, val, sequence_size, element_size, array_type&XPT_TDP_TAGMASK);
rc = FillSingleArray(*(void **)ns_v.val.p, val,
sequence_size, element_size,
array_type&XPT_TDP_TAGMASK, iid);
else {
// If it is an existing array, free it.
void **pp = (void **)ns_v.val.p;
@ -2620,7 +2628,9 @@ nsresult PyXPCOM_GatewayVariantHelper::BackFillVariant( PyObject *val, int index
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);
rc = FillSingleArray(*pp, val, sequence_size,
element_size,
array_type&XPT_TDP_TAGMASK, iid);
if (!rc) break;
if (bCanSetSizeIs)
rc = SetSizeIs(index, PR_FALSE, sequence_size);

View File

@ -418,8 +418,10 @@ def test_derived_interface(c, test_flat = 0):
test_method(c.AppendVariant, (None, None), None)
test_method(c.SumVariants, ([],), None)
# Array's dont expose their interface, so we are unable to auto-wrap
# variant arrays, as they aren't aware if the IID of the array
test_method(c.SumVariants, ([1,2,3],), 6)
test_method(c.SumVariants, (['foo', 'bar'],), 'foobar')
# We previously had trouble working out the IID of interface arrays, so
# had to pass an explicitly wrapped variant - let's check that still works.
test_method(c.SumVariants, ([MakeVariant(1),MakeVariant(2),MakeVariant(3)],), 6)
test_method(c.SumVariants, ([MakeVariant('foo'), MakeVariant('bar')],), 'foobar')

View File

@ -362,7 +362,12 @@ def MakeReprForInvoke(param):
elif tag == T_ARRAY:
i_info = param.interface_info
array_desc = i_info.GetTypeForParam(param.method_index, param.param_index, 1)
return param.type_desc[:-1] + array_desc[:1]
if XPT_TDP_TAG(array_desc[0]) in (T_INTERFACE, T_INTERFACE_IS):
iid = str(i_info.GetIIDForParam(param.method_index, param.param_index))
else:
iid = None
return param.type_desc[:-1] + (iid, array_desc[0])
return param.type_desc