| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760 |
- #include "iron_armpack.h"
- #include <stdlib.h>
- #include <stdbool.h>
- #include <string.h>
- #include "iron_gc.h"
- static const int PTR_SIZE = 8;
- static uint32_t di; // Decoded index
- static uint32_t ei; // Encoded index
- static uint32_t bottom; // Decoded bottom
- static uint8_t *decoded;
- static uint8_t *encoded;
- static uint32_t capacity;
- static uint32_t array_count;
- static uint32_t string_length;
- static void read_store();
- static inline uint64_t pad(int di, int n) {
- return (n - (di % n)) % n;
- }
- static void store_u8(uint8_t u8) {
- *(uint8_t *)(decoded + di) = u8;
- di += 1;
- }
- static void store_i16(int16_t i16) {
- di += pad(di, 2);
- *(int16_t *)(decoded + di) = i16;
- di += 2;
- }
- static void store_u32(uint32_t u32) {
- di += pad(di, 4);
- *(uint32_t *)(decoded + di) = u32;
- di += 4;
- }
- static void store_i32(int32_t i32) {
- di += pad(di, 4);
- *(int32_t *)(decoded + di) = i32;
- di += 4;
- }
- static void store_f32(float f32) {
- di += pad(di, 4);
- *(float *)(decoded + di) = f32;
- di += 4;
- }
- static void store_ptr(uint32_t ptr) {
- di += pad(di, PTR_SIZE);
- *(uint64_t *)(decoded + di) = (uint64_t)decoded + (uint64_t)ptr;
- di += PTR_SIZE;
- }
- static void store_ptr_abs(void *ptr) {
- di += pad(di, PTR_SIZE);
- *(uint64_t *)(decoded + di) = (uint64_t)ptr;
- di += PTR_SIZE;
- }
- static void store_string_bytes(char *str) {
- for (int i = 0; i < string_length; ++i) {
- store_u8(str[i]);
- }
- store_u8('\0');
- }
- static void store_string(char *str) {
- // Put string at the bottom and store a pointer to it
- store_ptr(bottom);
- uint32_t _di = di;
- di = bottom;
- store_string_bytes(str);
- bottom = pad(di, PTR_SIZE) + di;
- di = _di;
- }
- static uint8_t read_u8() {
- uint8_t u8 = *(uint8_t *)(encoded + ei);
- ei += 1;
- return u8;
- }
- static int16_t read_i16() {
- int16_t i16 = *(int16_t *)(encoded + ei);
- ei += 2;
- return i16;
- }
- static int32_t read_i32() {
- int32_t i32 = *(int32_t *)(encoded + ei);
- ei += 4;
- return i32;
- }
- static uint32_t read_u32() {
- uint32_t u32 = *(uint32_t *)(encoded + ei);
- ei += 4;
- return u32;
- }
- static float read_f32() {
- float f32 = *(float *)(encoded + ei);
- ei += 4;
- return f32;
- }
- static char *read_string() {
- string_length = read_u32();
- char *str = (char *)(encoded + ei);
- ei += string_length;
- return str;
- }
- static uint32_t traverse(int di, bool count_arrays) {
- uint8_t flag = read_u8();
- switch (flag) {
- case 0xc0: // NULL
- return pad(di, PTR_SIZE) + PTR_SIZE;
- case 0xc2: // false
- return 1;
- case 0xc3: // true
- return 1;
- case 0xca: // f32
- ei += 4;
- return pad(di, 4) + 4;
- case 0xd2: // i32
- ei += 4;
- return pad(di, 4) + 4;
- case 0xdf: { // map
- uint32_t len = 0;
- int count = read_i32();
- for (int i = 0; i < count; ++i) {
- read_u8(); // 0xdb string
- read_string(); // key
- len += traverse(di + len, count_arrays); // value
- }
- len += pad(di + len, PTR_SIZE) + PTR_SIZE; // void *_
- return len;
- }
- case 0xdd: { // array
- uint32_t len = 0;
- uint32_t count = read_u32();
- uint8_t flag2 = read_u8();
- switch (flag2) {
- case 0xca: // Typed f32
- ei += 4 * count;
- len += 4 * count;
- break;
- case 0xd2: // Typed i32
- ei += 4 * count;
- len += 4 * count;
- break;
- case 0xd1: // Typed i16
- ei += 2 * count;
- len += 2 * count;
- break;
- case 0xc4: // Typed u8
- ei += count;
- len += count;
- break;
- case 0xc2: // Bool array
- ei -= 1;
- ei += count;
- len += count;
- break;
- case 0xc3: // Bool array
- ei -= 1;
- ei += count;
- len += count;
- break;
- default: // Dynamic (type (array / map / string) - value)
- ei -= 1; // Undo flag2 read
- for (uint32_t j = 0; j < count; ++j) {
- len += traverse(0, count_arrays);
- }
- }
- len += 32; // buffer ptr, length, capacity + align?
- if (!count_arrays) {
- len = 0;
- }
- // ptr (to array_t)
- len += pad(di, PTR_SIZE) + PTR_SIZE;
- return len;
- }
- case 0xdb: { // string
- uint32_t len = read_u32(); // string_length
- ei += len;
- len += 1; // '\0'
- if (!count_arrays) {
- len = 0;
- }
- len += pad(di, PTR_SIZE) + PTR_SIZE;
- return len;
- }
- default:
- return 0;
- }
- }
- static uint32_t get_struct_length() {
- uint32_t _ei = ei;
- uint32_t len = traverse(0, false);
- ei = _ei;
- return len;
- }
- static void read_store_map(uint32_t count) {
- ei -= 5; // u8 map, i32 count
- uint32_t size = get_struct_length();
- size += pad(size, PTR_SIZE);
- bottom += size * array_count;
- array_count = 0;
- ei += 5;
- for (uint32_t i = 0; i < count; ++i) {
- read_u8(); // 0xdb string
- read_string(); // key
- read_store(); // value
- }
- di += pad(di, PTR_SIZE);
- di += PTR_SIZE; // void *_ for runtime storage
- }
- static bool is_typed_array(uint8_t flag) {
- return flag == 0xca || flag == 0xd2 || flag == 0xd1 || flag == 0xc4 || flag == 0xc2 || flag == 0xc3;
- }
- static uint8_t flag_to_byte_size(uint8_t flag) {
- if (flag == 0xca) return 4; // f32
- if (flag == 0xd2) return 4; // i32
- if (flag == 0xd1) return 2; // i16
- if (flag == 0xc4) return 1; // u8
- if (flag == 0xc2) return 1; // u8 (true)
- if (flag == 0xc3) return 1; // u8 (false)
- return 0;
- }
- static void store_typed_array(uint8_t flag, uint32_t count) {
- uint32_t size = flag_to_byte_size(flag) * count;
- memcpy(decoded + di, encoded + ei, size);
- if (size > 4096) {
- gc_cut(decoded, di, size);
- }
- ei += size;
- di += size;
- }
- static void read_store_array(uint32_t count) { // Store in any/i32/../_array_t format
- // Store pointer to array_t struct
- // Put array contents at the bottom
- // - pointer to array_t buffer
- // - element count
- // - capacity (same as count)
- // - buffer
- store_ptr(bottom);
- uint32_t _di = di;
- di = bottom;
- if (count > 0) {
- store_ptr(di + PTR_SIZE + 4 + 4); // Pointer to buffer contents
- }
- else {
- store_ptr_abs(NULL);
- }
- store_u32(count); // Element count
- store_u32(0); // Capacity = 0 -> do not free on first realloc
- bottom = di;
- if (count == 0) {
- di = _di;
- return;
- }
- uint8_t flag = read_u8();
- if (is_typed_array(flag)) {
- if (flag == 0xc2 || flag == 0xc3) {
- ei--; // Bool array
- }
- store_typed_array(flag, count);
- bottom = pad(di, PTR_SIZE) + di;
- }
- // Dynamic (type (array / map / string) - value)
- else {
- ei -= 1; // Undo flag read
- // Strings
- if (flag == 0xdb) {
- // String pointers
- uint32_t _ei = ei;
- uint32_t strings_length = 0;
- for (uint32_t i = 0; i < count; ++i) {
- store_ptr(bottom + count * PTR_SIZE + strings_length);
- if (i < count - 1) {
- ei += 1; // String flag
- uint32_t length = read_u32(); // String length
- ei += length;
- strings_length += length;
- strings_length += 1; // '\0'
- }
- }
- ei = _ei;
- // String bytes
- for (uint32_t i = 0; i < count; ++i) {
- ei += 1; // String flag
- store_string_bytes(read_string());
- }
- bottom = pad(di, PTR_SIZE) + di;
- }
- // Arrays
- else if (flag == 0xdd) {
- // Array pointers
- uint32_t _ei = ei;
- uint32_t arrays_length = 0;
- for (uint32_t i = 0; i < count; ++i) {
- store_ptr(bottom + count * PTR_SIZE + arrays_length);
- if (i < count - 1) {
- ei += 1; // Array flag
- uint32_t length = read_u32(); // Array length
- ei += length;
- length += pad(length, PTR_SIZE);
- arrays_length += length;
- arrays_length += 8 + 8 + 4 + 4;
- }
- }
- ei = _ei;
- // Array contents
- bottom = pad(di, PTR_SIZE) + di;
- array_count = count;
- for (uint32_t i = 0; i < count; ++i) {
- uint8_t flag = read_u8();
- read_store_array(read_i32());
- }
- }
- // Structs
- else {
- uint32_t size = get_struct_length();
- size += pad(size, PTR_SIZE);
- // Struct pointers
- for (uint32_t i = 0; i < count; ++i) {
- store_ptr(bottom + count * PTR_SIZE + i * size);
- }
- // Struct contents
- bottom = pad(di, PTR_SIZE) + di;
- array_count = count;
- for (uint32_t i = 0; i < count; ++i) {
- di = pad(di, PTR_SIZE) + di;
- uint8_t flag = read_u8();
- read_store_map(read_i32());
- }
- }
- }
- di = _di;
- }
- static void read_store() {
- uint8_t flag = read_u8();
- switch (flag) {
- case 0xc0:
- store_ptr_abs(NULL);
- break;
- case 0xc2:
- store_u8(false);
- break;
- case 0xc3:
- store_u8(true);
- break;
- case 0xca:
- store_f32(read_f32());
- break;
- case 0xd2:
- store_i32(read_i32());
- break;
- case 0xdf: {
- array_count = 1;
- read_store_map(read_i32());
- break;
- }
- case 0xdd:
- read_store_array(read_i32());
- break;
- case 0xdb:
- store_string(read_string());
- break;
- }
- }
- static void reset() {
- di = 0;
- ei = 0;
- bottom = 0;
- }
- void *armpack_decode(buffer_t *b) {
- reset();
- encoded = b->buffer;
- capacity = traverse(0, true);
- reset();
- decoded = gc_alloc(capacity);
- read_store();
- return decoded;
- }
- void armpack_encode_start(void *_encoded) {
- encoded = _encoded;
- ei = 0;
- }
- int armpack_encode_end() {
- return ei;
- }
- static void armpack_write_u8(uint8_t i) {
- *(uint8_t *)(encoded + ei) = i;
- ei += 1;
- }
- static void armpack_write_i16(int16_t i) {
- *(int16_t *)(encoded + ei) = i;
- ei += 2;
- }
- static void armpack_write_u32(uint32_t i) {
- *(uint32_t *)(encoded + ei) = i;
- ei += 4;
- }
- static void armpack_write_i32(int32_t i) {
- *(int32_t *)(encoded + ei) = i;
- ei += 4;
- }
- static void armpack_write_f32(float i) {
- *(float *)(encoded + ei) = i;
- ei += 4;
- }
- void armpack_encode_map(uint32_t count) {
- armpack_write_u8(0xdf);
- armpack_write_i32(count);
- }
- void armpack_encode_array(uint32_t count) { // array of arrays / array of maps / array of strings
- armpack_write_u8(0xdd);
- armpack_write_u32(count);
- }
- void armpack_encode_array_f32(f32_array_t *f32a) {
- if (f32a == NULL) {
- armpack_write_u8(0xc0); // NULL
- return;
- }
- armpack_write_u8(0xdd);
- armpack_write_u32(f32a->length);
- armpack_write_u8(0xca);
- for (uint32_t i = 0; i < f32a->length; ++i) {
- armpack_write_f32(f32a->buffer[i]);
- }
- }
- void armpack_encode_array_i32(i32_array_t *i32a) {
- if (i32a == NULL) {
- armpack_write_u8(0xc0); // NULL
- return;
- }
- armpack_write_u8(0xdd);
- armpack_write_u32(i32a->length);
- armpack_write_u8(0xd2);
- for (uint32_t i = 0; i < i32a->length; ++i) {
- armpack_write_i32(i32a->buffer[i]);
- }
- }
- void armpack_encode_array_i16(i16_array_t *i16a) {
- if (i16a == NULL) {
- armpack_write_u8(0xc0); // NULL
- return;
- }
- armpack_write_u8(0xdd);
- armpack_write_u32(i16a->length);
- armpack_write_u8(0xd1);
- for (uint32_t i = 0; i < i16a->length; ++i) {
- armpack_write_i16(i16a->buffer[i]);
- }
- }
- void armpack_encode_array_u8(u8_array_t *u8a) {
- if (u8a == NULL) {
- armpack_write_u8(0xc0); // NULL
- return;
- }
- armpack_write_u8(0xdd);
- armpack_write_u32(u8a->length);
- armpack_write_u8(0xc4);
- for (uint32_t i = 0; i < u8a->length; ++i) {
- armpack_write_u8(u8a->buffer[i]);
- }
- }
- void armpack_encode_array_string(char_ptr_array_t *strings) {
- if (strings == NULL) {
- armpack_write_u8(0xc0); // NULL
- return;
- }
- armpack_write_u8(0xdd);
- armpack_write_u32(strings->length);
- for (uint32_t i = 0; i < strings->length; ++i) {
- armpack_encode_string(strings->buffer[i]);
- }
- }
- void armpack_encode_string(char *str) {
- if (str == NULL) {
- armpack_write_u8(0xc0); // NULL
- return;
- }
- armpack_write_u8(0xdb);
- size_t len = strlen(str);
- armpack_write_u32(len);
- for (uint32_t i = 0; i < len; ++i) {
- armpack_write_u8(str[i]);
- }
- }
- void armpack_encode_i32(int32_t i) {
- armpack_write_u8(0xd2);
- armpack_write_i32(i);
- }
- void armpack_encode_f32(float f) {
- armpack_write_u8(0xca);
- armpack_write_f32(f);
- }
- void armpack_encode_bool(bool b) {
- armpack_write_u8(b ? 0xc3 : 0xc2);
- }
- void armpack_encode_null() {
- armpack_write_u8(0xc0);
- }
- uint32_t armpack_size_map() {
- return 1 + 4; // u8 tag + u32 count
- }
- uint32_t armpack_size_array() {
- return 1 + 4; // u8 tag + u32 count
- }
- uint32_t armpack_size_array_f32(f32_array_t *f32a) {
- return 1 + 4 + 1 + f32a->length * 4; // u8 tag + u32 count + u8 flag + f32* contents
- }
- uint32_t armpack_size_array_u8(u8_array_t *u8a) {
- return 1 + 4 + 1 + u8a->length; // u8 tag + u32 count + u8 flag + u8* contents
- }
- uint32_t armpack_size_string(char *str) {
- return 1 + 4 + strlen(str); // u8 tag + u32 length + contents
- }
- uint32_t armpack_size_i32() {
- return 1 + 4; // u8 tag + i32
- }
- uint32_t armpack_size_f32() {
- return 1 + 4; // u8 tag + f32
- }
- uint32_t armpack_size_bool() {
- return 1; // u8 tag
- }
- static char *read_string_alloc() {
- char *s = read_string();
- char *allocated = gc_alloc(string_length + 1);
- memcpy(allocated, s, string_length);
- allocated[string_length] = '\0';
- return allocated;
- }
- typedef union ptr_storage {
- void *p;
- struct {
- float f;
- int type; // 0 - float, 1 - int
- };
- int i;
- } ptr_storage_t;
- any_map_t *_armpack_decode_to_map() {
- any_map_t *result = any_map_create();
- uint32_t count = read_u32();
- for (uint32_t i = 0; i < count; i++) {
- read_u8(); // 0xdb string
- char *key = read_string_alloc();
- uint8_t flag = read_u8();
- switch (flag) {
- case 0xc0: { // NULL
- any_map_set(result, key, NULL);
- break;
- }
- case 0xc2: { // false
- ptr_storage_t s;
- s.i = 0;
- s.type = 1;
- any_map_set(result, key, s.p);
- break;
- }
- case 0xc3: { // true
- ptr_storage_t s;
- s.i = 1;
- s.type = 1;
- any_map_set(result, key, s.p);
- break;
- }
- case 0xca: { // f32
- ptr_storage_t s;
- s.f = read_f32();
- s.type = 0;
- any_map_set(result, key, s.p);
- break;
- }
- case 0xd2: { // i32
- ptr_storage_t s;
- s.i = read_i32();
- s.type = 1;
- any_map_set(result, key, s.p);
- break;
- }
- case 0xdb: { // string
- any_map_set(result, key, read_string_alloc());
- break;
- }
- case 0xdf: { // map
- any_map_t *nested_map = _armpack_decode_to_map();
- any_map_set(result, key, nested_map);
- break;
- }
- case 0xdd: { // array
- uint32_t array_count = read_u32();
- uint8_t element_flag = read_u8();
- if (element_flag == 0xca) { // f32
- f32_array_t *array = f32_array_create(array_count);
- for (uint32_t j = 0; j < array_count; j++) {
- array->buffer[j] = read_f32();
- }
- any_map_set(result, key, array);
- }
- else if (element_flag == 0xd2) { // i32
- i32_array_t *array = i32_array_create(array_count);
- for (uint32_t j = 0; j < array_count; j++) {
- array->buffer[j] = read_i32();
- }
- any_map_set(result, key, array);
- }
- else if (element_flag == 0xd1) { // i16
- i16_array_t *array = i16_array_create(array_count);
- for (uint32_t j = 0; j < array_count; j++) {
- array->buffer[j] = read_i16();
- }
- any_map_set(result, key, array);
- }
- else if (element_flag == 0xc4) { // u8
- u8_array_t *array = u8_array_create(array_count);
- for (uint32_t j = 0; j < array_count; j++) {
- array->buffer[j] = read_u8();
- }
- any_map_set(result, key, array);
- }
- else if (element_flag == 0xdb) { // string
- ei--;
- char_ptr_array_t *array = char_ptr_array_create(array_count);
- for (uint32_t j = 0; j < array_count; j++) {
- read_u8(); // flag
- array->buffer[j] = read_string_alloc();
- }
- any_map_set(result, key, array);
- }
- else if (element_flag == 0xdf) { // map
- ei--;
- any_array_t *array = any_array_create(array_count);
- for (uint32_t j = 0; j < array_count; j++) {
- read_u8(); // flag
- array->buffer[j] = _armpack_decode_to_map();
- }
- any_map_set(result, key, array);
- }
- else if (element_flag == 0xc6) { // buffer_t (deprecated)
- ei--;
- any_array_t *array = any_array_create(array_count);
- for (uint32_t j = 0; j < array_count; j++) {
- read_u8(); // flag
- uint32_t buffer_size = read_u32();
- buffer_t *buffer = buffer_create(buffer_size);
- for (uint32_t k = 0; k < buffer_size; k++) {
- buffer->buffer[k] = read_u8();
- }
- array->buffer[j] = buffer;
- }
- any_map_set(result, key, array);
- }
- break;
- }
- case 0xc6: { // buffer_t (deprecated)
- uint32_t buffer_size = read_u32();
- buffer_t *buffer = buffer_create(buffer_size);
- for (uint32_t j = 0; j < buffer_size; j++) {
- buffer->buffer[j] = read_u8();
- }
- any_map_set(result, key, buffer);
- }
- }
- }
- return result;
- }
- any_map_t *armpack_decode_to_map(buffer_t *b) {
- encoded = b->buffer;
- ei = 0;
- read_u8(); // Must be 0xdf for a map
- return _armpack_decode_to_map();
- }
- float armpack_map_get_f32(any_map_t *map, char *key) {
- ptr_storage_t ps;
- ps.p = any_map_get(map, key);
- if (ps.p == NULL) {
- return 0.0;
- }
- return ps.type == 0 ? ps.f : (float)ps.i;
- }
- int armpack_map_get_i32(any_map_t *map, char *key) {
- ptr_storage_t ps;
- ps.p = any_map_get(map, key);
- if (ps.p == NULL) {
- return 0;
- }
- return ps.type == 1 ? ps.i : (int)ps.f;
- }
|