VirtualBox

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

Last change on this file was 103505, checked in by vboxsync, 2 months ago

libs/xpcom: Fix some unused variable warnings, bugref:3409

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

© 2023 Oracle
ContactPrivacy policyTerms of Use