VirtualBox

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

Last change on this file since 59809 was 59809, checked in by vboxsync, 9 years ago

re-applied the remaining changes which were backed out in r105674

  • Property svn:eol-style set to native
File size: 99.3 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(obj))
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(obj) - 2) / sizeof(PRUnichar);
105 src = PyBytes_AS_STRING(obj) + 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_num_array = 0;
1119 m_methodindex = methodindex;
1120 // Parent should never die before we do, but let's not take the chance.
1121 m_parent = parent;
1122 Py_INCREF(parent);
1123}
1124
1125PyXPCOM_InterfaceVariantHelper::~PyXPCOM_InterfaceVariantHelper()
1126{
1127 Py_DECREF(m_parent);
1128 Py_XDECREF(m_pyparams);
1129 for (int i=0;i<m_num_array;i++) {
1130 if (m_var_array) {
1131 nsXPTCVariant &ns_v = m_var_array[i];
1132 if (ns_v.IsValInterface()) {
1133 if (ns_v.val.p) {
1134 Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
1135 ((nsISupports *)ns_v.val.p)->Release();
1136 Py_END_ALLOW_THREADS;
1137 }
1138 }
1139 if (ns_v.IsValDOMString() && ns_v.val.p) {
1140 delete (const nsAString *)ns_v.val.p;
1141 }
1142 if (ns_v.IsValCString() && ns_v.val.p) {
1143 delete (const nsACString *)ns_v.val.p;
1144 }
1145 if (ns_v.IsValUTF8String() && ns_v.val.p) {
1146 delete (const nsACString *)ns_v.val.p;
1147 }
1148 if (ns_v.IsValArray()) {
1149 nsXPTCVariant &ns_v = m_var_array[i];
1150 if (ns_v.val.p) {
1151 PRUint8 array_type = (PRUint8)PyInt_AsLong(m_python_type_desc_array[i].extra);
1152 PRUint32 seq_size = GetSizeIs(i, PR_FALSE);
1153 FreeSingleArray(ns_v.val.p, seq_size, array_type);
1154 }
1155 }
1156 // IsOwned must be the last check of the loop, as
1157 // this frees the underlying data used above (eg, by the array free process)
1158 if (ns_v.IsValAllocated() && !ns_v.IsValInterface() && !ns_v.IsValDOMString()) {
1159 NS_ABORT_IF_FALSE(ns_v.IsPtrData(), "expecting a pointer to free");
1160 nsMemory::Free(ns_v.val.p);
1161 }
1162 }
1163 if (m_buffer_array && m_buffer_array[i])
1164 nsMemory::Free(m_buffer_array[i]);
1165 }
1166 delete [] m_python_type_desc_array;
1167 delete [] m_buffer_array;
1168 delete [] m_var_array;
1169}
1170
1171PRBool PyXPCOM_InterfaceVariantHelper::Init(PyObject *obParams)
1172{
1173 PRBool ok = PR_FALSE;
1174 int i;
1175 int total_params_needed = 0;
1176 if (!PySequence_Check(obParams) || PySequence_Length(obParams)!=2) {
1177 PyErr_Format(PyExc_TypeError, "Param descriptors must be a sequence of exactly length 2");
1178 return PR_FALSE;
1179 }
1180 PyObject *typedescs = PySequence_GetItem(obParams, 0);
1181 if (typedescs==NULL)
1182 return PR_FALSE;
1183 // NOTE: The length of the typedescs may be different than the
1184 // args actually passed. The typedescs always include all
1185 // hidden params (such as "size_is"), while the actual
1186 // args never include this.
1187 m_num_array = PySequence_Length(typedescs);
1188 if (PyErr_Occurred()) goto done;
1189
1190 m_pyparams = PySequence_GetItem(obParams, 1);
1191 if (m_pyparams==NULL) goto done;
1192
1193 m_python_type_desc_array = new PythonTypeDescriptor[m_num_array];
1194 if (!m_python_type_desc_array) goto done;
1195
1196 // Pull apart the type descs and stash them.
1197 for (i=0;i<m_num_array;i++) {
1198 PyObject *desc_object = PySequence_GetItem(typedescs, i);
1199 if (desc_object==NULL)
1200 goto done;
1201
1202 // Pull apart the typedesc tuple back into a structure we can work with.
1203 PythonTypeDescriptor &ptd = m_python_type_desc_array[i];
1204 PRBool this_ok = PyArg_ParseTuple(desc_object, "bbbbO:type_desc",
1205 &ptd.param_flags, &ptd.type_flags, &ptd.argnum, &ptd.argnum2, &ptd.extra);
1206 Py_DECREF(desc_object);
1207 if (!this_ok) goto done;
1208 Py_INCREF(ptd.extra);
1209
1210 }
1211 total_params_needed = ProcessPythonTypeDescriptors(m_python_type_desc_array, m_num_array);
1212 // OK - check we got the number of args we expected.
1213 // If not, its really an internal error rather than the user.
1214 if (PySequence_Length(m_pyparams) != total_params_needed) {
1215#ifdef VBOX
1216 PyErr_Format(PyExc_ValueError, "The type descriptions indicate %d args are needed, but %ld were provided",
1217 total_params_needed, (long)PySequence_Length(m_pyparams));
1218#else
1219 PyErr_Format(PyExc_ValueError, "The type descriptions indicate %d args are needed, but %d were provided",
1220 total_params_needed, PySequence_Length(m_pyparams));
1221#endif
1222 goto done;
1223 }
1224
1225 // Init the other arrays.
1226 m_var_array = new nsXPTCVariant[m_num_array];
1227 if (!m_var_array) goto done;
1228 memset(m_var_array, 0, m_num_array * sizeof(m_var_array[0]));
1229
1230 m_buffer_array = new void *[m_num_array];
1231 if (!m_buffer_array) goto done;
1232 memset(m_buffer_array, 0, m_num_array * sizeof(m_buffer_array[0]));
1233
1234 ok = PR_TRUE;
1235done:
1236 if (!ok && !PyErr_Occurred())
1237 PyErr_NoMemory();
1238
1239 Py_XDECREF(typedescs);
1240 return ok;
1241}
1242
1243
1244PRBool PyXPCOM_InterfaceVariantHelper::FillArray()
1245{
1246 int param_index = 0;
1247 int i;
1248 for (i=0;i<m_num_array;i++) {
1249 PythonTypeDescriptor &ptd = m_python_type_desc_array[i];
1250 // stash the type_flags into the variant, and remember how many extra bits of info we have.
1251 m_var_array[i].type = ptd.type_flags;
1252 if (XPT_PD_IS_IN(ptd.param_flags) && !ptd.is_auto_in && !XPT_PD_IS_DIPPER(ptd.param_flags)) {
1253 if (!FillInVariant(ptd, i, param_index))
1254 return PR_FALSE;
1255 param_index++;
1256 }
1257 if ((XPT_PD_IS_OUT(ptd.param_flags) && !ptd.is_auto_out) || XPT_PD_IS_DIPPER(ptd.param_flags)) {
1258 if (!PrepareOutVariant(ptd, i))
1259 return PR_FALSE;
1260 }
1261 }
1262 // There may be out "size_is" params we havent touched yet
1263 // (ie, as the param itself is marked "out", we never got to
1264 // touch the associated "size_is".
1265 // Final loop to handle this.
1266 for (i=0;i<m_num_array;i++) {
1267 PythonTypeDescriptor &ptd = m_python_type_desc_array[i];
1268 if (ptd.is_auto_out && !ptd.have_set_auto) {
1269 // Call PrepareOutVariant to ensure buffers etc setup.
1270 if (!PrepareOutVariant(ptd, i))
1271 return PR_FALSE;
1272 }
1273 }
1274 return PR_TRUE;
1275}
1276
1277
1278PRBool PyXPCOM_InterfaceVariantHelper::SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size)
1279{
1280 NS_ABORT_IF_FALSE(var_index < m_num_array, "var_index param is invalid");
1281 PRUint8 argnum = is_arg1 ?
1282 m_python_type_desc_array[var_index].argnum :
1283 m_python_type_desc_array[var_index].argnum2;
1284 NS_ABORT_IF_FALSE(argnum < m_num_array, "size_is param is invalid");
1285 PythonTypeDescriptor &td_size = m_python_type_desc_array[argnum];
1286 NS_ABORT_IF_FALSE(td_size.is_auto_in || td_size.is_auto_out, "Setting size_is, but param is not marked as auto!");
1287 NS_ABORT_IF_FALSE( (td_size.type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32");
1288 nsXPTCVariant &ns_v = m_var_array[argnum];
1289
1290 if (!td_size.have_set_auto) {
1291 ns_v.type = td_size.type_flags;
1292 ns_v.val.u32 = new_size;
1293 // In case it is "out", setup the necessary pointers.
1294 PrepareOutVariant(td_size, argnum);
1295 td_size.have_set_auto = PR_TRUE;
1296 } else {
1297 if (ns_v.val.u32 != new_size) {
1298 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);
1299 return PR_FALSE;
1300 }
1301 }
1302 return PR_TRUE;
1303}
1304
1305PRUint32 PyXPCOM_InterfaceVariantHelper::GetSizeIs( int var_index, PRBool is_arg1)
1306{
1307 NS_ABORT_IF_FALSE(var_index < m_num_array, "var_index param is invalid");
1308 PRUint8 argnum = is_arg1 ?
1309 m_python_type_desc_array[var_index].argnum :
1310 m_python_type_desc_array[var_index].argnum2;
1311 NS_ABORT_IF_FALSE(argnum < m_num_array, "size_is param is invalid");
1312 NS_ABORT_IF_FALSE( (m_python_type_desc_array[argnum].type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32");
1313 PRBool is_out = XPT_PD_IS_OUT(m_python_type_desc_array[argnum].param_flags);
1314 nsXPTCVariant &ns_v = m_var_array[argnum];
1315 return is_out ? *((PRUint32 *)ns_v.ptr) : ns_v.val.u32;
1316}
1317
1318#define MAKE_VALUE_BUFFER(size) \
1319 if ((this_buffer_pointer = (void *)nsMemory::Alloc((size))) == nsnull) { \
1320 PyErr_NoMemory(); \
1321 BREAK_FALSE; \
1322 }
1323
1324PRBool PyXPCOM_InterfaceVariantHelper::FillInVariant(const PythonTypeDescriptor &td, int value_index, int param_index)
1325{
1326 PRBool rc = PR_TRUE;
1327 // Get a reference to the variant we are filling for convenience.
1328 nsXPTCVariant &ns_v = m_var_array[value_index];
1329 NS_ABORT_IF_FALSE(ns_v.type == td.type_flags, "Expecting variant all setup for us");
1330
1331 // We used to avoid passing internal buffers to PyString etc objects
1332 // for 2 reasons: paranoia (so incorrect external components couldn't break
1333 // Python) and simplicity (in vs in-out issues, etc)
1334 // However, at least one C++ implemented component (nsITimelineService)
1335 // uses a "char *", and keys on the address (assuming that the same
1336 // *pointer* is passed rather than value. Therefore, we have a special case
1337 // - T_CHAR_STR that is "in" gets the Python string pointer passed.
1338 void *&this_buffer_pointer = m_buffer_array[value_index]; // Freed at object destruction with PyMem_Free()
1339 NS_ABORT_IF_FALSE(this_buffer_pointer==nsnull, "We appear to already have a buffer");
1340 int cb_this_buffer_pointer = 0;
1341 if (XPT_PD_IS_IN(td.param_flags)) {
1342 NS_ABORT_IF_FALSE(!td.is_auto_in, "Param is 'auto-in', but we are filling it normally!");
1343 PyObject *val_use = NULL; // a temp object converters can use, and will be DECREF'd
1344 PyObject *val = PySequence_GetItem(m_pyparams, param_index);
1345 NS_WARN_IF_FALSE(val, "Have an 'in' param, but no Python value!");
1346 if (val==NULL) {
1347 PyErr_Format(PyExc_ValueError, "Param %d is marked as 'in', but no value was given", value_index);
1348 return PR_FALSE;
1349 }
1350 switch (XPT_TDP_TAG(ns_v.type)) {
1351 case nsXPTType::T_I8:
1352 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1353 ns_v.val.i8 = (PRInt8)PyInt_AsLong(val_use);
1354 break;
1355 case nsXPTType::T_I16:
1356 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1357 ns_v.val.i16 = (PRInt16)PyInt_AsLong(val_use);
1358 break;
1359 case nsXPTType::T_I32:
1360 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1361 ns_v.val.i32 = (PRInt32)PyInt_AsLong(val_use);
1362 break;
1363 case nsXPTType::T_I64:
1364 if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE
1365 ns_v.val.i64 = (PRInt64)PyLong_AsLongLong(val_use);
1366 break;
1367 case nsXPTType::T_U8:
1368 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1369 ns_v.val.u8 = (PRUint8)PyInt_AsLong(val_use);
1370 break;
1371 case nsXPTType::T_U16:
1372 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1373 ns_v.val.u16 = (PRUint16)PyInt_AsLong(val_use);
1374 break;
1375 case nsXPTType::T_U32:
1376 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1377 ns_v.val.u32 = (PRUint32)PyInt_AsLong(val_use);
1378 break;
1379 case nsXPTType::T_U64:
1380 if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE
1381 ns_v.val.u64 = (PRUint64)PyLong_AsUnsignedLongLong(val_use);
1382 break;
1383 case nsXPTType::T_FLOAT:
1384 if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
1385 ns_v.val.f = (float)PyFloat_AsDouble(val_use);
1386 break;
1387 case nsXPTType::T_DOUBLE:
1388 if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
1389 ns_v.val.d = PyFloat_AsDouble(val_use);
1390 break;
1391 case nsXPTType::T_BOOL:
1392 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1393 ns_v.val.b = (PRBool)PyInt_AsLong(val_use);
1394 break;
1395 case nsXPTType::T_CHAR:{
1396#if PY_MAJOR_VERSION <= 2
1397 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
1398 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
1399 BREAK_FALSE;
1400 }
1401 if ((val_use = PyObject_Str(val))==NULL)
1402 BREAK_FALSE;
1403 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
1404 NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
1405 if (PyString_GET_SIZE(val_use) != 1) {
1406 PyErr_SetString(PyExc_ValueError, "Must specify a one character string for a character");
1407 BREAK_FALSE;
1408 }
1409
1410 ns_v.val.c = *PyString_AS_STRING(val_use);
1411#else
1412 if (!PyUnicode_Check(val)) {
1413 PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object");
1414 BREAK_FALSE;
1415 }
1416 if (PyUnicode_GET_SIZE(val) != 1) {
1417 PyErr_SetString(PyExc_ValueError, "Must specify a one character string for a character");
1418 BREAK_FALSE;
1419 }
1420
1421 ns_v.val.c = *PyUnicode_AS_UNICODE(val_use);
1422#endif
1423 break;
1424 }
1425
1426 case nsXPTType::T_WCHAR: {
1427#if PY_MAJOR_VERSION <= 2
1428 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
1429 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
1430 BREAK_FALSE;
1431 }
1432#else
1433 if (!PyUnicode_Check(val)) {
1434 PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object");
1435 BREAK_FALSE;
1436 }
1437#endif
1438 if ((val_use = PyUnicode_FromObject(val))==NULL)
1439 BREAK_FALSE;
1440 // Sanity check should PyUnicode_FromObject() ever loosen its semantics wrt Unicode!
1441 NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a unicode object!");
1442 if (PyUnicode_GET_SIZE(val_use) != 1) {
1443 PyErr_SetString(PyExc_ValueError, "Must specify a one character string for a character");
1444 BREAK_FALSE;
1445 }
1446 // Lossy!
1447 ns_v.val.wc = *PyUnicode_AS_UNICODE(val_use);
1448 break;
1449 }
1450 // case nsXPTType::T_VOID: /* fall through */
1451 case nsXPTType::T_IID:
1452 nsIID iid;
1453 MAKE_VALUE_BUFFER(sizeof(nsIID));
1454 if (!Py_nsIID::IIDFromPyObject(val, &iid))
1455 BREAK_FALSE;
1456 memcpy(this_buffer_pointer, &iid, sizeof(iid));
1457 ns_v.val.p = this_buffer_pointer;
1458 break;
1459 case nsXPTType::T_ASTRING:
1460 case nsXPTType::T_DOMSTRING: {
1461 nsString *s = new nsString();
1462 if (!s) {
1463 PyErr_NoMemory();
1464 BREAK_FALSE;
1465 }
1466 ns_v.val.p = s;
1467 // We created it - flag as such for cleanup.
1468 ns_v.flags |= nsXPTCVariant::VAL_IS_DOMSTR;
1469
1470 if (!PyObject_AsNSString(val, *s))
1471 BREAK_FALSE;
1472 break;
1473 }
1474 case nsXPTType::T_CSTRING:
1475 case nsXPTType::T_UTF8STRING: {
1476 PRBool bIsUTF8 = XPT_TDP_TAG(ns_v.type) == nsXPTType::T_UTF8STRING;
1477 if (val==Py_None) {
1478 ns_v.val.p = new nsCString();
1479 } else {
1480#if PY_MAJOR_VERSION <= 2
1481 if (PyString_Check(val)) {
1482 // strings are assumed to already be UTF8 encoded.
1483 val_use = val;
1484 Py_INCREF(val);
1485 }
1486 else
1487#endif
1488 if (PyUnicode_Check(val)) {
1489 // Unicode objects are encoded by us.
1490 if (bIsUTF8)
1491 val_use = PyUnicode_AsUTF8String(val);
1492 else
1493#if PY_MAJOR_VERSION <= 2
1494 val_use = PyObject_Str(val);
1495#else
1496 val_use = PyUnicode_AsUTF8String(val);
1497#endif
1498 } else {
1499#if PY_MAJOR_VERSION <= 2
1500 PyErr_SetString(PyExc_TypeError, "UTF8 parameters must be string or Unicode objects");
1501#else
1502 PyErr_SetString(PyExc_TypeError, "UTF8 parameters must be unicode objects");
1503#endif
1504 BREAK_FALSE;
1505 }
1506 if (!val_use)
1507 BREAK_FALSE;
1508#if PY_MAJOR_VERSION <= 2
1509 ns_v.val.p = new nsCString(PyString_AS_STRING(val_use),
1510 PyString_GET_SIZE(val_use));
1511#else
1512 ns_v.val.p = new nsCString(PyBytes_AS_STRING(val_use),
1513 PyBytes_GET_SIZE(val_use));
1514#endif
1515 }
1516
1517 if (!ns_v.val.p) {
1518 PyErr_NoMemory();
1519 BREAK_FALSE;
1520 }
1521 // We created it - flag as such for cleanup.
1522 ns_v.flags |= bIsUTF8 ? nsXPTCVariant::VAL_IS_UTF8STR : nsXPTCVariant::VAL_IS_CSTR;
1523 break;
1524 }
1525 case nsXPTType::T_CHAR_STR: {
1526 if (val==Py_None) {
1527 ns_v.val.p = nsnull;
1528 break;
1529 }
1530#if PY_MAJOR_VERSION <= 2
1531 // If an "in" char *, and we have a PyString, then pass the
1532 // pointer (hoping everyone else plays by the rules too.
1533 if (!XPT_PD_IS_OUT(td.param_flags) && PyString_Check(val)) {
1534 ns_v.val.p = (void *)PyString_AS_STRING(val);
1535 break;
1536 }
1537
1538 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
1539 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
1540 BREAK_FALSE;
1541 }
1542 if ((val_use = PyObject_Str(val))==NULL)
1543 BREAK_FALSE;
1544 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
1545 NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
1546
1547 cb_this_buffer_pointer = PyString_GET_SIZE(val_use)+1;
1548 MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
1549 memcpy(this_buffer_pointer, PyString_AS_STRING(val_use), cb_this_buffer_pointer);
1550#else
1551
1552 if (!PyUnicode_Check(val)) {
1553 PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object");
1554 BREAK_FALSE;
1555 }
1556 if ((val_use = PyUnicode_AsUTF8String(val))==NULL)
1557 BREAK_FALSE;
1558
1559 cb_this_buffer_pointer = PyBytes_GET_SIZE(val_use)+1;
1560 MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
1561 memcpy(this_buffer_pointer, PyBytes_AS_STRING(val_use), cb_this_buffer_pointer);
1562#endif
1563 ns_v.val.p = this_buffer_pointer;
1564 break;
1565 }
1566
1567 case nsXPTType::T_WCHAR_STR: {
1568 if (val==Py_None) {
1569 ns_v.val.p = nsnull;
1570 break;
1571 }
1572#if PY_MAJOR_VERSION <= 2
1573 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
1574 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
1575 BREAK_FALSE;
1576 }
1577 if ((val_use = PyUnicode_FromObject(val))==NULL)
1578 BREAK_FALSE;
1579 NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!");
1580#else
1581 if (!PyUnicode_Check(val)) {
1582 PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object");
1583 BREAK_FALSE;
1584 }
1585 val_use = val;
1586 Py_INCREF(val_use);
1587#endif
1588 PRUnichar *sv;
1589 PRUint32 nch;
1590 if (PyUnicode_AsPRUnichar(val_use, &sv, &nch) < 0)
1591 BREAK_FALSE;
1592 cb_this_buffer_pointer = (nch + 1) * sizeof(PRUnichar);
1593 this_buffer_pointer = sv;
1594 ns_v.val.p = this_buffer_pointer;
1595 break;
1596 }
1597 case nsXPTType::T_INTERFACE: {
1598 nsIID iid;
1599 if (!Py_nsIID::IIDFromPyObject(td.extra, &iid))
1600 BREAK_FALSE;
1601 if (!Py_nsISupports::InterfaceFromPyObject(
1602 val,
1603 iid,
1604 (nsISupports **)&ns_v.val.p,
1605 PR_TRUE))
1606 BREAK_FALSE;
1607 // We have added a reference - flag as such for cleanup.
1608 ns_v.flags |= nsXPTCVariant::VAL_IS_IFACE;
1609 break;
1610 }
1611 case nsXPTType::T_INTERFACE_IS: {
1612 nsIID iid;
1613 nsXPTCVariant &ns_viid = m_var_array[td.argnum];
1614 NS_WARN_IF_FALSE(XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID, "The INTERFACE_IS iid describer isnt an IID!");
1615 // This is a pretty serious problem, but not Python's fault!
1616 // Just return an nsISupports and hope the caller does whatever
1617 // QI they need before using it.
1618 if (XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID &&
1619 XPT_PD_IS_IN(ns_viid.type)) {
1620 nsIID *piid = (nsIID *)ns_viid.val.p;
1621 if (piid==NULL)
1622 // Also serious, but like below, not our fault!
1623 iid = NS_GET_IID(nsISupports);
1624 else
1625 iid = *piid;
1626 } else
1627 // Use NULL IID to avoid a QI in this case.
1628 iid = Py_nsIID_NULL;
1629 if (!Py_nsISupports::InterfaceFromPyObject(
1630 val,
1631 iid,
1632 (nsISupports **)&ns_v.val.p,
1633 PR_TRUE))
1634 BREAK_FALSE;
1635 // We have added a reference - flag as such for cleanup.
1636 ns_v.flags |= nsXPTCVariant::VAL_IS_IFACE;
1637 break;
1638 }
1639 case nsXPTType::T_PSTRING_SIZE_IS: {
1640 if (val==Py_None) {
1641 ns_v.val.p = nsnull;
1642 break;
1643 }
1644#if PY_MAJOR_VERSION <= 2
1645 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
1646 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
1647 BREAK_FALSE;
1648 }
1649 if ((val_use = PyObject_Str(val))==NULL)
1650 BREAK_FALSE;
1651 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
1652 NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
1653
1654 cb_this_buffer_pointer = PyString_GET_SIZE(val_use);
1655 MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
1656 memcpy(this_buffer_pointer, PyString_AS_STRING(val_use), cb_this_buffer_pointer);
1657#else
1658 if (!PyUnicode_Check(val)) {
1659 PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object");
1660 BREAK_FALSE;
1661 }
1662 if ((val_use = PyUnicode_AsUTF8String(val))==NULL)
1663 BREAK_FALSE;
1664
1665 cb_this_buffer_pointer = PyBytes_GET_SIZE(val_use);
1666 MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
1667 memcpy(this_buffer_pointer, PyBytes_AS_STRING(val_use), cb_this_buffer_pointer);
1668#endif
1669 ns_v.val.p = this_buffer_pointer;
1670 rc = SetSizeIs(value_index, PR_TRUE, cb_this_buffer_pointer);
1671 break;
1672 }
1673
1674 case nsXPTType::T_PWSTRING_SIZE_IS: {
1675 if (val==Py_None) {
1676 ns_v.val.p = nsnull;
1677 break;
1678 }
1679#if PY_MAJOR_VERSION <= 2
1680 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
1681 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
1682 BREAK_FALSE;
1683 }
1684 if ((val_use = PyUnicode_FromObject(val))==NULL)
1685 BREAK_FALSE;
1686 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
1687 NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyObject_Unicode didnt return a unicode object!");
1688#else
1689 if (!PyUnicode_Check(val)) {
1690 PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object");
1691 BREAK_FALSE;
1692 }
1693 val_use = val;
1694 Py_INCREF(val_use);
1695#endif
1696 PRUnichar *sv;
1697 PRUint32 nch;
1698 if (PyUnicode_AsPRUnichar(val_use, &sv, &nch) < 0)
1699 BREAK_FALSE;
1700 cb_this_buffer_pointer = (nch + 1) * sizeof(PRUnichar);
1701 this_buffer_pointer = sv;
1702 ns_v.val.p = this_buffer_pointer;
1703 rc = SetSizeIs(value_index, PR_TRUE, nch);
1704 break;
1705 }
1706 case nsXPTType::T_ARRAY: {
1707 if (val==Py_None) {
1708 ns_v.val.p = nsnull;
1709 break;
1710 }
1711 if (!PyInt_Check(td.extra)) {
1712 PyErr_SetString(PyExc_TypeError, "The array info is not valid");
1713 BREAK_FALSE;
1714 }
1715 if (!PySequence_Check(val)) {
1716 PyErr_SetString(PyExc_TypeError, "This parameter must be a sequence");
1717 BREAK_FALSE;
1718 }
1719 int array_type = PyInt_AsLong(td.extra);
1720 PRUint32 element_size = GetArrayElementSize(array_type);
1721 int seq_length = PySequence_Length(val);
1722 cb_this_buffer_pointer = seq_length * element_size;
1723 if (cb_this_buffer_pointer==0)
1724 // prevent assertions allocing zero bytes. Can't use NULL.
1725 cb_this_buffer_pointer = 1;
1726 MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
1727 memset(this_buffer_pointer, 0, cb_this_buffer_pointer);
1728 rc = FillSingleArray(this_buffer_pointer, val, seq_length, element_size, array_type&XPT_TDP_TAGMASK, nsnull);
1729 if (!rc) break;
1730 rc = SetSizeIs(value_index, PR_FALSE, seq_length);
1731 if (!rc) break;
1732 ns_v.flags |= nsXPTCVariant::VAL_IS_ARRAY;
1733 ns_v.val.p = this_buffer_pointer;
1734 break;
1735 }
1736 default:
1737 PyErr_Format(PyExc_TypeError, "The object type (0x%x) is unknown", XPT_TDP_TAG(ns_v.type));
1738 rc = PR_FALSE;
1739 break;
1740 }
1741 Py_DECREF(val); // Cant be NULL!
1742 Py_XDECREF(val_use);
1743 }
1744 return rc && !PyErr_Occurred();
1745}
1746
1747PRBool PyXPCOM_InterfaceVariantHelper::PrepareOutVariant(const PythonTypeDescriptor &td, int value_index)
1748{
1749 PRBool rc = PR_TRUE;
1750 nsXPTCVariant &ns_v = m_var_array[value_index];
1751 void *&this_buffer_pointer = m_buffer_array[value_index]; // Freed at object destruction with PyMem_Free()
1752 // Do the out param thang...
1753 if (XPT_PD_IS_OUT(td.param_flags) || XPT_PD_IS_DIPPER(td.param_flags)) {
1754 NS_ABORT_IF_FALSE(ns_v.ptr == NULL, "already have a pointer!");
1755 ns_v.ptr = &ns_v;
1756 ns_v.flags |= nsXPTCVariant::PTR_IS_DATA;
1757
1758 // Special flags based on the data type
1759 switch (XPT_TDP_TAG(ns_v.type)) {
1760 case nsXPTType::T_I8:
1761 case nsXPTType::T_I16:
1762 case nsXPTType::T_I32:
1763 case nsXPTType::T_I64:
1764 case nsXPTType::T_U8:
1765 case nsXPTType::T_U16:
1766 case nsXPTType::T_U32:
1767 case nsXPTType::T_U64:
1768 case nsXPTType::T_FLOAT:
1769 case nsXPTType::T_DOUBLE:
1770 case nsXPTType::T_BOOL:
1771 case nsXPTType::T_CHAR:
1772 case nsXPTType::T_WCHAR:
1773 case nsXPTType::T_VOID:
1774 break;
1775
1776 case nsXPTType::T_INTERFACE:
1777 case nsXPTType::T_INTERFACE_IS:
1778 NS_ABORT_IF_FALSE(this_buffer_pointer==NULL, "Can't have an interface and a buffer pointer!");
1779 ns_v.flags |= nsXPTCVariant::VAL_IS_IFACE;
1780 ns_v.flags |= nsXPTCVariant::VAL_IS_ALLOCD;
1781 break;
1782 case nsXPTType::T_ARRAY:
1783 ns_v.flags |= nsXPTCVariant::VAL_IS_ARRAY;
1784 ns_v.flags |= nsXPTCVariant::VAL_IS_ALLOCD;
1785 // Even if ns_val.p already setup as part of "in" processing,
1786 // we need to ensure setup for out.
1787 NS_ABORT_IF_FALSE(ns_v.val.p==nsnull || ns_v.val.p==this_buffer_pointer, "Garbage in our pointer?");
1788 ns_v.val.p = this_buffer_pointer;
1789 this_buffer_pointer = nsnull;
1790 break;
1791 case nsXPTType::T_PWSTRING_SIZE_IS:
1792 case nsXPTType::T_PSTRING_SIZE_IS:
1793 case nsXPTType::T_WCHAR_STR:
1794 case nsXPTType::T_CHAR_STR:
1795 case nsXPTType::T_IID:
1796 // If we stashed a value in the this_buffer_pointer, and
1797 // we are passing it as an OUT param, we do _not_ want to
1798 // treat it as a temporary buffer.
1799 // For example, if we pass an IID or string as an IN param,
1800 // we allocate a buffer for the value, but this is NOT cleaned up
1801 // via normal VARIANT cleanup rules - hence we clean it up ourselves.
1802 // If the param is IN/OUT, then the buffer falls under the normal variant
1803 // rules (ie, is flagged as VAL_IS_ALLOCD), so we dont clean it as a temporary.
1804 // (it may have been changed under us - we free the _new_ value.
1805 // Even if ns_val.p already setup as part of "in" processing,
1806 // we need to ensure setup for out.
1807 NS_ABORT_IF_FALSE(ns_v.val.p==nsnull || ns_v.val.p==this_buffer_pointer, "Garbage in our pointer?");
1808 ns_v.val.p = this_buffer_pointer;
1809 ns_v.flags |= nsXPTCVariant::VAL_IS_ALLOCD;
1810 this_buffer_pointer = nsnull;
1811 break;
1812 case nsXPTType::T_DOMSTRING:
1813 case nsXPTType::T_ASTRING: {
1814 NS_ABORT_IF_FALSE(ns_v.val.p==nsnull, "T_DOMTSTRINGS cant be out and have a value (ie, no in/outs are allowed!");
1815 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!");
1816 ns_v.flags |= nsXPTCVariant::VAL_IS_DOMSTR;
1817 // Dippers are really treated like "in" params.
1818 ns_v.ptr = new nsString();
1819 ns_v.val.p = ns_v.ptr; // VAL_IS_* says the .p is what gets freed
1820 if (!ns_v.ptr) {
1821 PyErr_NoMemory();
1822 rc = PR_FALSE;
1823 }
1824 break;
1825 }
1826 case nsXPTType::T_CSTRING:
1827 case nsXPTType::T_UTF8STRING: {
1828 NS_ABORT_IF_FALSE(ns_v.val.p==nsnull, "T_DOMTSTRINGS cant be out and have a value (ie, no in/outs are allowed!");
1829 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!");
1830 ns_v.flags |= ( XPT_TDP_TAG(ns_v.type)==nsXPTType::T_CSTRING ? nsXPTCVariant::VAL_IS_CSTR : nsXPTCVariant::VAL_IS_UTF8STR);
1831 ns_v.ptr = new nsCString();
1832 ns_v.val.p = ns_v.ptr; // VAL_IS_* says the .p is what gets freed
1833 if (!ns_v.ptr) {
1834 PyErr_NoMemory();
1835 rc = PR_FALSE;
1836 }
1837 break;
1838 }
1839 default:
1840 NS_ABORT_IF_FALSE(0, "Unknown type - don't know how to prepare the output value");
1841 break; // Nothing to do!
1842 }
1843 }
1844 return rc;
1845}
1846
1847
1848PyObject *PyXPCOM_InterfaceVariantHelper::MakeSinglePythonResult(int index)
1849{
1850 nsXPTCVariant &ns_v = m_var_array[index];
1851 PyObject *ret = nsnull;
1852 NS_ABORT_IF_FALSE(ns_v.IsPtrData() || ns_v.IsValDOMString(), "expecting a pointer if you want a result!");
1853
1854 // Re-fetch the type descriptor.
1855 PythonTypeDescriptor &td = m_python_type_desc_array[index];
1856 // Make sure the type tag of the variant hasnt changed on us.
1857 NS_ABORT_IF_FALSE(ns_v.type==td.type_flags, "variant type has changed under us!");
1858
1859 // If the pointer is NULL, we can get out now!
1860 if (ns_v.ptr==nsnull) {
1861 Py_INCREF(Py_None);
1862 return Py_None;
1863 }
1864
1865 switch (XPT_TDP_TAG(ns_v.type)) {
1866 case nsXPTType::T_I8:
1867 ret = PyInt_FromLong( *((PRInt8 *)ns_v.ptr) );
1868 break;
1869 case nsXPTType::T_I16:
1870 ret = PyInt_FromLong( *((PRInt16 *)ns_v.ptr) );
1871 break;
1872 case nsXPTType::T_I32:
1873 ret = PyInt_FromLong( *((PRInt32 *)ns_v.ptr) );
1874 break;
1875 case nsXPTType::T_I64:
1876 ret = PyLong_FromLongLong( *((PRInt64 *)ns_v.ptr) );
1877 break;
1878 case nsXPTType::T_U8:
1879 ret = PyInt_FromLong( *((PRUint8 *)ns_v.ptr) );
1880 break;
1881 case nsXPTType::T_U16:
1882 ret = PyInt_FromLong( *((PRUint16 *)ns_v.ptr) );
1883 break;
1884 case nsXPTType::T_U32:
1885 ret = PyInt_FromLong( *((PRUint32 *)ns_v.ptr) );
1886 break;
1887 case nsXPTType::T_U64:
1888 ret = PyLong_FromUnsignedLongLong( *((PRUint64 *)ns_v.ptr) );
1889 break;
1890 case nsXPTType::T_FLOAT:
1891 ret = PyFloat_FromDouble( *((float *)ns_v.ptr) );
1892 break;
1893 case nsXPTType::T_DOUBLE:
1894 ret = PyFloat_FromDouble( *((double *)ns_v.ptr) );
1895 break;
1896 case nsXPTType::T_BOOL:
1897 ret = *((PRBool *)ns_v.ptr) ? Py_True : Py_False;
1898 Py_INCREF(ret);
1899 break;
1900 case nsXPTType::T_CHAR:
1901#if PY_MAJOR_VERSION <= 2
1902 ret = PyString_FromStringAndSize( ((char *)ns_v.ptr), 1 );
1903#else
1904 ret = PyUnicode_FromStringAndSize( ((char *)ns_v.ptr), 1 );
1905#endif
1906 break;
1907
1908 case nsXPTType::T_WCHAR:
1909 ret = PyUnicode_FromPRUnichar( ((PRUnichar *)ns_v.ptr), 1 );
1910 break;
1911// case nsXPTType::T_VOID:
1912 case nsXPTType::T_IID:
1913 ret = Py_nsIID::PyObjectFromIID( **((nsIID **)ns_v.ptr) );
1914 break;
1915 case nsXPTType::T_ASTRING:
1916 case nsXPTType::T_DOMSTRING: {
1917 nsAString *rs = (nsAString *)ns_v.ptr;
1918 ret = PyObject_FromNSString(*rs);
1919 break;
1920 }
1921 case nsXPTType::T_UTF8STRING:
1922 case nsXPTType::T_CSTRING: {
1923 nsCString *rs = (nsCString *)ns_v.ptr;
1924 ret = PyObject_FromNSString(*rs, XPT_TDP_TAG(ns_v.type)==nsXPTType::T_UTF8STRING);
1925 break;
1926 }
1927
1928 case nsXPTType::T_CHAR_STR:
1929 if (*((char **)ns_v.ptr) == NULL) {
1930 ret = Py_None;
1931 Py_INCREF(Py_None);
1932 } else
1933#if PY_MAJOR_VERSION <= 2
1934 ret = PyString_FromString( *((char **)ns_v.ptr) );
1935#else
1936 ret = PyUnicode_FromString( *((char **)ns_v.ptr) );
1937#endif
1938 break;
1939
1940 case nsXPTType::T_WCHAR_STR: {
1941 PRUnichar *us = *((PRUnichar **)ns_v.ptr);
1942 if (us == NULL) {
1943 ret = Py_None;
1944 Py_INCREF(Py_None);
1945 } else {
1946 ret = PyUnicode_FromPRUnichar( us, nsCRT::strlen(us));
1947 }
1948 break;
1949 }
1950 case nsXPTType::T_INTERFACE: {
1951 nsIID iid;
1952 if (!Py_nsIID::IIDFromPyObject(td.extra, &iid))
1953 break;
1954 nsISupports *iret = *((nsISupports **)ns_v.ptr);
1955 // Our cleanup code manages iret reference ownership, and our
1956 // new object takes its own.
1957 if (iid.Equals(NS_GET_IID(nsIVariant)))
1958 ret = PyObject_FromVariant(m_parent, (nsIVariant *)iret);
1959 else
1960 ret = m_parent->MakeInterfaceResult(iret, iid);
1961 break;
1962 }
1963 case nsXPTType::T_INTERFACE_IS: {
1964 nsIID iid;
1965 nsXPTCVariant &ns_viid = m_var_array[td.argnum];
1966 NS_WARN_IF_FALSE(XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID, "The INTERFACE_IS iid describer isnt an IID!");
1967 if (XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID) {
1968 nsIID *piid = (nsIID *)ns_viid.val.p;
1969 if (piid==NULL)
1970 // Also serious, but like below, not our fault!
1971 iid = NS_GET_IID(nsISupports);
1972 else
1973 iid = *piid;
1974 } else {
1975 // This is a pretty serious problem, but not Python's fault!
1976 // Just return an nsISupports and hope the caller does whatever
1977 // QI they need before using it.
1978 NS_ERROR("Failed to get the IID for T_INTERFACE_IS!");
1979 iid = NS_GET_IID(nsISupports);
1980 }
1981 nsISupports *iret = *((nsISupports **)ns_v.ptr);
1982 if (iid.Equals(NS_GET_IID(nsIVariant)))
1983 ret = PyObject_FromVariant(m_parent, (nsIVariant *)iret);
1984 else
1985 ret = m_parent->MakeInterfaceResult(iret, iid);
1986 break;
1987 }
1988 case nsXPTType::T_ARRAY: {
1989 if ( (* ((void **)ns_v.ptr)) == NULL) {
1990 ret = Py_None;
1991 Py_INCREF(Py_None);
1992 }
1993 if (!PyInt_Check(td.extra)) {
1994 PyErr_SetString(PyExc_TypeError, "The array info is not valid");
1995 break;
1996 }
1997 PRUint8 array_type = (PRUint8)PyInt_AsLong(td.extra);
1998 PRUint32 seq_size = GetSizeIs(index, PR_FALSE);
1999 nsXPTCVariant &ns_viid = m_var_array[td.argnum];
2000 nsIID iid;
2001 nsresult res = GetArrayElementIID(m_parent,
2002 m_var_array,
2003 m_methodindex,
2004 index,
2005 &iid);
2006 ret = UnpackSingleArray(m_parent, * ((void **)ns_v.ptr),
2007 seq_size, array_type&XPT_TDP_TAGMASK,
2008 NS_SUCCEEDED(res) ? &iid : NULL);
2009 break;
2010 }
2011
2012 case nsXPTType::T_PSTRING_SIZE_IS:
2013 if (*((char **)ns_v.ptr) == NULL) {
2014 ret = Py_None;
2015 Py_INCREF(Py_None);
2016 } else {
2017 PRUint32 string_size = GetSizeIs(index, PR_TRUE);
2018#if PY_MAJOR_VERSION <= 2
2019 ret = PyString_FromStringAndSize( *((char **)ns_v.ptr), string_size );
2020#else
2021 ret = PyUnicode_FromStringAndSize( *((char **)ns_v.ptr), string_size );
2022#endif
2023 }
2024 break;
2025
2026 case nsXPTType::T_PWSTRING_SIZE_IS:
2027 if (*((PRUnichar **)ns_v.ptr) == NULL) {
2028 ret = Py_None;
2029 Py_INCREF(Py_None);
2030 } else {
2031 PRUint32 string_size = GetSizeIs(index, PR_TRUE);
2032 ret = PyUnicode_FromPRUnichar( *((PRUnichar **)ns_v.ptr), string_size );
2033 }
2034 break;
2035 default:
2036 PyErr_Format(PyExc_ValueError, "Unknown XPCOM type code (0x%x)", XPT_TDP_TAG(ns_v.type));
2037 /* ret remains nsnull */
2038 break;
2039 }
2040 return ret;
2041}
2042
2043
2044PyObject *PyXPCOM_InterfaceVariantHelper::MakePythonResult()
2045{
2046 // First we count the results.
2047 int i = 0;
2048 int n_results = 0;
2049 PyObject *ret = NULL;
2050 PRBool have_retval = PR_FALSE;
2051 for (i=0;i<m_num_array;i++) {
2052 PythonTypeDescriptor &td = m_python_type_desc_array[i];
2053 if (!td.is_auto_out) {
2054 if (XPT_PD_IS_OUT(td.param_flags) || XPT_PD_IS_DIPPER(td.param_flags))
2055 n_results++;
2056 if (XPT_PD_IS_RETVAL(td.param_flags))
2057 have_retval = PR_TRUE;
2058 }
2059 }
2060 if (n_results==0) {
2061 ret = Py_None;
2062 Py_INCREF(ret);
2063 } else {
2064 if (n_results > 1) {
2065 ret = PyTuple_New(n_results);
2066 if (ret==NULL)
2067 return NULL;
2068 }
2069 int ret_index = 0;
2070 int max_index = m_num_array;
2071 // Stick the retval at the front if we have have
2072 if (have_retval && n_results > 1) {
2073 PyObject *val = MakeSinglePythonResult(m_num_array-1);
2074 if (val==NULL) {
2075 Py_DECREF(ret);
2076 return NULL;
2077 }
2078 PyTuple_SET_ITEM(ret, 0, val);
2079 max_index--;
2080 ret_index++;
2081
2082 }
2083 for (i=0;ret_index < n_results && i < max_index;i++) {
2084 if (!m_python_type_desc_array[i].is_auto_out) {
2085 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)) {
2086 PyObject *val = MakeSinglePythonResult(i);
2087 if (val==NULL) {
2088 Py_XDECREF(ret);
2089 return NULL;
2090 }
2091 if (n_results > 1) {
2092 PyTuple_SET_ITEM(ret, ret_index, val);
2093 ret_index++;
2094 } else {
2095 NS_ABORT_IF_FALSE(ret==NULL, "shouldnt already have a ret!");
2096 ret = val;
2097 }
2098 }
2099 }
2100 }
2101
2102 }
2103 return ret;
2104}
2105
2106/*************************************************************************
2107**************************************************************************
2108
2109 Helpers when IMPLEMENTING interfaces.
2110
2111**************************************************************************
2112*************************************************************************/
2113
2114PyXPCOM_GatewayVariantHelper::PyXPCOM_GatewayVariantHelper( PyG_Base *gw, int method_index, const nsXPTMethodInfo *info, nsXPTCMiniVariant* params )
2115{
2116 m_params = params;
2117 m_info = info;
2118 // no references added - this class is only alive for
2119 // a single gateway invocation
2120 m_gateway = gw;
2121 m_method_index = method_index;
2122 m_python_type_desc_array = NULL;
2123 m_num_type_descs = 0;
2124}
2125
2126PyXPCOM_GatewayVariantHelper::~PyXPCOM_GatewayVariantHelper()
2127{
2128 delete [] m_python_type_desc_array;
2129}
2130
2131PyObject *PyXPCOM_GatewayVariantHelper::MakePyArgs()
2132{
2133 NS_PRECONDITION(sizeof(XPTParamDescriptor) == sizeof(nsXPTParamInfo), "We depend on nsXPTParamInfo being a wrapper over the XPTParamDescriptor struct");
2134 // Setup our array of Python typedescs, and determine the number of objects we
2135 // pass to Python.
2136 m_num_type_descs = m_info->num_args;
2137 m_python_type_desc_array = new PythonTypeDescriptor[m_num_type_descs];
2138 if (m_python_type_desc_array==nsnull)
2139 return PyErr_NoMemory();
2140
2141 // First loop to count the number of objects
2142 // we pass to Python
2143 int i;
2144 for (i=0;i<m_info->num_args;i++) {
2145 nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+i;
2146 PythonTypeDescriptor &td = m_python_type_desc_array[i];
2147 td.param_flags = pi->flags;
2148 td.type_flags = pi->type.prefix.flags;
2149 td.argnum = pi->type.argnum;
2150 td.argnum2 = pi->type.argnum2;
2151 }
2152 int num_args = ProcessPythonTypeDescriptors(m_python_type_desc_array, m_num_type_descs);
2153 PyObject *ret = PyTuple_New(num_args);
2154 if (ret==NULL)
2155 return NULL;
2156 int this_arg = 0;
2157 for (i=0;i<m_num_type_descs;i++) {
2158 PythonTypeDescriptor &td = m_python_type_desc_array[i];
2159 if (XPT_PD_IS_IN(td.param_flags) && !td.is_auto_in && !XPT_PD_IS_DIPPER(td.param_flags)) {
2160 PyObject *sub = MakeSingleParam( i, td );
2161 if (sub==NULL) {
2162 Py_DECREF(ret);
2163 return NULL;
2164 }
2165 NS_ABORT_IF_FALSE(this_arg>=0 && this_arg<num_args, "We are going off the end of the array!");
2166 PyTuple_SET_ITEM(ret, this_arg, sub);
2167 this_arg++;
2168 }
2169 }
2170 return ret;
2171}
2172
2173PRBool PyXPCOM_GatewayVariantHelper::CanSetSizeIs( int var_index, PRBool is_arg1 )
2174{
2175 NS_ABORT_IF_FALSE(var_index < m_num_type_descs, "var_index param is invalid");
2176 PRUint8 argnum = is_arg1 ?
2177 m_python_type_desc_array[var_index].argnum :
2178 m_python_type_desc_array[var_index].argnum2;
2179 NS_ABORT_IF_FALSE(argnum < m_num_type_descs, "size_is param is invalid");
2180 return XPT_PD_IS_OUT(m_python_type_desc_array[argnum].param_flags);
2181}
2182
2183PRBool PyXPCOM_GatewayVariantHelper::SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size)
2184{
2185 NS_ABORT_IF_FALSE(var_index < m_num_type_descs, "var_index param is invalid");
2186 PRUint8 argnum = is_arg1 ?
2187 m_python_type_desc_array[var_index].argnum :
2188 m_python_type_desc_array[var_index].argnum2;
2189 NS_ABORT_IF_FALSE(argnum < m_num_type_descs, "size_is param is invalid");
2190 PythonTypeDescriptor &td_size = m_python_type_desc_array[argnum];
2191 NS_ABORT_IF_FALSE( XPT_PD_IS_OUT(td_size.param_flags), "size param must be out if we want to set it!");
2192 NS_ABORT_IF_FALSE(td_size.is_auto_out, "Setting size_is, but param is not marked as auto!");
2193
2194 nsXPTCMiniVariant &ns_v = m_params[argnum];
2195 NS_ABORT_IF_FALSE( (td_size.type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32");
2196 NS_ABORT_IF_FALSE(ns_v.val.p, "NULL pointer for size_is value!");
2197 if (ns_v.val.p) {
2198 if (!td_size.have_set_auto) {
2199 *((PRUint32 *)ns_v.val.p) = new_size;
2200 td_size.have_set_auto = PR_TRUE;
2201 } else {
2202 if (*((PRUint32 *)ns_v.val.p) != new_size ) {
2203 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);
2204 return PR_FALSE;
2205 }
2206 }
2207 }
2208 return PR_TRUE;
2209}
2210
2211PRUint32 PyXPCOM_GatewayVariantHelper::GetSizeIs( int var_index, PRBool is_arg1)
2212{
2213 NS_ABORT_IF_FALSE(var_index < m_num_type_descs, "var_index param is invalid");
2214 PRUint8 argnum = is_arg1 ?
2215 m_python_type_desc_array[var_index].argnum :
2216 m_python_type_desc_array[var_index].argnum2;
2217 NS_ABORT_IF_FALSE(argnum < m_num_type_descs, "size_is param is invalid");
2218 if (argnum >= m_num_type_descs) {
2219 PyErr_SetString(PyExc_ValueError, "dont have a valid size_is indicator for this param");
2220 return PR_FALSE;
2221 }
2222 PRBool is_out = XPT_PD_IS_OUT(m_python_type_desc_array[argnum].param_flags);
2223 nsXPTCMiniVariant &ns_v = m_params[argnum];
2224 NS_ABORT_IF_FALSE( (m_python_type_desc_array[argnum].type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32");
2225 return is_out ? *((PRUint32 *)ns_v.val.p) : ns_v.val.u32;
2226}
2227
2228#undef DEREF_IN_OR_OUT
2229#define DEREF_IN_OR_OUT( element, ret_type ) (ret_type)(is_out ? *((ret_type *)ns_v.val.p) : (ret_type)(element))
2230
2231PyObject *PyXPCOM_GatewayVariantHelper::MakeSingleParam(int index, PythonTypeDescriptor &td)
2232{
2233 NS_PRECONDITION(XPT_PD_IS_IN(td.param_flags), "Must be an [in] param!");
2234 nsXPTCMiniVariant &ns_v = m_params[index];
2235 PyObject *ret = NULL;
2236 PRBool is_out = XPT_PD_IS_OUT(td.param_flags);
2237
2238 switch (td.type_flags & XPT_TDP_TAGMASK) {
2239 case nsXPTType::T_I8:
2240 ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.i8, PRInt8 ) );
2241 break;
2242 case nsXPTType::T_I16:
2243 ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.i16, PRInt16) );
2244 break;
2245 case nsXPTType::T_I32:
2246 ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.i32, PRInt32) );
2247 break;
2248 case nsXPTType::T_I64:
2249 ret = PyLong_FromLongLong( DEREF_IN_OR_OUT(ns_v.val.i64, PRInt64) );
2250 break;
2251 case nsXPTType::T_U8:
2252 ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.u8, PRUint8) );
2253 break;
2254 case nsXPTType::T_U16:
2255 ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.u16, PRUint16) );
2256 break;
2257 case nsXPTType::T_U32:
2258 ret = PyInt_FromLong( DEREF_IN_OR_OUT(ns_v.val.u32, PRUint32) );
2259 break;
2260 case nsXPTType::T_U64:
2261 ret = PyLong_FromUnsignedLongLong( DEREF_IN_OR_OUT(ns_v.val.u64, PRUint64) );
2262 break;
2263 case nsXPTType::T_FLOAT:
2264 ret = PyFloat_FromDouble( DEREF_IN_OR_OUT(ns_v.val.f, float) );
2265 break;
2266 case nsXPTType::T_DOUBLE:
2267 ret = PyFloat_FromDouble( DEREF_IN_OR_OUT(ns_v.val.d, double) );
2268 break;
2269 case nsXPTType::T_BOOL: {
2270 PRBool temp = DEREF_IN_OR_OUT(ns_v.val.b, PRBool);
2271 ret = temp ? Py_True : Py_False;
2272 Py_INCREF(ret);
2273 break;
2274 }
2275 case nsXPTType::T_CHAR: {
2276 char temp = DEREF_IN_OR_OUT(ns_v.val.c, char);
2277#if PY_MAJOR_VERSION <= 2
2278 ret = PyString_FromStringAndSize(&temp, 1);
2279#else
2280 ret = PyUnicode_FromStringAndSize(&temp, 1);
2281#endif
2282 break;
2283 }
2284 case nsXPTType::T_WCHAR: {
2285 PRUnichar temp = (PRUnichar)DEREF_IN_OR_OUT(ns_v.val.wc, PRUnichar);
2286 ret = PyUnicode_FromPRUnichar(&temp, 1);
2287 break;
2288 }
2289// case nsXPTType::T_VOID:
2290 case nsXPTType::T_IID: {
2291 ret = Py_nsIID::PyObjectFromIID( * DEREF_IN_OR_OUT(ns_v.val.p, const nsIID *) );
2292 break;
2293 }
2294 case nsXPTType::T_ASTRING:
2295 case nsXPTType::T_DOMSTRING: {
2296 NS_ABORT_IF_FALSE(is_out || !XPT_PD_IS_DIPPER(td.param_flags), "DOMStrings can't be inout");
2297 const nsAString *rs = (const nsAString *)ns_v.val.p;
2298 ret = PyObject_FromNSString(*rs);
2299 break;
2300 }
2301 case nsXPTType::T_CSTRING:
2302 case nsXPTType::T_UTF8STRING: {
2303 NS_ABORT_IF_FALSE(is_out || !XPT_PD_IS_DIPPER(td.param_flags), "DOMStrings can't be inout");
2304 const nsCString *rs = (const nsCString *)ns_v.val.p;
2305 ret = PyObject_FromNSString(*rs, (td.type_flags & XPT_TDP_TAGMASK)==nsXPTType::T_UTF8STRING);
2306 break;
2307 }
2308 case nsXPTType::T_CHAR_STR: {
2309 char *t = DEREF_IN_OR_OUT(ns_v.val.p, char *);
2310 if (t==NULL) {
2311 ret = Py_None;
2312 Py_INCREF(Py_None);
2313 } else
2314#if PY_MAJOR_VERSION <= 2
2315 ret = PyString_FromString(t);
2316#else
2317 ret = PyUnicode_FromString(t);
2318#endif
2319 break;
2320 }
2321
2322 case nsXPTType::T_WCHAR_STR: {
2323 PRUnichar *us = DEREF_IN_OR_OUT(ns_v.val.p, PRUnichar *);
2324 if (us==NULL) {
2325 ret = Py_None;
2326 Py_INCREF(Py_None);
2327 } else {
2328 ret = PyUnicode_FromPRUnichar( us, nsCRT::strlen(us));
2329 }
2330 break;
2331 }
2332 case nsXPTType::T_INTERFACE_IS: // our Python code does it :-)
2333 case nsXPTType::T_INTERFACE: {
2334 nsISupports *iret = DEREF_IN_OR_OUT(ns_v.val.p, nsISupports *);
2335 nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index;
2336 ret = m_gateway->MakeInterfaceParam(iret, NULL, m_method_index, pi, index);
2337 break;
2338 }
2339/***
2340 nsISupports *iret = DEREF_IN_OR_OUT(ns_v.val.p, nsISupports *);
2341 nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index;
2342 nsXPTCMiniVariant &ns_viid = m_params[td.argnum];
2343 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!");
2344 const nsIID * iid = NULL;
2345 if (XPT_PD_IS_IN(m_python_type_desc_array[td.argnum].param_flags))
2346 // may still be inout!
2347 iid = DEREF_IN_OR_OUT(ns_v.val.p, const nsIID *);
2348
2349 ret = m_gateway->MakeInterfaceParam(iret, iid, m_method_index, pi, index);
2350 break;
2351 }
2352****/
2353 case nsXPTType::T_ARRAY: {
2354 void *t = DEREF_IN_OR_OUT(ns_v.val.p, void *);
2355 if (t==NULL) {
2356 // JS may send us a NULL here occasionally - as the
2357 // type is array, we silently convert this to a zero
2358 // length list, a-la JS.
2359 ret = PyList_New(0);
2360 } else {
2361 PRUint8 array_type;
2362 nsIID *piid;
2363 nsresult ns = GetArrayType(index, &array_type, &piid);
2364 if (NS_FAILED(ns)) {
2365 PyXPCOM_BuildPyException(ns);
2366 break;
2367 }
2368 PRUint32 seq_size = GetSizeIs(index, PR_FALSE);
2369 ret = UnpackSingleArray(NULL, t, seq_size, array_type&XPT_TDP_TAGMASK, piid);
2370 }
2371 break;
2372 }
2373 case nsXPTType::T_PSTRING_SIZE_IS: {
2374 char *t = DEREF_IN_OR_OUT(ns_v.val.p, char *);
2375 PRUint32 string_size = GetSizeIs(index, PR_TRUE);
2376 if (t==NULL) {
2377 ret = Py_None;
2378 Py_INCREF(Py_None);
2379 } else
2380#if PY_MAJOR_VERSION <= 2
2381 ret = PyString_FromStringAndSize(t, string_size);
2382#else
2383 ret = PyUnicode_FromStringAndSize(t, string_size);
2384#endif
2385 break;
2386 }
2387 case nsXPTType::T_PWSTRING_SIZE_IS: {
2388 PRUnichar *t = DEREF_IN_OR_OUT(ns_v.val.p, PRUnichar *);
2389 PRUint32 string_size = GetSizeIs(index, PR_TRUE);
2390 if (t==NULL) {
2391 ret = Py_None;
2392 Py_INCREF(Py_None);
2393 } else {
2394 ret = PyUnicode_FromPRUnichar(t, string_size);
2395 }
2396 break;
2397 }
2398 default:
2399 // As this is called by external components,
2400 // we return _something_ rather than failing before any user code has run!
2401 {
2402 char buf[128];
2403 sprintf(buf, "Unknown XPCOM type flags (0x%x)", td.type_flags);
2404 PyXPCOM_LogWarning("%s - returning a string object with this message!\n", buf);
2405#if PY_MAJOR_VERSION <= 2
2406 ret = PyString_FromString(buf);
2407#else
2408 ret = PyUnicode_FromString(buf);
2409#endif
2410 break;
2411 }
2412 }
2413 return ret;
2414}
2415
2416nsresult PyXPCOM_GatewayVariantHelper::GetArrayType(PRUint8 index, PRUint8 *ret, nsIID **iid)
2417{
2418 nsCOMPtr<nsIInterfaceInfoManager> iim(do_GetService(
2419 NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
2420 NS_ABORT_IF_FALSE(iim != nsnull, "Cant get interface from IIM!");
2421 if (iim==nsnull)
2422 return NS_ERROR_FAILURE;
2423
2424 nsCOMPtr<nsIInterfaceInfo> ii;
2425 nsresult rc = iim->GetInfoForIID( &m_gateway->m_iid, getter_AddRefs(ii));
2426 if (NS_FAILED(rc))
2427 return rc;
2428 nsXPTType datumType;
2429 const nsXPTParamInfo& param_info = m_info->GetParam((PRUint8)index);
2430 rc = ii->GetTypeForParam(m_method_index, &param_info, 1, &datumType);
2431 if (NS_FAILED(rc))
2432 return rc;
2433 if (iid) {
2434 *iid = (nsIID *)&NS_GET_IID(nsISupports);
2435 if (XPT_TDP_TAG(datumType)==nsXPTType::T_INTERFACE ||
2436 XPT_TDP_TAG(datumType)==nsXPTType::T_INTERFACE_IS ||
2437 XPT_TDP_TAG(datumType)==nsXPTType::T_ARRAY)
2438 ii->GetIIDForParam(m_method_index, &param_info, iid);
2439 }
2440 *ret = datumType.flags;
2441 return NS_OK;
2442}
2443
2444PRBool PyXPCOM_GatewayVariantHelper::GetIIDForINTERFACE_ID(int index, const nsIID **ppret)
2445{
2446 // Not sure if the IID pointed at by by this is allows to be
2447 // in or out, so we will allow it.
2448 nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index;
2449 nsXPTType typ = pi->GetType();
2450 NS_WARN_IF_FALSE(XPT_TDP_TAG(typ) == nsXPTType::T_IID, "INTERFACE_IS IID param isnt an IID!");
2451 NS_ABORT_IF_FALSE(typ.IsPointer(), "Expecting to re-fill a pointer value.");
2452 if (XPT_TDP_TAG(typ) != nsXPTType::T_IID)
2453 *ppret = &NS_GET_IID(nsISupports);
2454 else {
2455 nsXPTCMiniVariant &ns_v = m_params[index];
2456 if (pi->IsOut()) {
2457 nsIID **pp = (nsIID **)ns_v.val.p;
2458 if (pp && *pp)
2459 *ppret = *pp;
2460 else
2461 *ppret = &NS_GET_IID(nsISupports);
2462 } else if (pi->IsIn()) {
2463 nsIID *p = (nsIID *)ns_v.val.p;
2464 if (p)
2465 *ppret = p;
2466 else
2467 *ppret = &NS_GET_IID(nsISupports);
2468 } else {
2469 NS_ERROR("Param is not in or out!");
2470 *ppret = &NS_GET_IID(nsISupports);
2471 }
2472 }
2473 return PR_TRUE;
2474}
2475
2476nsIInterfaceInfo *PyXPCOM_GatewayVariantHelper::GetInterfaceInfo()
2477{
2478 if (!m_interface_info) {
2479 nsCOMPtr<nsIInterfaceInfoManager> iim(do_GetService(
2480 NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
2481 if (iim)
2482 iim->GetInfoForIID(&m_gateway->m_iid, getter_AddRefs(m_interface_info));
2483 }
2484 return m_interface_info;
2485}
2486
2487#undef FILL_SIMPLE_POINTER
2488#define FILL_SIMPLE_POINTER( type, ob ) *((type *)ns_v.val.p) = (type)(ob)
2489
2490nsresult PyXPCOM_GatewayVariantHelper::BackFillVariant( PyObject *val, int index)
2491{
2492 nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+index;
2493 NS_ABORT_IF_FALSE(pi->IsOut() || pi->IsDipper(), "The value must be marked as [out] (or a dipper) to be back-filled!");
2494 NS_ABORT_IF_FALSE(!pi->IsShared(), "Dont know how to back-fill a shared out param");
2495 nsXPTCMiniVariant &ns_v = m_params[index];
2496
2497 nsXPTType typ = pi->GetType();
2498 PyObject* val_use = NULL;
2499
2500 NS_ABORT_IF_FALSE(pi->IsDipper() || ns_v.val.p, "No space for result!");
2501 if (!pi->IsDipper() && !ns_v.val.p) return NS_ERROR_INVALID_POINTER;
2502
2503 PRBool rc = PR_TRUE;
2504 switch (XPT_TDP_TAG(typ)) {
2505 case nsXPTType::T_I8:
2506 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
2507 FILL_SIMPLE_POINTER( PRInt8, PyInt_AsLong(val_use) );
2508 break;
2509 case nsXPTType::T_I16:
2510 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
2511 FILL_SIMPLE_POINTER( PRInt16, PyInt_AsLong(val_use) );
2512 break;
2513 case nsXPTType::T_I32:
2514 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
2515 FILL_SIMPLE_POINTER( PRInt32, PyInt_AsLong(val_use) );
2516 break;
2517 case nsXPTType::T_I64:
2518 if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE;
2519 FILL_SIMPLE_POINTER( PRInt64, PyLong_AsLongLong(val_use) );
2520 break;
2521 case nsXPTType::T_U8:
2522 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
2523 FILL_SIMPLE_POINTER( PRUint8, PyInt_AsLong(val_use) );
2524 break;
2525 case nsXPTType::T_U16:
2526 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
2527 FILL_SIMPLE_POINTER( PRUint16, PyInt_AsLong(val_use) );
2528 break;
2529 case nsXPTType::T_U32:
2530 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE;
2531 FILL_SIMPLE_POINTER( PRUint32, PyInt_AsLong(val_use) );
2532 break;
2533 case nsXPTType::T_U64:
2534 if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE;
2535 FILL_SIMPLE_POINTER( PRUint64, PyLong_AsUnsignedLongLong(val_use) );
2536 break;
2537 case nsXPTType::T_FLOAT:
2538 if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
2539 FILL_SIMPLE_POINTER( float, PyFloat_AsDouble(val_use) );
2540 break;
2541 case nsXPTType::T_DOUBLE:
2542 if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
2543 FILL_SIMPLE_POINTER( double, PyFloat_AsDouble(val_use) );
2544 break;
2545 case nsXPTType::T_BOOL:
2546 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
2547 FILL_SIMPLE_POINTER( PRBool, PyInt_AsLong(val_use) );
2548 break;
2549 case nsXPTType::T_CHAR:
2550#if PY_MAJOR_VERSION <= 2
2551 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
2552 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
2553 BREAK_FALSE;
2554 }
2555 if ((val_use = PyObject_Str(val))==NULL)
2556 BREAK_FALSE;
2557 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
2558 NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
2559 FILL_SIMPLE_POINTER( char, *PyString_AS_STRING(val_use) );
2560#else
2561 if (!PyUnicode_Check(val)) {
2562 PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object");
2563 BREAK_FALSE;
2564 }
2565 FILL_SIMPLE_POINTER( char, *PyUnicode_AS_UNICODE(val) );
2566#endif
2567 break;
2568
2569 case nsXPTType::T_WCHAR:
2570#if PY_MAJOR_VERSION <= 2
2571 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
2572 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
2573 BREAK_FALSE;
2574 }
2575#else
2576 if (!PyUnicode_Check(val)) {
2577 PyErr_SetString(PyExc_TypeError, "This parameter must be a Unicode object");
2578 BREAK_FALSE;
2579 }
2580#endif
2581 if ((val_use = PyUnicode_FromObject(val))==NULL)
2582 BREAK_FALSE;
2583 NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!");
2584 // Lossy!
2585 FILL_SIMPLE_POINTER( PRUnichar, *PyUnicode_AS_UNICODE(val_use) );
2586 break;
2587
2588// case nsXPTType::T_VOID:
2589 case nsXPTType::T_IID: {
2590 nsIID iid;
2591 if (!Py_nsIID::IIDFromPyObject(val, &iid))
2592 BREAK_FALSE;
2593 nsIID **pp = (nsIID **)ns_v.val.p;
2594 // If there is an existing [in] IID, free it.
2595 if (*pp && pi->IsIn())
2596 nsMemory::Free(*pp);
2597 *pp = (nsIID *)nsMemory::Alloc(sizeof(nsIID));
2598 if (*pp==NULL) {
2599 PyErr_NoMemory();
2600 BREAK_FALSE;
2601 }
2602 memcpy(*pp, &iid, sizeof(iid));
2603 break;
2604 }
2605
2606 case nsXPTType::T_ASTRING:
2607 case nsXPTType::T_DOMSTRING: {
2608 nsAString *ws = (nsAString *)ns_v.val.p;
2609 NS_ABORT_IF_FALSE(ws->Length() == 0, "Why does this writable string already have chars??");
2610 if (!PyObject_AsNSString(val, *ws))
2611 BREAK_FALSE;
2612 break;
2613 }
2614 case nsXPTType::T_CSTRING: {
2615 nsCString *ws = (nsCString *)ns_v.val.p;
2616 NS_ABORT_IF_FALSE(ws->Length() == 0, "Why does this writable string already have chars??");
2617 if (val == Py_None) {
2618 NS_ABORT_IF_FALSE(0, "dont handle None here yet");
2619 } else {
2620#if PY_MAJOR_VERSION <= 2
2621 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
2622 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
2623 BREAK_FALSE;
2624 }
2625 val_use = PyObject_Str(val);
2626 NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
2627 const char *sz = PyString_AS_STRING(val_use);
2628 ws->Assign(sz, PyString_GET_SIZE(val_use));
2629#else
2630 if (!PyUnicode_Check(val)) {
2631 PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object");
2632 BREAK_FALSE;
2633 }
2634 val_use = PyUnicode_AsUTF8String(val);
2635 const char *sz = PyBytes_AS_STRING(val_use);
2636 ws->Assign(sz, PyBytes_GET_SIZE(val_use));
2637#endif
2638 }
2639 break;
2640 }
2641 case nsXPTType::T_UTF8STRING: {
2642 nsCString *ws = (nsCString *)ns_v.val.p;
2643 NS_ABORT_IF_FALSE(ws->Length() == 0, "Why does this writable string already have chars??");
2644 if (val == Py_None) {
2645 NS_ABORT_IF_FALSE(0, "dont handle None here yet");
2646 } else {
2647#if PY_MAJOR_VERSION <= 2
2648 if (PyString_Check(val)) {
2649 val_use = val;
2650 Py_INCREF(val);
2651 }
2652 else
2653#endif
2654 if (PyUnicode_Check(val)) {
2655 val_use = PyUnicode_AsUTF8String(val);
2656 } else {
2657#if PY_MAJOR_VERSION <= 2
2658 PyErr_SetString(PyExc_TypeError, "UTF8 parameters must be string or Unicode objects");
2659#else
2660 PyErr_SetString(PyExc_TypeError, "UTF8 parameters must be unicode objects");
2661#endif
2662 BREAK_FALSE;
2663 }
2664#if PY_MAJOR_VERSION <= 2
2665 NS_ABORT_IF_FALSE(PyString_Check(val_use), "must have a string object!");
2666 const char *sz = PyString_AS_STRING(val_use);
2667 ws->Assign(sz, PyString_GET_SIZE(val_use));
2668#else
2669 NS_ABORT_IF_FALSE(PyBytes_Check(val_use), "must have a bytes object!");
2670 const char *sz = PyBytes_AS_STRING(val_use);
2671 ws->Assign(sz, PyBytes_GET_SIZE(val_use));
2672#endif
2673 }
2674 break;
2675 }
2676
2677 case nsXPTType::T_CHAR_STR: {
2678 // If it is an existing string, free it.
2679 char **pp = (char **)ns_v.val.p;
2680 if (*pp && pi->IsIn())
2681 nsMemory::Free(*pp);
2682 *pp = nsnull;
2683
2684 if (val == Py_None)
2685 break; // Remains NULL.
2686#if PY_MAJOR_VERSION <= 2
2687 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
2688 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
2689 BREAK_FALSE;
2690 }
2691 if ((val_use = PyObject_Str(val))==NULL)
2692 BREAK_FALSE;
2693 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
2694 NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
2695
2696 const char *sz = PyString_AS_STRING(val_use);
2697 int nch = PyString_GET_SIZE(val_use);
2698#else
2699 if (!PyUnicode_Check(val)) {
2700 PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object");
2701 BREAK_FALSE;
2702 }
2703 if ((val_use = PyUnicode_AsUTF8String(val))==NULL)
2704 BREAK_FALSE;
2705
2706 const char *sz = PyBytes_AS_STRING(val_use);
2707 int nch = PyBytes_GET_SIZE(val_use);
2708#endif
2709
2710 *pp = (char *)nsMemory::Alloc(nch+1);
2711 if (*pp==NULL) {
2712 PyErr_NoMemory();
2713 BREAK_FALSE;
2714 }
2715 strncpy(*pp, sz, nch+1);
2716 break;
2717 }
2718 case nsXPTType::T_WCHAR_STR: {
2719 // If it is an existing string, free it.
2720 PRUnichar **pp = (PRUnichar **)ns_v.val.p;
2721 if (*pp && pi->IsIn())
2722 nsMemory::Free(*pp);
2723 *pp = nsnull;
2724 if (val == Py_None)
2725 break; // Remains NULL.
2726#if PY_MAJOR_VERSION <= 2
2727 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
2728 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
2729 BREAK_FALSE;
2730 }
2731 val_use = PyUnicode_FromObject(val);
2732 NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!");
2733#else
2734 if (!PyUnicode_Check(val)) {
2735 PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object");
2736 BREAK_FALSE;
2737 }
2738 val_use = val;
2739 Py_INCREF(val_use);
2740#endif
2741 if (PyUnicode_AsPRUnichar(val_use, pp, NULL) < 0)
2742 BREAK_FALSE;
2743 break;
2744 }
2745 case nsXPTType::T_INTERFACE: {
2746 nsISupports *pnew = nsnull;
2747 // Find out what IID we are declared to use.
2748 nsIID *iid;
2749 nsIInterfaceInfo *ii = GetInterfaceInfo();
2750 if (ii)
2751 ii->GetIIDForParam(m_method_index, pi, &iid);
2752
2753 // Get it the "standard" way.
2754 // We do allow NULL here, even tho doing so will no-doubt crash some objects.
2755 // (but there will certainly be objects out there that will allow NULL :-(
2756 nsIID iid_use = iid ? *iid : NS_GET_IID(nsISupports);
2757 if (!Py_nsISupports::InterfaceFromPyObject(val, iid_use, &pnew, PR_TRUE))
2758 BREAK_FALSE;
2759 nsISupports **pp = (nsISupports **)ns_v.val.p;
2760 if (*pp && pi->IsIn()) {
2761 Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
2762 (*pp)->Release();
2763 Py_END_ALLOW_THREADS;
2764 }
2765
2766 *pp = pnew; // ref-count added by InterfaceFromPyObject
2767 break;
2768 }
2769 case nsXPTType::T_INTERFACE_IS: {
2770 const nsIID *piid;
2771 if (!GetIIDForINTERFACE_ID(pi->type.argnum, &piid))
2772 BREAK_FALSE;
2773
2774 nsISupports *pnew = nsnull;
2775 // Get it the "standard" way.
2776 // We do allow NULL here, even tho doing so will no-doubt crash some objects.
2777 // (but there will certainly be objects out there that will allow NULL :-(
2778 if (!Py_nsISupports::InterfaceFromPyObject(val, *piid, &pnew, PR_TRUE))
2779 BREAK_FALSE;
2780 nsISupports **pp = (nsISupports **)ns_v.val.p;
2781 if (*pp && pi->IsIn()) {
2782 Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
2783 (*pp)->Release();
2784 Py_END_ALLOW_THREADS;
2785 }
2786
2787 *pp = pnew; // ref-count added by InterfaceFromPyObject
2788 break;
2789 }
2790
2791 case nsXPTType::T_PSTRING_SIZE_IS: {
2792 const char *sz = nsnull;
2793 PRUint32 nch = 0;
2794 if (val != Py_None) {
2795#if PY_MAJOR_VERSION <= 2
2796 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
2797 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
2798 BREAK_FALSE;
2799 }
2800 if ((val_use = PyObject_Str(val))==NULL)
2801 BREAK_FALSE;
2802 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
2803 NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
2804
2805 sz = PyString_AS_STRING(val_use);
2806 nch = PyString_GET_SIZE(val_use);
2807#else
2808 if (!PyUnicode_Check(val)) {
2809 PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object");
2810 BREAK_FALSE;
2811 }
2812 if ((val_use = PyUnicode_AsUTF8String(val))==NULL)
2813 BREAK_FALSE;
2814
2815 sz = PyBytes_AS_STRING(val_use);
2816 nch = PyBytes_GET_SIZE(val_use);
2817#endif
2818 }
2819 PRBool bBackFill = PR_FALSE;
2820 PRBool bCanSetSizeIs = CanSetSizeIs(index, PR_TRUE);
2821 // If we can not change the size, check our sequence is correct.
2822 if (!bCanSetSizeIs) {
2823 PRUint32 existing_size = GetSizeIs(index, PR_TRUE);
2824 if (nch != existing_size) {
2825 PyErr_Format(PyExc_ValueError, "This function is expecting a string of exactly length %d - %d characters were passed", existing_size, nch);
2826 BREAK_FALSE;
2827 }
2828 // It we have an "inout" param, but an "in" count, then
2829 // it is probably a buffer the caller expects us to
2830 // fill in-place!
2831 bBackFill = pi->IsIn();
2832 }
2833 if (bBackFill) {
2834 memcpy(*(char **)ns_v.val.p, sz, nch);
2835 } else {
2836 // If we have an existing string, free it!
2837 char **pp = (char **)ns_v.val.p;
2838 if (*pp && pi->IsIn())
2839 nsMemory::Free(*pp);
2840 *pp = nsnull;
2841 if (sz==nsnull) // None specified.
2842 break; // Remains NULL.
2843 *pp = (char *)nsMemory::Alloc(nch);
2844 if (*pp==NULL) {
2845 PyErr_NoMemory();
2846 BREAK_FALSE;
2847 }
2848 memcpy(*pp, sz, nch);
2849 if (bCanSetSizeIs)
2850 rc = SetSizeIs(index, PR_TRUE, nch);
2851 else {
2852 NS_ABORT_IF_FALSE(GetSizeIs(index, PR_TRUE) == nch, "Can't set sizeis, but string isnt correct size");
2853 }
2854 }
2855 break;
2856 }
2857
2858 case nsXPTType::T_PWSTRING_SIZE_IS: {
2859 PRUnichar *sz = nsnull;
2860 PRUint32 nch = 0;
2861 PRUint32 nbytes = 0;
2862
2863 if (val != Py_None) {
2864#if PY_MAJOR_VERSION <= 2
2865 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
2866 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
2867 BREAK_FALSE;
2868 }
2869 val_use = PyUnicode_FromObject(val);
2870 NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!");
2871#else
2872 if (!PyUnicode_Check(val)) {
2873 PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object");
2874 BREAK_FALSE;
2875 }
2876 val_use = val;
2877 Py_INCREF(val_use);
2878#endif
2879 if (PyUnicode_AsPRUnichar(val_use, &sz, &nch) < 0)
2880 BREAK_FALSE;
2881 nbytes = sizeof(PRUnichar) * nch;
2882 }
2883 PRBool bBackFill = PR_FALSE;
2884 PRBool bCanSetSizeIs = CanSetSizeIs(index, PR_TRUE);
2885 // If we can not change the size, check our sequence is correct.
2886 if (!bCanSetSizeIs) {
2887 // It is a buffer the caller prolly wants us to fill in-place!
2888 PRUint32 existing_size = GetSizeIs(index, PR_TRUE);
2889 if (nch != existing_size) {
2890 PyErr_Format(PyExc_ValueError, "This function is expecting a string of exactly length %d - %d characters were passed", existing_size, nch);
2891 BREAK_FALSE;
2892 }
2893 // It we have an "inout" param, but an "in" count, then
2894 // it is probably a buffer the caller expects us to
2895 // fill in-place!
2896 bBackFill = pi->IsIn();
2897 }
2898 if (bBackFill) {
2899 memcpy(*(PRUnichar **)ns_v.val.p, sz, nbytes);
2900 } else {
2901 // If it is an existing string, free it.
2902 PRUnichar **pp = (PRUnichar **)ns_v.val.p;
2903 if (*pp && pi->IsIn())
2904 nsMemory::Free(*pp);
2905 *pp = sz;
2906 sz = nsnull;
2907 if (bCanSetSizeIs)
2908 rc = SetSizeIs(index, PR_TRUE, nch);
2909 else {
2910 NS_ABORT_IF_FALSE(GetSizeIs(index, PR_TRUE) == nch, "Can't set sizeis, but string isnt correct size");
2911 }
2912 }
2913 if (sz)
2914 nsMemory::Free(sz);
2915 break;
2916 }
2917 case nsXPTType::T_ARRAY: {
2918 // If it is an existing array of the correct size, keep it.
2919 PRUint32 sequence_size = 0;
2920 PRUint8 array_type;
2921 nsIID *piid;
2922 nsresult ns = GetArrayType(index, &array_type, &piid);
2923 if (NS_FAILED(ns))
2924 return ns;
2925 PRUint32 element_size = GetArrayElementSize(array_type);
2926 if (val != Py_None) {
2927 if (!PySequence_Check(val)) {
2928 PyErr_Format(PyExc_TypeError, "Object for xpcom array must be a sequence, not type '%s'", val->ob_type->tp_name);
2929 BREAK_FALSE;
2930 }
2931 sequence_size = PySequence_Length(val);
2932 }
2933 PRUint32 existing_size = GetSizeIs(index, PR_FALSE);
2934 PRBool bBackFill = PR_FALSE;
2935 PRBool bCanSetSizeIs = CanSetSizeIs(index, PR_FALSE);
2936 // If we can not change the size, check our sequence is correct.
2937 if (!bCanSetSizeIs) {
2938 // It is a buffer the caller prolly wants us to fill in-place!
2939 if (sequence_size != existing_size) {
2940 PyErr_Format(PyExc_ValueError, "This function is expecting a sequence of exactly length %d - %d items were passed", existing_size, sequence_size);
2941 BREAK_FALSE;
2942 }
2943 // It we have an "inout" param, but an "in" count, then
2944 // it is probably a buffer the caller expects us to
2945 // fill in-place!
2946 bBackFill = pi->IsIn();
2947 }
2948 if (bBackFill)
2949 rc = FillSingleArray(*(void **)ns_v.val.p, val, sequence_size, element_size, array_type&XPT_TDP_TAGMASK, piid);
2950 else {
2951 // If it is an existing array, free it.
2952 void **pp = (void **)ns_v.val.p;
2953 if (*pp && pi->IsIn()) {
2954 FreeSingleArray(*pp, existing_size, array_type);
2955 nsMemory::Free(*pp);
2956 }
2957 *pp = nsnull;
2958 if (val == Py_None)
2959 break; // Remains NULL.
2960 size_t nbytes = sequence_size * element_size;
2961 if (nbytes==0) nbytes = 1; // avoid assertion about 0 bytes
2962 *pp = (void *)nsMemory::Alloc(nbytes);
2963 memset(*pp, 0, nbytes);
2964 rc = FillSingleArray(*pp, val, sequence_size, element_size, array_type&XPT_TDP_TAGMASK, piid);
2965 if (!rc) break;
2966 if (bCanSetSizeIs)
2967 rc = SetSizeIs(index, PR_FALSE, sequence_size);
2968 else {
2969 NS_ABORT_IF_FALSE(GetSizeIs(index, PR_FALSE) == sequence_size, "Can't set sizeis, but string isnt correct size");
2970 }
2971 }
2972 break;
2973 }
2974 default:
2975 // try and limp along in this case.
2976 // leave rc TRUE
2977 PyXPCOM_LogWarning("Converting Python object for an [out] param - The object type (0x%x) is unknown - leaving param alone!\n", XPT_TDP_TAG(typ));
2978 break;
2979 }
2980 Py_XDECREF(val_use);
2981 if (!rc)
2982 return NS_ERROR_FAILURE;
2983 return NS_OK;
2984}
2985
2986nsresult PyXPCOM_GatewayVariantHelper::ProcessPythonResult(PyObject *ret_ob)
2987{
2988 // NOTE - although we return an nresult, if we leave a Python
2989 // exception set, then our caller may take additional action
2990 // (ie, translating our nsresult to a more appropriate nsresult
2991 // for the Python exception.)
2992 NS_PRECONDITION(!PyErr_Occurred(), "Expecting no Python exception to be pending when processing the return result");
2993
2994 nsresult rc = NS_OK;
2995 // If we dont get a tuple back, then the result is only
2996 // an int nresult for the underlying function.
2997 // (ie, the policy is expected to return (NS_OK, user_retval),
2998 // but can also return (say), NS_ERROR_FAILURE
2999 if (PyInt_Check(ret_ob))
3000 return PyInt_AsLong(ret_ob);
3001 // Now it must be the tuple.
3002 if (!PyTuple_Check(ret_ob) ||
3003 PyTuple_Size(ret_ob)!=2 ||
3004 !PyInt_Check(PyTuple_GET_ITEM(ret_ob, 0))) {
3005 PyErr_SetString(PyExc_TypeError, "The Python result must be a single integer or a tuple of length==2 and first item an int.");
3006 return NS_ERROR_FAILURE;
3007 }
3008 PyObject *user_result = PyTuple_GET_ITEM(ret_ob, 1);
3009 // Count up how many results our function needs.
3010 int i;
3011 int num_results = 0;
3012 int last_result = -1; // optimization if we only have one - this is it!
3013 int index_retval = -1;
3014 for (i=0;i<m_num_type_descs;i++) {
3015 nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+i;
3016 if (!m_python_type_desc_array[i].is_auto_out) {
3017 if (pi->IsOut() || pi->IsDipper()) {
3018 num_results++;
3019 last_result = i;
3020 }
3021 if (pi->IsRetval())
3022 index_retval = i;
3023 }
3024 }
3025
3026 if (num_results==0) {
3027 ; // do nothing
3028 } else if (num_results==1) {
3029 // May or may not be the nominated retval - who cares!
3030 NS_ABORT_IF_FALSE(last_result >=0 && last_result < m_num_type_descs, "Have one result, but dont know its index!");
3031 rc = BackFillVariant( user_result, last_result );
3032 } else {
3033 // Loop over each one, filling as we go.
3034 // We allow arbitary sequences here, but _not_ strings
3035 // or Unicode!
3036 // NOTE - We ALWAYS do the nominated retval first.
3037 // The Python pattern is always:
3038 // return retval [, byref1 [, byref2 ...] ]
3039 // But the retval is often the last param described in the info.
3040 if (!PySequence_Check(user_result) ||
3041#if PY_MAJOR_VERSION <= 2
3042 PyString_Check(user_result) ||
3043#else
3044 PyBytes_Check(user_result) ||
3045#endif
3046 PyUnicode_Check(user_result)) {
3047 PyErr_SetString(PyExc_TypeError, "This function has multiple results, but a sequence was not given to fill them");
3048 return NS_ERROR_FAILURE;
3049 }
3050 int num_user_results = PySequence_Length(user_result);
3051 // If they havent given enough, we dont really care.
3052 // although a warning is probably appropriate.
3053 if (num_user_results != num_results) {
3054 const char *method_name = m_info->GetName();
3055 PyXPCOM_LogWarning("The method '%s' has %d out params, but %d were supplied by the Python code\n",
3056 method_name,
3057 num_results,
3058 num_user_results);
3059 }
3060 int this_py_index = 0;
3061 if (index_retval != -1) {
3062 // We always return the nominated result first!
3063 PyObject *sub = PySequence_GetItem(user_result, 0);
3064 if (sub==NULL)
3065 return NS_ERROR_FAILURE;
3066 rc = BackFillVariant(sub, index_retval);
3067 Py_DECREF(sub);
3068 this_py_index = 1;
3069 }
3070 for (i=0;NS_SUCCEEDED(rc) && i<m_info->GetParamCount();i++) {
3071 // If weve already done it, or dont need to do it!
3072 if (i==index_retval || m_python_type_desc_array[i].is_auto_out)
3073 continue;
3074 nsXPTParamInfo *pi = (nsXPTParamInfo *)m_info->params+i;
3075 if (pi->IsOut()) {
3076 PyObject *sub = PySequence_GetItem(user_result, this_py_index);
3077 if (sub==NULL)
3078 return NS_ERROR_FAILURE;
3079 rc = BackFillVariant(sub, i);
3080 Py_DECREF(sub);
3081 this_py_index++;
3082 }
3083 }
3084 }
3085 return rc;
3086}
Note: See TracBrowser for help on using the repository browser.

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