11 #include "byteorder.h"
14 #define LBX_MAGIC 0x0000fead
15 #define MIN(a,b) (((a)<(b))?(a):(b))
31 struct lbx_state *lbx_fopen(FILE *f, const char *name)
33 struct lbx_state *new = NULL;
34 uint16_t nfiles, version;
37 if (fread(&nfiles, sizeof nfiles, 1, f) != 1) goto readerr;
38 if (fread(&magic, sizeof magic, 1, f) != 1) goto readerr;
39 if (fread(&version, sizeof version, 1, f) != 1) goto readerr;
41 nfiles = letohs(nfiles);
42 magic = letohl(magic);
43 version = letohs(version);
45 if (magic != LBX_MAGIC) {
46 lbx_errno = LBX_EMAGIC;
50 new = malloc(sizeof *new + (nfiles+1)*(sizeof *new->offsets));
56 *new = (struct lbx_state){
60 .foff = sizeof nfiles + sizeof magic + sizeof version,
63 if (fread(new->offsets, sizeof *new->offsets, nfiles+1, f) != nfiles+1)
65 new->foff += sizeof *new->offsets * (nfiles+1);
79 static int _lbx_memcpy(void *dest, struct lbx_state *src, size_t size)
81 if (src->foff + size > src->memsize)
83 memcpy(dest, src->mem + src->foff, size);
88 struct lbx_state *lbx_mopen(void *_mem, size_t size, const char *name)
90 struct lbx_state *new = NULL;
91 struct lbx_state tmp = { .mem = _mem, .memsize = size };
92 uint16_t nfiles, version;
95 if (_lbx_memcpy(&nfiles, &tmp, sizeof nfiles) == -1) goto eof;
96 if (_lbx_memcpy(&magic, &tmp, sizeof magic) == -1) goto eof;
97 if (_lbx_memcpy(&version, &tmp, sizeof version) == -1) goto eof;
99 nfiles = letohs(nfiles);
100 magic = letohl(magic);
101 version = letohs(version);
103 if (magic != LBX_MAGIC) {
104 lbx_errno = LBX_EMAGIC;
108 new = malloc(sizeof *new + (nfiles+1)*(sizeof *new->offsets));
114 *new = (struct lbx_state){
122 if (_lbx_memcpy(new->offsets, new, (nfiles+1)*(sizeof *new->offsets)))
128 lbx_errno = LBX_EEOF;
132 struct lbx_state *lbx_open(const char *path)
134 struct lbx_state *new = NULL;
137 if ((f = fopen(path, "rb"))) {
138 const char *name = strrchr(path, '/');
139 new = lbx_fopen(f, name ? name+1 : path);
147 size_t lbx_numfiles(struct lbx_state *lbx)
152 int lbx_stat(struct lbx_state *lbx, size_t index, struct lbx_statbuf *buf)
154 static char str[256]; /* FIXME */
156 if (index >= lbx->nfiles) {
158 lbx_errno = LBX_ERANGE;
162 snprintf(str, sizeof str, "%s.%03d", lbx->name, index);
164 buf->size = lbx->offsets[index+1] - lbx->offsets[index];
168 /* Advance to the beginning of the index'th file by either fseek or reading. */
169 static int _lbx_fseek(struct lbx_state *lbx, size_t base)
171 static unsigned char oblivion[1024];
174 if (lbx->foff < base) {
175 dist = base - lbx->foff;
176 } else if (lbx->foff > base) {
177 dist = -(long)(lbx->foff - base);
182 if (fseek(lbx->f, dist, SEEK_CUR) == 0) {
184 } else if (lbx->foff < base) {
186 size_t rc, amt = MIN(sizeof oblivion, dist);
187 rc = fread(oblivion, 1, amt, lbx->f);
192 lbx_errno = LBX_EEOF;
206 _lbx_mextract(struct lbx_state *lbx, size_t base, size_t len, FILE *of)
211 assert(base + len <= lbx->memsize);
213 rc = fwrite(lbx->mem + base, 1, len, of);
221 _lbx_fextract(struct lbx_state *lbx, size_t base, size_t len, FILE *of)
223 unsigned char buf[1024];
224 size_t rc, written = 0;
228 if (_lbx_fseek(lbx, base) == -1)
232 size_t amt = MIN(len, sizeof buf);
234 rc = fread(buf, 1, amt, lbx->f);
238 if (feof(lbx->f)) lbx_errno = LBX_EEOF;
239 else lbx_errno = -errno;
243 rc = fwrite(buf, 1, amt, of);
254 size_t lbx_extract(struct lbx_state *lbx, size_t index, FILE *of)
258 if (index >= lbx->nfiles) {
259 lbx_errno = LBX_ERANGE;
263 base = lbx->offsets[index];
264 len = lbx->offsets[index+1] - lbx->offsets[index];
267 return _lbx_mextract(lbx, base, len, of);
268 return _lbx_fextract(lbx, base, len, of);
271 void *lbx_mmap(struct lbx_state *lbx, size_t index, size_t *len)
273 unsigned char *mapping;
277 if (index >= lbx->nfiles) {
278 lbx_errno = LBX_ERANGE;
282 base = lbx->offsets[index];
283 *len = lbx->offsets[index+1] - lbx->offsets[index];
286 return lbx->mem + base;
288 if (fstat(fileno(lbx->f), &statbuf) == -1) {
293 mapping = mmap(NULL, statbuf.st_size, PROT_READ, 0, fileno(lbx->f), 0);
294 if (mapping == MAP_FAILED) {
300 lbx->memsize = statbuf.st_size;
301 return mapping + base;
304 void lbx_close(struct lbx_state *lbx)
311 munmap(lbx->mem, lbx->memsize);
318 const char *lbx_strerror(void)
321 return strerror(-lbx_errno);
324 case LBX_ESUCCESS: return "Success";
325 case LBX_EMAGIC: return "Bad magic number";
326 case LBX_EEOF: return "Unexpected end-of-file";
327 case LBX_ERANGE: return "Index out of range";
330 return "Unknown error";