From e3614aaeb1f22f81859d0687144ed2e7b5eb7a76 Mon Sep 17 00:00:00 2001 From: luboslenco Date: Tue, 24 Mar 2026 19:50:07 +0100 Subject: [PATCH] plugins: make converter work --- base/sources/iron_armpack.c | 151 ++++++++++++++++++-- base/sources/iron_armpack.h | 13 +- base/sources/iron_json.c | 233 +++++++++++++++++++++++++++++++ base/sources/iron_json.h | 31 ++-- base/sources/libs/minic_api.c | 2 + paint/assets/Scene.arm | Bin 168952 -> 168952 bytes paint/assets/plugins/converter.c | 14 +- 7 files changed, 402 insertions(+), 42 deletions(-) diff --git a/base/sources/iron_armpack.c b/base/sources/iron_armpack.c index a070fe8e..bee803c0 100644 --- a/base/sources/iron_armpack.c +++ b/base/sources/iron_armpack.c @@ -2,6 +2,8 @@ #include "iron_armpack.h" #include "iron_gc.h" +#include "iron_json.h" +#include "iron_string.h" #include #include #include @@ -18,7 +20,7 @@ static uint8_t *decoded; static uint8_t *encoded; static uint32_t capacity; static uint32_t array_count; -static uint32_t string_length; +static uint32_t str_len; static void read_store(); static inline uint64_t pad(int di, int n) { @@ -67,7 +69,7 @@ static void store_ptr_abs(void *ptr) { } static void store_string_bytes(char *str) { - for (int i = 0; i < string_length; ++i) { + for (int i = 0; i < str_len; ++i) { store_u8(str[i]); } store_u8('\0'); @@ -114,9 +116,9 @@ static float read_f32() { } static char *read_string() { - string_length = read_u32(); - char *str = (char *)(encoded + ei); - ei += string_length; + str_len = read_u32(); + char *str = (char *)(encoded + ei); + ei += str_len; return str; } @@ -448,27 +450,27 @@ int armpack_encode_end() { return ei; } -static void armpack_write_u8(uint8_t i) { +void armpack_write_u8(uint8_t i) { *(uint8_t *)(encoded + ei) = i; ei += 1; } -static void armpack_write_i16(int16_t i) { +void armpack_write_i16(int16_t i) { *(int16_t *)(encoded + ei) = i; ei += 2; } -static void armpack_write_u32(uint32_t i) { +void armpack_write_u32(uint32_t i) { *(uint32_t *)(encoded + ei) = i; ei += 4; } -static void armpack_write_i32(int32_t i) { +void armpack_write_i32(int32_t i) { *(int32_t *)(encoded + ei) = i; ei += 4; } -static void armpack_write_f32(float i) { +void armpack_write_f32(float i) { *(float *)(encoded + ei) = i; ei += 4; } @@ -620,9 +622,9 @@ uint32_t armpack_size_bool() { 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'; + char *allocated = gc_alloc(str_len + 1); + memcpy(allocated, s, str_len); + allocated[str_len] = '\0'; return allocated; } @@ -772,6 +774,129 @@ any_map_t *armpack_decode_to_map(buffer_t *b) { return _armpack_decode_to_map(); } +static char *armpack_to_json_value(); + +static const char *peek_typed_array_suffix() { + if (encoded[ei] != 0xdd) + return ""; + uint32_t saved_ei = ei; + ei++; + uint32_t count = read_u32(); + const char *suffix = ""; + if (count > 0) { + uint8_t flag2 = read_u8(); + if (flag2 == 0xca) + suffix = "[f32]"; + else if (flag2 == 0xd2) + suffix = "[i32]"; + else if (flag2 == 0xd1) + suffix = "[i16]"; + else if (flag2 == 0xc4) + suffix = "[u8]"; + } + ei = saved_ei; + return suffix; +} + +static char *armpack_to_json_map(uint32_t count) { + char *result = "{"; + for (uint32_t i = 0; i < count; i++) { + read_u8(); // 0xdb string flag + char *key = read_string_alloc(); + const char *suffix = peek_typed_array_suffix(); + char *value = armpack_to_json_value(); + if (i > 0) { + result = string("%s,", result); + } + result = string("%s\"%s%s\":%s", result, key, suffix, value); + } + return string("%s}", result); +} + +static char *armpack_to_json_value() { + uint8_t flag = read_u8(); + switch (flag) { + case 0xc0: + return "null"; + case 0xc2: + return "false"; + case 0xc3: + return "true"; + case 0xca: + return f32_to_string_with_zeros(read_f32()); + case 0xd2: + return i32_to_string(read_i32()); + case 0xdb: { + char *s = read_string_alloc(); + return string("\"%s\"", s); + } + case 0xdf: + return armpack_to_json_map(read_i32()); + case 0xdd: { + uint32_t count = read_u32(); + if (count == 0) { + return "[]"; + } + uint8_t flag2 = read_u8(); + char *result = "["; + if (flag2 == 0xca) { // f32 + for (uint32_t i = 0; i < count; i++) { + if (i > 0) + result = string("%s,", result); + result = string("%s%s", result, f32_to_string_with_zeros(read_f32())); + } + } + else if (flag2 == 0xd2) { // i32 + for (uint32_t i = 0; i < count; i++) { + if (i > 0) + result = string("%s,", result); + result = string("%s%s", result, i32_to_string(read_i32())); + } + } + else if (flag2 == 0xd1) { // i16 + for (uint32_t i = 0; i < count; i++) { + if (i > 0) + result = string("%s,", result); + result = string("%s%s", result, i32_to_string(read_i16())); + } + } + else if (flag2 == 0xc4) { // u8 + for (uint32_t i = 0; i < count; i++) { + if (i > 0) + result = string("%s,", result); + result = string("%s%s", result, i32_to_string(read_u8())); + } + } + else if (flag2 == 0xc2 || flag2 == 0xc3) { // Deprecated: bool array + ei--; // undo flag2 read + for (uint32_t i = 0; i < count; i++) { + if (i > 0) + result = string("%s,", result); + result = string("%s%s", result, read_u8() ? "true" : "false"); + } + } + else { // dynamic (string, array, map) + ei--; // undo flag2 read + for (uint32_t i = 0; i < count; i++) { + if (i > 0) + result = string("%s,", result); + result = string("%s%s", result, armpack_to_json_value()); + } + } + return string("%s]", result); + } + default: + return "null"; + } +} + +char *armpack_decode_to_json(buffer_t *b) { + encoded = b->buffer; + ei = 0; + read_u8(); // Must be 0xdf for a map + return armpack_to_json_map(read_i32()); +} + float armpack_map_get_f32(any_map_t *map, char *key) { ptr_storage_t ps; ps.p = any_map_get(map, key); diff --git a/base/sources/iron_armpack.h b/base/sources/iron_armpack.h index 779b7da8..5a936bef 100644 --- a/base/sources/iron_armpack.h +++ b/base/sources/iron_armpack.h @@ -36,16 +36,23 @@ uint32_t armpack_size_f32(); uint32_t armpack_size_bool(); any_map_t *armpack_decode_to_map(buffer_t *b); +char *armpack_decode_to_json(buffer_t *b); float armpack_map_get_f32(any_map_t *map, char *key); int armpack_map_get_i32(any_map_t *map, char *key); -/* JS object: +void armpack_write_u8(uint8_t i); +void armpack_write_i16(int16_t i); +void armpack_write_u32(uint32_t i); +void armpack_write_i32(int32_t i); +void armpack_write_f32(float i); - let test = { +/* JSON object: + + { name: "test", point: { x: 2, y: 4 }, array: i32_array_create([1, 2, 3]) - }; + } */ /* C struct: diff --git a/base/sources/iron_json.c b/base/sources/iron_json.c index fbeea574..54a2f7bd 100644 --- a/base/sources/iron_json.c +++ b/base/sources/iron_json.c @@ -1,5 +1,6 @@ #include "iron_json.h" +#include "iron_armpack.h" #include "iron_string.h" #include #include @@ -431,3 +432,235 @@ void json_encode_map(any_map_t *m) { json_encode_string(keys->buffer[i], any_map_get(m, keys->buffer[i])); } } + +static char *jenc_src; +static jsmntok_t *jenc_tokens; +static int jenc_ti; +static uint8_t jenc_forced_array_type; + +static bool jenc_has_dot(int start, int end) { + for (int i = start; i < end; i++) { + if (jenc_src[i] == '.') + return true; + } + return false; +} + +static int jenc_skip(int ti) { + jsmntok_t t = jenc_tokens[ti++]; + if (t.type == JSMN_OBJECT) { + for (int i = 0; i < t.size; i++) { + ti = jenc_skip(ti); // key + ti = jenc_skip(ti); // value + } + } + else if (t.type == JSMN_ARRAY) { + for (int i = 0; i < t.size; i++) { + ti = jenc_skip(ti); + } + } + return ti; +} + +static uint8_t jenc_elem_type(int ti) { + jsmntok_t t = jenc_tokens[ti]; + if (t.type == JSMN_STRING) + return 0xdb; + if (t.type == JSMN_OBJECT) + return 0xdf; + if (t.type == JSMN_ARRAY) + return 0xdd; + char c = jenc_src[t.start]; + if (c == 't' || c == 'f') + return 0xc2; + if (c == 'n') + return 0xc0; + if (jenc_has_dot(t.start, t.end)) + return 0xca; + return 0xd2; +} + +static uint8_t jenc_array_type(int count) { + if (count == 0) + return 0x0; + int ti = jenc_ti; + uint8_t first_type = jenc_elem_type(ti); + if (first_type != 0xca && first_type != 0xd2 && first_type != 0xdb) { + return 0x0; // non-scalar types -> dynamic + } + for (int i = 0; i < count; i++) { + if (jenc_elem_type(ti) != first_type) + return 0x0; + ti = jenc_skip(ti); + } + return first_type; +} + +static void jenc_write_string(int start, int len) { + armpack_write_u8(0xdb); + armpack_write_u32(len); + for (int i = 0; i < len; i++) { + armpack_write_u8(jenc_src[start + i]); + } +} + +static void jenc_value(); + +static void jenc_object(int count) { + armpack_write_u8(0xdf); + armpack_write_i32(count); + for (int i = 0; i < count; i++) { + jsmntok_t key = jenc_tokens[jenc_ti++]; + int key_len = key.end - key.start; + // Check for [type] suffix in key name + uint8_t forced_type = 0; + int actual_len = key_len; + if (key_len >= 4 && jenc_src[key.end - 1] == ']') { + const char *ks = jenc_src + key.start; + if (key_len >= 5 && strncmp(ks + key_len - 5, "[f32]", 5) == 0) { + forced_type = 0xca; + actual_len = key_len - 5; + } + else if (key_len >= 5 && strncmp(ks + key_len - 5, "[i32]", 5) == 0) { + forced_type = 0xd2; + actual_len = key_len - 5; + } + else if (key_len >= 5 && strncmp(ks + key_len - 5, "[i16]", 5) == 0) { + forced_type = 0xd1; + actual_len = key_len - 5; + } + else if (key_len >= 4 && strncmp(ks + key_len - 4, "[u8]", 4) == 0) { + forced_type = 0xc4; + actual_len = key_len - 4; + } + } + jenc_write_string(key.start, actual_len); + jenc_forced_array_type = forced_type; + jenc_value(); + jenc_forced_array_type = 0; + } +} + +static void jenc_array(int count) { + armpack_write_u8(0xdd); + armpack_write_u32(count); + if (count == 0) + return; + + uint8_t forced = jenc_forced_array_type; + jenc_forced_array_type = 0; + uint8_t elem_type = forced != 0 ? forced : jenc_array_type(count); + + if (elem_type == 0xca) { // typed f32 + armpack_write_u8(0xca); + for (int i = 0; i < count; i++) { + jsmntok_t t = jenc_tokens[jenc_ti++]; + armpack_write_f32(strtof(jenc_src + t.start, NULL)); + } + } + else if (elem_type == 0xd2) { // typed i32 + armpack_write_u8(0xd2); + for (int i = 0; i < count; i++) { + jsmntok_t t = jenc_tokens[jenc_ti++]; +#ifdef _WIN32 + armpack_write_i32((int32_t)_strtoi64(jenc_src + t.start, NULL, 10)); +#else + armpack_write_i32((int32_t)strtol(jenc_src + t.start, NULL, 10)); +#endif + } + } + else if (elem_type == 0xd1) { // typed i16 + armpack_write_u8(0xd1); + for (int i = 0; i < count; i++) { + jsmntok_t t = jenc_tokens[jenc_ti++]; +#ifdef _WIN32 + armpack_write_i16((int16_t)_strtoi64(jenc_src + t.start, NULL, 10)); +#else + armpack_write_i16((int16_t)strtol(jenc_src + t.start, NULL, 10)); +#endif + } + } + else if (elem_type == 0xc4) { // typed u8 + armpack_write_u8(0xc4); + for (int i = 0; i < count; i++) { + jsmntok_t t = jenc_tokens[jenc_ti++]; +#ifdef _WIN32 + armpack_write_u8((uint8_t)_strtoi64(jenc_src + t.start, NULL, 10)); +#else + armpack_write_u8((uint8_t)strtol(jenc_src + t.start, NULL, 10)); +#endif + } + } + else { // dynamic + for (int i = 0; i < count; i++) { + jenc_value(); + } + } +} + +static void jenc_value() { + jsmntok_t t = jenc_tokens[jenc_ti++]; + if (t.type == JSMN_OBJECT) { + jenc_object(t.size); + return; + } + if (t.type == JSMN_ARRAY) { + jenc_array(t.size); + return; + } + if (t.type == JSMN_STRING) { + jenc_write_string(t.start, t.end - t.start); + return; + } + // JSMN_PRIMITIVE + char c = jenc_src[t.start]; + if (c == 't') { + armpack_write_u8(0xc3); // true + } + else if (c == 'f') { + armpack_write_u8(0xc2); // false + } + else if (c == 'n') { + armpack_write_u8(0xc0); // null + } + else if (jenc_has_dot(t.start, t.end)) { + armpack_write_u8(0xca); + armpack_write_f32(strtof(jenc_src + t.start, NULL)); + } + else { + armpack_write_u8(0xd2); +#ifdef _WIN32 + armpack_write_i32((int32_t)_strtoi64(jenc_src + t.start, NULL, 10)); +#else + armpack_write_i32((int32_t)strtol(jenc_src + t.start, NULL, 10)); +#endif + } +} + +buffer_t *json_encode_to_armpack(char *json) { + jsmn_parser parser; + jsmn_init(&parser); + int n = jsmn_parse(&parser, json, strlen(json), NULL, 0); + if (n <= 0) + return NULL; + + jenc_tokens = malloc(sizeof(jsmntok_t) * n); + jsmn_init(&parser); + jsmn_parse(&parser, json, strlen(json), jenc_tokens, n); + + jenc_src = json; + jenc_ti = 0; + + int max_size = strlen(json) * 3 + 64; + uint8_t *buf = malloc(max_size); + armpack_encode_start(buf); + jenc_value(); + int size = armpack_encode_end(); + + free(jenc_tokens); + + buffer_t *b = buffer_create(size); + memcpy(b->buffer, buf, size); + free(buf); + return b; +} diff --git a/base/sources/iron_json.h b/base/sources/iron_json.h index c9b671da..bb8fdd7f 100644 --- a/base/sources/iron_json.h +++ b/base/sources/iron_json.h @@ -7,18 +7,19 @@ void *json_parse(char *s); any_map_t *json_parse_to_map(char *s); -void json_encode_begin(); -char *json_encode_end(); -void json_encode_string(char *k, char *v); -void json_encode_string_array(char *k, string_array_t *a); -void json_encode_f32(char *k, float f); -void json_encode_i32(char *k, int i); -void json_encode_null(char *k); -void json_encode_f32_array(char *k, f32_array_t *a); -void json_encode_i32_array(char *k, i32_array_t *a); -void json_encode_bool(char *k, bool b); -void json_encode_begin_array(char *k); -void json_encode_end_array(); -void json_encode_begin_object(); -void json_encode_end_object(); -void json_encode_map(any_map_t *m); +void json_encode_begin(); +char *json_encode_end(); +void json_encode_string(char *k, char *v); +void json_encode_string_array(char *k, string_array_t *a); +void json_encode_f32(char *k, float f); +void json_encode_i32(char *k, int i); +void json_encode_null(char *k); +void json_encode_f32_array(char *k, f32_array_t *a); +void json_encode_i32_array(char *k, i32_array_t *a); +void json_encode_bool(char *k, bool b); +void json_encode_begin_array(char *k); +void json_encode_end_array(); +void json_encode_begin_object(); +void json_encode_end_object(); +void json_encode_map(any_map_t *m); +buffer_t *json_encode_to_armpack(char *json); diff --git a/base/sources/libs/minic_api.c b/base/sources/libs/minic_api.c index 1c8cb44d..cd1046ae 100644 --- a/base/sources/libs/minic_api.c +++ b/base/sources/libs/minic_api.c @@ -1661,10 +1661,12 @@ void minic_register_builtins() { R(json_encode_begin_object, "v()"); R(json_encode_end_object, "v()"); R(json_encode_map, "v(p)"); + R(json_encode_to_armpack, "p(p)"); // armpack R(armpack_decode, "p(p)"); R(armpack_decode_to_map, "p(p)"); + R(armpack_decode_to_json, "p(p)"); R(armpack_encode_start, "v(p)"); R(armpack_encode_end, "i()"); R(armpack_encode_map, "v(i)"); diff --git a/paint/assets/Scene.arm b/paint/assets/Scene.arm index 42f2bc937dc0d32457a58bd42c37897f5cb87046..c5c956916d02a5d3cdc22959073d4cd6344b50f2 100644 GIT binary patch delta 176 zcmeydoa@JOt_^QkS&WT~?I$<#$xL3yC^A`r?JcA6WCBGXH&0glF4Fw(@AiLx8GlU$0C?R! AN&o-= delta 176 zcmeydoa@JOt_^QkSxk(J?I$<#$xL3yC^A`r?Jc9pWSWJLA1#i*Hi$G{Y47^ diff --git a/paint/assets/plugins/converter.c b/paint/assets/plugins/converter.c index 180882fa..7fbb5e73 100644 --- a/paint/assets/plugins/converter.c +++ b/paint/assets/plugins/converter.c @@ -5,12 +5,7 @@ ui_handle_t *h1; void on_arm_to_json(char *path) { buffer_t *b = data_get_blob(path); - any_map_t *parsed = armpack_decode_to_map(b); - - json_encode_begin(); - json_encode_map(parsed); - char *s = json_encode_end(); - + char *s = armpack_decode_to_json(b); buffer_t *out = sys_string_to_buffer(s); char *p = substring(path, 0, string_length(path) - 3); p = string("%sjson", p); @@ -19,13 +14,10 @@ void on_arm_to_json(char *path) { void on_json_to_arm(char *path) { buffer_t *b = data_get_blob(path); - - // void *parsed = json_parse(sys_buffer_to_string(b)); - // let out = armpack_encode(parsed); - + buffer_t *out = json_encode_to_armpack(sys_buffer_to_string(b)); char *p = substring(path, 0, string_length(path) - 4); p = string("%sarm", p); - // iron_file_save_bytes(p, out, 0); + iron_file_save_bytes(p, out, 0); } void on_ui() {