void strbuffer_close(strbuffer_t *strbuff) { jsonp_free(strbuff->value); strbuff->size = 0; strbuff->length = 0; strbuff->value = NULL; }
static int hashtable_do_rehash(hashtable_t *hashtable) { list_t *list, *next; pair_t *pair; size_t i, index, new_size; jsonp_free(hashtable->buckets); hashtable->num_buckets++; new_size = num_buckets(hashtable); hashtable->buckets = jsonp_malloc(new_size * sizeof(bucket_t)); if(!hashtable->buckets) return -1; for(i = 0; i < num_buckets(hashtable); i++) { hashtable->buckets[i].first = hashtable->buckets[i].last = &hashtable->list; } list = hashtable->list.next; list_init(&hashtable->list); for(; list != &hashtable->list; list = next) { next = list->next; pair = list_to_pair(list); index = pair->hash % new_size; insert_to_bucket(hashtable, &hashtable->buckets[index], &pair->list); } return 0; }
/* returns 0 on success, -1 if key was not found */ static int hashtable_do_del(hashtable_t *hashtable, const char *key, size_t hash) { pair_t *pair; bucket_t *bucket; size_t index; index = hash % num_buckets(hashtable); bucket = &hashtable->buckets[index]; pair = hashtable_find_pair(hashtable, bucket, key, hash); if(!pair) return -1; if(&pair->list == bucket->first && &pair->list == bucket->last) bucket->first = bucket->last = &hashtable->list; else if(&pair->list == bucket->first) bucket->first = pair->list.next; else if(&pair->list == bucket->last) bucket->last = pair->list.prev; list_remove(&pair->list); json_decref(pair->value); jsonp_free(pair); hashtable->size--; return 0; }
int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size) { if(size >= strbuff->size - strbuff->length) { size_t new_size; char *new_value; /* avoid integer overflow */ if (strbuff->size > STRBUFFER_SIZE_MAX / STRBUFFER_FACTOR || size > STRBUFFER_SIZE_MAX - 1 || strbuff->length > STRBUFFER_SIZE_MAX - 1 - size) return -1; new_size = max(strbuff->size * STRBUFFER_FACTOR, strbuff->length + size + 1); new_value = (char *) jsonp_malloc(new_size); if(!new_value) return -1; memcpy(new_value, strbuff->value, strbuff->length); jsonp_free(strbuff->value); strbuff->value = new_value; strbuff->size = new_size; } memcpy(strbuff->value + strbuff->length, data, size); strbuff->length += size; strbuff->value[strbuff->length] = '\0'; return 0; }
static void hashtable_do_clear(hashtable_t *hashtable) { list_t *list, *next; pair_t *pair; for(list = hashtable->list.next; list != &hashtable->list; list = next) { next = list->next; pair = list_to_pair(list); json_decref(pair->value); jsonp_free(pair); } }
json_t *json_object(void) { json_object_t *object = jsonp_malloc(sizeof(json_object_t)); if(!object) return NULL; json_init(&object->json, JSON_OBJECT); if(hashtable_init(&object->hashtable)) { jsonp_free(object); return NULL; } object->serial = 0; object->visited = 0; return &object->json; }
int json_string_set_nocheck(json_t *json, const char *value) { char *dup; json_string_t *string; if(!json_is_string(json) || !value) return -1; dup = jsonp_strdup(value); if(!dup) return -1; string = json_to_string(json); jsonp_free(string->value); string->value = dup; return 0; }
json_t *json_string_nocheck(const char *value) { json_string_t *string; if(!value) return NULL; string = (json_string_t *) jsonp_malloc(sizeof(json_string_t)); if(!string) return NULL; json_init(&string->json, JSON_STRING); string->value = jsonp_strdup(value); if(!string->value) { jsonp_free(string); return NULL; } return &string->json; }
json_t *json_array(void) { json_array_t *array = (json_array_t *) jsonp_malloc(sizeof(json_array_t)); if(!array) return NULL; json_init(&array->json, JSON_ARRAY); array->entries = 0; array->size = 8; array->table = (json_t **) jsonp_malloc(array->size * sizeof(json_t *)); if(!array->table) { jsonp_free(array); return NULL; } array->visited = 0; return &array->json; }
json_t *json_object(void) { json_object_t *object = (json_object_t *) jsonp_malloc(sizeof(json_object_t)); if(!object) return NULL; json_init(&object->json, JSON_OBJECT); if(hashtable_init(&object->hashtable, hash_key, key_equal, jsonp_free, value_decref)) { jsonp_free(object); return NULL; } object->serial = 0; object->visited = 0; return &object->json; }
int json_array_insert_new(json_t *json, size_t index, json_t *value) { json_array_t *array; json_t **old_table; if(!value) return -1; if(!json_is_array(json) || json == value) { json_decref(value); return -1; } array = json_to_array(json); if(index > array->entries) { json_decref(value); return -1; } old_table = json_array_grow(array, 1, 0); if(!old_table) { json_decref(value); return -1; } if(old_table != array->table) { array_copy(array->table, 0, old_table, 0, index); array_copy(array->table, index + 1, old_table, index, array->entries - index); jsonp_free(old_table); } else array_move(array, index + 1, index, array->entries - index); array->table[index] = value; array->entries++; return 0; }
json_t *json_object(void) { json_object_t *object = jsonp_malloc(sizeof(json_object_t)); if(!object) return NULL; if (!hashtable_seed) { /* Autoseed */ json_object_seed(0); } json_init(&object->json, JSON_OBJECT); if(hashtable_init(&object->hashtable)) { jsonp_free(object); return NULL; } object->serial = 0; return &object->json; }
static char *parse_string(stream_t *stream, size_t flags, json_error_t *error) { char *endptr; ssize_t colon; size_t pos = 0; size_t length; char *string; (void) flags; colon = search(stream, ':'); if (colon < 0) { error_set(error, stream, "unterminated string length"); return NULL; } if (validate_number(stream, error)) return NULL; /* can overflow, but who cares? */ length = strtoul(&stream->buffer[stream->pos], &endptr, 10); if (endptr != &stream->buffer[colon]) { error_set(error, stream, "invalid string length"); return NULL; } stream->pos = colon + 1; string = jsonp_malloc(length + 1); if (!string) { error_set(error, stream, "out of memory (string length %zd)", length); return NULL; } string[length] = '\0'; while (pos < length) { char *zero; size_t chunk = stream->buflen - stream->pos; if (chunk == 0) { if (stream_refill(stream) <= 0) { error_set(error, stream, "partial string: %zd/%zd", pos, length); goto error; } continue; } if (chunk > length - pos) chunk = length - pos; /* null bytes are not allowed inside strings */ zero = memchr(&stream->buffer[stream->pos], '\0', chunk); if (zero) { stream->pos = zero - stream->buffer; error_set(error, stream, "string contains a zero byte"); goto error; } memcpy(&string[pos], &stream->buffer[stream->pos], chunk); stream->pos += chunk; pos += chunk; } return string; error: jsonp_free(string); return NULL; }
void hashtable_close(hashtable_t *hashtable) { hashtable_do_clear(hashtable); jsonp_free(hashtable->buckets); }
static void lex_free_string(lex_t *lex) { jsonp_free(lex->value.string.val); lex->value.string.val = NULL; lex->value.string.len = 0; }
static void finish_stream(stream_t *stream) { if (stream->fill) jsonp_free(stream->buffer); }
static void lex_close(lex_t *lex) { if(lex->token == TOKEN_STRING) jsonp_free(lex->value.string); strbuffer_close(&lex->saved_text); }
static void lex_scan_string(lex_t *lex, json_error_t *error) { int c; const char *p; char *t; int i; lex->value.string = NULL; lex->token = TOKEN_INVALID; c = lex_get_save(lex, error); while(c != '"') { if(c == STREAM_STATE_ERROR) goto out; else if(c == STREAM_STATE_EOF) { error_set(error, lex, "premature end of input"); goto out; } else if(0 <= c && c <= 0x1F) { /* control character */ lex_unget_unsave(lex, c); if(c == '\n') error_set(error, lex, "unexpected newline", c); else error_set(error, lex, "control character 0x%x", c); goto out; } else if(c == '\\') { c = lex_get_save(lex, error); if(c == 'u') { c = lex_get_save(lex, error); for(i = 0; i < 4; i++) { if(!l_isxdigit(c)) { error_set(error, lex, "invalid escape"); goto out; } c = lex_get_save(lex, error); } } else if(c == '"' || c == '\\' || c == '/' || c == 'b' || c == 'f' || c == 'n' || c == 'r' || c == 't') c = lex_get_save(lex, error); else { error_set(error, lex, "invalid escape"); goto out; } } else c = lex_get_save(lex, error); } /* the actual value is at most of the same length as the source string, because: - shortcut escapes (e.g. "\t") (length 2) are converted to 1 byte - a single \uXXXX escape (length 6) is converted to at most 3 bytes - two \uXXXX escapes (length 12) forming an UTF-16 surrogate pair are converted to 4 bytes */ lex->value.string = jsonp_malloc(lex->saved_text.length + 1); if(!lex->value.string) { /* this is not very nice, since TOKEN_INVALID is returned */ goto out; } /* the target */ t = lex->value.string; /* + 1 to skip the " */ p = strbuffer_value(&lex->saved_text) + 1; while(*p != '"') { if(*p == '\\') { p++; if(*p == 'u') { char buffer[4]; int length; int32_t value; value = decode_unicode_escape(p); p += 5; if(0xD800 <= value && value <= 0xDBFF) { /* surrogate pair */ if(*p == '\\' && *(p + 1) == 'u') { int32_t value2 = decode_unicode_escape(++p); p += 5; if(0xDC00 <= value2 && value2 <= 0xDFFF) { /* valid second surrogate */ value = ((value - 0xD800) << 10) + (value2 - 0xDC00) + 0x10000; } else { /* invalid second surrogate */ error_set(error, lex, "invalid Unicode '\\u%04X\\u%04X'", value, value2); goto out; } } else { /* no second surrogate */ error_set(error, lex, "invalid Unicode '\\u%04X'", value); goto out; } } else if(0xDC00 <= value && value <= 0xDFFF) { error_set(error, lex, "invalid Unicode '\\u%04X'", value); goto out; } else if(value == 0) { error_set(error, lex, "\\u0000 is not allowed"); goto out; } if(utf8_encode(value, buffer, &length)) assert(0); memcpy(t, buffer, length); t += length; } else { switch(*p) { case '"': case '\\': case '/': *t = *p; break; case 'b': *t = '\b'; break; case 'f': *t = '\f'; break; case 'n': *t = '\n'; break; case 'r': *t = '\r'; break; case 't': *t = '\t'; break; default: assert(0); } t++; p++; } } else *(t++) = *(p++); } *t = '\0'; lex->token = TOKEN_STRING; return; out: jsonp_free(lex->value.string); }
void MessageBuilder::freeMessage(char * message) { jsonp_free(message); }
static void json_delete_string(json_string_t *string) { jsonp_free(string->value); jsonp_free(string); }
static int lex_scan(lex_t *lex, json_error_t *error) { int c; strbuffer_clear(&lex->saved_text); if(lex->token == TOKEN_STRING) { jsonp_free(lex->value.string); lex->value.string = NULL; } c = lex_get(lex, error); while(c == ' ' || c == '\t' || c == '\n' || c == '\r') c = lex_get(lex, error); if(c == STREAM_STATE_EOF) { lex->token = TOKEN_EOF; goto out; } if(c == STREAM_STATE_ERROR) { lex->token = TOKEN_INVALID; goto out; } lex_save(lex, c); if(c == '{' || c == '}' || c == '[' || c == ']' || c == ':' || c == ',') lex->token = c; else if(c == '"') lex_scan_string(lex, error); else if(l_isdigit(c) || c == '-') { if(lex_scan_number(lex, c, error)) goto out; } else if(l_isalpha(c)) { /* eat up the whole identifier for clearer error messages */ const char *saved_text; c = lex_get_save(lex, error); while(l_isalpha(c)) c = lex_get_save(lex, error); lex_unget_unsave(lex, c); saved_text = strbuffer_value(&lex->saved_text); if(strcmp(saved_text, "true") == 0) lex->token = TOKEN_TRUE; else if(strcmp(saved_text, "false") == 0) lex->token = TOKEN_FALSE; else if(strcmp(saved_text, "null") == 0) lex->token = TOKEN_NULL; else lex->token = TOKEN_INVALID; } else { /* save the rest of the input UTF-8 sequence to get an error message of valid UTF-8 */ lex_save_cached(lex); lex->token = TOKEN_INVALID; } out: return lex->token; }
static void json_delete_integer(json_integer_t *integer) { jsonp_free(integer); }
static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) { json_t *object = json_object(); if(!object) return NULL; lex_scan(lex, error); if(lex->token == '}') return object; while(1) { char *key; json_t *value; if(lex->token != TOKEN_STRING) { error_set(error, lex, "string or '}' expected"); goto error; } key = lex_steal_string(lex); if(!key) return NULL; if(flags & JSON_REJECT_DUPLICATES) { if(json_object_get(object, key)) { jsonp_free(key); error_set(error, lex, "duplicate object key"); goto error; } } lex_scan(lex, error); if(lex->token != ':') { jsonp_free(key); error_set(error, lex, "':' expected"); goto error; } lex_scan(lex, error); value = parse_value(lex, flags, error); if(!value) { jsonp_free(key); goto error; } if(json_object_set_nocheck(object, key, value)) { jsonp_free(key); json_decref(value); goto error; } json_decref(value); jsonp_free(key); lex_scan(lex, error); if(lex->token != ',') break; lex_scan(lex, error); } if(lex->token != '}') { error_set(error, lex, "'}' expected"); goto error; } return object; error: json_decref(object); return NULL; }
static void json_delete_real(json_real_t *real) { jsonp_free(real); }
static void json_delete_object(json_object_t *object) { hashtable_close(&object->hashtable); jsonp_free(object); }
int json_path_set(json_t *json, const char *path, json_t *value, unsigned int append) { static const char array_open = '['; static const char object_delim = '.'; static const char *path_delims = ".["; static const char *array_close = "]"; json_t *cursor, *parent = NULL; char *token, *buf = NULL, *peek, delim = '\0'; const char *expect; int index_saved = -1; if (!json || !path || !value) { ERR("invalid arguments\n"); goto fail; } else { buf = jsonp_strdup(path); } peek = buf; token = buf; cursor = json; expect = path_delims; if (*token == array_open) { expect = array_close; token++; } while (peek && *peek && cursor) { char *last_peek = peek; peek = strpbrk(last_peek, expect); if (peek) { if (!token && peek != last_peek) { ERR("unexpected trailing chars in JSON path at pos %zu\n", last_peek - buf); goto fail; } delim = *peek; *peek++ = '\0'; } else { // end of path if (expect == path_delims) { break; } else { ERR("missing ']' at pos %zu\n", peek - buf); goto fail; } } if (expect == path_delims) { if (token) { if (token[0] == '\0') { ERR("empty token at pos %zu\n", peek - buf); goto fail; } parent = cursor; cursor = json_object_get(parent, token); if (!cursor) { if (!json_is_object(parent)) { ERR("object expected at pos %zu\n", peek - buf); goto fail; } if (delim == object_delim) { cursor = json_object(); json_object_set_new(parent, token, cursor); } else { ERR("new array is not allowed at pos %zu\n", peek - buf); goto fail; } } } expect = (delim == array_open ? array_close : path_delims); token = peek; } else if (expect == array_close) { char *endptr; size_t index; parent = cursor; if (!json_is_array(parent)) { ERR("array expected at pos %zu\n", peek - buf); goto fail; } index = strtol(token, &endptr, 0); if (*endptr) { ERR("invalid array index at pos %zu\n", peek - buf); goto fail; } cursor = json_array_get(parent, index); if (!cursor) { ERR("array index out of bound at pos %zu\n", peek - buf); goto fail; } index_saved = index; token = NULL; expect = path_delims; } else { ERR("fatal JSON error at pos %zu\n", peek - buf); goto fail; } } if (token && append) { if(strlen(token) > 0) { json_t* tmp = json_object_get(cursor, token); if(json_is_array(tmp)) { json_array_append(tmp, value); json_object_set(cursor, token, tmp); } else if(json_is_object(tmp) && json_is_object(value) ) { json_object_update(tmp, value); json_object_set(cursor, token, tmp); } else { ERR("JSON array or object expected at pos %zu\n", peek - buf); goto fail; } } else if(json_is_array(cursor)) { json_array_append(cursor, value); } else if(json_is_object(cursor) && json_is_object(value)) { json_object_update(cursor, value); } else { ERR("JSON array or object expected at pos %zu\n", peek - buf); goto fail; } } else if (token && strlen(token) != 0 ) { if (json_is_object(cursor)) { json_object_set(cursor, token, value); } else { ERR("JSON object expected at pos %zu\n", peek - buf); goto fail; } cursor = json_object_get(cursor, token); } else if (index_saved != -1 && json_is_array(parent)) { json_array_set(parent, index_saved, value); cursor = json_array_get(parent, index_saved); } else { ERR("invalid JSON path at pos %zu\n", peek - buf); goto fail; } json_decref(value); jsonp_free(buf); return 0; fail: json_decref(value); jsonp_free(buf); return -1; }