+++ /dev/null
-#include "Python.h"\r
-#include "structmember.h"\r
-#if PY_VERSION_HEX < 0x02060000 && !defined(Py_TYPE)\r
-#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)\r
-#endif\r
-#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)\r
-typedef int Py_ssize_t;\r
-#define PY_SSIZE_T_MAX INT_MAX\r
-#define PY_SSIZE_T_MIN INT_MIN\r
-#define PyInt_FromSsize_t PyInt_FromLong\r
-#define PyInt_AsSsize_t PyInt_AsLong\r
-#endif\r
-#ifndef Py_IS_FINITE\r
-#define Py_IS_FINITE(X) (!Py_IS_INFINITY(X) && !Py_IS_NAN(X))\r
-#endif\r
-\r
-#ifdef __GNUC__\r
-#define UNUSED __attribute__((__unused__))\r
-#else\r
-#define UNUSED\r
-#endif\r
-\r
-#define DEFAULT_ENCODING "utf-8"\r
-\r
-#define PyScanner_Check(op) PyObject_TypeCheck(op, &PyScannerType)\r
-#define PyScanner_CheckExact(op) (Py_TYPE(op) == &PyScannerType)\r
-#define PyEncoder_Check(op) PyObject_TypeCheck(op, &PyEncoderType)\r
-#define PyEncoder_CheckExact(op) (Py_TYPE(op) == &PyEncoderType)\r
-\r
-static PyTypeObject PyScannerType;\r
-static PyTypeObject PyEncoderType;\r
-\r
-typedef struct _PyScannerObject {\r
- PyObject_HEAD\r
- PyObject *encoding;\r
- PyObject *strict;\r
- PyObject *object_hook;\r
- PyObject *pairs_hook;\r
- PyObject *parse_float;\r
- PyObject *parse_int;\r
- PyObject *parse_constant;\r
-} PyScannerObject;\r
-\r
-static PyMemberDef scanner_members[] = {\r
- {"encoding", T_OBJECT, offsetof(PyScannerObject, encoding), READONLY, "encoding"},\r
- {"strict", T_OBJECT, offsetof(PyScannerObject, strict), READONLY, "strict"},\r
- {"object_hook", T_OBJECT, offsetof(PyScannerObject, object_hook), READONLY, "object_hook"},\r
- {"object_pairs_hook", T_OBJECT, offsetof(PyScannerObject, pairs_hook), READONLY, "object_pairs_hook"},\r
- {"parse_float", T_OBJECT, offsetof(PyScannerObject, parse_float), READONLY, "parse_float"},\r
- {"parse_int", T_OBJECT, offsetof(PyScannerObject, parse_int), READONLY, "parse_int"},\r
- {"parse_constant", T_OBJECT, offsetof(PyScannerObject, parse_constant), READONLY, "parse_constant"},\r
- {NULL}\r
-};\r
-\r
-typedef struct _PyEncoderObject {\r
- PyObject_HEAD\r
- PyObject *markers;\r
- PyObject *defaultfn;\r
- PyObject *encoder;\r
- PyObject *indent;\r
- PyObject *key_separator;\r
- PyObject *item_separator;\r
- PyObject *sort_keys;\r
- PyObject *skipkeys;\r
- int fast_encode;\r
- int allow_nan;\r
-} PyEncoderObject;\r
-\r
-static PyMemberDef encoder_members[] = {\r
- {"markers", T_OBJECT, offsetof(PyEncoderObject, markers), READONLY, "markers"},\r
- {"default", T_OBJECT, offsetof(PyEncoderObject, defaultfn), READONLY, "default"},\r
- {"encoder", T_OBJECT, offsetof(PyEncoderObject, encoder), READONLY, "encoder"},\r
- {"indent", T_OBJECT, offsetof(PyEncoderObject, indent), READONLY, "indent"},\r
- {"key_separator", T_OBJECT, offsetof(PyEncoderObject, key_separator), READONLY, "key_separator"},\r
- {"item_separator", T_OBJECT, offsetof(PyEncoderObject, item_separator), READONLY, "item_separator"},\r
- {"sort_keys", T_OBJECT, offsetof(PyEncoderObject, sort_keys), READONLY, "sort_keys"},\r
- {"skipkeys", T_OBJECT, offsetof(PyEncoderObject, skipkeys), READONLY, "skipkeys"},\r
- {NULL}\r
-};\r
-\r
-static Py_ssize_t\r
-ascii_escape_char(Py_UNICODE c, char *output, Py_ssize_t chars);\r
-static PyObject *\r
-ascii_escape_unicode(PyObject *pystr);\r
-static PyObject *\r
-ascii_escape_str(PyObject *pystr);\r
-static PyObject *\r
-py_encode_basestring_ascii(PyObject* self UNUSED, PyObject *pystr);\r
-void init_json(void);\r
-static PyObject *\r
-scan_once_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr);\r
-static PyObject *\r
-scan_once_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr);\r
-static PyObject *\r
-_build_rval_index_tuple(PyObject *rval, Py_ssize_t idx);\r
-static PyObject *\r
-scanner_new(PyTypeObject *type, PyObject *args, PyObject *kwds);\r
-static int\r
-scanner_init(PyObject *self, PyObject *args, PyObject *kwds);\r
-static void\r
-scanner_dealloc(PyObject *self);\r
-static int\r
-scanner_clear(PyObject *self);\r
-static PyObject *\r
-encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds);\r
-static int\r
-encoder_init(PyObject *self, PyObject *args, PyObject *kwds);\r
-static void\r
-encoder_dealloc(PyObject *self);\r
-static int\r
-encoder_clear(PyObject *self);\r
-static int\r
-encoder_listencode_list(PyEncoderObject *s, PyObject *rval, PyObject *seq, Py_ssize_t indent_level);\r
-static int\r
-encoder_listencode_obj(PyEncoderObject *s, PyObject *rval, PyObject *obj, Py_ssize_t indent_level);\r
-static int\r
-encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ssize_t indent_level);\r
-static PyObject *\r
-_encoded_const(PyObject *obj);\r
-static void\r
-raise_errmsg(char *msg, PyObject *s, Py_ssize_t end);\r
-static PyObject *\r
-encoder_encode_string(PyEncoderObject *s, PyObject *obj);\r
-static int\r
-_convertPyInt_AsSsize_t(PyObject *o, Py_ssize_t *size_ptr);\r
-static PyObject *\r
-_convertPyInt_FromSsize_t(Py_ssize_t *size_ptr);\r
-static PyObject *\r
-encoder_encode_float(PyEncoderObject *s, PyObject *obj);\r
-\r
-#define S_CHAR(c) (c >= ' ' && c <= '~' && c != '\\' && c != '"')\r
-#define IS_WHITESPACE(c) (((c) == ' ') || ((c) == '\t') || ((c) == '\n') || ((c) == '\r'))\r
-\r
-#define MIN_EXPANSION 6\r
-#ifdef Py_UNICODE_WIDE\r
-#define MAX_EXPANSION (2 * MIN_EXPANSION)\r
-#else\r
-#define MAX_EXPANSION MIN_EXPANSION\r
-#endif\r
-\r
-static int\r
-_convertPyInt_AsSsize_t(PyObject *o, Py_ssize_t *size_ptr)\r
-{\r
- /* PyObject to Py_ssize_t converter */\r
- *size_ptr = PyInt_AsSsize_t(o);\r
- if (*size_ptr == -1 && PyErr_Occurred())\r
- return 0;\r
- return 1;\r
-}\r
-\r
-static PyObject *\r
-_convertPyInt_FromSsize_t(Py_ssize_t *size_ptr)\r
-{\r
- /* Py_ssize_t to PyObject converter */\r
- return PyInt_FromSsize_t(*size_ptr);\r
-}\r
-\r
-static Py_ssize_t\r
-ascii_escape_char(Py_UNICODE c, char *output, Py_ssize_t chars)\r
-{\r
- /* Escape unicode code point c to ASCII escape sequences\r
- in char *output. output must have at least 12 bytes unused to\r
- accommodate an escaped surrogate pair "\uXXXX\uXXXX" */\r
- output[chars++] = '\\';\r
- switch (c) {\r
- case '\\': output[chars++] = (char)c; break;\r
- case '"': output[chars++] = (char)c; break;\r
- case '\b': output[chars++] = 'b'; break;\r
- case '\f': output[chars++] = 'f'; break;\r
- case '\n': output[chars++] = 'n'; break;\r
- case '\r': output[chars++] = 'r'; break;\r
- case '\t': output[chars++] = 't'; break;\r
- default:\r
-#ifdef Py_UNICODE_WIDE\r
- if (c >= 0x10000) {\r
- /* UTF-16 surrogate pair */\r
- Py_UNICODE v = c - 0x10000;\r
- c = 0xd800 | ((v >> 10) & 0x3ff);\r
- output[chars++] = 'u';\r
- output[chars++] = "0123456789abcdef"[(c >> 12) & 0xf];\r
- output[chars++] = "0123456789abcdef"[(c >> 8) & 0xf];\r
- output[chars++] = "0123456789abcdef"[(c >> 4) & 0xf];\r
- output[chars++] = "0123456789abcdef"[(c ) & 0xf];\r
- c = 0xdc00 | (v & 0x3ff);\r
- output[chars++] = '\\';\r
- }\r
-#endif\r
- output[chars++] = 'u';\r
- output[chars++] = "0123456789abcdef"[(c >> 12) & 0xf];\r
- output[chars++] = "0123456789abcdef"[(c >> 8) & 0xf];\r
- output[chars++] = "0123456789abcdef"[(c >> 4) & 0xf];\r
- output[chars++] = "0123456789abcdef"[(c ) & 0xf];\r
- }\r
- return chars;\r
-}\r
-\r
-static PyObject *\r
-ascii_escape_unicode(PyObject *pystr)\r
-{\r
- /* Take a PyUnicode pystr and return a new ASCII-only escaped PyString */\r
- Py_ssize_t i;\r
- Py_ssize_t input_chars;\r
- Py_ssize_t output_size;\r
- Py_ssize_t max_output_size;\r
- Py_ssize_t chars;\r
- PyObject *rval;\r
- char *output;\r
- Py_UNICODE *input_unicode;\r
-\r
- input_chars = PyUnicode_GET_SIZE(pystr);\r
- input_unicode = PyUnicode_AS_UNICODE(pystr);\r
-\r
- /* One char input can be up to 6 chars output, estimate 4 of these */\r
- output_size = 2 + (MIN_EXPANSION * 4) + input_chars;\r
- max_output_size = 2 + (input_chars * MAX_EXPANSION);\r
- rval = PyString_FromStringAndSize(NULL, output_size);\r
- if (rval == NULL) {\r
- return NULL;\r
- }\r
- output = PyString_AS_STRING(rval);\r
- chars = 0;\r
- output[chars++] = '"';\r
- for (i = 0; i < input_chars; i++) {\r
- Py_UNICODE c = input_unicode[i];\r
- if (S_CHAR(c)) {\r
- output[chars++] = (char)c;\r
- }\r
- else {\r
- chars = ascii_escape_char(c, output, chars);\r
- }\r
- if (output_size - chars < (1 + MAX_EXPANSION)) {\r
- /* There's more than four, so let's resize by a lot */\r
- Py_ssize_t new_output_size = output_size * 2;\r
- /* This is an upper bound */\r
- if (new_output_size > max_output_size) {\r
- new_output_size = max_output_size;\r
- }\r
- /* Make sure that the output size changed before resizing */\r
- if (new_output_size != output_size) {\r
- output_size = new_output_size;\r
- if (_PyString_Resize(&rval, output_size) == -1) {\r
- return NULL;\r
- }\r
- output = PyString_AS_STRING(rval);\r
- }\r
- }\r
- }\r
- output[chars++] = '"';\r
- if (_PyString_Resize(&rval, chars) == -1) {\r
- return NULL;\r
- }\r
- return rval;\r
-}\r
-\r
-static PyObject *\r
-ascii_escape_str(PyObject *pystr)\r
-{\r
- /* Take a PyString pystr and return a new ASCII-only escaped PyString */\r
- Py_ssize_t i;\r
- Py_ssize_t input_chars;\r
- Py_ssize_t output_size;\r
- Py_ssize_t chars;\r
- PyObject *rval;\r
- char *output;\r
- char *input_str;\r
-\r
- input_chars = PyString_GET_SIZE(pystr);\r
- input_str = PyString_AS_STRING(pystr);\r
-\r
- /* Fast path for a string that's already ASCII */\r
- for (i = 0; i < input_chars; i++) {\r
- Py_UNICODE c = (Py_UNICODE)(unsigned char)input_str[i];\r
- if (!S_CHAR(c)) {\r
- /* If we have to escape something, scan the string for unicode */\r
- Py_ssize_t j;\r
- for (j = i; j < input_chars; j++) {\r
- c = (Py_UNICODE)(unsigned char)input_str[j];\r
- if (c > 0x7f) {\r
- /* We hit a non-ASCII character, bail to unicode mode */\r
- PyObject *uni;\r
- uni = PyUnicode_DecodeUTF8(input_str, input_chars, "strict");\r
- if (uni == NULL) {\r
- return NULL;\r
- }\r
- rval = ascii_escape_unicode(uni);\r
- Py_DECREF(uni);\r
- return rval;\r
- }\r
- }\r
- break;\r
- }\r
- }\r
-\r
- if (i == input_chars) {\r
- /* Input is already ASCII */\r
- output_size = 2 + input_chars;\r
- }\r
- else {\r
- /* One char input can be up to 6 chars output, estimate 4 of these */\r
- output_size = 2 + (MIN_EXPANSION * 4) + input_chars;\r
- }\r
- rval = PyString_FromStringAndSize(NULL, output_size);\r
- if (rval == NULL) {\r
- return NULL;\r
- }\r
- output = PyString_AS_STRING(rval);\r
- output[0] = '"';\r
-\r
- /* We know that everything up to i is ASCII already */\r
- chars = i + 1;\r
- memcpy(&output[1], input_str, i);\r
-\r
- for (; i < input_chars; i++) {\r
- Py_UNICODE c = (Py_UNICODE)(unsigned char)input_str[i];\r
- if (S_CHAR(c)) {\r
- output[chars++] = (char)c;\r
- }\r
- else {\r
- chars = ascii_escape_char(c, output, chars);\r
- }\r
- /* An ASCII char can't possibly expand to a surrogate! */\r
- if (output_size - chars < (1 + MIN_EXPANSION)) {\r
- /* There's more than four, so let's resize by a lot */\r
- output_size *= 2;\r
- if (output_size > 2 + (input_chars * MIN_EXPANSION)) {\r
- output_size = 2 + (input_chars * MIN_EXPANSION);\r
- }\r
- if (_PyString_Resize(&rval, output_size) == -1) {\r
- return NULL;\r
- }\r
- output = PyString_AS_STRING(rval);\r
- }\r
- }\r
- output[chars++] = '"';\r
- if (_PyString_Resize(&rval, chars) == -1) {\r
- return NULL;\r
- }\r
- return rval;\r
-}\r
-\r
-static void\r
-raise_errmsg(char *msg, PyObject *s, Py_ssize_t end)\r
-{\r
- /* Use the Python function json.decoder.errmsg to raise a nice\r
- looking ValueError exception */\r
- static PyObject *errmsg_fn = NULL;\r
- PyObject *pymsg;\r
- if (errmsg_fn == NULL) {\r
- PyObject *decoder = PyImport_ImportModule("json.decoder");\r
- if (decoder == NULL)\r
- return;\r
- errmsg_fn = PyObject_GetAttrString(decoder, "errmsg");\r
- Py_DECREF(decoder);\r
- if (errmsg_fn == NULL)\r
- return;\r
- }\r
- pymsg = PyObject_CallFunction(errmsg_fn, "(zOO&)", msg, s, _convertPyInt_FromSsize_t, &end);\r
- if (pymsg) {\r
- PyErr_SetObject(PyExc_ValueError, pymsg);\r
- Py_DECREF(pymsg);\r
- }\r
-}\r
-\r
-static PyObject *\r
-join_list_unicode(PyObject *lst)\r
-{\r
- /* return u''.join(lst) */\r
- static PyObject *joinfn = NULL;\r
- if (joinfn == NULL) {\r
- PyObject *ustr = PyUnicode_FromUnicode(NULL, 0);\r
- if (ustr == NULL)\r
- return NULL;\r
-\r
- joinfn = PyObject_GetAttrString(ustr, "join");\r
- Py_DECREF(ustr);\r
- if (joinfn == NULL)\r
- return NULL;\r
- }\r
- return PyObject_CallFunctionObjArgs(joinfn, lst, NULL);\r
-}\r
-\r
-static PyObject *\r
-_build_rval_index_tuple(PyObject *rval, Py_ssize_t idx) {\r
- /* return (rval, idx) tuple, stealing reference to rval */\r
- PyObject *tpl;\r
- PyObject *pyidx;\r
- /*\r
- steal a reference to rval, returns (rval, idx)\r
- */\r
- if (rval == NULL) {\r
- return NULL;\r
- }\r
- pyidx = PyInt_FromSsize_t(idx);\r
- if (pyidx == NULL) {\r
- Py_DECREF(rval);\r
- return NULL;\r
- }\r
- tpl = PyTuple_New(2);\r
- if (tpl == NULL) {\r
- Py_DECREF(pyidx);\r
- Py_DECREF(rval);\r
- return NULL;\r
- }\r
- PyTuple_SET_ITEM(tpl, 0, rval);\r
- PyTuple_SET_ITEM(tpl, 1, pyidx);\r
- return tpl;\r
-}\r
-\r
-static PyObject *\r
-scanstring_str(PyObject *pystr, Py_ssize_t end, char *encoding, int strict, Py_ssize_t *next_end_ptr)\r
-{\r
- /* Read the JSON string from PyString pystr.\r
- end is the index of the first character after the quote.\r
- encoding is the encoding of pystr (must be an ASCII superset)\r
- if strict is zero then literal control characters are allowed\r
- *next_end_ptr is a return-by-reference index of the character\r
- after the end quote\r
-\r
- Return value is a new PyString (if ASCII-only) or PyUnicode\r
- */\r
- PyObject *rval;\r
- Py_ssize_t len = PyString_GET_SIZE(pystr);\r
- Py_ssize_t begin = end - 1;\r
- Py_ssize_t next;\r
- char *buf = PyString_AS_STRING(pystr);\r
- PyObject *chunks = PyList_New(0);\r
- if (chunks == NULL) {\r
- goto bail;\r
- }\r
- if (end < 0 || len <= end) {\r
- PyErr_SetString(PyExc_ValueError, "end is out of bounds");\r
- goto bail;\r
- }\r
- while (1) {\r
- /* Find the end of the string or the next escape */\r
- Py_UNICODE c = 0;\r
- PyObject *chunk = NULL;\r
- for (next = end; next < len; next++) {\r
- c = (unsigned char)buf[next];\r
- if (c == '"' || c == '\\') {\r
- break;\r
- }\r
- else if (strict && c <= 0x1f) {\r
- raise_errmsg("Invalid control character at", pystr, next);\r
- goto bail;\r
- }\r
- }\r
- if (!(c == '"' || c == '\\')) {\r
- raise_errmsg("Unterminated string starting at", pystr, begin);\r
- goto bail;\r
- }\r
- /* Pick up this chunk if it's not zero length */\r
- if (next != end) {\r
- PyObject *strchunk = PyString_FromStringAndSize(&buf[end], next - end);\r
- if (strchunk == NULL) {\r
- goto bail;\r
- }\r
- chunk = PyUnicode_FromEncodedObject(strchunk, encoding, NULL);\r
- Py_DECREF(strchunk);\r
- if (chunk == NULL) {\r
- goto bail;\r
- }\r
- if (PyList_Append(chunks, chunk)) {\r
- Py_DECREF(chunk);\r
- goto bail;\r
- }\r
- Py_DECREF(chunk);\r
- }\r
- next++;\r
- if (c == '"') {\r
- end = next;\r
- break;\r
- }\r
- if (next == len) {\r
- raise_errmsg("Unterminated string starting at", pystr, begin);\r
- goto bail;\r
- }\r
- c = buf[next];\r
- if (c != 'u') {\r
- /* Non-unicode backslash escapes */\r
- end = next + 1;\r
- switch (c) {\r
- case '"': break;\r
- case '\\': break;\r
- case '/': break;\r
- case 'b': c = '\b'; break;\r
- case 'f': c = '\f'; break;\r
- case 'n': c = '\n'; break;\r
- case 'r': c = '\r'; break;\r
- case 't': c = '\t'; break;\r
- default: c = 0;\r
- }\r
- if (c == 0) {\r
- raise_errmsg("Invalid \\escape", pystr, end - 2);\r
- goto bail;\r
- }\r
- }\r
- else {\r
- c = 0;\r
- next++;\r
- end = next + 4;\r
- if (end >= len) {\r
- raise_errmsg("Invalid \\uXXXX escape", pystr, next - 1);\r
- goto bail;\r
- }\r
- /* Decode 4 hex digits */\r
- for (; next < end; next++) {\r
- Py_UNICODE digit = buf[next];\r
- c <<= 4;\r
- switch (digit) {\r
- case '0': case '1': case '2': case '3': case '4':\r
- case '5': case '6': case '7': case '8': case '9':\r
- c |= (digit - '0'); break;\r
- case 'a': case 'b': case 'c': case 'd': case 'e':\r
- case 'f':\r
- c |= (digit - 'a' + 10); break;\r
- case 'A': case 'B': case 'C': case 'D': case 'E':\r
- case 'F':\r
- c |= (digit - 'A' + 10); break;\r
- default:\r
- raise_errmsg("Invalid \\uXXXX escape", pystr, end - 5);\r
- goto bail;\r
- }\r
- }\r
-#ifdef Py_UNICODE_WIDE\r
- /* Surrogate pair */\r
- if ((c & 0xfc00) == 0xd800) {\r
- Py_UNICODE c2 = 0;\r
- if (end + 6 >= len) {\r
- raise_errmsg("Unpaired high surrogate", pystr, end - 5);\r
- goto bail;\r
- }\r
- if (buf[next++] != '\\' || buf[next++] != 'u') {\r
- raise_errmsg("Unpaired high surrogate", pystr, end - 5);\r
- goto bail;\r
- }\r
- end += 6;\r
- /* Decode 4 hex digits */\r
- for (; next < end; next++) {\r
- Py_UNICODE digit = buf[next];\r
- c2 <<= 4;\r
- switch (digit) {\r
- case '0': case '1': case '2': case '3': case '4':\r
- case '5': case '6': case '7': case '8': case '9':\r
- c2 |= (digit - '0'); break;\r
- case 'a': case 'b': case 'c': case 'd': case 'e':\r
- case 'f':\r
- c2 |= (digit - 'a' + 10); break;\r
- case 'A': case 'B': case 'C': case 'D': case 'E':\r
- case 'F':\r
- c2 |= (digit - 'A' + 10); break;\r
- default:\r
- raise_errmsg("Invalid \\uXXXX escape", pystr, end - 5);\r
- goto bail;\r
- }\r
- }\r
- if ((c2 & 0xfc00) != 0xdc00) {\r
- raise_errmsg("Unpaired high surrogate", pystr, end - 5);\r
- goto bail;\r
- }\r
- c = 0x10000 + (((c - 0xd800) << 10) | (c2 - 0xdc00));\r
- }\r
- else if ((c & 0xfc00) == 0xdc00) {\r
- raise_errmsg("Unpaired low surrogate", pystr, end - 5);\r
- goto bail;\r
- }\r
-#endif\r
- }\r
- chunk = PyUnicode_FromUnicode(&c, 1);\r
- if (chunk == NULL) {\r
- goto bail;\r
- }\r
- if (PyList_Append(chunks, chunk)) {\r
- Py_DECREF(chunk);\r
- goto bail;\r
- }\r
- Py_DECREF(chunk);\r
- }\r
-\r
- rval = join_list_unicode(chunks);\r
- if (rval == NULL) {\r
- goto bail;\r
- }\r
- Py_CLEAR(chunks);\r
- *next_end_ptr = end;\r
- return rval;\r
-bail:\r
- *next_end_ptr = -1;\r
- Py_XDECREF(chunks);\r
- return NULL;\r
-}\r
-\r
-\r
-static PyObject *\r
-scanstring_unicode(PyObject *pystr, Py_ssize_t end, int strict, Py_ssize_t *next_end_ptr)\r
-{\r
- /* Read the JSON string from PyUnicode pystr.\r
- end is the index of the first character after the quote.\r
- if strict is zero then literal control characters are allowed\r
- *next_end_ptr is a return-by-reference index of the character\r
- after the end quote\r
-\r
- Return value is a new PyUnicode\r
- */\r
- PyObject *rval;\r
- Py_ssize_t len = PyUnicode_GET_SIZE(pystr);\r
- Py_ssize_t begin = end - 1;\r
- Py_ssize_t next;\r
- const Py_UNICODE *buf = PyUnicode_AS_UNICODE(pystr);\r
- PyObject *chunks = PyList_New(0);\r
- if (chunks == NULL) {\r
- goto bail;\r
- }\r
- if (end < 0 || len <= end) {\r
- PyErr_SetString(PyExc_ValueError, "end is out of bounds");\r
- goto bail;\r
- }\r
- while (1) {\r
- /* Find the end of the string or the next escape */\r
- Py_UNICODE c = 0;\r
- PyObject *chunk = NULL;\r
- for (next = end; next < len; next++) {\r
- c = buf[next];\r
- if (c == '"' || c == '\\') {\r
- break;\r
- }\r
- else if (strict && c <= 0x1f) {\r
- raise_errmsg("Invalid control character at", pystr, next);\r
- goto bail;\r
- }\r
- }\r
- if (!(c == '"' || c == '\\')) {\r
- raise_errmsg("Unterminated string starting at", pystr, begin);\r
- goto bail;\r
- }\r
- /* Pick up this chunk if it's not zero length */\r
- if (next != end) {\r
- chunk = PyUnicode_FromUnicode(&buf[end], next - end);\r
- if (chunk == NULL) {\r
- goto bail;\r
- }\r
- if (PyList_Append(chunks, chunk)) {\r
- Py_DECREF(chunk);\r
- goto bail;\r
- }\r
- Py_DECREF(chunk);\r
- }\r
- next++;\r
- if (c == '"') {\r
- end = next;\r
- break;\r
- }\r
- if (next == len) {\r
- raise_errmsg("Unterminated string starting at", pystr, begin);\r
- goto bail;\r
- }\r
- c = buf[next];\r
- if (c != 'u') {\r
- /* Non-unicode backslash escapes */\r
- end = next + 1;\r
- switch (c) {\r
- case '"': break;\r
- case '\\': break;\r
- case '/': break;\r
- case 'b': c = '\b'; break;\r
- case 'f': c = '\f'; break;\r
- case 'n': c = '\n'; break;\r
- case 'r': c = '\r'; break;\r
- case 't': c = '\t'; break;\r
- default: c = 0;\r
- }\r
- if (c == 0) {\r
- raise_errmsg("Invalid \\escape", pystr, end - 2);\r
- goto bail;\r
- }\r
- }\r
- else {\r
- c = 0;\r
- next++;\r
- end = next + 4;\r
- if (end >= len) {\r
- raise_errmsg("Invalid \\uXXXX escape", pystr, next - 1);\r
- goto bail;\r
- }\r
- /* Decode 4 hex digits */\r
- for (; next < end; next++) {\r
- Py_UNICODE digit = buf[next];\r
- c <<= 4;\r
- switch (digit) {\r
- case '0': case '1': case '2': case '3': case '4':\r
- case '5': case '6': case '7': case '8': case '9':\r
- c |= (digit - '0'); break;\r
- case 'a': case 'b': case 'c': case 'd': case 'e':\r
- case 'f':\r
- c |= (digit - 'a' + 10); break;\r
- case 'A': case 'B': case 'C': case 'D': case 'E':\r
- case 'F':\r
- c |= (digit - 'A' + 10); break;\r
- default:\r
- raise_errmsg("Invalid \\uXXXX escape", pystr, end - 5);\r
- goto bail;\r
- }\r
- }\r
-#ifdef Py_UNICODE_WIDE\r
- /* Surrogate pair */\r
- if ((c & 0xfc00) == 0xd800) {\r
- Py_UNICODE c2 = 0;\r
- if (end + 6 >= len) {\r
- raise_errmsg("Unpaired high surrogate", pystr, end - 5);\r
- goto bail;\r
- }\r
- if (buf[next++] != '\\' || buf[next++] != 'u') {\r
- raise_errmsg("Unpaired high surrogate", pystr, end - 5);\r
- goto bail;\r
- }\r
- end += 6;\r
- /* Decode 4 hex digits */\r
- for (; next < end; next++) {\r
- Py_UNICODE digit = buf[next];\r
- c2 <<= 4;\r
- switch (digit) {\r
- case '0': case '1': case '2': case '3': case '4':\r
- case '5': case '6': case '7': case '8': case '9':\r
- c2 |= (digit - '0'); break;\r
- case 'a': case 'b': case 'c': case 'd': case 'e':\r
- case 'f':\r
- c2 |= (digit - 'a' + 10); break;\r
- case 'A': case 'B': case 'C': case 'D': case 'E':\r
- case 'F':\r
- c2 |= (digit - 'A' + 10); break;\r
- default:\r
- raise_errmsg("Invalid \\uXXXX escape", pystr, end - 5);\r
- goto bail;\r
- }\r
- }\r
- if ((c2 & 0xfc00) != 0xdc00) {\r
- raise_errmsg("Unpaired high surrogate", pystr, end - 5);\r
- goto bail;\r
- }\r
- c = 0x10000 + (((c - 0xd800) << 10) | (c2 - 0xdc00));\r
- }\r
- else if ((c & 0xfc00) == 0xdc00) {\r
- raise_errmsg("Unpaired low surrogate", pystr, end - 5);\r
- goto bail;\r
- }\r
-#endif\r
- }\r
- chunk = PyUnicode_FromUnicode(&c, 1);\r
- if (chunk == NULL) {\r
- goto bail;\r
- }\r
- if (PyList_Append(chunks, chunk)) {\r
- Py_DECREF(chunk);\r
- goto bail;\r
- }\r
- Py_DECREF(chunk);\r
- }\r
-\r
- rval = join_list_unicode(chunks);\r
- if (rval == NULL) {\r
- goto bail;\r
- }\r
- Py_DECREF(chunks);\r
- *next_end_ptr = end;\r
- return rval;\r
-bail:\r
- *next_end_ptr = -1;\r
- Py_XDECREF(chunks);\r
- return NULL;\r
-}\r
-\r
-PyDoc_STRVAR(pydoc_scanstring,\r
- "scanstring(basestring, end, encoding, strict=True) -> (str, end)\n"\r
- "\n"\r
- "Scan the string s for a JSON string. End is the index of the\n"\r
- "character in s after the quote that started the JSON string.\n"\r
- "Unescapes all valid JSON string escape sequences and raises ValueError\n"\r
- "on attempt to decode an invalid string. If strict is False then literal\n"\r
- "control characters are allowed in the string.\n"\r
- "\n"\r
- "Returns a tuple of the decoded string and the index of the character in s\n"\r
- "after the end quote."\r
-);\r
-\r
-static PyObject *\r
-py_scanstring(PyObject* self UNUSED, PyObject *args)\r
-{\r
- PyObject *pystr;\r
- PyObject *rval;\r
- Py_ssize_t end;\r
- Py_ssize_t next_end = -1;\r
- char *encoding = NULL;\r
- int strict = 1;\r
- if (!PyArg_ParseTuple(args, "OO&|zi:scanstring", &pystr, _convertPyInt_AsSsize_t, &end, &encoding, &strict)) {\r
- return NULL;\r
- }\r
- if (encoding == NULL) {\r
- encoding = DEFAULT_ENCODING;\r
- }\r
- if (PyString_Check(pystr)) {\r
- rval = scanstring_str(pystr, end, encoding, strict, &next_end);\r
- }\r
- else if (PyUnicode_Check(pystr)) {\r
- rval = scanstring_unicode(pystr, end, strict, &next_end);\r
- }\r
- else {\r
- PyErr_Format(PyExc_TypeError,\r
- "first argument must be a string, not %.80s",\r
- Py_TYPE(pystr)->tp_name);\r
- return NULL;\r
- }\r
- return _build_rval_index_tuple(rval, next_end);\r
-}\r
-\r
-PyDoc_STRVAR(pydoc_encode_basestring_ascii,\r
- "encode_basestring_ascii(basestring) -> str\n"\r
- "\n"\r
- "Return an ASCII-only JSON representation of a Python string"\r
-);\r
-\r
-static PyObject *\r
-py_encode_basestring_ascii(PyObject* self UNUSED, PyObject *pystr)\r
-{\r
- /* Return an ASCII-only JSON representation of a Python string */\r
- /* METH_O */\r
- if (PyString_Check(pystr)) {\r
- return ascii_escape_str(pystr);\r
- }\r
- else if (PyUnicode_Check(pystr)) {\r
- return ascii_escape_unicode(pystr);\r
- }\r
- else {\r
- PyErr_Format(PyExc_TypeError,\r
- "first argument must be a string, not %.80s",\r
- Py_TYPE(pystr)->tp_name);\r
- return NULL;\r
- }\r
-}\r
-\r
-static void\r
-scanner_dealloc(PyObject *self)\r
-{\r
- /* Deallocate scanner object */\r
- scanner_clear(self);\r
- Py_TYPE(self)->tp_free(self);\r
-}\r
-\r
-static int\r
-scanner_traverse(PyObject *self, visitproc visit, void *arg)\r
-{\r
- PyScannerObject *s;\r
- assert(PyScanner_Check(self));\r
- s = (PyScannerObject *)self;\r
- Py_VISIT(s->encoding);\r
- Py_VISIT(s->strict);\r
- Py_VISIT(s->object_hook);\r
- Py_VISIT(s->pairs_hook);\r
- Py_VISIT(s->parse_float);\r
- Py_VISIT(s->parse_int);\r
- Py_VISIT(s->parse_constant);\r
- return 0;\r
-}\r
-\r
-static int\r
-scanner_clear(PyObject *self)\r
-{\r
- PyScannerObject *s;\r
- assert(PyScanner_Check(self));\r
- s = (PyScannerObject *)self;\r
- Py_CLEAR(s->encoding);\r
- Py_CLEAR(s->strict);\r
- Py_CLEAR(s->object_hook);\r
- Py_CLEAR(s->pairs_hook);\r
- Py_CLEAR(s->parse_float);\r
- Py_CLEAR(s->parse_int);\r
- Py_CLEAR(s->parse_constant);\r
- return 0;\r
-}\r
-\r
-static PyObject *\r
-_parse_object_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr) {\r
- /* Read a JSON object from PyString pystr.\r
- idx is the index of the first character after the opening curly brace.\r
- *next_idx_ptr is a return-by-reference index to the first character after\r
- the closing curly brace.\r
-\r
- Returns a new PyObject (usually a dict, but object_hook can change that)\r
- */\r
- char *str = PyString_AS_STRING(pystr);\r
- Py_ssize_t end_idx = PyString_GET_SIZE(pystr) - 1;\r
- PyObject *rval;\r
- PyObject *pairs;\r
- PyObject *item;\r
- PyObject *key = NULL;\r
- PyObject *val = NULL;\r
- char *encoding = PyString_AS_STRING(s->encoding);\r
- int strict = PyObject_IsTrue(s->strict);\r
- Py_ssize_t next_idx;\r
-\r
- pairs = PyList_New(0);\r
- if (pairs == NULL)\r
- return NULL;\r
-\r
- /* skip whitespace after { */\r
- while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++;\r
-\r
- /* only loop if the object is non-empty */\r
- if (idx <= end_idx && str[idx] != '}') {\r
- while (idx <= end_idx) {\r
- /* read key */\r
- if (str[idx] != '"') {\r
- raise_errmsg("Expecting property name", pystr, idx);\r
- goto bail;\r
- }\r
- key = scanstring_str(pystr, idx + 1, encoding, strict, &next_idx);\r
- if (key == NULL)\r
- goto bail;\r
- idx = next_idx;\r
-\r
- /* skip whitespace between key and : delimiter, read :, skip whitespace */\r
- while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++;\r
- if (idx > end_idx || str[idx] != ':') {\r
- raise_errmsg("Expecting : delimiter", pystr, idx);\r
- goto bail;\r
- }\r
- idx++;\r
- while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++;\r
-\r
- /* read any JSON data type */\r
- val = scan_once_str(s, pystr, idx, &next_idx);\r
- if (val == NULL)\r
- goto bail;\r
-\r
- item = PyTuple_Pack(2, key, val);\r
- if (item == NULL)\r
- goto bail;\r
- Py_CLEAR(key);\r
- Py_CLEAR(val);\r
- if (PyList_Append(pairs, item) == -1) {\r
- Py_DECREF(item);\r
- goto bail;\r
- }\r
- Py_DECREF(item);\r
- idx = next_idx;\r
-\r
- /* skip whitespace before } or , */\r
- while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++;\r
-\r
- /* bail if the object is closed or we didn't get the , delimiter */\r
- if (idx > end_idx) break;\r
- if (str[idx] == '}') {\r
- break;\r
- }\r
- else if (str[idx] != ',') {\r
- raise_errmsg("Expecting , delimiter", pystr, idx);\r
- goto bail;\r
- }\r
- idx++;\r
-\r
- /* skip whitespace after , delimiter */\r
- while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++;\r
- }\r
- }\r
- /* verify that idx < end_idx, str[idx] should be '}' */\r
- if (idx > end_idx || str[idx] != '}') {\r
- raise_errmsg("Expecting object", pystr, end_idx);\r
- goto bail;\r
- }\r
-\r
- /* if pairs_hook is not None: rval = object_pairs_hook(pairs) */\r
- if (s->pairs_hook != Py_None) {\r
- val = PyObject_CallFunctionObjArgs(s->pairs_hook, pairs, NULL);\r
- if (val == NULL)\r
- goto bail;\r
- Py_DECREF(pairs);\r
- *next_idx_ptr = idx + 1;\r
- return val;\r
- }\r
-\r
- rval = PyObject_CallFunctionObjArgs((PyObject *)(&PyDict_Type), \r
- pairs, NULL);\r
- if (rval == NULL)\r
- goto bail;\r
- Py_CLEAR(pairs);\r
-\r
- /* if object_hook is not None: rval = object_hook(rval) */\r
- if (s->object_hook != Py_None) {\r
- val = PyObject_CallFunctionObjArgs(s->object_hook, rval, NULL);\r
- if (val == NULL)\r
- goto bail;\r
- Py_DECREF(rval);\r
- rval = val;\r
- val = NULL;\r
- }\r
- *next_idx_ptr = idx + 1;\r
- return rval;\r
-bail:\r
- Py_XDECREF(key);\r
- Py_XDECREF(val);\r
- Py_XDECREF(pairs);\r
- return NULL;\r
-}\r
-\r
-static PyObject *\r
-_parse_object_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr) {\r
- /* Read a JSON object from PyUnicode pystr.\r
- idx is the index of the first character after the opening curly brace.\r
- *next_idx_ptr is a return-by-reference index to the first character after\r
- the closing curly brace.\r
-\r
- Returns a new PyObject (usually a dict, but object_hook can change that)\r
- */\r
- Py_UNICODE *str = PyUnicode_AS_UNICODE(pystr);\r
- Py_ssize_t end_idx = PyUnicode_GET_SIZE(pystr) - 1;\r
- PyObject *rval;\r
- PyObject *pairs;\r
- PyObject *item;\r
- PyObject *key = NULL;\r
- PyObject *val = NULL;\r
- int strict = PyObject_IsTrue(s->strict);\r
- Py_ssize_t next_idx;\r
-\r
- pairs = PyList_New(0);\r
- if (pairs == NULL)\r
- return NULL;\r
-\r
- /* skip whitespace after { */\r
- while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++;\r
-\r
- /* only loop if the object is non-empty */\r
- if (idx <= end_idx && str[idx] != '}') {\r
- while (idx <= end_idx) {\r
- /* read key */\r
- if (str[idx] != '"') {\r
- raise_errmsg("Expecting property name", pystr, idx);\r
- goto bail;\r
- }\r
- key = scanstring_unicode(pystr, idx + 1, strict, &next_idx);\r
- if (key == NULL)\r
- goto bail;\r
- idx = next_idx;\r
-\r
- /* skip whitespace between key and : delimiter, read :, skip whitespace */\r
- while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++;\r
- if (idx > end_idx || str[idx] != ':') {\r
- raise_errmsg("Expecting : delimiter", pystr, idx);\r
- goto bail;\r
- }\r
- idx++;\r
- while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++;\r
-\r
- /* read any JSON term */\r
- val = scan_once_unicode(s, pystr, idx, &next_idx);\r
- if (val == NULL)\r
- goto bail;\r
-\r
- item = PyTuple_Pack(2, key, val);\r
- if (item == NULL)\r
- goto bail;\r
- Py_CLEAR(key);\r
- Py_CLEAR(val);\r
- if (PyList_Append(pairs, item) == -1) {\r
- Py_DECREF(item);\r
- goto bail;\r
- }\r
- Py_DECREF(item);\r
- idx = next_idx;\r
-\r
- /* skip whitespace before } or , */\r
- while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++;\r
-\r
- /* bail if the object is closed or we didn't get the , delimiter */\r
- if (idx > end_idx) break;\r
- if (str[idx] == '}') {\r
- break;\r
- }\r
- else if (str[idx] != ',') {\r
- raise_errmsg("Expecting , delimiter", pystr, idx);\r
- goto bail;\r
- }\r
- idx++;\r
-\r
- /* skip whitespace after , delimiter */\r
- while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++;\r
- }\r
- }\r
-\r
- /* verify that idx < end_idx, str[idx] should be '}' */\r
- if (idx > end_idx || str[idx] != '}') {\r
- raise_errmsg("Expecting object", pystr, end_idx);\r
- goto bail;\r
- }\r
-\r
- /* if pairs_hook is not None: rval = object_pairs_hook(pairs) */\r
- if (s->pairs_hook != Py_None) {\r
- val = PyObject_CallFunctionObjArgs(s->pairs_hook, pairs, NULL);\r
- if (val == NULL)\r
- goto bail;\r
- Py_DECREF(pairs);\r
- *next_idx_ptr = idx + 1;\r
- return val;\r
- }\r
-\r
- rval = PyObject_CallFunctionObjArgs((PyObject *)(&PyDict_Type), \r
- pairs, NULL);\r
- if (rval == NULL)\r
- goto bail;\r
- Py_CLEAR(pairs);\r
-\r
- /* if object_hook is not None: rval = object_hook(rval) */\r
- if (s->object_hook != Py_None) {\r
- val = PyObject_CallFunctionObjArgs(s->object_hook, rval, NULL);\r
- if (val == NULL)\r
- goto bail;\r
- Py_DECREF(rval);\r
- rval = val;\r
- val = NULL;\r
- }\r
- *next_idx_ptr = idx + 1;\r
- return rval;\r
-bail:\r
- Py_XDECREF(key);\r
- Py_XDECREF(val);\r
- Py_XDECREF(pairs);\r
- return NULL;\r
-}\r
-\r
-static PyObject *\r
-_parse_array_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr) {\r
- /* Read a JSON array from PyString pystr.\r
- idx is the index of the first character after the opening brace.\r
- *next_idx_ptr is a return-by-reference index to the first character after\r
- the closing brace.\r
-\r
- Returns a new PyList\r
- */\r
- char *str = PyString_AS_STRING(pystr);\r
- Py_ssize_t end_idx = PyString_GET_SIZE(pystr) - 1;\r
- PyObject *val = NULL;\r
- PyObject *rval = PyList_New(0);\r
- Py_ssize_t next_idx;\r
- if (rval == NULL)\r
- return NULL;\r
-\r
- /* skip whitespace after [ */\r
- while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++;\r
-\r
- /* only loop if the array is non-empty */\r
- if (idx <= end_idx && str[idx] != ']') {\r
- while (idx <= end_idx) {\r
-\r
- /* read any JSON term and de-tuplefy the (rval, idx) */\r
- val = scan_once_str(s, pystr, idx, &next_idx);\r
- if (val == NULL)\r
- goto bail;\r
-\r
- if (PyList_Append(rval, val) == -1)\r
- goto bail;\r
-\r
- Py_CLEAR(val);\r
- idx = next_idx;\r
-\r
- /* skip whitespace between term and , */\r
- while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++;\r
-\r
- /* bail if the array is closed or we didn't get the , delimiter */\r
- if (idx > end_idx) break;\r
- if (str[idx] == ']') {\r
- break;\r
- }\r
- else if (str[idx] != ',') {\r
- raise_errmsg("Expecting , delimiter", pystr, idx);\r
- goto bail;\r
- }\r
- idx++;\r
-\r
- /* skip whitespace after , */\r
- while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++;\r
- }\r
- }\r
-\r
- /* verify that idx < end_idx, str[idx] should be ']' */\r
- if (idx > end_idx || str[idx] != ']') {\r
- raise_errmsg("Expecting object", pystr, end_idx);\r
- goto bail;\r
- }\r
- *next_idx_ptr = idx + 1;\r
- return rval;\r
-bail:\r
- Py_XDECREF(val);\r
- Py_DECREF(rval);\r
- return NULL;\r
-}\r
-\r
-static PyObject *\r
-_parse_array_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr) {\r
- /* Read a JSON array from PyString pystr.\r
- idx is the index of the first character after the opening brace.\r
- *next_idx_ptr is a return-by-reference index to the first character after\r
- the closing brace.\r
-\r
- Returns a new PyList\r
- */\r
- Py_UNICODE *str = PyUnicode_AS_UNICODE(pystr);\r
- Py_ssize_t end_idx = PyUnicode_GET_SIZE(pystr) - 1;\r
- PyObject *val = NULL;\r
- PyObject *rval = PyList_New(0);\r
- Py_ssize_t next_idx;\r
- if (rval == NULL)\r
- return NULL;\r
-\r
- /* skip whitespace after [ */\r
- while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++;\r
-\r
- /* only loop if the array is non-empty */\r
- if (idx <= end_idx && str[idx] != ']') {\r
- while (idx <= end_idx) {\r
-\r
- /* read any JSON term */\r
- val = scan_once_unicode(s, pystr, idx, &next_idx);\r
- if (val == NULL)\r
- goto bail;\r
-\r
- if (PyList_Append(rval, val) == -1)\r
- goto bail;\r
-\r
- Py_CLEAR(val);\r
- idx = next_idx;\r
-\r
- /* skip whitespace between term and , */\r
- while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++;\r
-\r
- /* bail if the array is closed or we didn't get the , delimiter */\r
- if (idx > end_idx) break;\r
- if (str[idx] == ']') {\r
- break;\r
- }\r
- else if (str[idx] != ',') {\r
- raise_errmsg("Expecting , delimiter", pystr, idx);\r
- goto bail;\r
- }\r
- idx++;\r
-\r
- /* skip whitespace after , */\r
- while (idx <= end_idx && IS_WHITESPACE(str[idx])) idx++;\r
- }\r
- }\r
-\r
- /* verify that idx < end_idx, str[idx] should be ']' */\r
- if (idx > end_idx || str[idx] != ']') {\r
- raise_errmsg("Expecting object", pystr, end_idx);\r
- goto bail;\r
- }\r
- *next_idx_ptr = idx + 1;\r
- return rval;\r
-bail:\r
- Py_XDECREF(val);\r
- Py_DECREF(rval);\r
- return NULL;\r
-}\r
-\r
-static PyObject *\r
-_parse_constant(PyScannerObject *s, char *constant, Py_ssize_t idx, Py_ssize_t *next_idx_ptr) {\r
- /* Read a JSON constant from PyString pystr.\r
- constant is the constant string that was found\r
- ("NaN", "Infinity", "-Infinity").\r
- idx is the index of the first character of the constant\r
- *next_idx_ptr is a return-by-reference index to the first character after\r
- the constant.\r
-\r
- Returns the result of parse_constant\r
- */\r
- PyObject *cstr;\r
- PyObject *rval;\r
- /* constant is "NaN", "Infinity", or "-Infinity" */\r
- cstr = PyString_InternFromString(constant);\r
- if (cstr == NULL)\r
- return NULL;\r
-\r
- /* rval = parse_constant(constant) */\r
- rval = PyObject_CallFunctionObjArgs(s->parse_constant, cstr, NULL);\r
- idx += PyString_GET_SIZE(cstr);\r
- Py_DECREF(cstr);\r
- *next_idx_ptr = idx;\r
- return rval;\r
-}\r
-\r
-static PyObject *\r
-_match_number_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t start, Py_ssize_t *next_idx_ptr) {\r
- /* Read a JSON number from PyString pystr.\r
- idx is the index of the first character of the number\r
- *next_idx_ptr is a return-by-reference index to the first character after\r
- the number.\r
-\r
- Returns a new PyObject representation of that number:\r
- PyInt, PyLong, or PyFloat.\r
- May return other types if parse_int or parse_float are set\r
- */\r
- char *str = PyString_AS_STRING(pystr);\r
- Py_ssize_t end_idx = PyString_GET_SIZE(pystr) - 1;\r
- Py_ssize_t idx = start;\r
- int is_float = 0;\r
- PyObject *rval;\r
- PyObject *numstr;\r
-\r
- /* read a sign if it's there, make sure it's not the end of the string */\r
- if (str[idx] == '-') {\r
- idx++;\r
- if (idx > end_idx) {\r
- PyErr_SetNone(PyExc_StopIteration);\r
- return NULL;\r
- }\r
- }\r
-\r
- /* read as many integer digits as we find as long as it doesn't start with 0 */\r
- if (str[idx] >= '1' && str[idx] <= '9') {\r
- idx++;\r
- while (idx <= end_idx && str[idx] >= '0' && str[idx] <= '9') idx++;\r
- }\r
- /* if it starts with 0 we only expect one integer digit */\r
- else if (str[idx] == '0') {\r
- idx++;\r
- }\r
- /* no integer digits, error */\r
- else {\r
- PyErr_SetNone(PyExc_StopIteration);\r
- return NULL;\r
- }\r
-\r
- /* if the next char is '.' followed by a digit then read all float digits */\r
- if (idx < end_idx && str[idx] == '.' && str[idx + 1] >= '0' && str[idx + 1] <= '9') {\r
- is_float = 1;\r
- idx += 2;\r
- while (idx <= end_idx && str[idx] >= '0' && str[idx] <= '9') idx++;\r
- }\r
-\r
- /* if the next char is 'e' or 'E' then maybe read the exponent (or backtrack) */\r
- if (idx < end_idx && (str[idx] == 'e' || str[idx] == 'E')) {\r
-\r
- /* save the index of the 'e' or 'E' just in case we need to backtrack */\r
- Py_ssize_t e_start = idx;\r
- idx++;\r
-\r
- /* read an exponent sign if present */\r
- if (idx < end_idx && (str[idx] == '-' || str[idx] == '+')) idx++;\r
-\r
- /* read all digits */\r
- while (idx <= end_idx && str[idx] >= '0' && str[idx] <= '9') idx++;\r
-\r
- /* if we got a digit, then parse as float. if not, backtrack */\r
- if (str[idx - 1] >= '0' && str[idx - 1] <= '9') {\r
- is_float = 1;\r
- }\r
- else {\r
- idx = e_start;\r
- }\r
- }\r
-\r
- /* copy the section we determined to be a number */\r
- numstr = PyString_FromStringAndSize(&str[start], idx - start);\r
- if (numstr == NULL)\r
- return NULL;\r
- if (is_float) {\r
- /* parse as a float using a fast path if available, otherwise call user defined method */\r
- if (s->parse_float != (PyObject *)&PyFloat_Type) {\r
- rval = PyObject_CallFunctionObjArgs(s->parse_float, numstr, NULL);\r
- }\r
- else {\r
- double d = PyOS_string_to_double(PyString_AS_STRING(numstr),\r
- NULL, NULL);\r
- if (d == -1.0 && PyErr_Occurred())\r
- return NULL;\r
- rval = PyFloat_FromDouble(d);\r
- }\r
- }\r
- else {\r
- /* parse as an int using a fast path if available, otherwise call user defined method */\r
- if (s->parse_int != (PyObject *)&PyInt_Type) {\r
- rval = PyObject_CallFunctionObjArgs(s->parse_int, numstr, NULL);\r
- }\r
- else {\r
- rval = PyInt_FromString(PyString_AS_STRING(numstr), NULL, 10);\r
- }\r
- }\r
- Py_DECREF(numstr);\r
- *next_idx_ptr = idx;\r
- return rval;\r
-}\r
-\r
-static PyObject *\r
-_match_number_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t start, Py_ssize_t *next_idx_ptr) {\r
- /* Read a JSON number from PyUnicode pystr.\r
- idx is the index of the first character of the number\r
- *next_idx_ptr is a return-by-reference index to the first character after\r
- the number.\r
-\r
- Returns a new PyObject representation of that number:\r
- PyInt, PyLong, or PyFloat.\r
- May return other types if parse_int or parse_float are set\r
- */\r
- Py_UNICODE *str = PyUnicode_AS_UNICODE(pystr);\r
- Py_ssize_t end_idx = PyUnicode_GET_SIZE(pystr) - 1;\r
- Py_ssize_t idx = start;\r
- int is_float = 0;\r
- PyObject *rval;\r
- PyObject *numstr;\r
-\r
- /* read a sign if it's there, make sure it's not the end of the string */\r
- if (str[idx] == '-') {\r
- idx++;\r
- if (idx > end_idx) {\r
- PyErr_SetNone(PyExc_StopIteration);\r
- return NULL;\r
- }\r
- }\r
-\r
- /* read as many integer digits as we find as long as it doesn't start with 0 */\r
- if (str[idx] >= '1' && str[idx] <= '9') {\r
- idx++;\r
- while (idx <= end_idx && str[idx] >= '0' && str[idx] <= '9') idx++;\r
- }\r
- /* if it starts with 0 we only expect one integer digit */\r
- else if (str[idx] == '0') {\r
- idx++;\r
- }\r
- /* no integer digits, error */\r
- else {\r
- PyErr_SetNone(PyExc_StopIteration);\r
- return NULL;\r
- }\r
-\r
- /* if the next char is '.' followed by a digit then read all float digits */\r
- if (idx < end_idx && str[idx] == '.' && str[idx + 1] >= '0' && str[idx + 1] <= '9') {\r
- is_float = 1;\r
- idx += 2;\r
- while (idx <= end_idx && str[idx] >= '0' && str[idx] <= '9') idx++;\r
- }\r
-\r
- /* if the next char is 'e' or 'E' then maybe read the exponent (or backtrack) */\r
- if (idx < end_idx && (str[idx] == 'e' || str[idx] == 'E')) {\r
- Py_ssize_t e_start = idx;\r
- idx++;\r
-\r
- /* read an exponent sign if present */\r
- if (idx < end_idx && (str[idx] == '-' || str[idx] == '+')) idx++;\r
-\r
- /* read all digits */\r
- while (idx <= end_idx && str[idx] >= '0' && str[idx] <= '9') idx++;\r
-\r
- /* if we got a digit, then parse as float. if not, backtrack */\r
- if (str[idx - 1] >= '0' && str[idx - 1] <= '9') {\r
- is_float = 1;\r
- }\r
- else {\r
- idx = e_start;\r
- }\r
- }\r
-\r
- /* copy the section we determined to be a number */\r
- numstr = PyUnicode_FromUnicode(&str[start], idx - start);\r
- if (numstr == NULL)\r
- return NULL;\r
- if (is_float) {\r
- /* parse as a float using a fast path if available, otherwise call user defined method */\r
- if (s->parse_float != (PyObject *)&PyFloat_Type) {\r
- rval = PyObject_CallFunctionObjArgs(s->parse_float, numstr, NULL);\r
- }\r
- else {\r
- rval = PyFloat_FromString(numstr, NULL);\r
- }\r
- }\r
- else {\r
- /* no fast path for unicode -> int, just call */\r
- rval = PyObject_CallFunctionObjArgs(s->parse_int, numstr, NULL);\r
- }\r
- Py_DECREF(numstr);\r
- *next_idx_ptr = idx;\r
- return rval;\r
-}\r
-\r
-static PyObject *\r
-scan_once_str(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr)\r
-{\r
- /* Read one JSON term (of any kind) from PyString pystr.\r
- idx is the index of the first character of the term\r
- *next_idx_ptr is a return-by-reference index to the first character after\r
- the number.\r
-\r
- Returns a new PyObject representation of the term.\r
- */\r
- PyObject *res;\r
- char *str = PyString_AS_STRING(pystr);\r
- Py_ssize_t length = PyString_GET_SIZE(pystr);\r
- if (idx >= length) {\r
- PyErr_SetNone(PyExc_StopIteration);\r
- return NULL;\r
- }\r
- switch (str[idx]) {\r
- case '"':\r
- /* string */\r
- return scanstring_str(pystr, idx + 1,\r
- PyString_AS_STRING(s->encoding),\r
- PyObject_IsTrue(s->strict),\r
- next_idx_ptr);\r
- case '{':\r
- /* object */\r
- if (Py_EnterRecursiveCall(" while decoding a JSON object "\r
- "from a byte string"))\r
- return NULL;\r
- res = _parse_object_str(s, pystr, idx + 1, next_idx_ptr);\r
- Py_LeaveRecursiveCall();\r
- return res;\r
- case '[':\r
- /* array */\r
- if (Py_EnterRecursiveCall(" while decoding a JSON array "\r
- "from a byte string"))\r
- return NULL;\r
- res = _parse_array_str(s, pystr, idx + 1, next_idx_ptr);\r
- Py_LeaveRecursiveCall();\r
- return res;\r
- case 'n':\r
- /* null */\r
- if ((idx + 3 < length) && str[idx + 1] == 'u' && str[idx + 2] == 'l' && str[idx + 3] == 'l') {\r
- Py_INCREF(Py_None);\r
- *next_idx_ptr = idx + 4;\r
- return Py_None;\r
- }\r
- break;\r
- case 't':\r
- /* true */\r
- if ((idx + 3 < length) && str[idx + 1] == 'r' && str[idx + 2] == 'u' && str[idx + 3] == 'e') {\r
- Py_INCREF(Py_True);\r
- *next_idx_ptr = idx + 4;\r
- return Py_True;\r
- }\r
- break;\r
- case 'f':\r
- /* false */\r
- if ((idx + 4 < length) && str[idx + 1] == 'a' && str[idx + 2] == 'l' && str[idx + 3] == 's' && str[idx + 4] == 'e') {\r
- Py_INCREF(Py_False);\r
- *next_idx_ptr = idx + 5;\r
- return Py_False;\r
- }\r
- break;\r
- case 'N':\r
- /* NaN */\r
- if ((idx + 2 < length) && str[idx + 1] == 'a' && str[idx + 2] == 'N') {\r
- return _parse_constant(s, "NaN", idx, next_idx_ptr);\r
- }\r
- break;\r
- case 'I':\r
- /* Infinity */\r
- if ((idx + 7 < length) && str[idx + 1] == 'n' && str[idx + 2] == 'f' && str[idx + 3] == 'i' && str[idx + 4] == 'n' && str[idx + 5] == 'i' && str[idx + 6] == 't' && str[idx + 7] == 'y') {\r
- return _parse_constant(s, "Infinity", idx, next_idx_ptr);\r
- }\r
- break;\r
- case '-':\r
- /* -Infinity */\r
- if ((idx + 8 < length) && str[idx + 1] == 'I' && str[idx + 2] == 'n' && str[idx + 3] == 'f' && str[idx + 4] == 'i' && str[idx + 5] == 'n' && str[idx + 6] == 'i' && str[idx + 7] == 't' && str[idx + 8] == 'y') {\r
- return _parse_constant(s, "-Infinity", idx, next_idx_ptr);\r
- }\r
- break;\r
- }\r
- /* Didn't find a string, object, array, or named constant. Look for a number. */\r
- return _match_number_str(s, pystr, idx, next_idx_ptr);\r
-}\r
-\r
-static PyObject *\r
-scan_once_unicode(PyScannerObject *s, PyObject *pystr, Py_ssize_t idx, Py_ssize_t *next_idx_ptr)\r
-{\r
- /* Read one JSON term (of any kind) from PyUnicode pystr.\r
- idx is the index of the first character of the term\r
- *next_idx_ptr is a return-by-reference index to the first character after\r
- the number.\r
-\r
- Returns a new PyObject representation of the term.\r
- */\r
- PyObject *res;\r
- Py_UNICODE *str = PyUnicode_AS_UNICODE(pystr);\r
- Py_ssize_t length = PyUnicode_GET_SIZE(pystr);\r
- if (idx >= length) {\r
- PyErr_SetNone(PyExc_StopIteration);\r
- return NULL;\r
- }\r
- switch (str[idx]) {\r
- case '"':\r
- /* string */\r
- return scanstring_unicode(pystr, idx + 1,\r
- PyObject_IsTrue(s->strict),\r
- next_idx_ptr);\r
- case '{':\r
- /* object */\r
- if (Py_EnterRecursiveCall(" while decoding a JSON object "\r
- "from a unicode string"))\r
- return NULL;\r
- res = _parse_object_unicode(s, pystr, idx + 1, next_idx_ptr);\r
- Py_LeaveRecursiveCall();\r
- return res;\r
- case '[':\r
- /* array */\r
- if (Py_EnterRecursiveCall(" while decoding a JSON array "\r
- "from a unicode string"))\r
- return NULL;\r
- res = _parse_array_unicode(s, pystr, idx + 1, next_idx_ptr);\r
- Py_LeaveRecursiveCall();\r
- return res;\r
- case 'n':\r
- /* null */\r
- if ((idx + 3 < length) && str[idx + 1] == 'u' && str[idx + 2] == 'l' && str[idx + 3] == 'l') {\r
- Py_INCREF(Py_None);\r
- *next_idx_ptr = idx + 4;\r
- return Py_None;\r
- }\r
- break;\r
- case 't':\r
- /* true */\r
- if ((idx + 3 < length) && str[idx + 1] == 'r' && str[idx + 2] == 'u' && str[idx + 3] == 'e') {\r
- Py_INCREF(Py_True);\r
- *next_idx_ptr = idx + 4;\r
- return Py_True;\r
- }\r
- break;\r
- case 'f':\r
- /* false */\r
- if ((idx + 4 < length) && str[idx + 1] == 'a' && str[idx + 2] == 'l' && str[idx + 3] == 's' && str[idx + 4] == 'e') {\r
- Py_INCREF(Py_False);\r
- *next_idx_ptr = idx + 5;\r
- return Py_False;\r
- }\r
- break;\r
- case 'N':\r
- /* NaN */\r
- if ((idx + 2 < length) && str[idx + 1] == 'a' && str[idx + 2] == 'N') {\r
- return _parse_constant(s, "NaN", idx, next_idx_ptr);\r
- }\r
- break;\r
- case 'I':\r
- /* Infinity */\r
- if ((idx + 7 < length) && str[idx + 1] == 'n' && str[idx + 2] == 'f' && str[idx + 3] == 'i' && str[idx + 4] == 'n' && str[idx + 5] == 'i' && str[idx + 6] == 't' && str[idx + 7] == 'y') {\r
- return _parse_constant(s, "Infinity", idx, next_idx_ptr);\r
- }\r
- break;\r
- case '-':\r
- /* -Infinity */\r
- if ((idx + 8 < length) && str[idx + 1] == 'I' && str[idx + 2] == 'n' && str[idx + 3] == 'f' && str[idx + 4] == 'i' && str[idx + 5] == 'n' && str[idx + 6] == 'i' && str[idx + 7] == 't' && str[idx + 8] == 'y') {\r
- return _parse_constant(s, "-Infinity", idx, next_idx_ptr);\r
- }\r
- break;\r
- }\r
- /* Didn't find a string, object, array, or named constant. Look for a number. */\r
- return _match_number_unicode(s, pystr, idx, next_idx_ptr);\r
-}\r
-\r
-static PyObject *\r
-scanner_call(PyObject *self, PyObject *args, PyObject *kwds)\r
-{\r
- /* Python callable interface to scan_once_{str,unicode} */\r
- PyObject *pystr;\r
- PyObject *rval;\r
- Py_ssize_t idx;\r
- Py_ssize_t next_idx = -1;\r
- static char *kwlist[] = {"string", "idx", NULL};\r
- PyScannerObject *s;\r
- assert(PyScanner_Check(self));\r
- s = (PyScannerObject *)self;\r
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&:scan_once", kwlist, &pystr, _convertPyInt_AsSsize_t, &idx))\r
- return NULL;\r
-\r
- if (PyString_Check(pystr)) {\r
- rval = scan_once_str(s, pystr, idx, &next_idx);\r
- }\r
- else if (PyUnicode_Check(pystr)) {\r
- rval = scan_once_unicode(s, pystr, idx, &next_idx);\r
- }\r
- else {\r
- PyErr_Format(PyExc_TypeError,\r
- "first argument must be a string, not %.80s",\r
- Py_TYPE(pystr)->tp_name);\r
- return NULL;\r
- }\r
- return _build_rval_index_tuple(rval, next_idx);\r
-}\r
-\r
-static PyObject *\r
-scanner_new(PyTypeObject *type, PyObject *args, PyObject *kwds)\r
-{\r
- PyScannerObject *s;\r
- s = (PyScannerObject *)type->tp_alloc(type, 0);\r
- if (s != NULL) {\r
- s->encoding = NULL;\r
- s->strict = NULL;\r
- s->object_hook = NULL;\r
- s->pairs_hook = NULL;\r
- s->parse_float = NULL;\r
- s->parse_int = NULL;\r
- s->parse_constant = NULL;\r
- }\r
- return (PyObject *)s;\r
-}\r
-\r
-static int\r
-scanner_init(PyObject *self, PyObject *args, PyObject *kwds)\r
-{\r
- /* Initialize Scanner object */\r
- PyObject *ctx;\r
- static char *kwlist[] = {"context", NULL};\r
- PyScannerObject *s;\r
-\r
- assert(PyScanner_Check(self));\r
- s = (PyScannerObject *)self;\r
-\r
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "O:make_scanner", kwlist, &ctx))\r
- return -1;\r
-\r
- /* PyString_AS_STRING is used on encoding */\r
- s->encoding = PyObject_GetAttrString(ctx, "encoding");\r
- if (s->encoding == NULL)\r
- goto bail;\r
- if (s->encoding == Py_None) {\r
- Py_DECREF(Py_None);\r
- s->encoding = PyString_InternFromString(DEFAULT_ENCODING);\r
- }\r
- else if (PyUnicode_Check(s->encoding)) {\r
- PyObject *tmp = PyUnicode_AsEncodedString(s->encoding, NULL, NULL);\r
- Py_DECREF(s->encoding);\r
- s->encoding = tmp;\r
- }\r
- if (s->encoding == NULL || !PyString_Check(s->encoding))\r
- goto bail;\r
-\r
- /* All of these will fail "gracefully" so we don't need to verify them */\r
- s->strict = PyObject_GetAttrString(ctx, "strict");\r
- if (s->strict == NULL)\r
- goto bail;\r
- s->object_hook = PyObject_GetAttrString(ctx, "object_hook");\r
- if (s->object_hook == NULL)\r
- goto bail;\r
- s->pairs_hook = PyObject_GetAttrString(ctx, "object_pairs_hook");\r
- if (s->pairs_hook == NULL)\r
- goto bail;\r
- s->parse_float = PyObject_GetAttrString(ctx, "parse_float");\r
- if (s->parse_float == NULL)\r
- goto bail;\r
- s->parse_int = PyObject_GetAttrString(ctx, "parse_int");\r
- if (s->parse_int == NULL)\r
- goto bail;\r
- s->parse_constant = PyObject_GetAttrString(ctx, "parse_constant");\r
- if (s->parse_constant == NULL)\r
- goto bail;\r
-\r
- return 0;\r
-\r
-bail:\r
- Py_CLEAR(s->encoding);\r
- Py_CLEAR(s->strict);\r
- Py_CLEAR(s->object_hook);\r
- Py_CLEAR(s->pairs_hook);\r
- Py_CLEAR(s->parse_float);\r
- Py_CLEAR(s->parse_int);\r
- Py_CLEAR(s->parse_constant);\r
- return -1;\r
-}\r
-\r
-PyDoc_STRVAR(scanner_doc, "JSON scanner object");\r
-\r
-static\r
-PyTypeObject PyScannerType = {\r
- PyObject_HEAD_INIT(NULL)\r
- 0, /* tp_internal */\r
- "_json.Scanner", /* tp_name */\r
- sizeof(PyScannerObject), /* tp_basicsize */\r
- 0, /* tp_itemsize */\r
- scanner_dealloc, /* tp_dealloc */\r
- 0, /* tp_print */\r
- 0, /* tp_getattr */\r
- 0, /* tp_setattr */\r
- 0, /* tp_compare */\r
- 0, /* tp_repr */\r
- 0, /* tp_as_number */\r
- 0, /* tp_as_sequence */\r
- 0, /* tp_as_mapping */\r
- 0, /* tp_hash */\r
- scanner_call, /* tp_call */\r
- 0, /* tp_str */\r
- 0,/* PyObject_GenericGetAttr, */ /* tp_getattro */\r
- 0,/* PyObject_GenericSetAttr, */ /* tp_setattro */\r
- 0, /* tp_as_buffer */\r
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */\r
- scanner_doc, /* tp_doc */\r
- scanner_traverse, /* tp_traverse */\r
- scanner_clear, /* tp_clear */\r
- 0, /* tp_richcompare */\r
- 0, /* tp_weaklistoffset */\r
- 0, /* tp_iter */\r
- 0, /* tp_iternext */\r
- 0, /* tp_methods */\r
- scanner_members, /* tp_members */\r
- 0, /* tp_getset */\r
- 0, /* tp_base */\r
- 0, /* tp_dict */\r
- 0, /* tp_descr_get */\r
- 0, /* tp_descr_set */\r
- 0, /* tp_dictoffset */\r
- scanner_init, /* tp_init */\r
- 0,/* PyType_GenericAlloc, */ /* tp_alloc */\r
- scanner_new, /* tp_new */\r
- 0,/* PyObject_GC_Del, */ /* tp_free */\r
-};\r
-\r
-static PyObject *\r
-encoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)\r
-{\r
- PyEncoderObject *s;\r
- s = (PyEncoderObject *)type->tp_alloc(type, 0);\r
- if (s != NULL) {\r
- s->markers = NULL;\r
- s->defaultfn = NULL;\r
- s->encoder = NULL;\r
- s->indent = NULL;\r
- s->key_separator = NULL;\r
- s->item_separator = NULL;\r
- s->sort_keys = NULL;\r
- s->skipkeys = NULL;\r
- }\r
- return (PyObject *)s;\r
-}\r
-\r
-static int\r
-encoder_init(PyObject *self, PyObject *args, PyObject *kwds)\r
-{\r
- /* initialize Encoder object */\r
- static char *kwlist[] = {"markers", "default", "encoder", "indent", "key_separator", "item_separator", "sort_keys", "skipkeys", "allow_nan", NULL};\r
-\r
- PyEncoderObject *s;\r
- PyObject *markers, *defaultfn, *encoder, *indent, *key_separator;\r
- PyObject *item_separator, *sort_keys, *skipkeys, *allow_nan;\r
-\r
- assert(PyEncoder_Check(self));\r
- s = (PyEncoderObject *)self;\r
-\r
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOOOOOOOO:make_encoder", kwlist,\r
- &markers, &defaultfn, &encoder, &indent, &key_separator, &item_separator,\r
- &sort_keys, &skipkeys, &allow_nan))\r
- return -1;\r
-\r
- s->markers = markers;\r
- s->defaultfn = defaultfn;\r
- s->encoder = encoder;\r
- s->indent = indent;\r
- s->key_separator = key_separator;\r
- s->item_separator = item_separator;\r
- s->sort_keys = sort_keys;\r
- s->skipkeys = skipkeys;\r
- s->fast_encode = (PyCFunction_Check(s->encoder) && PyCFunction_GetFunction(s->encoder) == (PyCFunction)py_encode_basestring_ascii);\r
- s->allow_nan = PyObject_IsTrue(allow_nan);\r
-\r
- Py_INCREF(s->markers);\r
- Py_INCREF(s->defaultfn);\r
- Py_INCREF(s->encoder);\r
- Py_INCREF(s->indent);\r
- Py_INCREF(s->key_separator);\r
- Py_INCREF(s->item_separator);\r
- Py_INCREF(s->sort_keys);\r
- Py_INCREF(s->skipkeys);\r
- return 0;\r
-}\r
-\r
-static PyObject *\r
-encoder_call(PyObject *self, PyObject *args, PyObject *kwds)\r
-{\r
- /* Python callable interface to encode_listencode_obj */\r
- static char *kwlist[] = {"obj", "_current_indent_level", NULL};\r
- PyObject *obj;\r
- PyObject *rval;\r
- Py_ssize_t indent_level;\r
- PyEncoderObject *s;\r
- assert(PyEncoder_Check(self));\r
- s = (PyEncoderObject *)self;\r
- if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO&:_iterencode", kwlist,\r
- &obj, _convertPyInt_AsSsize_t, &indent_level))\r
- return NULL;\r
- rval = PyList_New(0);\r
- if (rval == NULL)\r
- return NULL;\r
- if (encoder_listencode_obj(s, rval, obj, indent_level)) {\r
- Py_DECREF(rval);\r
- return NULL;\r
- }\r
- return rval;\r
-}\r
-\r
-static PyObject *\r
-_encoded_const(PyObject *obj)\r
-{\r
- /* Return the JSON string representation of None, True, False */\r
- if (obj == Py_None) {\r
- static PyObject *s_null = NULL;\r
- if (s_null == NULL) {\r
- s_null = PyString_InternFromString("null");\r
- }\r
- Py_INCREF(s_null);\r
- return s_null;\r
- }\r
- else if (obj == Py_True) {\r
- static PyObject *s_true = NULL;\r
- if (s_true == NULL) {\r
- s_true = PyString_InternFromString("true");\r
- }\r
- Py_INCREF(s_true);\r
- return s_true;\r
- }\r
- else if (obj == Py_False) {\r
- static PyObject *s_false = NULL;\r
- if (s_false == NULL) {\r
- s_false = PyString_InternFromString("false");\r
- }\r
- Py_INCREF(s_false);\r
- return s_false;\r
- }\r
- else {\r
- PyErr_SetString(PyExc_ValueError, "not a const");\r
- return NULL;\r
- }\r
-}\r
-\r
-static PyObject *\r
-encoder_encode_float(PyEncoderObject *s, PyObject *obj)\r
-{\r
- /* Return the JSON representation of a PyFloat */\r
- double i = PyFloat_AS_DOUBLE(obj);\r
- if (!Py_IS_FINITE(i)) {\r
- if (!s->allow_nan) {\r
- PyErr_SetString(PyExc_ValueError, "Out of range float values are not JSON compliant");\r
- return NULL;\r
- }\r
- if (i > 0) {\r
- return PyString_FromString("Infinity");\r
- }\r
- else if (i < 0) {\r
- return PyString_FromString("-Infinity");\r
- }\r
- else {\r
- return PyString_FromString("NaN");\r
- }\r
- }\r
- /* Use a better float format here? */\r
- return PyObject_Repr(obj);\r
-}\r
-\r
-static PyObject *\r
-encoder_encode_string(PyEncoderObject *s, PyObject *obj)\r
-{\r
- /* Return the JSON representation of a string */\r
- if (s->fast_encode)\r
- return py_encode_basestring_ascii(NULL, obj);\r
- else\r
- return PyObject_CallFunctionObjArgs(s->encoder, obj, NULL);\r
-}\r
-\r
-static int\r
-_steal_list_append(PyObject *lst, PyObject *stolen)\r
-{\r
- /* Append stolen and then decrement its reference count */\r
- int rval = PyList_Append(lst, stolen);\r
- Py_DECREF(stolen);\r
- return rval;\r
-}\r
-\r
-static int\r
-encoder_listencode_obj(PyEncoderObject *s, PyObject *rval, PyObject *obj, Py_ssize_t indent_level)\r
-{\r
- /* Encode Python object obj to a JSON term, rval is a PyList */\r
- PyObject *newobj;\r
- int rv;\r
-\r
- if (obj == Py_None || obj == Py_True || obj == Py_False) {\r
- PyObject *cstr = _encoded_const(obj);\r
- if (cstr == NULL)\r
- return -1;\r
- return _steal_list_append(rval, cstr);\r
- }\r
- else if (PyString_Check(obj) || PyUnicode_Check(obj))\r
- {\r
- PyObject *encoded = encoder_encode_string(s, obj);\r
- if (encoded == NULL)\r
- return -1;\r
- return _steal_list_append(rval, encoded);\r
- }\r
- else if (PyInt_Check(obj) || PyLong_Check(obj)) {\r
- PyObject *encoded = PyObject_Str(obj);\r
- if (encoded == NULL)\r
- return -1;\r
- return _steal_list_append(rval, encoded);\r
- }\r
- else if (PyFloat_Check(obj)) {\r
- PyObject *encoded = encoder_encode_float(s, obj);\r
- if (encoded == NULL)\r
- return -1;\r
- return _steal_list_append(rval, encoded);\r
- }\r
- else if (PyList_Check(obj) || PyTuple_Check(obj)) {\r
- if (Py_EnterRecursiveCall(" while encoding a JSON object"))\r
- return -1;\r
- rv = encoder_listencode_list(s, rval, obj, indent_level);\r
- Py_LeaveRecursiveCall();\r
- return rv;\r
- }\r
- else if (PyDict_Check(obj)) {\r
- if (Py_EnterRecursiveCall(" while encoding a JSON object"))\r
- return -1;\r
- rv = encoder_listencode_dict(s, rval, obj, indent_level);\r
- Py_LeaveRecursiveCall();\r
- return rv;\r
- }\r
- else {\r
- PyObject *ident = NULL;\r
- if (s->markers != Py_None) {\r
- int has_key;\r
- ident = PyLong_FromVoidPtr(obj);\r
- if (ident == NULL)\r
- return -1;\r
- has_key = PyDict_Contains(s->markers, ident);\r
- if (has_key) {\r
- if (has_key != -1)\r
- PyErr_SetString(PyExc_ValueError, "Circular reference detected");\r
- Py_DECREF(ident);\r
- return -1;\r
- }\r
- if (PyDict_SetItem(s->markers, ident, obj)) {\r
- Py_DECREF(ident);\r
- return -1;\r
- }\r
- }\r
- newobj = PyObject_CallFunctionObjArgs(s->defaultfn, obj, NULL);\r
- if (newobj == NULL) {\r
- Py_XDECREF(ident);\r
- return -1;\r
- }\r
-\r
- if (Py_EnterRecursiveCall(" while encoding a JSON object"))\r
- return -1;\r
- rv = encoder_listencode_obj(s, rval, newobj, indent_level);\r
- Py_LeaveRecursiveCall();\r
-\r
- Py_DECREF(newobj);\r
- if (rv) {\r
- Py_XDECREF(ident);\r
- return -1;\r
- }\r
- if (ident != NULL) {\r
- if (PyDict_DelItem(s->markers, ident)) {\r
- Py_XDECREF(ident);\r
- return -1;\r
- }\r
- Py_XDECREF(ident);\r
- }\r
- return rv;\r
- }\r
-}\r
-\r
-static int\r
-encoder_listencode_dict(PyEncoderObject *s, PyObject *rval, PyObject *dct, Py_ssize_t indent_level)\r
-{\r
- /* Encode Python dict dct a JSON term, rval is a PyList */\r
- static PyObject *open_dict = NULL;\r
- static PyObject *close_dict = NULL;\r
- static PyObject *empty_dict = NULL;\r
- PyObject *kstr = NULL;\r
- PyObject *ident = NULL;\r
- PyObject *key = NULL;\r
- PyObject *value = NULL;\r
- PyObject *it = NULL;\r
- int skipkeys;\r
- Py_ssize_t idx;\r
-\r
- if (open_dict == NULL || close_dict == NULL || empty_dict == NULL) {\r
- open_dict = PyString_InternFromString("{");\r
- close_dict = PyString_InternFromString("}");\r
- empty_dict = PyString_InternFromString("{}");\r
- if (open_dict == NULL || close_dict == NULL || empty_dict == NULL)\r
- return -1;\r
- }\r
- if (Py_SIZE(dct) == 0)\r
- return PyList_Append(rval, empty_dict);\r
-\r
- if (s->markers != Py_None) {\r
- int has_key;\r
- ident = PyLong_FromVoidPtr(dct);\r
- if (ident == NULL)\r
- goto bail;\r
- has_key = PyDict_Contains(s->markers, ident);\r
- if (has_key) {\r
- if (has_key != -1)\r
- PyErr_SetString(PyExc_ValueError, "Circular reference detected");\r
- goto bail;\r
- }\r
- if (PyDict_SetItem(s->markers, ident, dct)) {\r
- goto bail;\r
- }\r
- }\r
-\r
- if (PyList_Append(rval, open_dict))\r
- goto bail;\r
-\r
- if (s->indent != Py_None) {\r
- /* TODO: DOES NOT RUN */\r
- indent_level += 1;\r
- /*\r
- newline_indent = '\n' + (' ' * (_indent * _current_indent_level))\r
- separator = _item_separator + newline_indent\r
- buf += newline_indent\r
- */\r
- }\r
-\r
- /* TODO: C speedup not implemented for sort_keys */\r
-\r
- it = PyObject_GetIter(dct);\r
- if (it == NULL)\r
- goto bail;\r
- skipkeys = PyObject_IsTrue(s->skipkeys);\r
- idx = 0;\r
- while ((key = PyIter_Next(it)) != NULL) {\r
- PyObject *encoded;\r
-\r
- if (PyString_Check(key) || PyUnicode_Check(key)) {\r
- Py_INCREF(key);\r
- kstr = key;\r
- }\r
- else if (PyFloat_Check(key)) {\r
- kstr = encoder_encode_float(s, key);\r
- if (kstr == NULL)\r
- goto bail;\r
- }\r
- else if (PyInt_Check(key) || PyLong_Check(key)) {\r
- kstr = PyObject_Str(key);\r
- if (kstr == NULL)\r
- goto bail;\r
- }\r
- else if (key == Py_True || key == Py_False || key == Py_None) {\r
- kstr = _encoded_const(key);\r
- if (kstr == NULL)\r
- goto bail;\r
- }\r
- else if (skipkeys) {\r
- Py_DECREF(key);\r
- continue;\r
- }\r
- else {\r
- /* TODO: include repr of key */\r
- PyErr_SetString(PyExc_TypeError, "keys must be a string");\r
- goto bail;\r
- }\r
-\r
- if (idx) {\r
- if (PyList_Append(rval, s->item_separator))\r
- goto bail;\r
- }\r
-\r
- value = PyObject_GetItem(dct, key);\r
- if (value == NULL)\r
- goto bail;\r
-\r
- encoded = encoder_encode_string(s, kstr);\r
- Py_CLEAR(kstr);\r
- if (encoded == NULL)\r
- goto bail;\r
- if (PyList_Append(rval, encoded)) {\r
- Py_DECREF(encoded);\r
- goto bail;\r
- }\r
- Py_DECREF(encoded);\r
- if (PyList_Append(rval, s->key_separator))\r
- goto bail;\r
- if (encoder_listencode_obj(s, rval, value, indent_level))\r
- goto bail;\r
- idx += 1;\r
- Py_CLEAR(value);\r
- Py_DECREF(key);\r
- }\r
- if (PyErr_Occurred())\r
- goto bail;\r
- Py_CLEAR(it);\r
-\r
- if (ident != NULL) {\r
- if (PyDict_DelItem(s->markers, ident))\r
- goto bail;\r
- Py_CLEAR(ident);\r
- }\r
- if (s->indent != Py_None) {\r
- /* TODO: DOES NOT RUN */\r
- /*\r
- indent_level -= 1;\r
-\r
- yield '\n' + (' ' * (_indent * _current_indent_level))\r
- */\r
- }\r
- if (PyList_Append(rval, close_dict))\r
- goto bail;\r
- return 0;\r
-\r
-bail:\r
- Py_XDECREF(it);\r
- Py_XDECREF(key);\r
- Py_XDECREF(value);\r
- Py_XDECREF(kstr);\r
- Py_XDECREF(ident);\r
- return -1;\r
-}\r
-\r
-\r
-static int\r
-encoder_listencode_list(PyEncoderObject *s, PyObject *rval, PyObject *seq, Py_ssize_t indent_level)\r
-{\r
- /* Encode Python list seq to a JSON term, rval is a PyList */\r
- static PyObject *open_array = NULL;\r
- static PyObject *close_array = NULL;\r
- static PyObject *empty_array = NULL;\r
- PyObject *ident = NULL;\r
- PyObject *s_fast = NULL;\r
- Py_ssize_t num_items;\r
- PyObject **seq_items;\r
- Py_ssize_t i;\r
-\r
- if (open_array == NULL || close_array == NULL || empty_array == NULL) {\r
- open_array = PyString_InternFromString("[");\r
- close_array = PyString_InternFromString("]");\r
- empty_array = PyString_InternFromString("[]");\r
- if (open_array == NULL || close_array == NULL || empty_array == NULL)\r
- return -1;\r
- }\r
- ident = NULL;\r
- s_fast = PySequence_Fast(seq, "_iterencode_list needs a sequence");\r
- if (s_fast == NULL)\r
- return -1;\r
- num_items = PySequence_Fast_GET_SIZE(s_fast);\r
- if (num_items == 0) {\r
- Py_DECREF(s_fast);\r
- return PyList_Append(rval, empty_array);\r
- }\r
-\r
- if (s->markers != Py_None) {\r
- int has_key;\r
- ident = PyLong_FromVoidPtr(seq);\r
- if (ident == NULL)\r
- goto bail;\r
- has_key = PyDict_Contains(s->markers, ident);\r
- if (has_key) {\r
- if (has_key != -1)\r
- PyErr_SetString(PyExc_ValueError, "Circular reference detected");\r
- goto bail;\r
- }\r
- if (PyDict_SetItem(s->markers, ident, seq)) {\r
- goto bail;\r
- }\r
- }\r
-\r
- seq_items = PySequence_Fast_ITEMS(s_fast);\r
- if (PyList_Append(rval, open_array))\r
- goto bail;\r
- if (s->indent != Py_None) {\r
- /* TODO: DOES NOT RUN */\r
- indent_level += 1;\r
- /*\r
- newline_indent = '\n' + (' ' * (_indent * _current_indent_level))\r
- separator = _item_separator + newline_indent\r
- buf += newline_indent\r
- */\r
- }\r
- for (i = 0; i < num_items; i++) {\r
- PyObject *obj = seq_items[i];\r
- if (i) {\r
- if (PyList_Append(rval, s->item_separator))\r
- goto bail;\r
- }\r
- if (encoder_listencode_obj(s, rval, obj, indent_level))\r
- goto bail;\r
- }\r
- if (ident != NULL) {\r
- if (PyDict_DelItem(s->markers, ident))\r
- goto bail;\r
- Py_CLEAR(ident);\r
- }\r
- if (s->indent != Py_None) {\r
- /* TODO: DOES NOT RUN */\r
- /*\r
- indent_level -= 1;\r
-\r
- yield '\n' + (' ' * (_indent * _current_indent_level))\r
- */\r
- }\r
- if (PyList_Append(rval, close_array))\r
- goto bail;\r
- Py_DECREF(s_fast);\r
- return 0;\r
-\r
-bail:\r
- Py_XDECREF(ident);\r
- Py_DECREF(s_fast);\r
- return -1;\r
-}\r
-\r
-static void\r
-encoder_dealloc(PyObject *self)\r
-{\r
- /* Deallocate Encoder */\r
- encoder_clear(self);\r
- Py_TYPE(self)->tp_free(self);\r
-}\r
-\r
-static int\r
-encoder_traverse(PyObject *self, visitproc visit, void *arg)\r
-{\r
- PyEncoderObject *s;\r
- assert(PyEncoder_Check(self));\r
- s = (PyEncoderObject *)self;\r
- Py_VISIT(s->markers);\r
- Py_VISIT(s->defaultfn);\r
- Py_VISIT(s->encoder);\r
- Py_VISIT(s->indent);\r
- Py_VISIT(s->key_separator);\r
- Py_VISIT(s->item_separator);\r
- Py_VISIT(s->sort_keys);\r
- Py_VISIT(s->skipkeys);\r
- return 0;\r
-}\r
-\r
-static int\r
-encoder_clear(PyObject *self)\r
-{\r
- /* Deallocate Encoder */\r
- PyEncoderObject *s;\r
- assert(PyEncoder_Check(self));\r
- s = (PyEncoderObject *)self;\r
- Py_CLEAR(s->markers);\r
- Py_CLEAR(s->defaultfn);\r
- Py_CLEAR(s->encoder);\r
- Py_CLEAR(s->indent);\r
- Py_CLEAR(s->key_separator);\r
- Py_CLEAR(s->item_separator);\r
- Py_CLEAR(s->sort_keys);\r
- Py_CLEAR(s->skipkeys);\r
- return 0;\r
-}\r
-\r
-PyDoc_STRVAR(encoder_doc, "_iterencode(obj, _current_indent_level) -> iterable");\r
-\r
-static\r
-PyTypeObject PyEncoderType = {\r
- PyObject_HEAD_INIT(NULL)\r
- 0, /* tp_internal */\r
- "_json.Encoder", /* tp_name */\r
- sizeof(PyEncoderObject), /* tp_basicsize */\r
- 0, /* tp_itemsize */\r
- encoder_dealloc, /* tp_dealloc */\r
- 0, /* tp_print */\r
- 0, /* tp_getattr */\r
- 0, /* tp_setattr */\r
- 0, /* tp_compare */\r
- 0, /* tp_repr */\r
- 0, /* tp_as_number */\r
- 0, /* tp_as_sequence */\r
- 0, /* tp_as_mapping */\r
- 0, /* tp_hash */\r
- encoder_call, /* tp_call */\r
- 0, /* tp_str */\r
- 0, /* tp_getattro */\r
- 0, /* tp_setattro */\r
- 0, /* tp_as_buffer */\r
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */\r
- encoder_doc, /* tp_doc */\r
- encoder_traverse, /* tp_traverse */\r
- encoder_clear, /* tp_clear */\r
- 0, /* tp_richcompare */\r
- 0, /* tp_weaklistoffset */\r
- 0, /* tp_iter */\r
- 0, /* tp_iternext */\r
- 0, /* tp_methods */\r
- encoder_members, /* tp_members */\r
- 0, /* tp_getset */\r
- 0, /* tp_base */\r
- 0, /* tp_dict */\r
- 0, /* tp_descr_get */\r
- 0, /* tp_descr_set */\r
- 0, /* tp_dictoffset */\r
- encoder_init, /* tp_init */\r
- 0, /* tp_alloc */\r
- encoder_new, /* tp_new */\r
- 0, /* tp_free */\r
-};\r
-\r
-static PyMethodDef speedups_methods[] = {\r
- {"encode_basestring_ascii",\r
- (PyCFunction)py_encode_basestring_ascii,\r
- METH_O,\r
- pydoc_encode_basestring_ascii},\r
- {"scanstring",\r
- (PyCFunction)py_scanstring,\r
- METH_VARARGS,\r
- pydoc_scanstring},\r
- {NULL, NULL, 0, NULL}\r
-};\r
-\r
-PyDoc_STRVAR(module_doc,\r
-"json speedups\n");\r
-\r
-void\r
-init_json(void)\r
-{\r
- PyObject *m;\r
- PyScannerType.tp_new = PyType_GenericNew;\r
- if (PyType_Ready(&PyScannerType) < 0)\r
- return;\r
- PyEncoderType.tp_new = PyType_GenericNew;\r
- if (PyType_Ready(&PyEncoderType) < 0)\r
- return;\r
- m = Py_InitModule3("_json", speedups_methods, module_doc);\r
- Py_INCREF((PyObject*)&PyScannerType);\r
- PyModule_AddObject(m, "make_scanner", (PyObject*)&PyScannerType);\r
- Py_INCREF((PyObject*)&PyEncoderType);\r
- PyModule_AddObject(m, "make_encoder", (PyObject*)&PyEncoderType);\r
-}\r