11 #define LBX_MAGIC 0x0000fead
12 #define MIN(a,b) (((a)<(b))?(a):(b))
28 struct lbx_state *lbx_fopen(FILE *f, const char *name)
30 struct lbx_state *new = NULL;
31 uint16_t nfiles, version;
34 if (fread(&nfiles, sizeof nfiles, 1, f) != 1) goto readerr;
35 if (fread(&magic, sizeof magic, 1, f) != 1) goto readerr;
36 if (fread(&version, sizeof version, 1, f) != 1) goto readerr;
38 nfiles = letohs(nfiles);
39 magic = letohl(magic);
40 version = letohs(version);
42 if (magic != LBX_MAGIC) {
43 lbx_errno = LBX_EMAGIC;
47 new = malloc(sizeof *new + (nfiles+1)*(sizeof *new->offsets));
53 *new = (struct lbx_state){
57 .foff = sizeof nfiles + sizeof magic + sizeof version,
60 if (fread(new->offsets, sizeof *new->offsets, nfiles+1, f) != nfiles+1)
62 new->foff += sizeof *new->offsets * (nfiles+1);
76 static int _lbx_memcpy(void *dest, struct lbx_state *src, size_t size)
78 if (src->foff + size > src->memsize)
80 memcpy(dest, src->mem + src->foff, size);
85 struct lbx_state *lbx_mopen(void *_mem, size_t size, const char *name)
87 struct lbx_state *new = NULL;
88 struct lbx_state tmp = { .mem = _mem, .memsize = size };
89 uint16_t nfiles, version;
92 if (_lbx_memcpy(&nfiles, &tmp, sizeof nfiles) == -1) goto eof;
93 if (_lbx_memcpy(&magic, &tmp, sizeof magic) == -1) goto eof;
94 if (_lbx_memcpy(&version, &tmp, sizeof version) == -1) goto eof;
96 nfiles = letohs(nfiles);
97 magic = letohl(magic);
98 version = letohs(version);
100 if (magic != LBX_MAGIC) {
101 lbx_errno = LBX_EMAGIC;
105 new = malloc(sizeof *new + (nfiles+1)*(sizeof *new->offsets));
111 *new = (struct lbx_state){
119 if (_lbx_memcpy(new->offsets, new, (nfiles+1)*(sizeof *new->offsets)))
125 lbx_errno = LBX_EEOF;
129 struct lbx_state *lbx_open(const char *path)
131 struct lbx_state *new = NULL;
134 if ((f = fopen(path, "rb"))) {
135 const char *name = strrchr(path, '/');
136 new = lbx_fopen(f, name ? name+1 : path);
144 size_t lbx_numfiles(struct lbx_state *lbx)
149 int lbx_stat(struct lbx_state *lbx, size_t index, struct lbx_statbuf *buf)
151 static char str[256]; /* FIXME */
153 if (index >= lbx->nfiles) {
155 lbx_errno = LBX_ERANGE;
159 snprintf(str, sizeof str, "%s.%03d", lbx->name, index);
161 buf->size = lbx->offsets[index+1] - lbx->offsets[index];
165 /* Advance to the beginning of the index'th file by either fseek or reading. */
166 static int _lbx_fseek(struct lbx_state *lbx, size_t base)
168 static unsigned char oblivion[1024];
171 if (lbx->foff < base) {
172 dist = base - lbx->foff;
173 } else if (lbx->foff > base) {
174 dist = -(long)(lbx->foff - base);
179 if (fseek(lbx->f, dist, SEEK_CUR) == 0) {
181 } else if (lbx->foff < base) {
183 size_t rc, amt = MIN(sizeof oblivion, dist);
184 rc = fread(oblivion, 1, amt, lbx->f);
189 lbx_errno = LBX_EEOF;
203 _lbx_mextract(struct lbx_state *lbx, size_t base, size_t len, FILE *of)
208 assert(base + len <= lbx->memsize);
210 rc = fwrite(lbx->mem + base, 1, len, of);
218 _lbx_fextract(struct lbx_state *lbx, size_t base, size_t len, FILE *of)
220 unsigned char buf[1024];
221 size_t rc, written = 0;
225 if (_lbx_fseek(lbx, base) == -1)
229 size_t amt = MIN(len, sizeof buf);
231 rc = fread(buf, 1, amt, lbx->f);
235 if (feof(lbx->f)) lbx_errno = LBX_EEOF;
236 else lbx_errno = -errno;
240 rc = fwrite(buf, 1, amt, of);
251 size_t lbx_extract(struct lbx_state *lbx, size_t index, FILE *of)
255 if (index >= lbx->nfiles) {
256 lbx_errno = LBX_ERANGE;
260 base = lbx->offsets[index];
261 len = lbx->offsets[index+1] - lbx->offsets[index];
264 return _lbx_mextract(lbx, base, len, of);
265 return _lbx_fextract(lbx, base, len, of);
268 void lbx_close(struct lbx_state *lbx)
277 const char *lbx_strerror(void)
280 return strerror(-lbx_errno);
283 case LBX_ESUCCESS: return "Success";
284 case LBX_EMAGIC: return "Bad magic number";
285 case LBX_EEOF: return "Unexpected end-of-file";
286 case LBX_ERANGE: return "Index out of range";
289 return "Unknown error";