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 | * Alternatively, the contents of this file may be used under the terms of
|
---|
25 | * either the GNU General Public License Version 2 or later (the "GPL"), or
|
---|
26 | * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
---|
27 | * in which case the provisions of the GPL or the LGPL are applicable instead
|
---|
28 | * of those above. If you wish to allow use of your version of this file only
|
---|
29 | * under the terms of either the GPL or the LGPL, and not to allow others to
|
---|
30 | * use your version of this file under the terms of the MPL, indicate your
|
---|
31 | * decision by deleting the provisions above and replace them with the notice
|
---|
32 | * and other provisions required by the GPL or the LGPL. If you do not delete
|
---|
33 | * the provisions above, a recipient may use your version of this file under
|
---|
34 | * the terms of any one of the MPL, the GPL or the LGPL.
|
---|
35 | *
|
---|
36 | * ***** END LICENSE BLOCK ***** */
|
---|
37 |
|
---|
38 | // Py_nsIID.cpp -- IID type for Python/XPCOM
|
---|
39 | //
|
---|
40 | // This code is part of the XPCOM extensions for Python.
|
---|
41 | //
|
---|
42 | // Written May 2000 by Mark Hammond.
|
---|
43 | //
|
---|
44 | // Based heavily on the Python COM support, which is
|
---|
45 | // (c) Mark Hammond and Greg Stein.
|
---|
46 | //
|
---|
47 | // (c) 2000, ActiveState corp.
|
---|
48 | //
|
---|
49 | // @doc
|
---|
50 |
|
---|
51 | #include "PyXPCOM_std.h"
|
---|
52 | #include <nsIInterfaceInfoManager.h>
|
---|
53 |
|
---|
54 | nsIID Py_nsIID_NULL = {0,0,0,{0,0,0,0,0,0,0,0}};
|
---|
55 |
|
---|
56 | // @pymethod <o Py_nsIID>|xpcom|IID|Creates a new IID object
|
---|
57 | PYXPCOM_EXPORT PyObject *PyXPCOMMethod_IID(PyObject *self, PyObject *args)
|
---|
58 | {
|
---|
59 | PyObject *obIID;
|
---|
60 | PyObject *obBuf;
|
---|
61 | if ( PyArg_ParseTuple(args, "O", &obBuf)) {
|
---|
62 | #if PY_MAJOR_VERSION <= 2
|
---|
63 | if (PyBuffer_Check(obBuf)) {
|
---|
64 | PyBufferProcs *pb = NULL;
|
---|
65 | pb = obBuf->ob_type->tp_as_buffer;
|
---|
66 | void *buf = NULL;
|
---|
67 | int size = (*pb->bf_getreadbuffer)(obBuf, 0, &buf);
|
---|
68 | #else
|
---|
69 | if (PyObject_CheckBuffer(obBuf)) {
|
---|
70 | # ifndef Py_LIMITED_API
|
---|
71 | Py_buffer view;
|
---|
72 | if (PyObject_GetBuffer(obBuf, &view, PyBUF_CONTIG_RO) != 0) {
|
---|
73 | PyErr_Format(PyExc_ValueError, "Could not get contiguous buffer from object");
|
---|
74 | return NULL;
|
---|
75 | }
|
---|
76 | Py_ssize_t size = view.len;
|
---|
77 | const void *buf = view.buf;
|
---|
78 | # else /* Py_LIMITED_API - the buffer API is non-existant, from what I can tell */
|
---|
79 | const void *buf = NULL;
|
---|
80 | Py_ssize_t size = 0;
|
---|
81 | if (PyObject_AsReadBuffer(obBuf, &buf, &size) != 0) {
|
---|
82 | PyErr_Format(PyExc_ValueError, "Could not get read-only buffer from object");
|
---|
83 | return NULL;
|
---|
84 | }
|
---|
85 | # endif /* Py_LIMITED_API */
|
---|
86 | #endif
|
---|
87 | if (size != sizeof(nsIID) || buf==NULL) {
|
---|
88 | #if PY_MAJOR_VERSION >= 3 && !defined(Py_LIMITED_API)
|
---|
89 | PyBuffer_Release(&view);
|
---|
90 | #endif
|
---|
91 | #ifdef VBOX
|
---|
92 | PyErr_Format(PyExc_ValueError, "A buffer object to be converted to an IID must be exactly %d bytes long", (int)sizeof(nsIID));
|
---|
93 | #else
|
---|
94 | PyErr_Format(PyExc_ValueError, "A buffer object to be converted to an IID must be exactly %d bytes long", sizeof(nsIID));
|
---|
95 | #endif
|
---|
96 | return NULL;
|
---|
97 | }
|
---|
98 | nsIID iid;
|
---|
99 | unsigned char const *ptr = (unsigned char const *)buf;
|
---|
100 | iid.m0 = XPT_SWAB32(*((PRUint32 *)ptr));
|
---|
101 | ptr = ((unsigned char const *)buf) + offsetof(nsIID, m1);
|
---|
102 | iid.m1 = XPT_SWAB16(*((PRUint16 *)ptr));
|
---|
103 | ptr = ((unsigned char const *)buf) + offsetof(nsIID, m2);
|
---|
104 | iid.m2 = XPT_SWAB16(*((PRUint16 *)ptr));
|
---|
105 | ptr = ((unsigned char const *)buf) + offsetof(nsIID, m3);
|
---|
106 | for (int i=0;i<8;i++) {
|
---|
107 | iid.m3[i] = *((PRUint8 const *)ptr);
|
---|
108 | ptr += sizeof(PRUint8);
|
---|
109 | }
|
---|
110 | #if PY_MAJOR_VERSION >= 3 && !defined(Py_LIMITED_API)
|
---|
111 | PyBuffer_Release(&view);
|
---|
112 | #endif
|
---|
113 | return new Py_nsIID(iid);
|
---|
114 | }
|
---|
115 | }
|
---|
116 | PyErr_Clear();
|
---|
117 | // @pyparm string/Unicode|iidString||A string representation of an IID, or a ContractID.
|
---|
118 | if ( !PyArg_ParseTuple(args, "O", &obIID) )
|
---|
119 | return NULL;
|
---|
120 |
|
---|
121 | nsIID iid;
|
---|
122 | if (!Py_nsIID::IIDFromPyObject(obIID, &iid))
|
---|
123 | return NULL;
|
---|
124 | return new Py_nsIID(iid);
|
---|
125 | }
|
---|
126 |
|
---|
127 | /*static*/ PRBool
|
---|
128 | Py_nsIID::IIDFromPyObject(PyObject *ob, nsIID *pRet) {
|
---|
129 | PRBool ok = PR_TRUE;
|
---|
130 | nsIID iid;
|
---|
131 | if (ob==NULL) {
|
---|
132 | PyErr_SetString(PyExc_RuntimeError, "The IID object is invalid!");
|
---|
133 | return PR_FALSE;
|
---|
134 | }
|
---|
135 | #if PY_MAJOR_VERSION <= 2
|
---|
136 | if (PyString_Check(ob)) {
|
---|
137 | ok = iid.Parse(PyString_AsString(ob));
|
---|
138 | #else
|
---|
139 | if (PyUnicode_Check(ob)) {
|
---|
140 | ok = iid.Parse(PyUnicode_AsUTF8(ob));
|
---|
141 | #endif
|
---|
142 | if (!ok) {
|
---|
143 | PyXPCOM_BuildPyException(NS_ERROR_ILLEGAL_VALUE);
|
---|
144 | return PR_FALSE;
|
---|
145 | }
|
---|
146 | #ifndef Py_LIMITED_API
|
---|
147 | } else if (ob->ob_type == &type) {
|
---|
148 | #else
|
---|
149 | } else if (ob->ob_type == Py_nsIID::GetTypeObject()) {
|
---|
150 | #endif
|
---|
151 | iid = ((Py_nsIID *)ob)->m_iid;
|
---|
152 | } else if (PyObject_HasAttrString(ob, "__class__")) {
|
---|
153 | // Get the _iidobj_ attribute
|
---|
154 | PyObject *use_ob = PyObject_GetAttrString(ob, "_iidobj_");
|
---|
155 | if (use_ob==NULL) {
|
---|
156 | PyErr_SetString(PyExc_TypeError, "Only instances with _iidobj_ attributes can be used as IID objects");
|
---|
157 | return PR_FALSE;
|
---|
158 | }
|
---|
159 | #ifndef Py_LIMITED_API
|
---|
160 | if (use_ob->ob_type != &type) {
|
---|
161 | #else
|
---|
162 | if (use_ob->ob_type != Py_nsIID::GetTypeObject()) {
|
---|
163 | #endif
|
---|
164 | Py_DECREF(use_ob);
|
---|
165 | PyErr_SetString(PyExc_TypeError, "instance _iidobj_ attributes must be raw IID object");
|
---|
166 | return PR_FALSE;
|
---|
167 | }
|
---|
168 | iid = ((Py_nsIID *)use_ob)->m_iid;
|
---|
169 | Py_DECREF(use_ob);
|
---|
170 | } else {
|
---|
171 | PyErr_Format(PyExc_TypeError, "Objects of type '%s' can not be converted to an IID", PyXPCOM_ObTypeName(ob));
|
---|
172 | ok = PR_FALSE;
|
---|
173 | }
|
---|
174 | if (ok) *pRet = iid;
|
---|
175 | return ok;
|
---|
176 | }
|
---|
177 |
|
---|
178 |
|
---|
179 | // @object Py_nsIID|A Python object, representing an IID/CLSID.
|
---|
180 | // <nl>All pythoncom functions that return a CLSID/IID will return one of these
|
---|
181 | // objects. However, in almost all cases, functions that expect a CLSID/IID
|
---|
182 | // as a param will accept either a string object, or a native Py_nsIID object.
|
---|
183 | #ifndef Py_LIMITED_API
|
---|
184 | PyTypeObject Py_nsIID::type =
|
---|
185 | {
|
---|
186 | PyVarObject_HEAD_INIT(&PyType_Type, 0)
|
---|
187 | "IID",
|
---|
188 | sizeof(Py_nsIID),
|
---|
189 | 0,
|
---|
190 | PyTypeMethod_dealloc, /* tp_dealloc */
|
---|
191 | 0, /* tp_print */
|
---|
192 | PyTypeMethod_getattr, /* tp_getattr */
|
---|
193 | 0, /* tp_setattr */
|
---|
194 | #if PY_MAJOR_VERSION <= 2
|
---|
195 | PyTypeMethod_compare, /* tp_compare */
|
---|
196 | #else
|
---|
197 | 0, /* reserved */
|
---|
198 | #endif
|
---|
199 | PyTypeMethod_repr, /* tp_repr */
|
---|
200 | 0, /* tp_as_number */
|
---|
201 | 0, /* tp_as_sequence */
|
---|
202 | 0, /* tp_as_mapping */
|
---|
203 | PyTypeMethod_hash, /* tp_hash */
|
---|
204 | 0, /* tp_call */
|
---|
205 | PyTypeMethod_str, /* tp_str */
|
---|
206 | 0, /* tp_getattro */
|
---|
207 | 0, /* tp_setattro */
|
---|
208 | 0, /* tp_as_buffer */
|
---|
209 | 0, /* tp_flags */
|
---|
210 | 0, /* tp_doc */
|
---|
211 | 0, /* tp_traverse */
|
---|
212 | 0, /* tp_clear */
|
---|
213 | PyTypeMethod_richcompare, /* tp_richcompare */
|
---|
214 | 0, /* tp_weaklistoffset */
|
---|
215 | 0, /* tp_iter */
|
---|
216 | 0, /* tp_iternext */
|
---|
217 | 0, /* tp_methods */
|
---|
218 | 0, /* tp_members */
|
---|
219 | 0, /* tp_getset */
|
---|
220 | 0, /* tp_base */
|
---|
221 | };
|
---|
222 | #else /* Py_LIMITED_API */
|
---|
223 | NS_EXPORT_STATIC_MEMBER_(PyTypeObject *) Py_nsIID::s_pType = NULL;
|
---|
224 |
|
---|
225 | PyTypeObject *Py_nsIID::GetTypeObject(void)
|
---|
226 | {
|
---|
227 | PyTypeObject *pTypeObj = Py_nsIID::s_pType;
|
---|
228 | if (pTypeObj)
|
---|
229 | return pTypeObj;
|
---|
230 |
|
---|
231 | PyType_Slot aTypeSlots[] = {
|
---|
232 | { Py_tp_base, &PyType_Type },
|
---|
233 | { Py_tp_dealloc, (void *)(uintptr_t)&Py_nsIID::PyTypeMethod_dealloc },
|
---|
234 | { Py_tp_getattr, (void *)(uintptr_t)&Py_nsIID::PyTypeMethod_getattr },
|
---|
235 | { Py_tp_repr, (void *)(uintptr_t)&Py_nsIID::PyTypeMethod_repr },
|
---|
236 | { Py_tp_hash, (void *)(uintptr_t)&Py_nsIID::PyTypeMethod_hash },
|
---|
237 | { Py_tp_str, (void *)(uintptr_t)&Py_nsIID::PyTypeMethod_str },
|
---|
238 | { Py_tp_richcompare, (void *)(uintptr_t)&Py_nsIID::PyTypeMethod_richcompare },
|
---|
239 | { Py_tp_is_gc, (void *)(uintptr_t)&Py_nsIID::PyTypeMethod_is_gc },
|
---|
240 | { 0, NULL } /* terminator */
|
---|
241 | };
|
---|
242 | PyType_Spec TypeSpec = {
|
---|
243 | /* .name: */ "IID",
|
---|
244 | /* .basicsize: */ sizeof(Py_nsIID),
|
---|
245 | /* .itemsize: */ 0,
|
---|
246 | /* .flags: */ Py_TPFLAGS_DEFAULT,
|
---|
247 | /* .slots: */ aTypeSlots,
|
---|
248 | };
|
---|
249 |
|
---|
250 | PyObject *exc_typ = NULL, *exc_val = NULL, *exc_tb = NULL;
|
---|
251 | PyErr_Fetch(&exc_typ, &exc_val, &exc_tb); /* goes south in PyType_Ready if we don't clear exceptions first. */
|
---|
252 |
|
---|
253 | pTypeObj = (PyTypeObject *)PyType_FromSpec(&TypeSpec);
|
---|
254 | assert(pTypeObj);
|
---|
255 |
|
---|
256 | PyErr_Restore(exc_typ, exc_val, exc_tb);
|
---|
257 | Py_nsIID::s_pType = pTypeObj;
|
---|
258 | return pTypeObj;
|
---|
259 | }
|
---|
260 | #endif /* Py_LIMITED_API */
|
---|
261 |
|
---|
262 | Py_nsIID::Py_nsIID(const nsIID &riid)
|
---|
263 | {
|
---|
264 | #ifndef Py_LIMITED_API
|
---|
265 | ob_type = &type;
|
---|
266 | #else
|
---|
267 | ob_type = GetTypeObject();
|
---|
268 | #endif
|
---|
269 | #if 1 /* VBox: Must use for 3.9+, includes _Py_NewReferences. Works for all older versions too. @bugref{10079} */
|
---|
270 | PyObject_Init(this, ob_type);
|
---|
271 | #else
|
---|
272 | _Py_NewReference(this);
|
---|
273 | #endif
|
---|
274 |
|
---|
275 | m_iid = riid;
|
---|
276 | }
|
---|
277 |
|
---|
278 | /*static*/PyObject *
|
---|
279 | Py_nsIID::PyTypeMethod_getattr(PyObject *self, char *name)
|
---|
280 | {
|
---|
281 | Py_nsIID *me = (Py_nsIID *)self;
|
---|
282 | if (strcmp(name, "name")==0) {
|
---|
283 | char *iid_repr = nsnull;
|
---|
284 | nsCOMPtr<nsIInterfaceInfoManager> iim(do_GetService(
|
---|
285 | NS_INTERFACEINFOMANAGER_SERVICE_CONTRACTID));
|
---|
286 | if (iim!=nsnull)
|
---|
287 | iim->GetNameForIID(&me->m_iid, &iid_repr);
|
---|
288 | if (iid_repr==nsnull)
|
---|
289 | iid_repr = me->m_iid.ToString();
|
---|
290 | PyObject *ret;
|
---|
291 | if (iid_repr != nsnull) {
|
---|
292 | #if PY_MAJOR_VERSION <= 2
|
---|
293 | ret = PyString_FromString(iid_repr);
|
---|
294 | #else
|
---|
295 | ret = PyUnicode_FromString(iid_repr);
|
---|
296 | #endif
|
---|
297 | nsMemory::Free(iid_repr);
|
---|
298 | } else
|
---|
299 | #if PY_MAJOR_VERSION <= 2
|
---|
300 | ret = PyString_FromString("<cant get IID info!>");
|
---|
301 | #else
|
---|
302 | ret = PyUnicode_FromString("<cant get IID info!>");
|
---|
303 | #endif
|
---|
304 | return ret;
|
---|
305 | }
|
---|
306 | return PyErr_Format(PyExc_AttributeError, "IID objects have no attribute '%s'", name);
|
---|
307 | }
|
---|
308 |
|
---|
309 | #if PY_MAJOR_VERSION <= 2
|
---|
310 | /* static */ int
|
---|
311 | Py_nsIID::PyTypeMethod_compare(PyObject *self, PyObject *other)
|
---|
312 | {
|
---|
313 | Py_nsIID *s_iid = (Py_nsIID *)self;
|
---|
314 | Py_nsIID *o_iid = (Py_nsIID *)other;
|
---|
315 | int rc = memcmp(&s_iid->m_iid, &o_iid->m_iid, sizeof(s_iid->m_iid));
|
---|
316 | return rc == 0 ? 0 : (rc < 0 ? -1 : 1);
|
---|
317 | }
|
---|
318 | #endif
|
---|
319 |
|
---|
320 | /* static */ PyObject *
|
---|
321 | Py_nsIID::PyTypeMethod_richcompare(PyObject *self, PyObject *other, int op)
|
---|
322 | {
|
---|
323 | nsIID iid;
|
---|
324 | if (!Py_nsIID::IIDFromPyObject(other, &iid))
|
---|
325 | {
|
---|
326 | /* Can't do comparison besides equality/inequality if the other object does not contain an IID. */
|
---|
327 | if (op == Py_EQ)
|
---|
328 | Py_RETURN_FALSE;
|
---|
329 | else if (op == Py_NE)
|
---|
330 | Py_RETURN_TRUE;
|
---|
331 |
|
---|
332 | PyErr_SetString(PyExc_TypeError, "Comparison between different object types is not defined");
|
---|
333 | return NULL;
|
---|
334 | }
|
---|
335 |
|
---|
336 | PyObject *result = NULL;
|
---|
337 | Py_nsIID *s_iid = (Py_nsIID *)self;
|
---|
338 | int rc = memcmp(&s_iid->m_iid, &iid, sizeof(s_iid->m_iid));
|
---|
339 | switch (op)
|
---|
340 | {
|
---|
341 | case Py_LT:
|
---|
342 | result = rc < 0 ? Py_True : Py_False;
|
---|
343 | break;
|
---|
344 | case Py_LE:
|
---|
345 | result = rc <= 0 ? Py_True : Py_False;
|
---|
346 | break;
|
---|
347 | case Py_EQ:
|
---|
348 | result = rc == 0 ? Py_True : Py_False;
|
---|
349 | break;
|
---|
350 | case Py_NE:
|
---|
351 | result = rc != 0 ? Py_True : Py_False;
|
---|
352 | break;
|
---|
353 | case Py_GT:
|
---|
354 | result = rc > 0 ? Py_True : Py_False;
|
---|
355 | break;
|
---|
356 | case Py_GE:
|
---|
357 | result = rc >= 0 ? Py_True : Py_False;
|
---|
358 | break;
|
---|
359 | }
|
---|
360 | Py_XINCREF(result);
|
---|
361 | return result;
|
---|
362 | }
|
---|
363 |
|
---|
364 | /* static */ PyObject *
|
---|
365 | Py_nsIID::PyTypeMethod_repr(PyObject *self)
|
---|
366 | {
|
---|
367 | Py_nsIID *s_iid = (Py_nsIID *)self;
|
---|
368 | char buf[256];
|
---|
369 | char *sziid = s_iid->m_iid.ToString();
|
---|
370 | #ifdef VBOX
|
---|
371 | snprintf(buf, sizeof(buf), "_xpcom.ID('%s')", sziid);
|
---|
372 | #else
|
---|
373 | sprintf(buf, "_xpcom.IID('%s')", sziid);
|
---|
374 | #endif
|
---|
375 | nsMemory::Free(sziid);
|
---|
376 | #if PY_MAJOR_VERSION <= 2
|
---|
377 | return PyString_FromString(buf);
|
---|
378 | #else
|
---|
379 | return PyUnicode_FromString(buf);
|
---|
380 | #endif
|
---|
381 | }
|
---|
382 |
|
---|
383 | /* static */ PyObject *
|
---|
384 | Py_nsIID::PyTypeMethod_str(PyObject *self)
|
---|
385 | {
|
---|
386 | Py_nsIID *s_iid = (Py_nsIID *)self;
|
---|
387 | char *sziid = s_iid->m_iid.ToString();
|
---|
388 | #if PY_MAJOR_VERSION <= 2
|
---|
389 | PyObject *ret = PyString_FromString(sziid);
|
---|
390 | #else
|
---|
391 | PyObject *ret = PyUnicode_FromString(sziid);
|
---|
392 | #endif
|
---|
393 | nsMemory::Free(sziid);
|
---|
394 | return ret;
|
---|
395 | }
|
---|
396 |
|
---|
397 | #if PY_VERSION_HEX >= 0x03020000
|
---|
398 | /* static */Py_hash_t
|
---|
399 | Py_nsIID::PyTypeMethod_hash(PyObject *self)
|
---|
400 | #else
|
---|
401 | /* static */long
|
---|
402 | Py_nsIID::PyTypeMethod_hash(PyObject *self)
|
---|
403 | #endif
|
---|
404 | {
|
---|
405 | const nsIID &iid = ((Py_nsIID *)self)->m_iid;
|
---|
406 |
|
---|
407 | #if PY_VERSION_HEX >= 0x03020000
|
---|
408 | Py_hash_t ret = iid.m0 + iid.m1 + iid.m2;
|
---|
409 | #else
|
---|
410 | long ret = iid.m0 + iid.m1 + iid.m2;
|
---|
411 | #endif
|
---|
412 | for (int i=0;i<7;i++)
|
---|
413 | ret += iid.m3[i];
|
---|
414 | if ( ret == -1 )
|
---|
415 | return -2;
|
---|
416 | return ret;
|
---|
417 | }
|
---|
418 |
|
---|
419 | /*static*/ void
|
---|
420 | Py_nsIID::PyTypeMethod_dealloc(PyObject *ob)
|
---|
421 | {
|
---|
422 | delete (Py_nsIID *)ob;
|
---|
423 | }
|
---|
424 |
|
---|
425 | #ifdef Py_LIMITED_API
|
---|
426 | /* static */ int
|
---|
427 | Py_nsIID::PyTypeMethod_is_gc(PyObject *self)
|
---|
428 | {
|
---|
429 | return 0;
|
---|
430 | }
|
---|
431 | #endif
|
---|