10 #define LBX_MAGIC 0x0000fead
11 #define MIN(a,b) (((a)<(b))?(a):(b))
25 struct lbx_state *lbx_fopen(FILE *f, const char *name)
27 struct lbx_state *new = NULL;
28 uint16_t nfiles, version;
31 if (fread(&nfiles, sizeof nfiles, 1, f) != 1) goto readerr;
32 if (fread(&magic, sizeof magic, 1, f) != 1) goto readerr;
33 if (fread(&version, sizeof version, 1, f) != 1) goto readerr;
35 nfiles = letohs(nfiles);
36 magic = letohl(magic);
37 version = letohs(version);
39 if (magic != LBX_MAGIC) {
40 lbx_errno = LBX_EMAGIC;
44 new = malloc(sizeof *new + (nfiles+1)*(sizeof *new->offsets));
50 *new = (struct lbx_state){
54 .foff = sizeof nfiles + sizeof magic + sizeof version,
57 if (fread(new->offsets, sizeof *new->offsets, nfiles+1, f) != nfiles+1)
59 new->foff += sizeof *new->offsets * (nfiles+1);
73 struct lbx_state *lbx_open(const char *path)
75 struct lbx_state *new = NULL;
78 if ((f = fopen(path, "rb"))) {
79 const char *name = strrchr(path, '/');
80 new = lbx_fopen(f, name ? name+1 : path);
88 size_t lbx_numfiles(struct lbx_state *lbx)
93 int lbx_stat(struct lbx_state *lbx, size_t index, struct lbx_statbuf *buf)
95 static char str[256]; /* FIXME */
97 if (index >= lbx->nfiles) {
99 lbx_errno = LBX_ERANGE;
103 snprintf(str, sizeof str, "%s.%03d", lbx->name, index);
105 buf->size = lbx->offsets[index+1] - lbx->offsets[index];
109 /* Advance to the beginning of the index'th file by either fseek or reading. */
110 static int _lbx_fseek(struct lbx_state *lbx, size_t base)
112 static unsigned char oblivion[1024];
115 if (lbx->foff < base) {
116 dist = base - lbx->foff;
117 } else if (lbx->foff > base) {
118 dist = -(long)(lbx->foff - base);
123 if (fseek(lbx->f, dist, SEEK_CUR) == 0) {
125 } else if (lbx->foff < base) {
127 size_t rc, amt = MIN(sizeof oblivion, dist);
128 rc = fread(oblivion, 1, amt, lbx->f);
133 lbx_errno = LBX_EEOF;
146 size_t lbx_extract(struct lbx_state *lbx, size_t index, FILE *of)
148 unsigned char buf[1024];
149 size_t rc, written = 0, base, len;
151 if (index >= lbx->nfiles) {
152 lbx_errno = LBX_ERANGE;
156 base = lbx->offsets[index];
157 len = lbx->offsets[index+1] - lbx->offsets[index];
159 if (_lbx_fseek(lbx, base) == -1) {
160 /* lbx_errno set by _lbx_fseek(). */
166 size_t amt = MIN(sizeof buf, len);
168 rc = fread(buf, 1, amt, lbx->f);
173 lbx_errno = LBX_EEOF;
180 rc = fwrite(buf, 1, amt, of);
191 void lbx_close(struct lbx_state *lbx)
199 const char *lbx_strerror(void)
202 return strerror(-lbx_errno);
205 case LBX_ESUCCESS: return "Success";
206 case LBX_EMAGIC: return "Bad magic number";
207 case LBX_EEOF: return "Unexpected end-of-file";
208 case LBX_ERANGE: return "Index out of range";
211 return "Unknown error";