comparison src/utils.cpp @ 117:ac8ca0ee7760

Moved all .cpp/.h files into 'src' dir and test suite into 'tests' dir.
author Atul Varma <varmaa@toolness.com>
date Mon, 17 Aug 2009 22:08:33 -0700
parents utils.cpp@3570ab12747b
children 856ca7a139e4
comparison
equal deleted inserted replaced
116:06269ca0b36c 117:ac8ca0ee7760
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 Pymonkey.
15 *
16 * The Initial Developer of the Original Code is Mozilla.
17 * Portions created by the Initial Developer are Copyright (C) 2007
18 * the Initial Developer. All Rights Reserved.
19 *
20 * Contributor(s):
21 * Atul Varma <atul@mozilla.com>
22 *
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
34 *
35 * ***** END LICENSE BLOCK ***** */
36
37 #include "utils.h"
38 #include "undefined.h"
39 #include "object.h"
40
41 PyObject *PYM_error;
42
43 static int
44 PYM_doubleToJsval(PYM_JSContextObject *context,
45 double number,
46 jsval *rval)
47 {
48 jsdouble *numberAsJsdouble = JS_NewDouble(context->cx, number);
49 if (numberAsJsdouble == NULL) {
50 PyErr_SetString(PYM_error, "JS_NewDouble() failed");
51 return -1;
52 }
53 *rval = DOUBLE_TO_JSVAL(numberAsJsdouble);
54 return 0;
55 }
56
57 int
58 PYM_pyObjectToJsval(PYM_JSContextObject *context,
59 PyObject *object,
60 jsval *rval)
61 {
62 if (PyString_Check(object) || PyUnicode_Check(object)) {
63 PyObject *unicode;
64 if (PyString_Check(object)) {
65 unicode = PyUnicode_FromObject(object);
66 if (unicode == NULL)
67 return -1;
68 } else {
69 unicode = object;
70 Py_INCREF(unicode);
71 }
72
73 PyObject *string = PyUnicode_AsUTF16String(unicode);
74 Py_DECREF(unicode);
75 if (string == NULL)
76 return -1;
77
78 char *buffer = PyString_AS_STRING(string);
79 Py_ssize_t size = PyString_GET_SIZE(string);
80
81 // Note that we're manipulating buffer and size here to get rid of
82 // the BOM.
83 JSString *jsString = JS_NewUCStringCopyN(context->cx,
84 (const jschar *) (buffer + 2),
85 (size / 2) - 1);
86 Py_DECREF(string);
87 if (jsString == NULL) {
88 PyErr_SetString(PYM_error, "JS_NewUCStringCopyN() failed");
89 return -1;
90 }
91
92 *rval = STRING_TO_JSVAL(jsString);
93 return 0;
94 }
95
96 if (PyInt_Check(object)) {
97 long number = PyInt_AS_LONG(object);
98 if (INT_FITS_IN_JSVAL(number)) {
99 *rval = INT_TO_JSVAL(number);
100 return 0;
101 } else
102 return PYM_doubleToJsval(context, number, rval);
103 }
104
105 if (PyFloat_Check(object))
106 return PYM_doubleToJsval(context, PyFloat_AS_DOUBLE(object), rval);
107
108 if (PyObject_TypeCheck(object, &PYM_JSObjectType)) {
109 PYM_JSObject *jsObject = (PYM_JSObject *) object;
110 JSRuntime *rt = JS_GetRuntime(context->cx);
111 if (rt != jsObject->runtime->rt) {
112 PyErr_SetString(PyExc_ValueError,
113 "JS object and JS context are from different "
114 "JS runtimes");
115 return -1;
116 }
117 *rval = OBJECT_TO_JSVAL(jsObject->obj);
118 return 0;
119 }
120
121 if (object == Py_True) {
122 *rval = JSVAL_TRUE;
123 return 0;
124 }
125
126 if (object == Py_False) {
127 *rval = JSVAL_FALSE;
128 return 0;
129 }
130
131 if (object == Py_None) {
132 *rval = JSVAL_NULL;
133 return 0;
134 }
135
136 // TODO: Support more types.
137 PyErr_SetString(PyExc_NotImplementedError,
138 "Data type conversion not implemented.");
139 return -1;
140 }
141
142 PyObject *
143 PYM_jsvalToPyObject(PYM_JSContextObject *context,
144 jsval value) {
145 if (JSVAL_IS_INT(value))
146 return PyInt_FromLong(JSVAL_TO_INT(value));
147
148 if (JSVAL_IS_DOUBLE(value)) {
149 jsdouble *doubleRef = JSVAL_TO_DOUBLE(value);
150 return PyFloat_FromDouble(*doubleRef);
151 }
152
153 if (value == JSVAL_FALSE)
154 Py_RETURN_FALSE;
155
156 if (value == JSVAL_TRUE)
157 Py_RETURN_TRUE;
158
159 if (JSVAL_IS_NULL(value))
160 Py_RETURN_NONE;
161
162 if (JSVAL_IS_VOID(value))
163 Py_RETURN_UNDEFINED;
164
165 if (JSVAL_IS_STRING(value)) {
166 // Strings in JS are funky: think of them as 16-bit versions of
167 // Python 2.x's 'str' type. Whether or not they're valid UTF-16
168 // is entirely up to the client code.
169
170 // TODO: Instead of ignoring errors, consider actually treating
171 // the string as a raw character buffer.
172 JSString *str = JSVAL_TO_STRING(value);
173 const char *chars = (const char *) JS_GetStringChars(str);
174 size_t length = JS_GetStringLength(str);
175
176 // We're multiplying length by two since Python wants the number
177 // of bytes, not the number of 16-bit characters.
178 return PyUnicode_DecodeUTF16(chars, length * 2, "ignore", NULL);
179 }
180
181 if (JSVAL_IS_OBJECT(value))
182 return (PyObject *) PYM_newJSObject(context, JSVAL_TO_OBJECT(value),
183 NULL);
184
185 // TODO: Support more types.
186 PyErr_SetString(PyExc_NotImplementedError,
187 "Data type conversion not implemented.");
188 return NULL;
189 }
190
191 void
192 PYM_pythonExceptionToJs(PYM_JSContextObject *context)
193 {
194 PyObject *type;
195 PyObject *value;
196 PyObject *traceback;
197
198 PyErr_Fetch(&type, &value, &traceback);
199
200 if (type == PYM_error && value &&
201 PyObject_HasAttrString(value, "message")) {
202 jsval val;
203 PyObject *message = PyObject_GetAttrString(value, "message");
204 if (message && PYM_pyObjectToJsval(context, message, &val) == 0) {
205 JS_SetPendingException(context->cx, val);
206 } else
207 JS_ReportError(context->cx,
208 "Python exception occurred, but exception "
209 "couldn't be converted");
210 Py_XDECREF(message);
211 } else {
212 if (value) {
213 JSObject *exception = PYM_JS_newObject(context->cx, value);
214 if (exception)
215 JS_SetPendingException(context->cx, OBJECT_TO_JSVAL(exception));
216 else
217 JS_ReportOutOfMemory(context->cx);
218 } else
219 JS_ReportError(context->cx, "Python exception occurred");
220 }
221
222 Py_XDECREF(type);
223 Py_XDECREF(value);
224 Py_XDECREF(traceback);
225 }
226
227 void
228 PYM_jsExceptionToPython(PYM_JSContextObject *context)
229 {
230 if (!JS_IsExceptionPending(context->cx) &&
231 PyErr_Occurred())
232 return;
233
234 jsval val;
235 if (JS_GetPendingException(context->cx, &val)) {
236 PyObject *obj = PYM_jsvalToPyObject(context, val);
237 if (obj) {
238 PyErr_SetObject(PYM_error, obj);
239 Py_DECREF(obj);
240 } else {
241 PyErr_Clear();
242
243 JSString *str = NULL;
244
245 Py_BEGIN_ALLOW_THREADS;
246 str = JS_ValueToString(context->cx, val);
247 Py_END_ALLOW_THREADS;
248
249 if (str != NULL) {
250 const char *chars = JS_GetStringBytes(str);
251 PyErr_SetString(PYM_error, chars);
252 } else
253 PyErr_SetString(PYM_error, "JS exception occurred");
254 }
255 } else
256 PyErr_SetString(PYM_error, "JS_GetPendingException() failed");
257 }