root / trunk / plugins / jsonrpc / json_tokener.c @ 1858
History | View | Annotate | Download (13.2 KB)
| 1 | 
                  /* 
                 | 
              
|---|---|
| 2 | 
                  * $Id: json_tokener.c,v 1.10 2004/07/27 00:42:31 mclark Exp $  | 
              
| 3 | 
                  *  | 
              
| 4 | 
                  * Copyright Metaparadigm Pte. Ltd. 2004.  | 
              
| 5 | 
                  * Michael Clark  | 
              
| 6 | 
                  *  | 
              
| 7 | 
                  * This library is free software; you can redistribute it and/or  | 
              
| 8 | 
                  * modify it under the terms of the GNU Lesser General Public (LGPL)  | 
              
| 9 | 
                  * License as published by the Free Software Foundation; either  | 
              
| 10 | 
                  * version 2.1 of the License, or (at your option) any later version.  | 
              
| 11 | 
                  *  | 
              
| 12 | 
                  * This library is distributed in the hope that it will be useful,  | 
              
| 13 | 
                  * but WITHOUT ANY WARRANTY; without even the implied warranty of  | 
              
| 14 | 
                  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU  | 
              
| 15 | 
                  * Lesser General Public License for more details: https://www.gnu.org/  | 
              
| 16 | 
                  *  | 
              
| 17 | 
                  */  | 
              
| 18 | 
                   | 
              
| 19 | 
                  #include  | 
              
| 20 | 
                  #include  | 
              
| 21 | 
                  #include  | 
              
| 22 | 
                  #include  | 
              
| 23 | 
                   | 
              
| 24 | 
                  #include "bits.h"  | 
              
| 25 | 
                  #include "debug.h"  | 
              
| 26 | 
                  #include "printbuf.h"  | 
              
| 27 | 
                  #include "arraylist.h"  | 
              
| 28 | 
                  #include "json_object.h"  | 
              
| 29 | 
                  #include "json_tokener.h"  | 
              
| 30 | 
                   | 
              
| 31 | 
                  #if defined(DARWIN) || defined(WIN32)
                 | 
              
| 32 | 
                  #undef strndup
                 | 
              
| 33 | 
                  char *strndup(const char *str, size_t len)  | 
              
| 34 | 
                  {
                 | 
              
| 35 | 
                  char *ret = calloc(1, len + 1);  | 
              
| 36 | 
                  strncpy(ret, str, len);  | 
              
| 37 | 
                      return ret;
                 | 
              
| 38 | 
                  }  | 
              
| 39 | 
                  #endif
                 | 
              
| 40 | 
                   | 
              
| 41 | 
                  static struct json_object* json_tokener_do_parse(struct json_tokener *this);  | 
              
| 42 | 
                   | 
              
| 43 | 
                  struct json_object* json_tokener_parse(char * s)  | 
              
| 44 | 
                  {
                 | 
              
| 45 | 
                    struct json_tokener tok;
                 | 
              
| 46 | 
                    struct json_object* obj;
                 | 
              
| 47 | 
                   | 
              
| 48 | 
                  tok.source = s;  | 
              
| 49 | 
                    tok.pos = 0;
                 | 
              
| 50 | 
                  tok.pb = printbuf_new();  | 
              
| 51 | 
                  obj = json_tokener_do_parse(&tok);  | 
              
| 52 | 
                  printbuf_free(tok.pb);  | 
              
| 53 | 
                    return obj;
                 | 
              
| 54 | 
                  }  | 
              
| 55 | 
                   | 
              
| 56 | 
                  static struct json_object* json_tokener_do_parse(struct json_tokener *this)  | 
              
| 57 | 
                  {
                 | 
              
| 58 | 
                    enum json_tokener_state state, saved_state;
                 | 
              
| 59 | 
                    enum json_tokener_error err = json_tokener_success;
                 | 
              
| 60 | 
                  struct json_object *current = NULL, *obj;  | 
              
| 61 | 
                  char *obj_field_name = NULL;  | 
              
| 62 | 
                  char quote_char = '\0';  | 
              
| 63 | 
                  int deemed_double = 0, start_offset = 0;  | 
              
| 64 | 
                   | 
              
| 65 | 
                  state = json_tokener_state_eatws;  | 
              
| 66 | 
                  saved_state = json_tokener_state_start;  | 
              
| 67 | 
                   | 
              
| 68 | 
                    char c;
                 | 
              
| 69 | 
                    do {
                 | 
              
| 70 | 
                  c = this->source[this->pos];  | 
              
| 71 | 
                      switch(state) {
                 | 
              
| 72 | 
                   | 
              
| 73 | 
                  case json_tokener_state_eatws:  | 
              
| 74 | 
                        if(isspace(c)) {
                 | 
              
| 75 | 
                  this->pos++;  | 
              
| 76 | 
                  } else if(c == '/') {  | 
              
| 77 | 
                  state = json_tokener_state_comment_start;  | 
              
| 78 | 
                  start_offset = this->pos++;  | 
              
| 79 | 
                        } else {
                 | 
              
| 80 | 
                  state = saved_state;  | 
              
| 81 | 
                  }  | 
              
| 82 | 
                        break;
                 | 
              
| 83 | 
                   | 
              
| 84 | 
                  case json_tokener_state_start:  | 
              
| 85 | 
                        switch(c) {
                 | 
              
| 86 | 
                  case '{':  | 
              
| 87 | 
                  state = json_tokener_state_eatws;  | 
              
| 88 | 
                  saved_state = json_tokener_state_object;  | 
              
| 89 | 
                  current = json_object_new_object();  | 
              
| 90 | 
                  this->pos++;  | 
              
| 91 | 
                          break;
                 | 
              
| 92 | 
                  case '[':  | 
              
| 93 | 
                  state = json_tokener_state_eatws;  | 
              
| 94 | 
                  saved_state = json_tokener_state_array;  | 
              
| 95 | 
                  current = json_object_new_array();  | 
              
| 96 | 
                  this->pos++;  | 
              
| 97 | 
                          break;
                 | 
              
| 98 | 
                  case 'N':  | 
              
| 99 | 
                  case 'n':  | 
              
| 100 | 
                  state = json_tokener_state_null;  | 
              
| 101 | 
                  start_offset = this->pos++;  | 
              
| 102 | 
                          break;
                 | 
              
| 103 | 
                  case '"':  | 
              
| 104 | 
                  case '\'':  | 
              
| 105 | 
                  quote_char = c;  | 
              
| 106 | 
                  printbuf_reset(this->pb);  | 
              
| 107 | 
                  state = json_tokener_state_string;  | 
              
| 108 | 
                  start_offset = ++this->pos;  | 
              
| 109 | 
                          break;
                 | 
              
| 110 | 
                  case 'T':  | 
              
| 111 | 
                  case 't':  | 
              
| 112 | 
                  case 'F':  | 
              
| 113 | 
                  case 'f':  | 
              
| 114 | 
                  state = json_tokener_state_boolean;  | 
              
| 115 | 
                  start_offset = this->pos++;  | 
              
| 116 | 
                          break;
                 | 
              
| 117 | 
                  case '0' ... '9':  | 
              
| 118 | 
                  case '-':  | 
              
| 119 | 
                          deemed_double = 0;
                 | 
              
| 120 | 
                  state = json_tokener_state_number;  | 
              
| 121 | 
                  start_offset = this->pos++;  | 
              
| 122 | 
                          break;
                 | 
              
| 123 | 
                        default:
                 | 
              
| 124 | 
                  err = json_tokener_error_parse_unexpected;  | 
              
| 125 | 
                          goto out;
                 | 
              
| 126 | 
                  }  | 
              
| 127 | 
                        break;
                 | 
              
| 128 | 
                   | 
              
| 129 | 
                  case json_tokener_state_finish:  | 
              
| 130 | 
                        goto out;
                 | 
              
| 131 | 
                   | 
              
| 132 | 
                  case json_tokener_state_null:  | 
              
| 133 | 
                  if(strncasecmp("null", this->source + start_offset,  | 
              
| 134 | 
                                       this->pos - start_offset)) {
                 | 
              
| 135 | 
                  err = json_tokener_error_parse_null;  | 
              
| 136 | 
                          goto out;
                 | 
              
| 137 | 
                  }  | 
              
| 138 | 
                  if(this->pos - start_offset == 4) {  | 
              
| 139 | 
                          current = NULL;
                 | 
              
| 140 | 
                  saved_state = json_tokener_state_finish;  | 
              
| 141 | 
                  state = json_tokener_state_eatws;  | 
              
| 142 | 
                        } else {
                 | 
              
| 143 | 
                  this->pos++;  | 
              
| 144 | 
                  }  | 
              
| 145 | 
                        break;
                 | 
              
| 146 | 
                   | 
              
| 147 | 
                  case json_tokener_state_comment_start:  | 
              
| 148 | 
                  if(c == '*') {  | 
              
| 149 | 
                  state = json_tokener_state_comment;  | 
              
| 150 | 
                  } else if(c == '/') {  | 
              
| 151 | 
                  state = json_tokener_state_comment_eol;  | 
              
| 152 | 
                        } else {
                 | 
              
| 153 | 
                  err = json_tokener_error_parse_comment;  | 
              
| 154 | 
                          goto out;
                 | 
              
| 155 | 
                  }  | 
              
| 156 | 
                  this->pos++;  | 
              
| 157 | 
                        break;
                 | 
              
| 158 | 
                   | 
              
| 159 | 
                  case json_tokener_state_comment:  | 
              
| 160 | 
                  if(c == '*') state = json_tokener_state_comment_end;  | 
              
| 161 | 
                  this->pos++;  | 
              
| 162 | 
                        break;
                 | 
              
| 163 | 
                   | 
              
| 164 | 
                  case json_tokener_state_comment_eol:  | 
              
| 165 | 
                  if(c == '\n') {  | 
              
| 166 | 
                          if(mc_get_debug()) {
                 | 
              
| 167 | 
                            char *tmp = strndup(this->source + start_offset,
                 | 
              
| 168 | 
                  this->pos - start_offset);  | 
              
| 169 | 
                            mc_debug("json_tokener_comment: %s\n", tmp);
                 | 
              
| 170 | 
                  free(tmp);  | 
              
| 171 | 
                  }  | 
              
| 172 | 
                  state = json_tokener_state_eatws;  | 
              
| 173 | 
                  }  | 
              
| 174 | 
                  this->pos++;  | 
              
| 175 | 
                        break;
                 | 
              
| 176 | 
                   | 
              
| 177 | 
                  case json_tokener_state_comment_end:  | 
              
| 178 | 
                  if(c == '/') {  | 
              
| 179 | 
                          if(mc_get_debug()) {
                 | 
              
| 180 | 
                            char *tmp = strndup(this->source + start_offset,
                 | 
              
| 181 | 
                                                this->pos - start_offset + 1);
                 | 
              
| 182 | 
                            mc_debug("json_tokener_comment: %s\n", tmp);
                 | 
              
| 183 | 
                  free(tmp);  | 
              
| 184 | 
                  }  | 
              
| 185 | 
                  state = json_tokener_state_eatws;  | 
              
| 186 | 
                        } else {
                 | 
              
| 187 | 
                  state = json_tokener_state_comment;  | 
              
| 188 | 
                  }  | 
              
| 189 | 
                  this->pos++;  | 
              
| 190 | 
                        break;
                 | 
              
| 191 | 
                   | 
              
| 192 | 
                  case json_tokener_state_string:  | 
              
| 193 | 
                        if(c == quote_char) {
                 | 
              
| 194 | 
                  printbuf_memappend(this->pb, this->source + start_offset,  | 
              
| 195 | 
                  this->pos - start_offset);  | 
              
| 196 | 
                  current = json_object_new_string(this->pb->buf);  | 
              
| 197 | 
                  saved_state = json_tokener_state_finish;  | 
              
| 198 | 
                  state = json_tokener_state_eatws;  | 
              
| 199 | 
                  } else if(c == '\\') {  | 
              
| 200 | 
                  saved_state = json_tokener_state_string;  | 
              
| 201 | 
                  state = json_tokener_state_string_escape;  | 
              
| 202 | 
                  }  | 
              
| 203 | 
                  this->pos++;  | 
              
| 204 | 
                        break;
                 | 
              
| 205 | 
                   | 
              
| 206 | 
                  case json_tokener_state_string_escape:  | 
              
| 207 | 
                        switch(c) {
                 | 
              
| 208 | 
                  case '"':  | 
              
| 209 | 
                  case '\\':  | 
              
| 210 | 
                  printbuf_memappend(this->pb, this->source + start_offset,  | 
              
| 211 | 
                                             this->pos - start_offset - 1);
                 | 
              
| 212 | 
                  start_offset = this->pos++;  | 
              
| 213 | 
                  state = saved_state;  | 
              
| 214 | 
                          break;
                 | 
              
| 215 | 
                  case 'b':  | 
              
| 216 | 
                  case 'n':  | 
              
| 217 | 
                  case 'r':  | 
              
| 218 | 
                  case 't':  | 
              
| 219 | 
                  printbuf_memappend(this->pb, this->source + start_offset,  | 
              
| 220 | 
                                             this->pos - start_offset - 1);
                 | 
              
| 221 | 
                  if(c == 'b') printbuf_memappend(this->pb, "\b", 1);  | 
              
| 222 | 
                  else if(c == 'n') printbuf_memappend(this->pb, "\n", 1);  | 
              
| 223 | 
                  else if(c == 'r') printbuf_memappend(this->pb, "\r", 1);  | 
              
| 224 | 
                  else if(c == 't') printbuf_memappend(this->pb, "\t", 1);  | 
              
| 225 | 
                  start_offset = ++this->pos;  | 
              
| 226 | 
                  state = saved_state;  | 
              
| 227 | 
                          break;
                 | 
              
| 228 | 
                  case 'u':  | 
              
| 229 | 
                  printbuf_memappend(this->pb, this->source + start_offset,  | 
              
| 230 | 
                                             this->pos - start_offset - 1);
                 | 
              
| 231 | 
                  start_offset = ++this->pos;  | 
              
| 232 | 
                  state = json_tokener_state_escape_unicode;  | 
              
| 233 | 
                          break;
                 | 
              
| 234 | 
                        default:
                 | 
              
| 235 | 
                  err = json_tokener_error_parse_string;  | 
              
| 236 | 
                          goto out;
                 | 
              
| 237 | 
                  }  | 
              
| 238 | 
                        break;
                 | 
              
| 239 | 
                   | 
              
| 240 | 
                  case json_tokener_state_escape_unicode:  | 
              
| 241 | 
                        if(strchr(json_hex_chars, c)) {
                 | 
              
| 242 | 
                  this->pos++;  | 
              
| 243 | 
                  if(this->pos - start_offset == 4) {  | 
              
| 244 | 
                  unsigned char utf_out[3];  | 
              
| 245 | 
                  unsigned int ucs_char =  | 
              
| 246 | 
                              (hexdigit(*(this->source + start_offset)) << 12) +
                 | 
              
| 247 | 
                  (hexdigit(*(this->source + start_offset + 1)) << 8) +  | 
              
| 248 | 
                  (hexdigit(*(this->source + start_offset + 2)) << 4) +  | 
              
| 249 | 
                              hexdigit(*(this->source + start_offset + 3));
                 | 
              
| 250 | 
                  if (ucs_char < 0x80) {  | 
              
| 251 | 
                              utf_out[0] = ucs_char;
                 | 
              
| 252 | 
                  printbuf_memappend(this->pb, (char*) utf_out, 1);  | 
              
| 253 | 
                  } else if (ucs_char < 0x800) {  | 
              
| 254 | 
                  utf_out[0] = 0xc0 | (ucs_char >> 6);  | 
              
| 255 | 
                  utf_out[1] = 0x80 | (ucs_char & 0x3f);  | 
              
| 256 | 
                  printbuf_memappend(this->pb, (char*) utf_out, 2);  | 
              
| 257 | 
                            } else {
                 | 
              
| 258 | 
                  utf_out[0] = 0xe0 | (ucs_char >> 12);  | 
              
| 259 | 
                  utf_out[1] = 0x80 | ((ucs_char >> 6) & 0x3f);  | 
              
| 260 | 
                  utf_out[2] = 0x80 | (ucs_char & 0x3f);  | 
              
| 261 | 
                  printbuf_memappend(this->pb, (char*) utf_out, 3);  | 
              
| 262 | 
                  }  | 
              
| 263 | 
                  start_offset = this->pos;  | 
              
| 264 | 
                  state = saved_state;  | 
              
| 265 | 
                  }  | 
              
| 266 | 
                        } else {
                 | 
              
| 267 | 
                  err = json_tokener_error_parse_string;  | 
              
| 268 | 
                          goto out;
                 | 
              
| 269 | 
                  }  | 
              
| 270 | 
                        break;
                 | 
              
| 271 | 
                   | 
              
| 272 | 
                  case json_tokener_state_boolean:  | 
              
| 273 | 
                  if(strncasecmp("true", this->source + start_offset,  | 
              
| 274 | 
                                   this->pos - start_offset) == 0) {
                 | 
              
| 275 | 
                  if(this->pos - start_offset == 4) {  | 
              
| 276 | 
                            current = json_object_new_boolean(1);
                 | 
              
| 277 | 
                  saved_state = json_tokener_state_finish;  | 
              
| 278 | 
                  state = json_tokener_state_eatws;  | 
              
| 279 | 
                          } else {
                 | 
              
| 280 | 
                  this->pos++;  | 
              
| 281 | 
                  }  | 
              
| 282 | 
                  } else if(strncasecmp("false", this->source + start_offset,  | 
              
| 283 | 
                                          this->pos - start_offset) == 0) {
                 | 
              
| 284 | 
                  if(this->pos - start_offset == 5) {  | 
              
| 285 | 
                            current = json_object_new_boolean(0);
                 | 
              
| 286 | 
                  saved_state = json_tokener_state_finish;  | 
              
| 287 | 
                  state = json_tokener_state_eatws;  | 
              
| 288 | 
                          } else {
                 | 
              
| 289 | 
                  this->pos++;  | 
              
| 290 | 
                  }  | 
              
| 291 | 
                        } else {
                 | 
              
| 292 | 
                  err = json_tokener_error_parse_boolean;  | 
              
| 293 | 
                          goto out;
                 | 
              
| 294 | 
                  }  | 
              
| 295 | 
                        break;
                 | 
              
| 296 | 
                   | 
              
| 297 | 
                  case json_tokener_state_number:  | 
              
| 298 | 
                        if(!c || !strchr(json_number_chars, c)) {
                 | 
              
| 299 | 
                          int numi;
                 | 
              
| 300 | 
                          double numd;
                 | 
              
| 301 | 
                          char *tmp = strndup(this->source + start_offset,
                 | 
              
| 302 | 
                  this->pos - start_offset);  | 
              
| 303 | 
                  if(!deemed_double && sscanf(tmp, "%d", &numi) == 1) {  | 
              
| 304 | 
                  current = json_object_new_int(numi);  | 
              
| 305 | 
                  } else if(deemed_double && sscanf(tmp, "%lf", &numd) == 1) {  | 
              
| 306 | 
                  current = json_object_new_double(numd);  | 
              
| 307 | 
                          } else {
                 | 
              
| 308 | 
                  free(tmp);  | 
              
| 309 | 
                  err = json_tokener_error_parse_number;  | 
              
| 310 | 
                            goto out;
                 | 
              
| 311 | 
                  }  | 
              
| 312 | 
                  free(tmp);  | 
              
| 313 | 
                  saved_state = json_tokener_state_finish;  | 
              
| 314 | 
                  state = json_tokener_state_eatws;  | 
              
| 315 | 
                        } else {
                 | 
              
| 316 | 
                  if(c == '.' || c == 'e') deemed_double = 1;  | 
              
| 317 | 
                  this->pos++;  | 
              
| 318 | 
                  }  | 
              
| 319 | 
                        break;
                 | 
              
| 320 | 
                   | 
              
| 321 | 
                  case json_tokener_state_array:  | 
              
| 322 | 
                  if(c == ']') {  | 
              
| 323 | 
                  this->pos++;  | 
              
| 324 | 
                  saved_state = json_tokener_state_finish;  | 
              
| 325 | 
                  state = json_tokener_state_eatws;  | 
              
| 326 | 
                        } else {
                 | 
              
| 327 | 
                  obj = json_tokener_do_parse(this);  | 
              
| 328 | 
                          if(is_error(obj)) {
                 | 
              
| 329 | 
                  err = json_tokener_error_parse_array;  | 
              
| 330 | 
                            goto out;
                 | 
              
| 331 | 
                  }  | 
              
| 332 | 
                  json_object_array_add(current, obj);  | 
              
| 333 | 
                  saved_state = json_tokener_state_array_sep;  | 
              
| 334 | 
                  state = json_tokener_state_eatws;  | 
              
| 335 | 
                  }  | 
              
| 336 | 
                        break;
                 | 
              
| 337 | 
                   | 
              
| 338 | 
                  case json_tokener_state_array_sep:  | 
              
| 339 | 
                  if(c == ']') {  | 
              
| 340 | 
                  this->pos++;  | 
              
| 341 | 
                  saved_state = json_tokener_state_finish;  | 
              
| 342 | 
                  state = json_tokener_state_eatws;  | 
              
| 343 | 
                  } else if(c == ',') {  | 
              
| 344 | 
                  this->pos++;  | 
              
| 345 | 
                  saved_state = json_tokener_state_array;  | 
              
| 346 | 
                  state = json_tokener_state_eatws;  | 
              
| 347 | 
                        } else {
                 | 
              
| 348 | 
                  json_object_put(current);  | 
              
| 349 | 
                  err = json_tokener_error_parse_array;  | 
              
| 350 | 
                          goto out;
                 | 
              
| 351 | 
                  }  | 
              
| 352 | 
                        break;
                 | 
              
| 353 | 
                   | 
              
| 354 | 
                  case json_tokener_state_object:  | 
              
| 355 | 
                  state = json_tokener_state_object_field_start;  | 
              
| 356 | 
                  start_offset = this->pos;  | 
              
| 357 | 
                        break;
                 | 
              
| 358 | 
                   | 
              
| 359 | 
                  case json_tokener_state_object_field_start:  | 
              
| 360 | 
                  if(c == '}') {  | 
              
| 361 | 
                  this->pos++;  | 
              
| 362 | 
                  saved_state = json_tokener_state_finish;  | 
              
| 363 | 
                  state = json_tokener_state_eatws;  | 
              
| 364 | 
                  } else if (c == '"' || c == '\'') {  | 
              
| 365 | 
                  quote_char = c;  | 
              
| 366 | 
                  printbuf_reset(this->pb);  | 
              
| 367 | 
                  state = json_tokener_state_object_field;  | 
              
| 368 | 
                  start_offset = ++this->pos;  | 
              
| 369 | 
                        } else {
                 | 
              
| 370 | 
                  err = json_tokener_error_parse_object;  | 
              
| 371 | 
                          goto out;
                 | 
              
| 372 | 
                  }  | 
              
| 373 | 
                        break;
                 | 
              
| 374 | 
                   | 
              
| 375 | 
                  case json_tokener_state_object_field:  | 
              
| 376 | 
                        if(c == quote_char) {
                 | 
              
| 377 | 
                  printbuf_memappend(this->pb, this->source + start_offset,  | 
              
| 378 | 
                  this->pos - start_offset);  | 
              
| 379 | 
                  obj_field_name = strdup(this->pb->buf);  | 
              
| 380 | 
                  saved_state = json_tokener_state_object_field_end;  | 
              
| 381 | 
                  state = json_tokener_state_eatws;  | 
              
| 382 | 
                  } else if(c == '\\') {  | 
              
| 383 | 
                  saved_state = json_tokener_state_object_field;  | 
              
| 384 | 
                  state = json_tokener_state_string_escape;  | 
              
| 385 | 
                  }  | 
              
| 386 | 
                  this->pos++;  | 
              
| 387 | 
                        break;
                 | 
              
| 388 | 
                   | 
              
| 389 | 
                  case json_tokener_state_object_field_end:  | 
              
| 390 | 
                  if(c == ':') {  | 
              
| 391 | 
                  this->pos++;  | 
              
| 392 | 
                  saved_state = json_tokener_state_object_value;  | 
              
| 393 | 
                  state = json_tokener_state_eatws;  | 
              
| 394 | 
                        } else {
                 | 
              
| 395 | 
                  err = -json_tokener_error_parse_object;  | 
              
| 396 | 
                          goto out;
                 | 
              
| 397 | 
                  }  | 
              
| 398 | 
                        break;
                 | 
              
| 399 | 
                   | 
              
| 400 | 
                  case json_tokener_state_object_value:  | 
              
| 401 | 
                  obj = json_tokener_do_parse(this);  | 
              
| 402 | 
                        if(is_error(obj)) {
                 | 
              
| 403 | 
                  err = json_tokener_error_parse_object;  | 
              
| 404 | 
                          goto out;
                 | 
              
| 405 | 
                  }  | 
              
| 406 | 
                  json_object_object_add(current, obj_field_name, obj);  | 
              
| 407 | 
                  free(obj_field_name);  | 
              
| 408 | 
                        obj_field_name = NULL;
                 | 
              
| 409 | 
                  saved_state = json_tokener_state_object_sep;  | 
              
| 410 | 
                  state = json_tokener_state_eatws;  | 
              
| 411 | 
                        break;
                 | 
              
| 412 | 
                   | 
              
| 413 | 
                  case json_tokener_state_object_sep:  | 
              
| 414 | 
                  if(c == '}') {  | 
              
| 415 | 
                  this->pos++;  | 
              
| 416 | 
                  saved_state = json_tokener_state_finish;  | 
              
| 417 | 
                  state = json_tokener_state_eatws;  | 
              
| 418 | 
                  } else if(c == ',') {  | 
              
| 419 | 
                  this->pos++;  | 
              
| 420 | 
                  saved_state = json_tokener_state_object;  | 
              
| 421 | 
                  state = json_tokener_state_eatws;  | 
              
| 422 | 
                        } else {
                 | 
              
| 423 | 
                  err = json_tokener_error_parse_object;  | 
              
| 424 | 
                          goto out;
                 | 
              
| 425 | 
                  }  | 
              
| 426 | 
                        break;
                 | 
              
| 427 | 
                   | 
              
| 428 | 
                  }  | 
              
| 429 | 
                    } while(c);
                 | 
              
| 430 | 
                   | 
              
| 431 | 
                    if(state != json_tokener_state_finish &&
                 | 
              
| 432 | 
                  saved_state != json_tokener_state_finish)  | 
              
| 433 | 
                  err = json_tokener_error_parse_eof;  | 
              
| 434 | 
                   | 
              
| 435 | 
                   out:
                 | 
              
| 436 | 
                  free(obj_field_name);  | 
              
| 437 | 
                  if(err == json_tokener_success) return current;  | 
              
| 438 | 
                    mc_debug("json_tokener_do_parse: error=%d state=%d char=%c\n",
                 | 
              
| 439 | 
                  err, state, c);  | 
              
| 440 | 
                  json_object_put(current);  | 
              
| 441 | 
                  return NULL;  | 
              
| 442 | 
                  }  | 
              
NNTPGrab

