Crossfire Server, Branch 1.12  R12190
cjson.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006-2007 Dan Pascu.
00003  * Author: Dan Pascu <dan@ag-projects.com>
00004  *
00005  * Fast JSON encoder/decoder implementation for Python
00006  * This file is under GPL licence
00007  */
00008 
00009 #include <Python.h>
00010 #include <stddef.h>
00011 #include <stdio.h>
00012 #include <ctype.h>
00013 #include <math.h>
00014 
00015 typedef struct JSONData {
00016     char *str; /* the actual json string */
00017     char *end; /* pointer to the string end */
00018     char *ptr; /* pointer to the current parsing position */
00019     int  all_unicode; /* make all output strings unicode if true */
00020 } JSONData;
00021 
00022 static PyObject *encode_object(PyObject *object);
00023 static PyObject *encode_string(PyObject *object);
00024 static PyObject *encode_unicode(PyObject *object);
00025 static PyObject *encode_tuple(PyObject *object);
00026 static PyObject *encode_list(PyObject *object);
00027 static PyObject *encode_dict(PyObject *object);
00028 
00029 static PyObject *decode_json(JSONData *jsondata);
00030 static PyObject *decode_null(JSONData *jsondata);
00031 static PyObject *decode_bool(JSONData *jsondata);
00032 static PyObject *decode_string(JSONData *jsondata);
00033 static PyObject *decode_inf(JSONData *jsondata);
00034 static PyObject *decode_nan(JSONData *jsondata);
00035 static PyObject *decode_number(JSONData *jsondata);
00036 static PyObject *decode_array(JSONData *jsondata);
00037 static PyObject *decode_object(JSONData *jsondata);
00038 
00039 static PyObject *JSON_Error;
00040 static PyObject *JSON_EncodeError;
00041 static PyObject *JSON_DecodeError;
00042 
00043 #if PY_VERSION_HEX < 0x02050000
00044 typedef int Py_ssize_t;
00045 
00046 #define PY_SSIZE_T_MAX INT_MAX
00047 #define PY_SSIZE_T_MIN INT_MIN
00048 
00049 #define SSIZE_T_F "%d"
00050 #else
00051 #define SSIZE_T_F "%zd"
00052 #endif
00053 
00054 #define True  1
00055 #define False 0
00056 
00057 #ifndef INFINITY
00058 #define INFINITY HUGE_VAL
00059 #endif
00060 
00061 #ifndef NAN
00062 #define NAN (HUGE_VAL-HUGE_VAL)
00063 #endif
00064 
00065 #ifndef Py_IS_NAN
00066 #define Py_IS_NAN(X) ((X) != (X))
00067 #endif
00068 
00069 #define skipSpaces(d) while (*((d)->ptr) && isspace(*((d)->ptr))) (d)->ptr++
00070 
00071 /* ------------------------------ Decoding ----------------------------- */
00072 
00073 static void getRowAndCol(char *begin, char *current, int *row, int *col) {
00074     *col = 1;
00075     *row = 1;
00076     while (current > begin) {
00077         if (*current == '\n')
00078             (*row)++;
00079         if (*row < 2)
00080             (*col)++;
00081         current--;
00082     }
00083 }
00084 static PyObject *decode_null(JSONData *jsondata) {
00085     ptrdiff_t left;
00086 
00087     left = jsondata->end-jsondata->ptr;
00088 
00089     if (left >= 4 && strncmp(jsondata->ptr, "null", 4) == 0) {
00090         jsondata->ptr += 4;
00091         Py_INCREF(Py_None);
00092         return Py_None;
00093     } else {
00094         int row, col;
00095 
00096         getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
00097         PyErr_Format(JSON_DecodeError, "cannot parse JSON description: %.20s" "(row "SSIZE_T_F", col "SSIZE_T_F")", jsondata->ptr, (Py_ssize_t)row, (Py_ssize_t)col);
00098         return NULL;
00099     }
00100 }
00101 
00102 static PyObject *decode_bool(JSONData *jsondata) {
00103     ptrdiff_t left;
00104 
00105     left = jsondata->end-jsondata->ptr;
00106 
00107     if (left >= 4 && strncmp(jsondata->ptr, "true", 4) == 0) {
00108         jsondata->ptr += 4;
00109         Py_INCREF(Py_True);
00110         return Py_True;
00111     } else if (left >= 5 && strncmp(jsondata->ptr, "false", 5) == 0) {
00112         jsondata->ptr += 5;
00113         Py_INCREF(Py_False);
00114         return Py_False;
00115     } else {
00116         int row, col;
00117 
00118         getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
00119         PyErr_Format(JSON_DecodeError, "cannot parse JSON description: %.20s" "(row "SSIZE_T_F", col "SSIZE_T_F")", jsondata->ptr, (Py_ssize_t)row, (Py_ssize_t)col);
00120         return NULL;
00121     }
00122 }
00123 
00124 static PyObject *decode_string(JSONData *jsondata) {
00125     PyObject *object;
00126     int c, escaping, has_unicode, string_escape;
00127     Py_ssize_t len;
00128     char *ptr;
00129 
00130     /* look for the closing quote */
00131     escaping = has_unicode = string_escape = False;
00132     ptr = jsondata->ptr+1;
00133     while (True) {
00134         c = *ptr;
00135         if (c == 0) {
00136             int row, col;
00137 
00138             getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
00139             PyErr_Format(JSON_DecodeError, "unterminated string starting at position "SSIZE_T_F"(row "SSIZE_T_F", col "SSIZE_T_F")",
00140                          (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
00141             return NULL;
00142         }
00143         if (!escaping) {
00144             if (c == '\\') {
00145                 escaping = True;
00146             } else if (c == '"') {
00147                 break;
00148             } else if (!isascii(c)) {
00149                 has_unicode = True;
00150             }
00151         } else {
00152             switch (c) {
00153             case 'u':
00154                 has_unicode = True;
00155                 break;
00156             case '"':
00157             case 'r':
00158             case 'n':
00159             case 't':
00160             case 'b':
00161             case 'f':
00162             case '\\':
00163                 string_escape = True;
00164                 break;
00165             }
00166             escaping = False;
00167         }
00168         ptr++;
00169     }
00170 
00171     len = ptr-jsondata->ptr-1;
00172 
00173     if (has_unicode || jsondata->all_unicode)
00174         object = PyUnicode_DecodeUnicodeEscape(jsondata->ptr+1, len, NULL);
00175     else if (string_escape)
00176         object = PyString_DecodeEscape(jsondata->ptr+1, len, NULL, 0, NULL);
00177     else
00178         object = PyString_FromStringAndSize(jsondata->ptr+1, len);
00179 
00180     if (object == NULL) {
00181         PyObject *type, *value, *tb, *reason;
00182 
00183         PyErr_Fetch(&type, &value, &tb);
00184         if (type == NULL) {
00185             int row, col;
00186 
00187             getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
00188             PyErr_Format(JSON_DecodeError, "invalid string starting at position "SSIZE_T_F"(row "SSIZE_T_F", col "SSIZE_T_F")",
00189                          (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
00190         } else {
00191             if (PyErr_GivenExceptionMatches(type, PyExc_UnicodeDecodeError)) {
00192                 int row, col;
00193 
00194                 reason = PyObject_GetAttrString(value, "reason");
00195                 getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
00196                 PyErr_Format(JSON_DecodeError, "cannot decode string starting" " at position "SSIZE_T_F"(row "SSIZE_T_F", col "SSIZE_T_F"): %s",
00197                              (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col,
00198                              reason ? PyString_AsString(reason) : "bad format");
00199                 Py_XDECREF(reason);
00200             } else {
00201                 int row, col;
00202 
00203                 getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
00204                 PyErr_Format(JSON_DecodeError, "invalid string starting at position "SSIZE_T_F"(row "SSIZE_T_F", col "SSIZE_T_F")",
00205                              (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
00206             }
00207         }
00208         Py_XDECREF(type);
00209         Py_XDECREF(value);
00210         Py_XDECREF(tb);
00211     } else {
00212         jsondata->ptr = ptr+1;
00213     }
00214 
00215     return object;
00216 }
00217 
00218 static PyObject *decode_inf(JSONData *jsondata) {
00219     PyObject *object;
00220     ptrdiff_t left;
00221 
00222     left = jsondata->end-jsondata->ptr;
00223 
00224     if (left >= 8 && strncmp(jsondata->ptr, "Infinity", 8) == 0) {
00225         jsondata->ptr += 8;
00226         object = PyFloat_FromDouble(INFINITY);
00227         return object;
00228     } else if (left >= 9 && strncmp(jsondata->ptr, "+Infinity", 9) == 0) {
00229         jsondata->ptr += 9;
00230         object = PyFloat_FromDouble(INFINITY);
00231         return object;
00232     } else if (left >= 9 && strncmp(jsondata->ptr, "-Infinity", 9) == 0) {
00233         jsondata->ptr += 9;
00234         object = PyFloat_FromDouble(-INFINITY);
00235         return object;
00236     } else {
00237         int row, col;
00238 
00239         getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
00240         PyErr_Format(JSON_DecodeError, "cannot parse JSON description: %.20s (row "SSIZE_T_F", col "SSIZE_T_F")", jsondata->ptr, (Py_ssize_t)row, (Py_ssize_t)col);
00241         return NULL;
00242     }
00243 }
00244 
00245 static PyObject *decode_nan(JSONData *jsondata) {
00246     PyObject *object;
00247     ptrdiff_t left;
00248 
00249     left = jsondata->end-jsondata->ptr;
00250 
00251     if (left >= 3 && strncmp(jsondata->ptr, "NaN", 3) == 0) {
00252         jsondata->ptr += 3;
00253         object = PyFloat_FromDouble(NAN);
00254         return object;
00255     } else {
00256         int row, col;
00257         getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
00258         PyErr_Format(JSON_DecodeError, "cannot parse JSON description: %.20s(row "SSIZE_T_F", col "SSIZE_T_F")", jsondata->ptr, (Py_ssize_t)row, (Py_ssize_t)col);
00259         return NULL;
00260     }
00261 }
00262 
00263 static PyObject *decode_number(JSONData *jsondata) {
00264     PyObject *object, *str;
00265     int c, is_float, should_stop;
00266     char *ptr;
00267 
00268     /* check if we got a floating point number */
00269     ptr = jsondata->ptr;
00270     is_float = should_stop = False;
00271     while (True) {
00272         c = *ptr;
00273         if (c == 0)
00274             break;
00275         switch (c) {
00276         case '0':
00277         case '1':
00278         case '2':
00279         case '3':
00280         case '4':
00281         case '5':
00282         case '6':
00283         case '7':
00284         case '8':
00285         case '9':
00286         case '-':
00287         case '+':
00288             break;
00289 
00290         case '.':
00291         case 'e':
00292         case 'E':
00293             is_float = True;
00294             break;
00295 
00296         default:
00297             should_stop = True;
00298         }
00299         if (should_stop) {
00300             break;
00301         }
00302         ptr++;
00303     }
00304 
00305     str = PyString_FromStringAndSize(jsondata->ptr, ptr-jsondata->ptr);
00306     if (str == NULL)
00307         return NULL;
00308 
00309     if (is_float) {
00310         object = PyFloat_FromString(str, NULL);
00311     } else {
00312         object = PyInt_FromString(PyString_AS_STRING(str), NULL, 10);
00313     }
00314 
00315     Py_DECREF(str);
00316 
00317     if (object == NULL) {
00318         int row, col;
00319 
00320         getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
00321         PyErr_Format(JSON_DecodeError, "invalid number starting at position "SSIZE_T_F"(row "SSIZE_T_F", col "SSIZE_T_F")", (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
00322     } else {
00323         jsondata->ptr = ptr;
00324     }
00325 
00326     return object;
00327 }
00328 
00329 static PyObject *decode_array(JSONData *jsondata) {
00330     PyObject *object, *item;
00331     int c, expect_item, items, result;
00332     char *start;
00333 
00334     object = PyList_New(0);
00335 
00336     start = jsondata->ptr;
00337     jsondata->ptr++;
00338     expect_item = True;
00339     items = 0;
00340     while (True) {
00341         skipSpaces(jsondata);
00342         c = *jsondata->ptr;
00343         if (c == 0) {
00344             int row, col;
00345 
00346             getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
00347             PyErr_Format(JSON_DecodeError, "unterminated array starting at position "SSIZE_T_F"(row "SSIZE_T_F", col "SSIZE_T_F")",
00348                          (Py_ssize_t)(start-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
00349             goto failure;
00350         } else if (c == ']') {
00351             if (expect_item && items > 0) {
00352                 int row, col;
00353 
00354                 getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
00355                 PyErr_Format(JSON_DecodeError, "expecting array item at position "SSIZE_T_F"(row "SSIZE_T_F", col "SSIZE_T_F")",
00356                              (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
00357                 goto failure;
00358             }
00359             jsondata->ptr++;
00360             break;
00361         } else if (c == ',') {
00362             if (expect_item) {
00363                 int row, col;
00364 
00365                 getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
00366                 PyErr_Format(JSON_DecodeError, "expecting array item at position "SSIZE_T_F"(row "SSIZE_T_F", col "SSIZE_T_F")",
00367                              (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
00368                 goto failure;
00369             }
00370             expect_item = True;
00371             jsondata->ptr++;
00372             continue;
00373         } else {
00374             item = decode_json(jsondata);
00375             if (item == NULL)
00376                 goto failure;
00377             result = PyList_Append(object, item);
00378             Py_DECREF(item);
00379             if (result == -1)
00380                 goto failure;
00381             expect_item = False;
00382             items++;
00383         }
00384     }
00385 
00386     return object;
00387 
00388 failure:
00389     Py_DECREF(object);
00390     return NULL;
00391 }
00392 
00393 static PyObject *decode_object(JSONData *jsondata) {
00394     PyObject *object, *key, *value;
00395     int c, expect_key, items, result;
00396     char *start;
00397 
00398     object = PyDict_New();
00399 
00400     expect_key = True;
00401     items = 0;
00402     start = jsondata->ptr;
00403     jsondata->ptr++;
00404 
00405     while (True) {
00406         skipSpaces(jsondata);
00407         c = *jsondata->ptr;
00408         if (c == 0) {
00409             int row, col;
00410 
00411             getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
00412             PyErr_Format(JSON_DecodeError, "unterminated object starting at position "SSIZE_T_F"(row "SSIZE_T_F", col "SSIZE_T_F")",
00413                          (Py_ssize_t)(start-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
00414             goto failure;
00415         } else if (c == '}') {
00416             if (expect_key && items > 0) {
00417                 int row, col;
00418 
00419                 getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
00420                 PyErr_Format(JSON_DecodeError, "expecting object property name at position "SSIZE_T_F"(row "SSIZE_T_F", col "SSIZE_T_F")",
00421                              (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
00422                 goto failure;
00423             }
00424             jsondata->ptr++;
00425             break;
00426         } else if (c == ',') {
00427             if (expect_key) {
00428                 int row, col;
00429 
00430                 getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
00431                 PyErr_Format(JSON_DecodeError, "expecting object property name at position "SSIZE_T_F"(row "SSIZE_T_F", col "SSIZE_T_F")",
00432                              (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
00433                 goto failure;
00434             }
00435             expect_key = True;
00436             jsondata->ptr++;
00437             continue;
00438         } else {
00439             if (c != '"') {
00440                 int row, col;
00441 
00442                 getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
00443                 PyErr_Format(JSON_DecodeError, "expecting property name in object at position "SSIZE_T_F"(row "SSIZE_T_F", col "SSIZE_T_F")",
00444                              (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
00445                 goto failure;
00446             }
00447 
00448             key = decode_json(jsondata);
00449             if (key == NULL)
00450                 goto failure;
00451 
00452             skipSpaces(jsondata);
00453             if (*jsondata->ptr != ':') {
00454                 int row, col;
00455 
00456                 getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
00457                 PyErr_Format(JSON_DecodeError, "missing colon after object property name at position "SSIZE_T_F"(row "SSIZE_T_F", col "SSIZE_T_F")",
00458                              (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
00459                 Py_DECREF(key);
00460                 goto failure;
00461             } else {
00462                 jsondata->ptr++;
00463             }
00464 
00465             value = decode_json(jsondata);
00466             if (value == NULL) {
00467                 Py_DECREF(key);
00468                 goto failure;
00469             }
00470 
00471             result = PyDict_SetItem(object, key, value);
00472             Py_DECREF(key);
00473             Py_DECREF(value);
00474             if (result == -1)
00475                 goto failure;
00476             expect_key = False;
00477             items++;
00478         }
00479     }
00480 
00481     return object;
00482 
00483 failure:
00484     Py_DECREF(object);
00485     return NULL;
00486 }
00487 
00488 static PyObject *decode_json(JSONData *jsondata) {
00489     PyObject *object;
00490 
00491     skipSpaces(jsondata);
00492     switch (*jsondata->ptr) {
00493     case 0:
00494         PyErr_SetString(JSON_DecodeError, "empty JSON description");
00495         return NULL;
00496 
00497     case '{':
00498         object = decode_object(jsondata);
00499         break;
00500 
00501     case '[':
00502         object = decode_array(jsondata);
00503         break;
00504 
00505     case '"':
00506         object = decode_string(jsondata);
00507         break;
00508 
00509     case 't':
00510     case 'f':
00511         object = decode_bool(jsondata);
00512         break;
00513 
00514     case 'n':
00515         object = decode_null(jsondata);
00516         break;
00517 
00518     case 'N':
00519         object = decode_nan(jsondata);
00520         break;
00521 
00522     case 'I':
00523         object = decode_inf(jsondata);
00524         break;
00525 
00526     case '+':
00527     case '-':
00528         if (*(jsondata->ptr+1) == 'I') {
00529             object = decode_inf(jsondata);
00530         } else {
00531             object = decode_number(jsondata);
00532         }
00533         break;
00534 
00535     case '0':
00536     case '1':
00537     case '2':
00538     case '3':
00539     case '4':
00540     case '5':
00541     case '6':
00542     case '7':
00543     case '8':
00544     case '9':
00545         object = decode_number(jsondata);
00546         break;
00547 
00548     default:
00549         PyErr_SetString(JSON_DecodeError, "cannot parse JSON description");
00550         return NULL;
00551     }
00552 
00553     return object;
00554 }
00555 
00556 /* ------------------------------ Encoding ----------------------------- */
00557 
00558 /*
00559  * This function is an almost verbatim copy of PyString_Repr() from
00560  * Python's stringobject.c with the following differences:
00561  *
00562  * - it always quotes the output using double quotes.
00563  * - it also quotes \b and \f
00564  * - it replaces any non ASCII character hh with \u00hh instead of \xhh
00565  */
00566 static PyObject *encode_string(PyObject *string) {
00567     register PyStringObject *op = (PyStringObject *)string;
00568     size_t newsize = 2+6*op->ob_size;
00569     PyObject *v;
00570 
00571     if (op->ob_size > (PY_SSIZE_T_MAX-2)/6) {
00572         PyErr_SetString(PyExc_OverflowError, "string is too large to make repr");
00573         return NULL;
00574     }
00575     v = PyString_FromStringAndSize((char *)NULL, newsize);
00576     if (v == NULL) {
00577         return NULL;
00578     } else {
00579         register Py_ssize_t i;
00580         register char c;
00581         register char *p;
00582         int quote;
00583 
00584         quote = '"';
00585 
00586         p = PyString_AS_STRING(v);
00587         *p++ = quote;
00588         for (i = 0; i < op->ob_size; i++) {
00589             /* There's at least enough room for a hex escape
00590              and a closing quote. */
00591             assert(newsize-(p-PyString_AS_STRING(v)) >= 7);
00592             c = op->ob_sval[i];
00593             if (c == quote || c == '\\')
00594                 *p++ = '\\', *p++ = c;
00595             else if (c == '\t')
00596                 *p++ = '\\', *p++ = 't';
00597             else if (c == '\n')
00598                 *p++ = '\\', *p++ = 'n';
00599             else if (c == '\r')
00600                 *p++ = '\\', *p++ = 'r';
00601             else if (c == '\f')
00602                 *p++ = '\\', *p++ = 'f';
00603             else if (c == '\b')
00604                 *p++ = '\\', *p++ = 'b';
00605             else if (c < ' ' || c >= 0x7f) {
00606                 /* For performance, we don't want to call
00607                  * PyOS_snprintf here (extra layers of
00608                  * function call). */
00609                 sprintf(p, "\\u%04x", c&0xff);
00610                 p += 6;
00611             }
00612             else
00613                 *p++ = c;
00614         }
00615         assert(newsize-(p-PyString_AS_STRING(v)) >= 1);
00616         *p++ = quote;
00617         *p = '\0';
00618         _PyString_Resize(&v, (int) (p-PyString_AS_STRING(v)));
00619         return v;
00620     }
00621 }
00622 
00623 /*
00624  * This function is an almost verbatim copy of unicodeescape_string() from
00625  * Python's unicodeobject.c with the following differences:
00626  *
00627  * - it always quotes the output using double quotes.
00628  * - it uses \u00hh instead of \xhh in output.
00629  * - it also quotes \b and \f
00630  */
00631 static PyObject *encode_unicode(PyObject *unicode) {
00632     PyObject *repr;
00633     Py_UNICODE *s;
00634     Py_ssize_t size;
00635     char *p;
00636     static const char *hexdigit = "0123456789abcdef";
00637 
00638     s = PyUnicode_AS_UNICODE(unicode);
00639     size = PyUnicode_GET_SIZE(unicode);
00640 
00641     if (size > (PY_SSIZE_T_MAX-2-1)/6) {
00642         PyErr_SetString(PyExc_OverflowError, "unicode object is too large to make repr");
00643         return NULL;
00644     }
00645 
00646     repr = PyString_FromStringAndSize(NULL, 2+6*size+1);
00647     if (repr == NULL)
00648         return NULL;
00649 
00650     p = PyString_AS_STRING(repr);
00651 
00652     *p++ = '"';
00653 
00654     while (size-- > 0) {
00655         Py_UNICODE ch = *s++;
00656 
00657         /* Escape quotes */
00658         if ((ch == (Py_UNICODE)PyString_AS_STRING(repr)[0] || ch == '\\')) {
00659             *p++ = '\\';
00660             *p++ = (char)ch;
00661             continue;
00662 #ifdef Py_UNICODE_WIDE
00663         /* Map 21-bit characters to '\U00xxxxxx' */
00664         } else if (ch >= 0x10000) {
00665             int offset = p-PyString_AS_STRING(repr);
00666 
00667             /* Resize the string if necessary */
00668             if (offset+12 > PyString_GET_SIZE(repr)) {
00669                 if (_PyString_Resize(&repr, PyString_GET_SIZE(repr)+100))
00670                     return NULL;
00671                 p = PyString_AS_STRING(repr)+offset;
00672             }
00673 
00674             *p++ = '\\';
00675             *p++ = 'U';
00676             *p++ = hexdigit[(ch>>28)&0x0000000F];
00677             *p++ = hexdigit[(ch>>24)&0x0000000F];
00678             *p++ = hexdigit[(ch>>20)&0x0000000F];
00679             *p++ = hexdigit[(ch>>16)&0x0000000F];
00680             *p++ = hexdigit[(ch>>12)&0x0000000F];
00681             *p++ = hexdigit[(ch>>8)&0x0000000F];
00682             *p++ = hexdigit[(ch>>4)&0x0000000F];
00683             *p++ = hexdigit[ch&0x0000000F];
00684             continue;
00685 #endif
00686         /* Map UTF-16 surrogate pairs to Unicode \UXXXXXXXX escapes */
00687         } else if (ch >= 0xD800 && ch < 0xDC00) {
00688             Py_UNICODE ch2;
00689             Py_UCS4 ucs;
00690 
00691             ch2 = *s++;
00692             size--;
00693             if (ch2 >= 0xDC00 && ch2 <= 0xDFFF) {
00694                 ucs = (((ch&0x03FF)<<10)|(ch2&0x03FF))+0x00010000;
00695                 *p++ = '\\';
00696                 *p++ = 'U';
00697                 *p++ = hexdigit[(ucs>>28)&0x0000000F];
00698                 *p++ = hexdigit[(ucs>>24)&0x0000000F];
00699                 *p++ = hexdigit[(ucs>>20)&0x0000000F];
00700                 *p++ = hexdigit[(ucs>>16)&0x0000000F];
00701                 *p++ = hexdigit[(ucs>>12)&0x0000000F];
00702                 *p++ = hexdigit[(ucs>>8)&0x0000000F];
00703                 *p++ = hexdigit[(ucs>>4)&0x0000000F];
00704                 *p++ = hexdigit[ucs&0x0000000F];
00705                 continue;
00706             }
00707             /* Fall through: isolated surrogates are copied as-is */
00708             s--;
00709             size++;
00710         /* Map 16-bit characters to '\uxxxx' */
00711         } if (ch >= 256) {
00712             *p++ = '\\';
00713             *p++ = 'u';
00714             *p++ = hexdigit[(ch>>12)&0x000F];
00715             *p++ = hexdigit[(ch>>8)&0x000F];
00716             *p++ = hexdigit[(ch>>4)&0x000F];
00717             *p++ = hexdigit[ch&0x000F];
00718         /* Map special whitespace to '\t', \n', '\r', '\f', '\b' */
00719         } else if (ch == '\t') {
00720             *p++ = '\\';
00721             *p++ = 't';
00722         } else if (ch == '\n') {
00723             *p++ = '\\';
00724             *p++ = 'n';
00725         } else if (ch == '\r') {
00726             *p++ = '\\';
00727             *p++ = 'r';
00728         } else if (ch == '\f') {
00729             *p++ = '\\';
00730             *p++ = 'f';
00731         } else if (ch == '\b') {
00732             *p++ = '\\';
00733             *p++ = 'b';
00734         }
00735 
00736         /* Map non-printable US ASCII to '\u00hh' */
00737         else if (ch < ' ' || ch >= 0x7F) {
00738             *p++ = '\\';
00739             *p++ = 'u';
00740             *p++ = '0';
00741             *p++ = '0';
00742             *p++ = hexdigit[(ch>>4)&0x000F];
00743             *p++ = hexdigit[ch&0x000F];
00744         }
00745 
00746         /* Copy everything else as-is */
00747         else
00748             *p++ = (char)ch;
00749     }
00750 
00751     *p++ = PyString_AS_STRING(repr)[0];
00752 
00753     *p = '\0';
00754     _PyString_Resize(&repr, p-PyString_AS_STRING(repr));
00755     return repr;
00756 }
00757 
00758 /*
00759  * This function is an almost verbatim copy of tuplerepr() from
00760  * Python's tupleobject.c with the following differences:
00761  *
00762  * - it uses encode_object() to get the object's JSON reprezentation.
00763  * - it uses [] as decorations isntead of () (to masquerade as a JSON array).
00764  */
00765 
00766 static PyObject *encode_tuple(PyObject *tuple) {
00767     Py_ssize_t i, n;
00768     PyObject *s, *temp;
00769     PyObject *pieces, *result = NULL;
00770     PyTupleObject *v = (PyTupleObject *)tuple;
00771 
00772     n = v->ob_size;
00773     if (n == 0)
00774         return PyString_FromString("[]");
00775 
00776     pieces = PyTuple_New(n);
00777     if (pieces == NULL)
00778         return NULL;
00779 
00780     /* Do repr() on each element. */
00781     for (i = 0; i < n; ++i) {
00782         s = encode_object(v->ob_item[i]);
00783         if (s == NULL)
00784             goto Done;
00785         PyTuple_SET_ITEM(pieces, i, s);
00786     }
00787 
00788     /* Add "[]" decorations to the first and last items. */
00789     assert(n > 0);
00790     s = PyString_FromString("[");
00791     if (s == NULL)
00792         goto Done;
00793     temp = PyTuple_GET_ITEM(pieces, 0);
00794     PyString_ConcatAndDel(&s, temp);
00795     PyTuple_SET_ITEM(pieces, 0, s);
00796     if (s == NULL)
00797         goto Done;
00798 
00799     s = PyString_FromString("]");
00800     if (s == NULL)
00801         goto Done;
00802     temp = PyTuple_GET_ITEM(pieces, n-1);
00803     PyString_ConcatAndDel(&temp, s);
00804     PyTuple_SET_ITEM(pieces, n-1, temp);
00805     if (temp == NULL)
00806         goto Done;
00807 
00808     /* Paste them all together with ", " between. */
00809     s = PyString_FromString(", ");
00810     if (s == NULL)
00811         goto Done;
00812     result = _PyString_Join(s, pieces);
00813     Py_DECREF(s);
00814 
00815 Done:
00816     Py_DECREF(pieces);
00817     return result;
00818 }
00819 
00820 /*
00821  * This function is an almost verbatim copy of list_repr() from
00822  * Python's listobject.c with the following differences:
00823  *
00824  * - it uses encode_object() to get the object's JSON reprezentation.
00825  * - it doesn't use the ellipsis to represent a list with references
00826  *   to itself, instead it raises an exception as such lists cannot be
00827  *   represented in JSON.
00828  */
00829 static PyObject *encode_list(PyObject *list) {
00830     Py_ssize_t i;
00831     PyObject *s, *temp;
00832     PyObject *pieces = NULL, *result = NULL;
00833     PyListObject *v = (PyListObject *)list;
00834 
00835     i = Py_ReprEnter((PyObject *)v);
00836     if (i != 0) {
00837         if (i > 0) {
00838             PyErr_SetString(JSON_EncodeError, "a list with references to itself is not JSON encodable");
00839         }
00840         return NULL;
00841     }
00842 
00843     if (v->ob_size == 0) {
00844         result = PyString_FromString("[]");
00845         goto Done;
00846     }
00847 
00848     pieces = PyList_New(0);
00849     if (pieces == NULL)
00850         goto Done;
00851 
00852     /* Do repr() on each element.  Note that this may mutate the list,
00853      * so must refetch the list size on each iteration. */
00854     for (i = 0; i < v->ob_size; ++i) {
00855         int status;
00856         s = encode_object(v->ob_item[i]);
00857         if (s == NULL)
00858             goto Done;
00859         status = PyList_Append(pieces, s);
00860         Py_DECREF(s);  /* append created a new ref */
00861         if (status < 0)
00862             goto Done;
00863     }
00864 
00865     /* Add "[]" decorations to the first and last items. */
00866     assert(PyList_GET_SIZE(pieces) > 0);
00867     s = PyString_FromString("[");
00868     if (s == NULL)
00869         goto Done;
00870     temp = PyList_GET_ITEM(pieces, 0);
00871     PyString_ConcatAndDel(&s, temp);
00872     PyList_SET_ITEM(pieces, 0, s);
00873     if (s == NULL)
00874         goto Done;
00875 
00876     s = PyString_FromString("]");
00877     if (s == NULL)
00878         goto Done;
00879     temp = PyList_GET_ITEM(pieces, PyList_GET_SIZE(pieces)-1);
00880     PyString_ConcatAndDel(&temp, s);
00881     PyList_SET_ITEM(pieces, PyList_GET_SIZE(pieces)-1, temp);
00882     if (temp == NULL)
00883         goto Done;
00884 
00885     /* Paste them all together with ", " between. */
00886     s = PyString_FromString(", ");
00887     if (s == NULL)
00888         goto Done;
00889     result = _PyString_Join(s, pieces);
00890     Py_DECREF(s);
00891 
00892 Done:
00893     Py_XDECREF(pieces);
00894     Py_ReprLeave((PyObject *)v);
00895     return result;
00896 }
00897 
00898 /*
00899  * This function is an almost verbatim copy of dict_repr() from
00900  * Python's dictobject.c with the following differences:
00901  *
00902  * - it uses encode_object() to get the object's JSON reprezentation.
00903  * - only accept strings for keys.
00904  * - it doesn't use the ellipsis to represent a dictionary with references
00905  *   to itself, instead it raises an exception as such dictionaries cannot
00906  *   be represented in JSON.
00907  */
00908 static PyObject *encode_dict(PyObject *dict) {
00909     Py_ssize_t i;
00910     PyObject *s, *temp, *colon = NULL;
00911     PyObject *pieces = NULL, *result = NULL;
00912     PyObject *key, *value;
00913     PyDictObject *mp = (PyDictObject *)dict;
00914 
00915     i = Py_ReprEnter((PyObject *)mp);
00916     if (i != 0) {
00917         if (i > 0) {
00918             PyErr_SetString(JSON_EncodeError, "a dict with references to "
00919                             "itself is not JSON encodable");
00920         }
00921         return NULL;
00922     }
00923 
00924     if (mp->ma_used == 0) {
00925         result = PyString_FromString("{}");
00926         goto Done;
00927     }
00928 
00929     pieces = PyList_New(0);
00930     if (pieces == NULL)
00931         goto Done;
00932 
00933     colon = PyString_FromString(": ");
00934     if (colon == NULL)
00935         goto Done;
00936 
00937     /* Do repr() on each key+value pair, and insert ": " between them.
00938      * Note that repr may mutate the dict. */
00939     i = 0;
00940     while (PyDict_Next((PyObject *)mp, &i, &key, &value)) {
00941         int status;
00942 
00943         if (!PyString_Check(key) && !PyUnicode_Check(key)) {
00944             PyErr_SetString(JSON_EncodeError, "JSON encodable dictionaries must have string/unicode keys");
00945             goto Done;
00946         }
00947 
00948         /* Prevent repr from deleting value during key format. */
00949         Py_INCREF(value);
00950         s = encode_object(key);
00951         PyString_Concat(&s, colon);
00952         PyString_ConcatAndDel(&s, encode_object(value));
00953         Py_DECREF(value);
00954         if (s == NULL)
00955             goto Done;
00956         status = PyList_Append(pieces, s);
00957         Py_DECREF(s);  /* append created a new ref */
00958         if (status < 0)
00959             goto Done;
00960     }
00961 
00962     /* Add "{}" decorations to the first and last items. */
00963     assert(PyList_GET_SIZE(pieces) > 0);
00964     s = PyString_FromString("{");
00965     if (s == NULL)
00966         goto Done;
00967     temp = PyList_GET_ITEM(pieces, 0);
00968     PyString_ConcatAndDel(&s, temp);
00969     PyList_SET_ITEM(pieces, 0, s);
00970     if (s == NULL)
00971         goto Done;
00972 
00973     s = PyString_FromString("}");
00974     if (s == NULL)
00975         goto Done;
00976     temp = PyList_GET_ITEM(pieces, PyList_GET_SIZE(pieces)-1);
00977     PyString_ConcatAndDel(&temp, s);
00978     PyList_SET_ITEM(pieces, PyList_GET_SIZE(pieces)-1, temp);
00979     if (temp == NULL)
00980         goto Done;
00981 
00982     /* Paste them all together with ", " between. */
00983     s = PyString_FromString(", ");
00984     if (s == NULL)
00985         goto Done;
00986     result = _PyString_Join(s, pieces);
00987     Py_DECREF(s);
00988 
00989 Done:
00990     Py_XDECREF(pieces);
00991     Py_XDECREF(colon);
00992     Py_ReprLeave((PyObject *)mp);
00993     return result;
00994 }
00995 
00996 static PyObject *encode_object(PyObject *object) {
00997     if (object == Py_True) {
00998         return PyString_FromString("true");
00999     } else if (object == Py_False) {
01000         return PyString_FromString("false");
01001     } else if (object == Py_None) {
01002         return PyString_FromString("null");
01003     } else if (PyString_Check(object)) {
01004         return encode_string(object);
01005     } else if (PyUnicode_Check(object)) {
01006         return encode_unicode(object);
01007     } else if (PyFloat_Check(object)) {
01008         double val = PyFloat_AS_DOUBLE(object);
01009         if (Py_IS_NAN(val)) {
01010             return PyString_FromString("NaN");
01011         } else if (Py_IS_INFINITY(val)) {
01012             if (val > 0) {
01013                 return PyString_FromString("Infinity");
01014             } else {
01015                 return PyString_FromString("-Infinity");
01016             }
01017         } else {
01018             return PyObject_Str(object);
01019         }
01020     } else if (PyInt_Check(object) || PyLong_Check(object)) {
01021         return PyObject_Str(object);
01022     } else if (PyList_Check(object)) {
01023         return encode_list(object);
01024     } else if (PyTuple_Check(object)) {
01025         return encode_tuple(object);
01026     } else if (PyDict_Check(object)) { /* use PyMapping_Check(object) instead? -Dan */
01027         return encode_dict(object);
01028     } else {
01029         PyErr_SetString(JSON_EncodeError, "object is not JSON encodable");
01030         return NULL;
01031     }
01032 }
01033 
01034 /* Encode object into its JSON representation */
01035 
01036 static PyObject *JSON_encode(PyObject *self, PyObject *object) {
01037     return encode_object(object);
01038 }
01039 
01040 /* Decode JSON representation into pyhton objects */
01041 
01042 static PyObject *JSON_decode(PyObject *self, PyObject *args, PyObject *kwargs) {
01043     static char *kwlist[] = { "json", "all_unicode", NULL };
01044     int all_unicode = False; /* by default return unicode only when needed */
01045     PyObject *object, *string, *str;
01046     JSONData jsondata;
01047 
01048     if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:decode", kwlist, &string, &all_unicode))
01049         return NULL;
01050 
01051     if (PyUnicode_Check(string)) {
01052         str = PyUnicode_AsRawUnicodeEscapeString(string);
01053         if (str == NULL) {
01054             return NULL;
01055         }
01056     } else {
01057         Py_INCREF(string);
01058         str = string;
01059     }
01060 
01061     if (PyString_AsStringAndSize(str, &(jsondata.str), NULL) == -1) {
01062         Py_DECREF(str);
01063         return NULL; /* not a string object or it contains null bytes */
01064     }
01065 
01066     jsondata.ptr = jsondata.str;
01067     jsondata.end = jsondata.str+strlen(jsondata.str);
01068     jsondata.all_unicode = all_unicode;
01069 
01070     object = decode_json(&jsondata);
01071 
01072     if (object != NULL) {
01073         skipSpaces(&jsondata);
01074         if (jsondata.ptr < jsondata.end) {
01075             PyErr_Format(JSON_DecodeError, "extra data after JSON description at position "SSIZE_T_F, (Py_ssize_t)(jsondata.ptr-jsondata.str));
01076             Py_DECREF(str);
01077             Py_DECREF(object);
01078             return NULL;
01079         }
01080     }
01081 
01082     Py_DECREF(str);
01083 
01084     return object;
01085 }
01086 
01087 /* List of functions defined in the module */
01088 
01089 static PyMethodDef cjson_methods[] = {
01090     { "encode", (PyCFunction)JSON_encode,  METH_O,
01091     PyDoc_STR("encode(object) -> generate the JSON representation for object.") },
01092 
01093     { "decode", (PyCFunction)JSON_decode,  METH_VARARGS|METH_KEYWORDS,
01094     PyDoc_STR("decode(string, all_unicode=False) -> parse the JSON representation into\n"
01095               "python objects. The optional argument `all_unicode', specifies how to\n"
01096               "convert the strings in the JSON representation into python objects.\n"
01097               "If it is False (default), it will return strings everywhere possible\n"
01098               "and unicode objects only where necessary, else it will return unicode\n"
01099               "objects everywhere (this is slower).") },
01100 
01101     { NULL, NULL, 0, NULL }  /* sentinel */
01102 };
01103 
01104 PyDoc_STRVAR(module_doc, "Fast JSON encoder/decoder module.");
01105 
01106 /* Initialization function for the module (*must *be called initcjson) */
01107 #define MODULE_VERSION "1.0.5"
01108 PyMODINIT_FUNC initcjson(void) {
01109     PyObject *m;
01110 
01111     m = Py_InitModule3("cjson", cjson_methods, module_doc);
01112 
01113     if (m == NULL)
01114         return;
01115 
01116     JSON_Error = PyErr_NewException("cjson.Error", NULL, NULL);
01117     if (JSON_Error == NULL)
01118         return;
01119     Py_INCREF(JSON_Error);
01120     PyModule_AddObject(m, "Error", JSON_Error);
01121 
01122     JSON_EncodeError = PyErr_NewException("cjson.EncodeError", JSON_Error, NULL);
01123     if (JSON_EncodeError == NULL)
01124         return;
01125     Py_INCREF(JSON_EncodeError);
01126     PyModule_AddObject(m, "EncodeError", JSON_EncodeError);
01127 
01128     JSON_DecodeError = PyErr_NewException("cjson.DecodeError", JSON_Error, NULL);
01129     if (JSON_DecodeError == NULL)
01130         return;
01131     Py_INCREF(JSON_DecodeError);
01132     PyModule_AddObject(m, "DecodeError", JSON_DecodeError);
01133 
01134     /* Module version (the MODULE_VERSION macro is defined by setup.py) */
01135     PyModule_AddStringConstant(m, "__version__", MODULE_VERSION);
01136 }