#include #include #include #include "upkg.h" #include "pack.h" struct upkg_name { unsigned long flags; char *name; }; struct upkg_private { FILE *f; struct upkg_name *names; unsigned long name_offset, export_offset, import_offset; unsigned char guid[16]; }; static long decode_index(unsigned char *bytes) { long val = 0; size_t i = 1; val += bytes[0] & 0x3f; if (bytes[0] & 0x40) do { val += bytes[i] & 0x7f; } while (bytes[i] & 0x80 && i < 5); return bytes[0] & 0x80 ? -val : val; } static struct upkg *init_upkg(unsigned char hdr[static UPKG_HDR_SIZE]) { struct upkg *pkg; pkg = malloc(sizeof *pkg); if (!pkg) { return NULL; } pkg->priv = malloc(sizeof *pkg->priv); if (!pkg->priv) { free(pkg); return NULL; } pkg->version = unpack_16_le(hdr+4); pkg->license = unpack_16_le(hdr+6); pkg->flags = unpack_32_le(hdr+8); pkg->name_count = unpack_32_le(hdr+12); pkg->export_count = unpack_32_le(hdr+20); pkg->import_count = unpack_32_le(hdr+28); pkg->priv->name_offset = unpack_32_le(hdr+16); pkg->priv->export_offset = unpack_32_le(hdr+24); pkg->priv->import_offset = unpack_32_le(hdr+32); return pkg; } static int pkg_init_names(struct upkg *pkg) { size_t rc, len, nbuf = 0; unsigned long index = 0; char buf[512]; if (fseek(pkg->priv->f, pkg->priv->name_offset, SEEK_SET) != 0) return -1; pkg->priv->names = malloc(pkg->name_count * sizeof *pkg->priv->names); if (!pkg->priv->names) return -1; while (index < pkg->name_count) { 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 (rc == 0) goto err; nbuf += rc; } if (pkg->version >= 64) { len = buf[0]; if (nbuf <= len + 4 || buf[len]) goto err; name->name = malloc(len); if (!name->name) goto err; memcpy(name->name, buf+1, len); name->flags = unpack_32_le(buf+len+1); nbuf -= len + 5; memmove(buf, buf+len+5, nbuf); index++; } else { abort(); } } return 0; err: free(pkg->priv->names); return -1; } struct upkg *upkg_fopen(const char *path) { unsigned char hdr_buf[UPKG_HDR_SIZE]; struct upkg *pkg; FILE *f; if (!(f = fopen(path, "rb"))) { 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; } /* Initialize package structure. */ pkg = init_upkg(hdr_buf); if (!pkg) { goto err1; } pkg->priv->f = f; if (pkg_init_names(pkg) != 0) { goto err2; } return pkg; err2: free(pkg->priv); free(pkg); err1: fclose(f); return NULL; } int upkg_close(struct upkg *pkg) { int rc = 0; if (pkg->priv->f) { rc = fclose(pkg->priv->f); for (unsigned i = 0; i < pkg->name_count; i++) { free(pkg->priv->names[i].name); } free(pkg->priv->names); return rc; } free(pkg->priv); free(pkg); return 0; } const char *upkg_get_name(struct upkg *pkg, unsigned long idx) { if (idx >= pkg->name_count) return 0; return pkg->priv->names[idx].name; }