15 #include "byteorder.h"
19 #define LBX_MAGIC 0x0000fead
35 struct lbx_state *lbx_fopen(FILE *f, const char *name)
37 struct lbx_state *new = NULL;
38 uint16_t nfiles, version;
41 if (fread(&nfiles, sizeof nfiles, 1, f) != 1) goto readerr;
42 if (fread(&magic, sizeof magic, 1, f) != 1) goto readerr;
43 if (fread(&version, sizeof version, 1, f) != 1) goto readerr;
45 nfiles = letohs(nfiles);
46 magic = letohl(magic);
47 version = letohs(version);
49 if (magic != LBX_MAGIC) {
50 lbx_errno = LBX_EMAGIC;
54 new = malloc(sizeof *new + (nfiles+1)*(sizeof *new->offsets));
60 *new = (struct lbx_state){
64 .foff = sizeof nfiles + sizeof magic + sizeof version,
67 if (fread(new->offsets, sizeof *new->offsets, nfiles+1, f) != nfiles+1)
69 new->foff += sizeof *new->offsets * (nfiles+1);
83 static int _lbx_memcpy(void *dest, struct lbx_state *src, size_t size)
85 if (src->foff + size > src->memsize)
87 memcpy(dest, src->mem + src->foff, size);
92 struct lbx_state *lbx_mopen(void *_mem, size_t size, const char *name)
94 struct lbx_state *new = NULL;
95 struct lbx_state tmp = { .mem = _mem, .memsize = size };
96 uint16_t nfiles, version;
99 if (_lbx_memcpy(&nfiles, &tmp, sizeof nfiles) == -1) goto eof;
100 if (_lbx_memcpy(&magic, &tmp, sizeof magic) == -1) goto eof;
101 if (_lbx_memcpy(&version, &tmp, sizeof version) == -1) goto eof;
103 nfiles = letohs(nfiles);
104 magic = letohl(magic);
105 version = letohs(version);
107 if (magic != LBX_MAGIC) {
108 lbx_errno = LBX_EMAGIC;
112 new = malloc(sizeof *new + (nfiles+1)*(sizeof *new->offsets));
118 *new = (struct lbx_state){
126 if (_lbx_memcpy(new->offsets, new, (nfiles+1)*(sizeof *new->offsets)))
132 lbx_errno = LBX_EEOF;
136 struct lbx_state *lbx_open(const char *path)
138 struct lbx_state *new = NULL;
141 if ((f = fopen(path, "rb"))) {
142 const char *name = strrchr(path, '/');
143 new = lbx_fopen(f, name ? name+1 : path);
151 size_t lbx_numfiles(struct lbx_state *lbx)
156 int lbx_stat(struct lbx_state *lbx, size_t index, struct lbx_statbuf *buf)
158 static char str[256]; /* FIXME */
160 if (index >= lbx->nfiles) {
162 lbx_errno = LBX_ERANGE;
166 snprintf(str, sizeof str, "%s.%03d", lbx->name, index);
168 buf->size = lbx->offsets[index+1] - lbx->offsets[index];
173 _lbx_mextract(struct lbx_state *lbx, size_t base, size_t len, FILE *of)
178 assert(base + len <= lbx->memsize);
180 rc = fwrite(lbx->mem + base, 1, len, of);
188 _lbx_fextract(struct lbx_state *lbx, size_t base, size_t len, FILE *of)
190 unsigned char buf[1024];
191 size_t rc, written = 0;
195 if (_lbx_fseek(lbx->f, &lbx->foff, base) == -1)
199 size_t amt = MIN(len, sizeof buf);
201 rc = fread(buf, 1, amt, lbx->f);
205 if (feof(lbx->f)) lbx_errno = LBX_EEOF;
206 else lbx_errno = -errno;
210 rc = fwrite(buf, 1, amt, of);
221 size_t lbx_extract(struct lbx_state *lbx, size_t index, FILE *of)
225 if (index >= lbx->nfiles) {
226 lbx_errno = LBX_ERANGE;
230 base = lbx->offsets[index];
231 len = lbx->offsets[index+1] - lbx->offsets[index];
234 return _lbx_mextract(lbx, base, len, of);
235 return _lbx_fextract(lbx, base, len, of);
238 void *lbx_mmap(struct lbx_state *lbx, size_t index, size_t *len)
240 unsigned char *mapping;
244 if (index >= lbx->nfiles) {
245 lbx_errno = LBX_ERANGE;
249 base = lbx->offsets[index];
250 *len = lbx->offsets[index+1] - lbx->offsets[index];
253 return lbx->mem + base;
255 if (fstat(fileno(lbx->f), &statbuf) == -1) {
260 mapping = mmap(NULL, statbuf.st_size, PROT_READ, 0, fileno(lbx->f), 0);
261 if (mapping == MAP_FAILED) {
267 lbx->memsize = statbuf.st_size;
268 return mapping + base;
271 void lbx_close(struct lbx_state *lbx)
278 munmap(lbx->mem, lbx->memsize);
285 const char *lbx_strerror(void)
288 return strerror(-lbx_errno);
291 case LBX_ESUCCESS: return "Success";
292 case LBX_EMAGIC: return "Bad magic number";
293 case LBX_EEOF: return "Unexpected end-of-file";
294 case LBX_ERANGE: return "Index out of range";
295 case LBX_EFORMAT: return "Invalid file format";
298 return "Unknown error";