/*
 * incbin.h — Portable binary embedding via assembler .incbin directive
 *
 * Usage:
 *   INCBIN(myData, "path/to/file.bin");
 *
 * This creates:
 *   extern const unsigned char g_myData_data[];   // file contents
 *   extern const unsigned char *g_myData_end;     // one past end
 *   extern const unsigned int   g_myData_size;    // byte count
 *
 * Compared to xxd -i hex arrays, this uses near-zero compile-time RAM
 * because the assembler streams the file directly into the object file
 * without building an AST for millions of array elements.
 *
 * Supports: GCC, Clang, MinGW (any target that uses GAS).
 * MSVC: not supported (would need a different strategy).
 *
 * Based on the public-domain incbin technique.
 * Adapted for DragonX Wallet by The Hush Developers, 2024-2026.
 */

#ifndef DRAGONX_INCBIN_H
#define DRAGONX_INCBIN_H

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Helper macros for token pasting and stringification.
 */
#define INCBIN_CAT(a, b)        INCBIN_CAT_(a, b)
#define INCBIN_CAT_(a, b)       a ## b
#define INCBIN_STR(x)           INCBIN_STR_(x)
#define INCBIN_STR_(x)          #x

/*
 * Section attribute: place embedded data in .rodata so it lives in the
 * read-only segment just like a normal const array would.
 */
#if defined(__APPLE__)
#  define INCBIN_SECTION        "__DATA,__const"
#  define INCBIN_MANGLE         "_"
#else
#  define INCBIN_SECTION        ".rodata"
#  define INCBIN_MANGLE         ""
#endif

/*
 * Alignment: 16 bytes is sufficient for SIMD loads if anyone ever
 * wants to process embedded data with SSE/NEON, and is a safe default.
 */
#define INCBIN_ALIGN            16

/*
 * INCBIN_EXTERN  — declare the symbols (use in headers)
 */
#define INCBIN_EXTERN(NAME)                                                  \
    extern const unsigned char INCBIN_CAT(g_, INCBIN_CAT(NAME, _data))[];    \
    extern const unsigned char *INCBIN_CAT(g_, INCBIN_CAT(NAME, _end));      \
    extern const unsigned int  INCBIN_CAT(g_, INCBIN_CAT(NAME, _size))

/*
 * INCBIN  — define the symbols + embed the file  (use in ONE .cpp/.c file)
 *
 * NAME : C identifier prefix (no quotes)
 * FILE : path to the file to embed (string literal, relative to -I or absolute)
 *
 * The generated assembly:
 *   .section .rodata
 *   .balign 16
 *   .global g_NAME_data
 *   g_NAME_data:
 *       .incbin "FILE"
 *   .global g_NAME_end
 *   g_NAME_end:
 *       .byte 0           // NUL sentinel for C string compatibility
 *   .balign 4
 *   .global g_NAME_size
 *   g_NAME_size:
 *       .int g_NAME_end - g_NAME_data
 */
#define INCBIN(NAME, FILE)                                                   \
    __asm__(                                                                 \
        ".section " INCBIN_SECTION "\n"                                      \
        ".balign " INCBIN_STR(INCBIN_ALIGN) "\n"                             \
        ".global " INCBIN_MANGLE "g_" #NAME "_data\n"                        \
        INCBIN_MANGLE "g_" #NAME "_data:\n"                                  \
        "    .incbin \"" FILE "\"\n"                                         \
        ".global " INCBIN_MANGLE "g_" #NAME "_end\n"                         \
        INCBIN_MANGLE "g_" #NAME "_end:\n"                                   \
        "    .byte 0\n"                                                      \
        ".balign 4\n"                                                        \
        ".global " INCBIN_MANGLE "g_" #NAME "_size\n"                        \
        INCBIN_MANGLE "g_" #NAME "_size:\n"                                  \
        "    .int " INCBIN_MANGLE "g_" #NAME "_end - "                       \
                     INCBIN_MANGLE "g_" #NAME "_data\n"                      \
        ".text\n"  /* restore default section */                             \
    );                                                                       \
    INCBIN_EXTERN(NAME)

#ifdef __cplusplus
}
#endif

#endif /* DRAGONX_INCBIN_H */
