summaryrefslogtreecommitdiff
path: root/src/mcp/json.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mcp/json.c')
-rw-r--r--src/mcp/json.c137
1 files changed, 137 insertions, 0 deletions
diff --git a/src/mcp/json.c b/src/mcp/json.c
new file mode 100644
index 0000000..dcef91b
--- /dev/null
+++ b/src/mcp/json.c
@@ -0,0 +1,137 @@
+#include "mcp/json.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static bool
+reserve(tiny_json_buffer_t *buffer, size_t addition)
+{
+ size_t needed, capacity;
+ char *resized;
+ 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)
+{
+ memset(buffer, 0, sizeof(*buffer));
+}
+void
+tiny_json_free(tiny_json_buffer_t *buffer)
+{
+ free(buffer->data);
+ tiny_json_init(buffer);
+}
+
+bool
+tiny_json_raw_n(tiny_json_buffer_t *buffer, const char *value, size_t length)
+{
+ if (!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 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 (!tiny_json_raw(buffer, "\""))
+ {
+ return false;
+ }
+ while (*position)
+ {
+ char escaped[7];
+ if (*position == '"' || *position == '\\')
+ {
+ escaped[0] = '\\';
+ escaped[1] = (char)*position;
+ escaped[2] = '\0';
+ tiny_json_raw(buffer, escaped);
+ }
+ else if (*position == '\b')
+ {
+ tiny_json_raw(buffer, "\\b");
+ }
+ else if (*position == '\f')
+ {
+ tiny_json_raw(buffer, "\\f");
+ }
+ else if (*position == '\n')
+ {
+ tiny_json_raw(buffer, "\\n");
+ }
+ else if (*position == '\r')
+ {
+ tiny_json_raw(buffer, "\\r");
+ }
+ else if (*position == '\t')
+ {
+ tiny_json_raw(buffer, "\\t");
+ }
+ else if (*position < 0x20)
+ {
+ snprintf(escaped, sizeof(escaped), "\\u%04x", *position);
+ tiny_json_raw(buffer, escaped);
+ }
+ else
+ {
+ tiny_json_raw_n(buffer, (const char *)position, 1);
+ }
+ ++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);
+}