VirtualBox

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

Last change on this file since 104494 was 104494, checked in by vboxsync, 12 months ago

libs/xpcom/python/src/VariantUtils.cpp: Missing break (harmless), bugref:3409

  • Property svn:eol-style set to native
File size: 99.9 KB
Line 
1/* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
3 *
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
8 *
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
13 *
14 * The Original Code is the Python XPCOM language bindings.
15 *
16 * The Initial Developer of the Original Code is
17 * ActiveState Tool Corp.
18 * Portions created by the Initial Developer are Copyright (C) 2000
19 * the Initial Developer. All Rights Reserved.
20 *
21 * Contributor(s):
22 * Mark Hammond <[email protected]> (original author)
23 *
24 * Unicode corrections by Shane Hathaway (http://hathawaymix.org),
25 * inspired by Mikhail Sobolev
26 *
27 * Alternatively, the contents of this file may be used under the terms of
28 * either the GNU General Public License Version 2 or later (the "GPL"), or
29 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 * in which case the provisions of the GPL or the LGPL are applicable instead
31 * of those above. If you wish to allow use of your version of this file only
32 * under the terms of either the GPL or the LGPL, and not to allow others to
33 * use your version of this file under the terms of the MPL, indicate your
34 * decision by deleting the provisions above and replace them with the notice
35 * and other provisions required by the GPL or the LGPL. If you do not delete
36 * the provisions above, a recipient may use your version of this file under
37 * the terms of any one of the MPL, the GPL or the LGPL.
38 *
39 * ***** END LICENSE BLOCK ***** */
40
41//
42// This code is part of the XPCOM extensions for Python.
43//
44// Written May 2000 by Mark Hammond.
45//
46// Based heavily on the Python COM support, which is
47// (c) Mark Hammond and Greg Stein.
48//
49// (c) 2000, ActiveState corp.
50
51#include "PyXPCOM_std.h"
52#include <nsIInterfaceInfoManager.h>
53#include <nsAString.h>
54#include <nsString.h>
55#include <nsReadableUtils.h>
56
57// ------------------------------------------------------------------------
58// nsString utilities
59// ------------------------------------------------------------------------
60// one day we may know what they look like.
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 break;
904 default:
905 NS_ABORT_IF_FALSE(0, "BestVariantTypeForPyObject() returned a variant type not handled here!");
906 PyXPCOM_LogWarning("Objects of type '%s' can not be converted to an nsIVariant", PyXPCOM_ObTypeName(ob));
907 nr = NS_ERROR_UNEXPECTED;
908 }
909 if (NS_FAILED(nr))
910 return nr;
911 return v->QueryInterface(NS_GET_IID(nsIVariant), (void **)aRet);
912}
913
914static PyObject *MyBool_FromBool(PRBool v)
915{
916 PyObject *ret = v ? Py_True : Py_False;
917 Py_INCREF(ret);
918 return ret;
919}
920
921#define GET_FROM_V(Type, FuncGet, FuncConvert) { \
922 Type t; \
923 if (NS_FAILED(nr = FuncGet( &t ))) goto done;\
924 ret = FuncConvert(t);\
925 break; \
926}
927
928DECLHIDDEN(PyObject *) PyObject_FromVariantArray( Py_nsISupports *parent, nsIVariant *v)
929{
930 nsresult nr;
931 NS_PRECONDITION(v, "NULL variant!");
932 if (!v)
933 return PyXPCOM_BuildPyException(NS_ERROR_INVALID_POINTER);
934#ifdef NS_DEBUG
935 PRUint16 dt;
936 nr = v->GetDataType(&dt);
937 NS_ABORT_IF_FALSE(dt == nsIDataType::VTYPE_ARRAY, "expected an array variant");
938#endif
939 nsIID iid;
940 void *p;
941 PRUint16 type;
942 PRUint32 count;
943 nr = v->GetAsArray(&type, &iid, &count, &p);
944 if (NS_FAILED(nr)) return PyXPCOM_BuildPyException(nr);
945 PyObject *ret = UnpackSingleArray(parent, p, count, (PRUint8)type, &iid);
946 FreeSingleArray(p, count, (PRUint8)type);
947 nsMemory::Free(p);
948 return ret;
949}
950
951PyObject *PyObject_FromVariant( Py_nsISupports *parent, nsIVariant *v)
952{
953 if (!v) {
954 Py_INCREF(Py_None);
955 return Py_None;
956 }
957 PRUint16 dt;
958 nsresult nr;
959 PyObject *ret = NULL;
960 nr = v->GetDataType(&dt);
961 if (NS_FAILED(nr)) goto done;
962 switch (dt) {
963 case nsIDataType::VTYPE_VOID:
964 case nsIDataType::VTYPE_EMPTY:
965 case nsIDataType::VTYPE_EMPTY_ARRAY:
966 ret = Py_None;
967 Py_INCREF(Py_None);
968 break;
969 case nsIDataType::VTYPE_ARRAY:
970 ret = PyObject_FromVariantArray(parent, v);
971 break;
972 case nsIDataType::VTYPE_INT8:
973 case nsIDataType::VTYPE_INT16:
974 case nsIDataType::VTYPE_INT32:
975 GET_FROM_V(PRInt32, v->GetAsInt32, PyInt_FromLong);
976 case nsIDataType::VTYPE_UINT8:
977 case nsIDataType::VTYPE_UINT16:
978 case nsIDataType::VTYPE_UINT32:
979 GET_FROM_V(PRUint32, v->GetAsUint32, PyLong_FromUnsignedLong);
980 case nsIDataType::VTYPE_INT64:
981 GET_FROM_V(PRInt64, v->GetAsInt64, PyLong_FromLongLong);
982 case nsIDataType::VTYPE_UINT64:
983 GET_FROM_V(PRUint64, v->GetAsUint64, PyLong_FromUnsignedLongLong);
984 case nsIDataType::VTYPE_FLOAT:
985 case nsIDataType::VTYPE_DOUBLE:
986 GET_FROM_V(double, v->GetAsDouble, PyFloat_FromDouble);
987 case nsIDataType::VTYPE_BOOL:
988 GET_FROM_V(PRBool, v->GetAsBool, MyBool_FromBool);
989 default:
990 PyXPCOM_LogWarning("Converting variant to Python object - variant type '%d' unknown - using string.\n", dt);
991 // Fall through to the string case
992 case nsIDataType::VTYPE_CHAR:
993 case nsIDataType::VTYPE_CHAR_STR:
994 case nsIDataType::VTYPE_STRING_SIZE_IS:
995 case nsIDataType::VTYPE_CSTRING: {
996 nsCAutoString s;
997 if (NS_FAILED(nr=v->GetAsACString(s))) goto done;
998 ret = PyObject_FromNSString(s);
999 break;
1000 }
1001 case nsIDataType::VTYPE_WCHAR:
1002 case nsIDataType::VTYPE_DOMSTRING:
1003 case nsIDataType::VTYPE_WSTRING_SIZE_IS:
1004 case nsIDataType::VTYPE_ASTRING: {
1005 nsAutoString s;
1006 if (NS_FAILED(nr=v->GetAsAString(s))) goto done;
1007 ret = PyObject_FromNSString(s);
1008 break;
1009 }
1010 case nsIDataType::VTYPE_ID:
1011 GET_FROM_V(nsIID, v->GetAsID, Py_nsIID::PyObjectFromIID);
1012 case nsIDataType::VTYPE_INTERFACE: {
1013 nsCOMPtr<nsISupports> p;
1014 if (NS_FAILED(nr=v->GetAsISupports(getter_AddRefs(p)))) goto done;
1015 if (parent)
1016 ret = parent->MakeInterfaceResult(p, NS_GET_IID(nsISupports));
1017 else
1018 ret = Py_nsISupports::PyObjectFromInterface(
1019 p, NS_GET_IID(nsISupports), PR_TRUE);
1020 break;
1021 }
1022 case nsIDataType::VTYPE_INTERFACE_IS: {
1023 nsCOMPtr<nsISupports> p;
1024 nsIID *iid;
1025 if (NS_FAILED(nr=v->GetAsInterface(&iid, getter_AddRefs(p)))) goto done;
1026 // If the variant itself holds a variant, we should
1027 // probably unpack that too?
1028 ret = parent->MakeInterfaceResult(p, *iid);
1029 break;
1030 // case nsIDataType::VTYPE_WCHAR_STR
1031 // case nsIDataType::VTYPE_UTF8STRING
1032 }
1033 }
1034done:
1035 if (NS_FAILED(nr)) {
1036 NS_ABORT_IF_FALSE(ret==NULL, "Have an error, but also a return val!");
1037 PyXPCOM_BuildPyException(nr);
1038 }
1039 return ret;
1040}
1041
1042// ------------------------------------------------------------------------
1043// TypeDescriptor helper class
1044// ------------------------------------------------------------------------
1045class PythonTypeDescriptor {
1046public:
1047 PythonTypeDescriptor() {
1048 param_flags = type_flags = argnum = argnum2 = 0;
1049 extra = NULL;
1050 is_auto_out = PR_FALSE;
1051 is_auto_in = PR_FALSE;
1052 have_set_auto = PR_FALSE;
1053 }
1054 ~PythonTypeDescriptor() {
1055 Py_XDECREF(extra);
1056 }
1057 PRUint8 param_flags;
1058 PRUint8 type_flags;
1059 PRUint8 argnum; /* used for iid_is and size_is */
1060 PRUint8 argnum2; /* used for length_is */
1061 PyObject *extra; // The IID object, or the type of the array.
1062 // Extra items to help our processing.
1063 // Is this auto-filled by some other "in" param?
1064 PRBool is_auto_in;
1065 // Is this auto-filled by some other "out" param?
1066 PRBool is_auto_out;
1067 // If is_auto_out, have I already filled it? Used when multiple
1068 // params share a size_is fields - first time sets it, subsequent
1069 // time check it.
1070 PRBool have_set_auto;
1071};
1072
1073static int ProcessPythonTypeDescriptors(PythonTypeDescriptor *pdescs, int num)
1074{
1075 // Loop over the array, checking all the params marked as having an arg.
1076 // If these args nominate another arg as the size_is param, then
1077 // we reset the size_is param to _not_ requiring an arg.
1078 int i;
1079 for (i=0;i<num;i++) {
1080 PythonTypeDescriptor &ptd = pdescs[i];
1081 // Can't use XPT_TDP_TAG() - it uses a ".flags" reference in the macro.
1082 switch (ptd.type_flags & XPT_TDP_TAGMASK) {
1083 case nsXPTType::T_ARRAY:
1084 NS_ABORT_IF_FALSE(ptd.argnum < num, "Bad dependent index");
1085 if (ptd.argnum2 < num) {
1086 if (XPT_PD_IS_IN(ptd.param_flags))
1087 pdescs[ptd.argnum2].is_auto_in = PR_TRUE;
1088 if (XPT_PD_IS_OUT(ptd.param_flags))
1089 pdescs[ptd.argnum2].is_auto_out = PR_TRUE;
1090 }
1091 break;
1092 case nsXPTType::T_PSTRING_SIZE_IS:
1093 case nsXPTType::T_PWSTRING_SIZE_IS:
1094 NS_ABORT_IF_FALSE(ptd.argnum < num, "Bad dependent index");
1095 if (ptd.argnum < num) {
1096 if (XPT_PD_IS_IN(ptd.param_flags))
1097 pdescs[ptd.argnum].is_auto_in = PR_TRUE;
1098 if (XPT_PD_IS_OUT(ptd.param_flags))
1099 pdescs[ptd.argnum].is_auto_out = PR_TRUE;
1100 }
1101 break;
1102 default:
1103 break;
1104 }
1105 }
1106 int total_params_needed = 0;
1107 for (i=0;i<num;i++)
1108 if (XPT_PD_IS_IN(pdescs[i].param_flags) && !pdescs[i].is_auto_in && !XPT_PD_IS_DIPPER(pdescs[i].param_flags))
1109 total_params_needed++;
1110
1111 return total_params_needed;
1112}
1113
1114/*************************************************************************
1115**************************************************************************
1116
1117Helpers when CALLING interfaces.
1118
1119**************************************************************************
1120*************************************************************************/
1121
1122PyXPCOM_InterfaceVariantHelper::PyXPCOM_InterfaceVariantHelper(Py_nsISupports *parent, int methodindex)
1123{
1124 m_var_array=nsnull;
1125 m_buffer_array=nsnull;
1126 m_pyparams=nsnull;
1127 m_typedescs = nsnull;
1128 m_python_type_desc_array = nsnull;
1129 m_num_array = 0;
1130 m_methodindex = methodindex;
1131 // Parent should never die before we do, but let's not take the chance.
1132 m_parent = parent;
1133 Py_INCREF(parent);
1134}
1135
1136PyXPCOM_InterfaceVariantHelper::~PyXPCOM_InterfaceVariantHelper()
1137{
1138 Py_DECREF(m_parent);
1139 Py_XDECREF(m_pyparams);
1140 for (int i=0;i<m_num_array;i++) {
1141 if (m_var_array) {
1142 nsXPTCVariant &ns_v = m_var_array[i];
1143 if (ns_v.IsValInterface()) {
1144 if (ns_v.val.p) {
1145 Py_BEGIN_ALLOW_THREADS; // MUST release thread-lock, incase a Python COM object that re-acquires.
1146 ((nsISupports *)ns_v.val.p)->Release();
1147 Py_END_ALLOW_THREADS;
1148 }
1149 }
1150 if (ns_v.IsValDOMString() && ns_v.val.p) {
1151 delete (const nsAString *)ns_v.val.p;
1152 }
1153 if (ns_v.IsValCString() && ns_v.val.p) {
1154 delete (const nsACString *)ns_v.val.p;
1155 }
1156 if (ns_v.IsValUTF8String() && ns_v.val.p) {
1157 delete (const nsACString *)ns_v.val.p;
1158 }
1159 if (ns_v.IsValArray()) {
1160 nsXPTCVariant &ns_v = m_var_array[i];
1161 if (ns_v.val.p) {
1162 PRUint8 array_type = (PRUint8)PyInt_AsLong(m_python_type_desc_array[i].extra);
1163 PRUint32 seq_size = GetSizeIs(i, PR_FALSE);
1164 FreeSingleArray(ns_v.val.p, seq_size, array_type);
1165 }
1166 }
1167 // IsOwned must be the last check of the loop, as
1168 // this frees the underlying data used above (eg, by the array free process)
1169 if (ns_v.IsValAllocated() && !ns_v.IsValInterface() && !ns_v.IsValDOMString()) {
1170 NS_ABORT_IF_FALSE(ns_v.IsPtrData(), "expecting a pointer to free");
1171 nsMemory::Free(ns_v.val.p);
1172 }
1173 }
1174 if (m_buffer_array && m_buffer_array[i])
1175 nsMemory::Free(m_buffer_array[i]);
1176 }
1177 delete [] m_python_type_desc_array;
1178 delete [] m_buffer_array;
1179 delete [] m_var_array;
1180}
1181
1182PRBool PyXPCOM_InterfaceVariantHelper::Init(PyObject *obParams)
1183{
1184 PRBool ok = PR_FALSE;
1185 int i;
1186 int total_params_needed = 0;
1187 if (!PySequence_Check(obParams) || PySequence_Length(obParams)!=2) {
1188 PyErr_Format(PyExc_TypeError, "Param descriptors must be a sequence of exactly length 2");
1189 return PR_FALSE;
1190 }
1191 PyObject *typedescs = PySequence_GetItem(obParams, 0);
1192 if (typedescs==NULL)
1193 return PR_FALSE;
1194 // NOTE: The length of the typedescs may be different than the
1195 // args actually passed. The typedescs always include all
1196 // hidden params (such as "size_is"), while the actual
1197 // args never include this.
1198 m_num_array = PySequence_Length(typedescs);
1199 if (PyErr_Occurred()) goto done;
1200
1201 m_pyparams = PySequence_GetItem(obParams, 1);
1202 if (m_pyparams==NULL) goto done;
1203
1204 m_python_type_desc_array = new PythonTypeDescriptor[m_num_array];
1205 if (!m_python_type_desc_array) goto done;
1206
1207 // Pull apart the type descs and stash them.
1208 for (i=0;i<m_num_array;i++) {
1209 PyObject *desc_object = PySequence_GetItem(typedescs, i);
1210 if (desc_object==NULL)
1211 goto done;
1212
1213 // Pull apart the typedesc tuple back into a structure we can work with.
1214 PythonTypeDescriptor &ptd = m_python_type_desc_array[i];
1215 PRBool this_ok = PyArg_ParseTuple(desc_object, "bbbbO:type_desc",
1216 &ptd.param_flags, &ptd.type_flags, &ptd.argnum, &ptd.argnum2, &ptd.extra);
1217 Py_DECREF(desc_object);
1218 if (!this_ok) goto done;
1219 Py_INCREF(ptd.extra);
1220
1221 }
1222 total_params_needed = ProcessPythonTypeDescriptors(m_python_type_desc_array, m_num_array);
1223 // OK - check we got the number of args we expected.
1224 // If not, its really an internal error rather than the user.
1225 if (PySequence_Length(m_pyparams) != total_params_needed) {
1226#ifdef VBOX
1227 PyErr_Format(PyExc_ValueError, "The type descriptions indicate %d args are needed, but %ld were provided",
1228 total_params_needed, (long)PySequence_Length(m_pyparams));
1229#else
1230 PyErr_Format(PyExc_ValueError, "The type descriptions indicate %d args are needed, but %d were provided",
1231 total_params_needed, PySequence_Length(m_pyparams));
1232#endif
1233 goto done;
1234 }
1235
1236 // Init the other arrays.
1237 m_var_array = new nsXPTCVariant[m_num_array];
1238 if (!m_var_array) goto done;
1239 /*memset(m_var_array, 0, m_num_array * sizeof(m_var_array[0])); - VBox not needed */
1240
1241 m_buffer_array = new void *[m_num_array];
1242 if (!m_buffer_array) goto done;
1243 memset(m_buffer_array, 0, m_num_array * sizeof(m_buffer_array[0]));
1244
1245 ok = PR_TRUE;
1246done:
1247 if (!ok && !PyErr_Occurred())
1248 PyErr_NoMemory();
1249
1250 Py_XDECREF(typedescs);
1251 return ok;
1252}
1253
1254
1255PRBool PyXPCOM_InterfaceVariantHelper::FillArray()
1256{
1257 int param_index = 0;
1258 int i;
1259 for (i=0;i<m_num_array;i++) {
1260 PythonTypeDescriptor &ptd = m_python_type_desc_array[i];
1261 // stash the type_flags into the variant, and remember how many extra bits of info we have.
1262 m_var_array[i].type = ptd.type_flags;
1263 if (XPT_PD_IS_IN(ptd.param_flags) && !ptd.is_auto_in && !XPT_PD_IS_DIPPER(ptd.param_flags)) {
1264 if (!FillInVariant(ptd, i, param_index))
1265 return PR_FALSE;
1266 param_index++;
1267 }
1268 if ((XPT_PD_IS_OUT(ptd.param_flags) && !ptd.is_auto_out) || XPT_PD_IS_DIPPER(ptd.param_flags)) {
1269 if (!PrepareOutVariant(ptd, i))
1270 return PR_FALSE;
1271 }
1272 }
1273 // There may be out "size_is" params we havent touched yet
1274 // (ie, as the param itself is marked "out", we never got to
1275 // touch the associated "size_is".
1276 // Final loop to handle this.
1277 for (i=0;i<m_num_array;i++) {
1278 PythonTypeDescriptor &ptd = m_python_type_desc_array[i];
1279 if (ptd.is_auto_out && !ptd.have_set_auto) {
1280 // Call PrepareOutVariant to ensure buffers etc setup.
1281 if (!PrepareOutVariant(ptd, i))
1282 return PR_FALSE;
1283 }
1284 }
1285 return PR_TRUE;
1286}
1287
1288
1289PRBool PyXPCOM_InterfaceVariantHelper::SetSizeIs( int var_index, PRBool is_arg1, PRUint32 new_size)
1290{
1291 NS_ABORT_IF_FALSE(var_index < m_num_array, "var_index param is invalid");
1292 PRUint8 argnum = is_arg1 ?
1293 m_python_type_desc_array[var_index].argnum :
1294 m_python_type_desc_array[var_index].argnum2;
1295 NS_ABORT_IF_FALSE(argnum < m_num_array, "size_is param is invalid");
1296 PythonTypeDescriptor &td_size = m_python_type_desc_array[argnum];
1297 NS_ABORT_IF_FALSE(td_size.is_auto_in || td_size.is_auto_out, "Setting size_is, but param is not marked as auto!");
1298 NS_ABORT_IF_FALSE( (td_size.type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32");
1299 nsXPTCVariant &ns_v = m_var_array[argnum];
1300
1301 if (!td_size.have_set_auto) {
1302 ns_v.type = td_size.type_flags;
1303 ns_v.val.u32 = new_size;
1304 // In case it is "out", setup the necessary pointers.
1305 PrepareOutVariant(td_size, argnum);
1306 td_size.have_set_auto = PR_TRUE;
1307 } else {
1308 if (ns_v.val.u32 != new_size) {
1309 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);
1310 return PR_FALSE;
1311 }
1312 }
1313 return PR_TRUE;
1314}
1315
1316PRUint32 PyXPCOM_InterfaceVariantHelper::GetSizeIs( int var_index, PRBool is_arg1)
1317{
1318 NS_ABORT_IF_FALSE(var_index < m_num_array, "var_index param is invalid");
1319 PRUint8 argnum = is_arg1 ?
1320 m_python_type_desc_array[var_index].argnum :
1321 m_python_type_desc_array[var_index].argnum2;
1322 NS_ABORT_IF_FALSE(argnum < m_num_array, "size_is param is invalid");
1323 NS_ABORT_IF_FALSE( (m_python_type_desc_array[argnum].type_flags & XPT_TDP_TAGMASK) == nsXPTType::T_U32, "size param must be Uint32");
1324 PRBool is_out = XPT_PD_IS_OUT(m_python_type_desc_array[argnum].param_flags);
1325 nsXPTCVariant &ns_v = m_var_array[argnum];
1326 return is_out ? *((PRUint32 *)ns_v.ptr) : ns_v.val.u32;
1327}
1328
1329#define MAKE_VALUE_BUFFER(size) \
1330 if ((this_buffer_pointer = (void *)nsMemory::Alloc((size))) == nsnull) { \
1331 PyErr_NoMemory(); \
1332 BREAK_FALSE; \
1333 }
1334
1335PRBool PyXPCOM_InterfaceVariantHelper::FillInVariant(const PythonTypeDescriptor &td, int value_index, int param_index)
1336{
1337 PRBool rc = PR_TRUE;
1338 // Get a reference to the variant we are filling for convenience.
1339 nsXPTCVariant &ns_v = m_var_array[value_index];
1340 NS_ABORT_IF_FALSE(ns_v.type == td.type_flags, "Expecting variant all setup for us");
1341
1342 // We used to avoid passing internal buffers to PyString etc objects
1343 // for 2 reasons: paranoia (so incorrect external components couldn't break
1344 // Python) and simplicity (in vs in-out issues, etc)
1345 // However, at least one C++ implemented component (nsITimelineService)
1346 // uses a "char *", and keys on the address (assuming that the same
1347 // *pointer* is passed rather than value. Therefore, we have a special case
1348 // - T_CHAR_STR that is "in" gets the Python string pointer passed.
1349 void *&this_buffer_pointer = m_buffer_array[value_index]; // Freed at object destruction with PyMem_Free()
1350 NS_ABORT_IF_FALSE(this_buffer_pointer==nsnull, "We appear to already have a buffer");
1351 int cb_this_buffer_pointer = 0;
1352 if (XPT_PD_IS_IN(td.param_flags)) {
1353 NS_ABORT_IF_FALSE(!td.is_auto_in, "Param is 'auto-in', but we are filling it normally!");
1354 PyObject *val_use = NULL; // a temp object converters can use, and will be DECREF'd
1355 PyObject *val = PySequence_GetItem(m_pyparams, param_index);
1356 NS_WARN_IF_FALSE(val, "Have an 'in' param, but no Python value!");
1357 if (val==NULL) {
1358 PyErr_Format(PyExc_ValueError, "Param %d is marked as 'in', but no value was given", value_index);
1359 return PR_FALSE;
1360 }
1361 switch (XPT_TDP_TAG(ns_v.type)) {
1362 case nsXPTType::T_I8:
1363 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1364 ns_v.val.i8 = (PRInt8)PyInt_AsLong(val_use);
1365 break;
1366 case nsXPTType::T_I16:
1367 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1368 ns_v.val.i16 = (PRInt16)PyInt_AsLong(val_use);
1369 break;
1370 case nsXPTType::T_I32:
1371 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1372 ns_v.val.i32 = (PRInt32)PyInt_AsLong(val_use);
1373 break;
1374 case nsXPTType::T_I64:
1375 if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE
1376 ns_v.val.i64 = (PRInt64)PyLong_AsLongLong(val_use);
1377 break;
1378 case nsXPTType::T_U8:
1379 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1380 ns_v.val.u8 = (PRUint8)PyInt_AsLong(val_use);
1381 break;
1382 case nsXPTType::T_U16:
1383 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1384 ns_v.val.u16 = (PRUint16)PyInt_AsLong(val_use);
1385 break;
1386 case nsXPTType::T_U32:
1387 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1388 ns_v.val.u32 = (PRUint32)PyInt_AsLong(val_use);
1389 break;
1390 case nsXPTType::T_U64:
1391 if ((val_use=PyNumber_Long(val))==NULL) BREAK_FALSE
1392 ns_v.val.u64 = (PRUint64)PyLong_AsUnsignedLongLong(val_use);
1393 break;
1394 case nsXPTType::T_FLOAT:
1395 if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
1396 ns_v.val.f = (float)PyFloat_AsDouble(val_use);
1397 break;
1398 case nsXPTType::T_DOUBLE:
1399 if ((val_use=PyNumber_Float(val))==NULL) BREAK_FALSE
1400 ns_v.val.d = PyFloat_AsDouble(val_use);
1401 break;
1402 case nsXPTType::T_BOOL:
1403 if ((val_use=PyNumber_Int(val))==NULL) BREAK_FALSE
1404 ns_v.val.b = (PRBool)PyInt_AsLong(val_use);
1405 break;
1406 case nsXPTType::T_CHAR:{
1407#if PY_MAJOR_VERSION <= 2
1408 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
1409 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
1410 BREAK_FALSE;
1411 }
1412 if ((val_use = PyObject_Str(val))==NULL)
1413 BREAK_FALSE;
1414 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
1415 NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
1416 if (PyString_GET_SIZE(val_use) != 1) {
1417 PyErr_SetString(PyExc_ValueError, "Must specify a one character string for a character");
1418 BREAK_FALSE;
1419 }
1420
1421 ns_v.val.c = *PyString_AS_STRING(val_use);
1422#else
1423 if (!PyUnicode_Check(val)) {
1424 PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object");
1425 BREAK_FALSE;
1426 }
1427 if (PyUnicode_GET_SIZE(val) != 1) {
1428 PyErr_SetString(PyExc_ValueError, "Must specify a one character string for a character");
1429 BREAK_FALSE;
1430 }
1431
1432# ifndef Py_LIMITED_API
1433 ns_v.val.c = *PyUnicode_AS_UNICODE(val_use);
1434# else
1435 ns_v.val.c = PyUnicode_ReadChar(val_use, 0);
1436# endif
1437#endif
1438 break;
1439 }
1440
1441 case nsXPTType::T_WCHAR: {
1442#if PY_MAJOR_VERSION <= 2
1443 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
1444 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
1445 BREAK_FALSE;
1446 }
1447#else
1448 if (!PyUnicode_Check(val)) {
1449 PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object");
1450 BREAK_FALSE;
1451 }
1452#endif
1453 if ((val_use = PyUnicode_FromObject(val))==NULL)
1454 BREAK_FALSE;
1455 // Sanity check should PyUnicode_FromObject() ever loosen its semantics wrt Unicode!
1456 NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a unicode object!");
1457 if (PyUnicode_GET_SIZE(val_use) != 1) {
1458 PyErr_SetString(PyExc_ValueError, "Must specify a one character string for a character");
1459 BREAK_FALSE;
1460 }
1461 // Lossy!
1462#ifndef Py_LIMITED_API
1463 ns_v.val.wc = *PyUnicode_AS_UNICODE(val_use);
1464#else
1465 ns_v.val.wc = PyUnicode_ReadChar(val_use, 0);
1466#endif
1467 break;
1468 }
1469 // case nsXPTType::T_VOID: /* fall through */
1470 case nsXPTType::T_IID:
1471 nsIID iid;
1472 MAKE_VALUE_BUFFER(sizeof(nsIID));
1473 if (!Py_nsIID::IIDFromPyObject(val, &iid))
1474 BREAK_FALSE;
1475 memcpy(this_buffer_pointer, &iid, sizeof(iid));
1476 ns_v.val.p = this_buffer_pointer;
1477 break;
1478 case nsXPTType::T_ASTRING:
1479 case nsXPTType::T_DOMSTRING: {
1480 nsString *s = new nsString();
1481 if (!s) {
1482 PyErr_NoMemory();
1483 BREAK_FALSE;
1484 }
1485 ns_v.val.p = s;
1486 // We created it - flag as such for cleanup.
1487 ns_v.flags |= nsXPTCVariant::VAL_IS_DOMSTR;
1488
1489 if (!PyObject_AsNSString(val, *s))
1490 BREAK_FALSE;
1491 break;
1492 }
1493 case nsXPTType::T_CSTRING:
1494 case nsXPTType::T_UTF8STRING: {
1495 PRBool bIsUTF8 = XPT_TDP_TAG(ns_v.type) == nsXPTType::T_UTF8STRING;
1496 if (val==Py_None) {
1497 ns_v.val.p = new nsCString();
1498 } else {
1499#if PY_MAJOR_VERSION <= 2
1500 if (PyString_Check(val)) {
1501 // strings are assumed to already be UTF8 encoded.
1502 val_use = val;
1503 Py_INCREF(val);
1504 }
1505 else
1506#endif
1507 if (PyUnicode_Check(val)) {
1508 // Unicode objects are encoded by us.
1509 if (bIsUTF8)
1510 val_use = PyUnicode_AsUTF8String(val);
1511 else
1512#if PY_MAJOR_VERSION <= 2
1513 val_use = PyObject_Str(val);
1514#else
1515 val_use = PyUnicode_AsUTF8String(val);
1516#endif
1517 } else {
1518#if PY_MAJOR_VERSION <= 2
1519 PyErr_SetString(PyExc_TypeError, "UTF8 parameters must be string or Unicode objects");
1520#else
1521 PyErr_SetString(PyExc_TypeError, "UTF8 parameters must be unicode objects");
1522#endif
1523 BREAK_FALSE;
1524 }
1525 if (!val_use)
1526 BREAK_FALSE;
1527#if PY_MAJOR_VERSION <= 2
1528 ns_v.val.p = new nsCString(PyString_AS_STRING(val_use),
1529 PyString_GET_SIZE(val_use));
1530#else
1531 ns_v.val.p = new nsCString(PyBytes_AS_STRING(val_use),
1532 PyBytes_GET_SIZE(val_use));
1533#endif
1534 }
1535
1536 if (!ns_v.val.p) {
1537 PyErr_NoMemory();
1538 BREAK_FALSE;
1539 }
1540 // We created it - flag as such for cleanup.
1541 ns_v.flags |= bIsUTF8 ? nsXPTCVariant::VAL_IS_UTF8STR : nsXPTCVariant::VAL_IS_CSTR;
1542 break;
1543 }
1544 case nsXPTType::T_CHAR_STR: {
1545 if (val==Py_None) {
1546 ns_v.val.p = nsnull;
1547 break;
1548 }
1549#if PY_MAJOR_VERSION <= 2
1550 // If an "in" char *, and we have a PyString, then pass the
1551 // pointer (hoping everyone else plays by the rules too.
1552 if (!XPT_PD_IS_OUT(td.param_flags) && PyString_Check(val)) {
1553 ns_v.val.p = (void *)PyString_AS_STRING(val);
1554 break;
1555 }
1556
1557 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
1558 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
1559 BREAK_FALSE;
1560 }
1561 if ((val_use = PyObject_Str(val))==NULL)
1562 BREAK_FALSE;
1563 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
1564 NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
1565
1566 cb_this_buffer_pointer = PyString_GET_SIZE(val_use)+1;
1567 MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
1568 memcpy(this_buffer_pointer, PyString_AS_STRING(val_use), cb_this_buffer_pointer);
1569#else
1570
1571 if (!PyUnicode_Check(val)) {
1572 PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object");
1573 BREAK_FALSE;
1574 }
1575 if ((val_use = PyUnicode_AsUTF8String(val))==NULL)
1576 BREAK_FALSE;
1577
1578 cb_this_buffer_pointer = PyBytes_GET_SIZE(val_use)+1;
1579 MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
1580 memcpy(this_buffer_pointer, PyBytes_AS_STRING(val_use), cb_this_buffer_pointer);
1581#endif
1582 ns_v.val.p = this_buffer_pointer;
1583 break;
1584 }
1585
1586 case nsXPTType::T_WCHAR_STR: {
1587 if (val==Py_None) {
1588 ns_v.val.p = nsnull;
1589 break;
1590 }
1591#if PY_MAJOR_VERSION <= 2
1592 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
1593 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
1594 BREAK_FALSE;
1595 }
1596 if ((val_use = PyUnicode_FromObject(val))==NULL)
1597 BREAK_FALSE;
1598 NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyUnicode_FromObject didnt return a Unicode object!");
1599#else
1600 if (!PyUnicode_Check(val)) {
1601 PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object");
1602 BREAK_FALSE;
1603 }
1604 val_use = val;
1605 Py_INCREF(val_use);
1606#endif
1607 PRUnichar *sv;
1608 PRUint32 nch;
1609 if (PyUnicode_AsPRUnichar(val_use, &sv, &nch) < 0)
1610 BREAK_FALSE;
1611 cb_this_buffer_pointer = (nch + 1) * sizeof(PRUnichar);
1612 this_buffer_pointer = sv;
1613 ns_v.val.p = this_buffer_pointer;
1614 break;
1615 }
1616 case nsXPTType::T_INTERFACE: {
1617 nsIID iid;
1618 if (!Py_nsIID::IIDFromPyObject(td.extra, &iid))
1619 BREAK_FALSE;
1620 if (!Py_nsISupports::InterfaceFromPyObject(
1621 val,
1622 iid,
1623 (nsISupports **)&ns_v.val.p,
1624 PR_TRUE))
1625 BREAK_FALSE;
1626 // We have added a reference - flag as such for cleanup.
1627 ns_v.flags |= nsXPTCVariant::VAL_IS_IFACE;
1628 break;
1629 }
1630 case nsXPTType::T_INTERFACE_IS: {
1631 nsIID iid;
1632 nsXPTCVariant &ns_viid = m_var_array[td.argnum];
1633 NS_WARN_IF_FALSE(XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID, "The INTERFACE_IS iid describer isnt an IID!");
1634 // This is a pretty serious problem, but not Python's fault!
1635 // Just return an nsISupports and hope the caller does whatever
1636 // QI they need before using it.
1637 if (XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID &&
1638 XPT_PD_IS_IN(ns_viid.type)) {
1639 nsIID *piid = (nsIID *)ns_viid.val.p;
1640 if (piid==NULL)
1641 // Also serious, but like below, not our fault!
1642 iid = NS_GET_IID(nsISupports);
1643 else
1644 iid = *piid;
1645 } else
1646 // Use NULL IID to avoid a QI in this case.
1647 iid = Py_nsIID_NULL;
1648 if (!Py_nsISupports::InterfaceFromPyObject(
1649 val,
1650 iid,
1651 (nsISupports **)&ns_v.val.p,
1652 PR_TRUE))
1653 BREAK_FALSE;
1654 // We have added a reference - flag as such for cleanup.
1655 ns_v.flags |= nsXPTCVariant::VAL_IS_IFACE;
1656 break;
1657 }
1658 case nsXPTType::T_PSTRING_SIZE_IS: {
1659 if (val==Py_None) {
1660 ns_v.val.p = nsnull;
1661 break;
1662 }
1663#if PY_MAJOR_VERSION <= 2
1664 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
1665 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
1666 BREAK_FALSE;
1667 }
1668 if ((val_use = PyObject_Str(val))==NULL)
1669 BREAK_FALSE;
1670 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
1671 NS_ABORT_IF_FALSE(PyString_Check(val_use), "PyObject_Str didnt return a string object!");
1672
1673 cb_this_buffer_pointer = PyString_GET_SIZE(val_use);
1674 MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
1675 memcpy(this_buffer_pointer, PyString_AS_STRING(val_use), cb_this_buffer_pointer);
1676#else
1677 if (!PyUnicode_Check(val)) {
1678 PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object");
1679 BREAK_FALSE;
1680 }
1681 if ((val_use = PyUnicode_AsUTF8String(val))==NULL)
1682 BREAK_FALSE;
1683
1684 cb_this_buffer_pointer = PyBytes_GET_SIZE(val_use);
1685 MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
1686 memcpy(this_buffer_pointer, PyBytes_AS_STRING(val_use), cb_this_buffer_pointer);
1687#endif
1688 ns_v.val.p = this_buffer_pointer;
1689 rc = SetSizeIs(value_index, PR_TRUE, cb_this_buffer_pointer);
1690 break;
1691 }
1692
1693 case nsXPTType::T_PWSTRING_SIZE_IS: {
1694 if (val==Py_None) {
1695 ns_v.val.p = nsnull;
1696 break;
1697 }
1698#if PY_MAJOR_VERSION <= 2
1699 if (!PyString_Check(val) && !PyUnicode_Check(val)) {
1700 PyErr_SetString(PyExc_TypeError, "This parameter must be a string or Unicode object");
1701 BREAK_FALSE;
1702 }
1703 if ((val_use = PyUnicode_FromObject(val))==NULL)
1704 BREAK_FALSE;
1705 // Sanity check should PyObject_Str() ever loosen its semantics wrt Unicode!
1706 NS_ABORT_IF_FALSE(PyUnicode_Check(val_use), "PyObject_Unicode didnt return a unicode object!");
1707#else
1708 if (!PyUnicode_Check(val)) {
1709 PyErr_SetString(PyExc_TypeError, "This parameter must be a unicode object");
1710 BREAK_FALSE;
1711 }
1712 val_use = val;
1713 Py_INCREF(val_use);
1714#endif
1715 PRUnichar *sv;
1716 PRUint32 nch;
1717 if (PyUnicode_AsPRUnichar(val_use, &sv, &nch) < 0)
1718 BREAK_FALSE;
1719 cb_this_buffer_pointer = (nch + 1) * sizeof(PRUnichar);
1720 this_buffer_pointer = sv;
1721 ns_v.val.p = this_buffer_pointer;
1722 rc = SetSizeIs(value_index, PR_TRUE, nch);
1723 break;
1724 }
1725 case nsXPTType::T_ARRAY: {
1726 if (val==Py_None) {
1727 ns_v.val.p = nsnull;
1728 break;
1729 }
1730 if (!PyInt_Check(td.extra)) {
1731 PyErr_SetString(PyExc_TypeError, "The array info is not valid");
1732 BREAK_FALSE;
1733 }
1734 if (!PySequence_Check(val)) {
1735 PyErr_SetString(PyExc_TypeError, "This parameter must be a sequence");
1736 BREAK_FALSE;
1737 }
1738 int array_type = PyInt_AsLong(td.extra);
1739 PRUint32 element_size = GetArrayElementSize(array_type);
1740 int seq_length = PySequence_Length(val);
1741 cb_this_buffer_pointer = seq_length * element_size;
1742 if (cb_this_buffer_pointer==0)
1743 // prevent assertions allocing zero bytes. Can't use NULL.
1744 cb_this_buffer_pointer = 1;
1745 MAKE_VALUE_BUFFER(cb_this_buffer_pointer);
1746 memset(this_buffer_pointer, 0, cb_this_buffer_pointer);
1747 rc = FillSingleArray(this_buffer_pointer, val, seq_length, element_size, array_type&XPT_TDP_TAGMASK, nsnull);
1748 if (!rc) break;
1749 rc = SetSizeIs(value_index, PR_FALSE, seq_length);
1750 if (!rc) break;
1751 ns_v.flags |= nsXPTCVariant::VAL_IS_ARRAY;
1752 ns_v.val.p = this_buffer_pointer;
1753 break;
1754 }
1755 default:
1756 PyErr_Format(PyExc_TypeError, "The object type (0x%x) is unknown", XPT_TDP_TAG(ns_v.type));
1757 rc = PR_FALSE;
1758 break;
1759 }
1760 Py_DECREF(val); // Cant be NULL!
1761 Py_XDECREF(val_use);
1762 }
1763 return rc && !PyErr_Occurred();
1764}
1765
1766PRBool PyXPCOM_InterfaceVariantHelper::PrepareOutVariant(const PythonTypeDescriptor &td, int value_index)
1767{
1768 PRBool rc = PR_TRUE;
1769 nsXPTCVariant &ns_v = m_var_array[value_index];
1770 void *&this_buffer_pointer = m_buffer_array[value_index]; // Freed at object destruction with PyMem_Free()
1771 // Do the out param thang...
1772 if (XPT_PD_IS_OUT(td.param_flags) || XPT_PD_IS_DIPPER(td.param_flags)) {
1773 NS_ABORT_IF_FALSE(ns_v.ptr == NULL, "already have a pointer!");
1774 ns_v.ptr = &ns_v;
1775 ns_v.flags |= nsXPTCVariant::PTR_IS_DATA;
1776
1777 // Special flags based on the data type
1778 switch (XPT_TDP_TAG(ns_v.type)) {
1779 case nsXPTType::T_I8:
1780 case nsXPTType::T_I16:
1781 case nsXPTType::T_I32:
1782 case nsXPTType::T_I64:
1783 case nsXPTType::T_U8:
1784 case nsXPTType::T_U16:
1785 case nsXPTType::T_U32:
1786 case nsXPTType::T_U64:
1787 case nsXPTType::T_FLOAT:
1788 case nsXPTType::T_DOUBLE:
1789 case nsXPTType::T_BOOL:
1790 case nsXPTType::T_CHAR:
1791 case nsXPTType::T_WCHAR:
1792 case nsXPTType::T_VOID:
1793 break;
1794
1795 case nsXPTType::T_INTERFACE:
1796 case nsXPTType::T_INTERFACE_IS:
1797 NS_ABORT_IF_FALSE(this_buffer_pointer==NULL, "Can't have an interface and a buffer pointer!");
1798 ns_v.flags |= nsXPTCVariant::VAL_IS_IFACE;
1799 ns_v.flags |= nsXPTCVariant::VAL_IS_ALLOCD;
1800 break;
1801 case nsXPTType::T_ARRAY:
1802 ns_v.flags |= nsXPTCVariant::VAL_IS_ARRAY;
1803 ns_v.flags |= nsXPTCVariant::VAL_IS_ALLOCD;
1804 // Even if ns_val.p already setup as part of "in" processing,
1805 // we need to ensure setup for out.
1806 NS_ABORT_IF_FALSE(ns_v.val.p==nsnull || ns_v.val.p==this_buffer_pointer, "Garbage in our pointer?");
1807 ns_v.val.p = this_buffer_pointer;
1808 this_buffer_pointer = nsnull;
1809 break;
1810 case nsXPTType::T_PWSTRING_SIZE_IS:
1811 case nsXPTType::T_PSTRING_SIZE_IS:
1812 case nsXPTType::T_WCHAR_STR:
1813 case nsXPTType::T_CHAR_STR:
1814 case nsXPTType::T_IID:
1815 // If we stashed a value in the this_buffer_pointer, and
1816 // we are passing it as an OUT param, we do _not_ want to
1817 // treat it as a temporary buffer.
1818 // For example, if we pass an IID or string as an IN param,
1819 // we allocate a buffer for the value, but this is NOT cleaned up
1820 // via normal VARIANT cleanup rules - hence we clean it up ourselves.
1821 // If the param is IN/OUT, then the buffer falls under the normal variant
1822 // rules (ie, is flagged as VAL_IS_ALLOCD), so we dont clean it as a temporary.
1823 // (it may have been changed under us - we free the _new_ value.
1824 // Even if ns_val.p already setup as part of "in" processing,
1825 // we need to ensure setup for out.
1826 NS_ABORT_IF_FALSE(ns_v.val.p==nsnull || ns_v.val.p==this_buffer_pointer, "Garbage in our pointer?");
1827 ns_v.val.p = this_buffer_pointer;
1828 ns_v.flags |= nsXPTCVariant::VAL_IS_ALLOCD;
1829 this_buffer_pointer = nsnull;
1830 break;
1831 case nsXPTType::T_DOMSTRING:
1832 case nsXPTType::T_ASTRING: {
1833 NS_ABORT_IF_FALSE(ns_v.val.p==nsnull, "T_DOMTSTRINGS cant be out and have a value (ie, no in/outs are allowed!");
1834 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!");
1835 ns_v.flags |= nsXPTCVariant::VAL_IS_DOMSTR;
1836 // Dippers are really treated like "in" params.
1837 ns_v.ptr = new nsString();
1838 ns_v.val.p = ns_v.ptr; // VAL_IS_* says the .p is what gets freed
1839 if (!ns_v.ptr) {
1840 PyErr_NoMemory();
1841 rc = PR_FALSE;
1842 }
1843 break;
1844 }
1845 case nsXPTType::T_CSTRING:
1846 case nsXPTType::T_UTF8STRING: {
1847 NS_ABORT_IF_FALSE(ns_v.val.p==nsnull, "T_DOMTSTRINGS cant be out and have a value (ie, no in/outs are allowed!");
1848 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!");
1849 ns_v.flags |= ( XPT_TDP_TAG(ns_v.type)==nsXPTType::T_CSTRING ? nsXPTCVariant::VAL_IS_CSTR : nsXPTCVariant::VAL_IS_UTF8STR);
1850 ns_v.ptr = new nsCString();
1851 ns_v.val.p = ns_v.ptr; // VAL_IS_* says the .p is what gets freed
1852 if (!ns_v.ptr) {
1853 PyErr_NoMemory();
1854 rc = PR_FALSE;
1855 }
1856 break;
1857 }
1858 default:
1859 NS_ABORT_IF_FALSE(0, "Unknown type - don't know how to prepare the output value");
1860 break; // Nothing to do!
1861 }
1862 }
1863 return rc;
1864}
1865
1866
1867PyObject *PyXPCOM_InterfaceVariantHelper::MakeSinglePythonResult(int index)
1868{
1869 nsXPTCVariant &ns_v = m_var_array[index];
1870 PyObject *ret = nsnull;
1871 NS_ABORT_IF_FALSE(ns_v.IsPtrData() || ns_v.IsValDOMString(), "expecting a pointer if you want a result!");
1872
1873 // Re-fetch the type descriptor.
1874 PythonTypeDescriptor &td = m_python_type_desc_array[index];
1875 // Make sure the type tag of the variant hasnt changed on us.
1876 NS_ABORT_IF_FALSE(ns_v.type==td.type_flags, "variant type has changed under us!");
1877
1878 // If the pointer is NULL, we can get out now!
1879 if (ns_v.ptr==nsnull) {
1880 Py_INCREF(Py_None);
1881 return Py_None;
1882 }
1883
1884 switch (XPT_TDP_TAG(ns_v.type)) {
1885 case nsXPTType::T_I8:
1886 ret = PyInt_FromLong( *((PRInt8 *)ns_v.ptr) );
1887 break;
1888 case nsXPTType::T_I16:
1889 ret = PyInt_FromLong( *((PRInt16 *)ns_v.ptr) );
1890 break;
1891 case nsXPTType::T_I32:
1892 ret = PyInt_FromLong( *((PRInt32 *)ns_v.ptr) );
1893 break;
1894 case nsXPTType::T_I64:
1895 ret = PyLong_FromLongLong( *((PRInt64 *)ns_v.ptr) );
1896 break;
1897 case nsXPTType::T_U8:
1898 ret = PyInt_FromLong( *((PRUint8 *)ns_v.ptr) );
1899 break;
1900 case nsXPTType::T_U16:
1901 ret = PyInt_FromLong( *((PRUint16 *)ns_v.ptr) );
1902 break;
1903 case nsXPTType::T_U32:
1904 ret = PyInt_FromLong( *((PRUint32 *)ns_v.ptr) );
1905 break;
1906 case nsXPTType::T_U64:
1907 ret = PyLong_FromUnsignedLongLong( *((PRUint64 *)ns_v.ptr) );
1908 break;
1909 case nsXPTType::T_FLOAT:
1910 ret = PyFloat_FromDouble( *((float *)ns_v.ptr) );
1911 break;
1912 case nsXPTType::T_DOUBLE:
1913 ret = PyFloat_FromDouble( *((double *)ns_v.ptr) );
1914 break;
1915 case nsXPTType::T_BOOL:
1916 ret = *((PRBool *)ns_v.ptr) ? Py_True : Py_False;
1917 Py_INCREF(ret);
1918 break;
1919 case nsXPTType::T_CHAR:
1920#if PY_MAJOR_VERSION <= 2
1921 ret = PyString_FromStringAndSize( ((char *)ns_v.ptr), 1 );
1922#else
1923 ret = PyUnicode_FromStringAndSize( ((char *)ns_v.ptr), 1 );
1924#endif
1925 break;
1926
1927 case nsXPTType::T_WCHAR:
1928 ret = PyUnicode_FromPRUnichar( ((PRUnichar *)ns_v.ptr), 1 );
1929 break;
1930// case nsXPTType::T_VOID:
1931 case nsXPTType::T_IID:
1932 ret = Py_nsIID::PyObjectFromIID( **((nsIID **)ns_v.ptr) );
1933 break;
1934 case nsXPTType::T_ASTRING:
1935 case nsXPTType::T_DOMSTRING: {
1936 nsAString *rs = (nsAString *)ns_v.ptr;
1937 ret = PyObject_FromNSString(*rs);
1938 break;
1939 }
1940 case nsXPTType::T_UTF8STRING:
1941 case nsXPTType::T_CSTRING: {
1942 nsCString *rs = (nsCString *)ns_v.ptr;
1943 ret = PyObject_FromNSString(*rs, XPT_TDP_TAG(ns_v.type)==nsXPTType::T_UTF8STRING);
1944 break;
1945 }
1946
1947 case nsXPTType::T_CHAR_STR:
1948 if (*((char **)ns_v.ptr) == NULL) {
1949 ret = Py_None;
1950 Py_INCREF(Py_None);
1951 } else
1952#if PY_MAJOR_VERSION <= 2
1953 ret = PyString_FromString( *((char **)ns_v.ptr) );
1954#else
1955 ret = PyUnicode_FromString( *((char **)ns_v.ptr) );
1956#endif
1957 break;
1958
1959 case nsXPTType::T_WCHAR_STR: {
1960 PRUnichar *us = *((PRUnichar **)ns_v.ptr);
1961 if (us == NULL) {
1962 ret = Py_None;
1963 Py_INCREF(Py_None);
1964 } else {
1965 ret = PyUnicode_FromPRUnichar( us, nsCRT::strlen(us));
1966 }
1967 break;
1968 }
1969 case nsXPTType::T_INTERFACE: {
1970 nsIID iid;
1971 if (!Py_nsIID::IIDFromPyObject(td.extra, &iid))
1972 break;
1973 nsISupports *iret = *((nsISupports **)ns_v.ptr);
1974 // Our cleanup code manages iret reference ownership, and our
1975 // new object takes its own.
1976 if (iid.Equals(NS_GET_IID(nsIVariant)))
1977 ret = PyObject_FromVariant(m_parent, (nsIVariant *)iret);
1978 else
1979 ret = m_parent->MakeInterfaceResult(iret, iid);
1980 break;
1981 }
1982 case nsXPTType::T_INTERFACE_IS: {
1983 nsIID iid;
1984 nsXPTCVariant &ns_viid = m_var_array[td.argnum];
1985 NS_WARN_IF_FALSE(XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID, "The INTERFACE_IS iid describer isnt an IID!");
1986 if (XPT_TDP_TAG(ns_viid.type)==nsXPTType::T_IID) {
1987 nsIID *piid = (nsIID *)ns_viid.val.p;
1988 if (piid==NULL)
1989 // Also serious, but like below, not our fault!
1990 iid = NS_GET_IID(nsISupports);
1991 else
1992 iid = *piid;
1993 } else {
1994 // This is a pretty serious problem, but not Python's fault!
1995 // Just return an nsISupports and hope the caller does whatever
1996 // QI they need before using it.
1997 NS_ERROR("Failed to get the IID for T_INTERFACE_IS!");
1998 iid = NS_GET_IID(nsISupports);
1999 }
2000 nsISupports *iret = *((nsISupports **)ns_v.ptr);
2001 if (iid.Equals(NS_GET_IID(nsIVariant)))
2002 ret = PyObject_FromVariant(m_parent, (nsIVariant *)iret);
2003 else
2004 ret = m_parent->MakeInterfaceResult(iret, iid);
2005 break;
2006 }
2007 case nsXPTType::T_ARRAY: {
2008 if ( (* ((void **)ns_v.ptr)) == NULL) {
2009 ret = Py_None;
2010 Py_INCREF(Py_None);
2011 }
2012 if (!PyInt_Check(td.extra)) {
2013 PyErr_SetString(PyExc_TypeError, "The array info is not valid");
2014 break;
2015 }
2016 PRUint8 array_type = (PRUint8)PyInt_AsLong(td.extra);
2017 PRUint32 seq_size = GetSizeIs(index, PR_FALSE);
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.

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