X-Git-Url: https://git.draconx.ca/gitweb/upkg.git/blobdiff_plain/33c1796d255a720ad076160efd6859ca74d0792f..5f381395f22864d2c8213d2288d21aa2a2efbe0d:/src/libupkg.c diff --git a/src/libupkg.c b/src/libupkg.c index ae48820..e861bcb 100644 --- a/src/libupkg.c +++ b/src/libupkg.c @@ -25,16 +25,28 @@ #define MIN(a, b) ((a) < (b) ? (a) : (b)) +/* + * Print a message and execute some statement(s) if the expression evaluates + * to zero. Intended to help verify that assumed constraints on the file + * format actually are not violated. + */ +#define format_assert(expr, body) do { \ + if (!(expr)) { \ + fprintf(stderr, "%s: %d: %s: format assertion failed: %s\n", \ + __FILE__, __LINE__, __func__, #expr); \ + body; \ + } \ +} while (0) + struct upkg_name { unsigned long flags; char *name; }; -struct upkg_export { - const char *name; +struct upkg_export_priv { + struct upkg_export pub; long package, class, super; - unsigned long flags; unsigned long size, offset; }; @@ -45,13 +57,14 @@ struct upkg_import { struct upkg_private { const struct upkg_file_ops *fops; + int (*dtor)(void *handle); void *f; struct upkg_file *last_file; - struct upkg_name *names; - struct upkg_export *exports; - struct upkg_import *imports; + struct upkg_name *names; + struct upkg_export_priv *exports; + struct upkg_import *imports; unsigned long name_offset, export_offset, import_offset; unsigned char guid[16]; @@ -60,22 +73,27 @@ struct upkg_private { /* 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); + return fread(buf, 1, size, (FILE *)handle); } static int file_seek(void *handle, long offset, int whence) { - return fseek(handle, offset, whence); + return fseek((FILE *)handle, offset, whence); } static long file_tell(void *handle) { - return ftell(handle); + return ftell((FILE *)handle); } static int file_eof(void *handle) { - return feof(handle); + return feof((FILE *)handle); +} + +static int file_close(void *handle) +{ + return fclose((FILE *)handle); } const struct upkg_file_ops upkg_default_fops = { @@ -265,7 +283,7 @@ static int pkg_init_exports(struct upkg *pkg) return -1; while (index < pkg->export_count) { - struct upkg_export *export = &pkg->priv->exports[index]; + struct upkg_export_priv *export = &pkg->priv->exports[index]; long tmp; /* Read some data into buffer. */ @@ -291,11 +309,11 @@ static int pkg_init_exports(struct upkg *pkg) 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; + export->pub.name = pkg->priv->names[tmp].name; len += rc; if (nbuf-len < 4) goto err; - export->flags = unpack_32_le(buf+len); + export->pub.flags = unpack_32_le(buf+len); len += 4; rc = upkg_decode_index(&tmp, buf+len, nbuf-len); @@ -351,12 +369,12 @@ static int pkg_init_imports(struct upkg *pkg) len = 0; rc = upkg_decode_index(&tmp, buf+len, nbuf-len); - if (rc == 0 || len < 0 || len >= pkg->name_count) goto err; + if (rc == 0 || len >= pkg->name_count) goto err; import->class_package = pkg->priv->names[tmp].name; len += rc; rc = upkg_decode_index(&tmp, buf+len, nbuf-len); - if (rc == 0 || len < 0 || len >= pkg->name_count) goto err; + if (rc == 0 || len >= pkg->name_count) goto err; import->class_name = pkg->priv->names[tmp].name; len += rc; @@ -365,7 +383,7 @@ static int pkg_init_imports(struct upkg *pkg) len += 4; rc = upkg_decode_index(&tmp, buf+len, nbuf-len); - if (rc == 0 || len < 0 || len >= pkg->name_count) goto err; + if (rc == 0 || len >= pkg->name_count) goto err; import->object_name = pkg->priv->names[tmp].name; len += rc; @@ -380,7 +398,8 @@ err: return -1; } -struct upkg *upkg_open(void *f, const struct upkg_file_ops *fops) +struct upkg *upkg_open(void *f, const struct upkg_file_ops *fops, + int (*destructor)(void *handle)) { unsigned char hdr_buf[UPKG_HDR_SIZE]; struct upkg *pkg; @@ -398,6 +417,7 @@ struct upkg *upkg_open(void *f, const struct upkg_file_ops *fops) return NULL; } pkg->priv->fops = fops; + pkg->priv->dtor = destructor; pkg->priv->f = f; if (pkg_init_guid(pkg) != 0) { @@ -438,7 +458,7 @@ struct upkg *upkg_fopen(const char *path) return NULL; } - pkg = upkg_open(f, &upkg_default_fops); + pkg = upkg_open(f, &upkg_default_fops, file_close); if (!pkg) { fclose(f); } @@ -450,12 +470,12 @@ int upkg_close(struct upkg *pkg) { int rc = 0; - if (pkg->priv->f) { - rc = fclose(pkg->priv->f); + if (pkg->priv->dtor) { + rc = pkg->priv->dtor(pkg->priv->f); + } - for (unsigned i = 0; i < pkg->name_count; i++) { - free(pkg->priv->names[i].name); - } + for (unsigned i = 0; i < pkg->name_count; i++) { + free(pkg->priv->names[i].name); } free(pkg->priv->imports); @@ -473,13 +493,17 @@ const char *upkg_get_name(struct upkg *pkg, unsigned long idx) return pkg->priv->names[idx].name; } -long upkg_export_find(struct upkg *pkg, const char *name) +long upkg_export_find(struct upkg *pkg, long parent, const char *name) { - /* This is wrong. - * Export names are not necessarily unique within a package. */ - for (unsigned i = 0; i < pkg->export_count; i++) { - struct upkg_export *export = &pkg->priv->exports[i]; - if (strcmp(export->name, name) == 0) { + /* This only makes sense if the assertion below is not violated. */ + long package = parent < 0 ? 0 : parent + 1; + + for (unsigned long i = 0; i < pkg->export_count; i++) { + struct upkg_export_priv *e = &pkg->priv->exports[i]; + + /* Assertion: an object's package is an export. */ + format_assert(e->package >= 0, continue); + if (e->package == package && strcmp(e->pub.name, name) == 0) { return i; } } @@ -487,24 +511,17 @@ long upkg_export_find(struct upkg *pkg, const char *name) return -1; } -unsigned long upkg_export_flags(struct upkg *pkg, unsigned long idx) +const struct upkg_export *upkg_get_export(struct upkg *pkg, unsigned long idx) { if (idx < pkg->export_count) - return pkg->priv->exports[idx].flags; - return 0; -} - -const char *upkg_export_name(struct upkg *pkg, unsigned long idx) -{ - if (idx < pkg->export_count) - return pkg->priv->exports[idx].name; + return &pkg->priv->exports[idx].pub; return NULL; } const char *upkg_export_class(struct upkg *pkg, unsigned long idx, const char **package) { - struct upkg_export *export; + struct upkg_export_priv *export; struct upkg_import *iclass, *ipackage; unsigned long pkg_idx; @@ -513,11 +530,8 @@ const char *upkg_export_class(struct upkg *pkg, unsigned long idx, export = &pkg->priv->exports[idx]; - /* ASSUMPTION: class references are always imports */ - if (export->class > 0) { - fprintf(stderr, "Assumption Violated: class not import\n"); - return NULL; - } + /* Assumption: class references are always imports. */ + format_assert(export->class <= 0, return NULL); /* Get the class. */ if (export->class == 0) { @@ -530,17 +544,12 @@ const char *upkg_export_class(struct upkg *pkg, unsigned long idx, return NULL; iclass = &pkg->priv->imports[pkg_idx]; - /* ASSUMPTION: Class references are always Core.Class */ - if (strcmp(iclass->class_name, "Class") || strcmp(iclass->class_package, "Core")) { - fprintf(stderr, "Assumption Violated: class not Core.Class\n"); - return NULL; - } + /* Assumption: class references are always Core.Class. */ + format_assert(!strcmp(iclass->class_package, "Core"), return NULL); + format_assert(!strcmp(iclass->class_name, "Class"), return NULL); - /* ASSUMPTION: Package references are always imports */ - if (iclass->package >= 0) { - fprintf(stderr, "Assumption Violated: package not import\n"); - return NULL; - } + /* Assumption: package references are always imports. */ + format_assert(iclass->package <= 0, return NULL); /* Get the package. */ pkg_idx = -(iclass->package + 1); @@ -548,11 +557,9 @@ const char *upkg_export_class(struct upkg *pkg, unsigned long idx, return NULL; ipackage = &pkg->priv->imports[pkg_idx]; - /* ASSUMPTION: Package references are always Core.Package */ - if (strcmp(ipackage->class_name, "Package") || strcmp(ipackage->class_package, "Core")) { - fprintf(stderr, "Assumption Violated: package not Core.Package\n"); - return NULL; - } + /* Assumption: package references are always Core.Package. */ + format_assert(!strcmp(ipackage->class_package, "Core"), return NULL); + format_assert(!strcmp(ipackage->class_name, "Package"), return NULL); if (package) *package = ipackage->object_name; return iclass->object_name; @@ -573,7 +580,7 @@ struct upkg_file *upkg_export_open(struct upkg *pkg, unsigned long idx) .pkg = pkg, .base = pkg->priv->exports[idx].offset, .len = pkg->priv->exports[idx].size, - .name = pkg->priv->exports[idx].name, + .name = pkg->priv->exports[idx].pub.name, }; return f;