/
Zamar_Terrier
/
TigorEngineWeb
Обзор
Документация
Войти
/
Zamar_Terrier
/
TigorEngineWeb
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
main
src/json_parser.c
662 строки
17 KB
Zamar_Terrier
add json and xml parsers
12 мар 2026, 17:40
12 мар 2026, 17:40
becab97
Код
Авторство
О чём код?
#include "json_parser.h" #include <ctype.h> static int stringify_get_length(const json_value_t* value, int* offset); // Вспомогательные функции static void skip_whitespace(const char** str) { while (isspace(**str)) { (*str)++; } } static char* parse_string(const char** str) { if (**str != '"') return NULL; (*str)++; const char* start = *str; while (**str != '"' && **str != '\0') { if (**str == '\\') { (*str) += 2; // Пропускаем экранированный символ } else { (*str)++; } } if (**str != '"') return NULL; int length = *str - start; char* result = (char*)malloc(length + 1); memcpy(result, start, length); result[length] = '\0'; (*str)++; return result; } static double parse_number(const char** str) { char* end; double value = strtod(*str, &end); *str = end; return value; } // Создание значений json_value_t* json_null() { json_value_t* value = (json_value_t*)malloc(sizeof(json_value_t)); value->type = JSON_NULL; return value; } json_value_t* json_boolean(int boolean) { json_value_t* value = (json_value_t*)malloc(sizeof(json_value_t)); value->type = JSON_BOOL; value->data.boolean = boolean; return value; } json_value_t* json_number(double number) { json_value_t* value = (json_value_t*)malloc(sizeof(json_value_t)); value->type = JSON_NUMBER; value->data.number = number; return value; } json_value_t* json_string(const char* string) { json_value_t* value = (json_value_t*)malloc(sizeof(json_value_t)); value->type = JSON_STRING; value->data.string = string ? strdup(string) : NULL; return value; } json_value_t* json_array() { json_value_t* value = (json_value_t*)malloc(sizeof(json_value_t)); value->type = JSON_ARRAY; value->data.array = NULL; return value; } json_value_t* json_object() { json_value_t* value = (json_value_t*)malloc(sizeof(json_value_t)); value->type = JSON_OBJECT; value->data.object = NULL; return value; } // Работа с массивами int json_array_add(json_value_t* array, json_value_t* value) { if (!array || array->type != JSON_ARRAY || !value) return 0; json_element_t* element = (json_element_t*)malloc(sizeof(json_element_t)); element->value = value; element->next = NULL; if (!array->data.array) { array->data.array = element; } else { json_element_t* current = array->data.array; while (current->next) { current = current->next; } current->next = element; } return 1; } json_value_t* json_array_get(json_value_t* array, int index) { if (!array || array->type != JSON_ARRAY || index < 0) return NULL; json_element_t* current = array->data.array; for (int i = 0; i < index && current; i++) { current = current->next; } return current ? current->value : NULL; } int json_array_size(json_value_t* array) { if (!array || array->type != JSON_ARRAY) return 0; int size = 0; json_element_t* current = array->data.array; while (current) { size++; current = current->next; } return size; } // Работа с объектами json_pair_t* json_object_find_pair(json_value_t* object, const char* key) { if (!object || object->type != JSON_OBJECT || !key) return NULL; json_pair_t* current = object->data.object; while (current) { if (strcmp(current->key, key) == 0) { return current; } current = current->next; } return NULL; } int json_object_set(json_value_t* object, const char* key, json_value_t* value) { if (!object || object->type != JSON_OBJECT || !key || !value) return 0; json_pair_t* pair = json_object_find_pair(object, key); if (pair) { // Обновляем существующее значение json_free(pair->value); pair->value = value; } else { // Создаем новую пару pair = (json_pair_t*)malloc(sizeof(json_pair_t)); pair->key = strdup(key); pair->value = value; pair->next = object->data.object; object->data.object = pair; } return 1; } json_value_t* json_object_get(json_value_t* object, const char* key) { json_pair_t* pair = json_object_find_pair(object, key); return pair ? pair->value : NULL; } // Парсинг static json_value_t* parse_value(const char** str); static json_value_t* parse_array(const char** str) { json_value_t* array = json_array(); (*str)++; // Пропускаем '[' skip_whitespace(str); if (**str == ']') { (*str)++; return array; } while (1) { json_value_t* value = parse_value(str); if (!value) { json_free(array); return NULL; } json_array_add(array, value); skip_whitespace(str); if (**str == ']') { (*str)++; break; } if (**str != ',') { json_free(array); return NULL; } (*str)++; skip_whitespace(str); } return array; } static json_value_t* parse_object(const char** str) { json_value_t* object = json_object(); (*str)++; // Пропускаем '{' skip_whitespace(str); if (**str == '}') { (*str)++; return object; } while (1) { // Парсим ключ skip_whitespace(str); if (**str != '"') { json_free(object); return NULL; } char* key = parse_string(str); if (!key) { json_free(object); return NULL; } skip_whitespace(str); if (**str != ':') { free(key); json_free(object); return NULL; } (*str)++; skip_whitespace(str); // Парсим значение json_value_t* value = parse_value(str); if (!value) { free(key); json_free(object); return NULL; } json_object_set(object, key, value); free(key); skip_whitespace(str); if (**str == '}') { (*str)++; break; } if (**str != ',') { json_free(object); return NULL; } (*str)++; skip_whitespace(str); } return object; } static json_value_t* parse_value(const char** str) { skip_whitespace(str); switch (**str) { case 'n': if (strncmp(*str, "null", 4) == 0) { (*str) += 4; return json_null(); } break; case 't': if (strncmp(*str, "true", 4) == 0) { (*str) += 4; return json_boolean(1); } break; case 'f': if (strncmp(*str, "false", 5) == 0) { (*str) += 5; return json_boolean(0); } break; case '"': return json_string(parse_string(str)); case '[': return parse_array(str); case '{': return parse_object(str); default: if (isdigit(**str) || **str == '-' || **str == '+') { return json_number(parse_number(str)); } break; } return NULL; } json_value_t* json_parse(const char* json_str) { if (!json_str) return NULL; const char* str = json_str; return parse_value(&str); } // Сериализация static int stringify_value(const json_value_t* value, char* buffer, int size, int* offset); static int stringify_string(const char* str, char* buffer, int size, int* offset) { if (*offset >= size) return 0; buffer[(*offset)++] = '"'; if (str) { for (int i = 0; str[i]; i++) { if (*offset >= size) return 0; // Экранирование специальных символов switch (str[i]) { case '\\': if (*offset >= size) return 0; buffer[(*offset)++] = '\\'; buffer[(*offset)++] = '\\'; break; case '"': if (*offset >= size) return 0; buffer[(*offset)++] = '\\'; buffer[(*offset)++] = '"'; break; case '\n': if (*offset >= size) return 0; buffer[(*offset)++] = '\\'; buffer[(*offset)++] = 'n'; break; case '\r': if (*offset >= size) return 0; buffer[(*offset)++] = '\\'; buffer[(*offset)++] = 'r'; break; case '\t': if (*offset >= size) return 0; buffer[(*offset)++] = '\\'; buffer[(*offset)++] = 't'; break; default: buffer[(*offset)++] = str[i]; break; } } } if (*offset >= size) return 0; buffer[(*offset)++] = '"'; return 1; } static int stringify_array(const json_value_t* array, char* buffer, int size, int* offset) { if (*offset >= size) return 0; buffer[(*offset)++] = '['; const json_element_t* current = array->data.array; int first = 1; while (current) { if (!first) { if (*offset >= size) return 0; buffer[(*offset)++] = ','; } if (!stringify_value(current->value, buffer, size, offset)) { return 0; } first = 0; current = current->next; } if (*offset >= size) return 0; buffer[(*offset)++] = ']'; return 1; } static int stringify_object(const json_value_t* object, char* buffer, int size, int* offset) { if (*offset >= size) return 0; buffer[(*offset)++] = '{'; const json_pair_t* current = object->data.object; int first = 1; while (current) { if (!first) { if (*offset >= size) return 0; buffer[(*offset)++] = ','; } if (!stringify_string(current->key, buffer, size, offset)) { return 0; } if (*offset >= size) return 0; buffer[(*offset)++] = ':'; if (!stringify_value(current->value, buffer, size, offset)) { return 0; } first = 0; current = current->next; } if (*offset >= size) return 0; buffer[(*offset)++] = '}'; return 1; } static int stringify_get_length_string(const char* str, int* offset){ (*offset)++; if (str) { for (int i = 0; str[i]; i++) { // Экранирование специальных символов switch (str[i]) { case '\\': (*offset)++; (*offset)++; break; case '"': (*offset)++; (*offset)++; break; case '\n': (*offset)++; (*offset)++; break; case '\r': (*offset)++; (*offset)++; break; case '\t': (*offset)++; (*offset)++; break; default: (*offset)++; break; } } } (*offset)++; return 1; } static int stringify_get_length_array(const json_value_t* array, int* offset){ (*offset)++; const json_element_t* current = array->data.array; int first = 1; while (current) { if (!first) { (*offset)++; } if (!stringify_get_length(current->value, offset)) { return 0; } first = 0; current = current->next; } (*offset)++; return 1; } static int stringify_get_length_object(const json_value_t* object, int* offset){ (*offset)++; const json_pair_t* current = object->data.object; int first = 1; while (current) { if (!first) { (*offset)++; } if (!stringify_get_length_string(current->key, offset)) { return 0; } (*offset)++; if (!stringify_get_length(current->value, offset)) { return 0; } first = 0; current = current->next; } (*offset)++; return 1; } static int stringify_get_length(const json_value_t* value, int* offset) { if (!value) return 0; switch (value->type) { case JSON_NULL: *offset += 4; return 1; case JSON_BOOL: if (value->data.boolean) { *offset += 4; } else { *offset += 5; } return 1; case JSON_NUMBER: { char num_str[64]; int len = snprintf(num_str, sizeof(num_str), "%.17g", value->data.number); *offset += len; if (len == 0) return 0; return 1; } case JSON_STRING: return stringify_get_length_string(value->data.string, offset); case JSON_ARRAY: return stringify_get_length_array(value, offset); case JSON_OBJECT: return stringify_get_length_object(value, offset); default: return 0; } return 0; // Добавлено для предотвращения предупреждений компилятора } static int stringify_value(const json_value_t* value, char* buffer, int size, int* offset) { if (!value) return 0; switch (value->type) { case JSON_NULL: if (*offset >= size) return 0; memcpy(buffer + *offset, "null", 4); *offset += 4; return 1; case JSON_BOOL: if (value->data.boolean) { if (*offset >= size) return 0; memcpy(buffer + *offset, "true", 4); *offset += 4; } else { if (*offset >= size) return 0; memcpy(buffer + *offset, "false", 5); *offset += 5; } return 1; case JSON_NUMBER: { char num_str[64]; int len = snprintf(num_str, sizeof(num_str), "%.17g", value->data.number); if (*offset >= size) return 0; memcpy(buffer + *offset, num_str, len); *offset += len; if (len == 0) return 0; return 1; } case JSON_STRING: return stringify_string(value->data.string, buffer, size, offset); case JSON_ARRAY: return stringify_array(value, buffer, size, offset); case JSON_OBJECT: return stringify_object(value, buffer, size, offset); default: return 0; } return 0; // Добавлено для предотвращения предупреждений компилятора } char* json_stringify(const json_value_t* value) { if (!value) return NULL; // Сначала вычисляем необходимый размер int size = 1; // Для '\0' int offset = 0; // Используем временный буфер для подсчета stringify_get_length(value, &offset); size = offset + 1; // Учитываем нуль-терминатор // Теперь создаем буфер нужного размера char* buffer = (char*)calloc(1, size); if (!buffer) return NULL; offset = 0; stringify_value(value, buffer, size - 1, &offset); // Оставляем место для нуль-терминатора buffer[offset] = '\0'; return buffer; } // Освобождение памяти static void free_element(json_element_t* element) { while (element) { json_element_t* next = element->next; json_free(element->value); free(element); element = next; } } static void free_pair(json_pair_t* pair) { while (pair) { json_pair_t* next = pair->next; free(pair->key); json_free(pair->value); free(pair); pair = next; } } void json_free(json_value_t* value) { if (!value) return; switch (value->type) { case JSON_STRING: free(value->data.string); break; case JSON_ARRAY: free_element(value->data.array); break; case JSON_OBJECT: free_pair(value->data.object); break; default: break; } free(value); }