VirtualBox

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

Last change on this file since 103176 was 103176, checked in by vboxsync, 3 months ago

libs/xpcom/python: Some cleanup, bugref:3409

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

© 2023 Oracle
ContactPrivacy policyTerms of Use