VirtualBox

source: vbox/trunk/src/libs/xpcom18a4/python/src/VariantUtils.cpp@ 32229

Last change on this file since 32229 was 32229, checked in by vboxsync, 15 years ago

libs/xpcom: shut up a bunch of annoying warnings

  • Property svn:eol-style set to native
File size: 91.8 KB
Line 
1/* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Original Code is the Python XPCOM language bindings.
15 *
16 * The Initial Developer of the Original Code is
17 * ActiveState Tool Corp.
18 * Portions created by the Initial Developer are Copyright (C) 2000
19 * the Initial Developer. All Rights Reserved.
20 *
21 * Contributor(s):
22 * Mark Hammond <mhammond@skippinet.com.au> (original author)
23 *
24 * Unicode corrections by Shane Hathaway (http://hathawaymix.org),
25 * inspired by Mikhail Sobolev
26 *
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
38 *
39 * ***** END LICENSE BLOCK ***** */
40
41//
42// This code is part of the XPCOM extensions for Python.
43//
44// Written May 2000 by Mark Hammond.
45//
46// Based heavily on the Python COM support, which is
47// (c) Mark Hammond and Greg Stein.
48//
49// (c) 2000, ActiveState corp.
50
51#include "PyXPCOM_std.h"
52#include <nsIInterfaceInfoManager.h>
53#include <nsAString.h>
54#include <nsString.h>
55#include <nsReadableUtils.h>
56
57// ------------------------------------------------------------------------
58// nsString utilities
59// ------------------------------------------------------------------------
60// one day we may know what they look like.
61inline
62PRBool
63IsNullDOMString( const nsAString& aString )
64{
65 return PR_FALSE;
66}
67
68inline
69PRBool
70IsNullDOMString( const nsACString& aString )
71{
72 return PR_FALSE;
73}
74
75#define PyUnicode_FromPRUnichar(src, size) \
76 PyUnicode_DecodeUTF16((char*)(src),sizeof(PRUnichar)*(size),NULL,NULL)
77
78// Create a zero-terminated PRUnichar buffer from a Python unicode.
79// On success, returns 0. On failure, returns -1 and sets an exception.
80// dest_out must not be null. size_out may be null.
81static int
82PyUnicode_AsPRUnichar(PyObject *obj, PRUnichar **dest_out, PRUint32 *size_out)
83{
84 PRUint32 size;
85 PyObject *s;
86 PRUnichar *dest;
87
88 s = PyUnicode_AsUTF16String(obj);
89 if (!s)
90 return -1;
91 size = (PyString_GET_SIZE(s) - 2) / sizeof(PRUnichar);
92 dest = (PRUnichar *)nsMemory::Alloc(sizeof(PRUnichar) * (size + 1));
93 if (!dest) {
94 PyErr_NoMemory();
95 Py_DECREF(s);
96 return -1;
97 }
98 // Drop the UTF-16 byte order mark at the beginning of
99 // the string. (See the docs on PyUnicode_AsUTF16String.)
100 // Some Mozilla libraries don't like the mark.
101 memcpy(dest, PyString_AS_STRING(s) + 2, sizeof(PRUnichar) * size);
102 Py_DECREF(s);
103 dest[size] = 0;
104 *dest_out = dest;
105 if (size_out)
106 *size_out = size;
107 return 0;
108}
109
110PyObject *PyObject_FromNSString( const nsACString &s, PRBool bAssumeUTF8 /*= PR_FALSE */)
111{
112 PyObject *ret;
113 if (IsNullDOMString(s)) {
114 ret = Py_None;
115 Py_INCREF(Py_None);
116 } else {
117 if (bAssumeUTF8) {
118 const nsPromiseFlatCString& temp = PromiseFlatCString(s);
119 ret = PyUnicode_DecodeUTF8(temp.get(), temp.Length(), NULL);
120 } else {
121 ret = PyString_FromStringAndSize(NULL, s.Length());
122 if (!ret)
123 return NULL;
124 // Need "CopyAsciiTo"!?
125 nsACString::const_iterator fromBegin, fromEnd;
126 char* dest = PyString_AS_STRING(ret);
127 copy_string(s.BeginReading(fromBegin), s.EndReading(fromEnd), dest);
128 }
129 }
130 return ret;
131}
132
133PyObject *PyObject_FromNSString( const nsAString &s )
134{
135 PyObject *ret;
136 if (IsNullDOMString(s)) {
137 ret = Py_None;
138 Py_INCREF(Py_None);
139 } else {
140 const nsPromiseFlatString& temp = PromiseFlatString(s);
141 ret = PyUnicode_FromPRUnichar(temp.get(), temp.Length());
142 }
143 return ret;
144}
145
146PyObject *PyObject_FromNSString( const PRUnichar *s,
147 PRUint32 len /* = (PRUint32)-1*/)
148{
149 return PyUnicode_FromPRUnichar(s,
150 len==((PRUint32)-1)? nsCRT::strlen(s) : len);
151}
152
153PRBool PyObject_AsNSString( PyObject *val, nsAString &aStr)
154{
155 if (val == Py_None) {
156 aStr.Truncate();
157 return NS_OK;
158 }
159 PyObject *val_use = NULL;
160 PRBool ok = PR_TRUE;
161 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
162 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
163 ok = PR_FALSE;
164 }
165 if (ok && (val_use = PyUnicode_FromObject(val))==NULL)
166 ok = PR_FALSE;
167 if (ok) {
168 if (PyUnicode_GET_SIZE(val_use) == 0) {
169 aStr.Truncate();
170 }
171 else {
172 PRUint32 nch;
173 PRUnichar *tempo;
174 // can we do this without the copy?
175 if (PyUnicode_AsPRUnichar(val_use, &tempo, &nch) < 0)
176 return PR_FALSE;
177 aStr.Assign(tempo, nch);
178 nsMemory::Free(tempo);
179 }
180 }
181 Py_XDECREF(val_use);
182 return ok;
183}
184
185// Array utilities
186static PRUint32 GetArrayElementSize( PRUint8 t)
187{
188 PRUint32 ret;
189 switch (t & XPT_TDP_TAGMASK) {
190 case nsXPTType::T_U8:
191 case nsXPTType::T_I8:
192 ret = sizeof(PRInt8);
193 break;
194 case nsXPTType::T_I16:
195 case nsXPTType::T_U16:
196 ret = sizeof(PRInt16);
197 break;
198 case nsXPTType::T_I32:
199 case nsXPTType::T_U32:
200 ret = sizeof(PRInt32);
201 break;
202 case nsXPTType::T_I64:
203 case nsXPTType::T_U64:
204 ret = sizeof(PRInt64);
205 break;
206 case nsXPTType::T_FLOAT:
207 ret = sizeof(float);
208 break;
209 case nsXPTType::T_DOUBLE:
210 ret = sizeof(double);
211 break;
212 case nsXPTType::T_BOOL:
213 ret = sizeof(PRBool);
214 break;
215 case nsXPTType::T_CHAR:
216 ret = sizeof(char);
217 break;
218 case nsXPTType::T_WCHAR:
219 ret = sizeof(PRUnichar);
220 break;
221 case nsXPTType::T_IID:
222 case nsXPTType::T_CHAR_STR:
223 case nsXPTType::T_WCHAR_STR:
224 case nsXPTType::T_INTERFACE:
225 case nsXPTType::T_DOMSTRING:
226 case nsXPTType::T_INTERFACE_IS:
227 case nsXPTType::T_PSTRING_SIZE_IS:
228 case nsXPTType::T_CSTRING:
229 case nsXPTType::T_ASTRING:
230 case nsXPTType::T_UTF8STRING:
231
232 ret = sizeof( void * );
233 break;
234 default:
235 NS_ABORT_IF_FALSE(0, "Unknown array type code!");
236 ret = 0;
237 break;
238 }
239 return ret;
240}
241
242static nsresult
243GetArrayElementIID(Py_nsISupports* self,
244 nsXPTCVariant* dispatchParams,
245 PRUint16 methodIndex,
246 PRUint8 paramIndex,
247 nsIID *result)
248{
249 nsCOMPtr<nsIInterfaceInfoManager> iim = XPTI_GetInterfaceInfoManager();
250 nsCOMPtr<nsIInterfaceInfo> ii;
251 nsresult rc;
252
253 rc = iim->GetInfoForIID(&self->m_iid, getter_AddRefs(ii));
254 if (NS_FAILED(rc))
255 return rc;
256
257
258 const nsXPTMethodInfo *mi;
259 rc = ii->GetMethodInfo(methodIndex, &mi);
260 if (NS_FAILED(rc))
261 return rc;
262
263 const nsXPTParamInfo& paramInfo = mi->GetParam(paramIndex);
264
265 if (!paramInfo.GetType().IsArray()) {
266 PyXPCOM_LogWarning("Passing non-array to GetArrayElementIID\n");
267 return NS_ERROR_INVALID_ARG;
268 }
269
270 nsXPTType elemType;
271 rc = ii->GetTypeForParam(methodIndex, &paramInfo, 1, &elemType);
272 if (NS_FAILED(rc))
273 return rc;
274
275 PRUint8 tag = elemType.TagPart();
276 if (tag == nsXPTType::T_INTERFACE)
277 {
278 rc = ii->GetIIDForParamNoAlloc(methodIndex, &paramInfo, result);
279 }
280 else if (tag == nsXPTType::T_INTERFACE_IS)
281 {
282 PyXPCOM_LogWarning("Unable to handle T_INTERFACE_IS yet\n");
283 return NS_ERROR_NOT_IMPLEMENTED;
284 }
285 else
286 {
287 // this may be valid case, for arrays of other types
288 // we don't need IID for
289 rc = NS_ERROR_INVALID_ARG;
290 }
291
292 return rc;
293}
294
295
296void FreeSingleArray(void *array_ptr, PRUint32 sequence_size, PRUint8 array_type)
297{
298 // Free each array element - NOT the array itself
299 // Thus, we only need to free arrays or pointers.
300 void **p = (void **)array_ptr;
301 PRUint32 i;
302 switch(array_type & XPT_TDP_TAGMASK) {
303 case nsXPTType::T_IID:
304 case nsXPTType::T_CHAR_STR:
305 case nsXPTType::T_WCHAR_STR:
306 for (i=0; i<sequence_size; i++)
307 if (p[i]) nsMemory::Free(p[i]);
308 break;
309 case nsXPTType::T_INTERFACE:
310 case nsXPTType::T_INTERFACE_IS:
311 for (i=0; i<sequence_size; i++)
312 if (p[i]) {
313 Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
314 ((nsISupports *)p[i])->Release();
315 Py_END_ALLOW_THREADS;
316 }
317 break;
318
319 // Ones we know need no deallocation
320 case nsXPTType::T_U8:
321 case nsXPTType::T_I8:
322 case nsXPTType::T_I16:
323 case nsXPTType::T_U16:
324 case nsXPTType::T_I32:
325 case nsXPTType::T_U32:
326 case nsXPTType::T_I64:
327 case nsXPTType::T_U64:
328 case nsXPTType::T_FLOAT:
329 case nsXPTType::T_DOUBLE:
330 case nsXPTType::T_BOOL:
331 case nsXPTType::T_CHAR:
332 case nsXPTType::T_WCHAR:
333 break;
334
335 // And a warning should new type codes appear, as they may need deallocation.
336 default:
337 PyXPCOM_LogWarning("Deallocating unknown type %d (0x%x) - possible memory leak\n");
338 break;
339 }
340}
341
342#define FILL_SIMPLE_POINTER( type, val ) *((type *)pthis) = (type)(val)
343#define BREAK_FALSE {rc=PR_FALSE;break;}
344
345
346PRBool FillSingleArray(void *array_ptr, PyObject *sequence_ob, PRUint32 sequence_size,
347 PRUint32 array_element_size, PRUint8 array_type, nsIID *pIID)
348{
349 PRUint8 *pthis = (PRUint8 *)array_ptr;
350 NS_ABORT_IF_FALSE(pthis, "Don't have a valid array to fill!");
351 PRBool rc = PR_TRUE;
352 // We handle T_U8 specially as a string/Unicode.
353 // If it is NOT a string, we just fall through and allow the standard
354 // sequence unpack code process it (just slower!)
355 if ( array_type == nsXPTType::T_U8 &&
356 (PyString_Check(sequence_ob) || PyUnicode_Check(sequence_ob))) {
357
358 PRBool release_seq;
359 if (PyUnicode_Check(sequence_ob)) {
360 release_seq = PR_TRUE;
361 sequence_ob = PyObject_Str(sequence_ob);
362 } else
363 release_seq = PR_FALSE;
364 if (!sequence_ob) // presumably a memory error, or Unicode encoding error.
365 return PR_FALSE;
366 memcpy(pthis, PyString_AS_STRING(sequence_ob), sequence_size);
367 if (release_seq)
368 {
369 Py_DECREF(sequence_ob);
370 }
371 return PR_TRUE;
372 }
373
374 for (PRUint32 i=0; rc && i<sequence_size; i++,pthis += array_element_size) {
375 PyObject *val = PySequence_GetItem(sequence_ob, i);
376 PyObject *val_use = NULL;
377 if (val==NULL)
378 return PR_FALSE;
379 switch(array_type) {
380 case nsXPTType::T_I8:
381 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
382 FILL_SIMPLE_POINTER( PRInt8, PyInt_AsLong(val_use) );
383 break;
384 case nsXPTType::T_I16:
385 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
386 FILL_SIMPLE_POINTER( PRInt16, PyInt_AsLong(val_use) );
387 break;
388 case nsXPTType::T_I32:
389 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
390 FILL_SIMPLE_POINTER( PRInt32, PyInt_AsLong(val_use) );
391 break;
392 case nsXPTType::T_I64:
393 if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE;
394 FILL_SIMPLE_POINTER( PRInt64, PyLong_AsLongLong(val_use) );
395 break;
396 case nsXPTType::T_U8:
397 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
398 FILL_SIMPLE_POINTER( PRUint8, PyInt_AsLong(val_use) );
399 break;
400 case nsXPTType::T_U16:
401 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
402 FILL_SIMPLE_POINTER( PRUint16, PyInt_AsLong(val_use) );
403 break;
404 case nsXPTType::T_U32:
405 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
406 FILL_SIMPLE_POINTER( PRUint32, PyInt_AsLong(val_use) );
407 break;
408 case nsXPTType::T_U64:
409 if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE;
410 FILL_SIMPLE_POINTER( PRUint64, PyLong_AsUnsignedLongLong(val_use) );
411 break;
412 case nsXPTType::T_FLOAT:
413 if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
414 FILL_SIMPLE_POINTER( float, PyFloat_AsDouble(val_use) );
415 break;
416 case nsXPTType::T_DOUBLE:
417 if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
418 FILL_SIMPLE_POINTER( double, PyFloat_AsDouble(val_use) );
419 break;
420 case nsXPTType::T_BOOL:
421 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
422 FILL_SIMPLE_POINTER( PRBool, PyInt_AsLong(val_use) );
423 break;
424 case nsXPTType::T_CHAR:
425 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
426 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
427 BREAK_FALSE;
428 }
429 if ((val_use = PyObject_Str(val))==NULL)
430 BREAK_FALSE;
431 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
432 NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
433 FILL_SIMPLE_POINTER( char, *PyString_AS_STRING(val_use) );
434 break;
435
436 case nsXPTType::T_WCHAR:
437 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
438 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
439 BREAK_FALSE;
440 }
441 if ((val_use = PyUnicode_FromObject(val)) == NULL)
442 BREAK_FALSE;
443 NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!");
444 // Lossy!
445 FILL_SIMPLE_POINTER( PRUnichar, *PyUnicode_AS_UNICODE(val_use) );
446 break;
447
448 case nsXPTType::T_IID: {
449 nsIID iid;
450 if (!Py_nsIID::IIDFromPyObject(val, &iid))
451 BREAK_FALSE;
452 nsIID **pp = (nsIID **)pthis;
453 // If there is an existing IID, free it.
454 if (*pp)
455 nsMemory::Free(*pp);
456 *pp = (nsIID *)nsMemory::Alloc(sizeof(nsIID));
457 if (*pp==NULL) {
458 PyErr_NoMemory();
459 BREAK_FALSE;
460 }
461 memcpy(*pp, &iid, sizeof(iid));
462 break;
463 }
464
465 // case nsXPTType::T_BSTR:
466
467 case nsXPTType::T_CHAR_STR: {
468 // If it is an existing string, free it.
469 char **pp = (char **)pthis;
470 if (*pp)
471 nsMemory::Free(*pp);
472 *pp = nsnull;
473
474 if (val == Py_None)
475 break; // Remains NULL.
476 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
477 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
478 BREAK_FALSE;
479 }
480 if ((val_use = PyObject_Str(val))==NULL)
481 BREAK_FALSE;
482 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
483 NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
484
485 const char *sz = PyString_AS_STRING(val_use);
486 int nch = PyString_GET_SIZE(val_use);
487
488 *pp = (char *)nsMemory::Alloc(nch+1);
489 if (*pp==NULL) {
490 PyErr_NoMemory();
491 BREAK_FALSE;
492 }
493 strncpy(*pp, sz, nch+1);
494 break;
495 }
496 case nsXPTType::T_WCHAR_STR: {
497 // If it is an existing string, free it.
498 PRUnichar **pp = (PRUnichar **)pthis;
499 if (*pp)
500 nsMemory::Free(*pp);
501 *pp = nsnull;
502 if (val == Py_None)
503 break; // Remains NULL.
504 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
505 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
506 BREAK_FALSE;
507 }
508 if ((val_use = PyUnicode_FromObject(val))==NULL)
509 BREAK_FALSE;
510 NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!");
511 if (PyUnicode_AsPRUnichar(val_use, pp, NULL) < 0)
512 BREAK_FALSE;
513 break;
514 }
515 case nsXPTType::T_INTERFACE_IS: // hmm - ignoring the IID can't be good :(
516 case nsXPTType::T_INTERFACE: {
517 // We do allow NULL here, even tho doing so will no-doubt crash some objects.
518 // (but there will certainly be objects out there that will allow NULL :-(
519 nsISupports *pnew;
520 if (!Py_nsISupports::InterfaceFromPyObject(val, NS_GET_IID(nsISupports), &pnew, PR_TRUE))
521 BREAK_FALSE;
522 nsISupports **pp = (nsISupports **)pthis;
523 if (*pp) {
524 Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
525 (*pp)->Release();
526 Py_END_ALLOW_THREADS;
527 }
528 *pp = pnew; // ref-count added by InterfaceFromPyObject
529 break;
530 }
531 default:
532 // try and limp along in this case.
533 // leave rc TRUE
534 PyXPCOM_LogWarning("Converting Python object for an array element - The object type (0x%x) is unknown - leaving param alone!\n", array_type);
535 break;
536 }
537 Py_XDECREF(val_use);
538 Py_DECREF(val);
539 }
540 return rc;
541}
542
543static PyObject *UnpackSingleArray(Py_nsISupports *parent, void *array_ptr,
544 PRUint32 sequence_size, PRUint8 array_type, nsIID *iid)
545{
546 if (array_ptr==NULL) {
547 Py_INCREF(Py_None);
548 return Py_None;
549 }
550 if (array_type == nsXPTType::T_U8)
551 return PyString_FromStringAndSize( (char *)array_ptr, sequence_size );
552
553 PRUint32 array_element_size = GetArrayElementSize(array_type);
554 PyObject *list_ret = PyList_New(sequence_size);
555 PRUint8 *pthis = (PRUint8 *)array_ptr;
556 for (PRUint32 i=0; i<sequence_size; i++,pthis += array_element_size) {
557 PyObject *val = NULL;
558 switch(array_type) {
559 case nsXPTType::T_I8:
560 val = PyInt_FromLong( *((PRInt8 *)pthis) );
561 break;
562 case nsXPTType::T_I16:
563 val = PyInt_FromLong( *((PRInt16 *)pthis) );
564 break;
565 case nsXPTType::T_I32:
566 val = PyInt_FromLong( *((PRInt32 *)pthis) );
567 break;
568 case nsXPTType::T_I64:
569 val = PyLong_FromLongLong( *((PRInt64 *)pthis) );
570 break;
571 // case nsXPTType::T_U8 - handled above!
572 case nsXPTType::T_U16:
573 val = PyInt_FromLong( *((PRUint16 *)pthis) );
574 break;
575 case nsXPTType::T_U32:
576 val = PyInt_FromLong( *((PRUint32 *)pthis) );
577 break;
578 case nsXPTType::T_U64:
579 val = PyLong_FromUnsignedLongLong( *((PRUint64 *)pthis) );
580 break;
581 case nsXPTType::T_FLOAT:
582 val = PyFloat_FromDouble( *((float*)pthis) );
583 break;
584 case nsXPTType::T_DOUBLE:
585 val = PyFloat_FromDouble( *((double*)pthis) );
586 break;
587 case nsXPTType::T_BOOL:
588 val = (*((PRBool *)pthis)) ? Py_True : Py_False;
589 Py_INCREF(val);
590 break;
591 case nsXPTType::T_IID:
592 val = Py_nsIID::PyObjectFromIID( **((nsIID **)pthis) );
593 break;
594
595 case nsXPTType::T_CHAR_STR: {
596 char **pp = (char **)pthis;
597 if (*pp==NULL) {
598 Py_INCREF(Py_None);
599 val = Py_None;
600 } else
601 val = PyString_FromString(*pp);
602 break;
603 }
604 case nsXPTType::T_WCHAR_STR: {
605 PRUnichar **pp = (PRUnichar **)pthis;
606 if (*pp==NULL) {
607 Py_INCREF(Py_None);
608 val = Py_None;
609 } else {
610 val = PyUnicode_FromPRUnichar( *pp, nsCRT::strlen(*pp) );
611 }
612 break;
613 }
614 case nsXPTType::T_INTERFACE_IS:
615 case nsXPTType::T_INTERFACE: {
616 nsISupports **pp = (nsISupports **)pthis;
617 // If we have an owning parent, let it create
618 // the object for us.
619 if (iid && iid->Equals(NS_GET_IID(nsIVariant)))
620 val = PyObject_FromVariant(parent, (nsIVariant *)*pp);
621 else if (parent)
622 val = parent->MakeInterfaceResult(*pp, iid ? *iid : NS_GET_IID(nsISupports));
623 else
624 val = Py_nsISupports::PyObjectFromInterface(
625 *pp,
626 iid ? *iid : NS_GET_IID(nsISupports),
627 PR_TRUE);
628 break;
629 }
630 default: {
631 char buf[128];
632 sprintf(buf, "Unknown XPCOM array type flags (0x%x)", array_type);
633 PyXPCOM_LogWarning("%s - returning a string object with this message!\n", buf);
634 val = PyString_FromString(buf);
635 break;
636 }
637 }
638 if (val==NULL) {
639 NS_ABORT_IF_FALSE(PyErr_Occurred(), "NULL result in array conversion, but no error set!");
640 return NULL;
641 }
642 PyList_SET_ITEM(list_ret, i, val); // ref-count consumed.
643 }
644 return list_ret;
645}
646
647
648// ------------------------------------------------------------------------
649// nsIVariant utilities
650// ------------------------------------------------------------------------
651struct BVFTResult {
652 BVFTResult() {pis = NULL;iid=Py_nsIID_NULL;}
653 nsISupports *pis;
654 nsIID iid;
655};
656
657static PRUint16 BestVariantTypeForPyObject( PyObject *ob, BVFTResult *pdata = NULL)
658{
659 nsISupports *ps = NULL;
660 nsIID iid;
661 // start with some fast concrete checks.
662 if (ob==Py_None)
663 return nsIDataType::VTYPE_EMPTY;
664 if (ob==Py_True || ob == Py_False)
665 return nsIDataType::VTYPE_BOOL;
666 if (PyInt_Check(ob))
667 return nsIDataType::VTYPE_INT32;
668 if (PyLong_Check(ob))
669 return nsIDataType::VTYPE_INT64;
670 if (PyFloat_Check(ob))
671 return nsIDataType::VTYPE_DOUBLE;
672 if (PyString_Check(ob))
673 return nsIDataType::VTYPE_STRING_SIZE_IS;
674 if (PyUnicode_Check(ob))
675 return nsIDataType::VTYPE_WSTRING_SIZE_IS;
676 if (PyTuple_Check(ob) || PyList_Check(ob)) {
677 if (PySequence_Length(ob))
678 return nsIDataType::VTYPE_ARRAY;
679 return nsIDataType::VTYPE_EMPTY_ARRAY;
680 }
681 // Now do expensive or abstract checks.
682 if (Py_nsISupports::InterfaceFromPyObject(ob, NS_GET_IID(nsISupports), &ps, PR_TRUE)) {
683 if (pdata) {
684 pdata->pis = ps;
685 pdata->iid = NS_GET_IID(nsISupports);
686 } else
687 ps->Release();
688 return nsIDataType::VTYPE_INTERFACE_IS;
689 } else
690 PyErr_Clear();
691 if (Py_nsIID::IIDFromPyObject(ob, &iid)) {
692 if (pdata)
693 pdata->iid = iid;
694 return nsIDataType::VTYPE_ID;
695 } else
696 PyErr_Clear();
697 if (PySequence_Check(ob)) {
698 if (PySequence_Length(ob))
699 return nsIDataType::VTYPE_ARRAY;
700 return nsIDataType::VTYPE_EMPTY_ARRAY;
701 }
702 return (PRUint16)-1;
703}
704
705nsresult PyObject_AsVariant( PyObject *ob, nsIVariant **aRet)
706{
707 nsresult nr = NS_OK;
708 nsCOMPtr<nsIWritableVariant> v = do_CreateInstance("@mozilla.org/variant;1", &nr);
709 NS_ENSURE_SUCCESS(nr, nr);
710 // *sigh* - I tried the abstract API (PyNumber_Check, etc)
711 // but our COM instances too often qualify.
712 BVFTResult cvt_result;
713 PRUint16 dt = BestVariantTypeForPyObject(ob, &cvt_result);
714 switch (dt) {
715 case nsIDataType::VTYPE_BOOL:
716 nr = v->SetAsBool(ob==Py_True);
717 break;
718 case nsIDataType::VTYPE_INT32:
719 nr = v->SetAsInt32(PyInt_AsLong(ob));
720 break;
721 case nsIDataType::VTYPE_INT64:
722 nr = v->SetAsInt64(PyLong_AsLongLong(ob));
723 break;
724 case nsIDataType::VTYPE_DOUBLE:
725 nr = v->SetAsDouble(PyFloat_AsDouble(ob));
726 break;
727 case nsIDataType::VTYPE_STRING_SIZE_IS:
728 nr = v->SetAsStringWithSize(PyString_Size(ob), PyString_AsString(ob));
729 break;
730 case nsIDataType::VTYPE_WSTRING_SIZE_IS:
731 if (PyUnicode_GetSize(ob) == 0) {
732 nr = v->SetAsWStringWithSize(0, (PRUnichar*)NULL);
733 }
734 else {
735 PRUint32 nch;
736 PRUnichar *p;
737 if (PyUnicode_AsPRUnichar(ob, &p, &nch) < 0) {
738 PyXPCOM_LogWarning("Failed to convert object to unicode", ob->ob_type->tp_name);
739 nr = NS_ERROR_UNEXPECTED;
740 break;
741 }
742 nr = v->SetAsWStringWithSize(nch, p);
743 nsMemory::Free(p);
744 }
745 break;
746 case nsIDataType::VTYPE_INTERFACE_IS:
747 {
748 nsISupports *ps = cvt_result.pis;
749 nr = v->SetAsInterface(cvt_result.iid, ps);
750 if (ps) {
751 Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
752 ps->Release();
753 Py_END_ALLOW_THREADS;
754 }
755 break;
756 }
757 case nsIDataType::VTYPE_ID:
758 nr = v->SetAsID(cvt_result.iid);
759 break;
760 case nsIDataType::VTYPE_ARRAY:
761 {
762 int seq_length = PySequence_Length(ob);
763 NS_ABORT_IF_FALSE(seq_length!=0, "VTYPE_ARRAY assumes at least one element!");
764 PyObject *first = PySequence_GetItem(ob, 0);
765 if (!first) break;
766 int array_type = BestVariantTypeForPyObject(first);
767 Py_DECREF(first);
768 // Arrays can't handle all types. This means we lost embedded NULLs.
769 // This should really be fixed in XPCOM.
770 if (array_type == nsIDataType::VTYPE_STRING_SIZE_IS) array_type = nsIDataType::VTYPE_CHAR_STR;
771 if (array_type == nsIDataType::VTYPE_WSTRING_SIZE_IS) array_type = nsIDataType::VTYPE_WCHAR_STR;
772 PRUint32 element_size = GetArrayElementSize(array_type);
773 int cb_buffer_pointer = seq_length * element_size;
774 void *buffer_pointer;
775 if ((buffer_pointer = (void *)nsMemory::Alloc(cb_buffer_pointer)) == nsnull) {
776 nr = NS_ERROR_OUT_OF_MEMORY;
777 break;
778 }
779 memset(buffer_pointer, 0, cb_buffer_pointer);
780 if (FillSingleArray(buffer_pointer, ob, seq_length, element_size, array_type, nsnull)) {
781 nr = v->SetAsArray(array_type, &NS_GET_IID(nsISupports), seq_length, buffer_pointer);
782 FreeSingleArray(buffer_pointer, seq_length, array_type);
783 } else
784 nr = NS_ERROR_UNEXPECTED;
785 nsMemory::Free(buffer_pointer);
786 break;
787 }
788 case nsIDataType::VTYPE_EMPTY:
789 nr = v->SetAsEmpty();
790 break;
791 case nsIDataType::VTYPE_EMPTY_ARRAY:
792 nr = v->SetAsEmptyArray();
793 break;
794 case (PRUint16)-1:
795 PyXPCOM_LogWarning("Objects of type '%s' can not be converted to an nsIVariant", ob->ob_type->tp_name);
796 nr = NS_ERROR_UNEXPECTED;
797 default:
798 NS_ABORT_IF_FALSE(0, "BestVariantTypeForPyObject() returned a variant type not handled here!");
799 PyXPCOM_LogWarning("Objects of type '%s' can not be converted to an nsIVariant", ob->ob_type->tp_name);
800 nr = NS_ERROR_UNEXPECTED;
801 }
802 if (NS_FAILED(nr))
803 return nr;
804 return v->QueryInterface(NS_GET_IID(nsIVariant), (void **)aRet);
805}
806
807static PyObject *MyBool_FromBool(PRBool v)
808{
809 PyObject *ret = v ? Py_True : Py_False;
810 Py_INCREF(ret);
811 return ret;
812}
813
814#define GET_FROM_V(Type, FuncGet, FuncConvert) { \
815 Type t; \
816 if (NS_FAILED(nr = FuncGet( &t ))) goto done;\
817 ret = FuncConvert(t);\
818 break; \
819}
820
821PyObject *PyObject_FromVariantArray( Py_nsISupports *parent, nsIVariant *v)
822{
823 nsresult nr;
824 NS_PRECONDITION(v, "NULL variant!");
825 if (!v)
826 return PyXPCOM_BuildPyException(NS_ERROR_INVALID_POINTER);
827#ifdef NS_DEBUG
828 PRUint16 dt;
829 nr = v->GetDataType(&dt);
830 NS_ABORT_IF_FALSE(dt == nsIDataType::VTYPE_ARRAY, "expected an array variant");
831#endif
832 nsIID iid;
833 void *p;
834 PRUint16 type;
835 PRUint32 count;
836 nr = v->GetAsArray(&type, &iid, &count, &p);
837 if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr);
838 PyObject *ret = UnpackSingleArray(parent, p, count, (PRUint8)type, &iid);
839 FreeSingleArray(p, count, (PRUint8)type);
840 nsMemory::Free(p);
841 return ret;
842}
843
844PyObject *PyObject_FromVariant( Py_nsISupports *parent, nsIVariant *v)
845{
846 if (!v) {
847 Py_INCREF(Py_None);
848 return Py_None;
849 }
850 PRUint16 dt;
851 nsresult nr;
852 PyObject *ret = NULL;
853 nr = v->GetDataType(&dt);
854 if (NS_FAILED(nr)) goto done;
855 switch (dt) {
856 case nsIDataType::VTYPE_VOID:
857 case nsIDataType::VTYPE_EMPTY:
858 case nsIDataType::VTYPE_EMPTY_ARRAY:
859 ret = Py_None;
860 Py_INCREF(Py_None);
861 break;
862 case nsIDataType::VTYPE_ARRAY:
863 ret = PyObject_FromVariantArray(parent, v);
864 break;
865 case nsIDataType::VTYPE_INT8:
866 case nsIDataType::VTYPE_INT16:
867 case nsIDataType::VTYPE_INT32:
868 GET_FROM_V(PRInt32, v->GetAsInt32, PyInt_FromLong);
869 case nsIDataType::VTYPE_UINT8:
870 case nsIDataType::VTYPE_UINT16:
871 case nsIDataType::VTYPE_UINT32:
872 GET_FROM_V(PRUint32, v->GetAsUint32, PyLong_FromUnsignedLong);
873 case nsIDataType::VTYPE_INT64:
874 GET_FROM_V(PRInt64, v->GetAsInt64, PyLong_FromLongLong);
875 case nsIDataType::VTYPE_UINT64:
876 GET_FROM_V(PRUint64, v->GetAsUint64, PyLong_FromUnsignedLongLong);
877 case nsIDataType::VTYPE_FLOAT:
878 case nsIDataType::VTYPE_DOUBLE:
879 GET_FROM_V(double, v->GetAsDouble, PyFloat_FromDouble);
880 case nsIDataType::VTYPE_BOOL:
881 GET_FROM_V(PRBool, v->GetAsBool, MyBool_FromBool);
882 default:
883 PyXPCOM_LogWarning("Converting variant to Python object - variant type '%d' unknown - using string.\n", dt);
884 // Fall through to the string case
885 case nsIDataType::VTYPE_CHAR:
886 case nsIDataType::VTYPE_CHAR_STR:
887 case nsIDataType::VTYPE_STRING_SIZE_IS:
888 case nsIDataType::VTYPE_CSTRING: {
889 nsCAutoString s;
890 if (NS_FAILED(nr=v->GetAsACString(s))) goto done;
891 ret = PyObject_FromNSString(s);
892 break;
893 }
894 case nsIDataType::VTYPE_WCHAR:
895 case nsIDataType::VTYPE_DOMSTRING:
896 case nsIDataType::VTYPE_WSTRING_SIZE_IS:
897 case nsIDataType::VTYPE_ASTRING: {
898 nsAutoString s;
899 if (NS_FAILED(nr=v->GetAsAString(s))) goto done;
900 ret = PyObject_FromNSString(s);
901 break;
902 }
903 case nsIDataType::VTYPE_ID:
904 GET_FROM_V(nsIID, v->GetAsID, Py_nsIID::PyObjectFromIID);
905 case nsIDataType::VTYPE_INTERFACE: {
906 nsCOMPtr<nsISupports> p;
907 if (NS_FAILED(nr=v->GetAsISupports(getter_AddRefs(p)))) goto done;
908 if (parent)
909 ret = parent->MakeInterfaceResult(p, NS_GET_IID(nsISupports));
910 else
911 ret = Py_nsISupports::PyObjectFromInterface(
912 p, NS_GET_IID(nsISupports), PR_TRUE);
913 break;
914 }
915 case nsIDataType::VTYPE_INTERFACE_IS: {
916 nsCOMPtr<nsISupports> p;
917 nsIID *iid;
918 if (NS_FAILED(nr=v->GetAsInterface(&iid, getter_AddRefs(p)))) goto done;
919 // If the variant itself holds a variant, we should
920 // probably unpack that too?
921 ret = parent->MakeInterfaceResult(p, *iid);
922 break;
923 // case nsIDataType::VTYPE_WCHAR_STR
924 // case nsIDataType::VTYPE_UTF8STRING
925 }
926 }
927done:
928 if (NS_FAILED(nr)) {
929 NS_ABORT_IF_FALSE(ret==NULL, "Have an error, but also a return val!");
930 PyXPCOM_BuildPyException(nr);
931 }
932 return ret;
933}
934
935// ------------------------------------------------------------------------
936// TypeDescriptor helper class
937// ------------------------------------------------------------------------
938class PythonTypeDescriptor {
939public:
940 PythonTypeDescriptor() {
941 param_flags = type_flags = argnum = argnum2 = 0;
942 extra = NULL;
943 is_auto_out = PR_FALSE;
944 is_auto_in = PR_FALSE;
945 have_set_auto = PR_FALSE;
946 }
947 ~PythonTypeDescriptor() {
948 Py_XDECREF(extra);
949 }
950 PRUint8 param_flags;
951 PRUint8 type_flags;
952 PRUint8 argnum; /* used for iid_is and size_is */
953 PRUint8 argnum2; /* used for length_is */
954 PyObject *extra; // The IID object, or the type of the array.
955 // Extra items to help our processing.
956 // Is this auto-filled by some other "in" param?
957 PRBool is_auto_in;
958 // Is this auto-filled by some other "out" param?
959 PRBool is_auto_out;
960 // If is_auto_out, have I already filled it? Used when multiple
961 // params share a size_is fields - first time sets it, subsequent
962 // time check it.
963 PRBool have_set_auto;
964};
965
966static int ProcessPythonTypeDescriptors(PythonTypeDescriptor *pdescs, int num)
967{
968 // Loop over the array, checking all the params marked as having an arg.
969 // If these args nominate another arg as the size_is param, then
970 // we reset the size_is param to _not_ requiring an arg.
971 int i;
972 for (i=0;i<num;i++) {
973 PythonTypeDescriptor &ptd = pdescs[i];
974 // Can't use XPT_TDP_TAG() - it uses a ".flags" reference in the macro.
975 switch (ptd.type_flags & XPT_TDP_TAGMASK) {
976 case nsXPTType::T_ARRAY:
977 NS_ABORT_IF_FALSE(ptd.argnum < num, "Bad dependent index");
978 if (ptd.argnum2 < num) {
979 if (XPT_PD_IS_IN(ptd.param_flags))
980 pdescs[ptd.argnum2].is_auto_in = PR_TRUE;
981 if (XPT_PD_IS_OUT(ptd.param_flags))
982 pdescs[ptd.argnum2].is_auto_out = PR_TRUE;
983 }
984 break;
985 case nsXPTType::T_PSTRING_SIZE_IS:
986 case nsXPTType::T_PWSTRING_SIZE_IS:
987 NS_ABORT_IF_FALSE(ptd.argnum < num, "Bad dependent index");
988 if (ptd.argnum < num) {
989 if (XPT_PD_IS_IN(ptd.param_flags))
990 pdescs[ptd.argnum].is_auto_in = PR_TRUE;
991 if (XPT_PD_IS_OUT(ptd.param_flags))
992 pdescs[ptd.argnum].is_auto_out = PR_TRUE;
993 }
994 break;
995 default:
996 break;
997 }
998 }
999 int total_params_needed = 0;
1000 for (i=0;i<num;i++)
1001 if (XPT_PD_IS_IN(pdescs[i].param_flags) && !pdescs[i].is_auto_in && !XPT_PD_IS_DIPPER(pdescs[i].param_flags))
1002 total_params_needed++;
1003
1004 return total_params_needed;
1005}
1006
1007/*************************************************************************
1008**************************************************************************
1009
1010Helpers when CALLING interfaces.
1011
1012**************************************************************************
1013*************************************************************************/
1014
1015PyXPCOM_InterfaceVariantHelper::PyXPCOM_InterfaceVariantHelper(Py_nsISupports *parent, int methodindex)
1016{
1017 m_var_array=nsnull;
1018 m_buffer_array=nsnull;
1019 m_pyparams=nsnull;
1020 m_num_array = 0;
1021 m_methodindex = methodindex;
1022 // Parent should never die before we do, but let's not take the chance.
1023 m_parent = parent;
1024 Py_INCREF(parent);
1025}
1026
1027PyXPCOM_InterfaceVariantHelper::~PyXPCOM_InterfaceVariantHelper()
1028{
1029 Py_DECREF(m_parent);
1030 Py_XDECREF(m_pyparams);
1031 for (int i=0;i<m_num_array;i++) {
1032 if (m_var_array) {
1033 nsXPTCVariant &ns_v = m_var_array[i];
1034 if (ns_v.IsValInterface()) {
1035 if (ns_v.val.p) {
1036 Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
1037 ((nsISupports *)ns_v.val.p)->Release();
1038 Py_END_ALLOW_THREADS;
1039 }
1040 }
1041 if (ns_v.IsValDOMString() && ns_v.val.p) {
1042 delete (const nsAString *)ns_v.val.p;
1043 }
1044 if (ns_v.IsValCString() && ns_v.val.p) {
1045 delete (const nsACString *)ns_v.val.p;
1046 }
1047 if (ns_v.IsValUTF8String() && ns_v.val.p) {
1048 delete (const nsACString *)ns_v.val.p;
1049 }
1050 if (ns_v.IsValArray()) {
1051 nsXPTCVariant &ns_v = m_var_array[i];
1052 if (ns_v.val.p) {
1053 PRUint8 array_type = (PRUint8)PyInt_AsLong(m_python_type_desc_array[i].extra);
1054 PRUint32 seq_size = GetSizeIs(i, PR_FALSE);
1055 FreeSingleArray(ns_v.val.p, seq_size, array_type);
1056 }
1057 }
1058 // IsOwned must be the last check of the loop, as
1059 // this frees the underlying data used above (eg, by the array free process)
1060 if (ns_v.IsValAllocated() && !ns_v.IsValInterface() && !ns_v.IsValDOMString()) {
1061 NS_ABORT_IF_FALSE(ns_v.IsPtrData(), "expecting a pointer to free");
1062 nsMemory::Free(ns_v.val.p);
1063 }
1064 }
1065 if (m_buffer_array && m_buffer_array[i])
1066 nsMemory::Free(m_buffer_array[i]);
1067 }
1068 delete [] m_python_type_desc_array;
1069 delete [] m_buffer_array;
1070 delete [] m_var_array;
1071}
1072
1073PRBool PyXPCOM_InterfaceVariantHelper::Init(PyObject *obParams)
1074{
1075 PRBool ok = PR_FALSE;
1076 int i;
1077 int total_params_needed = 0;
1078 if (!PySequence_Check(obParams) || PySequence_Length(obParams)!=2) {
1079 PyErr_Format(PyExc_TypeError, "Param descriptors must be a sequence of exactly length 2");
1080 return PR_FALSE;
1081 }
1082 PyObject *typedescs = PySequence_GetItem(obParams, 0);
1083 if (typedescs==NULL)
1084 return PR_FALSE;
1085 // NOTE: The length of the typedescs may be different than the
1086 // args actually passed. The typedescs always include all
1087 // hidden params (such as "size_is"), while the actual
1088 // args never include this.
1089 m_num_array = PySequence_Length(typedescs);
1090 if (PyErr_Occurred()) goto done;
1091
1092 m_pyparams = PySequence_GetItem(obParams, 1);
1093 if (m_pyparams==NULL) goto done;
1094
1095 m_python_type_desc_array = new PythonTypeDescriptor[m_num_array];
1096 if (!m_python_type_desc_array) goto done;
1097
1098 // Pull apart the type descs and stash them.
1099 for (i=0;i<m_num_array;i++) {
1100 PyObject *desc_object = PySequence_GetItem(typedescs, i);
1101 if (desc_object==NULL)
1102 goto done;
1103
1104 // Pull apart the typedesc tuple back into a structure we can work with.
1105 PythonTypeDescriptor &ptd = m_python_type_desc_array[i];
1106 PRBool this_ok = PyArg_ParseTuple(desc_object, "bbbbO:type_desc",
1107 &ptd.param_flags, &ptd.type_flags, &ptd.argnum, &ptd.argnum2, &ptd.extra);
1108 Py_DECREF(desc_object);
1109 if (!this_ok) goto done;
1110 Py_INCREF(ptd.extra);
1111
1112 }
1113 total_params_needed = ProcessPythonTypeDescriptors(m_python_type_desc_array, m_num_array);
1114 // OK - check we got the number of args we expected.
1115 // If not, its really an internal error rather than the user.
1116 if (PySequence_Length(m_pyparams) != total_params_needed) {
1117#ifdef VBOX
1118 PyErr_Format(PyExc_ValueError, "The type descriptions indicate %d args are needed, but %u were provided",
1119 total_params_needed, PySequence_Length(m_pyparams));
1120#else
1121 PyErr_Format(PyExc_ValueError, "The type descriptions indicate %d args are needed, but %d were provided",
1122 total_params_needed, PySequence_Length(m_pyparams));
1123#endif
1124 goto done;
1125 }
1126
1127 // Init the other arrays.
1128 m_var_array = new nsXPTCVariant[m_num_array];
1129 if (!m_var_array) goto done;
1130 memset(m_var_array, 0, m_num_array * sizeof(m_var_array[0]));
1131
1132 m_buffer_array = new void *[m_num_array];
1133 if (!m_buffer_array) goto done;
1134 memset(m_buffer_array, 0, m_num_array * sizeof(m_buffer_array[0]));
1135
1136 ok = PR_TRUE;
1137done:
1138 if (!ok && !PyErr_Occurred())
1139 PyErr_NoMemory();
1140
1141 Py_XDECREF(typedescs);
1142 return ok;
1143}
1144
1145
1146PRBool PyXPCOM_InterfaceVariantHelper::FillArray()
1147{
1148 int param_index = 0;
1149 int i;
1150 for (i=0;i<m_num_array;i++) {
1151 PythonTypeDescriptor &ptd = m_python_type_desc_array[i];
1152 // stash the type_flags into the variant, and remember how many extra bits of info we have.
1153 m_var_array[i].type = ptd.type_flags;
1154 if (XPT_PD_IS_IN(ptd.param_flags) && !ptd.is_auto_in && !XPT_PD_IS_DIPPER(ptd.param_flags)) {
1155 if (!FillInVariant(ptd, i, param_index))
1156 return PR_FALSE;
1157 param_index++;
1158 }
1159 if ((XPT_PD_IS_OUT(ptd.param_flags) && !ptd.is_auto_out) || XPT_PD_IS_DIPPER(ptd.param_flags)) {
1160 if (!PrepareOutVariant(ptd, i))
1161 return PR_FALSE;
1162 }
1163 }
1164 // There may be out "size_is" params we havent touched yet
1165 // (ie, as the param itself is marked "out", we never got to
1166 // touch the associated "size_is".
1167 // Final loop to handle this.
1168 for (i=0;i<m_num_array;i++) {
1169 PythonTypeDescriptor &ptd = m_python_type_desc_array[i];
1170 if (ptd.is_auto_out && !ptd.have_set_auto) {
1171 // Call PrepareOutVariant to ensure buffers etc setup.
1172 if (!PrepareOutVariant(ptd, i))
1173 return PR_FALSE;
1174 }
1175 }
1176 return PR_TRUE;
1177}
1178
1179
1180PRBool PyXPCOM_InterfaceVariantHelper::SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size)
1181{
1182 NS_ABORT_IF_FALSE(var_index < m_num_array, "var_index param is invalid");
1183 PRUint8 argnum = is_arg1 ?
1184 m_python_type_desc_array[var_index].argnum :
1185 m_python_type_desc_array[var_index].argnum2;
1186 NS_ABORT_IF_FALSE(argnum < m_num_array, "size_is param is invalid");
1187 PythonTypeDescriptor &td_size = m_python_type_desc_array[argnum];
1188 NS_ABORT_IF_FALSE(td_size.is_auto_in || td_size.is_auto_out, "Setting size_is, but param is not marked as auto!");
1189 NS_ABORT_IF_FALSE( (td_size.type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32");
1190 nsXPTCVariant &ns_v = m_var_array[argnum];
1191
1192 if (!td_size.have_set_auto) {
1193 ns_v.type = td_size.type_flags;
1194 ns_v.val.u32 = new_size;
1195 // In case it is "out", setup the necessary pointers.
1196 PrepareOutVariant(td_size, argnum);
1197 td_size.have_set_auto = PR_TRUE;
1198 } else {
1199 if (ns_v.val.u32 != new_size) {
1200 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);
1201 return PR_FALSE;
1202 }
1203 }
1204 return PR_TRUE;
1205}
1206
1207PRUint32 PyXPCOM_InterfaceVariantHelper::GetSizeIs( int var_index, PRBool is_arg1)
1208{
1209 NS_ABORT_IF_FALSE(var_index < m_num_array, "var_index param is invalid");
1210 PRUint8 argnum = is_arg1 ?
1211 m_python_type_desc_array[var_index].argnum :
1212 m_python_type_desc_array[var_index].argnum2;
1213 NS_ABORT_IF_FALSE(argnum < m_num_array, "size_is param is invalid");
1214 NS_ABORT_IF_FALSE( (m_python_type_desc_array[argnum].type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32");
1215 PRBool is_out = XPT_PD_IS_OUT(m_python_type_desc_array[argnum].param_flags);
1216 nsXPTCVariant &ns_v = m_var_array[argnum];
1217 return is_out ? *((PRUint32 *)ns_v.ptr) : ns_v.val.u32;
1218}
1219
1220#define MAKE_VALUE_BUFFER(size) \
1221 if ((this_buffer_pointer = (void *)nsMemory::Alloc((size))) == nsnull) { \
1222 PyErr_NoMemory(); \
1223 BREAK_FALSE; \
1224 }
1225
1226PRBool PyXPCOM_InterfaceVariantHelper::FillInVariant(const PythonTypeDescriptor &td, int value_index, int param_index)
1227{
1228 PRBool rc = PR_TRUE;
1229 // Get a reference to the variant we are filling for convenience.
1230 nsXPTCVariant &ns_v = m_var_array[value_index];
1231 NS_ABORT_IF_FALSE(ns_v.type == td.type_flags, "Expecting variant all setup for us");
1232
1233 // We used to avoid passing internal buffers to PyString etc objects
1234 // for 2 reasons: paranoia (so incorrect external components couldn't break
1235 // Python) and simplicity (in vs in-out issues, etc)
1236 // However, at least one C++ implemented component (nsITimelineService)
1237 // uses a "char *", and keys on the address (assuming that the same
1238 // *pointer* is passed rather than value. Therefore, we have a special case
1239 // - T_CHAR_STR that is "in" gets the Python string pointer passed.
1240 void *&this_buffer_pointer = m_buffer_array[value_index]; // Freed at object destruction with PyMem_Free()
1241 NS_ABORT_IF_FALSE(this_buffer_pointer==nsnull, "We appear to already have a buffer");
1242 int cb_this_buffer_pointer = 0;
1243 if (XPT_PD_IS_IN(td.param_flags)) {
1244 NS_ABORT_IF_FALSE(!td.is_auto_in, "Param is 'auto-in', but we are filling it normally!");
1245 PyObject *val_use = NULL; // a temp object converters can use, and will be DECREF'd
1246 PyObject *val = PySequence_GetItem(m_pyparams, param_index);
1247 NS_WARN_IF_FALSE(val, "Have an 'in' param, but no Python value!");
1248 if (val==NULL) {
1249 PyErr_Format(PyExc_ValueError, "Param %d is marked as 'in', but no value was given", value_index);
1250 return PR_FALSE;
1251 }
1252 switch (XPT_TDP_TAG(ns_v.type)) {
1253 case nsXPTType::T_I8:
1254 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1255 ns_v.val.i8 = (PRInt8)PyInt_AsLong(val_use);
1256 break;
1257 case nsXPTType::T_I16:
1258 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1259 ns_v.val.i16 = (PRInt16)PyInt_AsLong(val_use);
1260 break;
1261 case nsXPTType::T_I32:
1262 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1263 ns_v.val.i32 = (PRInt32)PyInt_AsLong(val_use);
1264 break;
1265 case nsXPTType::T_I64:
1266 if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE
1267 ns_v.val.i64 = (PRInt64)PyLong_AsLongLong(val_use);
1268 break;
1269 case nsXPTType::T_U8:
1270 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1271 ns_v.val.u8 = (PRUint8)PyInt_AsLong(val_use);
1272 break;
1273 case nsXPTType::T_U16:
1274 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1275 ns_v.val.u16 = (PRUint16)PyInt_AsLong(val_use);
1276 break;
1277 case nsXPTType::T_U32:
1278 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1279 ns_v.val.u32 = (PRUint32)PyInt_AsLong(val_use);
1280 break;
1281 case nsXPTType::T_U64:
1282 if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE
1283 ns_v.val.u64 = (PRUint64)PyLong_AsUnsignedLongLong(val_use);
1284 break;
1285 case nsXPTType::T_FLOAT:
1286 if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
1287 ns_v.val.f = (float)PyFloat_AsDouble(val_use);
1288 break;
1289 case nsXPTType::T_DOUBLE:
1290 if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
1291 ns_v.val.d = PyFloat_AsDouble(val_use);
1292 break;
1293 case nsXPTType::T_BOOL:
1294 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1295 ns_v.val.b = (PRBool)PyInt_AsLong(val_use);
1296 break;
1297 case nsXPTType::T_CHAR:{
1298 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
1299 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
1300 BREAK_FALSE;
1301 }
1302 if ((val_use = PyObject_Str(val))==NULL)
1303 BREAK_FALSE;
1304 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
1305 NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
1306 if (PyString_GET_SIZE(val_use) != 1) {
1307 PyErr_SetString(PyExc_ValueError, "Must specify a one character string for a character");
1308 BREAK_FALSE;
1309 }
1310
1311 ns_v.val.c = *PyString_AS_STRING(val_use);
1312 break;
1313 }
1314
1315 case nsXPTType::T_WCHAR: {
1316 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
1317 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
1318 BREAK_FALSE;
1319 }
1320 if ((val_use = PyUnicode_FromObject(val))==NULL)
1321 BREAK_FALSE;
1322 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
1323 NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a unicode object!");
1324 if (PyUnicode_GetSize(val_use) != 1) {
1325 PyErr_SetString(PyExc_ValueError, "Must specify a one character string for a character");
1326 BREAK_FALSE;
1327 }
1328 // Lossy!
1329 ns_v.val.wc = *PyUnicode_AS_UNICODE(val_use);
1330 break;
1331 }
1332 // case nsXPTType::T_VOID: /* fall through */
1333 case nsXPTType::T_IID:
1334 nsIID iid;
1335 MAKE_VALUE_BUFFER(sizeof(nsIID));
1336 if (!Py_nsIID::IIDFromPyObject(val, &iid))
1337 BREAK_FALSE;
1338 memcpy(this_buffer_pointer, &iid, sizeof(iid));
1339 ns_v.val.p = this_buffer_pointer;
1340 break;
1341 case nsXPTType::T_ASTRING:
1342 case nsXPTType::T_DOMSTRING: {
1343 nsString *s = new nsString();
1344 if (!s) {
1345 PyErr_NoMemory();
1346 BREAK_FALSE;
1347 }
1348 ns_v.val.p = s;
1349 // We created it - flag as such for cleanup.
1350 ns_v.flags |= nsXPTCVariant::VAL_IS_DOMSTR;
1351
1352 if (!PyObject_AsNSString(val, *s))
1353 BREAK_FALSE;
1354 break;
1355 }
1356 case nsXPTType::T_CSTRING:
1357 case nsXPTType::T_UTF8STRING: {
1358 PRBool bIsUTF8 = XPT_TDP_TAG(ns_v.type) == nsXPTType::T_UTF8STRING;
1359 if (val==Py_None) {
1360 ns_v.val.p = new nsCString();
1361 } else {
1362 // strings are assumed to already be UTF8 encoded.
1363 if (PyString_Check(val)) {
1364 val_use = val;
1365 Py_INCREF(val);
1366 // Unicode objects are encoded by us.
1367 } else if (PyUnicode_Check(val)) {
1368 if (bIsUTF8)
1369 val_use = PyUnicode_AsUTF8String(val);
1370 else
1371 val_use = PyObject_Str(val);
1372 } else {
1373 PyErr_SetString(PyExc_TypeError, "UTF8 parameters must be string or Unicode objects");
1374 BREAK_FALSE;
1375 }
1376 if (!val_use)
1377 BREAK_FALSE;
1378 ns_v.val.p = new nsCString(PyString_AS_STRING(val_use),
1379 PyString_GET_SIZE(val_use));
1380 }
1381
1382 if (!ns_v.val.p) {
1383 PyErr_NoMemory();
1384 BREAK_FALSE;
1385 }
1386 // We created it - flag as such for cleanup.
1387 ns_v.flags |= bIsUTF8 ? nsXPTCVariant::VAL_IS_UTF8STR : nsXPTCVariant::VAL_IS_CSTR;
1388 break;
1389 }
1390 case nsXPTType::T_CHAR_STR: {
1391 if (val==Py_None) {
1392 ns_v.val.p = nsnull;
1393 break;
1394 }
1395 // If an "in" char *, and we have a PyString, then pass the
1396 // pointer (hoping everyone else plays by the rules too.
1397 if (!XPT_PD_IS_OUT(td.param_flags) && PyString_Check(val)) {
1398 ns_v.val.p = PyString_AS_STRING(val);
1399 break;
1400 }
1401
1402 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
1403 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
1404 BREAK_FALSE;
1405 }
1406 if ((val_use = PyObject_Str(val))==NULL)
1407 BREAK_FALSE;
1408 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
1409 NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
1410
1411 cb_this_buffer_pointer = PyString_GET_SIZE(val_use)+1;
1412 MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
1413 memcpy(this_buffer_pointer, PyString_AS_STRING(val_use), cb_this_buffer_pointer);
1414 ns_v.val.p = this_buffer_pointer;
1415 break;
1416 }
1417
1418 case nsXPTType::T_WCHAR_STR: {
1419 if (val==Py_None) {
1420 ns_v.val.p = nsnull;
1421 break;
1422 }
1423 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
1424 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
1425 BREAK_FALSE;
1426 }
1427 if ((val_use = PyUnicode_FromObject(val))==NULL)
1428 BREAK_FALSE;
1429 NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!");
1430 PRUnichar *sv;
1431 PRUint32 nch;
1432 if (PyUnicode_AsPRUnichar(val_use, &sv, &nch) < 0)
1433 BREAK_FALSE;
1434 cb_this_buffer_pointer = (nch + 1) * sizeof(PRUnichar);
1435 this_buffer_pointer = sv;
1436 ns_v.val.p = this_buffer_pointer;
1437 break;
1438 }
1439 case nsXPTType::T_INTERFACE: {
1440 nsIID iid;
1441 if (!Py_nsIID::IIDFromPyObject(td.extra, &iid))
1442 BREAK_FALSE;
1443 if (!Py_nsISupports::InterfaceFromPyObject(
1444 val,
1445 iid,
1446 (nsISupports **)&ns_v.val.p,
1447 PR_TRUE))
1448 BREAK_FALSE;
1449 // We have added a reference - flag as such for cleanup.
1450 ns_v.flags |= nsXPTCVariant::VAL_IS_IFACE;
1451 break;
1452 }
1453 case nsXPTType::T_INTERFACE_IS: {
1454 nsIID iid;
1455 nsXPTCVariant &ns_viid = m_var_array[td.argnum];
1456 NS_WARN_IF_FALSE(XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID, "The INTERFACE_IS iid describer isnt an IID!");
1457 // This is a pretty serious problem, but not Python's fault!
1458 // Just return an nsISupports and hope the caller does whatever
1459 // QI they need before using it.
1460 if (XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID &&
1461 XPT_PD_IS_IN(ns_viid.type)) {
1462 nsIID *piid = (nsIID *)ns_viid.val.p;
1463 if (piid==NULL)
1464 // Also serious, but like below, not our fault!
1465 iid = NS_GET_IID(nsISupports);
1466 else
1467 iid = *piid;
1468 } else
1469 // Use NULL IID to avoid a QI in this case.
1470 iid = Py_nsIID_NULL;
1471 if (!Py_nsISupports::InterfaceFromPyObject(
1472 val,
1473 iid,
1474 (nsISupports **)&ns_v.val.p,
1475 PR_TRUE))
1476 BREAK_FALSE;
1477 // We have added a reference - flag as such for cleanup.
1478 ns_v.flags |= nsXPTCVariant::VAL_IS_IFACE;
1479 break;
1480 }
1481 case nsXPTType::T_PSTRING_SIZE_IS: {
1482 if (val==Py_None) {
1483 ns_v.val.p = nsnull;
1484 break;
1485 }
1486 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
1487 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
1488 BREAK_FALSE;
1489 }
1490 if ((val_use = PyObject_Str(val))==NULL)
1491 BREAK_FALSE;
1492 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
1493 NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
1494
1495 cb_this_buffer_pointer = PyString_GET_SIZE(val_use);
1496 MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
1497 memcpy(this_buffer_pointer, PyString_AS_STRING(val_use), cb_this_buffer_pointer);
1498 ns_v.val.p = this_buffer_pointer;
1499 rc = SetSizeIs(value_index, PR_TRUE, cb_this_buffer_pointer);
1500 break;
1501 }
1502
1503 case nsXPTType::T_PWSTRING_SIZE_IS: {
1504 if (val==Py_None) {
1505 ns_v.val.p = nsnull;
1506 break;
1507 }
1508 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
1509 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
1510 BREAK_FALSE;
1511 }
1512 if ((val_use = PyUnicode_FromObject(val))==NULL)
1513 BREAK_FALSE;
1514 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
1515 NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyObject_Unicode didnt return a unicode object!");
1516 PRUnichar *sv;
1517 PRUint32 nch;
1518 if (PyUnicode_AsPRUnichar(val_use, &sv, &nch) < 0)
1519 BREAK_FALSE;
1520 cb_this_buffer_pointer = (nch + 1) * sizeof(PRUnichar);
1521 this_buffer_pointer = sv;
1522 ns_v.val.p = this_buffer_pointer;
1523 rc = SetSizeIs(value_index, PR_TRUE, nch);
1524 break;
1525 }
1526 case nsXPTType::T_ARRAY: {
1527 if (val==Py_None) {
1528 ns_v.val.p = nsnull;
1529 break;
1530 }
1531 if (!PyInt_Check(td.extra)) {
1532 PyErr_SetString(PyExc_TypeError, "The array info is not valid");
1533 BREAK_FALSE;
1534 }
1535 if (!PySequence_Check(val)) {
1536 PyErr_SetString(PyExc_TypeError, "This parameter must be a sequence");
1537 BREAK_FALSE;
1538 }
1539 int array_type = PyInt_AsLong(td.extra);
1540 PRUint32 element_size = GetArrayElementSize(array_type);
1541 int seq_length = PySequence_Length(val);
1542 cb_this_buffer_pointer = seq_length * element_size;
1543 if (cb_this_buffer_pointer==0)
1544 // prevent assertions allocing zero bytes. Can't use NULL.
1545 cb_this_buffer_pointer = 1;
1546 MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
1547 memset(this_buffer_pointer, 0, cb_this_buffer_pointer);
1548 rc = FillSingleArray(this_buffer_pointer, val, seq_length, element_size, array_type&XPT_TDP_TAGMASK, nsnull);
1549 if (!rc) break;
1550 rc = SetSizeIs(value_index, PR_FALSE, seq_length);
1551 if (!rc) break;
1552 ns_v.flags |= nsXPTCVariant::VAL_IS_ARRAY;
1553 ns_v.val.p = this_buffer_pointer;
1554 break;
1555 }
1556 default:
1557 PyErr_Format(PyExc_TypeError, "The object type (0x%x) is unknown", XPT_TDP_TAG(ns_v.type));
1558 rc = PR_FALSE;
1559 break;
1560 }
1561 Py_DECREF(val); // Cant be NULL!
1562 Py_XDECREF(val_use);
1563 }
1564 return rc && !PyErr_Occurred();
1565}
1566
1567PRBool PyXPCOM_InterfaceVariantHelper::PrepareOutVariant(const PythonTypeDescriptor &td, int value_index)
1568{
1569 PRBool rc = PR_TRUE;
1570 nsXPTCVariant &ns_v = m_var_array[value_index];
1571 void *&this_buffer_pointer = m_buffer_array[value_index]; // Freed at object destruction with PyMem_Free()
1572 // Do the out param thang...
1573 if (XPT_PD_IS_OUT(td.param_flags) || XPT_PD_IS_DIPPER(td.param_flags)) {
1574 NS_ABORT_IF_FALSE(ns_v.ptr == NULL, "already have a pointer!");
1575 ns_v.ptr = &ns_v;
1576 ns_v.flags |= nsXPTCVariant::PTR_IS_DATA;
1577
1578 // Special flags based on the data type
1579 switch (XPT_TDP_TAG(ns_v.type)) {
1580 case nsXPTType::T_I8:
1581 case nsXPTType::T_I16:
1582 case nsXPTType::T_I32:
1583 case nsXPTType::T_I64:
1584 case nsXPTType::T_U8:
1585 case nsXPTType::T_U16:
1586 case nsXPTType::T_U32:
1587 case nsXPTType::T_U64:
1588 case nsXPTType::T_FLOAT:
1589 case nsXPTType::T_DOUBLE:
1590 case nsXPTType::T_BOOL:
1591 case nsXPTType::T_CHAR:
1592 case nsXPTType::T_WCHAR:
1593 case nsXPTType::T_VOID:
1594 break;
1595
1596 case nsXPTType::T_INTERFACE:
1597 case nsXPTType::T_INTERFACE_IS:
1598 NS_ABORT_IF_FALSE(this_buffer_pointer==NULL, "Can't have an interface and a buffer pointer!");
1599 ns_v.flags |= nsXPTCVariant::VAL_IS_IFACE;
1600 ns_v.flags |= nsXPTCVariant::VAL_IS_ALLOCD;
1601 break;
1602 case nsXPTType::T_ARRAY:
1603 ns_v.flags |= nsXPTCVariant::VAL_IS_ARRAY;
1604 ns_v.flags |= nsXPTCVariant::VAL_IS_ALLOCD;
1605 // Even if ns_val.p already setup as part of "in" processing,
1606 // we need to ensure setup for out.
1607 NS_ABORT_IF_FALSE(ns_v.val.p==nsnull || ns_v.val.p==this_buffer_pointer, "Garbage in our pointer?");
1608 ns_v.val.p = this_buffer_pointer;
1609 this_buffer_pointer = nsnull;
1610 break;
1611 case nsXPTType::T_PWSTRING_SIZE_IS:
1612 case nsXPTType::T_PSTRING_SIZE_IS:
1613 case nsXPTType::T_WCHAR_STR:
1614 case nsXPTType::T_CHAR_STR:
1615 case nsXPTType::T_IID:
1616 // If we stashed a value in the this_buffer_pointer, and
1617 // we are passing it as an OUT param, we do _not_ want to
1618 // treat it as a temporary buffer.
1619 // For example, if we pass an IID or string as an IN param,
1620 // we allocate a buffer for the value, but this is NOT cleaned up
1621 // via normal VARIANT cleanup rules - hence we clean it up ourselves.
1622 // If the param is IN/OUT, then the buffer falls under the normal variant
1623 // rules (ie, is flagged as VAL_IS_ALLOCD), so we dont clean it as a temporary.
1624 // (it may have been changed under us - we free the _new_ value.
1625 // Even if ns_val.p already setup as part of "in" processing,
1626 // we need to ensure setup for out.
1627 NS_ABORT_IF_FALSE(ns_v.val.p==nsnull || ns_v.val.p==this_buffer_pointer, "Garbage in our pointer?");
1628 ns_v.val.p = this_buffer_pointer;
1629 ns_v.flags |= nsXPTCVariant::VAL_IS_ALLOCD;
1630 this_buffer_pointer = nsnull;
1631 break;
1632 case nsXPTType::T_DOMSTRING:
1633 case nsXPTType::T_ASTRING: {
1634 NS_ABORT_IF_FALSE(ns_v.val.p==nsnull, "T_DOMTSTRINGS cant be out and have a value (ie, no in/outs are allowed!");
1635 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!");
1636 ns_v.flags |= nsXPTCVariant::VAL_IS_DOMSTR;
1637 // Dippers are really treated like "in" params.
1638 ns_v.ptr = new nsString();
1639 ns_v.val.p = ns_v.ptr; // VAL_IS_* says the .p is what gets freed
1640 if (!ns_v.ptr) {
1641 PyErr_NoMemory();
1642 rc = PR_FALSE;
1643 }
1644 break;
1645 }
1646 case nsXPTType::T_CSTRING:
1647 case nsXPTType::T_UTF8STRING: {
1648 NS_ABORT_IF_FALSE(ns_v.val.p==nsnull, "T_DOMTSTRINGS cant be out and have a value (ie, no in/outs are allowed!");
1649 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!");
1650 ns_v.flags |= ( XPT_TDP_TAG(ns_v.type)==nsXPTType::T_CSTRING ? nsXPTCVariant::VAL_IS_CSTR : nsXPTCVariant::VAL_IS_UTF8STR);
1651 ns_v.ptr = new nsCString();
1652 ns_v.val.p = ns_v.ptr; // VAL_IS_* says the .p is what gets freed
1653 if (!ns_v.ptr) {
1654 PyErr_NoMemory();
1655 rc = PR_FALSE;
1656 }
1657 break;
1658 }
1659 default:
1660 NS_ABORT_IF_FALSE(0, "Unknown type - don't know how to prepare the output value");
1661 break; // Nothing to do!
1662 }
1663 }
1664 return rc;
1665}
1666
1667
1668PyObject *PyXPCOM_InterfaceVariantHelper::MakeSinglePythonResult(int index)
1669{
1670 nsXPTCVariant &ns_v = m_var_array[index];
1671 PyObject *ret = nsnull;
1672 NS_ABORT_IF_FALSE(ns_v.IsPtrData() || ns_v.IsValDOMString(), "expecting a pointer if you want a result!");
1673
1674 // Re-fetch the type descriptor.
1675 PythonTypeDescriptor &td = m_python_type_desc_array[index];
1676 // Make sure the type tag of the variant hasnt changed on us.
1677 NS_ABORT_IF_FALSE(ns_v.type==td.type_flags, "variant type has changed under us!");
1678
1679 // If the pointer is NULL, we can get out now!
1680 if (ns_v.ptr==nsnull) {
1681 Py_INCREF(Py_None);
1682 return Py_None;
1683 }
1684
1685 switch (XPT_TDP_TAG(ns_v.type)) {
1686 case nsXPTType::T_I8:
1687 ret = PyInt_FromLong( *((PRInt8 *)ns_v.ptr) );
1688 break;
1689 case nsXPTType::T_I16:
1690 ret = PyInt_FromLong( *((PRInt16 *)ns_v.ptr) );
1691 break;
1692 case nsXPTType::T_I32:
1693 ret = PyInt_FromLong( *((PRInt32 *)ns_v.ptr) );
1694 break;
1695 case nsXPTType::T_I64:
1696 ret = PyLong_FromLongLong( *((PRInt64 *)ns_v.ptr) );
1697 break;
1698 case nsXPTType::T_U8:
1699 ret = PyInt_FromLong( *((PRUint8 *)ns_v.ptr) );
1700 break;
1701 case nsXPTType::T_U16:
1702 ret = PyInt_FromLong( *((PRUint16 *)ns_v.ptr) );
1703 break;
1704 case nsXPTType::T_U32:
1705 ret = PyInt_FromLong( *((PRUint32 *)ns_v.ptr) );
1706 break;
1707 case nsXPTType::T_U64:
1708 ret = PyLong_FromUnsignedLongLong( *((PRUint64 *)ns_v.ptr) );
1709 break;
1710 case nsXPTType::T_FLOAT:
1711 ret = PyFloat_FromDouble( *((float *)ns_v.ptr) );
1712 break;
1713 case nsXPTType::T_DOUBLE:
1714 ret = PyFloat_FromDouble( *((double *)ns_v.ptr) );
1715 break;
1716 case nsXPTType::T_BOOL:
1717 ret = *((PRBool *)ns_v.ptr) ? Py_True : Py_False;
1718 Py_INCREF(ret);
1719 break;
1720 case nsXPTType::T_CHAR:
1721 ret = PyString_FromStringAndSize( ((char *)ns_v.ptr), 1 );
1722 break;
1723
1724 case nsXPTType::T_WCHAR:
1725 ret = PyUnicode_FromPRUnichar( ((PRUnichar *)ns_v.ptr), 1 );
1726 break;
1727// case nsXPTType::T_VOID:
1728 case nsXPTType::T_IID:
1729 ret = Py_nsIID::PyObjectFromIID( **((nsIID **)ns_v.ptr) );
1730 break;
1731 case nsXPTType::T_ASTRING:
1732 case nsXPTType::T_DOMSTRING: {
1733 nsAString *rs = (nsAString *)ns_v.ptr;
1734 ret = PyObject_FromNSString(*rs);
1735 break;
1736 }
1737 case nsXPTType::T_UTF8STRING:
1738 case nsXPTType::T_CSTRING: {
1739 nsCString *rs = (nsCString *)ns_v.ptr;
1740 ret = PyObject_FromNSString(*rs, XPT_TDP_TAG(ns_v.type)==nsXPTType::T_UTF8STRING);
1741 break;
1742 }
1743
1744 case nsXPTType::T_CHAR_STR:
1745 if (*((char **)ns_v.ptr) == NULL) {
1746 ret = Py_None;
1747 Py_INCREF(Py_None);
1748 } else
1749 ret = PyString_FromString( *((char **)ns_v.ptr) );
1750 break;
1751
1752 case nsXPTType::T_WCHAR_STR: {
1753 PRUnichar *us = *((PRUnichar **)ns_v.ptr);
1754 if (us == NULL) {
1755 ret = Py_None;
1756 Py_INCREF(Py_None);
1757 } else {
1758 ret = PyUnicode_FromPRUnichar( us, nsCRT::strlen(us));
1759 }
1760 break;
1761 }
1762 case nsXPTType::T_INTERFACE: {
1763 nsIID iid;
1764 if (!Py_nsIID::IIDFromPyObject(td.extra, &iid))
1765 break;
1766 nsISupports *iret = *((nsISupports **)ns_v.ptr);
1767 // Our cleanup code manages iret reference ownership, and our
1768 // new object takes its own.
1769 if (iid.Equals(NS_GET_IID(nsIVariant)))
1770 ret = PyObject_FromVariant(m_parent, (nsIVariant *)iret);
1771 else
1772 ret = m_parent->MakeInterfaceResult(iret, iid);
1773 break;
1774 }
1775 case nsXPTType::T_INTERFACE_IS: {
1776 nsIID iid;
1777 nsXPTCVariant &ns_viid = m_var_array[td.argnum];
1778 NS_WARN_IF_FALSE(XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID, "The INTERFACE_IS iid describer isnt an IID!");
1779 if (XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID) {
1780 nsIID *piid = (nsIID *)ns_viid.val.p;
1781 if (piid==NULL)
1782 // Also serious, but like below, not our fault!
1783 iid = NS_GET_IID(nsISupports);
1784 else
1785 iid = *piid;
1786 } else {
1787 // This is a pretty serious problem, but not Python's fault!
1788 // Just return an nsISupports and hope the caller does whatever
1789 // QI they need before using it.
1790 NS_ERROR("Failed to get the IID for T_INTERFACE_IS!");
1791 iid = NS_GET_IID(nsISupports);
1792 }
1793 nsISupports *iret = *((nsISupports **)ns_v.ptr);
1794 if (iid.Equals(NS_GET_IID(nsIVariant)))
1795 ret = PyObject_FromVariant(m_parent, (nsIVariant *)iret);
1796 else
1797 ret = m_parent->MakeInterfaceResult(iret, iid);
1798 break;
1799 }
1800 case nsXPTType::T_ARRAY: {
1801 if ( (* ((void **)ns_v.ptr)) == NULL) {
1802 ret = Py_None;
1803 Py_INCREF(Py_None);
1804 }
1805 if (!PyInt_Check(td.extra)) {
1806 PyErr_SetString(PyExc_TypeError, "The array info is not valid");
1807 break;
1808 }
1809 PRUint8 array_type = (PRUint8)PyInt_AsLong(td.extra);
1810 PRUint32 seq_size = GetSizeIs(index, PR_FALSE);
1811 nsXPTCVariant &ns_viid = m_var_array[td.argnum];
1812 nsIID iid;
1813 nsresult res = GetArrayElementIID(m_parent,
1814 m_var_array,
1815 m_methodindex,
1816 index,
1817 &iid);
1818 ret = UnpackSingleArray(m_parent, * ((void **)ns_v.ptr),
1819 seq_size, array_type&XPT_TDP_TAGMASK,
1820 NS_SUCCEEDED(res) ? &iid : NULL);
1821 break;
1822 }
1823
1824 case nsXPTType::T_PSTRING_SIZE_IS:
1825 if (*((char **)ns_v.ptr) == NULL) {
1826 ret = Py_None;
1827 Py_INCREF(Py_None);
1828 } else {
1829 PRUint32 string_size = GetSizeIs(index, PR_TRUE);
1830 ret = PyString_FromStringAndSize( *((char **)ns_v.ptr), string_size );
1831 }
1832 break;
1833
1834 case nsXPTType::T_PWSTRING_SIZE_IS:
1835 if (*((PRUnichar **)ns_v.ptr) == NULL) {
1836 ret = Py_None;
1837 Py_INCREF(Py_None);
1838 } else {
1839 PRUint32 string_size = GetSizeIs(index, PR_TRUE);
1840 ret = PyUnicode_FromPRUnichar( *((PRUnichar **)ns_v.ptr), string_size );
1841 }
1842 break;
1843 default:
1844 PyErr_Format(PyExc_ValueError, "Unknown XPCOM type code (0x%x)", XPT_TDP_TAG(ns_v.type));
1845 /* ret remains nsnull */
1846 break;
1847 }
1848 return ret;
1849}
1850
1851
1852PyObject *PyXPCOM_InterfaceVariantHelper::MakePythonResult()
1853{
1854 // First we count the results.
1855 int i = 0;
1856 int n_results = 0;
1857 PyObject *ret = NULL;
1858 PRBool have_retval = PR_FALSE;
1859 for (i=0;i<m_num_array;i++) {
1860 PythonTypeDescriptor &td = m_python_type_desc_array[i];
1861 if (!td.is_auto_out) {
1862 if (XPT_PD_IS_OUT(td.param_flags) || XPT_PD_IS_DIPPER(td.param_flags))
1863 n_results++;
1864 if (XPT_PD_IS_RETVAL(td.param_flags))
1865 have_retval = PR_TRUE;
1866 }
1867 }
1868 if (n_results==0) {
1869 ret = Py_None;
1870 Py_INCREF(ret);
1871 } else {
1872 if (n_results > 1) {
1873 ret = PyTuple_New(n_results);
1874 if (ret==NULL)
1875 return NULL;
1876 }
1877 int ret_index = 0;
1878 int max_index = m_num_array;
1879 // Stick the retval at the front if we have have
1880 if (have_retval && n_results > 1) {
1881 PyObject *val = MakeSinglePythonResult(m_num_array-1);
1882 if (val==NULL) {
1883 Py_DECREF(ret);
1884 return NULL;
1885 }
1886 PyTuple_SET_ITEM(ret, 0, val);
1887 max_index--;
1888 ret_index++;
1889
1890 }
1891 for (i=0;ret_index < n_results && i < max_index;i++) {
1892 if (!m_python_type_desc_array[i].is_auto_out) {
1893 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)) {
1894 PyObject *val = MakeSinglePythonResult(i);
1895 if (val==NULL) {
1896 Py_XDECREF(ret);
1897 return NULL;
1898 }
1899 if (n_results > 1) {
1900 PyTuple_SET_ITEM(ret, ret_index, val);
1901 ret_index++;
1902 } else {
1903 NS_ABORT_IF_FALSE(ret==NULL, "shouldnt already have a ret!");
1904 ret = val;
1905 }
1906 }
1907 }
1908 }
1909
1910 }
1911 return ret;
1912}
1913
1914/*************************************************************************
1915**************************************************************************
1916
1917 Helpers when IMPLEMENTING interfaces.
1918
1919**************************************************************************
1920*************************************************************************/
1921
1922PyXPCOM_GatewayVariantHelper::PyXPCOM_GatewayVariantHelper( PyG_Base *gw, int method_index, const nsXPTMethodInfo *info, nsXPTCMiniVariant* params )
1923{
1924 m_params = params;
1925 m_info = info;
1926 // no references added - this class is only alive for
1927 // a single gateway invocation
1928 m_gateway = gw;
1929 m_method_index = method_index;
1930 m_python_type_desc_array = NULL;
1931 m_num_type_descs = 0;
1932}
1933
1934PyXPCOM_GatewayVariantHelper::~PyXPCOM_GatewayVariantHelper()
1935{
1936 delete [] m_python_type_desc_array;
1937}
1938
1939PyObject *PyXPCOM_GatewayVariantHelper::MakePyArgs()
1940{
1941 NS_PRECONDITION(sizeof(XPTParamDescriptor) == sizeof(nsXPTParamInfo), "We depend on nsXPTParamInfo being a wrapper over the XPTParamDescriptor struct");
1942 // Setup our array of Python typedescs, and determine the number of objects we
1943 // pass to Python.
1944 m_num_type_descs = m_info->num_args;
1945 m_python_type_desc_array = new PythonTypeDescriptor[m_num_type_descs];
1946 if (m_python_type_desc_array==nsnull)
1947 return PyErr_NoMemory();
1948
1949 // First loop to count the number of objects
1950 // we pass to Python
1951 int i;
1952 for (i=0;i<m_info->num_args;i++) {
1953 nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+i;
1954 PythonTypeDescriptor &td = m_python_type_desc_array[i];
1955 td.param_flags = pi->flags;
1956 td.type_flags = pi->type.prefix.flags;
1957 td.argnum = pi->type.argnum;
1958 td.argnum2 = pi->type.argnum2;
1959 }
1960 int num_args = ProcessPythonTypeDescriptors(m_python_type_desc_array, m_num_type_descs);
1961 PyObject *ret = PyTuple_New(num_args);
1962 if (ret==NULL)
1963 return NULL;
1964 int this_arg = 0;
1965 for (i=0;i<m_num_type_descs;i++) {
1966 PythonTypeDescriptor &td = m_python_type_desc_array[i];
1967 if (XPT_PD_IS_IN(td.param_flags) && !td.is_auto_in && !XPT_PD_IS_DIPPER(td.param_flags)) {
1968 PyObject *sub = MakeSingleParam( i, td );
1969 if (sub==NULL) {
1970 Py_DECREF(ret);
1971 return NULL;
1972 }
1973 NS_ABORT_IF_FALSE(this_arg>=0 && this_arg<num_args, "We are going off the end of the array!");
1974 PyTuple_SET_ITEM(ret, this_arg, sub);
1975 this_arg++;
1976 }
1977 }
1978 return ret;
1979}
1980
1981PRBool PyXPCOM_GatewayVariantHelper::CanSetSizeIs( int var_index, PRBool is_arg1 )
1982{
1983 NS_ABORT_IF_FALSE(var_index < m_num_type_descs, "var_index param is invalid");
1984 PRUint8 argnum = is_arg1 ?
1985 m_python_type_desc_array[var_index].argnum :
1986 m_python_type_desc_array[var_index].argnum2;
1987 NS_ABORT_IF_FALSE(argnum < m_num_type_descs, "size_is param is invalid");
1988 return XPT_PD_IS_OUT(m_python_type_desc_array[argnum].param_flags);
1989}
1990
1991PRBool PyXPCOM_GatewayVariantHelper::SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size)
1992{
1993 NS_ABORT_IF_FALSE(var_index < m_num_type_descs, "var_index param is invalid");
1994 PRUint8 argnum = is_arg1 ?
1995 m_python_type_desc_array[var_index].argnum :
1996 m_python_type_desc_array[var_index].argnum2;
1997 NS_ABORT_IF_FALSE(argnum < m_num_type_descs, "size_is param is invalid");
1998 PythonTypeDescriptor &td_size = m_python_type_desc_array[argnum];
1999 NS_ABORT_IF_FALSE( XPT_PD_IS_OUT(td_size.param_flags), "size param must be out if we want to set it!");
2000 NS_ABORT_IF_FALSE(td_size.is_auto_out, "Setting size_is, but param is not marked as auto!");
2001
2002 nsXPTCMiniVariant &ns_v = m_params[argnum];
2003 NS_ABORT_IF_FALSE( (td_size.type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32");
2004 NS_ABORT_IF_FALSE(ns_v.val.p, "NULL pointer for size_is value!");
2005 if (ns_v.val.p) {
2006 if (!td_size.have_set_auto) {
2007 *((PRUint32 *)ns_v.val.p) = new_size;
2008 td_size.have_set_auto = PR_TRUE;
2009 } else {
2010 if (*((PRUint32 *)ns_v.val.p) != new_size ) {
2011 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);
2012 return PR_FALSE;
2013 }
2014 }
2015 }
2016 return PR_TRUE;
2017}
2018
2019PRUint32 PyXPCOM_GatewayVariantHelper::GetSizeIs( int var_index, PRBool is_arg1)
2020{
2021 NS_ABORT_IF_FALSE(var_index < m_num_type_descs, "var_index param is invalid");
2022 PRUint8 argnum = is_arg1 ?
2023 m_python_type_desc_array[var_index].argnum :
2024 m_python_type_desc_array[var_index].argnum2;
2025 NS_ABORT_IF_FALSE(argnum < m_num_type_descs, "size_is param is invalid");
2026 if (argnum >= m_num_type_descs) {
2027 PyErr_SetString(PyExc_ValueError, "dont have a valid size_is indicator for this param");
2028 return PR_FALSE;
2029 }
2030 PRBool is_out = XPT_PD_IS_OUT(m_python_type_desc_array[argnum].param_flags);
2031 nsXPTCMiniVariant &ns_v = m_params[argnum];
2032 NS_ABORT_IF_FALSE( (m_python_type_desc_array[argnum].type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32");
2033 return is_out ? *((PRUint32 *)ns_v.val.p) : ns_v.val.u32;
2034}
2035
2036#undef DEREF_IN_OR_OUT
2037#define DEREF_IN_OR_OUT( element, ret_type ) (ret_type)(is_out ? *((ret_type *)ns_v.val.p) : (ret_type)(element))
2038
2039PyObject *PyXPCOM_GatewayVariantHelper::MakeSingleParam(int index, PythonTypeDescriptor &td)
2040{
2041 NS_PRECONDITION(XPT_PD_IS_IN(td.param_flags), "Must be an [in] param!");
2042 nsXPTCMiniVariant &ns_v = m_params[index];
2043 PyObject *ret = NULL;
2044 PRBool is_out = XPT_PD_IS_OUT(td.param_flags);
2045
2046 switch (td.type_flags & XPT_TDP_TAGMASK) {
2047 case nsXPTType::T_I8:
2048 ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.i8, PRInt8 ) );
2049 break;
2050 case nsXPTType::T_I16:
2051 ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.i16, PRInt16) );
2052 break;
2053 case nsXPTType::T_I32:
2054 ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.i32, PRInt32) );
2055 break;
2056 case nsXPTType::T_I64:
2057 ret = PyLong_FromLongLong( DEREF_IN_OR_OUT(ns_v.val.i64, PRInt64) );
2058 break;
2059 case nsXPTType::T_U8:
2060 ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.u8, PRUint8) );
2061 break;
2062 case nsXPTType::T_U16:
2063 ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.u16, PRUint16) );
2064 break;
2065 case nsXPTType::T_U32:
2066 ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.u32, PRUint32) );
2067 break;
2068 case nsXPTType::T_U64:
2069 ret = PyLong_FromUnsignedLongLong( DEREF_IN_OR_OUT(ns_v.val.u64, PRUint64) );
2070 break;
2071 case nsXPTType::T_FLOAT:
2072 ret = PyFloat_FromDouble( DEREF_IN_OR_OUT(ns_v.val.f, float) );
2073 break;
2074 case nsXPTType::T_DOUBLE:
2075 ret = PyFloat_FromDouble( DEREF_IN_OR_OUT(ns_v.val.d, double) );
2076 break;
2077 case nsXPTType::T_BOOL: {
2078 PRBool temp = DEREF_IN_OR_OUT(ns_v.val.b, PRBool);
2079 ret = temp ? Py_True : Py_False;
2080 Py_INCREF(ret);
2081 break;
2082 }
2083 case nsXPTType::T_CHAR: {
2084 char temp = DEREF_IN_OR_OUT(ns_v.val.c, char);
2085 ret = PyString_FromStringAndSize(&temp, 1);
2086 break;
2087 }
2088 case nsXPTType::T_WCHAR: {
2089 PRUnichar temp = (PRUnichar)DEREF_IN_OR_OUT(ns_v.val.wc, PRUnichar);
2090 ret = PyUnicode_FromPRUnichar(&temp, 1);
2091 break;
2092 }
2093// case nsXPTType::T_VOID:
2094 case nsXPTType::T_IID: {
2095 ret = Py_nsIID::PyObjectFromIID( * DEREF_IN_OR_OUT(ns_v.val.p, const nsIID *) );
2096 break;
2097 }
2098 case nsXPTType::T_ASTRING:
2099 case nsXPTType::T_DOMSTRING: {
2100 NS_ABORT_IF_FALSE(is_out || !XPT_PD_IS_DIPPER(td.param_flags), "DOMStrings can't be inout");
2101 const nsAString *rs = (const nsAString *)ns_v.val.p;
2102 ret = PyObject_FromNSString(*rs);
2103 break;
2104 }
2105 case nsXPTType::T_CSTRING:
2106 case nsXPTType::T_UTF8STRING: {
2107 NS_ABORT_IF_FALSE(is_out || !XPT_PD_IS_DIPPER(td.param_flags), "DOMStrings can't be inout");
2108 const nsCString *rs = (const nsCString *)ns_v.val.p;
2109 ret = PyObject_FromNSString(*rs, (td.type_flags & XPT_TDP_TAGMASK)==nsXPTType::T_UTF8STRING);
2110 break;
2111 }
2112 case nsXPTType::T_CHAR_STR: {
2113 char *t = DEREF_IN_OR_OUT(ns_v.val.p, char *);
2114 if (t==NULL) {
2115 ret = Py_None;
2116 Py_INCREF(Py_None);
2117 } else
2118 ret = PyString_FromString(t);
2119 break;
2120 }
2121
2122 case nsXPTType::T_WCHAR_STR: {
2123 PRUnichar *us = DEREF_IN_OR_OUT(ns_v.val.p, PRUnichar *);
2124 if (us==NULL) {
2125 ret = Py_None;
2126 Py_INCREF(Py_None);
2127 } else {
2128 ret = PyUnicode_FromPRUnichar( us, nsCRT::strlen(us));
2129 }
2130 break;
2131 }
2132 case nsXPTType::T_INTERFACE_IS: // our Python code does it :-)
2133 case nsXPTType::T_INTERFACE: {
2134 nsISupports *iret = DEREF_IN_OR_OUT(ns_v.val.p, nsISupports *);
2135 nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index;
2136 ret = m_gateway->MakeInterfaceParam(iret, NULL, m_method_index, pi, index);
2137 break;
2138 }
2139/***
2140 nsISupports *iret = DEREF_IN_OR_OUT(ns_v.val.p, nsISupports *);
2141 nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index;
2142 nsXPTCMiniVariant &ns_viid = m_params[td.argnum];
2143 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!");
2144 const nsIID * iid = NULL;
2145 if (XPT_PD_IS_IN(m_python_type_desc_array[td.argnum].param_flags))
2146 // may still be inout!
2147 iid = DEREF_IN_OR_OUT(ns_v.val.p, const nsIID *);
2148
2149 ret = m_gateway->MakeInterfaceParam(iret, iid, m_method_index, pi, index);
2150 break;
2151 }
2152****/
2153 case nsXPTType::T_ARRAY: {
2154 void *t = DEREF_IN_OR_OUT(ns_v.val.p, void *);
2155 if (t==NULL) {
2156 // JS may send us a NULL here occasionally - as the
2157 // type is array, we silently convert this to a zero
2158 // length list, a-la JS.
2159 ret = PyList_New(0);
2160 } else {
2161 PRUint8 array_type;
2162 nsIID *piid;
2163 nsresult ns = GetArrayType(index, &array_type, &piid);
2164 if (NS_FAILED(ns)) {
2165 PyXPCOM_BuildPyException(ns);
2166 break;
2167 }
2168 PRUint32 seq_size = GetSizeIs(index, PR_FALSE);
2169 ret = UnpackSingleArray(NULL, t, seq_size, array_type&XPT_TDP_TAGMASK, piid);
2170 }
2171 break;
2172 }
2173 case nsXPTType::T_PSTRING_SIZE_IS: {
2174 char *t = DEREF_IN_OR_OUT(ns_v.val.p, char *);
2175 PRUint32 string_size = GetSizeIs(index, PR_TRUE);
2176 if (t==NULL) {
2177 ret = Py_None;
2178 Py_INCREF(Py_None);
2179 } else
2180 ret = PyString_FromStringAndSize(t, string_size);
2181 break;
2182 }
2183 case nsXPTType::T_PWSTRING_SIZE_IS: {
2184 PRUnichar *t = DEREF_IN_OR_OUT(ns_v.val.p, PRUnichar *);
2185 PRUint32 string_size = GetSizeIs(index, PR_TRUE);
2186 if (t==NULL) {
2187 ret = Py_None;
2188 Py_INCREF(Py_None);
2189 } else {
2190 ret = PyUnicode_FromPRUnichar(t, string_size);
2191 }
2192 break;
2193 }
2194 default:
2195 // As this is called by external components,
2196 // we return _something_ rather than failing before any user code has run!
2197 {
2198 char buf[128];
2199 sprintf(buf, "Unknown XPCOM type flags (0x%x)", td.type_flags);
2200 PyXPCOM_LogWarning("%s - returning a string object with this message!\n", buf);
2201 ret = PyString_FromString(buf);
2202 break;
2203 }
2204 }
2205 return ret;
2206}
2207
2208nsresult PyXPCOM_GatewayVariantHelper::GetArrayType(PRUint8 index, PRUint8 *ret, nsIID **iid)
2209{
2210 nsCOMPtr<nsIInterfaceInfoManager> iim(do_GetService(
2211 NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
2212 NS_ABORT_IF_FALSE(iim != nsnull, "Cant get interface from IIM!");
2213 if (iim==nsnull)
2214 return NS_ERROR_FAILURE;
2215
2216 nsCOMPtr<nsIInterfaceInfo> ii;
2217 nsresult rc = iim->GetInfoForIID( &m_gateway->m_iid, getter_AddRefs(ii));
2218 if (NS_FAILED(rc))
2219 return rc;
2220 nsXPTType datumType;
2221 const nsXPTParamInfo& param_info = m_info->GetParam((PRUint8)index);
2222 rc = ii->GetTypeForParam(m_method_index, &param_info, 1, &datumType);
2223 if (NS_FAILED(rc))
2224 return rc;
2225 if (iid) {
2226 *iid = (nsIID *)&NS_GET_IID(nsISupports);
2227 if (XPT_TDP_TAG(datumType)==nsXPTType::T_INTERFACE ||
2228 XPT_TDP_TAG(datumType)==nsXPTType::T_INTERFACE_IS ||
2229 XPT_TDP_TAG(datumType)==nsXPTType::T_ARRAY)
2230 ii->GetIIDForParam(m_method_index, &param_info, iid);
2231 }
2232 *ret = datumType.flags;
2233 return NS_OK;
2234}
2235
2236PRBool PyXPCOM_GatewayVariantHelper::GetIIDForINTERFACE_ID(int index, const nsIID **ppret)
2237{
2238 // Not sure if the IID pointed at by by this is allows to be
2239 // in or out, so we will allow it.
2240 nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index;
2241 nsXPTType typ = pi->GetType();
2242 NS_WARN_IF_FALSE(XPT_TDP_TAG(typ) == nsXPTType::T_IID, "INTERFACE_IS IID param isnt an IID!");
2243 NS_ABORT_IF_FALSE(typ.IsPointer(), "Expecting to re-fill a pointer value.");
2244 if (XPT_TDP_TAG(typ) != nsXPTType::T_IID)
2245 *ppret = &NS_GET_IID(nsISupports);
2246 else {
2247 nsXPTCMiniVariant &ns_v = m_params[index];
2248 if (pi->IsOut()) {
2249 nsIID **pp = (nsIID **)ns_v.val.p;
2250 if (pp && *pp)
2251 *ppret = *pp;
2252 else
2253 *ppret = &NS_GET_IID(nsISupports);
2254 } else if (pi->IsIn()) {
2255 nsIID *p = (nsIID *)ns_v.val.p;
2256 if (p)
2257 *ppret = p;
2258 else
2259 *ppret = &NS_GET_IID(nsISupports);
2260 } else {
2261 NS_ERROR("Param is not in or out!");
2262 *ppret = &NS_GET_IID(nsISupports);
2263 }
2264 }
2265 return PR_TRUE;
2266}
2267
2268nsIInterfaceInfo *PyXPCOM_GatewayVariantHelper::GetInterfaceInfo()
2269{
2270 if (!m_interface_info) {
2271 nsCOMPtr<nsIInterfaceInfoManager> iim(do_GetService(
2272 NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
2273 if (iim)
2274 iim->GetInfoForIID(&m_gateway->m_iid, getter_AddRefs(m_interface_info));
2275 }
2276 return m_interface_info;
2277}
2278
2279#undef FILL_SIMPLE_POINTER
2280#define FILL_SIMPLE_POINTER( type, ob ) *((type *)ns_v.val.p) = (type)(ob)
2281
2282nsresult PyXPCOM_GatewayVariantHelper::BackFillVariant( PyObject *val, int index)
2283{
2284 nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index;
2285 NS_ABORT_IF_FALSE(pi->IsOut() || pi->IsDipper(), "The value must be marked as [out] (or a dipper) to be back-filled!");
2286 NS_ABORT_IF_FALSE(!pi->IsShared(), "Dont know how to back-fill a shared out param");
2287 nsXPTCMiniVariant &ns_v = m_params[index];
2288
2289 nsXPTType typ = pi->GetType();
2290 PyObject* val_use = NULL;
2291
2292 NS_ABORT_IF_FALSE(pi->IsDipper() || ns_v.val.p, "No space for result!");
2293 if (!pi->IsDipper() && !ns_v.val.p) return NS_ERROR_INVALID_POINTER;
2294
2295 PRBool rc = PR_TRUE;
2296 switch (XPT_TDP_TAG(typ)) {
2297 case nsXPTType::T_I8:
2298 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
2299 FILL_SIMPLE_POINTER( PRInt8, PyInt_AsLong(val_use) );
2300 break;
2301 case nsXPTType::T_I16:
2302 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
2303 FILL_SIMPLE_POINTER( PRInt16, PyInt_AsLong(val_use) );
2304 break;
2305 case nsXPTType::T_I32:
2306 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
2307 FILL_SIMPLE_POINTER( PRInt32, PyInt_AsLong(val_use) );
2308 break;
2309 case nsXPTType::T_I64:
2310 if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE;
2311 FILL_SIMPLE_POINTER( PRInt64, PyLong_AsLongLong(val_use) );
2312 break;
2313 case nsXPTType::T_U8:
2314 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
2315 FILL_SIMPLE_POINTER( PRUint8, PyInt_AsLong(val_use) );
2316 break;
2317 case nsXPTType::T_U16:
2318 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
2319 FILL_SIMPLE_POINTER( PRUint16, PyInt_AsLong(val_use) );
2320 break;
2321 case nsXPTType::T_U32:
2322 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
2323 FILL_SIMPLE_POINTER( PRUint32, PyInt_AsLong(val_use) );
2324 break;
2325 case nsXPTType::T_U64:
2326 if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE;
2327 FILL_SIMPLE_POINTER( PRUint64, PyLong_AsUnsignedLongLong(val_use) );
2328 break;
2329 case nsXPTType::T_FLOAT:
2330 if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
2331 FILL_SIMPLE_POINTER( float, PyFloat_AsDouble(val_use) );
2332 break;
2333 case nsXPTType::T_DOUBLE:
2334 if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
2335 FILL_SIMPLE_POINTER( double, PyFloat_AsDouble(val_use) );
2336 break;
2337 case nsXPTType::T_BOOL:
2338 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
2339 FILL_SIMPLE_POINTER( PRBool, PyInt_AsLong(val_use) );
2340 break;
2341 case nsXPTType::T_CHAR:
2342 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
2343 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
2344 BREAK_FALSE;
2345 }
2346 if ((val_use = PyObject_Str(val))==NULL)
2347 BREAK_FALSE;
2348 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
2349 NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
2350 FILL_SIMPLE_POINTER( char, *PyString_AS_STRING(val_use) );
2351 break;
2352
2353 case nsXPTType::T_WCHAR:
2354 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
2355 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
2356 BREAK_FALSE;
2357 }
2358 if ((val_use = PyUnicode_FromObject(val))==NULL)
2359 BREAK_FALSE;
2360 NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!");
2361 // Lossy!
2362 FILL_SIMPLE_POINTER( PRUnichar, *PyUnicode_AS_UNICODE(val_use) );
2363 break;
2364
2365// case nsXPTType::T_VOID:
2366 case nsXPTType::T_IID: {
2367 nsIID iid;
2368 if (!Py_nsIID::IIDFromPyObject(val, &iid))
2369 BREAK_FALSE;
2370 nsIID **pp = (nsIID **)ns_v.val.p;
2371 // If there is an existing [in] IID, free it.
2372 if (*pp && pi->IsIn())
2373 nsMemory::Free(*pp);
2374 *pp = (nsIID *)nsMemory::Alloc(sizeof(nsIID));
2375 if (*pp==NULL) {
2376 PyErr_NoMemory();
2377 BREAK_FALSE;
2378 }
2379 memcpy(*pp, &iid, sizeof(iid));
2380 break;
2381 }
2382
2383 case nsXPTType::T_ASTRING:
2384 case nsXPTType::T_DOMSTRING: {
2385 nsAString *ws = (nsAString *)ns_v.val.p;
2386 NS_ABORT_IF_FALSE(ws->Length() == 0, "Why does this writable string already have chars??");
2387 if (!PyObject_AsNSString(val, *ws))
2388 BREAK_FALSE;
2389 break;
2390 }
2391 case nsXPTType::T_CSTRING: {
2392 nsCString *ws = (nsCString *)ns_v.val.p;
2393 NS_ABORT_IF_FALSE(ws->Length() == 0, "Why does this writable string already have chars??");
2394 if (val == Py_None) {
2395 NS_ABORT_IF_FALSE(0, "dont handle None here yet");
2396 } else {
2397 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
2398 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
2399 BREAK_FALSE;
2400 }
2401 val_use = PyObject_Str(val);
2402 NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
2403 const char *sz = PyString_AS_STRING(val_use);
2404 ws->Assign(sz, PyString_Size(val_use));
2405 }
2406 break;
2407 }
2408 case nsXPTType::T_UTF8STRING: {
2409 nsCString *ws = (nsCString *)ns_v.val.p;
2410 NS_ABORT_IF_FALSE(ws->Length() == 0, "Why does this writable string already have chars??");
2411 if (val == Py_None) {
2412 NS_ABORT_IF_FALSE(0, "dont handle None here yet");
2413 } else {
2414 if (PyString_Check(val)) {
2415 val_use = val;
2416 Py_INCREF(val);
2417 } else if (PyUnicode_Check(val)) {
2418 val_use = PyUnicode_AsUTF8String(val);
2419 } else {
2420 PyErr_SetString(PyExc_TypeError, "UTF8 parameters must be string or Unicode objects");
2421 BREAK_FALSE;
2422 }
2423 NS_ABORT_IF_FALSE(PyString_Check(val_use), "must have a string object!");
2424 const char *sz = PyString_AS_STRING(val_use);
2425 ws->Assign(sz, PyString_Size(val_use));
2426 }
2427 break;
2428 }
2429
2430 case nsXPTType::T_CHAR_STR: {
2431 // If it is an existing string, free it.
2432 char **pp = (char **)ns_v.val.p;
2433 if (*pp && pi->IsIn())
2434 nsMemory::Free(*pp);
2435 *pp = nsnull;
2436
2437 if (val == Py_None)
2438 break; // Remains NULL.
2439 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
2440 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
2441 BREAK_FALSE;
2442 }
2443 if ((val_use = PyObject_Str(val))==NULL)
2444 BREAK_FALSE;
2445 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
2446 NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
2447
2448 const char *sz = PyString_AS_STRING(val_use);
2449 int nch = PyString_GET_SIZE(val_use);
2450
2451 *pp = (char *)nsMemory::Alloc(nch+1);
2452 if (*pp==NULL) {
2453 PyErr_NoMemory();
2454 BREAK_FALSE;
2455 }
2456 strncpy(*pp, sz, nch+1);
2457 break;
2458 }
2459 case nsXPTType::T_WCHAR_STR: {
2460 // If it is an existing string, free it.
2461 PRUnichar **pp = (PRUnichar **)ns_v.val.p;
2462 if (*pp && pi->IsIn())
2463 nsMemory::Free(*pp);
2464 *pp = nsnull;
2465 if (val == Py_None)
2466 break; // Remains NULL.
2467 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
2468 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
2469 BREAK_FALSE;
2470 }
2471 val_use = PyUnicode_FromObject(val);
2472 NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!");
2473 if (PyUnicode_AsPRUnichar(val_use, pp, NULL) < 0)
2474 BREAK_FALSE;
2475 break;
2476 }
2477 case nsXPTType::T_INTERFACE: {
2478 nsISupports *pnew = nsnull;
2479 // Find out what IID we are declared to use.
2480 nsIID *iid;
2481 nsIInterfaceInfo *ii = GetInterfaceInfo();
2482 if (ii)
2483 ii->GetIIDForParam(m_method_index, pi, &iid);
2484
2485 // Get it the "standard" way.
2486 // We do allow NULL here, even tho doing so will no-doubt crash some objects.
2487 // (but there will certainly be objects out there that will allow NULL :-(
2488 nsIID iid_use = iid ? *iid : NS_GET_IID(nsISupports);
2489 if (!Py_nsISupports::InterfaceFromPyObject(val, iid_use, &pnew, PR_TRUE))
2490 BREAK_FALSE;
2491 nsISupports **pp = (nsISupports **)ns_v.val.p;
2492 if (*pp && pi->IsIn()) {
2493 Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
2494 (*pp)->Release();
2495 Py_END_ALLOW_THREADS;
2496 }
2497
2498 *pp = pnew; // ref-count added by InterfaceFromPyObject
2499 break;
2500 }
2501 case nsXPTType::T_INTERFACE_IS: {
2502 const nsIID *piid;
2503 if (!GetIIDForINTERFACE_ID(pi->type.argnum, &piid))
2504 BREAK_FALSE;
2505
2506 nsISupports *pnew = nsnull;
2507 // Get it the "standard" way.
2508 // We do allow NULL here, even tho doing so will no-doubt crash some objects.
2509 // (but there will certainly be objects out there that will allow NULL :-(
2510 if (!Py_nsISupports::InterfaceFromPyObject(val, *piid, &pnew, PR_TRUE))
2511 BREAK_FALSE;
2512 nsISupports **pp = (nsISupports **)ns_v.val.p;
2513 if (*pp && pi->IsIn()) {
2514 Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
2515 (*pp)->Release();
2516 Py_END_ALLOW_THREADS;
2517 }
2518
2519 *pp = pnew; // ref-count added by InterfaceFromPyObject
2520 break;
2521 }
2522
2523 case nsXPTType::T_PSTRING_SIZE_IS: {
2524 const char *sz = nsnull;
2525 PRUint32 nch = 0;
2526 if (val != Py_None) {
2527 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
2528 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
2529 BREAK_FALSE;
2530 }
2531 if ((val_use = PyObject_Str(val))==NULL)
2532 BREAK_FALSE;
2533 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
2534 NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
2535
2536 sz = PyString_AS_STRING(val_use);
2537 nch = PyString_GET_SIZE(val_use);
2538 }
2539 PRBool bBackFill = PR_FALSE;
2540 PRBool bCanSetSizeIs = CanSetSizeIs(index, PR_TRUE);
2541 // If we can not change the size, check our sequence is correct.
2542 if (!bCanSetSizeIs) {
2543 PRUint32 existing_size = GetSizeIs(index, PR_TRUE);
2544 if (nch != existing_size) {
2545 PyErr_Format(PyExc_ValueError, "This function is expecting a string of exactly length %d - %d characters were passed", existing_size, nch);
2546 BREAK_FALSE;
2547 }
2548 // It we have an "inout" param, but an "in" count, then
2549 // it is probably a buffer the caller expects us to
2550 // fill in-place!
2551 bBackFill = pi->IsIn();
2552 }
2553 if (bBackFill) {
2554 memcpy(*(char **)ns_v.val.p, sz, nch);
2555 } else {
2556 // If we have an existing string, free it!
2557 char **pp = (char **)ns_v.val.p;
2558 if (*pp && pi->IsIn())
2559 nsMemory::Free(*pp);
2560 *pp = nsnull;
2561 if (sz==nsnull) // None specified.
2562 break; // Remains NULL.
2563 *pp = (char *)nsMemory::Alloc(nch);
2564 if (*pp==NULL) {
2565 PyErr_NoMemory();
2566 BREAK_FALSE;
2567 }
2568 memcpy(*pp, sz, nch);
2569 if (bCanSetSizeIs)
2570 rc = SetSizeIs(index, PR_TRUE, nch);
2571 else {
2572 NS_ABORT_IF_FALSE(GetSizeIs(index, PR_TRUE) == nch, "Can't set sizeis, but string isnt correct size");
2573 }
2574 }
2575 break;
2576 }
2577
2578 case nsXPTType::T_PWSTRING_SIZE_IS: {
2579 PRUnichar *sz = nsnull;
2580 PRUint32 nch = 0;
2581 PRUint32 nbytes = 0;
2582
2583 if (val != Py_None) {
2584 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
2585 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
2586 BREAK_FALSE;
2587 }
2588 val_use = PyUnicode_FromObject(val);
2589 NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!");
2590 if (PyUnicode_AsPRUnichar(val_use, &sz, &nch) < 0)
2591 BREAK_FALSE;
2592 nbytes = sizeof(PRUnichar) * nch;
2593 }
2594 PRBool bBackFill = PR_FALSE;
2595 PRBool bCanSetSizeIs = CanSetSizeIs(index, PR_TRUE);
2596 // If we can not change the size, check our sequence is correct.
2597 if (!bCanSetSizeIs) {
2598 // It is a buffer the caller prolly wants us to fill in-place!
2599 PRUint32 existing_size = GetSizeIs(index, PR_TRUE);
2600 if (nch != existing_size) {
2601 PyErr_Format(PyExc_ValueError, "This function is expecting a string of exactly length %d - %d characters were passed", existing_size, nch);
2602 BREAK_FALSE;
2603 }
2604 // It we have an "inout" param, but an "in" count, then
2605 // it is probably a buffer the caller expects us to
2606 // fill in-place!
2607 bBackFill = pi->IsIn();
2608 }
2609 if (bBackFill) {
2610 memcpy(*(PRUnichar **)ns_v.val.p, sz, nbytes);
2611 } else {
2612 // If it is an existing string, free it.
2613 PRUnichar **pp = (PRUnichar **)ns_v.val.p;
2614 if (*pp && pi->IsIn())
2615 nsMemory::Free(*pp);
2616 *pp = sz;
2617 sz = nsnull;
2618 if (bCanSetSizeIs)
2619 rc = SetSizeIs(index, PR_TRUE, nch);
2620 else {
2621 NS_ABORT_IF_FALSE(GetSizeIs(index, PR_TRUE) == nch, "Can't set sizeis, but string isnt correct size");
2622 }
2623 }
2624 if (sz)
2625 nsMemory::Free(sz);
2626 break;
2627 }
2628 case nsXPTType::T_ARRAY: {
2629 // If it is an existing array of the correct size, keep it.
2630 PRUint32 sequence_size = 0;
2631 PRUint8 array_type;
2632 nsIID *piid;
2633 nsresult ns = GetArrayType(index, &array_type, &piid);
2634 if (NS_FAILED(ns))
2635 return ns;
2636 PRUint32 element_size = GetArrayElementSize(array_type);
2637 if (val != Py_None) {
2638 if (!PySequence_Check(val)) {
2639 PyErr_Format(PyExc_TypeError, "Object for xpcom array must be a sequence, not type '%s'", val->ob_type->tp_name);
2640 BREAK_FALSE;
2641 }
2642 sequence_size = PySequence_Length(val);
2643 }
2644 PRUint32 existing_size = GetSizeIs(index, PR_FALSE);
2645 PRBool bBackFill = PR_FALSE;
2646 PRBool bCanSetSizeIs = CanSetSizeIs(index, PR_FALSE);
2647 // If we can not change the size, check our sequence is correct.
2648 if (!bCanSetSizeIs) {
2649 // It is a buffer the caller prolly wants us to fill in-place!
2650 if (sequence_size != existing_size) {
2651 PyErr_Format(PyExc_ValueError, "This function is expecting a sequence of exactly length %d - %d items were passed", existing_size, sequence_size);
2652 BREAK_FALSE;
2653 }
2654 // It we have an "inout" param, but an "in" count, then
2655 // it is probably a buffer the caller expects us to
2656 // fill in-place!
2657 bBackFill = pi->IsIn();
2658 }
2659 if (bBackFill)
2660 rc = FillSingleArray(*(void **)ns_v.val.p, val, sequence_size, element_size, array_type&XPT_TDP_TAGMASK, piid);
2661 else {
2662 // If it is an existing array, free it.
2663 void **pp = (void **)ns_v.val.p;
2664 if (*pp && pi->IsIn()) {
2665 FreeSingleArray(*pp, existing_size, array_type);
2666 nsMemory::Free(*pp);
2667 }
2668 *pp = nsnull;
2669 if (val == Py_None)
2670 break; // Remains NULL.
2671 size_t nbytes = sequence_size * element_size;
2672 if (nbytes==0) nbytes = 1; // avoid assertion about 0 bytes
2673 *pp = (void *)nsMemory::Alloc(nbytes);
2674 memset(*pp, 0, nbytes);
2675 rc = FillSingleArray(*pp, val, sequence_size, element_size, array_type&XPT_TDP_TAGMASK, piid);
2676 if (!rc) break;
2677 if (bCanSetSizeIs)
2678 rc = SetSizeIs(index, PR_FALSE, sequence_size);
2679 else {
2680 NS_ABORT_IF_FALSE(GetSizeIs(index, PR_FALSE) == sequence_size, "Can't set sizeis, but string isnt correct size");
2681 }
2682 }
2683 break;
2684 }
2685 default:
2686 // try and limp along in this case.
2687 // leave rc TRUE
2688 PyXPCOM_LogWarning("Converting Python object for an [out] param - The object type (0x%x) is unknown - leaving param alone!\n", XPT_TDP_TAG(typ));
2689 break;
2690 }
2691 Py_XDECREF(val_use);
2692 if (!rc)
2693 return NS_ERROR_FAILURE;
2694 return NS_OK;
2695}
2696
2697nsresult PyXPCOM_GatewayVariantHelper::ProcessPythonResult(PyObject *ret_ob)
2698{
2699 // NOTE - although we return an nresult, if we leave a Python
2700 // exception set, then our caller may take additional action
2701 // (ie, translating our nsresult to a more appropriate nsresult
2702 // for the Python exception.)
2703 NS_PRECONDITION(!PyErr_Occurred(), "Expecting no Python exception to be pending when processing the return result");
2704
2705 nsresult rc = NS_OK;
2706 // If we dont get a tuple back, then the result is only
2707 // an int nresult for the underlying function.
2708 // (ie, the policy is expected to return (NS_OK, user_retval),
2709 // but can also return (say), NS_ERROR_FAILURE
2710 if (PyInt_Check(ret_ob))
2711 return PyInt_AsLong(ret_ob);
2712 // Now it must be the tuple.
2713 if (!PyTuple_Check(ret_ob) ||
2714 PyTuple_Size(ret_ob)!=2 ||
2715 !PyInt_Check(PyTuple_GET_ITEM(ret_ob, 0))) {
2716 PyErr_SetString(PyExc_TypeError, "The Python result must be a single integer or a tuple of length==2 and first item an int.");
2717 return NS_ERROR_FAILURE;
2718 }
2719 PyObject *user_result = PyTuple_GET_ITEM(ret_ob, 1);
2720 // Count up how many results our function needs.
2721 int i;
2722 int num_results = 0;
2723 int last_result = -1; // optimization if we only have one - this is it!
2724 int index_retval = -1;
2725 for (i=0;i<m_num_type_descs;i++) {
2726 nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+i;
2727 if (!m_python_type_desc_array[i].is_auto_out) {
2728 if (pi->IsOut() || pi->IsDipper()) {
2729 num_results++;
2730 last_result = i;
2731 }
2732 if (pi->IsRetval())
2733 index_retval = i;
2734 }
2735 }
2736
2737 if (num_results==0) {
2738 ; // do nothing
2739 } else if (num_results==1) {
2740 // May or may not be the nominated retval - who cares!
2741 NS_ABORT_IF_FALSE(last_result >=0 && last_result < m_num_type_descs, "Have one result, but dont know its index!");
2742 rc = BackFillVariant( user_result, last_result );
2743 } else {
2744 // Loop over each one, filling as we go.
2745 // We allow arbitary sequences here, but _not_ strings
2746 // or Unicode!
2747 // NOTE - We ALWAYS do the nominated retval first.
2748 // The Python pattern is always:
2749 // return retval [, byref1 [, byref2 ...] ]
2750 // But the retval is often the last param described in the info.
2751 if (!PySequence_Check(user_result) ||
2752 PyString_Check(user_result) ||
2753 PyUnicode_Check(user_result)) {
2754 PyErr_SetString(PyExc_TypeError, "This function has multiple results, but a sequence was not given to fill them");
2755 return NS_ERROR_FAILURE;
2756 }
2757 int num_user_results = PySequence_Length(user_result);
2758 // If they havent given enough, we dont really care.
2759 // although a warning is probably appropriate.
2760 if (num_user_results != num_results) {
2761 const char *method_name = m_info->GetName();
2762 PyXPCOM_LogWarning("The method '%s' has %d out params, but %d were supplied by the Python code\n",
2763 method_name,
2764 num_results,
2765 num_user_results);
2766 }
2767 int this_py_index = 0;
2768 if (index_retval != -1) {
2769 // We always return the nominated result first!
2770 PyObject *sub = PySequence_GetItem(user_result, 0);
2771 if (sub==NULL)
2772 return NS_ERROR_FAILURE;
2773 rc = BackFillVariant(sub, index_retval);
2774 Py_DECREF(sub);
2775 this_py_index = 1;
2776 }
2777 for (i=0;NS_SUCCEEDED(rc) && i<m_info->GetParamCount();i++) {
2778 // If weve already done it, or dont need to do it!
2779 if (i==index_retval || m_python_type_desc_array[i].is_auto_out)
2780 continue;
2781 nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+i;
2782 if (pi->IsOut()) {
2783 PyObject *sub = PySequence_GetItem(user_result, this_py_index);
2784 if (sub==NULL)
2785 return NS_ERROR_FAILURE;
2786 rc = BackFillVariant(sub, i);
2787 Py_DECREF(sub);
2788 this_py_index++;
2789 }
2790 }
2791 }
2792 return rc;
2793}
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette