From: Nick Bowler Date: Wed, 16 Sep 2009 01:05:32 +0000 (-0400) Subject: libupkg: Parameterise I/O functions to allow custom streams. X-Git-Url: https://git.draconx.ca/gitweb/upkg.git/commitdiff_plain/33c1796d255a720ad076160efd6859ca74d0792f libupkg: Parameterise I/O functions to allow custom streams. --- diff --git a/src/libupkg.c b/src/libupkg.c index 503e3f5..ae48820 100644 --- a/src/libupkg.c +++ b/src/libupkg.c @@ -44,7 +44,8 @@ struct upkg_import { }; struct upkg_private { - FILE *f; + const struct upkg_file_ops *fops; + void *f; struct upkg_file *last_file; @@ -56,6 +57,34 @@ struct upkg_private { unsigned char guid[16]; }; +/* Default I/O operations for ordinary files. */ +static size_t file_read(void *buf, size_t size, void *handle) +{ + return fread(buf, 1, size, handle); +} + +static int file_seek(void *handle, long offset, int whence) +{ + return fseek(handle, offset, whence); +} + +static long file_tell(void *handle) +{ + return ftell(handle); +} + +static int file_eof(void *handle) +{ + return feof(handle); +} + +const struct upkg_file_ops upkg_default_fops = { + .read = file_read, + .seek = file_seek, + .tell = file_tell, + .eof = file_eof, +}; + /* * Decode the compact index format from the upkg. This format is fucked. * Stores the result in *val and returns the number of input bytes read (or 0 @@ -125,13 +154,14 @@ static struct upkg *init_upkg(unsigned char hdr[static UPKG_HDR_SIZE]) static int pkg_init_guid(struct upkg *pkg) { + const struct upkg_file_ops *fops = pkg->priv->fops; size_t rc; if (pkg->version < 68) { unsigned long heritage_count, heritage_offset; unsigned char buf[8]; - rc = fread(buf, 1, sizeof buf, pkg->priv->f); + rc = fops->read(buf, sizeof buf, pkg->priv->f); if (rc < 8) return -1; @@ -140,11 +170,11 @@ static int pkg_init_guid(struct upkg *pkg) if (heritage_count == 0) return -1; - if (fseek(pkg->priv->f, heritage_offset, SEEK_SET) != 0) + if (fops->seek(pkg->priv->f, heritage_offset, SEEK_SET) != 0) return -1; } - rc = fread(pkg->guid, 1, 16, pkg->priv->f); + rc = fops->read(pkg->guid, 16, pkg->priv->f); if (rc < 16) return -1; @@ -153,11 +183,14 @@ static int pkg_init_guid(struct upkg *pkg) static int pkg_init_names(struct upkg *pkg) { + const struct upkg_file_ops *fops = pkg->priv->fops; + void *f = pkg->priv->f; + size_t rc, len, nbuf = 0; unsigned long index = 0; unsigned char buf[512]; - if (fseek(pkg->priv->f, pkg->priv->name_offset, SEEK_SET) != 0) + if (fops->seek(f, pkg->priv->name_offset, SEEK_SET) != 0) return -1; pkg->priv->names = malloc(pkg->name_count * sizeof *pkg->priv->names); @@ -168,8 +201,8 @@ static int pkg_init_names(struct upkg *pkg) struct upkg_name *name = &pkg->priv->names[index]; /* Read some data into buffer. */ - if (!feof(pkg->priv->f)) { - rc = fread(buf+nbuf, 1, sizeof buf-nbuf, pkg->priv->f); + if (!fops->eof(pkg->priv->f)) { + rc = fops->read(buf+nbuf, sizeof buf-nbuf, f); if (rc == 0 && nbuf == 0) goto err; nbuf += rc; @@ -217,11 +250,14 @@ err: static int pkg_init_exports(struct upkg *pkg) { + const struct upkg_file_ops *fops = pkg->priv->fops; + void *f = pkg->priv->f; + size_t rc, len, nbuf = 0; unsigned long index = 0; unsigned char buf[512]; - if (fseek(pkg->priv->f, pkg->priv->export_offset, SEEK_SET) != 0) + if (fops->seek(f, pkg->priv->export_offset, SEEK_SET) != 0) return -1; pkg->priv->exports = malloc(pkg->export_count * sizeof *pkg->priv->exports); @@ -233,8 +269,8 @@ static int pkg_init_exports(struct upkg *pkg) long tmp; /* Read some data into buffer. */ - if (!feof(pkg->priv->f)) { - rc = fread(buf+nbuf, 1, sizeof buf-nbuf, pkg->priv->f); + if (!fops->eof(pkg->priv->f)) { + rc = fops->read(buf+nbuf, sizeof buf-nbuf, f); if (rc == 0 && nbuf == 0) goto err; nbuf += rc; @@ -287,11 +323,14 @@ err: static int pkg_init_imports(struct upkg *pkg) { + const struct upkg_file_ops *fops = pkg->priv->fops; + void *f = pkg->priv->f; + size_t rc, len, nbuf = 0; unsigned long index = 0; unsigned char buf[512]; - if (fseek(pkg->priv->f, pkg->priv->import_offset, SEEK_SET) != 0) + if (fops->seek(f, pkg->priv->import_offset, SEEK_SET) != 0) return -1; pkg->priv->imports = malloc(pkg->import_count * sizeof *pkg->priv->imports); @@ -303,8 +342,8 @@ static int pkg_init_imports(struct upkg *pkg) long tmp; /* Read some data into buffer. */ - if (!feof(pkg->priv->f)) { - rc = fread(buf+nbuf, 1, sizeof buf-nbuf, pkg->priv->f); + if (!fops->eof(pkg->priv->f)) { + rc = fops->read(buf+nbuf, sizeof buf-nbuf, f); if (rc == 0 && nbuf == 0) goto err; nbuf += rc; @@ -341,59 +380,72 @@ err: return -1; } -struct upkg *upkg_fopen(const char *path) +struct upkg *upkg_open(void *f, const struct upkg_file_ops *fops) { unsigned char hdr_buf[UPKG_HDR_SIZE]; struct upkg *pkg; - FILE *f; - if (!(f = fopen(path, "rb"))) { + if (fops->read(hdr_buf, sizeof hdr_buf, f) != sizeof hdr_buf) { return NULL; } - if (fread(hdr_buf, sizeof hdr_buf, 1, f) != 1) { - goto err1; - } if (unpack_32_le(hdr_buf) != UPKG_HDR_MAGIC) { - goto err1; + return NULL; } /* Initialize package structure. */ pkg = init_upkg(hdr_buf); if (!pkg) { - goto err1; + return NULL; } - pkg->priv->f = f; + pkg->priv->fops = fops; + pkg->priv->f = f; if (pkg_init_guid(pkg) != 0) { - goto err2; + goto err1; } if (pkg_init_names(pkg) != 0) { - goto err2; + goto err1; } if (pkg_init_exports(pkg) != 0) { - goto err3; + goto err2; } if (pkg_init_imports(pkg) != 0) { - goto err4; + goto err3; } return pkg; -err4: - free(pkg->priv->exports); err3: + free(pkg->priv->exports); +err2: for (unsigned i = 0; i < pkg->name_count; i++) free(pkg->priv->names[i].name); free(pkg->priv->names); -err2: - free(pkg); err1: - fclose(f); + free(pkg); return NULL; } +struct upkg *upkg_fopen(const char *path) +{ + struct upkg *pkg; + FILE *f; + + f = fopen(path, "rb"); + if (!f) { + return NULL; + } + + pkg = upkg_open(f, &upkg_default_fops); + if (!pkg) { + fclose(f); + } + + return pkg; +} + int upkg_close(struct upkg *pkg) { int rc = 0; @@ -458,7 +510,7 @@ const char *upkg_export_class(struct upkg *pkg, unsigned long idx, if (idx >= pkg->export_count) return NULL; - + export = &pkg->priv->exports[idx]; /* ASSUMPTION: class references are always imports */ @@ -541,6 +593,7 @@ long upkg_export_tell(struct upkg_file *f) int upkg_export_seek(struct upkg_file *f, long offset, int whence) { + const struct upkg_file_ops *fops = f->pkg->priv->fops; int rc = EOF; switch (whence) { @@ -549,14 +602,14 @@ int upkg_export_seek(struct upkg_file *f, long offset, int whence) case SEEK_SET: if (offset < 0 || offset > f->len) return EOF; - rc = fseek(f->pkg->priv->f, f->base + offset, SEEK_SET); + rc = fops->seek(f->pkg->priv->f, f->base + offset, SEEK_SET); break; case SEEK_END: offset = -offset; if (offset < 0 || offset > f->len) return EOF; offset = f->len - offset; - rc = fseek(f->pkg->priv->f, f->base + offset, SEEK_SET); + rc = fops->seek(f->pkg->priv->f, f->base + offset, SEEK_SET); break; } @@ -573,6 +626,7 @@ int upkg_export_seek(struct upkg_file *f, long offset, int whence) size_t upkg_export_read(struct upkg_file *f, void *buf, size_t n) { + const struct upkg_file_ops *fops = f->pkg->priv->fops; size_t want = MIN(n, f->len - f->offset); size_t rc; @@ -581,14 +635,14 @@ size_t upkg_export_read(struct upkg_file *f, void *buf, size_t n) } if (f != f->pkg->priv->last_file) { - if (fseek(f->pkg->priv->f, f->base + f->offset, SEEK_SET)) + if (fops->seek(f->pkg->priv->f, f->base + f->offset, SEEK_SET)) return 0; } - rc = fread(buf, 1, want, f->pkg->priv->f); + rc = fops->read(buf, want, f->pkg->priv->f); f->offset += rc; - if (want < n || (rc < want && feof(f->pkg->priv->f))) + if (want < n || (rc < want && fops->eof(f->pkg->priv->f))) f->eof = 1; return rc; } diff --git a/src/upkg.h b/src/upkg.h index 7565b32..9fc8003 100644 --- a/src/upkg.h +++ b/src/upkg.h @@ -62,6 +62,13 @@ #define UPKG_HDR_MAGIC 0x9e2a83c1 #define UPKG_HDR_SIZE 36 +struct upkg_file_ops { + size_t (*read)(void *buf, size_t size, void *handle); + int (*seek)(void *handle, long offset, int whence); + long (*tell)(void *handle); + int (*eof) (void *handle); +}; + struct upkg { unsigned version, license; unsigned char guid[16]; @@ -81,6 +88,10 @@ struct upkg_file { unsigned long base, offset, len; }; +/* Default I/O operations for ordinary files. */ +extern const struct upkg_file_ops upkg_default_fops; + +struct upkg *upkg_open(void *handle, const struct upkg_file_ops *fops); struct upkg *upkg_fopen(const char *path); int upkg_close(struct upkg *pkg);