Microsoft Azure IoTHub client libraries
Dependents: sht15_remote_monitoring RobotArmDemo iothub_client_sample_amqp f767zi_mqtt ... more
This library implements the Microsoft Azure IoTHub client library. The code is replicated from https://github.com/Azure/azure-iot-sdks
Diff: parson.c
- Revision:
- 61:8b85a4e797cf
- Parent:
- 56:fdda9c1244e4
- Child:
- 75:86205ca63a59
--- a/parson.c Fri Feb 24 14:00:43 2017 -0800 +++ b/parson.c Fri Mar 10 11:47:36 2017 -0800 @@ -1,6 +1,6 @@ /* Parson ( http://kgabis.github.com/parson/ ) - Copyright (c) 2012 - 2016 Krzysztof Gabis + Copyright (c) 2012 - 2017 Krzysztof Gabis Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -33,6 +33,11 @@ #include <string.h> #include <ctype.h> #include <math.h> +#include <errno.h> + +/* Apparently sscanf is not implemented in some "standard" libraries, so don't use it, if you + * don't have to. */ +#define sscanf THINK_TWICE_ABOUT_USING_SSCANF #define STARTING_CAPACITY 15 #define ARRAY_MAX_CAPACITY 122880 /* 15*(2^13) */ @@ -64,11 +69,13 @@ } JSON_Value_Value; struct json_value_t { - JSON_Value_Type type; - JSON_Value_Value value; + JSON_Value *parent; + JSON_Value_Type type; + JSON_Value_Value value; }; struct json_object_t { + JSON_Value *wrapping_value; char **names; JSON_Value **values; size_t count; @@ -76,6 +83,7 @@ }; struct json_array_t { + JSON_Value *wrapping_value; JSON_Value **items; size_t count; size_t capacity; @@ -86,21 +94,22 @@ static void remove_comments(char *string, const char *start_token, const char *end_token); static char * parson_strndup(const char *string, size_t n); static char * parson_strdup(const char *string); -static int is_utf16_hex(const unsigned char *string); +static int hex_char_to_int(char c); +static int parse_utf16_hex(const char *string, unsigned int *result); static int num_bytes_in_utf8_sequence(unsigned char c); static int verify_utf8_sequence(const unsigned char *string, int *len); static int is_valid_utf8(const char *string, size_t string_len); static int is_decimal(const char *string, size_t length); /* JSON Object */ -static JSON_Object * json_object_init(void); +static JSON_Object * json_object_init(JSON_Value *wrapping_value); static JSON_Status json_object_add(JSON_Object *object, const char *name, JSON_Value *value); static JSON_Status json_object_resize(JSON_Object *object, size_t new_capacity); static JSON_Value * json_object_nget_value(const JSON_Object *object, const char *name, size_t n); static void json_object_free(JSON_Object *object); /* JSON Array */ -static JSON_Array * json_array_init(void); +static JSON_Array * json_array_init(JSON_Value *wrapping_value); static JSON_Status json_array_add(JSON_Array *array, JSON_Value *value); static JSON_Status json_array_resize(JSON_Array *array, size_t new_capacity); static void json_array_free(JSON_Array *array); @@ -110,7 +119,7 @@ /* Parser */ static JSON_Status skip_quotes(const char **string); -static int parse_utf_16(const char **unprocessed, char **processed); +static int parse_utf16(const char **unprocessed, char **processed); static char * process_string(const char *input, size_t len); static char * get_quoted_string(const char **string); static JSON_Value * parse_object_value(const char **string, size_t nesting); @@ -142,8 +151,31 @@ return parson_strndup(string, strlen(string)); } -static int is_utf16_hex(const unsigned char *s) { - return isxdigit(s[0]) && isxdigit(s[1]) && isxdigit(s[2]) && isxdigit(s[3]); +static int hex_char_to_int(char c) { + if (c >= '0' && c <= '9') { + return c - '0'; + } else if (c >= 'a' && c <= 'f') { + return c - 'a' + 10; + } else if (c >= 'A' && c <= 'F') { + return c - 'A' + 10; + } + return -1; +} + +static int parse_utf16_hex(const char *s, unsigned int *result) { + int x1, x2, x3, x4; + if (s[0] == '\0' || s[1] == '\0' || s[2] == '\0' || s[3] == '\0') { + return 0; + } + x1 = hex_char_to_int(s[0]); + x2 = hex_char_to_int(s[1]); + x3 = hex_char_to_int(s[2]); + x4 = hex_char_to_int(s[3]); + if (x1 == -1 || x2 == -1 || x3 == -1 || x4 == -1) { + return 0; + } + *result = (unsigned int)((x1 << 12) | (x2 << 8) | (x3 << 4) | x4); + return 1; } static int num_bytes_in_utf8_sequence(unsigned char c) { @@ -222,10 +254,11 @@ if (length > 2 && !strncmp(string, "-0", 2) && string[2] != '.') { return 0; } - while (length--) + while (length--) { if (strchr("xX", string[length])) { return 0; } + } return 1; } @@ -298,11 +331,12 @@ } /* JSON Object */ -static JSON_Object * json_object_init(void) { +static JSON_Object * json_object_init(JSON_Value *wrapping_value) { JSON_Object *new_obj = (JSON_Object*)parson_malloc(sizeof(JSON_Object)); - if (!new_obj) { + if (new_obj == NULL) { return NULL; } + new_obj->wrapping_value = wrapping_value; new_obj->names = (char**)NULL; new_obj->values = (JSON_Value**)NULL; new_obj->capacity = 0; @@ -332,6 +366,7 @@ if (object->names[index] == NULL) { return JSONFailure; } + value->parent = json_object_get_wrapping_value(object); object->values[index] = value; object->count++; return JSONSuccess; @@ -346,18 +381,15 @@ new_capacity == 0) { return JSONFailure; /* Shouldn't happen */ } - temp_names = (char**)parson_malloc(new_capacity * sizeof(char*)); if (temp_names == NULL) { return JSONFailure; } - temp_values = (JSON_Value**)parson_malloc(new_capacity * sizeof(JSON_Value*)); if (temp_values == NULL) { parson_free(temp_names); return JSONFailure; } - if (object->names != NULL && object->values != NULL && object->count > 0) { memcpy(temp_names, object->names, object->count * sizeof(char*)); memcpy(temp_values, object->values, object->count * sizeof(JSON_Value*)); @@ -385,9 +417,10 @@ } static void json_object_free(JSON_Object *object) { - while(object->count--) { - parson_free(object->names[object->count]); - json_value_free(object->values[object->count]); + size_t i; + for (i = 0; i < object->count; i++) { + parson_free(object->names[i]); + json_value_free(object->values[i]); } parson_free(object->names); parson_free(object->values); @@ -395,11 +428,12 @@ } /* JSON Array */ -static JSON_Array * json_array_init(void) { +static JSON_Array * json_array_init(JSON_Value *wrapping_value) { JSON_Array *new_array = (JSON_Array*)parson_malloc(sizeof(JSON_Array)); - if (!new_array) { + if (new_array == NULL) { return NULL; } + new_array->wrapping_value = wrapping_value; new_array->items = (JSON_Value**)NULL; new_array->capacity = 0; new_array->count = 0; @@ -416,6 +450,7 @@ return JSONFailure; } } + value->parent = json_array_get_wrapping_value(array); array->items[array->count] = value; array->count++; return JSONSuccess; @@ -440,8 +475,10 @@ } static void json_array_free(JSON_Array *array) { - while (array->count--) - json_value_free(array->items[array->count]); + size_t i; + for (i = 0; i < array->count; i++) { + json_value_free(array->items[i]); + } parson_free(array->items); parson_free(array); } @@ -452,6 +489,7 @@ if (!new_value) { return NULL; } + new_value->parent = NULL; new_value->type = JSONString; new_value->value.string = string; return new_value; @@ -478,16 +516,18 @@ return JSONSuccess; } -static int parse_utf_16(const char **unprocessed, char **processed) { +static int parse_utf16(const char **unprocessed, char **processed) { unsigned int cp, lead, trail; + int parse_succeeded = 0; char *processed_ptr = *processed; const char *unprocessed_ptr = *unprocessed; unprocessed_ptr++; /* skips u */ - if (!is_utf16_hex((const unsigned char*)unprocessed_ptr) || sscanf(unprocessed_ptr, "%4x", &cp) == EOF) { + parse_succeeded = parse_utf16_hex(unprocessed_ptr, &cp); + if (!parse_succeeded) { return JSONFailure; } if (cp < 0x80) { - *processed_ptr = cp; /* 0xxxxxxx */ + *processed_ptr = (char)cp; /* 0xxxxxxx */ } else if (cp < 0x800) { *processed_ptr++ = ((cp >> 6) & 0x1F) | 0xC0; /* 110xxxxx */ *processed_ptr = ((cp ) & 0x3F) | 0x80; /* 10xxxxxx */ @@ -498,11 +538,12 @@ } else if (cp >= 0xD800 && cp <= 0xDBFF) { /* lead surrogate (0xD800..0xDBFF) */ lead = cp; unprocessed_ptr += 4; /* should always be within the buffer, otherwise previous sscanf would fail */ - if (*unprocessed_ptr++ != '\\' || *unprocessed_ptr++ != 'u' || /* starts with \u? */ - !is_utf16_hex((const unsigned char*)unprocessed_ptr) || - sscanf(unprocessed_ptr, "%4x", &trail) == EOF || - trail < 0xDC00 || trail > 0xDFFF) { /* valid trail surrogate? (0xDC00..0xDFFF) */ - return JSONFailure; + if (*unprocessed_ptr++ != '\\' || *unprocessed_ptr++ != 'u') { + return JSONFailure; + } + parse_succeeded = parse_utf16_hex(unprocessed_ptr, &trail); + if (!parse_succeeded || trail < 0xDC00 || trail > 0xDFFF) { /* valid trail surrogate? (0xDC00..0xDFFF) */ + return JSONFailure; } cp = ((((lead-0xD800)&0x3FF)<<10)|((trail-0xDC00)&0x3FF))+0x010000; *processed_ptr++ = (((cp >> 18) & 0x07) | 0xF0); /* 11110xxx */ @@ -541,7 +582,7 @@ case 'r': *output_ptr = '\r'; break; case 't': *output_ptr = '\t'; break; case 'u': - if (parse_utf_16(&input_ptr, &output_ptr) == JSONFailure) { + if (parse_utf16(&input_ptr, &output_ptr) == JSONFailure) { goto error; } break; @@ -730,15 +771,14 @@ static JSON_Value * parse_number_value(const char **string) { char *end; - double number = strtod(*string, &end); - JSON_Value *output_value; - if (is_decimal(*string, end - *string)) { - *string = end; - output_value = json_value_init_number(number); - } else { - output_value = NULL; + double number = 0; + errno = 0; + number = strtod(*string, &end); + if (errno || !is_decimal(*string, end - *string)) { + return NULL; } - return output_value; + *string = end; + return json_value_init_number(number); } static JSON_Value * parse_null_value(const char **string) { @@ -813,6 +853,9 @@ } for (i = 0; i < count; i++) { key = json_object_get_name(object, i); + if (key == NULL) { + return -1; + } if (is_pretty) { APPEND_INDENT(level+1); } @@ -851,6 +894,9 @@ return written_total; case JSONString: string = json_value_get_string(value); + if (string == NULL) { + return -1; + } written = json_serialize_string(string, buf); if (written < 0) { return -1; @@ -1101,6 +1147,10 @@ return object->values[index]; } +JSON_Value *json_object_get_wrapping_value(const JSON_Object *object) { + return object->wrapping_value; +} + int json_object_has_value (const JSON_Object *object, const char *name) { return json_object_get_value(object, name) != NULL; } @@ -1151,6 +1201,10 @@ return array ? array->count : 0; } +JSON_Value * json_array_get_wrapping_value(const JSON_Array *array) { + return array->wrapping_value; +} + /* JSON Value API */ JSON_Value_Type json_value_get_type(const JSON_Value *value) { return value ? value->type : JSONError; @@ -1176,15 +1230,17 @@ return json_value_get_type(value) == JSONBoolean ? value->value.boolean : -1; } +JSON_Value * json_value_get_parent (const JSON_Value *value) { + return value ? value->parent : NULL; +} + void json_value_free(JSON_Value *value) { switch (json_value_get_type(value)) { case JSONObject: json_object_free(value->value.object); break; case JSONString: - if (value->value.string) { - parson_free(value->value.string); - } + parson_free(value->value.string); break; case JSONArray: json_array_free(value->value.array); @@ -1200,8 +1256,9 @@ if (!new_value) { return NULL; } + new_value->parent = NULL; new_value->type = JSONObject; - new_value->value.object = json_object_init(); + new_value->value.object = json_object_init(new_value); if (!new_value->value.object) { parson_free(new_value); return NULL; @@ -1214,8 +1271,9 @@ if (!new_value) { return NULL; } + new_value->parent = NULL; new_value->type = JSONArray; - new_value->value.array = json_array_init(); + new_value->value.array = json_array_init(new_value); if (!new_value->value.array) { parson_free(new_value); return NULL; @@ -1250,6 +1308,7 @@ if (!new_value) { return NULL; } + new_value->parent = NULL; new_value->type = JSONNumber; new_value->value.number = number; return new_value; @@ -1260,6 +1319,7 @@ if (!new_value) { return NULL; } + new_value->parent = NULL; new_value->type = JSONBoolean; new_value->value.boolean = boolean ? 1 : 0; return new_value; @@ -1270,6 +1330,7 @@ if (!new_value) { return NULL; } + new_value->parent = NULL; new_value->type = JSONNull; return new_value; } @@ -1332,6 +1393,9 @@ return json_value_init_number(json_value_get_number(value)); case JSONString: temp_string = json_value_get_string(value); + if (temp_string == NULL) { + return NULL; + } temp_string_copy = parson_strdup(temp_string); if (temp_string_copy == NULL) { return NULL; @@ -1494,10 +1558,11 @@ } JSON_Status json_array_replace_value(JSON_Array *array, size_t ix, JSON_Value *value) { - if (array == NULL || value == NULL || ix >= json_array_get_count(array)) { + if (array == NULL || value == NULL || value->parent != NULL || ix >= json_array_get_count(array)) { return JSONFailure; } json_value_free(json_array_get_value(array, ix)); + value->parent = json_array_get_wrapping_value(array); array->items[ix] = value; return JSONSuccess; } @@ -1563,7 +1628,7 @@ } JSON_Status json_array_append_value(JSON_Array *array, JSON_Value *value) { - if (array == NULL || value == NULL) { + if (array == NULL || value == NULL || value->parent != NULL) { return JSONFailure; } return json_array_add(array, value); @@ -1620,7 +1685,7 @@ JSON_Status json_object_set_value(JSON_Object *object, const char *name, JSON_Value *value) { size_t i = 0; JSON_Value *old_value; - if (object == NULL || name == NULL || value == NULL) { + if (object == NULL || name == NULL || value == NULL || value->parent != NULL) { return JSONFailure; } old_value = json_object_get_value(object, name); @@ -1628,6 +1693,7 @@ json_value_free(old_value); for (i = 0; i < json_object_get_count(object); i++) { if (strcmp(object->names[i], name) == 0) { + value->parent = json_object_get_wrapping_value(object); object->values[i] = value; return JSONSuccess; } @@ -1892,6 +1958,9 @@ case JSONString: a_string = json_value_get_string(a); b_string = json_value_get_string(b); + if (a_string == NULL || b_string == NULL) { + return 0; /* shouldn't happen */ + } return strcmp(a_string, b_string) == 0; case JSONBoolean: return json_value_get_boolean(a) == json_value_get_boolean(b);