diff --git a/src/buffer.c b/src/buffer.c new file mode 100644 index 0000000..1238570 --- /dev/null +++ b/src/buffer.c @@ -0,0 +1,56 @@ +/* This software is licensed by the MIT License, see LICENSE file */ +/* Copyright © 2022 Gregory Lirent */ + +#include "buffer.h" + +static inline void libcjsonp_builtin_write8(buffer_t* x, unsigned char s) { + *(x->ptr++) = s; + --x->c; +} + +static inline void libcjsonp_builtin_wrap8_8(buffer_t* x, unsigned char s) { + *(x->ptr++) = '\\'; + *(x->ptr++) = s; + x->c -= 2; +} + +static inline void libcjsonp_builtin_wrap8_e16(buffer_t* x, unsigned char s) { + *(x->ptr++) = '\\'; + *(x->ptr++) = 'u'; + *(x->ptr++) = '0'; + *(x->ptr++) = '0'; + + if ((s&0xf0) < 0xa0) { + *(x->ptr++) = 0x30 + (s>>4); + } else *(x->ptr++) = 0x57 + (s>>4); + + if ((s&0x0f) < 0x0a) { + *(x->ptr++) = 0x30 + (s&0x0f); + } else *(x->ptr++) = 0x57 + (s&0x0f); + + x->c -= 6; +} + +void libcjsonp_builtin_buffer_write_and_wrap(buffer_t* x, const char* s) { + unsigned char* v = (void*)s; + + buffer_check_size(x, 7); + libcjsonp_builtin_write8(x, '"'); + + while (*v) { + if (*v < 0x20 || *v == 0x7f) switch (*v) { + case 0x09: libcjsonp_builtin_wrap8_8 (x, 't'); break; + case 0x0a: libcjsonp_builtin_wrap8_8 (x, 'n'); break; + case 0x0d: libcjsonp_builtin_wrap8_8 (x, 'r'); break; + default: libcjsonp_builtin_wrap8_e16(x, *v); break; + } else if (*v == '\\') libcjsonp_builtin_wrap8_8(x, '\\'); + else if (*v == '"') libcjsonp_builtin_wrap8_8(x, '"'); + else libcjsonp_builtin_write8 (x, *v); + + ++v; + + buffer_check_size(x, 6); + } + + buffer_write_char(x, '"'); +} diff --git a/src/buffer.h b/src/buffer.h new file mode 100644 index 0000000..6b5c8a7 --- /dev/null +++ b/src/buffer.h @@ -0,0 +1,71 @@ +/* This software is licensed by the MIT License, see LICENSE file */ +/* Copyright © 2022 Gregory Lirent */ + +#include + +#include "include.h" + +#ifndef LIBCJSONP_SRC_BUFFER_H +#define LIBCJSONP_SRC_BUFFER_H + +#define buffer_block 1024 + +typedef struct { + char* mem; + char* ptr; + size_t n; + size_t c; +} buffer_t; + +static_assert(offsetof(vtype_string, buffer) == offsetof(buffer_t, mem), "Implementation assert"); + +#define buffer_write_and_wrap libcjsonp_builtin_buffer_write_and_wrap +#define buffer_check_size libcjsonp_builtin_buffer_check_size +#define buffer_write_indent libcjsonp_builtin_buffer_write_indent +#define buffer_write_char libcjsonp_builtin_buffer_write_char +#define buffer_write libcjsonp_builtin_buffer_write + +extern void libcjsonp_builtin_buffer_write_and_wrap(buffer_t* x, const char* s); +inline void libcjsonp_builtin_buffer_check_size (buffer_t* x, size_t need) Always_inline__; +inline void libcjsonp_builtin_buffer_write_indent (buffer_t* x, indent_t* indent, size_t level) Always_inline__; +inline void libcjsonp_builtin_buffer_write_char (buffer_t* x, char c) Always_inline__; +inline void libcjsonp_builtin_buffer_write (buffer_t* x, const char* v) Always_inline__; + +inline void libcjsonp_builtin_buffer_check_size(buffer_t* x, size_t need) { + while (x->c < need) { + x->mem = libcdsb_realloc(x->mem, x->n + buffer_block); + x->ptr = x->mem + (x->n - x->c); + x->n += buffer_block; + x->c += buffer_block; + } +} + +inline void libcjsonp_builtin_buffer_write_char(buffer_t* x, char c) { + + buffer_check_size(x, 1); + + *(x->ptr++) = c; + --x->c; +} + +inline void libcjsonp_builtin_buffer_write(buffer_t* x, const char* v) { + size_t n = libcdsb_strlen(v); + + buffer_check_size(x, n); + + x->ptr = memcpy(x->ptr, v, n) + n; + x->c -= n; +} + +inline void libcjsonp_builtin_buffer_write_indent(buffer_t* x, indent_t* indent, size_t level) { + + libcjsonp_builtin_buffer_check_size(x, indent->nmemb * level); + + while (level--) { + memcpy(x->ptr, indent->indent, indent->nmemb); + x->ptr += indent->nmemb; + x->c -= indent->nmemb; + } +} + +#endif /* LIBCJSONP_SRC_BUFFER_H */ diff --git a/src/include.h b/src/include.h new file mode 100644 index 0000000..5a3f811 --- /dev/null +++ b/src/include.h @@ -0,0 +1,43 @@ +/* This software is licensed by the MIT License, see LICENSE file */ +/* Copyright © 2022 Gregory Lirent */ + +#include + +#include "../include/jsonp.h" +#include "../include/bits/string.h" + +#ifndef LIBCJSONP_SRC_INCLUDE_H +#define LIBCJSONP_SRC_INCLUDE_H + +typedef struct { + char* indent; + size_t nmemb; +} indent_t; + +typedef struct { + union { + vtype_bool b; + vtype_int8 s8; + vtype_int16 s16; + vtype_int32 s32; + vtype_int64 s64; + vtype_uint8 u8; + vtype_uint16 u16; + vtype_uint32 u32; + vtype_uint64 u64; + vtype_ldouble ldbl; + vtype_map map; + vtype_list list; + vtype_string str; + vtype_pointer ptr; + } value[1]; + + vtype type; +} value_t; + +extern indent_t LIBCJSONP_BUILTIN_WITHOUT_INDENT[1]; + +extern const char* libcjsonp_builtin_fetch_number(value_t* x, const char *s, bool is_float); + + +#endif /* LIBCJSONP_SRC_INCLUDE_H */ diff --git a/src/memory.c b/src/memory.c new file mode 100644 index 0000000..8634d46 --- /dev/null +++ b/src/memory.c @@ -0,0 +1,43 @@ +/* This software is licensed by the MIT License, see LICENSE file */ +/* Copyright © 2022 Gregory Lirent */ + +#include "include.h" + +extern const size_t *LIBCDSB_BUILTIN_VTYPE_SIZES; + +indent_t LIBCJSONP_BUILTIN_WITHOUT_INDENT[1] = {{ .indent = 0, .nmemb = 0 }}; + +void libcjsonp_json_init(json_t* x, void* v, vtype t, bool attach) { + value_t value; + + if (!attach) { + switch (t) { + default: break; + case VTYPE_STRING: string_copy_init((void*)value.value, v); v = value.value; break; + case VTYPE_MAP: map_copy_init((void*)value.value, v); v = value.value; break; + case VTYPE_ARRAY: array_copy_init((void*)value.value, v); v = value.value; break; + case VTYPE_LIST: list_copy_init((void*)value.value, v); v = value.value; break; + case VTYPE_SET: vset_copy_init((void*)value.value, v); v = value.value; break; + case VTYPE_DICT: dict_copy_init((void*)value.value, v); v = value.value; break; + } + } + + x->data = libcdsb_memndup(v, LIBCDSB_BUILTIN_VTYPE_SIZES[t]); + x->type = t; +} + + +void json_free(json_t* x) { + switch (x->type) { + default: break; + case VTYPE_STRING: string_free(x->data); break; + case VTYPE_MAP: map_free(x->data); break; + case VTYPE_ARRAY: array_free(x->data); break; + case VTYPE_LIST: list_free(x->data); break; + case VTYPE_SET: vset_free(x->data); break; + case VTYPE_DICT: dict_free(x->data); break; + } + + libcdsb_free(x->data); + memset(x, 0, sizeof(*x)); +} diff --git a/src/string.c b/src/string.c new file mode 100644 index 0000000..b14cf73 --- /dev/null +++ b/src/string.c @@ -0,0 +1,178 @@ +/* This software is licensed by the MIT License, see LICENSE file */ +/* Copyright © 2022 Gregory Lirent */ + +#include "../modules/libcdsb/modules/libunic/include.h" +#include "buffer.h" + +#define unescape8 libcjsonp_builtin_unescape8 +#define unescape16 libcjsonp_builtin_unescape32 +#define unescape32 libcjsonp_builtin_unescape16 + +static bool libcjsonp_builtin_unescape8(unsigned char* x, const char* s) { + unsigned char c[2]; + + if (*s > 0x39) { + c[0] = (*s|0x20); + + if (c[0] < 0x61 || c[0] > 0x66) + return false; + + c[0] -= 0x57; + } else if (*s >= 0x30) { + c[0] = *s&0x0f; + } else return false; + + if (*++s > 0x39) { + c[1] = (*s|0x20); + + if (c[1] < 0x61 || c[1] > 0x66) + return false; + + c[1] -= 0x57; + } else if (*s >= 0x30) { + c[1] |= *s&0x0f; + } else return false; + + *x = (c[0]<<4) | c[1]; + + return true; +} + +static void libcjsonp_builtin_unescape32(char** x, char** s) { + + vtype_uint32 uc; + size_t n; + bool f; + char* p; + + n = 4; + uc = 0; + f = 0; + p = *s; + + while (n--) { + unsigned char c; + + f |= !libcjsonp_builtin_unescape8(&c, p); + uc = c | uc >> 8; + + p += 2; + } + + if (!f) { + *s = p; + if (!f && (p = tochar_unicode(*x, uc))) + *x = p; + } else --*s; +} + +static void libcjsonp_builtin_unescape16(char** x, char** s) { + + vtype_uint32 uc; + char* p; + bool f; + unsigned char c[2]; + + f = 0; + p = *s; + + f |= !libcjsonp_builtin_unescape8(c, p); + f |= !libcjsonp_builtin_unescape8(c + 1, p += 2); + + p += 2; + + if (f) goto bad_; + + if (*c < 0xd8 || *c >= 0xdc) { + uc = *c << 8 | c[1]; + goto end_; + } + + if ((p)[0] != '\\' || (p)[1] != 'u') + return; + + p += 2; + + uc = (c[0]&0x03) << 18; + uc |= c[1] << 10; + + f |= !libcjsonp_builtin_unescape8(c, p); + f |= !libcjsonp_builtin_unescape8(c + 1, p += 2); + + p += 2; + + if (!f) { + if (*c < 0xdc || *c > 0xdf) + goto bad_; + + uc |= (c[0]&0x03)<<8; + uc |= c[1]; + uc += 0x010000; + + end_: *s = p; + if ((p = tochar_unicode(*x, uc))) + *x = p; + } else bad_: --*s; +} + +/*#####################################################################################################################*/ + +void libcjsonp_string_unescape(vtype_string* x) { + + char *p, *c; + + if (!x->buffer || !*x->buffer) + return; + + p = c = x->buffer; + + while (*p) { + + if (*p == '\\') { + switch (*(++p)) { + default : *(c++) = *p; break; + case 'n': *(c++) = '\n'; break; + case 'r': *(c++) = '\r'; break; + case 'e': *(c++) = '\e'; break; + case 'v': *(c++) = '\v'; break; + case 't': *(c++) = '\t'; break; + case 'a': *(c++) = '\a'; break; + + case 'x': if (unescape8((void*)c, p + 1)) { + ++c; + p += 3; + } goto end_loop_; + case 'U': ++p; unescape32(&c, &p); goto end_loop_; + case 'u': ++p; unescape16(&c, &p); goto end_loop_; + } + + } else if (p != c) { + *(c++) = *p; + } else ++c; + + ++p; + + end_loop_:{} + } + + *c = 0; +} + + +void libcjsonp_string_escape(vtype_string* s) { + buffer_t x; + + if (!s->buffer || !*s->buffer) + return; + + memset(&x, 0, sizeof(x)); + + buffer_write_and_wrap(&x, s->buffer); + + x.n = (x.ptr - x.mem) - 1; + s->buffer = libcdsb_realloc(s->buffer, x.n); + x.ptr[-1] = 0; + + memcpy(s->buffer, x.mem + 1, x.n); + libcdsb_free(x.mem); +}