15 #include "byteorder.h"
18 #define LBX_MAGIC 0x0000fead
19 #define MIN(a,b) (((a)<(b))?(a):(b))
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];
172 /* Advance to the beginning of the index'th file by either fseek or reading. */
173 static int _lbx_fseek(struct lbx_state *lbx, size_t base)
175 static unsigned char oblivion[1024];
178 if (lbx->foff < base) {
179 dist = base - lbx->foff;
180 } else if (lbx->foff > base) {
181 dist = -(long)(lbx->foff - base);
186 if (fseek(lbx->f, dist, SEEK_CUR) == 0) {
188 } else if (lbx->foff < base) {
190 size_t rc, amt = MIN(sizeof oblivion, dist);
191 rc = fread(oblivion, 1, amt, lbx->f);
196 lbx_errno = LBX_EEOF;
210 _lbx_mextract(struct lbx_state *lbx, size_t base, size_t len, FILE *of)
215 assert(base + len <= lbx->memsize);
217 rc = fwrite(lbx->mem + base, 1, len, of);
225 _lbx_fextract(struct lbx_state *lbx, size_t base, size_t len, FILE *of)
227 unsigned char buf[1024];
228 size_t rc, written = 0;
232 if (_lbx_fseek(lbx, base) == -1)
236 size_t amt = MIN(len, sizeof buf);
238 rc = fread(buf, 1, amt, lbx->f);
242 if (feof(lbx->f)) lbx_errno = LBX_EEOF;
243 else lbx_errno = -errno;
247 rc = fwrite(buf, 1, amt, of);
258 size_t lbx_extract(struct lbx_state *lbx, size_t index, FILE *of)
262 if (index >= lbx->nfiles) {
263 lbx_errno = LBX_ERANGE;
267 base = lbx->offsets[index];
268 len = lbx->offsets[index+1] - lbx->offsets[index];
271 return _lbx_mextract(lbx, base, len, of);
272 return _lbx_fextract(lbx, base, len, of);
275 void *lbx_mmap(struct lbx_state *lbx, size_t index, size_t *len)
277 unsigned char *mapping;
281 if (index >= lbx->nfiles) {
282 lbx_errno = LBX_ERANGE;
286 base = lbx->offsets[index];
287 *len = lbx->offsets[index+1] - lbx->offsets[index];
290 return lbx->mem + base;
292 if (fstat(fileno(lbx->f), &statbuf) == -1) {
297 mapping = mmap(NULL, statbuf.st_size, PROT_READ, 0, fileno(lbx->f), 0);
298 if (mapping == MAP_FAILED) {
304 lbx->memsize = statbuf.st_size;
305 return mapping + base;
308 void lbx_close(struct lbx_state *lbx)
315 munmap(lbx->mem, lbx->memsize);
322 const char *lbx_strerror(void)
325 return strerror(-lbx_errno);
328 case LBX_ESUCCESS: return "Success";
329 case LBX_EMAGIC: return "Bad magic number";
330 case LBX_EEOF: return "Unexpected end-of-file";
331 case LBX_ERANGE: return "Index out of range";
334 return "Unknown error";