X-Git-Url: https://git.draconx.ca/gitweb/upkg.git/blobdiff_plain/79dd803a930da414ec5af1bf41e36317e601fac7..90b53df329f9a114770dccab6b7e41f9094dfac9:/src/libupkg.c diff --git a/src/libupkg.c b/src/libupkg.c index 66546fd..f2addc9 100644 --- a/src/libupkg.c +++ b/src/libupkg.c @@ -47,6 +47,8 @@ struct upkg_import { struct upkg_private { FILE *f; + struct upkg_file *last_file; + struct upkg_name *names; struct upkg_export *exports; struct upkg_import *imports; @@ -60,7 +62,7 @@ struct upkg_private { * Stores the result in *val and returns the number of input bytes read (or 0 * if the input is invalid, in which case *val is undefined). */ -static size_t decode_index(long *val, unsigned char *bytes, size_t n) +size_t upkg_decode_index(long *val, unsigned char *bytes, size_t n) { size_t i = 0; @@ -122,6 +124,34 @@ static struct upkg *init_upkg(unsigned char hdr[static UPKG_HDR_SIZE]) return &alloc->pkg; } +static int pkg_init_guid(struct upkg *pkg) +{ + 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); + if (rc < 8) + return -1; + + heritage_count = unpack_32_le(buf+0); + heritage_offset = unpack_32_le(buf+4); + + if (heritage_count == 0) + return -1; + if (fseek(pkg->priv->f, heritage_offset, SEEK_SET) != 0) + return -1; + } + + rc = fread(pkg->guid, 1, 16, pkg->priv->f); + if (rc < 16) + return -1; + + return 0; +} + static int pkg_init_names(struct upkg *pkg) { size_t rc, len, nbuf = 0; @@ -212,11 +242,11 @@ static int pkg_init_exports(struct upkg *pkg) } len = 0; - rc = decode_index(&export->class, buf+len, nbuf-len); + rc = upkg_decode_index(&export->class, buf+len, nbuf-len); if (rc == 0) goto err; len += rc; - rc = decode_index(&export->super, buf+len, nbuf-len); + rc = upkg_decode_index(&export->super, buf+len, nbuf-len); if (rc == 0) goto err; len += rc; @@ -224,7 +254,7 @@ static int pkg_init_exports(struct upkg *pkg) export->package = unpack_32_le(buf+len); len += 4; - rc = decode_index(&tmp, buf+len, nbuf-len); + rc = upkg_decode_index(&tmp, buf+len, nbuf-len); if (rc == 0 || tmp < 0 || tmp >= pkg->name_count) goto err; export->name = pkg->priv->names[tmp].name; len += rc; @@ -233,12 +263,12 @@ static int pkg_init_exports(struct upkg *pkg) export->flags = unpack_32_le(buf+len); len += 4; - rc = decode_index(&export->size, buf+len, nbuf-len); + rc = upkg_decode_index(&export->size, buf+len, nbuf-len); if (rc == 0) goto err; len += rc; if (export->size) { - rc = decode_index(&export->offset, buf+len, nbuf-len); + rc = upkg_decode_index(&export->offset, buf+len, nbuf-len); if (rc == 0) goto err; len += rc; } @@ -280,12 +310,12 @@ static int pkg_init_imports(struct upkg *pkg) } len = 0; - rc = decode_index(&tmp, buf+len, nbuf-len); + rc = upkg_decode_index(&tmp, buf+len, nbuf-len); if (rc == 0 || len < 0 || len >= pkg->name_count) goto err; import->class_package = pkg->priv->names[tmp].name; len += rc; - rc = decode_index(&tmp, buf+len, nbuf-len); + rc = upkg_decode_index(&tmp, buf+len, nbuf-len); if (rc == 0 || len < 0 || len >= pkg->name_count) goto err; import->class_name = pkg->priv->names[tmp].name; len += rc; @@ -294,7 +324,7 @@ static int pkg_init_imports(struct upkg *pkg) import->package = unpack_32_le(buf+len); len += 4; - rc = decode_index(&tmp, buf+len, nbuf-len); + rc = upkg_decode_index(&tmp, buf+len, nbuf-len); if (rc == 0 || len < 0 || len >= pkg->name_count) goto err; import->object_name = pkg->priv->names[tmp].name; len += rc; @@ -333,6 +363,10 @@ struct upkg *upkg_fopen(const char *path) } pkg->priv->f = f; + if (pkg_init_guid(pkg) != 0) { + goto err2; + } + if (pkg_init_names(pkg) != 0) { goto err2; } @@ -385,3 +419,81 @@ const char *upkg_get_name(struct upkg *pkg, unsigned long idx) return 0; return pkg->priv->names[idx].name; } + +struct upkg_file *upkg_export_open(struct upkg *pkg, unsigned long idx) +{ + struct upkg_file *f; + + if (idx >= pkg->export_count) + return NULL; + + f = malloc(sizeof *f); + if (f == NULL) + return NULL; + + *f = (struct upkg_file) { + .pkg = pkg, + .base = pkg->priv->exports[idx].offset, + .len = pkg->priv->exports[idx].size, + .name = pkg->priv->exports[idx].name, + }; + + return f; +} + +void upkg_export_close(struct upkg_file *f) +{ + if (f->pkg->priv->last_file == f) + f->pkg->priv->last_file = NULL; + free(f); +} + +long upkg_export_tell(struct upkg_file *f) +{ + return f->offset; +} + +int upkg_export_seek(struct upkg_file *f, long offset, int whence) +{ + int rc = EOF; + + switch (whence) { + case SEEK_CUR: + offset = f->offset + offset; + case SEEK_SET: + if (offset < 0 || offset > f->len) + return EOF; + rc = fseek(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); + break; + } + + if (rc == 0) + f->pkg->priv->last_file = f; + return rc; +} + +size_t upkg_export_read(struct upkg_file *f, void *buf, size_t n) +{ + size_t want = MIN(n, f->len - f->offset); + size_t rc; + + if (want == 0) { + return 0; + } + + if (f != f->pkg->priv->last_file) { + if (fseek(f->pkg->priv->f, f->base + f->offset, SEEK_SET)) + return 0; + } + + rc = fread(buf, 1, want, f->pkg->priv->f); + f->offset += rc; + return rc; +}