X-Git-Url: https://gerrit.o-ran-sc.org/r/gitweb?a=blobdiff_plain;f=schemaparser%2Fjson.cc;fp=schemaparser%2Fjson.cc;h=5fdff19b35b60a2917e1d66d9fc37a741b84cf23;hb=783f6bfa93c3eed4787bded3c35016952b74b2e3;hp=0000000000000000000000000000000000000000;hpb=5b238b84dd6a6fb77a68f9b37906b465ab08a7fd;p=ric-app%2Fmc.git diff --git a/schemaparser/json.cc b/schemaparser/json.cc new file mode 100644 index 0000000..5fdff19 --- /dev/null +++ b/schemaparser/json.cc @@ -0,0 +1,482 @@ +// Distributed under the MIT license. Copyright (c) 2010, Ivan Vashchaev + + + + +#include +#include "json.h" + +namespace mc_json{ + +// true if character represent a digit +#define IS_DIGIT(c) (c >= '0' && c <= '9') + +// convert string to integer +static char *atoi(char *first, char *last, int *out) +{ + int sign = 1; + if (first != last) + { + if (*first == '-') + { + sign = -1; + ++first; + } + else if (*first == '+') + { + ++first; + } + } + + int result = 0; + for (; first != last && IS_DIGIT(*first); ++first) + { + result = 10 * result + (*first - '0'); + } + *out = result * sign; + + return first; +} + +// convert hexadecimal string to unsigned integer +static char *hatoui(char *first, char *last, unsigned int *out) +{ + unsigned int result = 0; + for (; first != last; ++first) + { + int digit; + if (IS_DIGIT(*first)) + { + digit = *first - '0'; + } + else if (*first >= 'a' && *first <= 'f') + { + digit = *first - 'a' + 10; + } + else if (*first >= 'A' && *first <= 'F') + { + digit = *first - 'A' + 10; + } + else + { + break; + } + result = 16 * result + (unsigned int)digit; + } + *out = result; + + return first; +} + +// convert string to floating point +static char *atof(char *first, char *last, float *out) +{ + // sign + float sign = 1; + if (first != last) + { + if (*first == '-') + { + sign = -1; + ++first; + } + else if (*first == '+') + { + ++first; + } + } + + // integer part + float result = 0; + for (; first != last && IS_DIGIT(*first); ++first) + { + result = 10 * result + (float)(*first - '0'); + } + + // fraction part + if (first != last && *first == '.') + { + ++first; + + float inv_base = 0.1f; + for (; first != last && IS_DIGIT(*first); ++first) + { + result += (float)(*first - '0') * inv_base; + inv_base *= 0.1f; + } + } + + // result w\o exponent + result *= sign; + + // exponent + bool exponent_negative = false; + int exponent = 0; + if (first != last && (*first == 'e' || *first == 'E')) + { + ++first; + + if (*first == '-') + { + exponent_negative = true; + ++first; + } + else if (*first == '+') + { + ++first; + } + + for (; first != last && IS_DIGIT(*first); ++first) + { + exponent = 10 * exponent + (*first - '0'); + } + } + + if (exponent) + { + float power_of_ten = 10; + for (; exponent > 1; exponent--) + { + power_of_ten *= 10; + } + + if (exponent_negative) + { + result /= power_of_ten; + } + else + { + result *= power_of_ten; + } + } + + *out = result; + + return first; +} + +static inline json_value *json_alloc(block_allocator *allocator) +{ + json_value *value = (json_value *)allocator->malloc(sizeof(json_value)); + memset(value, 0, sizeof(json_value)); + return value; +} + +static inline void json_append(json_value *lhs, json_value *rhs) +{ + rhs->parent = lhs; + if (lhs->last_child) + { + lhs->last_child = lhs->last_child->next_sibling = rhs; + } + else + { + lhs->first_child = lhs->last_child = rhs; + } +} + +#define ERROR(it, desc)\ + *error_pos = it;\ + *error_desc = desc;\ + *error_line = 1 - escaped_newlines;\ + for (char *c = it; c != source; --c)\ + if (*c == '\n') ++*error_line;\ + return 0 + +#define CHECK_TOP() if (!top) {ERROR(it, "Unexpected character");} + +json_value *json_parse(char *source, char **error_pos, const char **error_desc, int *error_line, block_allocator *allocator) +{ + json_value *root = 0; + json_value *top = 0; + + char *name = 0; + char *it = source; + + int escaped_newlines = 0; + + while (*it) + { + // skip white space + while (*it == '\x20' || *it == '\x9' || *it == '\xD' || *it == '\xA') + { + ++it; + } + + switch (*it) + { + case '\0': + break; + case '{': + case '[': + { + // create new value + json_value *object = json_alloc(allocator); + + // name + object->name = name; + name = 0; + + // type + object->type = (*it == '{') ? JSON_OBJECT : JSON_ARRAY; + + // skip open character + ++it; + + // set top and root + if (top) + { + json_append(top, object); + } + else if (!root) + { + root = object; + } + else + { + ERROR(it, "Second root. Only one root allowed"); + } + top = object; + } + break; + + case '}': + case ']': + { + if (!top || top->type != ((*it == '}') ? JSON_OBJECT : JSON_ARRAY)) + { + ERROR(it, "Mismatch closing brace/bracket"); + } + + // skip close character + ++it; + + // set top + top = top->parent; + } + break; + + case ':': + if (!top || top->type != JSON_OBJECT) + { + ERROR(it, "Unexpected character"); + } + ++it; + break; + + case ',': + CHECK_TOP(); + ++it; + break; + + case '"': + { + CHECK_TOP(); + + // skip '"' character + ++it; + + char *first = it; + char *last = it; + while (*it) + { + if ((unsigned char)*it < '\x20') + { + ERROR(first, "Control characters not allowed in strings"); + } + else if (*it == '\\') + { + switch (it[1]) + { + case '"': + *last = '"'; + break; + case '\\': + *last = '\\'; + break; + case '/': + *last = '/'; + break; + case 'b': + *last = '\b'; + break; + case 'f': + *last = '\f'; + break; + case 'n': + *last = '\n'; + ++escaped_newlines; + break; + case 'r': + *last = '\r'; + break; + case 't': + *last = '\t'; + break; + case 'u': + { + unsigned int codepoint; + if (hatoui(it + 2, it + 6, &codepoint) != it + 6) + { + ERROR(it, "Bad unicode codepoint"); + } + + if (codepoint <= 0x7F) + { + *last = (char)codepoint; + } + else if (codepoint <= 0x7FF) + { + *last++ = (char)(0xC0 | (codepoint >> 6)); + *last = (char)(0x80 | (codepoint & 0x3F)); + } + else if (codepoint <= 0xFFFF) + { + *last++ = (char)(0xE0 | (codepoint >> 12)); + *last++ = (char)(0x80 | ((codepoint >> 6) & 0x3F)); + *last = (char)(0x80 | (codepoint & 0x3F)); + } + } + it += 4; + break; + default: + ERROR(first, "Unrecognized escape sequence"); + } + + ++last; + it += 2; + } + else if (*it == '"') + { + *last = 0; + ++it; + break; + } + else + { + *last++ = *it++; + } + } + + if (!name && top->type == JSON_OBJECT) + { + // field name in object + name = first; + } + else + { + // new string value + json_value *object = json_alloc(allocator); + + object->name = name; + name = 0; + + object->type = JSON_STRING; + object->string_value = first; + + json_append(top, object); + } + } + break; + + case 'n': + case 't': + case 'f': + { + CHECK_TOP(); + + // new null/bool value + json_value *object = json_alloc(allocator); + + object->name = name; + name = 0; + + // null + if (it[0] == 'n' && it[1] == 'u' && it[2] == 'l' && it[3] == 'l') + { + object->type = JSON_NULL; + it += 4; + } + // true + else if (it[0] == 't' && it[1] == 'r' && it[2] == 'u' && it[3] == 'e') + { + object->type = JSON_BOOL; + object->int_value = 1; + it += 4; + } + // false + else if (it[0] == 'f' && it[1] == 'a' && it[2] == 'l' && it[3] == 's' && it[4] == 'e') + { + object->type = JSON_BOOL; + object->int_value = 0; + it += 5; + } + else + { + ERROR(it, "Unknown identifier"); + } + + json_append(top, object); + } + break; + + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + CHECK_TOP(); + + // new number value + json_value *object = json_alloc(allocator); + + object->name = name; + name = 0; + + object->type = JSON_INT; + + char *first = it; + while (*it != '\x20' && *it != '\x9' && *it != '\xD' && *it != '\xA' && *it != ',' && *it != ']' && *it != '}') + { + if (*it == '.' || *it == 'e' || *it == 'E') + { + object->type = JSON_FLOAT; + } + ++it; + } + + if (object->type == JSON_INT && atoi(first, it, &object->int_value) != it) + { + ERROR(first, "Bad integer number"); + } + + if (object->type == JSON_FLOAT && atof(first, it, &object->float_value) != it) + { + ERROR(first, "Bad float number"); + } + + json_append(top, object); + } + break; + + default: + ERROR(it, "Unexpected character"); + } + } + + if (top) + { + ERROR(it, "Not all objects/arrays have been properly closed"); + } + + return root; +} + +} // end namespace mc_json