Crossfire Server, Trunk  1.75.0
cjson.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2007 Dan Pascu.
3  * Author: Dan Pascu <dan@ag-projects.com>
4  *
5  * Fast JSON encoder/decoder implementation for Python
6  * This file is under GPL licence
7  */
8 
9 #include <cfpython.h>
10 #include <stddef.h>
11 #include <stdio.h>
12 #include <ctype.h>
13 #include <math.h>
14 
15 #ifdef IS_PY3K9
16 #pragma GCC diagnostic push
17 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
18 #pragma GCC diagnostic ignored "-Wcast-function-type"
19 #endif
20 
21 using namespace std;
22 
23 typedef struct JSONData {
24  char *str; /* the actual json string */
25  char *end; /* pointer to the string end */
26  char *ptr; /* pointer to the current parsing position */
27  int all_unicode; /* make all output strings unicode if true */
28 } JSONData;
29 
30 static PyObject *encode_object(PyObject *object);
31 static PyObject *encode_string(PyObject *object);
32 static PyObject *encode_unicode(PyObject *object);
33 static PyObject *encode_tuple(PyObject *object);
34 static PyObject *encode_list(PyObject *object);
35 static PyObject *encode_dict(PyObject *object);
36 
37 static PyObject *decode_json(JSONData *jsondata);
38 static PyObject *decode_null(JSONData *jsondata);
39 static PyObject *decode_bool(JSONData *jsondata);
40 static PyObject *decode_string(JSONData *jsondata);
41 static PyObject *decode_inf(JSONData *jsondata);
42 static PyObject *decode_nan(JSONData *jsondata);
43 static PyObject *decode_number(JSONData *jsondata);
44 static PyObject *decode_array(JSONData *jsondata);
45 static PyObject *decode_object(JSONData *jsondata);
46 
47 static PyObject *JSON_Error;
48 static PyObject *JSON_EncodeError;
49 static PyObject *JSON_DecodeError;
50 
51 #if PY_VERSION_HEX < 0x02050000
52 typedef int Py_ssize_t;
53 
54 #define PY_SSIZE_T_MAX INT_MAX
55 #define PY_SSIZE_T_MIN INT_MIN
56 
57 #define SSIZE_T_F "%d"
58 #else
59 #define SSIZE_T_F "%zd"
60 #endif
61 
62 #define True 1
63 #define False 0
64 
65 #ifndef INFINITY
66 #define INFINITY HUGE_VAL
67 #endif
68 
69 #ifndef NAN
70 #define NAN (HUGE_VAL-HUGE_VAL)
71 #endif
72 
73 #ifndef Py_IS_NAN
74 #define Py_IS_NAN(X) ((X) != (X))
75 #endif
76 
77 #define skipSpaces(d) while (*((d)->ptr) && isspace(*((d)->ptr))) (d)->ptr++
78 
79 /* ------------------------------ Utility ----------------------------- */
80 
82 static PyObject* cjson_PyObject_Str(PyObject* obj) {
83  PyObject *tmp_str, *result;
84  tmp_str = PyObject_Str(obj);
85  if (!tmp_str)
86  return NULL;
87  result = PyUnicode_AsUTF8String(tmp_str);
88  Py_DECREF(tmp_str);
89  return result;
90 }
91 
92 /* ------------------------------ Decoding ----------------------------- */
93 
94 static void getRowAndCol(char *begin, char *current, int *row, int *col) {
95  *col = 1;
96  *row = 1;
97  while (current > begin) {
98  if (*current == '\n')
99  (*row)++;
100  if (*row < 2)
101  (*col)++;
102  current--;
103  }
104 }
105 static PyObject *decode_null(JSONData *jsondata) {
106  ptrdiff_t left;
107 
108  left = jsondata->end-jsondata->ptr;
109 
110  if (left >= 4 && strncmp(jsondata->ptr, "null", 4) == 0) {
111  jsondata->ptr += 4;
112  Py_INCREF(Py_None);
113  return Py_None;
114  } else {
115  int row, col;
116 
117  getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
118  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);
119  return NULL;
120  }
121 }
122 
123 static PyObject *decode_bool(JSONData *jsondata) {
124  ptrdiff_t left;
125 
126  left = jsondata->end-jsondata->ptr;
127 
128  if (left >= 4 && strncmp(jsondata->ptr, "true", 4) == 0) {
129  jsondata->ptr += 4;
130  Py_INCREF(Py_True);
131  return Py_True;
132  } else if (left >= 5 && strncmp(jsondata->ptr, "false", 5) == 0) {
133  jsondata->ptr += 5;
134  Py_INCREF(Py_False);
135  return Py_False;
136  } else {
137  int row, col;
138 
139  getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
140  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);
141  return NULL;
142  }
143 }
144 
145 static PyObject *decode_string(JSONData *jsondata) {
146  PyObject *object;
147  int c, escaping, has_unicode, string_escape;
148  Py_ssize_t len;
149  char *ptr;
150 
151  /* look for the closing quote */
152  escaping = has_unicode = string_escape = False;
153  ptr = jsondata->ptr+1;
154  while (True) {
155  c = *ptr;
156  if (c == 0) {
157  int row, col;
158 
159  getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
160  PyErr_Format(JSON_DecodeError, "unterminated string starting at position " SSIZE_T_F "(row " SSIZE_T_F ", col " SSIZE_T_F ")",
161  (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
162  return NULL;
163  }
164  if (!escaping) {
165  if (c == '\\') {
166  escaping = True;
167  } else if (c == '"') {
168  break;
169  } else if (!isascii(c)) {
170  has_unicode = True;
171  }
172  } else {
173  switch (c) {
174  case 'u':
175  has_unicode = True;
176  break;
177  case '"':
178  case 'r':
179  case 'n':
180  case 't':
181  case 'b':
182  case 'f':
183  case '\\':
184  string_escape = True;
185  break;
186  }
187  escaping = False;
188  }
189  ptr++;
190  }
191 
192  len = ptr-jsondata->ptr-1;
193 
194  if (has_unicode || jsondata->all_unicode)
195  object = PyUnicode_DecodeUnicodeEscape(jsondata->ptr+1, len, NULL);
196  else if (string_escape)
197  object = PyBytes_DecodeEscape(jsondata->ptr+1, len, NULL, 0, NULL);
198  else
199  object = PyBytes_FromStringAndSize(jsondata->ptr+1, len);
200 
201  if (object == NULL) {
202  PyObject *type, *value, *tb, *reason;
203 
204  PyErr_Fetch(&type, &value, &tb);
205  if (type == NULL) {
206  int row, col;
207 
208  getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
209  PyErr_Format(JSON_DecodeError, "invalid string starting at position " SSIZE_T_F "(row " SSIZE_T_F ", col " SSIZE_T_F ")",
210  (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
211  } else {
212  if (PyErr_GivenExceptionMatches(type, PyExc_UnicodeDecodeError)) {
213  int row, col;
214 
215  reason = PyObject_GetAttrString(value, "reason");
216  /* If we are using Python3 we need to convert to bytes here. */
217  if (reason && PyUnicode_Check(reason)) {
218  PyObject * bytes_reason = PyUnicode_AsUTF8String(reason);
219  Py_DECREF(reason);
220  reason = bytes_reason;
221  }
222  getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
223  PyErr_Format(JSON_DecodeError, "cannot decode string starting" " at position " SSIZE_T_F "(row " SSIZE_T_F ", col " SSIZE_T_F "): %s",
224  (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col,
225  reason ? PyBytes_AsString(reason) : "bad format");
226  Py_XDECREF(reason);
227  } else {
228  int row, col;
229 
230  getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
231  PyErr_Format(JSON_DecodeError, "invalid string starting at position " SSIZE_T_F "(row " SSIZE_T_F ", col " SSIZE_T_F ")",
232  (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
233  }
234  }
235  Py_XDECREF(type);
236  Py_XDECREF(value);
237  Py_XDECREF(tb);
238  } else {
239  jsondata->ptr = ptr+1;
240  }
241 
242  return object;
243 }
244 
245 static PyObject *decode_inf(JSONData *jsondata) {
246  PyObject *object;
247  ptrdiff_t left;
248 
249  left = jsondata->end-jsondata->ptr;
250 
251  if (left >= 8 && strncmp(jsondata->ptr, "Infinity", 8) == 0) {
252  jsondata->ptr += 8;
253  object = PyFloat_FromDouble(INFINITY);
254  return object;
255  } else if (left >= 9 && strncmp(jsondata->ptr, "+Infinity", 9) == 0) {
256  jsondata->ptr += 9;
257  object = PyFloat_FromDouble(INFINITY);
258  return object;
259  } else if (left >= 9 && strncmp(jsondata->ptr, "-Infinity", 9) == 0) {
260  jsondata->ptr += 9;
261  object = PyFloat_FromDouble(-INFINITY);
262  return object;
263  } else {
264  int row, col;
265 
266  getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
267  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);
268  return NULL;
269  }
270 }
271 
272 static PyObject *decode_nan(JSONData *jsondata) {
273  PyObject *object;
274  ptrdiff_t left;
275 
276  left = jsondata->end-jsondata->ptr;
277 
278  if (left >= 3 && strncmp(jsondata->ptr, "NaN", 3) == 0) {
279  jsondata->ptr += 3;
280  object = PyFloat_FromDouble(NAN);
281  return object;
282  } else {
283  int row, col;
284  getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
285  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);
286  return NULL;
287  }
288 }
289 
290 static PyObject *decode_number(JSONData *jsondata) {
291  PyObject *object, *str;
292  int c, is_float, should_stop;
293  char *ptr;
294 
295  /* check if we got a floating point number */
296  ptr = jsondata->ptr;
297  is_float = should_stop = False;
298  while (True) {
299  c = *ptr;
300  if (c == 0)
301  break;
302  switch (c) {
303  case '0':
304  case '1':
305  case '2':
306  case '3':
307  case '4':
308  case '5':
309  case '6':
310  case '7':
311  case '8':
312  case '9':
313  case '-':
314  case '+':
315  break;
316 
317  case '.':
318  case 'e':
319  case 'E':
320  is_float = True;
321  break;
322 
323  default:
324  should_stop = True;
325  }
326  if (should_stop) {
327  break;
328  }
329  ptr++;
330  }
331 
332  str = PyBytes_FromStringAndSize(jsondata->ptr, ptr-jsondata->ptr);
333  if (str == NULL)
334  return NULL;
335 
336  if (is_float) {
337  object = PyFloat_FromString(str);
338  } else {
339  object = PyLong_FromString(PyBytes_AS_STRING(str), NULL, 10);
340  }
341 
342  Py_DECREF(str);
343 
344  if (object == NULL) {
345  int row, col;
346 
347  getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
348  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);
349  } else {
350  jsondata->ptr = ptr;
351  }
352 
353  return object;
354 }
355 
356 static PyObject *decode_array(JSONData *jsondata) {
357  PyObject *object, *item;
358  int c, expect_item, items, result;
359  char *start;
360 
361  object = PyList_New(0);
362 
363  start = jsondata->ptr;
364  jsondata->ptr++;
365  expect_item = True;
366  items = 0;
367  while (True) {
368  skipSpaces(jsondata);
369  c = *jsondata->ptr;
370  if (c == 0) {
371  int row, col;
372 
373  getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
374  PyErr_Format(JSON_DecodeError, "unterminated array starting at position " SSIZE_T_F "(row " SSIZE_T_F ", col " SSIZE_T_F ")",
375  (Py_ssize_t)(start-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
376  goto failure;
377  } else if (c == ']') {
378  if (expect_item && items > 0) {
379  int row, col;
380 
381  getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
382  PyErr_Format(JSON_DecodeError, "expecting array item at position " SSIZE_T_F "(row " SSIZE_T_F ", col " SSIZE_T_F ")",
383  (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
384  goto failure;
385  }
386  jsondata->ptr++;
387  break;
388  } else if (c == ',') {
389  if (expect_item) {
390  int row, col;
391 
392  getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
393  PyErr_Format(JSON_DecodeError, "expecting array item at position " SSIZE_T_F "(row " SSIZE_T_F ", col " SSIZE_T_F ")",
394  (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
395  goto failure;
396  }
397  expect_item = True;
398  jsondata->ptr++;
399  continue;
400  } else {
401  item = decode_json(jsondata);
402  if (item == NULL)
403  goto failure;
404  result = PyList_Append(object, item);
405  Py_DECREF(item);
406  if (result == -1)
407  goto failure;
408  expect_item = False;
409  items++;
410  }
411  }
412 
413  return object;
414 
415 failure:
416  Py_DECREF(object);
417  return NULL;
418 }
419 
420 static PyObject *decode_object(JSONData *jsondata) {
421  PyObject *object, *key, *value;
422  int c, expect_key, items, result;
423  char *start;
424 
425  object = PyDict_New();
426 
427  expect_key = True;
428  items = 0;
429  start = jsondata->ptr;
430  jsondata->ptr++;
431 
432  while (True) {
433  skipSpaces(jsondata);
434  c = *jsondata->ptr;
435  if (c == 0) {
436  int row, col;
437 
438  getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
439  PyErr_Format(JSON_DecodeError, "unterminated object starting at position " SSIZE_T_F "(row " SSIZE_T_F ", col " SSIZE_T_F ")",
440  (Py_ssize_t)(start-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
441  goto failure;
442  } else if (c == '}') {
443  if (expect_key && items > 0) {
444  int row, col;
445 
446  getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
447  PyErr_Format(JSON_DecodeError, "expecting object property name at position " SSIZE_T_F "(row " SSIZE_T_F ", col " SSIZE_T_F ")",
448  (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
449  goto failure;
450  }
451  jsondata->ptr++;
452  break;
453  } else if (c == ',') {
454  if (expect_key) {
455  int row, col;
456 
457  getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
458  PyErr_Format(JSON_DecodeError, "expecting object property name at position " SSIZE_T_F "(row " SSIZE_T_F ", col " SSIZE_T_F ")",
459  (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
460  goto failure;
461  }
462  expect_key = True;
463  jsondata->ptr++;
464  continue;
465  } else {
466  if (c != '"') {
467  int row, col;
468 
469  getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
470  PyErr_Format(JSON_DecodeError, "expecting property name in object at position " SSIZE_T_F "(row " SSIZE_T_F ", col " SSIZE_T_F ")",
471  (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
472  goto failure;
473  }
474 
475  key = decode_json(jsondata);
476  if (key == NULL)
477  goto failure;
478 
479  skipSpaces(jsondata);
480  if (*jsondata->ptr != ':') {
481  int row, col;
482 
483  getRowAndCol(jsondata->str, jsondata->ptr, &row, &col);
484  PyErr_Format(JSON_DecodeError, "missing colon after object property name at position " SSIZE_T_F "(row " SSIZE_T_F ", col " SSIZE_T_F ")",
485  (Py_ssize_t)(jsondata->ptr-jsondata->str), (Py_ssize_t)row, (Py_ssize_t)col);
486  Py_DECREF(key);
487  goto failure;
488  } else {
489  jsondata->ptr++;
490  }
491 
492  value = decode_json(jsondata);
493  if (value == NULL) {
494  Py_DECREF(key);
495  goto failure;
496  }
497 
498  result = PyDict_SetItem(object, key, value);
499  Py_DECREF(key);
500  Py_DECREF(value);
501  if (result == -1)
502  goto failure;
503  expect_key = False;
504  items++;
505  }
506  }
507 
508  return object;
509 
510 failure:
511  Py_DECREF(object);
512  return NULL;
513 }
514 
515 static PyObject *decode_json(JSONData *jsondata) {
516  PyObject *object;
517 
518  skipSpaces(jsondata);
519  switch (*jsondata->ptr) {
520  case 0:
521  PyErr_SetString(JSON_DecodeError, "empty JSON description");
522  return NULL;
523 
524  case '{':
525  object = decode_object(jsondata);
526  break;
527 
528  case '[':
529  object = decode_array(jsondata);
530  break;
531 
532  case '"':
533  object = decode_string(jsondata);
534  break;
535 
536  case 't':
537  case 'f':
538  object = decode_bool(jsondata);
539  break;
540 
541  case 'n':
542  object = decode_null(jsondata);
543  break;
544 
545  case 'N':
546  object = decode_nan(jsondata);
547  break;
548 
549  case 'I':
550  object = decode_inf(jsondata);
551  break;
552 
553  case '+':
554  case '-':
555  if (*(jsondata->ptr+1) == 'I') {
556  object = decode_inf(jsondata);
557  } else {
558  object = decode_number(jsondata);
559  }
560  break;
561 
562  case '0':
563  case '1':
564  case '2':
565  case '3':
566  case '4':
567  case '5':
568  case '6':
569  case '7':
570  case '8':
571  case '9':
572  object = decode_number(jsondata);
573  break;
574 
575  default:
576  PyErr_SetString(JSON_DecodeError, "cannot parse JSON description");
577  return NULL;
578  }
579 
580  return object;
581 }
582 
583 /* ------------------------------ Encoding ----------------------------- */
584 
585 /*
586  * This function is an almost verbatim copy of PyString_Repr() from
587  * Python's stringobject.c with the following differences:
588  *
589  * - it always quotes the output using double quotes.
590  * - it also quotes \b and \f
591  * - it replaces any non ASCII character hh with \u00hh instead of \xhh
592  */
593 static PyObject *encode_string(PyObject *string) {
594  PyBytesObject *op = (PyBytesObject *)string;
595  size_t newsize = 2+6*Py_SIZE(op);
596  PyObject *v;
597 
598  if (Py_SIZE(op) > (PY_SSIZE_T_MAX-2)/6) {
599  PyErr_SetString(PyExc_OverflowError, "string is too large to make repr");
600  return NULL;
601  }
602  v = PyBytes_FromStringAndSize((char *)NULL, newsize);
603  if (v == NULL) {
604  return NULL;
605  } else {
606  Py_ssize_t i;
607  char c;
608  char *p;
609  int quote;
610 
611  quote = '"';
612 
613  p = PyBytes_AS_STRING(v);
614  *p++ = quote;
615  for (i = 0; i < Py_SIZE(op); i++) {
616  /* There's at least enough room for a hex escape
617  and a closing quote. */
618  assert(newsize-(p-PyBytes_AS_STRING(v)) >= 7);
619  c = op->ob_sval[i];
620  if (c == quote || c == '\\')
621  *p++ = '\\', *p++ = c;
622  else if (c == '\t')
623  *p++ = '\\', *p++ = 't';
624  else if (c == '\n')
625  *p++ = '\\', *p++ = 'n';
626  else if (c == '\r')
627  *p++ = '\\', *p++ = 'r';
628  else if (c == '\f')
629  *p++ = '\\', *p++ = 'f';
630  else if (c == '\b')
631  *p++ = '\\', *p++ = 'b';
632  else if (c < ' ' || c >= 0x7f) {
633  /* For performance, we don't want to call
634  * PyOS_snprintf here (extra layers of
635  * function call). */
636  sprintf(p, "\\u%04x", c&0xff);
637  p += 6;
638  }
639  else
640  *p++ = c;
641  }
642  assert(newsize-(p-PyBytes_AS_STRING(v)) >= 1);
643  *p++ = quote;
644  *p = '\0';
645  _PyBytes_Resize(&v, (int) (p-PyBytes_AS_STRING(v)));
646  return v;
647  }
648 }
649 
650 /*
651  * This function is an almost verbatim copy of unicodeescape_string() from
652  * Python's unicodeobject.c with the following differences:
653  *
654  * - it always quotes the output using double quotes.
655  * - it uses \u00hh instead of \xhh in output.
656  * - it also quotes \b and \f
657  */
658 static PyObject *encode_unicode(PyObject *unicode) {
659  PyObject *repr;
660  Py_ssize_t size, pos;
661  char *p;
662  static const char *hexdigit = "0123456789abcdef";
663  static const Py_ssize_t expandsize = 10;
664 
665  int kind = PyUnicode_KIND(unicode);
666  void *data = PyUnicode_DATA(unicode);
667  size = PyUnicode_GET_LENGTH(unicode);
668 
669  if (size > (PY_SSIZE_T_MAX-2-1)/expandsize) {
670  PyErr_SetString(PyExc_OverflowError, "unicode object is too large to make repr");
671  return NULL;
672  }
673 
674  repr = PyByteArray_FromStringAndSize(NULL,
675  2
676  + expandsize*size
677  + 1);
678  if (repr == NULL)
679  return NULL;
680 
681  p = PyByteArray_AS_STRING(repr);
682 
683  *p++ = '"';
684  pos = 0;
685 
686  const Py_UCS4 quote = PyByteArray_AS_STRING(repr)[0];
687 
688  while (pos < size) {
689  Py_UCS4 ch = PyUnicode_READ(kind, data, pos);
690  pos++;
691 
692  /* Escape quotes */
693  if ((ch == quote || ch == '\\')) {
694  *p++ = '\\';
695  *p++ = (char)ch;
696  continue;
697  }
698 
699  /* Map 21-bit characters to '\U00xxxxxx' */
700  else if (ch >= 0x10000) {
701  *p++ = '\\';
702  *p++ = 'U';
703  *p++ = hexdigit[(ch>>28)&0x0000000F];
704  *p++ = hexdigit[(ch>>24)&0x0000000F];
705  *p++ = hexdigit[(ch>>20)&0x0000000F];
706  *p++ = hexdigit[(ch>>16)&0x0000000F];
707  *p++ = hexdigit[(ch>>12)&0x0000000F];
708  *p++ = hexdigit[(ch>>8)&0x0000000F];
709  *p++ = hexdigit[(ch>>4)&0x0000000F];
710  *p++ = hexdigit[ch&0x0000000F];
711  continue;
712  }
713  /* Map 16-bit characters to '\uxxxx' */
714  if (ch >= 256) {
715  *p++ = '\\';
716  *p++ = 'u';
717  *p++ = hexdigit[(ch>>12)&0x000F];
718  *p++ = hexdigit[(ch>>8)&0x000F];
719  *p++ = hexdigit[(ch>>4)&0x000F];
720  *p++ = hexdigit[ch&0x000F];
721  /* Map special whitespace to '\t', \n', '\r', '\f', '\b' */
722  } else if (ch == '\t') {
723  *p++ = '\\';
724  *p++ = 't';
725  } else if (ch == '\n') {
726  *p++ = '\\';
727  *p++ = 'n';
728  } else if (ch == '\r') {
729  *p++ = '\\';
730  *p++ = 'r';
731  } else if (ch == '\f') {
732  *p++ = '\\';
733  *p++ = 'f';
734  } else if (ch == '\b') {
735  *p++ = '\\';
736  *p++ = 'b';
737  }
738 
739  /* Map non-printable US ASCII to '\u00hh' */
740  else if (ch < ' ' || ch >= 0x7F) {
741  *p++ = '\\';
742  *p++ = 'u';
743  *p++ = '0';
744  *p++ = '0';
745  *p++ = hexdigit[(ch>>4)&0x000F];
746  *p++ = hexdigit[ch&0x000F];
747  }
748 
749  /* Copy everything else as-is */
750  else
751  *p++ = (char)ch;
752  }
753 
754  *p++ = PyByteArray_AS_STRING(repr)[0];
755 
756  *p = '\0';
757  {
758  PyObject *result = PyBytes_FromStringAndSize(PyByteArray_AS_STRING(repr),
759  p - PyByteArray_AS_STRING(repr));
760  Py_DECREF(repr);
761  return result;
762  }
763 }
764 
765 /*
766  * This function is an almost verbatim copy of tuplerepr() from
767  * Python's tupleobject.c with the following differences:
768  *
769  * - it uses encode_object() to get the object's JSON reprezentation.
770  * - it uses [] as decorations isntead of () (to masquerade as a JSON array).
771  */
772 
773 static PyObject *encode_tuple(PyObject *tuple) {
774  Py_ssize_t i, n;
775  PyObject *s, *temp;
776  PyObject *pieces, *result = NULL;
777  PyTupleObject *v = (PyTupleObject *)tuple;
778 
779  n = Py_SIZE(v);
780  if (n == 0)
781  return PyBytes_FromString("[]");
782 
783  pieces = PyTuple_New(n);
784  if (pieces == NULL)
785  return NULL;
786 
787  /* Do repr() on each element. */
788  for (i = 0; i < n; ++i) {
789  s = encode_object(v->ob_item[i]);
790  if (s == NULL)
791  goto Done;
792  PyTuple_SET_ITEM(pieces, i, s);
793  }
794 
795  /* Add "[]" decorations to the first and last items. */
796  assert(n > 0);
797  s = PyBytes_FromString("[");
798  if (s == NULL)
799  goto Done;
800  temp = PyTuple_GET_ITEM(pieces, 0);
801  PyBytes_ConcatAndDel(&s, temp);
802  PyTuple_SET_ITEM(pieces, 0, s);
803  if (s == NULL)
804  goto Done;
805 
806  s = PyBytes_FromString("]");
807  if (s == NULL)
808  goto Done;
809  temp = PyTuple_GET_ITEM(pieces, n-1);
810  PyBytes_ConcatAndDel(&temp, s);
811  PyTuple_SET_ITEM(pieces, n-1, temp);
812  if (temp == NULL)
813  goto Done;
814 
815  /* Paste them all together with ", " between. */
816  s = PyBytes_FromString(", ");
817  if (s == NULL)
818  goto Done;
819  result = _PyBytes_Join(s, pieces);
820  Py_DECREF(s);
821 
822 Done:
823  Py_DECREF(pieces);
824  return result;
825 }
826 
827 /*
828  * This function is an almost verbatim copy of list_repr() from
829  * Python's listobject.c with the following differences:
830  *
831  * - it uses encode_object() to get the object's JSON reprezentation.
832  * - it doesn't use the ellipsis to represent a list with references
833  * to itself, instead it raises an exception as such lists cannot be
834  * represented in JSON.
835  */
836 static PyObject *encode_list(PyObject *list) {
837  Py_ssize_t i;
838  PyObject *s, *temp;
839  PyObject *pieces = NULL, *result = NULL;
840  PyListObject *v = (PyListObject *)list;
841 
842  i = Py_ReprEnter((PyObject *)v);
843  if (i != 0) {
844  if (i > 0) {
845  PyErr_SetString(JSON_EncodeError, "a list with references to itself is not JSON encodable");
846  }
847  return NULL;
848  }
849 
850  if (Py_SIZE(v) == 0) {
851  result = PyBytes_FromString("[]");
852  goto Done;
853  }
854 
855  pieces = PyList_New(0);
856  if (pieces == NULL)
857  goto Done;
858 
859  /* Do repr() on each element. Note that this may mutate the list,
860  * so must refetch the list size on each iteration. */
861  for (i = 0; i < Py_SIZE(v); ++i) {
862  int status;
863  s = encode_object(v->ob_item[i]);
864  if (s == NULL)
865  goto Done;
866  status = PyList_Append(pieces, s);
867  Py_DECREF(s); /* append created a new ref */
868  if (status < 0)
869  goto Done;
870  }
871 
872  /* Add "[]" decorations to the first and last items. */
873  assert(PyList_GET_SIZE(pieces) > 0);
874  s = PyBytes_FromString("[");
875  if (s == NULL)
876  goto Done;
877  temp = PyList_GET_ITEM(pieces, 0);
878  PyBytes_ConcatAndDel(&s, temp);
879  PyList_SET_ITEM(pieces, 0, s);
880  if (s == NULL)
881  goto Done;
882 
883  s = PyBytes_FromString("]");
884  if (s == NULL)
885  goto Done;
886  temp = PyList_GET_ITEM(pieces, PyList_GET_SIZE(pieces)-1);
887  PyBytes_ConcatAndDel(&temp, s);
888  PyList_SET_ITEM(pieces, PyList_GET_SIZE(pieces)-1, temp);
889  if (temp == NULL)
890  goto Done;
891 
892  /* Paste them all together with ", " between. */
893  s = PyBytes_FromString(", ");
894  if (s == NULL)
895  goto Done;
896  result = _PyBytes_Join(s, pieces);
897  Py_DECREF(s);
898 
899 Done:
900  Py_XDECREF(pieces);
901  Py_ReprLeave((PyObject *)v);
902  return result;
903 }
904 
905 /*
906  * This function is an almost verbatim copy of dict_repr() from
907  * Python's dictobject.c with the following differences:
908  *
909  * - it uses encode_object() to get the object's JSON reprezentation.
910  * - only accept strings for keys.
911  * - it doesn't use the ellipsis to represent a dictionary with references
912  * to itself, instead it raises an exception as such dictionaries cannot
913  * be represented in JSON.
914  */
915 static PyObject *encode_dict(PyObject *dict) {
916  Py_ssize_t i;
917  PyObject *s, *temp, *colon = NULL;
918  PyObject *pieces = NULL, *result = NULL;
919  PyObject *key, *value;
920  PyDictObject *mp = (PyDictObject *)dict;
921 
922  i = Py_ReprEnter((PyObject *)mp);
923  if (i != 0) {
924  if (i > 0) {
925  PyErr_SetString(JSON_EncodeError, "a dict with references to "
926  "itself is not JSON encodable");
927  }
928  return NULL;
929  }
930 
931  if (mp->ma_used == 0) {
932  result = PyBytes_FromString("{}");
933  goto Done;
934  }
935 
936  pieces = PyList_New(0);
937  if (pieces == NULL)
938  goto Done;
939 
940  colon = PyBytes_FromString(": ");
941  if (colon == NULL)
942  goto Done;
943 
944  /* Do repr() on each key+value pair, and insert ": " between them.
945  * Note that repr may mutate the dict. */
946  i = 0;
947  while (PyDict_Next((PyObject *)mp, &i, &key, &value)) {
948  int status;
949 
950  if (!PyBytes_Check(key) && !PyUnicode_Check(key)) {
951  PyErr_SetString(JSON_EncodeError, "JSON encodable dictionaries must have string/unicode keys");
952  goto Done;
953  }
954 
955  /* Prevent repr from deleting value during key format. */
956  Py_INCREF(value);
957  s = encode_object(key);
958  PyBytes_Concat(&s, colon);
959  PyBytes_ConcatAndDel(&s, encode_object(value));
960  Py_DECREF(value);
961  if (s == NULL)
962  goto Done;
963  status = PyList_Append(pieces, s);
964  Py_DECREF(s); /* append created a new ref */
965  if (status < 0)
966  goto Done;
967  }
968 
969  /* Add "{}" decorations to the first and last items. */
970  assert(PyList_GET_SIZE(pieces) > 0);
971  s = PyBytes_FromString("{");
972  if (s == NULL)
973  goto Done;
974  temp = PyList_GET_ITEM(pieces, 0);
975  PyBytes_ConcatAndDel(&s, temp);
976  PyList_SET_ITEM(pieces, 0, s);
977  if (s == NULL)
978  goto Done;
979 
980  s = PyBytes_FromString("}");
981  if (s == NULL)
982  goto Done;
983  temp = PyList_GET_ITEM(pieces, PyList_GET_SIZE(pieces)-1);
984  PyBytes_ConcatAndDel(&temp, s);
985  PyList_SET_ITEM(pieces, PyList_GET_SIZE(pieces)-1, temp);
986  if (temp == NULL)
987  goto Done;
988 
989  /* Paste them all together with ", " between. */
990  s = PyBytes_FromString(", ");
991  if (s == NULL)
992  goto Done;
993  result = _PyBytes_Join(s, pieces);
994  Py_DECREF(s);
995 
996 Done:
997  Py_XDECREF(pieces);
998  Py_XDECREF(colon);
999  Py_ReprLeave((PyObject *)mp);
1000  return result;
1001 }
1002 
1003 static PyObject *encode_object(PyObject *object) {
1004  if (object == Py_True) {
1005  return PyBytes_FromString("true");
1006  } else if (object == Py_False) {
1007  return PyBytes_FromString("false");
1008  } else if (object == Py_None) {
1009  return PyBytes_FromString("null");
1010  } else if (PyBytes_Check(object)) {
1011  return encode_string(object);
1012  } else if (PyUnicode_Check(object)) {
1013  return encode_unicode(object);
1014  } else if (PyFloat_Check(object)) {
1015  double val = PyFloat_AS_DOUBLE(object);
1016  if (Py_IS_NAN(val)) {
1017  return PyBytes_FromString("NaN");
1018  } else if (Py_IS_INFINITY(val)) {
1019  if (val > 0) {
1020  return PyBytes_FromString("Infinity");
1021  } else {
1022  return PyBytes_FromString("-Infinity");
1023  }
1024  } else {
1025  return cjson_PyObject_Str(object);
1026  }
1027  }
1028  else if (PyLong_Check(object)) {
1029  return cjson_PyObject_Str(object);
1030  }
1031  else if (PyList_Check(object)) {
1032  return encode_list(object);
1033  } else if (PyTuple_Check(object)) {
1034  return encode_tuple(object);
1035  } else if (PyDict_Check(object)) { /* use PyMapping_Check(object) instead? -Dan */
1036  return encode_dict(object);
1037  } else {
1038  PyErr_SetString(JSON_EncodeError, "object is not JSON encodable");
1039  return NULL;
1040  }
1041 }
1042 
1043 /* Encode object into its JSON representation */
1044 
1045 static PyObject *JSON_encode(PyObject *self, PyObject *object) {
1046  (void)self;
1047  return encode_object(object);
1048 }
1049 
1050 /* Decode JSON representation into pyhton objects */
1051 
1052 static PyObject *JSON_decode(PyObject *self, PyObject *args, PyObject *kwargs) {
1053  static char *kwlist[] = { (char*)"json", (char*)"all_unicode", NULL };
1054  int all_unicode = True; /* by default return unicode always */
1055  PyObject *object, *string, *str;
1056  JSONData jsondata;
1057  (void)self;
1058 
1059  if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|i:decode", kwlist, &string, &all_unicode))
1060  return NULL;
1061 
1062  if (PyUnicode_Check(string)) {
1063  // PyUnicode_EncodeRawUnicodeEscape() is deprecated as of Python 3.3, scheduled for removal in Python 3.11
1064 #ifndef IS_PY3K3
1065  /* HACK: Workaround for crash bug in Python3's PyUnicode_AsRawUnicodeEscapeString... */
1066  str = PyUnicode_EncodeRawUnicodeEscape(PyUnicode_AS_UNICODE(string),
1067  PyUnicode_GET_SIZE(string));
1068 #else
1069  // The Python docs recommend using PyUnicode_AsRawUnicodeEscapeString() or PyUnicode_AsEncodedString() over PyUnicode_EncodeRawUnicodeEscape().
1070  str = PyUnicode_AsRawUnicodeEscapeString(string);
1071 #endif
1072  if (str == NULL) {
1073  return NULL;
1074  }
1075  } else {
1076  Py_INCREF(string);
1077  str = string;
1078  }
1079 
1080  if (PyBytes_AsStringAndSize(str, &(jsondata.str), NULL) == -1) {
1081  Py_DECREF(str);
1082  return NULL; /* not a string object or it contains null bytes */
1083  }
1084 
1085  jsondata.ptr = jsondata.str;
1086  jsondata.end = jsondata.str+strlen(jsondata.str);
1087  jsondata.all_unicode = all_unicode;
1088 
1089  object = decode_json(&jsondata);
1090 
1091  if (object != NULL) {
1092  skipSpaces(&jsondata);
1093  if (jsondata.ptr < jsondata.end) {
1094  PyErr_Format(JSON_DecodeError, "extra data after JSON description at position " SSIZE_T_F, (Py_ssize_t)(jsondata.ptr-jsondata.str));
1095  Py_DECREF(str);
1096  Py_DECREF(object);
1097  return NULL;
1098  }
1099  }
1100 
1101  Py_DECREF(str);
1102 
1103  return object;
1104 }
1105 
1106 /* List of functions defined in the module */
1107 
1108 static PyMethodDef cjson_methods[] = {
1109  { "encode", (PyCFunction)JSON_encode, METH_O,
1110  PyDoc_STR("encode(object) -> generate the JSON representation for object.") },
1111 
1112 /* On Python 3.x we normally want Unicode. */
1113  { "decode", (PyCFunction)JSON_decode, METH_VARARGS|METH_KEYWORDS,
1114  PyDoc_STR("decode(string, all_unicode=True) -> parse the JSON representation into\n"
1115  "python objects. The optional argument `all_unicode', specifies how to\n"
1116  "convert the strings in the JSON representation into python objects.\n"
1117  "If it is False (default on Python 2.x), it will return strings/bytes\n"
1118  "everywhere possible and unicode objects only where necessary, else\n"
1119  "it will return unicode objects everywhere (this is slower, but default\n"
1120  "on Python 3.x).")
1121  },
1122  { NULL, NULL, 0, NULL } /* sentinel */
1123 };
1124 
1125 PyDoc_STRVAR(module_doc, "Fast JSON encoder/decoder module.");
1126 
1127 #define MODULE_VERSION "1.0.5"
1128 
1129 static void initcjson_shared(PyObject *m) {
1130  JSON_Error = PyErr_NewException("cjson.Error", NULL, NULL);
1131  if (JSON_Error == NULL)
1132  return;
1133  Py_INCREF(JSON_Error);
1134  PyModule_AddObject(m, "Error", JSON_Error);
1135 
1136  JSON_EncodeError = PyErr_NewException("cjson.EncodeError", JSON_Error, NULL);
1137  if (JSON_EncodeError == NULL)
1138  return;
1139  Py_INCREF(JSON_EncodeError);
1140  PyModule_AddObject(m, "EncodeError", JSON_EncodeError);
1141 
1142  JSON_DecodeError = PyErr_NewException("cjson.DecodeError", JSON_Error, NULL);
1143  if (JSON_DecodeError == NULL)
1144  return;
1145  Py_INCREF(JSON_DecodeError);
1146  PyModule_AddObject(m, "DecodeError", JSON_DecodeError);
1147 
1148  /* Module version (the MODULE_VERSION macro is defined by setup.py) */
1149  PyModule_AddStringConstant(m, "__version__", MODULE_VERSION);
1150 }
1151 
1152 
1153 static PyModuleDef cjsonModule = {
1154  PyModuleDef_HEAD_INIT,
1155  "cjson", /* m_name */
1156  module_doc, /* m_doc */
1157  -1, /* m_size */
1158  cjson_methods, /* m_methods */
1159  NULL, /* m_reload */
1160  NULL, /* m_traverse */
1161  NULL, /* m_clear */
1162  NULL /* m_free */
1163 };
1164 
1165 PyObject* PyInit_cjson(void)
1166 {
1167  PyObject *m;
1168 
1169  m = PyModule_Create(&cjsonModule);
1170 
1171  if (m == NULL)
1172  return NULL;
1173 
1175 
1176  return m;
1177 }
1178 
1179 #ifdef IS_PY3K9
1180 #pragma GCC diagnostic pop
1181 #endif
MODULE_VERSION
#define MODULE_VERSION
Definition: cjson.cpp:1127
PY_SSIZE_T_MAX
#define PY_SSIZE_T_MAX
Definition: cjson.cpp:54
object
Main Crossfire structure, one ingame object.
Definition: object.h:282
getRowAndCol
static void getRowAndCol(char *begin, char *current, int *row, int *col)
Definition: cjson.cpp:94
encode_object
static PyObject * encode_object(PyObject *object)
Definition: cjson.cpp:1003
PyInit_cjson
PyObject * PyInit_cjson(void)
Definition: cjson.cpp:1165
Py_ssize_t
int Py_ssize_t
Definition: cjson.cpp:52
JSON_Error
static PyObject * JSON_Error
Definition: cjson.cpp:47
JSONData
Definition: cjson.cpp:23
quote
TIPS on SURVIVING Crossfire is populated with a wealth of different monsters These monsters can have varying immunities and attack types In some of them can be quite a bit smarter than others It will be important for new players to learn the abilities of different monsters and learn just how much it will take to kill them This section discusses how monsters can interact with players Most monsters in the game are out to mindlessly kill and destroy the players These monsters will help boost a player s after he kills them When fighting a large amount of monsters in a single attempt to find a narrower hallway so that you are not being attacked from all sides Charging into a room full of Beholders for instance would not be open the door and fight them one at a time For there are several maps designed for them Find these areas and clear them out All throughout these a player can find signs and books which they can read by stepping onto them and hitting A to apply the book sign These messages will help the player to learn the system One more always keep an eye on your food If your food drops to your character will soon so BE CAREFUL ! NPCs Non Player Character are special monsters which have intelligence Players may be able to interact with these monsters to help solve puzzles and find items of interest To speak with a monster you suspect to be a simply move to an adjacent square to them and push the double quote
Definition: survival-guide.txt:34
c
static event_registration c
Definition: citylife.cpp:422
SSIZE_T_F
#define SSIZE_T_F
Definition: cjson.cpp:57
JSON_decode
static PyObject * JSON_decode(PyObject *self, PyObject *args, PyObject *kwargs)
Definition: cjson.cpp:1052
skipSpaces
#define skipSpaces(d)
Definition: cjson.cpp:77
JSONData::ptr
char * ptr
Definition: cjson.cpp:26
encode_list
static PyObject * encode_list(PyObject *object)
Definition: cjson.cpp:836
decode_nan
static PyObject * decode_nan(JSONData *jsondata)
Definition: cjson.cpp:272
decode_inf
static PyObject * decode_inf(JSONData *jsondata)
Definition: cjson.cpp:245
cjson_methods
static PyMethodDef cjson_methods[]
Definition: cjson.cpp:1108
m
static event_registration m
Definition: citylife.cpp:422
JSON_EncodeError
static PyObject * JSON_EncodeError
Definition: cjson.cpp:48
decode_string
static PyObject * decode_string(JSONData *jsondata)
Definition: cjson.cpp:145
NAN
#define NAN
Definition: cjson.cpp:70
JSON_encode
static PyObject * JSON_encode(PyObject *self, PyObject *object)
Definition: cjson.cpp:1045
False
#define False
Definition: cjson.cpp:63
JSONData::all_unicode
int all_unicode
Definition: cjson.cpp:27
cfpython.h
PyDoc_STRVAR
PyDoc_STRVAR(module_doc, "Fast JSON encoder/decoder module.")
cjson_PyObject_Str
static PyObject * cjson_PyObject_Str(PyObject *obj)
Same as PyObject_Str but return a UTF-8 encoded Bytes object instead.
Definition: cjson.cpp:82
decode_array
static PyObject * decode_array(JSONData *jsondata)
Definition: cjson.cpp:356
JSON_DecodeError
static PyObject * JSON_DecodeError
Definition: cjson.cpp:49
JSONData
struct JSONData JSONData
decode_object
static PyObject * decode_object(JSONData *jsondata)
Definition: cjson.cpp:420
encode_dict
static PyObject * encode_dict(PyObject *object)
Definition: cjson.cpp:915
decode_number
static PyObject * decode_number(JSONData *jsondata)
Definition: cjson.cpp:290
decode_null
static PyObject * decode_null(JSONData *jsondata)
Definition: cjson.cpp:105
encode_tuple
static PyObject * encode_tuple(PyObject *object)
Definition: cjson.cpp:773
JSONData::str
char * str
Definition: cjson.cpp:24
INFINITY
#define INFINITY
Definition: cjson.cpp:66
True
#define True
Definition: cjson.cpp:62
data
====Textual A command containing textual data has data fields separated by one ASCII space character. word::A sequence of ASCII characters that does not contain the space or nul character. This is to distinguish it from the _string_, which may contain space characters. Not to be confused with a machine word. int::A _word_ containing the textual representation of an integer. Not to be confused with any of the binary integers in the following section. Otherwise known as the "string value of integer data". Must be parsed, e.g. using `atoi()` to get the actual integer value. string::A sequence of ASCII characters. This must only appear at the end of a command, since spaces are used to separate fields of a textual message.=====Binary All multi-byte integers are transmitted in network byte order(MSB first). int8::1-byte(8-bit) integer int16::2-byte(16-bit) integer int32::4-byte(32-bit) integer lstring::A length-prefixed string, which consists of an `int8` followed by that many bytes of the actual string. This is used to transmit a string(that may contain spaces) in the middle of binary data. l2string::Like _lstring_, but is prefixed with an `int16` to support longer strings Implementation Notes ~~~~~~~~~~~~~~~~~~~~ - Typical implementations read two bytes to determine the length of the subsequent read for the actual message, then read and parse the data from each message according to the commands described below. To send a message, the sender builds the message in a buffer, counts the length of the message, sends the length, and finally sends the actual message. TIP:Incorrectly transmitting or receiving the `length` field can lead to apparent "no response" issues as the client or server blocks to read the entire length of the message. - Since the protocol is highly interactive, it may be useful to set `TCP_NODELAY` on both the client and server. - If you are using a language with a buffered output stream, remember to flush the stream after a complete message. - If the connection is lost(which will also happen if the output buffer overflowing), the player is saved and the server cleans up. This does open up some abuses, but there is no perfect solution here. - The server only reads data from the socket if the player has an action. This isn 't really good, since many of the commands below might not be actual commands for the player. The alternative is to look at the data, and if it is a player command and there isn 't time, store it away to be processed later. But this increases complexity, in that the server must start buffering the commands. Fortunately, for now, there are few such client commands. Commands -------- In the documentation below, `S->C` represents a message to the client from the server, and `C->S` represents a message to the server from the client. Commands are documented in a brief format like:C->S:version< csval >[scval[vinfo]] Fields are enclosed like `< this >`. Optional fields are denoted like `[this]`. Spaces that appear in the command are literal, i.e. the<< _version > > command above uses spaces to separate its fields, but the command below does not:C->S:accountlogin< name >< password > As described in<< _messages > >, if a command contains data, then the command is separated from the data by a literal space. Many of the commands below refer to 'object tags'. Whenever the server creates an object, it creates a unique tag for that object(starting at 1 when the server is first run, and ever increasing.) Tags are unique, but are not consistent between runs. Thus, the client can not store tags when it exits and hope to re-use them when it joins the server at a later time - tags are only valid for the current connection. The protocol commands are broken into various sections which based somewhat on what the commands are for(ie, item related commands, map commands, image commands, etc.) In this way, all the commands related to similar functionality is in the same place. Initialization ~~~~~~~~~~~~~~ version ^^^^^^^ C->S:version< csval >[scval[vinfo]] S->C:version< csval >[scval[vinfo]] Used by the client and server to exchange which version of the Crossfire protocol they understand. Neither send this in response to the other - they should both send this shortly after a connection is established. csval::int, version level of C->S communications scval::int, version level of S->C communications vinfo::string, that is purely for informative that general client/server info(ie, javaclient, x11client, winclient, sinix server, etc). It is purely of interest of server admins who can see what type of clients people are using.=====Version ID If a new command is added to the protocol in the C->S direction, then the version number in csval will get increased. Likewise, the same is true for the scval. The version are currently integers, in the form ABCD. A=1, and will likely for quite a while. This will only really change if needed from rollover of B. B represents major protocol changes - if B mismatches, the clients will be totally unusable. Such an example would be change of map or item sending commands(either new commands or new format.) C represents more minor but still significant changes - clients might still work together, but some features that used to work may now fail due to the mismatch. An example may be a change in the meaning of some field in some command - providing the field is the same size, it still should be decoded properly, but the meaning won 't be processed properly. D represents very minor changes or new commands. Things should work no worse if D does not match, however if they do match, some new features might be included. An example of the would be the C->S mark command to mark items. Server not understanding this just means that the server can not process it, and will ignore it.=====Handling As far as the client is concerned, its _scval_ must be at least equal to the server, and its _csval_ should not be newer than the server. The server does not care about the version command it receives right now - all it currently does is log mismatches. In theory, the server should keep track of what the client has, and adjust the commands it sends respectively in the S->C direction. The server is resilant enough that it won 't crash with a version mismatch(however, client may end up sending commands that the server just ignores). It is really up to the client to enforce versioning and quit if the versions don 't match. NOTE:Since all packets have the length as the first 2 bytes, all that either the client or server needs to be able to do is look at the first string and see if it understands it. If not, it knows how many bytes it can skip. As such, exact version matches should not be necessary for proper operation - however, both the client and server needs to be coded to handle such cases.=====History _scval_ and _vinfo_ were added in version 1020. Before then, there was only one version sent in the version command. NOTE:For the most part, this has been obsoleted by the setup command which always return status and whether it understood the command or not. However there are still some cases where using this versioning is useful - an example it the addition of the requestinfo/replyinfo commands - the client wants to wait for acknowledge of all the replyinfo commands it has issued before sending the addme command. However, if the server doesn 't understand these options, the client will never get a response. With the versioning, the client can look at the version and know if it should wait for a response or if the server will never send back. setup ^^^^^ C->S, S->C:setup< option1 >< value1 >< option2 >< value2 > ... Sent by the client to request protocol option changes. This can be at any point during the life of a connection, but usually sent at least once right after the<< _version > > command. The server responds with a message in the same format confirming what configuration options were set. The server only sends a setup command in response to one from the client. The sc_version should be updated in the server if commands have been obsoleted such that old clients may not be able to play. option::word, name of configuration option value::word, value of configuration option. May need further parsing according to the setup options below=====Setup Options There are really 2 set of setup commands here:. Those that control preferences of the client(how big is the map, what faceset to use, etc). . Those that describe capabilities of the client(client supports this protocol command or that) .Setup Options[options="autowidth,header"]|===========================|Command|Description|beat|Ask the server to enable heartbeat support. When heartbeat is enabled, the client must send the server a command every three seconds. If no commands need to be sent, use the `beat` no-op command. Clients that do not contact the server within the interval are assumed to have a temporary connection failure.|bot(0/1 value)|If set to 1, the client will not be considered a player when updating information to the metaserver. This is to avoid having a server with many bots appear more crowded than others.|darkness(0/1 value)|If set to 1(default), the server will send darkness information in the map protocol commands. If 0, the server will not include darkness, thus saving a minor amount of bandwidth. Since the client is free to ignore the darkness information, this does not allow the client to cheat. In the case of the old 'map' protocol command, turning darkness off will result in the masking faces not getting sent to the client.|extended_stats(0/1 value)|If set to 1, the server will send the CS_STAT_RACE_xxx and CS_STAT_BASE_xxx values too, so the client can display various status related to statistics. Default is 0.|facecache(0/1)|Determines if the client is caching images(1) or wants the images sent to it without caching them(0). Default is 0. This replaces the setfacemode command.|faceset(8 bit)|Faceset the client wishes to use. If the faceset is not valid, the server returns the faceset the client will be using(default 0).|loginmethod(8 bit)|Client sends this to server to note login support. This is basically used as a subset of the csversion/scversion to find out what level of login support the server and client support. Current defined values:0:no advanced support - only legacy login method 1:account based login(described more below) 2:new character creation support This list may grow - for example, advanced character creation could become a feature.|map2cmd:(1)|This indicates client support for the map2 protocol command. See the map2 protocol details above for the main differences. Obsolete:This is the only supported mode now, but many clients use it as a sanity check for protocol versions, so the server still replies. It doesn 't do anything with the data|mapsize(int x) X(int y)|Sets the map size to x X y. Note the spaces here are only for clarity - there should be no spaces when actually sent(it should be 11x11 or 25x25). The default map size unless changed is 11x11. The minimum map size the server will allow is 9x9(no technical reason this could be smaller, but I don 't think the game would be smaller). The maximum map size supported in the current protocol is 63x63. However, each server can have its maximum map size sent to most any value. If the client sends an invalid mapsize command or a mapsize of 0x0, the server will respond with a mapsize that is the maximum size the server supports. Thus, if the client wants to know the maximum map size, it can just do a 'mapsize 0x0' or 'mapsize' and it will get the maximum size back. The server will constrain the provided mapsize x &y to the configured minumum and maximums. For example, if the maximum map size is 25x25, the minimum map size is 9x9, and the client sends a 31x7 mapsize request, the mapsize will be set to 25x9 and the server will send back a mapsize 25x9 setup command. When the values are valid, the server will send back a mapsize XxY setup command. Note that this is from its parsed values, so it may not match stringwise with what the client sent, but will match 0 wise. For example, the client may send a 'mapsize 025X025' command, in which case the server will respond with a 'mapsize 25x25' command - the data is functionally the same. The server will send an updated map view when this command is sent.|notifications(int value)|Value indicating what notifications the client accepts. It is incremental, a value means "all notifications till this level". The following levels are supported:1:quest-related notifications("addquest" and "updquest") 2:knowledge-related notifications("addknowledge") 3:character status flags(overloaded, blind,...)|num_look_objects(int value)|The maximum number of objects shown in the ground view. If more objects are present, fake objects are created for selecting the previous/next group of items. Defaults to 50 if not set. The server may adjust the given value to a suitable one data
Definition: protocol.txt:379
initcjson_shared
static void initcjson_shared(PyObject *m)
Definition: cjson.cpp:1129
encode_string
static PyObject * encode_string(PyObject *object)
Definition: cjson.cpp:593
cjsonModule
static PyModuleDef cjsonModule
Definition: cjson.cpp:1153
Py_IS_NAN
#define Py_IS_NAN(X)
Definition: cjson.cpp:74
list
How to Install a Crossfire Server on you must install a python script engine on your computer Python is the default script engine of Crossfire You can find the python engine you have only to install them The VisualC Crossfire settings are for but you habe then to change the pathes in the VC settings Go in Settings C and Settings Link and change the optional include and libs path to the new python installation path o except the maps ! You must download a map package and install them the share folder Its must look like doubleclick on crossfire32 dsw There are projects in your libcross lib and plugin_python You need to compile all Easiest way is to select the plugin_python ReleaseLog as active this will compile all others too Then in Visual C press< F7 > to compile If you don t have an appropriate compiler you can try to get the the VC copies the crossfire32 exe in the crossfire folder and the plugin_python dll in the crossfire share plugins folder we will remove it when we get time for it o Last showing lots of weird write to the Crossfire mailing list
Definition: INSTALL_WIN32.txt:50
JSONData::end
char * end
Definition: cjson.cpp:25
decode_json
static PyObject * decode_json(JSONData *jsondata)
Definition: cjson.cpp:515
encode_unicode
static PyObject * encode_unicode(PyObject *object)
Definition: cjson.cpp:658
decode_bool
static PyObject * decode_bool(JSONData *jsondata)
Definition: cjson.cpp:123
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25