From 358691759871264951bcacb3066340030466d93d Mon Sep 17 00:00:00 2001 From: Nick Bowler Date: Fri, 5 Jun 2009 15:18:49 -0400 Subject: [PATCH] Implement export table parsing. --- libupkg.c | 127 +++++++++++++++++++++++++++++++++++++++++++++++++----- upkg.c | 2 + 2 files changed, 118 insertions(+), 11 deletions(-) diff --git a/libupkg.c b/libupkg.c index de4b2f1..f55c079 100644 --- a/libupkg.c +++ b/libupkg.c @@ -5,31 +5,63 @@ #include "upkg.h" #include "pack.h" +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + struct upkg_name { unsigned long flags; char *name; }; +struct upkg_export { + long class, super, name; + unsigned long package, flags; + unsigned long size, offset; +}; + struct upkg_private { FILE *f; - struct upkg_name *names; + struct upkg_name *names; + struct upkg_export *exports; unsigned long name_offset, export_offset, import_offset; unsigned char guid[16]; }; -static long decode_index(unsigned char *bytes) +/* + * 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 + * if the input is invalid, in which case *val is undefined). + */ +static size_t decode_index(long *val, unsigned char *bytes, size_t n) { - long val = 0; - size_t i = 1; + size_t i = 0; + + *val = 0; + while (i < MIN(n, 5)) { + /* + * Least significant bytes are first, so we need to do this + * nonsense. + */ + long tmp = bytes[i] & (i == 0 ? 0x3f : 0x7f); + + if (i > 0) tmp <<= 6; + if (i > 1) tmp <<= 7*(i-1); + *val += tmp; + + if (!(bytes[i] & (i == 0 ? 0x40 : 0x80))) { + i++; + break; + } - val += bytes[0] & 0x3f; - if (bytes[0] & 0x40) do { - val += bytes[i] & 0x7f; - } while (bytes[i] & 0x80 && i < 5); + i++; + } - return bytes[0] & 0x80 ? -val : val; + if (i > MIN(n, 5) || n == 0) + return 0; + if (bytes[0] & 0x80) + *val = -*val; + return i; } static struct upkg *init_upkg(unsigned char hdr[static UPKG_HDR_SIZE]) @@ -112,6 +144,72 @@ err: return -1; } +static int pkg_init_exports(struct upkg *pkg) +{ + size_t rc, len, nbuf = 0; + unsigned long index = 0; + char buf[512]; + + if (fseek(pkg->priv->f, pkg->priv->export_offset, SEEK_SET) != 0) + return -1; + + pkg->priv->exports = malloc(pkg->export_count * sizeof *pkg->priv->exports); + if (!pkg->priv->exports) + return -1; + + while (index < pkg->export_count) { + struct upkg_export *export = &pkg->priv->exports[index]; + + /* Read some data into buffer. */ + if (!feof(pkg->priv->f)) { + rc = fread(buf+nbuf, 1, sizeof buf-nbuf, pkg->priv->f); + if (rc == 0) + goto err; + nbuf += rc; + } + + len = 0; + rc = decode_index(&export->class, buf+len, nbuf-len); + if (rc == 0) goto err; + len += rc; + + rc = decode_index(&export->super, buf+len, nbuf-len); + if (rc == 0) goto err; + len += rc; + + if (nbuf-len < 4) goto err; + export->package = unpack_32_le(buf+len); + len += 4; + + rc = decode_index(&export->name, buf+len, nbuf-len); + if (rc == 0) goto err; + len += rc; + + if (nbuf-len < 4) goto err; + export->flags = unpack_32_le(buf+len); + len += 4; + + rc = 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); + if (rc == 0) goto err; + len += rc; + } + + nbuf -= len; + memmove(buf, buf+len, nbuf); + index++; + } + + return 0; +err: + free(pkg->priv->exports); + return -1; +} + struct upkg *upkg_fopen(const char *path) { unsigned char hdr_buf[UPKG_HDR_SIZE]; @@ -135,11 +233,17 @@ struct upkg *upkg_fopen(const char *path) } pkg->priv->f = f; - if (pkg_init_names(pkg) != 0) { + if (pkg_init_exports(pkg) != 0) { goto err2; } + if (pkg_init_names(pkg) != 0) { + goto err3; + } + return pkg; +err3: + free(pkg->priv->exports); err2: free(pkg->priv); free(pkg); @@ -158,11 +262,12 @@ int upkg_close(struct upkg *pkg) for (unsigned i = 0; i < pkg->name_count; i++) { free(pkg->priv->names[i].name); } - free(pkg->priv->names); return rc; } + free(pkg->priv->exports); + free(pkg->priv->names); free(pkg->priv); free(pkg); diff --git a/upkg.c b/upkg.c index d7b181d..2694f5b 100644 --- a/upkg.c +++ b/upkg.c @@ -45,6 +45,8 @@ int main(int argc, char **argv) printf("\t%s\n", upkg_get_name(pkg, i)); } + printf("Exports: %lu\n", pkg->export_count); + upkg_close(pkg); return 0; } -- 2.43.2