Crossfire Server, Branch 1.12
R12190
|
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 }