/* ObjectWhack.c - Complete Program with Menus, Exports, and Efficient Serialization */
//
// compile: gcc -O2 -o ow ObjectWhack.c -lm
// On Windows (MinGW): gcc -O2 -o ow ObjectWhack.c -lm -lcrypto -lws2_32

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <ctype.h>
#include <dirent.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <time.h>
#include <errno.h>
#include <signal.h>

#ifndef O_BINARY
#define O_BINARY 0
#endif

/* ===== Platform-specific networking ===== */
#ifdef _WIN32
#include <winsock2.h>
#include <ws2tcpip.h>
#include <windows.h>
#define close_socket closesocket
#define socket_errno WSAGetLastError()
static bool winsock_initialized = false;
#else
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define close_socket close
#define socket_errno errno
#endif

#define OBJECTWHACK_VERSION "2.03"

/* ===== Forward declarations ===== */
struct GraphicsContext;
struct Runtime;
struct NetXecThread;
struct Channel;
struct HyperLock;

/* ===== Constants ===== */
#define MAX_FIELDS              32
#define MAX_FIELD_LISTENERS     8

#define FIELD_FLAG_ALLOCATED    0x00000001U
#define FIELD_FLAG_SHARED       0x00000002U

#define DATA_BYTE       0
#define DATA_SHORT      1
#define DATA_CHAR       2
#define DATA_INT        3
#define DATA_LONG       4
#define DATA_FLOAT      5
#define DATA_DOUBLE     6
#define DATA_OBJECT     7

#define SIGN_BIT        0x40
#define COMPRESS_BIT    0x80
#define DIM_SHIFT       3

/* Serialization Protocol */
#define SER_MAGIC       0x4F57424A
#define SER_VERSION     1

static const size_t g_elem_sizes[8] = {1, 2, 2, 4, 8, 4, 8, 8};
#define OBJ_PTR_SIZE  sizeof(void *)

/* ===== Endianness ===== */
static inline int is_little_endian(void) {
    uint32_t test = 1;
    return *(uint8_t*)&test;
}

static inline uint16_t hton16(uint16_t x) {
    if (is_little_endian()) return (x >> 8) | (x << 8);
    return x;
}

static inline uint32_t hton32(uint32_t x) {
    if (!is_little_endian()) return x;
    return ((x & 0xFF000000) >> 24) | ((x & 0x00FF0000) >> 8) |
           ((x & 0x0000FF00) << 8) | ((x & 0x000000FF) << 24);
}

static inline uint64_t hton64(uint64_t x) {
    if (!is_little_endian()) return x;
    return ((x & 0xFF00000000000000ULL) >> 56) |
           ((x & 0x00FF000000000000ULL) >> 40) |
           ((x & 0x0000FF0000000000ULL) >> 24) |
           ((x & 0x000000FF00000000ULL) >> 8) |
           ((x & 0x00000000FF000000ULL) << 8) |
           ((x & 0x0000000000FF0000ULL) << 24) |
           ((x & 0x000000000000FF00ULL) << 40) |
           ((x & 0x00000000000000FFULL) << 56);
}

#define ntoh16 hton16
#define ntoh32 hton32
#define ntoh64 hton64

/* Serialization Header */
typedef struct __attribute__((packed)) {
    uint32_t magic;
    uint32_t version;
    uint64_t flags;
    uint32_t name_len;
    uint32_t field_count;
    uint32_t total_size;
} SerialHeader;

typedef struct {
    const char *name;
    uint8_t     base_type;
    size_t      elem_size;
    bool        is_signed;
} TypeInfo;

static const TypeInfo type_table[] = {
    /* Canonical names */
    {"int8_t",   DATA_BYTE,   1, true},
    {"byte8_t",  DATA_BYTE,   1, false},
    {"uint8_t",  DATA_BYTE,   1, false},
    {"int16_t",  DATA_SHORT,  2, true},
    {"uint16_t", DATA_SHORT,  2, false},
    {"int32_t",  DATA_INT,    4, true},
    {"uint32_t", DATA_INT,    4, false},
    {"int64_t",  DATA_LONG,   8, true},
    {"uint64_t", DATA_LONG,   8, false},
    {"float",    DATA_FLOAT,  4, false},
    {"double",   DATA_DOUBLE, 8, false},
    {"char",     DATA_CHAR,   2, false},
    {"Object",   DATA_OBJECT, OBJ_PTR_SIZE, false},
    /* Short-form aliases */
    {"i8",       DATA_BYTE,   1, true},
    {"i16",      DATA_SHORT,  2, true},
    {"i32",      DATA_INT,    4, true},
    {"i64",      DATA_LONG,   8, true},
    {"u8",       DATA_BYTE,   1, false},
    {"u16",      DATA_SHORT,  2, false},
    {"u32",      DATA_INT,    4, false},
    {"u64",      DATA_LONG,   8, false},
    {"f32",      DATA_FLOAT,  4, false},
    {"f64",      DATA_DOUBLE, 8, false},
    {NULL, 0, 0, false}
};

static const char *storage_names[] = {
    "HEAP", "STACK", "IPC", "GPU", "CLOUD", "REGISTRY", "PAGE", NULL
};

/* ===== Structures ===== */
struct Listener {
    int32_t  listener_flags;
    uint32_t pad;
    void    *callback;
};

struct Field {
    char          field_name[64];
    uint8_t       field_type;
    uint8_t       pad[7];
    void         *data;
    struct Listener listeners[MAX_FIELD_LISTENERS];
    int32_t     (*FieldHandler)(struct Field *);
    uint32_t      pad2;
    uint32_t      dims[3];
};

struct Object {
    struct Field          *ob_fields;
    uint64_t               ob_flags;
    uint64_t               ob_size;
    char                   ob_name[256];
    struct GraphicsContext *ob_graphics;
    struct Runtime        *ob_run;
    uint32_t               ob_field_number;
    uint32_t               user_data;
    uint64_t               crc;
};

/* ===== Global variables ===== */
static char g_object_dir[512] = "./objects";
static uint32_t g_export_flags = 0;

/* Export flags */
#define EXFLAG_JAVA    (1<<0)
#define EXFLAG_JS      (1<<1)
#define EXFLAG_JSON    (1<<2)
#define EXFLAG_TS      (1<<3)
#define EXFLAG_C       (1<<5)
#define EXFLAG_GO      (1<<6)
#define EXFLAG_SWIFT   (1<<7)
#define EXFLAG_ODL     (1<<8)
#define EXFLAG_RUST    (1<<9)
#define EXFLAG_KOTLIN  (1<<10)
#define EXFLAG_CSHARP  (1<<11)
#define EXFLAG_TOML    (1<<12)
#define EXFLAG_WASM    (1<<13)
#define EXFLAG_MSGPACK (1<<14)
#define EXFLAG_ALL     0xFFFF

/* ===== Forward declaration of ExportObject ===== */
static void ExportObject(struct Object *obj, uint32_t flags);

/* ===== Function Prototypes ===== */
void SaveObject(struct Object *obj);
struct Object *LoadObject(const char *name);
struct Object *AllocObject(const char *desc);
void LoadODLString(const char *src);
void LoadODLFile(const char *filename);
void SaveJavaClass(struct Object *obj);
void SaveJavaScript(struct Object *obj);
void SaveJSON(struct Object *obj);
void SaveTypeScript(struct Object *obj);
void SaveCHeader(struct Object *obj);
void SaveGoStruct(struct Object *obj);
void SaveSwiftStruct(struct Object *obj);
void SaveODL(struct Object *obj);
void SaveRustStruct(struct Object *obj);
void SaveKotlinClass(struct Object *obj);
void SaveCSharpStruct(struct Object *obj);
void SaveTOML(struct Object *obj);
void SaveWebAssembly(struct Object *obj);
void SaveMessagePack(struct Object *obj);
void FreeObject(struct Object *obj);
void PrintObject(const struct Object *obj);
void ListSavedObjects(void);
void PrintAllObjects(void);
void ShowHelp(void);
void ProcessODLFiles(void);
void SelectAndLoadObject(struct Object **current);
void SaveAllFormats(struct Object *obj);
int64_t FSendObject(struct Object *obj, int fd);
struct Object* FReceiveObject(int fd);

/* ===== Directory & Path Helpers ===== */
static void init_object_dir(void) {
    const char *env = getenv("OBJECT_DIRECTORY");
    if (env && env[0]) {
        strncpy(g_object_dir, env, sizeof(g_object_dir)-1);
        g_object_dir[sizeof(g_object_dir)-1] = '\0';
    }
}

static void make_directory(const char *path) {
    char tmp[512];
    snprintf(tmp, sizeof(tmp), "%s", path);
    char *p = tmp;
    if (*p == '/') p++;
    while (*p) {
        if (*p == '/') {
            *p = '\0';
#ifdef _WIN32
            mkdir(tmp);
#else
            mkdir(tmp, 0755);
#endif
            *p = '/';
        }
        p++;
    }
#ifdef _WIN32
    mkdir(tmp);
#else
    mkdir(tmp, 0755);
#endif
}

static void build_obj_path(char *dest, size_t destsz, const char *obj_name, const char *suffix) {
    if (suffix) {
        snprintf(dest, destsz, "%s/%s/%s.%s", g_object_dir, obj_name, obj_name, suffix);
    } else {
        snprintf(dest, destsz, "%s/%s", g_object_dir, obj_name);
    }
}

static uint8_t pack_field_type(uint8_t base, int dims, bool sign, bool comp) {
    uint8_t t = base & 0x07;
    t |= (dims & 0x03) << DIM_SHIFT;
    if (sign) t |= SIGN_BIT;
    if (comp)  t |= COMPRESS_BIT;
    return t;
}

/* ===== ODL Tokenizer ===== */
typedef enum {
    TOK_EOF, TOK_IDENT, TOK_NUMBER, TOK_FLOAT, TOK_STRING,
    TOK_LBRACKET, TOK_RBRACKET,
    TOK_LBRACE, TOK_RBRACE, TOK_EQUALS, TOK_COMMA, TOK_SEMICOLON
} ODLTokenType;

typedef struct {
    ODLTokenType type;
    char text[512];
    int64_t ival;
    double fval;
} Token;

typedef struct {
    const char *src;
    const char *pos;
    int line;
    int held;
    Token hold;
} Tokenizer;

static void tok_init(Tokenizer *t, const char *src) {
    memset(t, 0, sizeof(*t));
    t->src = src;
    t->pos = src;
    t->line = 1;
}

static void tok_push(Tokenizer *t, Token tok) {
    t->hold = tok;
    t->held = 1;
}

static Token tok_next(Tokenizer *t) {
    Token tok = {0};
    if (t->held) { t->held = 0; return t->hold; }
    while (isspace(*t->pos)) {
        if (*t->pos == '\n') t->line++;
        t->pos++;
    }
    if (!*t->pos) { tok.type = TOK_EOF; return tok; }

    if (t->pos[0] == '/' && t->pos[1] == '/') {
        while (*t->pos && *t->pos != '\n') t->pos++;
        return tok_next(t);
    }
    if (*t->pos == '#') {
        while (*t->pos && *t->pos != '\n') t->pos++;
        return tok_next(t);
    }

    if (*t->pos == '"') {
        int i = 0;
        t->pos++;
        while (*t->pos && *t->pos != '"') {
            char c = *t->pos++;
            if (c == '\\' && *t->pos) {
                char e = *t->pos++;
                if (e == 'n') c = '\n';
                else if (e == 't') c = '\t';
                else c = e;
            }
            if (c == '\n') t->line++;
            if (i < (int)sizeof(tok.text) - 1) tok.text[i++] = c;
        }
        if (*t->pos == '"') t->pos++;
        tok.text[i] = '\0';
        tok.type = TOK_STRING;
        return tok;
    }

    if (isdigit((unsigned char)*t->pos) ||
        ((*t->pos == '-' || *t->pos == '+') &&
         (isdigit((unsigned char)t->pos[1]) || t->pos[1] == '.')) ||
        (*t->pos == '.' && isdigit((unsigned char)t->pos[1]))) {
        const char *look = t->pos;
        int hex = 0, flt = 0;
        if (*look == '-' || *look == '+') look++;
        if (look[0] == '0' && (look[1] == 'x' || look[1] == 'X')) hex = 1;
        if (!hex) {
            for (const char *q = look; *q; q++) {
                if (*q == '.' || *q == 'e' || *q == 'E') { flt = 1; break; }
                if (!isdigit((unsigned char)*q)) break;
            }
        }
        char *end = NULL;
        if (flt) {
            tok.fval = strtod(t->pos, &end);
            tok.ival = (int64_t)tok.fval;
            tok.type = TOK_FLOAT;
        } else {
            tok.ival = strtoll(t->pos, &end, 0);
            tok.fval = (double)tok.ival;
            tok.type = TOK_NUMBER;
        }
        if (end == t->pos) { t->pos++; return tok_next(t); }
        snprintf(tok.text, sizeof(tok.text), "%.*s", (int)(end - t->pos), t->pos);
        t->pos = end;
        return tok;
    }

    switch (*t->pos) {
        case '[': tok.type = TOK_LBRACKET; t->pos++; return tok;
        case ']': tok.type = TOK_RBRACKET; t->pos++; return tok;
        case '{': tok.type = TOK_LBRACE; t->pos++; return tok;
        case '}': tok.type = TOK_RBRACE; t->pos++; return tok;
        case '=': tok.type = TOK_EQUALS; t->pos++; return tok;
        case ',': tok.type = TOK_COMMA; t->pos++; return tok;
        case ';': tok.type = TOK_SEMICOLON; t->pos++; return tok;
    }

    if (isalpha(*t->pos) || *t->pos == '_') {
        int i = 0;
        while (isalnum(*t->pos) || *t->pos == '_') {
            if (i < 255) tok.text[i++] = *t->pos;
            t->pos++;
        }
        tok.text[i] = '\0';
        tok.type = TOK_IDENT;
        return tok;
    }

    fprintf(stderr, "Skipped unexpected '%c' at line %d\n", *t->pos, t->line);
    t->pos++;
    return tok_next(t);
}

/* ===== ODL Parser ===== */
static int is_storage_name(const char *s) {
    for (int i = 0; storage_names[i]; i++)
        if (!strcasecmp(s, storage_names[i])) return 1;
    return 0;
}

static void store_elem(void *data, size_t index, uint8_t base, int sign,
                       int64_t ival, double fval, int is_float) {
    uint8_t *p = (uint8_t *)data + index * g_elem_sizes[base];
    switch (base) {
    case DATA_BYTE:
        if (sign) { int8_t v = (int8_t)ival; memcpy(p, &v, 1); }
        else { uint8_t v = (uint8_t)ival; memcpy(p, &v, 1); }
        break;
    case DATA_SHORT:
        if (sign) { int16_t v = (int16_t)ival; memcpy(p, &v, 2); }
        else { uint16_t v = (uint16_t)ival; memcpy(p, &v, 2); }
        break;
    case DATA_CHAR: {
        uint16_t v = (uint16_t)ival;
        memcpy(p, &v, 2);
        break;
    }
    case DATA_INT:
        if (sign) { int32_t v = (int32_t)ival; memcpy(p, &v, 4); }
        else { uint32_t v = (uint32_t)ival; memcpy(p, &v, 4); }
        break;
    case DATA_LONG:
        if (sign) memcpy(p, &ival, 8);
        else { uint64_t v = (uint64_t)ival; memcpy(p, &v, 8); }
        break;
    case DATA_FLOAT: {
        float v = is_float ? (float)fval : (float)ival;
        memcpy(p, &v, 4);
        break;
    }
    case DATA_DOUBLE: {
        double v = is_float ? fval : (double)ival;
        memcpy(p, &v, 8);
        break;
    }
    default:
        break;
    }
}

static int parse_aggregate(const char **s, void *dest, uint8_t base_type, bool is_signed,
                           uint32_t *dims, int max_level, int level) {
    while (isspace(**s)) (*s)++;
    if (**s == '\0') return 0;
    if (**s == '{') {
        if (level >= max_level) { fprintf(stderr, "Too many dimensions\n"); return 0; }
        int groups = 0;
        while (**s == '{') {
            (*s)++;
            (void)parse_aggregate(s, dest, base_type, is_signed, dims, max_level, level+1);
            while (isspace(**s)) (*s)++;
            if (**s != '}') { fprintf(stderr, "Missing '}'\n"); return 0; }
            (*s)++;
            groups++;
            while (isspace(**s)) (*s)++;
            if (**s == ',') { (*s)++; while (isspace(**s)) (*s)++; if (**s != '{') break; }
            else break;
        }
        dims[level] = groups;
        return groups;
    } else {
        size_t esize = g_elem_sizes[base_type];
        int count = 0;
        char *end;
        while (**s && **s != ',' && **s != '}') {
            int flt = 0;
            const char *look = *s;
            if (*look == '-' || *look == '+') look++;
            if (!(look[0] == '0' && (look[1] == 'x' || look[1] == 'X'))) {
                for (const char *q = look; *q && *q != ',' && *q != '}'; q++) {
                    if (*q == '.' || *q == 'e' || *q == 'E') { flt = 1; break; }
                    if (!isdigit((unsigned char)*q)) break;
                }
            }
            int64_t iv = 0;
            double fv = 0;
            if (flt) { fv = strtod(*s, &end); iv = (int64_t)fv; }
            else if (is_signed) iv = strtoll(*s, &end, 0);
            else iv = (int64_t)strtoull(*s, &end, 0);
            if (end == *s) break;
            store_elem(dest, 0, base_type, is_signed, iv, fv, flt);
            dest = (char*)dest + esize;
            count++;
            *s = end;
            while (isspace(**s)) (*s)++;
            if (**s == ',') { (*s)++; while (isspace(**s)) (*s)++; }
        }
        if (level < max_level) dims[level] = count;
        return count;
    }
}

/* ===== AllocObject from description ===== */
struct Object *AllocObject(const char *desc) {
    if (!desc) return NULL;
    char *buf = strdup(desc);
    if (!buf) return NULL;

    char *p = buf;
    while (isspace(*p)) p++;
    char *name_end = strchr(p, ',');
    const char *obj_name;
    if (name_end) {
        *name_end = '\0';
        obj_name = p;
        p = name_end + 1;
    } else {
        obj_name = p;
        p = p + strlen(p);
    }
    while (isspace(*p)) p++;

    struct Object *obj = calloc(1, sizeof(struct Object));
    if (!obj) { free(buf); return NULL; }
    strncpy(obj->ob_name, obj_name, sizeof(obj->ob_name)-1);
    obj->ob_name[sizeof(obj->ob_name)-1] = '\0';

    obj->ob_fields = calloc(MAX_FIELDS, sizeof(struct Field));
    if (!obj->ob_fields) { free(obj); free(buf); return NULL; }

    uint32_t field_count = 0;
    while (*p && field_count < MAX_FIELDS) {
        bool inquote = false;
        int brace_depth = 0;
        char *fend = p;
        while (*fend) {
            if (!inquote) {
                if (*fend == '"') inquote = true;
                else if (*fend == '{') brace_depth++;
                else if (*fend == '}') brace_depth--;
                else if (*fend == ',' && brace_depth == 0) break;
            } else {
                if (*fend == '"') inquote = false;
            }
            fend++;
        }
        char fsaved = *fend; *fend = '\0';
        char *fstr = p;
        while (isspace(*fstr)) fstr++;
        if (!*fstr) { *fend = fsaved; goto next; }

        char *tstart = fstr;
        char *tend = tstart;
        while (*tend && !isspace(*tend) && *tend != '[') tend++;
        char type_name[64] = {0};
        size_t tlen = tend - tstart;
        if (tlen >= sizeof(type_name)) tlen = sizeof(type_name)-1;
        memcpy(type_name, tstart, tlen);

        const TypeInfo *type = NULL;
        for (const TypeInfo *tp = type_table; tp->name; tp++)
            if (!strcmp(type_name, tp->name)) { type = tp; break; }
        if (!type) { fprintf(stderr, "Unknown type: %s\n", type_name); *fend = fsaved; goto next; }

        uint32_t dims[3] = {0};
        int dimcnt = 0;
        char *bp = tend;
        while (*bp == '[' && dimcnt < 3) {
            bp++;
            char *num_end;
            dims[dimcnt] = (uint32_t)strtoul(bp, &num_end, 10);
            if (num_end == bp) dims[dimcnt] = 0;
            bp = num_end;
            if (*bp != ']') { fprintf(stderr, "Missing ']'\n"); *fend = fsaved; goto next; }
            bp++;
            dimcnt++;
        }
        while (isspace(*bp)) bp++;

        char *nstart = bp;
        char *nend = nstart;
        while (*nend && *nend != '=' && !isspace(*nend)) nend++;
        char field_name[64] = {0};
        if (nend > nstart) {
            size_t nlen = nend - nstart;
            if (nlen >= sizeof(field_name)) nlen = sizeof(field_name)-1;
            memcpy(field_name, nstart, nlen);
        }
        bp = nend;
        while (isspace(*bp)) bp++;

        char *init_copy = NULL;
        if (*bp == '=') {
            bp++;
            while (isspace(*bp)) bp++;
            if (*bp == '"' || *bp == '{' || isdigit((unsigned char)*bp) || *bp == '-') {
                char *istart = bp;
                char *iend = istart;
                bool inq = false;
                int brace_nest = 0;
                if (*iend == '"') { inq = true; iend++; }
                else if (*iend == '{') { brace_nest++; iend++; }
                while (*iend) {
                    if (inq) {
                        if (*iend == '"') { inq = false; iend++; break; }
                    } else {
                        if (*iend == '{') brace_nest++;
                        else if (*iend == '}') {
                            brace_nest--;
                            if (brace_nest == 0) { iend++; break; }
                        }
                        else if (*iend == ',' && brace_nest == 0) break;
                    }
                    iend++;
                }
                char saved_i = *iend; *iend = '\0';
                init_copy = strdup(istart);
                *iend = saved_i;
            }
        }

        uint8_t base = type->base_type;
        size_t esize = (base == DATA_OBJECT) ? OBJ_PTR_SIZE : type->elem_size;
        bool issigned = type->is_signed;

        size_t total = 1;
        if (dimcnt > 0) {
            total = 1;
            for (int d = 0; d < dimcnt; d++) {
                if (dims[d] == 0) { total = 0; break; }
                total *= dims[d];
            }
        }
        void *data = total ? calloc(total, esize) : NULL;

        struct Field *fld = &obj->ob_fields[field_count];
        strncpy(fld->field_name, field_name, sizeof(fld->field_name)-1);
        fld->field_name[sizeof(fld->field_name)-1] = '\0';
        fld->field_type = pack_field_type(base, dimcnt, issigned, false);
        memcpy(fld->dims, dims, sizeof(dims));
        fld->data = data;
        fld->pad2 = FIELD_FLAG_ALLOCATED;

        if (init_copy && data) {
            if (base == DATA_OBJECT) {
                if (*init_copy == '{') {
                    size_t len = strlen(init_copy);
                    if (len >= 2 && init_copy[len-1] == '}') {
                        init_copy[len-1] = '\0';
                        char *inner = init_copy + 1;
                        while (isspace(*inner)) inner++;
                        struct Object *sub = AllocObject(inner);
                        if (sub) {
                            *(struct Object**)data = sub;
                            SaveObject(sub);
                            fld->pad2 |= FIELD_FLAG_SHARED;
                        }
                    }
                } else {
                    char *ref = init_copy;
                    if (*ref == '"') { ref++; char *q = strchr(ref, '"'); if (q) *q = '\0'; }
                    struct Object *sub = LoadObject(ref);
                    if (sub) {
                        *(struct Object**)data = sub;
                        fld->pad2 |= FIELD_FLAG_SHARED;
                    }
                }
            } else {
                if (*init_copy == '{') {
                    uint32_t infer[3] = {0};
                    const char *pp = init_copy;
                    parse_aggregate(&pp, data, base, issigned, infer, dimcnt, 0);
                    for (int d = 0; d < dimcnt; d++) {
                        if (dims[d] == 0) dims[d] = infer[d];
                        else if (infer[d] && infer[d] != dims[d])
                            fprintf(stderr, "Dimension mismatch %s[%d] %u vs %u\n",
                                    field_name, d, infer[d], dims[d]);
                    }
                } else {
                    char *num = init_copy;
                    uint32_t cnt = 0;
                    while (*num) {
                        if (base == DATA_FLOAT) {
                            float val = (float)strtod(num, &num);
                            memcpy((char*)data + cnt * esize, &val, esize);
                        } else if (base == DATA_DOUBLE) {
                            double val = strtod(num, &num);
                            memcpy((char*)data + cnt * esize, &val, esize);
                        } else {
                            if (issigned) {
                                int64_t val = strtoll(num, &num, 0);
                                memcpy((char*)data + cnt * esize, &val, esize);
                            } else {
                                uint64_t val = strtoull(num, &num, 0);
                                memcpy((char*)data + cnt * esize, &val, esize);
                            }
                        }
                        cnt++;
                        while (isspace(*num)) num++;
                        if (*num == ',') num++;
                        while (isspace(*num)) num++;
                    }
                    if (dimcnt > 0 && dims[0] == 0) dims[0] = cnt;
                }
            }
            free(init_copy);
        }
        field_count++;
    next:
        *fend = fsaved;
        if (*fend) p = fend + 1;
        else break;
        while (isspace(*p)) p++;
    }

    obj->ob_field_number = field_count;
    free(buf);
    return obj;
}

/* ===== ODL String Parser ===== */
static const TypeInfo *lookup_type(const char *name) {
    for (const TypeInfo *tp = type_table; tp->name; tp++)
        if (!strcasecmp(name, tp->name)) return tp;
    return NULL;
}

/* Read [n][m][] starting at tok. Returns -1 on a broken bracket. */
static int parse_dims(Tokenizer *t, Token *tok, uint32_t dims[3]) {
    int dimcnt = 0;
    while (dimcnt < 3 && tok->type == TOK_LBRACKET) {
        *tok = tok_next(t);
        if (tok->type == TOK_NUMBER) {
            dims[dimcnt] = (uint32_t)tok->ival;
            *tok = tok_next(t);
            if (tok->type != TOK_RBRACKET) return -1;
        } else if (tok->type == TOK_RBRACKET) {
            dims[dimcnt] = 0;
        } else {
            return -1;
        }
        dimcnt++;
        *tok = tok_next(t);
    }
    return dimcnt;
}

static size_t field_cap(int dimcnt, const uint32_t dims[3], int *sparse) {
    *sparse = 0;
    if (dimcnt <= 0) return 1;
    size_t cap = 1;
    for (int d = 0; d < dimcnt; d++) {
        if (dims[d] == 0) { *sparse = 1; return 1024; }
        cap *= dims[d];
    }
    return cap ? cap : 1;
}

static void apply_sparse_len(uint32_t dims[3], int dimcnt, size_t count) {
    if (count == 0) return;
    size_t rest = 1;
    int open = -1;
    for (int d = 0; d < dimcnt; d++) {
        if (dims[d] == 0) { if (open < 0) open = d; }
        else rest *= dims[d];
    }
    if (open < 0) return;
    if (open == 0 && rest) dims[0] = (uint32_t)(count / rest);
    else dims[open] = (uint32_t)count;
    for (int d = 0; d < dimcnt; d++) if (dims[d] == 0) dims[d] = 1;
}

static void store_text(void *data, uint8_t base, const char *s, size_t cap) {
    size_t n = strlen(s);
    if (n > cap) n = cap;
    for (size_t i = 0; i < n; i++)
        store_elem(data, i, base, 0, (unsigned char)s[i], 0, 0);
}

/* Numbers, floats, and nested { } groups. A comma followed by a name is the
   next field of this type (i32 a = 1, b = 2), so that name is pushed back and
   the comma is left as the current token. */
static Token parse_value_list(Tokenizer *t, Token tok, void *data, size_t cap,
                              uint8_t base, int sign, int depth, size_t *stored) {
    size_t count = 0;
    int warned = 0;
    while (tok.type != TOK_EOF) {
        if (tok.type == TOK_LBRACE) { depth++; tok = tok_next(t); continue; }
        if (tok.type == TOK_RBRACE) {
            if (depth <= 0) break;
            depth--;
            tok = tok_next(t);
            if (depth == 0) break;
            continue;
        }
        if (tok.type == TOK_NUMBER || tok.type == TOK_FLOAT) {
            if (count < cap)
                store_elem(data, count, base, sign, tok.ival, tok.fval, tok.type == TOK_FLOAT);
            else if (!warned) {
                fprintf(stderr, "Too many initializers at line %d\n", t->line);
                warned = 1;
            }
            count++;
            tok = tok_next(t);
            continue;
        }
        if (tok.type == TOK_COMMA) {
            Token nxt = tok_next(t);
            if (depth > 0 || nxt.type == TOK_NUMBER || nxt.type == TOK_FLOAT ||
                nxt.type == TOK_LBRACE || nxt.type == TOK_STRING) {
                tok = nxt;
                continue;
            }
            tok_push(t, nxt);
            break;
        }
        break;
    }
    *stored = count < cap ? count : cap;
    return tok;
}

static void parse_odl_object_block(Tokenizer *t) {
    Token tok = tok_next(t);
    if (tok.type != TOK_IDENT) {
        fprintf(stderr, "Expected object name at line %d\n", t->line);
        while (tok.type != TOK_SEMICOLON && tok.type != TOK_EOF) tok = tok_next(t);
        return;
    }

    struct Object *obj = calloc(1, sizeof(struct Object));
    if (!obj) return;
    obj->ob_fields = calloc(MAX_FIELDS, sizeof(struct Field));
    if (!obj->ob_fields) { free(obj); return; }

    strncpy(obj->ob_name, tok.text, sizeof(obj->ob_name)-1);
    obj->ob_name[sizeof(obj->ob_name)-1] = '\0';

    tok = tok_next(t);
    if (tok.type != TOK_SEMICOLON)
        fprintf(stderr, "Expected ; after object name at line %d\n", t->line);

    tok = tok_next(t);
    if (tok.type == TOK_LBRACE) tok = tok_next(t);

    uint32_t fc = 0;
    while (tok.type != TOK_EOF && tok.type != TOK_RBRACE && fc < MAX_FIELDS) {
        if (tok.type == TOK_SEMICOLON) { tok = tok_next(t); continue; }

        /* HEAP/STACK/IPC/GPU/CLOUD/REGISTRY/PAGE are layout hints. */
        while (tok.type == TOK_IDENT && is_storage_name(tok.text))
            tok = tok_next(t);

        if (tok.type == TOK_RBRACE || tok.type == TOK_EOF) break;
        if (tok.type == TOK_IDENT && !strcasecmp(tok.text, "OBJECT")) {
            tok_push(t, tok);
            break;
        }
        if (tok.type != TOK_IDENT) {
            fprintf(stderr, "Expected type at line %d\n", t->line);
            break;
        }

        const TypeInfo *type = lookup_type(tok.text);
        if (!type) {
            fprintf(stderr, "Expected type at line %d ('%s')\n", t->line, tok.text);
            obj->ob_field_number = fc;
            FreeObject(obj);
            return;
        }

        uint8_t base = type->base_type;
        int sign = type->is_signed;
        size_t esize = (base == DATA_OBJECT) ? OBJ_PTR_SIZE : type->elem_size;
        int shared = 0;
        int shared_dimcnt = 0;
        uint32_t shared_dims[3] = {0};

        tok = tok_next(t);
        if (tok.type == TOK_LBRACKET) {
            shared_dimcnt = parse_dims(t, &tok, shared_dims);
            if (shared_dimcnt < 0) {
                fprintf(stderr, "Expected number or ] at line %d\n", t->line);
                obj->ob_field_number = fc;
                FreeObject(obj);
                return;
            }
            shared = 1;
        }

        while (fc < MAX_FIELDS) {
            uint32_t dims[3] = {0};
            int dimcnt = 0;
            char fname[64] = {0};

            if (shared) {
                if (tok.type != TOK_IDENT) {
                    fprintf(stderr, "Expected field name at line %d\n", t->line);
                    obj->ob_field_number = fc;
                    FreeObject(obj);
                    return;
                }
                strncpy(fname, tok.text, sizeof(fname)-1);
                dimcnt = shared_dimcnt;
                memcpy(dims, shared_dims, sizeof(dims));
                tok = tok_next(t);
            } else {
                if (tok.type != TOK_IDENT) {
                    fprintf(stderr, "Expected field name at line %d\n", t->line);
                    obj->ob_field_number = fc;
                    FreeObject(obj);
                    return;
                }
                strncpy(fname, tok.text, sizeof(fname)-1);
                tok = tok_next(t);
                dimcnt = parse_dims(t, &tok, dims);
                if (dimcnt < 0) {
                    fprintf(stderr, "Expected number or ] at line %d\n", t->line);
                    obj->ob_field_number = fc;
                    FreeObject(obj);
                    return;
                }
            }

            struct Field *fld = &obj->ob_fields[fc];
            strncpy(fld->field_name, fname, sizeof(fld->field_name)-1);
            fld->field_type = pack_field_type(base, dimcnt, sign, false);
            memcpy(fld->dims, dims, sizeof(dims));

            if (tok.type == TOK_EQUALS) {
                tok = tok_next(t);
                int brace = 0;
                if (tok.type == TOK_LBRACE && base != DATA_OBJECT) {
                    brace = 1;
                    tok = tok_next(t);
                }
                if (base == DATA_OBJECT) {
                    if (tok.type == TOK_LBRACE) {
                        char obj_desc[1024] = {0};
                        int depth = 1, i = 0;
                        while (depth > 0 && i < 1020) {
                            tok = tok_next(t);
                            if (tok.type == TOK_EOF) break;
                            if (tok.type == TOK_LBRACE) depth++;
                            if (tok.type == TOK_RBRACE) depth--;
                            if (depth > 0 && tok.text[0]) {
                                if (i > 0) obj_desc[i++] = ' ';
                                size_t n = strlen(tok.text);
                                if (i + n >= sizeof(obj_desc)) n = sizeof(obj_desc) - 1 - i;
                                memcpy(obj_desc + i, tok.text, n);
                                i += (int)n;
                                obj_desc[i] = '\0';
                            }
                        }
                        if (tok.type == TOK_RBRACE) tok = tok_next(t);
                        struct Object *sub = AllocObject(obj_desc);
                        if (sub) {
                            fld->data = calloc(1, sizeof(void *));
                            *(struct Object **)fld->data = sub;
                            SaveObject(sub);
                            ExportObject(sub, g_export_flags);
                        }
                    } else if (tok.type == TOK_IDENT || tok.type == TOK_STRING) {
                        struct Object *sub = LoadObject(tok.text);
                        if (sub) {
                            fld->data = calloc(1, sizeof(void *));
                            *(struct Object **)fld->data = sub;
                        }
                        tok = tok_next(t);
                    }
                } else if (tok.type == TOK_STRING && (base == DATA_CHAR || base == DATA_BYTE)) {
                    int sparse = 0;
                    size_t cap = field_cap(dimcnt, dims, &sparse);
                    void *data = calloc(cap, esize);
                    size_t n = strlen(tok.text);
                    if (n > cap) n = cap;
                    if (data) store_text(data, base, tok.text, cap);
                    if (sparse) apply_sparse_len(dims, dimcnt, n);
                    memcpy(fld->dims, dims, sizeof(dims));
                    fld->field_type = pack_field_type(base, dimcnt, sign, false);
                    fld->data = data;
                    if (data) fld->pad2 |= FIELD_FLAG_ALLOCATED;
                    tok = tok_next(t);
                    if (brace && tok.type == TOK_RBRACE) tok = tok_next(t);
                } else {
                    int sparse = 0;
                    size_t cap = field_cap(dimcnt, dims, &sparse);
                    void *data = calloc(cap, esize);
                    size_t stored = 0;
                    if (data)
                        tok = parse_value_list(t, tok, data, cap, base, sign, brace, &stored);
                    else
                        tok = parse_value_list(t, tok, NULL, 0, base, sign, brace, &stored);
                    if (sparse) apply_sparse_len(dims, dimcnt, stored);
                    memcpy(fld->dims, dims, sizeof(dims));
                    fld->field_type = pack_field_type(base, dimcnt, sign, false);
                    fld->data = data;
                    if (data) fld->pad2 |= FIELD_FLAG_ALLOCATED;
                }
            }

            fc++;
            obj->ob_field_number = fc;

            if (tok.type == TOK_SEMICOLON) { tok = tok_next(t); break; }
            if (tok.type == TOK_COMMA) {
                Token nxt = tok_next(t);
                if (nxt.type == TOK_IDENT) { tok = nxt; continue; }
                tok_push(t, nxt);
                break;
            }
            break;
        }
    }

    obj->ob_field_number = fc;
    if (obj->ob_name[0]) {
        SaveObject(obj);
        ExportObject(obj, g_export_flags);
    }
    FreeObject(obj);
}

void LoadODLString(const char *src) {
    Tokenizer t;
    tok_init(&t, src);
    Token tok;
    while ((tok = tok_next(&t)).type != TOK_EOF) {
        if (tok.type == TOK_IDENT && !strcasecmp(tok.text, "OBJECT")) {
            parse_odl_object_block(&t);
        }
    }
}

void LoadODLFile(const char *filename) {
    int fd = open(filename, O_RDONLY);
    if (fd < 0) {
        perror("Cannot open ODL file");
        return;
    }
    off_t size = lseek(fd, 0, SEEK_END);
    lseek(fd, 0, SEEK_SET);
    char *src = malloc(size + 1);
    if (!src) { close(fd); return; }
    read(fd, src, size);
    src[size] = '\0';
    close(fd);
    LoadODLString(src);
    free(src);
}

static char *extract_first_object_name(const char *src) {
    Tokenizer t;
    tok_init(&t, src);
    Token tok;
    while ((tok = tok_next(&t)).type != TOK_EOF) {
        if (tok.type == TOK_IDENT && !strcasecmp(tok.text, "OBJECT")) {
            tok = tok_next(&t);
            if (tok.type == TOK_IDENT) {
                return strdup(tok.text);
            }
            break;
        }
    }
    return NULL;
}

/* ===== File I/O for .chd ===== */
static int write_all(int fd, const void *buf, size_t len) {
    const char *p = buf;
    while (len) {
        ssize_t n = write(fd, p, len);
        if (n <= 0) return -1;
        p += n; len -= n;
    }
    return 0;
}

static int read_all(int fd, void *buf, size_t len) {
    char *p = buf;
    while (len) {
        ssize_t n = read(fd, p, len);
        if (n <= 0) return -1;
        p += n; len -= n;
    }
    return 0;
}

/* .chd bytes are the FSendObject image. Dimensions and pad2 stay host-endian,
   the same way the socket writer has always emitted them. Element values are
   network order. Listeners and function pointers stay off the image. */
static size_t field_elems(const struct Field *f) {
    int dimcnt = (f->field_type >> DIM_SHIFT) & 0x03;
    size_t elems = 1;
    for (int d = 0; d < dimcnt && d < 3; d++)
        if (f->dims[d]) elems *= f->dims[d];
    return elems;
}

static uint8_t *serialize_object(struct Object *obj, size_t *out_len) {
    if (!obj || !out_len) return NULL;
    size_t name_len = strlen(obj->ob_name) + 1;
    size_t total_size = sizeof(SerialHeader) + name_len;

    for (uint32_t i = 0; i < obj->ob_field_number; i++) {
        struct Field *f = &obj->ob_fields[i];
        uint8_t base = f->field_type & 0x07;
        size_t elems = field_elems(f);
        total_size += 64 + 1 + 12 + 4;
        if (base == DATA_OBJECT) {
            struct Object **objs = (struct Object **)f->data;
            for (size_t j = 0; j < elems; j++)
                total_size += (objs && objs[j]) ? strlen(objs[j]->ob_name) + 1 : 1;
        } else {
            total_size += elems * g_elem_sizes[base];
        }
    }
    if (total_size > 10u * 1024u * 1024u) return NULL;

    uint8_t *buf = (uint8_t *)malloc(total_size);
    if (!buf) return NULL;
    uint8_t *ptr = buf;

    SerialHeader *hdr = (SerialHeader *)ptr;
    hdr->magic = hton32(SER_MAGIC);
    hdr->version = hton32(SER_VERSION);
    hdr->flags = hton64(obj->ob_flags);
    hdr->name_len = hton32((uint32_t)name_len);
    hdr->field_count = hton32(obj->ob_field_number);
    hdr->total_size = hton32((uint32_t)total_size);
    ptr += sizeof(SerialHeader);

    memcpy(ptr, obj->ob_name, name_len);
    ptr += name_len;

    for (uint32_t i = 0; i < obj->ob_field_number; i++) {
        struct Field *f = &obj->ob_fields[i];
        uint8_t base = f->field_type & 0x07;
        size_t elems = field_elems(f);

        memcpy(ptr, f->field_name, 64);
        ptr += 64;
        *ptr++ = f->field_type;
        memcpy(ptr, f->dims, 12);
        ptr += 12;
        memcpy(ptr, &f->pad2, 4);
        ptr += 4;

        if (base == DATA_OBJECT) {
            struct Object **objs = (struct Object **)f->data;
            for (size_t j = 0; j < elems; j++) {
                if (objs && objs[j]) {
                    size_t len = strlen(objs[j]->ob_name) + 1;
                    memcpy(ptr, objs[j]->ob_name, len);
                    ptr += len;
                } else {
                    *ptr++ = 0;
                }
            }
        } else {
            size_t ds = elems * g_elem_sizes[base];
            if (f->data && (f->pad2 & FIELD_FLAG_ALLOCATED)) {
                if (g_elem_sizes[base] == 2) {
                    for (size_t j = 0; j < elems; j++) {
                        uint16_t val;
                        memcpy(&val, (uint8_t *)f->data + j * 2, 2);
                        val = hton16(val);
                        memcpy(ptr, &val, 2);
                        ptr += 2;
                    }
                } else if (g_elem_sizes[base] == 4) {
                    for (size_t j = 0; j < elems; j++) {
                        uint32_t val;
                        memcpy(&val, (uint8_t *)f->data + j * 4, 4);
                        val = hton32(val);
                        memcpy(ptr, &val, 4);
                        ptr += 4;
                    }
                } else if (g_elem_sizes[base] == 8) {
                    for (size_t j = 0; j < elems; j++) {
                        uint64_t val;
                        memcpy(&val, (uint8_t *)f->data + j * 8, 8);
                        val = hton64(val);
                        memcpy(ptr, &val, 8);
                        ptr += 8;
                    }
                } else {
                    memcpy(ptr, f->data, ds);
                    ptr += ds;
                }
            } else {
                memset(ptr, 0, ds);
                ptr += ds;
            }
        }
    }

    if ((size_t)(ptr - buf) != total_size) { free(buf); return NULL; }
    *out_len = total_size;
    return buf;
}

static struct Object *deserialize_buffer(const uint8_t *buf, size_t len, int resolve);

void SaveObject(struct Object *obj) {
    if (!obj || !obj->ob_name[0]) return;
    for (uint32_t i = 0; i < obj->ob_field_number; i++) {
        struct Field *fld = &obj->ob_fields[i];
        if ((fld->field_type & 0x07) != DATA_OBJECT) continue;
        if (fld->pad2 & FIELD_FLAG_SHARED) continue;
        struct Object **subs = fld->data;
        size_t total = field_elems(fld);
        for (size_t j = 0; j < total; j++)
            if (subs && subs[j]) SaveObject(subs[j]);
    }
    char objdir[512];
    if (snprintf(objdir, sizeof(objdir), "%s/%s", g_object_dir, obj->ob_name) >= (int)sizeof(objdir)) { fprintf(stderr, "Path too long: %s/%s\n", g_object_dir, obj->ob_name); return; }
    make_directory(objdir);
    char file_path[512];
    build_obj_path(file_path, sizeof(file_path), obj->ob_name, "chd");
    size_t n = 0;
    uint8_t *buf = serialize_object(obj, &n);
    if (!buf) return;
    int fd = open(file_path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
    if (fd < 0) { perror("open save"); free(buf); return; }
    if (write_all(fd, buf, n) != 0) perror("write save");
    close(fd);
    free(buf);
    printf("Saved: %s\n", file_path);
}

static struct Object *deserialize_buffer(const uint8_t *buf, size_t len, int resolve) {
    if (!buf || len < sizeof(SerialHeader)) return NULL;
    SerialHeader hdr;
    memcpy(&hdr, buf, sizeof(hdr));
    if (ntoh32(hdr.magic) != SER_MAGIC || ntoh32(hdr.version) != SER_VERSION) return NULL;
    uint32_t total = ntoh32(hdr.total_size);
    if (total < sizeof(SerialHeader) || (size_t)total > len || total > 10u * 1024u * 1024u)
        return NULL;

    const uint8_t *ptr = buf + sizeof(SerialHeader);
    const uint8_t *end = buf + total;
    uint32_t name_len = ntoh32(hdr.name_len);
    if (name_len == 0 || (size_t)name_len > (size_t)(end - ptr)) return NULL;

    struct Object *obj = calloc(1, sizeof(struct Object));
    if (!obj) return NULL;
    size_t copy = name_len < sizeof(obj->ob_name) ? name_len : sizeof(obj->ob_name);
    memcpy(obj->ob_name, ptr, copy);
    obj->ob_name[sizeof(obj->ob_name) - 1] = '\0';
    ptr += name_len;

    obj->ob_field_number = ntoh32(hdr.field_count);
    obj->ob_flags = ntoh64(hdr.flags);
    if (obj->ob_field_number > MAX_FIELDS) { free(obj); return NULL; }
    obj->ob_fields = calloc(obj->ob_field_number ? obj->ob_field_number : 1, sizeof(struct Field));
    if (!obj->ob_fields) { free(obj); return NULL; }

    for (uint32_t i = 0; i < obj->ob_field_number; i++) {
        struct Field *f = &obj->ob_fields[i];
        if (ptr + 81 > end) goto error;
        memcpy(f->field_name, ptr, 64);
        f->field_name[63] = '\0';
        ptr += 64;
        f->field_type = *ptr++;
        memcpy(f->dims, ptr, 12);
        ptr += 12;
        memcpy(&f->pad2, ptr, 4);
        ptr += 4;

        uint8_t base = f->field_type & 0x07;
        size_t elems = field_elems(f);
        if (elems > 1000000) goto error;

        if (base == DATA_OBJECT) {
            f->data = calloc(elems, sizeof(void *));
            if (!f->data) goto error;
            struct Object **objs = f->data;
            for (size_t j = 0; j < elems; j++) {
                if (ptr >= end) goto error;
                size_t left = (size_t)(end - ptr);
                size_t sl = 0;
                while (sl < left && ptr[sl]) sl++;
                if (sl == left) goto error;
                ptr += sl + 1;
                if (resolve && sl) {
                    struct Object *sub = LoadObject((const char *)(ptr - sl - 1));
                    if (sub) objs[j] = sub;
                }
            }
        } else {
            size_t ds = elems * g_elem_sizes[base];
            if (ptr + ds > end) goto error;
            f->data = malloc(ds ? ds : 1);
            if (!f->data) goto error;
            if (g_elem_sizes[base] == 2) {
                for (size_t j = 0; j < elems; j++) {
                    uint16_t val;
                    memcpy(&val, ptr, 2);
                    val = ntoh16(val);
                    memcpy((uint8_t *)f->data + j * 2, &val, 2);
                    ptr += 2;
                }
            } else if (g_elem_sizes[base] == 4) {
                for (size_t j = 0; j < elems; j++) {
                    uint32_t val;
                    memcpy(&val, ptr, 4);
                    val = ntoh32(val);
                    memcpy((uint8_t *)f->data + j * 4, &val, 4);
                    ptr += 4;
                }
            } else if (g_elem_sizes[base] == 8) {
                for (size_t j = 0; j < elems; j++) {
                    uint64_t val;
                    memcpy(&val, ptr, 8);
                    val = ntoh64(val);
                    memcpy((uint8_t *)f->data + j * 8, &val, 8);
                    ptr += 8;
                }
            } else {
                memcpy(f->data, ptr, ds);
                ptr += ds;
            }
            f->pad2 |= FIELD_FLAG_ALLOCATED;
        }
    }
    return obj;

error:
    FreeObject(obj);
    return NULL;
}

struct Object *LoadObject(const char *name) {
    char file_path[512];
    build_obj_path(file_path, sizeof(file_path), name, "chd");
    int fd = open(file_path, O_RDONLY | O_BINARY);
    if (fd < 0) return NULL;
    off_t sz = lseek(fd, 0, SEEK_END);
    if (sz < (off_t)sizeof(SerialHeader) || sz > 10 * 1024 * 1024) { close(fd); return NULL; }
    if (lseek(fd, 0, SEEK_SET) < 0) { close(fd); return NULL; }
    uint8_t *buf = malloc((size_t)sz);
    if (!buf) { close(fd); return NULL; }
    if (read_all(fd, buf, (size_t)sz) != 0) { free(buf); close(fd); return NULL; }
    close(fd);
    struct Object *obj = deserialize_buffer(buf, (size_t)sz, 1);
    free(buf);
    return obj;
}

void FreeObject(struct Object *obj) {
    if (!obj) return;
    if (obj->ob_fields) {
        for (uint32_t i = 0; i < obj->ob_field_number; i++) {
            struct Field *fld = &obj->ob_fields[i];
            if (fld->data) {
                uint8_t base = fld->field_type & 0x07;
                if (base == DATA_OBJECT) {
                    if (!(fld->pad2 & FIELD_FLAG_SHARED)) {
                        int dimcnt = (fld->field_type >> DIM_SHIFT) & 0x03;
                        size_t total = 1;
                        if (dimcnt) { total = 1; for (int d=0; d<dimcnt; d++) total *= fld->dims[d]; }
                        struct Object **objs = fld->data;
                        for (size_t j = 0; j < total; j++) if (objs[j]) FreeObject(objs[j]);
                    }
                }
                free(fld->data);
            }
        }
        free(obj->ob_fields);
    }
    free(obj);
}

/* ===== Language Exports ===== */
static int export_fd;
static void write_str(const char *s) { write_all(export_fd, s, strlen(s)); }
static void write_fmt(const char *fmt, ...) {
    va_list ap; va_start(ap, fmt);
    char buf[4096]; vsnprintf(buf, sizeof(buf), fmt, ap); va_end(ap);
    write_str(buf);
}

static void export_lang(struct Object *obj, const char *ext,
                        void (*prolog)(struct Object*), void (*epilog)(struct Object*),
                        void (*fieldfn)(struct Field*)) {
    if (!obj || !obj->ob_name[0]) return;
    char objdir[512]; if (snprintf(objdir, sizeof(objdir), "%s/%s", g_object_dir, obj->ob_name) >= (int)sizeof(objdir)) { fprintf(stderr, "Path too long: %s/%s\n", g_object_dir, obj->ob_name); return; }
    make_directory(objdir);
    char path[512]; build_obj_path(path, sizeof(path), obj->ob_name, ext);
    export_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (export_fd < 0) { perror("export open"); return; }
    prolog(obj);
    for (uint32_t i = 0; i < obj->ob_field_number; i++) fieldfn(&obj->ob_fields[i]);
    epilog(obj);
    close(export_fd);
    printf("%-6s -> %s\n", ext, path);
}

static int ft_signed(uint8_t ft) { return (ft & SIGN_BIT) != 0; }
static uint8_t ft_base(uint8_t ft) { return ft & 0x07; }
static int ft_dims(uint8_t ft) { return (ft >> DIM_SHIFT) & 0x03; }

static const char *c_type_ft(uint8_t ft) {
    int s = ft_signed(ft);
    switch (ft_base(ft)) {
    case DATA_BYTE:   return s ? "int8_t" : "uint8_t";
    case DATA_SHORT:  return s ? "int16_t" : "uint16_t";
    case DATA_CHAR:   return "uint16_t";
    case DATA_INT:    return s ? "int32_t" : "uint32_t";
    case DATA_LONG:   return s ? "int64_t" : "uint64_t";
    case DATA_FLOAT:  return "float";
    case DATA_DOUBLE: return "double";
    case DATA_OBJECT: return "struct Object*";
    default:          return "int64_t";
    }
}
static const char *java_t_ft(uint8_t ft) {
    int s = ft_signed(ft);
    switch (ft_base(ft)) {
    case DATA_BYTE:   return s ? "byte" : "int";
    case DATA_SHORT:  return s ? "short" : "int";
    case DATA_CHAR:   return "char";
    case DATA_INT:    return s ? "int" : "long";
    case DATA_LONG:   return "long";
    case DATA_FLOAT:  return "float";
    case DATA_DOUBLE: return "double";
    case DATA_OBJECT: return "Object";
    default:          return "long";
    }
}
static const char *ts_t_ft(uint8_t ft) {
    uint8_t b = ft_base(ft);
    if (b == DATA_LONG) return "bigint";
    if (b <= DATA_DOUBLE) return "number";
    return "any";
}
static const char *go_t_ft(uint8_t ft) {
    int s = ft_signed(ft);
    switch (ft_base(ft)) {
    case DATA_BYTE:   return s ? "int8" : "uint8";
    case DATA_SHORT:  return s ? "int16" : "uint16";
    case DATA_CHAR:   return "uint16";
    case DATA_INT:    return s ? "int32" : "uint32";
    case DATA_LONG:   return s ? "int64" : "uint64";
    case DATA_FLOAT:  return "float32";
    case DATA_DOUBLE: return "float64";
    case DATA_OBJECT: return "interface{}";
    default:          return "int64";
    }
}
static const char *swift_t_ft(uint8_t ft) {
    int s = ft_signed(ft);
    switch (ft_base(ft)) {
    case DATA_BYTE:   return s ? "Int8" : "UInt8";
    case DATA_SHORT:  return s ? "Int16" : "UInt16";
    case DATA_CHAR:   return "UInt16";
    case DATA_INT:    return s ? "Int32" : "UInt32";
    case DATA_LONG:   return s ? "Int64" : "UInt64";
    case DATA_FLOAT:  return "Float";
    case DATA_DOUBLE: return "Double";
    case DATA_OBJECT: return "AnyObject";
    default:          return "Int64";
    }
}
static const char *odl_type_name(uint8_t ft) {
    int s = ft_signed(ft);
    switch (ft_base(ft)) {
    case DATA_BYTE:   return s ? "i8" : "u8";
    case DATA_SHORT:  return s ? "i16" : "u16";
    case DATA_CHAR:   return "char";
    case DATA_INT:    return s ? "i32" : "u32";
    case DATA_LONG:   return s ? "i64" : "u64";
    case DATA_FLOAT:  return "f32";
    case DATA_DOUBLE: return "f64";
    case DATA_OBJECT: return "Object";
    default:          return "i64";
    }
}

static void format_elem(char *dst, size_t dstsz, const struct Field *f, size_t index) {
    uint8_t b = ft_base(f->field_type);
    int sign = ft_signed(f->field_type);
    const uint8_t *p = (const uint8_t *)f->data + index * g_elem_sizes[b];
    switch (b) {
    case DATA_BYTE:
        if (sign) { int8_t v; memcpy(&v, p, 1); snprintf(dst, dstsz, "%d", (int)v); }
        else { uint8_t v; memcpy(&v, p, 1); snprintf(dst, dstsz, "%u", (unsigned)v); }
        break;
    case DATA_SHORT:
        if (sign) { int16_t v; memcpy(&v, p, 2); snprintf(dst, dstsz, "%d", (int)v); }
        else { uint16_t v; memcpy(&v, p, 2); snprintf(dst, dstsz, "%u", (unsigned)v); }
        break;
    case DATA_CHAR: {
        uint16_t v; memcpy(&v, p, 2);
        snprintf(dst, dstsz, "%u", (unsigned)v);
        break;
    }
    case DATA_INT:
        if (sign) { int32_t v; memcpy(&v, p, 4); snprintf(dst, dstsz, "%d", (int)v); }
        else { uint32_t v; memcpy(&v, p, 4); snprintf(dst, dstsz, "%u", (unsigned)v); }
        break;
    case DATA_LONG:
        if (sign) { int64_t v; memcpy(&v, p, 8); snprintf(dst, dstsz, "%lld", (long long)v); }
        else { uint64_t v; memcpy(&v, p, 8); snprintf(dst, dstsz, "%llu", (unsigned long long)v); }
        break;
    case DATA_FLOAT: {
        float v; memcpy(&v, p, 4); snprintf(dst, dstsz, "%.9g", (double)v); break;
    }
    case DATA_DOUBLE: {
        double v; memcpy(&v, p, 8); snprintf(dst, dstsz, "%.17g", v); break;
    }
    default:
        snprintf(dst, dstsz, "0");
        break;
    }
}

static void write_escaped_unit(uint16_t v) {
    if (v == '"' || v == '\\') write_fmt("\\%c", (char)v);
    else if (v == '\n') write_str("\\n");
    else if (v == '\t') write_str("\\t");
    else if (v < 32 || v > 126) write_fmt("\\u%04x", (unsigned)v);
    else write_fmt("%c", (char)v);
}

static void write_text_field(const struct Field *f) {
    uint8_t b = ft_base(f->field_type);
    int d = ft_dims(f->field_type);
    size_t n = d ? f->dims[0] : 1;
    size_t es = g_elem_sizes[b];
    write_str("\"");
    for (size_t i = 0; i < n; i++) {
        uint16_t v = 0;
        memcpy(&v, (const uint8_t *)f->data + i * es, es < 2 ? es : 2);
        if (es == 1) v = (uint16_t)(*(const uint8_t *)((const uint8_t *)f->data + i));
        if (v == 0) break;
        write_escaped_unit(v);
    }
    write_str("\"");
}

static void write_dims_value(const struct Field *f, int dim, size_t *idx) {
    int dimcnt = ft_dims(f->field_type);
    uint32_t n = f->dims[dim];
    write_str("[");
    for (uint32_t i = 0; i < n; i++) {
        if (i) write_str(", ");
        if (dim + 1 < dimcnt) write_dims_value(f, dim + 1, idx);
        else {
            char buf[80];
            format_elem(buf, sizeof buf, f, *idx);
            write_str(buf);
            (*idx)++;
        }
    }
    write_str("]");
}

static void write_field_value(const struct Field *f) {
    uint8_t b = ft_base(f->field_type);
    int d = ft_dims(f->field_type);
    const char *blank = "null";
    if (b == DATA_OBJECT) {
        struct Object **o = f->data;
        if (o && *o) write_fmt("\"%s\"", (*o)->ob_name);
        else write_str(blank);
        return;
    }
    if (!f->data || !(f->pad2 & FIELD_FLAG_ALLOCATED)) { write_str(blank); return; }
    if (b == DATA_CHAR) { write_text_field(f); return; }
    if (d == 0) {
        char buf[80];
        format_elem(buf, sizeof buf, f, 0);
        write_str(buf);
        return;
    }
    size_t idx = 0;
    write_dims_value(f, 0, &idx);
}

static int g_value_comma;

static void java_pro(struct Object *o) { write_fmt("public class %s {\n", o->ob_name); }
static void java_field(struct Field *f) { int d = ft_dims(f->field_type); write_fmt("    public %s", java_t_ft(f->field_type)); for (int i=0; i<d; i++) write_fmt("[]"); write_fmt(" %s;\n", f->field_name); }
static void java_epi(struct Object *o) { (void)o; write_fmt("}\n"); }

static void js_pro(struct Object *o) { g_value_comma = 0; write_fmt("const %s = {\n", o->ob_name); }
static void js_field(struct Field *f) {
    if (g_value_comma) write_str(",\n");
    g_value_comma = 1;
    write_fmt("  %s: ", f->field_name);
    write_field_value(f);
}
static void js_epi(struct Object *o) { (void)o; write_str("\n};\n"); }

static void json_pro(struct Object *o) { g_value_comma = 0; write_fmt("{\n  \"name\": \"%s\",\n  \"fields\": {\n", o->ob_name); }
static void json_field(struct Field *f) {
    if (g_value_comma) write_str(",\n");
    g_value_comma = 1;
    write_fmt("    \"%s\": ", f->field_name);
    write_field_value(f);
}
static void json_epi(struct Object *o) { (void)o; write_str("\n  }\n}\n"); }

static void ts_pro(struct Object *o) { write_fmt("interface %s {\n", o->ob_name); }
static void ts_field(struct Field *f) { int d = ft_dims(f->field_type); write_fmt("  %s: %s", f->field_name, ts_t_ft(f->field_type)); for (int i=0; i<d; i++) write_fmt("[]"); write_fmt(";\n"); }
static void ts_epi(struct Object *o) { (void)o; write_fmt("}\n"); }


static void c_pro(struct Object *o) { write_fmt("#ifndef %s_H\n#define %s_H\n\n#include <stdint.h>\n\nstruct %s {\n", o->ob_name, o->ob_name, o->ob_name); }
static void c_field(struct Field *f) { int d = ft_dims(f->field_type); write_fmt("    %s %s", c_type_ft(f->field_type), f->field_name); for (int i=0; i<d; i++) write_fmt("[%u]", f->dims[i]); write_fmt(";\n"); }
static void c_epi(struct Object *o) { (void)o; write_fmt("};\n\n#endif\n"); }

static void go_pro(struct Object *o) { write_fmt("package main\n\ntype %s struct {\n", o->ob_name); }
static void go_field(struct Field *f) { int d = ft_dims(f->field_type); char cap[64]; strncpy(cap, f->field_name, sizeof(cap)-1); cap[sizeof(cap)-1] = '\0'; if (cap[0]) cap[0] = (char)toupper((unsigned char)cap[0]); write_fmt("    %s ", cap); for (int i=0; i<d; i++) write_fmt("[]"); write_fmt("%s\n", go_t_ft(f->field_type)); }
static void go_epi(struct Object *o) { (void)o; write_fmt("}\n"); }

static void sw_pro(struct Object *o) { write_fmt("struct %s {\n", o->ob_name); }
static void sw_field(struct Field *f) { int d = ft_dims(f->field_type); write_fmt("    var %s: ", f->field_name); for (int i=0; i<d; i++) write_fmt("["); write_fmt("%s", swift_t_ft(f->field_type)); for (int i=0; i<d; i++) write_fmt("]"); write_fmt("\n"); }
static void sw_epi(struct Object *o) { (void)o; write_fmt("}\n"); }

void SaveJavaClass(struct Object *obj)    { export_lang(obj, "java",   java_pro, java_epi, java_field); }
void SaveJavaScript(struct Object *obj)   { export_lang(obj, "js",     js_pro,   js_epi,   js_field); }
void SaveJSON(struct Object *obj)         { export_lang(obj, "json",   json_pro, json_epi, json_field); }
void SaveTypeScript(struct Object *obj)   { export_lang(obj, "ts",     ts_pro,   ts_epi,   ts_field); }
void SaveCHeader(struct Object *obj)      { export_lang(obj, "h",      c_pro,    c_epi,    c_field); }
void SaveGoStruct(struct Object *obj)     { export_lang(obj, "go",     go_pro,   go_epi,   go_field); }
void SaveSwiftStruct(struct Object *obj)  { export_lang(obj, "swift",  sw_pro,   sw_epi,   sw_field); }

void SaveRustStruct(struct Object *obj) {
    if (!obj || !obj->ob_name[0]) return;
    char objdir[512]; if (snprintf(objdir, sizeof(objdir), "%s/%s", g_object_dir, obj->ob_name) >= (int)sizeof(objdir)) { fprintf(stderr, "Path too long: %s/%s\n", g_object_dir, obj->ob_name); return; }
    make_directory(objdir);
    char path[512]; build_obj_path(path, sizeof(path), obj->ob_name, "rs");
    export_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (export_fd < 0) { perror("open rs"); return; }
    write_fmt("// Rust struct for %s\n", obj->ob_name);
    write_fmt("#[derive(Debug, Clone)]\n");
    write_fmt("pub struct %s {\n", obj->ob_name);
    for (uint32_t i = 0; i < obj->ob_field_number; i++) {
        struct Field *f = &obj->ob_fields[i];
        uint8_t b = f->field_type & 0x07;
        int s = ft_signed(f->field_type);
        int d = (f->field_type >> DIM_SHIFT) & 0x03;
        const char *t = "i64";
        switch (b) {
            case DATA_BYTE:   t = s ? "i8" : "u8"; break;
            case DATA_SHORT:  t = s ? "i16" : "u16"; break;
            case DATA_CHAR:   t = "u16"; break;
            case DATA_INT:    t = s ? "i32" : "u32"; break;
            case DATA_LONG:   t = s ? "i64" : "u64"; break;
            case DATA_FLOAT:  t = "f32"; break;
            case DATA_DOUBLE: t = "f64"; break;
            case DATA_OBJECT: t = "String"; break;
        }
        write_fmt("    pub %s: ", f->field_name);
        for (int j = 0; j < d; j++) write_fmt("Vec<");
        write_fmt("%s", t);
        for (int j = 0; j < d; j++) write_fmt(">");
        write_fmt(",\n");
    }
    write_fmt("}\n");
    close(export_fd);
    printf("Rust  -> %s\n", path);
}

void SaveKotlinClass(struct Object *obj) {
    if (!obj || !obj->ob_name[0]) return;
    char objdir[512]; if (snprintf(objdir, sizeof(objdir), "%s/%s", g_object_dir, obj->ob_name) >= (int)sizeof(objdir)) { fprintf(stderr, "Path too long: %s/%s\n", g_object_dir, obj->ob_name); return; }
    make_directory(objdir);
    char path[512]; build_obj_path(path, sizeof(path), obj->ob_name, "kt");
    export_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (export_fd < 0) { perror("open kt"); return; }
    write_fmt("data class %s (\n", obj->ob_name);
    for (uint32_t i = 0; i < obj->ob_field_number; i++) {
        struct Field *f = &obj->ob_fields[i];
        uint8_t b = f->field_type & 0x07;
        int s = ft_signed(f->field_type);
        int d = (f->field_type >> DIM_SHIFT) & 0x03;
        const char *t = "Long";
        switch (b) {
            case DATA_BYTE:   t = s ? "Byte" : "UByte"; break;
            case DATA_SHORT:  t = s ? "Short" : "UShort"; break;
            case DATA_CHAR:   t = "Char"; break;
            case DATA_INT:    t = s ? "Int" : "UInt"; break;
            case DATA_LONG:   t = s ? "Long" : "ULong"; break;
            case DATA_FLOAT:  t = "Float"; break;
            case DATA_DOUBLE: t = "Double"; break;
            case DATA_OBJECT: t = "Any"; break;
        }
        write_fmt("    val %s: %s", f->field_name, t);
        for (int j = 0; j < d; j++) write_fmt("Array");
        if (i < obj->ob_field_number - 1) write_fmt(",");
        write_fmt("\n");
    }
    write_fmt(")\n");
    close(export_fd);
    printf("Kotlin -> %s\n", path);
}

void SaveCSharpStruct(struct Object *obj) {
    if (!obj || !obj->ob_name[0]) return;
    char objdir[512]; if (snprintf(objdir, sizeof(objdir), "%s/%s", g_object_dir, obj->ob_name) >= (int)sizeof(objdir)) { fprintf(stderr, "Path too long: %s/%s\n", g_object_dir, obj->ob_name); return; }
    make_directory(objdir);
    char path[512]; build_obj_path(path, sizeof(path), obj->ob_name, "cs");
    export_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (export_fd < 0) { perror("open cs"); return; }
    write_fmt("public record struct %s {\n", obj->ob_name);
    for (uint32_t i = 0; i < obj->ob_field_number; i++) {
        struct Field *f = &obj->ob_fields[i];
        uint8_t b = f->field_type & 0x07;
        int s = ft_signed(f->field_type);
        int d = (f->field_type >> DIM_SHIFT) & 0x03;
        const char *t = "long";
        switch (b) {
            case DATA_BYTE:   t = s ? "sbyte" : "byte"; break;
            case DATA_SHORT:  t = s ? "short" : "ushort"; break;
            case DATA_CHAR:   t = "char"; break;
            case DATA_INT:    t = s ? "int" : "uint"; break;
            case DATA_LONG:   t = s ? "long" : "ulong"; break;
            case DATA_FLOAT:  t = "float"; break;
            case DATA_DOUBLE: t = "double"; break;
            case DATA_OBJECT: t = "object"; break;
        }
        write_fmt("    public %s", t);
        for (int j = 0; j < d; j++) write_fmt("[]");
        write_fmt(" %s { get; init; }\n", f->field_name);
    }
    write_fmt("}\n");
    close(export_fd);
    printf("C#    -> %s\n", path);
}

void SaveTOML(struct Object *obj) {
    if (!obj || !obj->ob_name[0]) return;
    char objdir[512]; if (snprintf(objdir, sizeof(objdir), "%s/%s", g_object_dir, obj->ob_name) >= (int)sizeof(objdir)) { fprintf(stderr, "Path too long: %s/%s\n", g_object_dir, obj->ob_name); return; }
    make_directory(objdir);
    char path[512]; build_obj_path(path, sizeof(path), obj->ob_name, "toml");
    export_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (export_fd < 0) { perror("open toml"); return; }
    write_fmt("[%s]\n", obj->ob_name);
    for (uint32_t i = 0; i < obj->ob_field_number; i++) {
        struct Field *f = &obj->ob_fields[i];
        write_fmt("%s = ", f->field_name);
        write_field_value(f);
        write_str("\n");
    }
    close(export_fd);
    printf("TOML  -> %s\n", path);
}

void SaveWebAssembly(struct Object *obj) {
    if (!obj || !obj->ob_name[0]) return;
    char objdir[512]; if (snprintf(objdir, sizeof(objdir), "%s/%s", g_object_dir, obj->ob_name) >= (int)sizeof(objdir)) { fprintf(stderr, "Path too long: %s/%s\n", g_object_dir, obj->ob_name); return; }
    make_directory(objdir);
    char path[512]; build_obj_path(path, sizeof(path), obj->ob_name, "wat");
    export_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (export_fd < 0) { perror("open wat"); return; }
    write_fmt(";; WebAssembly module for %s\n", obj->ob_name);
    write_fmt("(module\n");
    size_t total_data = 0;
    for (uint32_t i = 0; i < obj->ob_field_number; i++) {
        struct Field *f = &obj->ob_fields[i];
        uint8_t b = f->field_type & 0x07;
        if (b == DATA_OBJECT) continue;
        int dimcnt = (f->field_type >> DIM_SHIFT) & 0x03;
        size_t esize = g_elem_sizes[b];
        size_t total = 1;
        if (dimcnt) { total = 1; for (int d=0; d<dimcnt; d++) total *= f->dims[d]; }
        total_data += total * esize;
    }
    if (total_data > 0) {
        write_fmt("  (memory (export \"memory\") 1)\n");
        write_fmt("  (data (i32.const 0) \"");
        for (uint32_t i = 0; i < obj->ob_field_number; i++) {
            struct Field *f = &obj->ob_fields[i];
            uint8_t b = f->field_type & 0x07;
            if (b == DATA_OBJECT) continue;
            int dimcnt = (f->field_type >> DIM_SHIFT) & 0x03;
            size_t esize = g_elem_sizes[b];
            size_t total = 1;
            if (dimcnt) { total = 1; for (int d=0; d<dimcnt; d++) total *= f->dims[d]; }
            if (f->data && (f->pad2 & FIELD_FLAG_ALLOCATED)) {
                for (size_t j = 0; j < total; j++) {
                    unsigned char *bytes = (unsigned char*)f->data + j * esize;
                    for (size_t k = 0; k < esize; k++) {
                        write_fmt("\\%02x", bytes[k]);
                    }
                }
            }
        }
        write_fmt("\")\n");
    }
    write_fmt(")\n");
    close(export_fd);
    printf("WASM  -> %s\n", path);
}

void SaveMessagePack(struct Object *obj) {
    if (!obj || !obj->ob_name[0]) return;
    char objdir[512]; if (snprintf(objdir, sizeof(objdir), "%s/%s", g_object_dir, obj->ob_name) >= (int)sizeof(objdir)) { fprintf(stderr, "Path too long: %s/%s\n", g_object_dir, obj->ob_name); return; }
    make_directory(objdir);
    char path[512]; build_obj_path(path, sizeof(path), obj->ob_name, "msgpack");
    export_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0644);
    if (export_fd < 0) { perror("open msgpack"); return; }
    write_all(export_fd, &obj->ob_field_number, sizeof(uint32_t));
    for (uint32_t i = 0; i < obj->ob_field_number; i++) {
        struct Field *f = &obj->ob_fields[i];
        uint8_t base = f->field_type & 0x07;
        int dimcnt = (f->field_type >> DIM_SHIFT) & 0x03;
        size_t esize = (base == DATA_OBJECT) ? OBJ_PTR_SIZE : g_elem_sizes[base];
        size_t total = 1;
        if (dimcnt) { total = 1; for (int d=0; d<dimcnt; d++) total *= f->dims[d]; }
        uint8_t nlen = strlen(f->field_name);
        write_all(export_fd, &nlen, 1);
        write_all(export_fd, f->field_name, nlen);
        if (base == DATA_OBJECT) {
            if (f->data) {
                struct Object **sub = f->data;
                if (*sub) {
                    nlen = strlen((*sub)->ob_name);
                    write_all(export_fd, &nlen, 1);
                    write_all(export_fd, (*sub)->ob_name, nlen);
                } else {
                    nlen = 0;
                    write_all(export_fd, &nlen, 1);
                }
            } else {
                nlen = 0;
                write_all(export_fd, &nlen, 1);
            }
        } else {
            if (f->data && (f->pad2 & FIELD_FLAG_ALLOCATED))
                write_all(export_fd, f->data, total * esize);
            else {
                void *zero = calloc(total, esize);
                write_all(export_fd, zero, total * esize);
                free(zero);
            }
        }
    }
    close(export_fd);
    printf("MsgPk -> %s\n", path);
}

void SaveODL(struct Object *obj) {
    if (!obj || !obj->ob_name[0]) return;
    char objdir[512]; if (snprintf(objdir, sizeof(objdir), "%s/%s", g_object_dir, obj->ob_name) >= (int)sizeof(objdir)) { fprintf(stderr, "Path too long: %s/%s\n", g_object_dir, obj->ob_name); return; }
    make_directory(objdir);
    char path[512]; build_obj_path(path, sizeof(path), obj->ob_name, "odl");
    export_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
    if (export_fd < 0) { perror("Cannot open ODL export"); return; }
    write_fmt("OBJECT %s;\n", obj->ob_name);
    for (uint32_t i = 0; i < obj->ob_field_number; i++) {
        struct Field *f = &obj->ob_fields[i];
        uint8_t base = ft_base(f->field_type);
        int dimcnt = ft_dims(f->field_type);
        write_fmt("    %s %s", odl_type_name(f->field_type), f->field_name);
        for (int d = 0; d < dimcnt; d++) {
            if (f->dims[d] == 0) write_str("[]");
            else write_fmt("[%u]", f->dims[d]);
        }
        if (base == DATA_OBJECT) {
            if (f->data) {
                struct Object **sub = f->data;
                if (*sub) write_fmt(" = %s", (*sub)->ob_name);
            }
        } else if (f->data && (f->pad2 & FIELD_FLAG_ALLOCATED)) {
            write_str(" = ");
            if (base == DATA_CHAR) write_text_field(f);
            else {
                size_t total = field_elems(f);
                if (dimcnt) write_str("{ ");
                for (size_t j = 0; j < total; j++) {
                    char buf[80];
                    if (j) write_str(", ");
                    format_elem(buf, sizeof buf, f, j);
                    write_str(buf);
                }
                if (dimcnt) write_str(" }");
            }
        }
        write_str(";\n");
    }
    close(export_fd);
    printf("ODL   -> %s\n", path);
}

void SaveAllFormats(struct Object *obj) {
    if (!obj) return;
    printf("\nExporting %s to all formats...\n", obj->ob_name);
    SaveObject(obj);
    SaveODL(obj);
    SaveJavaClass(obj); SaveJavaScript(obj); SaveJSON(obj); SaveTypeScript(obj);
    SaveCHeader(obj); SaveGoStruct(obj); SaveSwiftStruct(obj);
    SaveRustStruct(obj); SaveKotlinClass(obj); SaveCSharpStruct(obj);
    SaveTOML(obj); SaveWebAssembly(obj); SaveMessagePack(obj);
    puts("Export complete.");
}

static void ExportObject(struct Object *obj, uint32_t flags) {
    if (!obj) return;
    if (flags & EXFLAG_JAVA)    SaveJavaClass(obj);
    if (flags & EXFLAG_JS)      SaveJavaScript(obj);
    if (flags & EXFLAG_JSON)    SaveJSON(obj);
    if (flags & EXFLAG_TS)      SaveTypeScript(obj);
    if (flags & EXFLAG_C)       SaveCHeader(obj);
    if (flags & EXFLAG_GO)      SaveGoStruct(obj);
    if (flags & EXFLAG_SWIFT)   SaveSwiftStruct(obj);
    if (flags & EXFLAG_ODL)     SaveODL(obj);
    if (flags & EXFLAG_RUST)    SaveRustStruct(obj);
    if (flags & EXFLAG_KOTLIN)  SaveKotlinClass(obj);
    if (flags & EXFLAG_CSHARP)  SaveCSharpStruct(obj);
    if (flags & EXFLAG_TOML)    SaveTOML(obj);
    if (flags & EXFLAG_WASM)    SaveWebAssembly(obj);
    if (flags & EXFLAG_MSGPACK) SaveMessagePack(obj);
}

/* ===== Efficient Serialization for Network (platform portable) ===== */
#ifdef _WIN32
static ssize_t write_exact(SOCKET fd, const void *buf, size_t len) {
    ssize_t total = 0;
    while (total < (ssize_t)len) {
        int n = send(fd, (const char*)buf + total, (int)(len - total), 0);
        if (n == SOCKET_ERROR) return -1;
        total += n;
    }
    return total;
}

static ssize_t read_exact(SOCKET fd, void *buf, size_t len) {
    ssize_t total = 0;
    while (total < (ssize_t)len) {
        int n = recv(fd, (char*)buf + total, (int)(len - total), 0);
        if (n == SOCKET_ERROR || n == 0) return -1;
        total += n;
    }
    return total;
}
#else
static ssize_t write_exact(int fd, const void *buf, size_t len) {
    ssize_t total = 0;
    while (total < (ssize_t)len) {
        ssize_t n = write(fd, (const char*)buf + total, len - total);
        if (n <= 0) return -1;
        total += n;
    }
    return total;
}

static ssize_t read_exact(int fd, void *buf, size_t len) {
    ssize_t total = 0;
    while (total < (ssize_t)len) {
        ssize_t n = read(fd, (char*)buf + total, len - total);
        if (n <= 0) return -1;
        total += n;
    }
    return total;
}
#endif

int64_t FSendObject(struct Object *obj, int fd) {
    if (!obj || fd < 0) return -1;
    size_t n = 0;
    uint8_t *buf = serialize_object(obj, &n);
    if (!buf) return -1;
    ssize_t sent = write_exact(fd, buf, n);
    free(buf);
    return (sent == (ssize_t)n) ? (int64_t)n : -1;
}

struct Object* FReceiveObject(int fd) {
    SerialHeader hdr;
    if (read_exact(fd, &hdr, sizeof(SerialHeader)) != (ssize_t)sizeof(SerialHeader))
        return NULL;
    uint32_t total = ntoh32(hdr.total_size);
    if (ntoh32(hdr.magic) != SER_MAGIC || total < sizeof(SerialHeader) || total > 10u * 1024u * 1024u)
        return NULL;
    uint8_t *buf = (uint8_t *)malloc(total);
    if (!buf) return NULL;
    memcpy(buf, &hdr, sizeof(SerialHeader));
    if (read_exact(fd, buf + sizeof(SerialHeader), total - sizeof(SerialHeader)) !=
        (ssize_t)(total - sizeof(SerialHeader))) {
        free(buf);
        return NULL;
    }
    struct Object *obj = deserialize_buffer(buf, total, 0);
    free(buf);
    return obj;
}

/* ===== CLI and Interactive Functions ===== */
static void print_field_line(const struct Field *f) {
    uint8_t base = ft_base(f->field_type);
    int dimcnt = ft_dims(f->field_type);
    printf("  %s %s", odl_type_name(f->field_type), f->field_name);
    for (int d = 0; d < dimcnt; d++) {
        if (f->dims[d] == 0) printf("[]");
        else printf("[%u]", f->dims[d]);
    }
    if (base == DATA_OBJECT) {
        struct Object **objs = f->data;
        if (objs && *objs) printf(" = %s", (*objs)->ob_name);
    } else if (f->data && (f->pad2 & FIELD_FLAG_ALLOCATED)) {
        printf(" = ");
        if (base == DATA_CHAR) {
            size_t n = dimcnt ? f->dims[0] : 1;
            putchar('"');
            for (size_t i = 0; i < n; i++) {
                uint16_t v;
                memcpy(&v, (const uint8_t *)f->data + i * 2, 2);
                if (!v) break;
                if (v >= 32 && v < 127 && v != '"') putchar((char)v);
                else printf("\\u%04x", (unsigned)v);
            }
            putchar('"');
        } else {
            size_t tot = field_elems(f);
            size_t show = tot > 12 ? 12 : tot;
            if (dimcnt) printf("{ ");
            for (size_t j = 0; j < show; j++) {
                char buf[80];
                if (j) printf(", ");
                format_elem(buf, sizeof buf, f, j);
                fputs(buf, stdout);
            }
            if (tot > show) printf(", ...");
            if (dimcnt) printf(" }");
        }
    }
    printf(";\n");
}

void PrintObject(const struct Object *obj) {
    if (!obj) { puts("No object."); return; }
    printf("\n%s\n{\n", obj->ob_name);
    for (uint32_t i = 0; i < obj->ob_field_number; i++)
        print_field_line(&obj->ob_fields[i]);
    printf("}\n");
}

void ListSavedObjects(void) {
    DIR *d = opendir(g_object_dir);
    if (!d) { puts("No objects directory."); return; }
    puts("\nSaved Objects:");
    struct dirent *e; struct stat st; char p[512];
    while ((e = readdir(d))) {
        if (strcmp(e->d_name,".")==0||strcmp(e->d_name,"..")==0) continue;
        if (snprintf(p,sizeof(p),"%s/%s", g_object_dir, e->d_name) >= (int)sizeof(p)) continue;
        if (!stat(p,&st) && S_ISDIR(st.st_mode)) printf("  %s\n", e->d_name);
    }
    closedir(d);
}

static int get_obj_list(char names[][64], int max) {
    DIR *d = opendir(g_object_dir);
    if (!d) return 0;
    int c=0; struct dirent *e; struct stat st; char p[512];
    while ((e=readdir(d)) && c<max) {
        if (strcmp(e->d_name,".")==0||strcmp(e->d_name,"..")==0) continue;
        if (snprintf(p,sizeof(p),"%s/%s", g_object_dir, e->d_name) >= (int)sizeof(p)) continue;
        if (!stat(p,&st) && S_ISDIR(st.st_mode)) {
            strncpy(names[c], e->d_name, 63); names[c][63]='\0'; c++;
        }
    }
    closedir(d); return c;
}

void SelectAndLoadObject(struct Object **current) {
    char names[128][64];
    int cnt = get_obj_list(names,128);
    if (!cnt) { puts("No saved objects."); return; }
    for (int i=0; i<cnt; i++) printf("%2d) %s\n", i, names[i]);
    printf("Enter # (0-%d) or Enter: ", cnt-1);
    char in[64]; if (!fgets(in,sizeof(in),stdin)) return;
    in[strcspn(in,"\n")]='\0';
    if (!*in) return;
    char *end; long n = strtol(in,&end,10);
    if (*end || n<0 || n>=cnt) return;
    if (*current) { printf("Replace %s? (y/N) ", (*current)->ob_name); if (!fgets(in,sizeof(in),stdin)||tolower(in[0])!='y') return; FreeObject(*current); *current=NULL; }
    *current = LoadObject(names[n]);
    if (*current) printf("Loaded '%s'\n", (*current)->ob_name);
    else printf("Failed\n");
}

void PrintAllObjects(void) {
    DIR *d = opendir(g_object_dir);
    if (!d) { puts("No objects directory."); return; }
    struct dirent *e; struct stat st; char p[512]; int cnt=0;
    while ((e=readdir(d))) {
        if (strcmp(e->d_name,".")==0||strcmp(e->d_name,"..")==0) continue;
        if (snprintf(p,sizeof(p),"%s/%s", g_object_dir, e->d_name) >= (int)sizeof(p)) continue;
        if (stat(p,&st)||!S_ISDIR(st.st_mode)) continue;
        struct Object *obj = LoadObject(e->d_name);
        if (!obj) continue;
        cnt++;
        printf("\n%s\n{\n", obj->ob_name);
        for (uint32_t i=0; i<obj->ob_field_number; i++)
            print_field_line(&obj->ob_fields[i]);
        printf("}\n----------------------------------------\n");
        FreeObject(obj);
    }
    closedir(d);
    if (!cnt) puts("No objects found.");
    else printf("Total: %d\n", cnt);
}

void ProcessODLFiles(void) {
    DIR *d = opendir(g_object_dir);
    if (!d) {
        printf("Cannot open object directory: %s\n", g_object_dir);
        return;
    }
    struct dirent *entry;
    char filepath[1024];
    struct stat st;
    int count = 0;
    while ((entry = readdir(d)) != NULL) {
        if (strlen(entry->d_name) < 4) continue;
        if (strcmp(entry->d_name + strlen(entry->d_name) - 4, ".odl") != 0) continue;
        snprintf(filepath, sizeof(filepath), "%s/%s", g_object_dir, entry->d_name);
        if (stat(filepath, &st) != 0 || !S_ISREG(st.st_mode)) continue;
        printf("Processing ODL file: %s\n", entry->d_name);
        int fd = open(filepath, O_RDONLY);
        if (fd < 0) { perror("Cannot open ODL file"); continue; }
        off_t size = lseek(fd, 0, SEEK_END);
        lseek(fd, 0, SEEK_SET);
        char *src = malloc(size + 1);
        if (!src) { close(fd); continue; }
        read(fd, src, size);
        src[size] = '\0';
        close(fd);
        LoadODLString(src);
        char *objname = extract_first_object_name(src);
        free(src);
        char processed_dir[1024];
        snprintf(processed_dir, sizeof(processed_dir), "%s/processed", g_object_dir);
        make_directory(processed_dir);
        time_t now = time(NULL);
        struct tm *tm = localtime(&now);
        char timestamp[13];
        strftime(timestamp, sizeof(timestamp), "%y%m%d%H%M%S", tm);
        char newname[1024];
        if (objname) {
            snprintf(newname, sizeof(newname), "%s_%s.odl", timestamp, objname);
            free(objname);
        } else {
            snprintf(newname, sizeof(newname), "%s_%s", timestamp, entry->d_name);
        }
        char newpath[1024];
        if (snprintf(newpath, sizeof(newpath), "%s/%s", processed_dir, newname) >= (int)sizeof(newpath)) { fprintf(stderr, "Path too long, not moved: %s\n", filepath); continue; }
        if (rename(filepath, newpath) == 0) {
            printf("Moved to: %s\n", newpath);
            count++;
        } else {
            perror("Error moving ODL file");
        }
    }
    closedir(d);
    if (count == 0) puts("No .odl files found in object directory.");
    else printf("Processed %d ODL file(s).\n", count);
}

void ShowHelp(void) {
    printf("\nObjectWhack v%s - ODL Object Definition Language\n", OBJECTWHACK_VERSION);
    puts("Usage: ./ow [options] [file.odl ...]");
    puts("Options:");
    puts("  -j  Java          -c  C header");
    puts("  -k  JavaScript    -g  Go");
    puts("  -z  JSON          -w  Swift");
    puts("  -v  TypeScript    -o  ODL");
    puts("                    -a  All formats");
    puts("  If files given, processes them; else reads stdin.");
    puts("  No files and stdin is a terminal -> interactive mode.");
    puts("\nInteractive commands:");
    puts("  n  New object (compact single-line)");
    puts("  P  Process all .odl files in object directory");
    puts("  l  Load object   s  Save object   p  Print object");
    puts("  t  List objects  b  Print all     a  Export all");
    puts("  o  Export ODL    j/k/z/v/c/g/w  Export specific language");
    puts("  h  Help          q  Quit");
}

/* ===== Main ===== */
int main(int argc, char **argv) {
#ifdef _WIN32
    WSADATA wsa;
    if (WSAStartup(MAKEWORD(2,2), &wsa) != 0) {
        fprintf(stderr, "WSAStartup failed\n");
        return 1;
    }
#endif

    init_object_dir();
    bool has_files = false;
    g_export_flags = 0;
    for (int i = 1; i < argc; i++) {
        if (argv[i][0] == '-') {
            switch (argv[i][1]) {
                case 'j': g_export_flags |= EXFLAG_JAVA; break;
                case 'k': g_export_flags |= EXFLAG_JS; break;
                case 'z': g_export_flags |= EXFLAG_JSON; break;
                case 'v': g_export_flags |= EXFLAG_TS; break;
                case 'c': g_export_flags |= EXFLAG_C; break;
                case 'g': g_export_flags |= EXFLAG_GO; break;
                case 'w': g_export_flags |= EXFLAG_SWIFT; break;
                case 'o': g_export_flags |= EXFLAG_ODL; break;
                case 'a': g_export_flags = EXFLAG_ALL; break;
                default: fprintf(stderr, "Unknown option: %s\n", argv[i]); return 1;
            }
        } else {
            has_files = true;
            LoadODLFile(argv[i]);
        }
    }
    if (has_files) {
#ifdef _WIN32
        WSACleanup();
#endif
        return 0;
    }
    if (!isatty(STDIN_FILENO)) {
        char *input = NULL;
        size_t len = 0, cap = 0;
        char buf[4096];
        ssize_t n;
        while ((n = read(STDIN_FILENO, buf, sizeof(buf))) > 0) {
            if (len + n >= cap) {
                cap = cap ? cap * 2 : 4096;
                input = realloc(input, cap);
            }
            memcpy(input + len, buf, n);
            len += n;
        }
        if (input) {
            input[len] = '\0';
            LoadODLString(input);
            free(input);
        }
#ifdef _WIN32
        WSACleanup();
#endif
        return 0;
    }
    printf("ObjectWhack v%s - unbuffered file system edition\n", OBJECTWHACK_VERSION);
    printf("Object directory: %s\n", g_object_dir);
    struct Object *current = NULL;
    char line[1024];
    ListSavedObjects();
    ShowHelp();
    while (1) {
        printf("\nCurrent: %s\n> ", current ? current->ob_name : "(none)");
        if (!fgets(line, sizeof(line), stdin)) break;
        line[strcspn(line, "\n")] = '\0';
        if (!line[0]) continue;
        char raw_cmd = line[0];
        char cmd = tolower(raw_cmd);
        if (cmd == 'q') {
            if (current) { printf("Free current? (y/n) "); if (fgets(line,sizeof(line),stdin) && tolower(line[0])=='y') FreeObject(current); }
            puts("Goodbye.");
#ifdef _WIN32
            WSACleanup();
#endif
            break;
        }
        if (raw_cmd == 'P') {
            ProcessODLFiles();
            continue;
        }
        switch (cmd) {
            case 'n':
                if (current) { printf("Overwrite '%s'? (y/n) ", current->ob_name); if (fgets(line,sizeof(line),stdin) && tolower(line[0])=='y') { FreeObject(current); current=NULL; } else break; }
                printf("Description: "); if (fgets(line,sizeof(line),stdin)) { line[strcspn(line,"\n")]='\0'; current = AllocObject(line); if (current) printf("Created %s\n", current->ob_name); }
                break;
            case 'l': SelectAndLoadObject(&current); break;
            case 's': SaveObject(current); break;
            case 'p': PrintObject(current); break;
            case 't': ListSavedObjects(); break;
            case 'b': PrintAllObjects(); break;
            case 'a': SaveAllFormats(current); break;
            case 'o': SaveODL(current); break;
            case 'j': SaveJavaClass(current); break;
            case 'k': SaveJavaScript(current); break;
            case 'z': SaveJSON(current); break;
            case 'v': SaveTypeScript(current); break;
            case 'c': SaveCHeader(current); break;
            case 'g': SaveGoStruct(current); break;
            case 'w': SaveSwiftStruct(current); break;
            case 'h': ShowHelp(); break;
            default: printf("Unknown command '%c'  type h for help\n", raw_cmd);
        }
    }
    if (current) FreeObject(current);
#ifdef _WIN32
    WSACleanup();
#endif
    return 0;
}
