json: Move from lib to include/openvswitch.
[cascardo/ovs.git] / python / ovs / _json.c
1 #include "Python.h"
2 #include <openvswitch/json.h>
3 #include "structmember.h"
4
5 #if PY_MAJOR_VERSION >= 3
6 #define IS_PY3K
7 #endif
8
9 typedef struct {
10     PyObject_HEAD
11     struct json_parser *_parser;
12 } json_ParserObject;
13
14 static void
15 Parser_dealloc(json_ParserObject * p)
16 {
17     json_parser_abort(p->_parser);
18     Py_TYPE(p)->tp_free(p);
19 }
20
21 static PyObject *
22 Parser_new(PyTypeObject * type, PyObject * args, PyObject * kwargs)
23 {
24     json_ParserObject *self;
25     static char *kwlist[] = { "check_trailer", NULL };
26     PyObject *check_trailer = NULL;
27     int ct_int = 0;
28
29     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist,
30                                      &check_trailer)) {
31         return NULL;
32     }
33
34     if (check_trailer != NULL) {
35         ct_int = PyObject_IsTrue(check_trailer);
36         if (ct_int < 0) {
37             return NULL;
38         } else if (ct_int) {
39             ct_int = JSPF_TRAILER;
40         }
41     }
42
43     self = (json_ParserObject *) type->tp_alloc(type, 0);
44     if (self != NULL) {
45         self->_parser = json_parser_create(ct_int);
46     }
47
48     return (PyObject *) self;
49 }
50
51 static PyObject *
52 Parser_feed(json_ParserObject * self, PyObject * args)
53 {
54     Py_ssize_t input_sz;
55     PyObject *input;
56     size_t rd;
57     char *input_str;
58
59     if (self->_parser == NULL) {
60         return NULL;
61     }
62
63     if (!PyArg_UnpackTuple(args, "input", 1, 1, &input)) {
64         return NULL;
65     }
66 #ifdef IS_PY3K
67     if ((input_str = PyUnicode_AsUTF8AndSize(input, &input_sz)) == NULL) {
68 #else
69     if (PyString_AsStringAndSize(input, &input_str, &input_sz) < 0) {
70 #endif
71         return NULL;
72     }
73
74     rd = json_parser_feed(self->_parser, input_str, (size_t) input_sz);
75
76 #ifdef IS_PY3K
77     return PyLong_FromSize_t(rd);
78 #else
79     return PyInt_FromSize_t(rd);
80 #endif
81 }
82
83 static PyObject *
84 Parser_is_done(json_ParserObject * self)
85 {
86     if (self->_parser == NULL) {
87         return NULL;
88     }
89     return PyBool_FromLong(json_parser_is_done(self->_parser));
90 }
91
92 static PyObject *
93 json_to_python(struct json *json)
94 {
95     switch (json->type) {
96     case JSON_NULL:
97         Py_RETURN_NONE;
98     case JSON_FALSE:
99         Py_RETURN_FALSE;
100     case JSON_TRUE:
101         Py_RETURN_TRUE;
102     case JSON_OBJECT:{
103             struct shash_node *node;
104             PyObject *dict = PyDict_New();
105
106             if (dict == NULL) {
107                 return PyErr_NoMemory();
108             }
109             SHASH_FOR_EACH(node, json->u.object) {
110                 PyObject *key = PyUnicode_FromString(node->name);
111                 PyObject *val = json_to_python(node->data);
112
113                 if (!(key && val) || PyDict_SetItem(dict, key, val)) {
114                     Py_XDECREF(key);
115                     Py_XDECREF(val);
116                     Py_XDECREF(dict);
117                     return NULL;
118                 }
119
120                 Py_XDECREF(key);
121                 Py_XDECREF(val);
122             }
123             return dict;
124         }
125     case JSON_ARRAY:{
126             int i;
127             PyObject *arr = PyList_New(json->u.array.n);
128
129             if (arr == NULL) {
130                 return PyErr_NoMemory();
131             }
132             for (i = 0; i < json->u.array.n; i++) {
133                 PyObject *item = json_to_python(json->u.array.elems[i]);
134
135                 if (!item || PyList_SetItem(arr, i, item)) {
136                     Py_XDECREF(arr);
137                     return NULL;
138                 }
139             }
140             return arr;
141         }
142     case JSON_REAL:
143         if (json->u.real != 0) {
144             return PyFloat_FromDouble(json->u.real);
145         } /* fall through to treat 0 as int */
146     case JSON_INTEGER:
147 #ifdef IS_PY3K
148         return PyLong_FromLong((long) json->u.integer);
149 #else
150         return PyInt_FromLong((long) json->u.integer);
151 #endif
152
153     case JSON_STRING:
154         return PyUnicode_FromString(json->u.string);
155     default:
156         return NULL;
157     }
158 }
159
160 static PyObject *
161 Parser_finish(json_ParserObject * self)
162 {
163     struct json *json;
164     PyObject *obj;
165
166     if (self->_parser == NULL) {
167         return NULL;
168     }
169
170     json = json_parser_finish(self->_parser);
171     self->_parser = NULL;
172     obj = json_to_python(json);
173     return obj;
174 }
175
176 static PyMethodDef Parser_methods[] = {
177     {"feed", (PyCFunction) Parser_feed, METH_VARARGS,
178      "Feed data to the parser and return the index of the last object."},
179     {"is_done", (PyCFunction) Parser_is_done, METH_NOARGS,
180      "Whether the parser has finished decoding an object."},
181     {"finish", (PyCFunction) Parser_finish, METH_NOARGS,
182      "Finish parsing and return Python object parsed."},
183     {NULL},
184 };
185
186 static PyTypeObject json_ParserType = {
187     PyVarObject_HEAD_INIT(NULL, 0)
188         "ovs._json.Parser",     /* tp_name */
189     sizeof (json_ParserObject), /* tp_basicsize */
190     0,                          /* tp_itemsize */
191     (destructor) Parser_dealloc,        /* tp_dealloc */
192     0,                          /* tp_print */
193     0,                          /* tp_getattr */
194     0,                          /* tp_setattr */
195     0,                          /* tp_compare */
196     0,                          /* tp_repr */
197     0,                          /* tp_as_number */
198     0,                          /* tp_as_sequence */
199     0,                          /* tp_as_mapping */
200     0,                          /* tp_hash */
201     0,                          /* tp_call */
202     0,                          /* tp_str */
203     0,                          /* tp_getattro */
204     0,                          /* tp_setattro */
205     0,                          /* tp_as_buffer */
206     Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,   /* tp_flags */
207     "Parser objects",           /* tp_doc */
208     0,                          /* tp_traverse */
209     0,                          /* tp_clear */
210     0,                          /* tp_richcompare */
211     0,                          /* tp_weaklistoffset */
212     0,                          /* tp_iter */
213     0,                          /* tp_iternext */
214     Parser_methods,             /* tp_methods */
215     0,                          /* tp_members */
216     0,                          /* tp_getset */
217     0,                          /* tp_base */
218     0,                          /* tp_dict */
219     0,                          /* tp_descr_get */
220     0,                          /* tp_descr_set */
221     0,                          /* tp_dictoffset */
222     0,                          /* tp_init */
223     0,                          /* tp_alloc */
224     Parser_new,                 /* tp_new */
225 };
226
227 #ifdef IS_PY3K
228 static struct PyModuleDef moduledef = {
229     PyModuleDef_HEAD_INIT,
230     "ovs._json",                /* m_name */
231     "OVS JSON Parser module",   /* m_doc */
232     0,                          /* m_size */
233     0,                          /* m_methods */
234     0,                          /* m_slots */
235     0,                          /* m_traverse */
236     0,                          /* m_clear */
237     0,                          /* m_free */
238 };
239
240 #define INITERROR return NULL
241 #else /* !IS_PY3K */
242 #define INITERROR return
243 #endif
244
245 PyMODINIT_FUNC
246 #ifdef IS_PY3K
247 PyInit__json(void)
248 #else
249 init_json(void)
250 #endif
251 {
252     PyObject *m;
253
254     if (PyType_Ready(&json_ParserType) < 0) {
255         INITERROR;
256     }
257 #ifdef IS_PY3K
258     m = PyModule_Create(&moduledef);
259 #else
260     m = Py_InitModule3("ovs._json", NULL, "OVS JSON Parser module");
261 #endif
262
263     Py_INCREF(&json_ParserType);
264     PyModule_AddObject(m, "Parser", (PyObject *) & json_ParserType);
265 #ifdef IS_PY3K
266     return m;
267 #endif
268 }