struct upkg_private {
FILE *f;
+ struct upkg_file *last_file;
+
struct upkg_name *names;
struct upkg_export *exports;
struct upkg_import *imports;
* 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;
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;
}
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;
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;
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;
}
}
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;
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;
}
pkg->priv->f = f;
+ if (pkg_init_guid(pkg) != 0) {
+ goto err2;
+ }
+
if (pkg_init_names(pkg) != 0) {
goto err2;
}
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;
+}