+static struct lbx_state *lbx_init(unsigned char hdr[static LBX_HDR_SIZE])
+{
+ unsigned short nfiles = unpack_16_le(hdr+0);
+ unsigned long magic = unpack_32_le(hdr+2);
+ unsigned short version = unpack_16_le(hdr+6);
+ struct lbx_state *lbx;
+
+ if (magic != LBX_MAGIC) {
+ lbx_errno = -LBX_EMAGIC;
+ return NULL;
+ }
+
+ lbx = malloc(sizeof *lbx + sizeof lbx->offsets[0] * (nfiles+1));
+ if (!lbx) {
+ lbx_errno = -errno;
+ return NULL;
+ }
+
+ *lbx = (struct lbx_state) {
+ .nfiles = nfiles,
+ };
+
+ return lbx;
+}
+
+struct lbx_state *lbx_fopen(FILE *f, const char *name)
+{
+ unsigned char hdr_buf[LBX_HDR_SIZE];
+ struct lbx_state *lbx;
+
+ if (fread(hdr_buf, 1, sizeof hdr_buf, f) != sizeof hdr_buf) {
+ lbx_errno = -errno;
+ return NULL;
+ }
+
+ lbx = lbx_init(hdr_buf);
+ if (!lbx)
+ return NULL;
+
+ lbx->name = name;
+ lbx->f = f;
+ lbx->foff = sizeof hdr_buf;
+
+ for (unsigned i = 0; i <= lbx->nfiles; i++) {
+ unsigned char buf[4];
+
+ if (fread(buf, 1, sizeof buf, f) != sizeof buf) {
+ lbx_errno = -errno;
+ if (feof(f))
+ lbx_errno = LBX_EEOF;
+ free(lbx);
+ return NULL;
+ }
+
+ lbx->offsets[i] = unpack_32_le(buf);
+ lbx->foff += sizeof buf;
+ }
+
+ return lbx;
+}
+
+static int _lbx_memcpy(void *dest, struct lbx_state *src, size_t size)
+{
+ if (src->foff + size > src->memsize)
+ return -1;
+ memcpy(dest, src->mem + src->foff, size);
+ src->foff += size;
+ return 0;
+}
+
+struct lbx_state *lbx_mopen(void *_mem, size_t size, const char *name)