X-Git-Url: https://git.draconx.ca/gitweb/upkg.git/blobdiff_plain/33c1796d255a720ad076160efd6859ca74d0792f..7904dbe4fcbe956ee4bf785df97d714a397defc1:/src/libupkg.c diff --git a/src/libupkg.c b/src/libupkg.c index ae48820..6b1cfb3 100644 --- a/src/libupkg.c +++ b/src/libupkg.c @@ -25,6 +25,19 @@ #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; @@ -45,6 +58,7 @@ struct upkg_import { struct upkg_private { const struct upkg_file_ops *fops; + int (*dtor)(void *handle); void *f; struct upkg_file *last_file; @@ -60,22 +74,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 = { @@ -351,12 +370,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 +384,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 +399,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 +418,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 +459,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 +471,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); @@ -513,11 +534,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 +548,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 +561,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;