VirtualBox

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

Last change on this file since 70577 was 70577, checked in by vboxsync, 7 years ago

xpcom/VBoxPython: Fixed broken string handling in py3. Fixed wrong module+init names with the pymalloc abi variant.

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

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