text: /**
   * From https://github.com/graphitemaster/incbin licenced in public domain
   */
  #ifndef INCBIN_HDR
  #define INCBIN_HDR
  #include <limits.h>
  #if   defined(__AVX512BW__) || \
        defined(__AVX512CD__) || \
        defined(__AVX512DQ__) || \
        defined(__AVX512ER__) || \
        defined(__AVX512PF__) || \
        defined(__AVX512VL__) || \
        defined(__AVX512F__)
  # define INCBIN_ALIGNMENT_INDEX 6
  #elif defined(__AVX__)      || \
        defined(__AVX2__)
  # define INCBIN_ALIGNMENT_INDEX 5
  #elif defined(__SSE__)      || \
        defined(__SSE2__)     || \
        defined(__SSE3__)     || \
        defined(__SSSE3__)    || \
        defined(__SSE4_1__)   || \
        defined(__SSE4_2__)   || \
        defined(__neon__)
  # define INCBIN_ALIGNMENT_INDEX 4
  #elif ULONG_MAX != 0xffffffffu
  # define INCBIN_ALIGNMENT_INDEX 3
  # else
  # define INCBIN_ALIGNMENT_INDEX 2
  #endif
  
  /* Lookup table of (1 << n) where `n' is `INCBIN_ALIGNMENT_INDEX' */
  #define INCBIN_ALIGN_SHIFT_0 1
  #define INCBIN_ALIGN_SHIFT_1 2
  #define INCBIN_ALIGN_SHIFT_2 4
  #define INCBIN_ALIGN_SHIFT_3 8
  #define INCBIN_ALIGN_SHIFT_4 16
  #define INCBIN_ALIGN_SHIFT_5 32
  #define INCBIN_ALIGN_SHIFT_6 64
  
  /* Actual alignment value */
  #define INCBIN_ALIGNMENT \
      INCBIN_CONCATENATE( \
          INCBIN_CONCATENATE(INCBIN_ALIGN_SHIFT, _), \
          INCBIN_ALIGNMENT_INDEX)
  
  /* Stringize */
  #define INCBIN_STR(X) \
      #X
  #define INCBIN_STRINGIZE(X) \
      INCBIN_STR(X)
  /* Concatenate */
  #define INCBIN_CAT(X, Y) \
      X ## Y
  #define INCBIN_CONCATENATE(X, Y) \
      INCBIN_CAT(X, Y)
  /* Deferred macro expansion */
  #define INCBIN_EVAL(X) \
      X
  #define INCBIN_INVOKE(N, ...) \
      INCBIN_EVAL(N(__VA_ARGS__))
  
  /* Green Hills uses a different directive for including binary data */
  #if defined(__ghs__)
  #  define INCBIN_MACRO "\tINCBIN"
  #else
  #  define INCBIN_MACRO ".incbin"
  #endif
  
  #ifndef _MSC_VER
  #  define INCBIN_ALIGN \
      __attribute__((aligned(INCBIN_ALIGNMENT)))
  #else
  #  define INCBIN_ALIGN __declspec(align(INCBIN_ALIGNMENT))
  #endif
  
  #if defined(__arm__) || /* GNU C and RealView */ \
      defined(__arm) || /* Diab */ \
      defined(_ARM) /* ImageCraft */
  #  define INCBIN_ARM
  #endif
  
  #ifdef __GNUC__
  /* Utilize .balign where supported */
  #  define INCBIN_ALIGN_HOST ".balign " INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n"
  #  define INCBIN_ALIGN_BYTE ".balign 1\n"
  #elif defined(INCBIN_ARM)
  /*
   * On arm assemblers, the alignment value is calculated as (1 << n) where `n' is
   * the shift count. This is the value passed to `.align'
   */
  #  define INCBIN_ALIGN_HOST ".align" INCBIN_STRINGIZE(INCBIN_ALIGNMENT_INDEX) "\n"
  #  define INCBIN_ALIGN_BYTE ".align 0\n"
  #else
  /* We assume other inline assembler's treat `.align' as `.balign' */
  #  define INCBIN_ALIGN_HOST ".align" INCBIN_STRINGIZE(INCBIN_ALIGNMENT) "\n"
  #  define INCBIN_ALIGN_BYTE ".align 1\n"
  #endif
  
  /* INCBIN_CONST is used by incbin.c generated files */
  #if defined(__cplusplus)
  #  define INCBIN_EXTERNAL extern "C"
  #  define INCBIN_CONST    extern const
  #else
  #  define INCBIN_EXTERNAL extern
  #  define INCBIN_CONST    const
  #endif
  
  /**
   * @brief Optionally override the linker section into which data is emitted.
   *
   * @warning If you use this facility, you'll have to deal with platform-specific linker output
   * section naming on your own
   *
   * Overriding the default linker output section, e.g for esp8266/Arduino:
   * @code
   * #define INCBIN_OUTPUT_SECTION ".irom.text"
   * #include "incbin.h"
   * INCBIN(Foo, "foo.txt");
   * // Data is emitted into program memory that never gets copied to RAM
   * @endcode
   */
  #if !defined(INCBIN_OUTPUT_SECTION)
  #  if defined(__APPLE__)
  #    define INCBIN_OUTPUT_SECTION         ".const_data"
  #  else
  #    define INCBIN_OUTPUT_SECTION         ".rodata"
  #  endif
  #endif
  
  #if defined(__APPLE__)
  /* The directives are different for Apple branded compilers */
  #  define INCBIN_SECTION         INCBIN_OUTPUT_SECTION "\n"
  #  define INCBIN_GLOBAL(NAME)    ".globl " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n"
  #  define INCBIN_INT             ".long "
  #  define INCBIN_MANGLE          "_"
  #  define INCBIN_BYTE            ".byte "
  #  define INCBIN_TYPE(...)
  #else
  #  define INCBIN_SECTION         ".section " INCBIN_OUTPUT_SECTION "\n"
  #  define INCBIN_GLOBAL(NAME)    ".global " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME "\n"
  #  define INCBIN_INT             ".int "
  #  if defined(__USER_LABEL_PREFIX__)
  #    define INCBIN_MANGLE        INCBIN_STRINGIZE(__USER_LABEL_PREFIX__)
  #  else
  #    define INCBIN_MANGLE        ""
  #  endif
  #  if defined(INCBIN_ARM)
  /* On arm assemblers, `@' is used as a line comment token */
  #    define INCBIN_TYPE(NAME)    ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", %object\n"
  #  elif defined(__MINGW32__) || defined(__MINGW64__)
  /* Mingw doesn't support this directive either */
  #    define INCBIN_TYPE(NAME)
  #  else
  /* It's safe to use `@' on other architectures */
  #    define INCBIN_TYPE(NAME)    ".type " INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME ", @object\n"
  #  endif
  #  define INCBIN_BYTE            ".byte "
  #endif
  
  /* List of style types used for symbol names */
  #define INCBIN_STYLE_CAMEL 0
  #define INCBIN_STYLE_SNAKE 1
  
  /**
   * @brief Specify the prefix to use for symbol names.
   *
   * By default this is `g', producing symbols of the form:
   * @code
   * #include "incbin.h"
   * INCBIN(Foo, "foo.txt");
   *
   * // Now you have the following symbols:
   * // const unsigned char gFooData[];
   * // const unsigned char *const gFooEnd;
   * // const unsigned int gFooSize;
   * @endcode
   *
   * If however you specify a prefix before including: e.g:
   * @code
   * #define INCBIN_PREFIX incbin
   * #include "incbin.h"
   * INCBIN(Foo, "foo.txt");
   *
   * // Now you have the following symbols instead:
   * // const unsigned char incbinFooData[];
   * // const unsigned char *const incbinFooEnd;
   * // const unsigned int incbinFooSize;
   * @endcode
   */
  #if !defined(INCBIN_PREFIX)
  #  define INCBIN_PREFIX g
  #endif
  
  /**
   * @brief Specify the style used for symbol names.
   *
   * Possible options are
   * - INCBIN_STYLE_CAMEL "CamelCase"
   * - INCBIN_STYLE_SNAKE "snake_case"
   *
   * Default option is *INCBIN_STYLE_CAMEL* producing symbols of the form:
   * @code
   * #include "incbin.h"
   * INCBIN(Foo, "foo.txt");
   *
   * // Now you have the following symbols:
   * // const unsigned char <prefix>FooData[];
   * // const unsigned char *const <prefix>FooEnd;
   * // const unsigned int <prefix>FooSize;
   * @endcode
   *
   * If however you specify a style before including: e.g:
   * @code
   * #define INCBIN_STYLE INCBIN_STYLE_SNAKE
   * #include "incbin.h"
   * INCBIN(foo, "foo.txt");
   *
   * // Now you have the following symbols:
   * // const unsigned char <prefix>foo_data[];
   * // const unsigned char *const <prefix>foo_end;
   * // const unsigned int <prefix>foo_size;
   * @endcode
   */
  #if !defined(INCBIN_STYLE)
  #  define INCBIN_STYLE INCBIN_STYLE_CAMEL
  #endif
  
  /* Style lookup tables */
  #define INCBIN_STYLE_0_DATA Data
  #define INCBIN_STYLE_0_END End
  #define INCBIN_STYLE_0_SIZE Size
  #define INCBIN_STYLE_1_DATA _data
  #define INCBIN_STYLE_1_END _end
  #define INCBIN_STYLE_1_SIZE _size
  
  /* Style lookup: returning identifier */
  #define INCBIN_STYLE_IDENT(TYPE) \
      INCBIN_CONCATENATE( \
          INCBIN_STYLE_, \
          INCBIN_CONCATENATE( \
              INCBIN_EVAL(INCBIN_STYLE), \
              INCBIN_CONCATENATE(_, TYPE)))
  
  /* Style lookup: returning string literal */
  #define INCBIN_STYLE_STRING(TYPE) \
      INCBIN_STRINGIZE( \
          INCBIN_STYLE_IDENT(TYPE)) \
  
  /* Generate the global labels by indirectly invoking the macro with our style
   * type and concatenating the name against them. */
  #define INCBIN_GLOBAL_LABELS(NAME, TYPE) \
      INCBIN_INVOKE( \
          INCBIN_GLOBAL, \
          INCBIN_CONCATENATE( \
              NAME, \
              INCBIN_INVOKE( \
                  INCBIN_STYLE_IDENT, \
                  TYPE))) \
      INCBIN_INVOKE( \
          INCBIN_TYPE, \
          INCBIN_CONCATENATE( \
              NAME, \
              INCBIN_INVOKE( \
                  INCBIN_STYLE_IDENT, \
                  TYPE)))
  
  /**
   * @brief Externally reference binary data included in another translation unit.
   *
   * Produces three external symbols that reference the binary data included in
   * another translation unit.
   *
   * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with
   * "Data", as well as "End" and "Size" after. An example is provided below.
   *
   * @param NAME The name given for the binary data
   *
   * @code
   * INCBIN_EXTERN(Foo);
   *
   * // Now you have the following symbols:
   * // extern const unsigned char <prefix>FooData[];
   * // extern const unsigned char *const <prefix>FooEnd;
   * // extern const unsigned int <prefix>FooSize;
   * @endcode
   */
  #define INCBIN_EXTERN(NAME) \
      INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char \
          INCBIN_CONCATENATE( \
              INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
              INCBIN_STYLE_IDENT(DATA))[]; \
      INCBIN_EXTERNAL const INCBIN_ALIGN unsigned char *const \
      INCBIN_CONCATENATE( \
          INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
          INCBIN_STYLE_IDENT(END)); \
      INCBIN_EXTERNAL const unsigned int \
          INCBIN_CONCATENATE( \
              INCBIN_CONCATENATE(INCBIN_PREFIX, NAME), \
              INCBIN_STYLE_IDENT(SIZE))
  
  /**
   * @brief Include a binary file into the current translation unit.
   *
   * Includes a binary file into the current translation unit, producing three symbols
   * for objects that encode the data and size respectively.
   *
   * The symbol names are a concatenation of `INCBIN_PREFIX' before *NAME*; with
   * "Data", as well as "End" and "Size" after. An example is provided below.
   *
   * @param NAME The name to associate with this binary data (as an identifier.)
   * @param FILENAME The file to include (as a string literal.)
   *
   * @code
   * INCBIN(Icon, "icon.png");
   *
   * // Now you have the following symbols:
   * // const unsigned char <prefix>IconData[];
   * // const unsigned char *const <prefix>IconEnd;
   * // const unsigned int <prefix>IconSize;
   * @endcode
   *
   * @warning This must be used in global scope
   * @warning The identifiers may be different if INCBIN_STYLE is not default
   *
   * To externally reference the data included by this in another translation unit
   * please @see INCBIN_EXTERN.
   */
  #ifdef _MSC_VER
  #define INCBIN(NAME, FILENAME) \
      INCBIN_EXTERN(NAME)
  #else
  #define INCBIN(NAME, FILENAME) \
      __asm__(INCBIN_SECTION \
              INCBIN_GLOBAL_LABELS(NAME, DATA) \
              INCBIN_ALIGN_HOST \
              INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) ":\n" \
              INCBIN_MACRO " \"" FILENAME "\"\n" \
              INCBIN_GLOBAL_LABELS(NAME, END) \
              INCBIN_ALIGN_BYTE \
              INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) ":\n" \
                  INCBIN_BYTE "1\n" \
              INCBIN_GLOBAL_LABELS(NAME, SIZE) \
              INCBIN_ALIGN_HOST \
              INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(SIZE) ":\n" \
                  INCBIN_INT INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(END) " - " \
                             INCBIN_MANGLE INCBIN_STRINGIZE(INCBIN_PREFIX) #NAME INCBIN_STYLE_STRING(DATA) "\n" \
      ); \
      INCBIN_EXTERN(NAME)
  
  #endif
  #endif
  