#include "mcp/json.h" #include #include #include #include "base/allocator.h" static bool reserve(tiny_json_buffer_t *buffer, size_t addition) { size_t needed, capacity; char *resized; if (buffer == NULL) { return false; } if (buffer->failed || addition > SIZE_MAX - buffer->length - 1) { return false; } needed = buffer->length + addition + 1; if (needed <= buffer->capacity) { return true; } capacity = buffer->capacity == 0 ? 256 : buffer->capacity; while (capacity < needed) { if (capacity > SIZE_MAX / 2) { buffer->failed = true; return false; } capacity *= 2; } resized = realloc(buffer->data, capacity); if (resized == NULL) { buffer->failed = true; return false; } buffer->data = resized; buffer->capacity = capacity; return true; } void tiny_json_init(tiny_json_buffer_t *buffer) { if (buffer != NULL) { memset(buffer, 0, sizeof(*buffer)); } } void tiny_json_free(tiny_json_buffer_t *buffer) { if (buffer == NULL) { return; } free(buffer->data); tiny_json_init(buffer); } bool tiny_json_raw_n(tiny_json_buffer_t *buffer, const char *value, size_t length) { if ((value == NULL && length != 0) || !reserve(buffer, length)) { return false; } memcpy(buffer->data + buffer->length, value, length); buffer->length += length; buffer->data[buffer->length] = '\0'; return true; } bool tiny_json_raw(tiny_json_buffer_t *buffer, const char *value) { return value != NULL && tiny_json_raw_n(buffer, value, strlen(value)); } bool tiny_json_string(tiny_json_buffer_t *buffer, const char *value) { const unsigned char *position = (const unsigned char *)value; if (value == NULL || !tiny_json_raw(buffer, "\"")) { return false; } while (*position) { char escaped[7]; if (*position == '"' || *position == '\\') { escaped[0] = '\\'; escaped[1] = (char)*position; escaped[2] = '\0'; if (!tiny_json_raw(buffer, escaped)) { return false; } } else if (*position == '\b') { if (!tiny_json_raw(buffer, "\\b")) { return false; } } else if (*position == '\f') { if (!tiny_json_raw(buffer, "\\f")) { return false; } } else if (*position == '\n') { if (!tiny_json_raw(buffer, "\\n")) { return false; } } else if (*position == '\r') { if (!tiny_json_raw(buffer, "\\r")) { return false; } } else if (*position == '\t') { if (!tiny_json_raw(buffer, "\\t")) { return false; } } else if (*position < 0x20) { snprintf(escaped, sizeof(escaped), "\\u%04x", *position); if (!tiny_json_raw(buffer, escaped)) { return false; } } else { if (!tiny_json_raw_n(buffer, (const char *)position, 1)) { return false; } } ++position; } return tiny_json_raw(buffer, "\""); } bool tiny_json_u64(tiny_json_buffer_t *buffer, unsigned long long value) { char text[32]; snprintf(text, sizeof(text), "%llu", value); return tiny_json_raw(buffer, text); } bool tiny_json_i64(tiny_json_buffer_t *buffer, long long value) { char text[32]; snprintf(text, sizeof(text), "%lld", value); return tiny_json_raw(buffer, text); }