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];
110 * Read and discard len bytes from the file. On success, returns 0. On
111 * failure, returns -1 and sets lbx_errno.
113 static int skipdata(FILE *f, size_t len)
115 unsigned char buf[1024];
118 if (fread(buf, MIN(sizeof buf, len), 1, f) != 1) {
120 lbx_errno = LBX_EEOF;
126 len -= MIN(sizeof buf, len);
132 size_t lbx_extract(struct lbx_state *lbx, size_t index, FILE *of)
134 unsigned char buf[1024];
135 size_t rc, written = 0, base, len;
137 if (index >= lbx->nfiles) {
138 lbx_errno = LBX_ERANGE;
142 base = lbx->offsets[index];
143 len = lbx->offsets[index+1] - lbx->offsets[index];
145 /* Seek to the beginning of the file. */
146 if (lbx->foff != base) {
148 long dist = (lbx->foff < base) ? (base - lbx->foff)
149 : -(lbx->foff - base);
151 seekrc = fseek(lbx->f, dist, SEEK_CUR);
152 if (seekrc == -1 && lbx->foff < base) {
153 if (skipdata(lbx->f, dist) == -1) {
154 /* lbx_errno set by skipdata */
157 } else if (seekrc == -1) {
161 lbx->foff += dist; /* FIXME: failed skipdata breaks this. */
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";