diff options
Diffstat (limited to 'src/mess/tools/imgtool/imgtool.c')
-rw-r--r-- | src/mess/tools/imgtool/imgtool.c | 2812 |
1 files changed, 2812 insertions, 0 deletions
diff --git a/src/mess/tools/imgtool/imgtool.c b/src/mess/tools/imgtool/imgtool.c new file mode 100644 index 00000000000..4236050f870 --- /dev/null +++ b/src/mess/tools/imgtool/imgtool.c @@ -0,0 +1,2812 @@ +/*************************************************************************** + + imgtool.c + + Core code for Imgtool + +***************************************************************************/ + +#include <string.h> +#include <ctype.h> + +#include "imgtool.h" +#include "formats/imageutl.h" +#include "library.h" +#include "modules.h" +#include "pool.h" + + +/*************************************************************************** + TYPE DEFINITIONS +***************************************************************************/ + +struct _imgtool_image +{ + const imgtool_module *module; + object_pool *pool; +}; + +struct _imgtool_partition +{ + imgtool_image *image; + object_pool *pool; + int partition_index; + UINT64 base_block; + UINT64 block_count; + + imgtool_class imgclass; + size_t partition_extra_bytes; + size_t directory_extra_bytes; + + char path_separator; + char alternate_path_separator; + + unsigned int prefer_ucase : 1; + unsigned int supports_creation_time : 1; + unsigned int supports_lastmodified_time : 1; + unsigned int supports_bootblock : 1; /* this module supports loading/storing the boot block */ + + imgtoolerr_t (*begin_enum) (imgtool_directory *enumeration, const char *path); + imgtoolerr_t (*next_enum) (imgtool_directory *enumeration, imgtool_dirent *ent); + void (*close_enum) (imgtool_directory *enumeration); + imgtoolerr_t (*free_space) (imgtool_partition *partition, UINT64 *size); + imgtoolerr_t (*read_file) (imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf); + imgtoolerr_t (*write_file) (imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *opts); + imgtoolerr_t (*delete_file) (imgtool_partition *partition, const char *filename); + imgtoolerr_t (*list_forks) (imgtool_partition *partition, const char *path, imgtool_forkent *ents, size_t len); + imgtoolerr_t (*create_dir) (imgtool_partition *partition, const char *path); + imgtoolerr_t (*delete_dir) (imgtool_partition *partition, const char *path); + imgtoolerr_t (*list_attrs) (imgtool_partition *partition, const char *path, UINT32 *attrs, size_t len); + imgtoolerr_t (*get_attrs) (imgtool_partition *partition, const char *path, const UINT32 *attrs, imgtool_attribute *values); + imgtoolerr_t (*set_attrs) (imgtool_partition *partition, const char *path, const UINT32 *attrs, const imgtool_attribute *values); + imgtoolerr_t (*attr_name) (UINT32 attribute, const imgtool_attribute *attr, char *buffer, size_t buffer_len); + imgtoolerr_t (*get_iconinfo) (imgtool_partition *partition, const char *path, imgtool_iconinfo *iconinfo); + imgtoolerr_t (*suggest_transfer)(imgtool_partition *partition, const char *path, imgtool_transfer_suggestion *suggestions, size_t suggestions_length); + imgtoolerr_t (*get_chain) (imgtool_partition *partition, const char *path, imgtool_chainent *chain, size_t chain_size); + + const option_guide *writefile_optguide; + const char *writefile_optspec; +}; + +struct _imgtool_directory +{ + imgtool_partition *partition; +}; + + + +/*************************************************************************** + GLOBALS +***************************************************************************/ + +static imgtool_library *global_imgtool_library; + +static int global_omit_untested; +static void (*global_warn)(const char *message); + + +void CLIB_DECL logerror(const char *format, ...) +{ + va_list arg; + va_start(arg, format); + printf(format, arg); + va_end(arg); +} + +/*************************************************************************** + + Imgtool initialization and basics + +***************************************************************************/ +void rtrim(char *buf) +{ + size_t buflen; + char *s; + + buflen = strlen(buf); + if (buflen) + { + for (s = &buf[buflen-1]; s >= buf && (*s >= '\0') && isspace(*s); s--) + *s = '\0'; + } +} + +char *strncpyz(char *dest, const char *source, size_t len) +{ + char *s; + if (len) { + s = strncpy(dest, source, len - 1); + dest[len-1] = '\0'; + } + else { + s = dest; + } + return s; +} + +char *strncatz(char *dest, const char *source, size_t len) +{ + size_t l; + l = strlen(dest); + dest += l; + if (len > l) + len -= l; + else + len = 0; + return strncpyz(dest, source, len); +} + +/*------------------------------------------------- + markerrorsource - marks where an error source +-------------------------------------------------*/ + +static imgtoolerr_t markerrorsource(imgtoolerr_t err) +{ + switch(err) + { + case IMGTOOLERR_OUTOFMEMORY: + case IMGTOOLERR_UNEXPECTED: + case IMGTOOLERR_BUFFERTOOSMALL: + /* Do nothing */ + break; + + case IMGTOOLERR_FILENOTFOUND: + case IMGTOOLERR_BADFILENAME: + err = (imgtoolerr_t)(err | IMGTOOLERR_SRC_FILEONIMAGE); + break; + + default: + err = (imgtoolerr_t)(err | IMGTOOLERR_SRC_IMAGEFILE); + break; + } + return err; +} + +char *imgtool_basename(char *filename) +{ + char *c; + + // NULL begets NULL + if (!filename) + return NULL; + + // start at the end and return when we hit a slash or colon + for (c = filename + strlen(filename) - 1; c >= filename; c--) + if (*c == '\\' || *c == '/' || *c == ':') + return c + 1; + + // otherwise, return the whole thing + return filename; +} + +/*------------------------------------------------- + internal_error - debug function for raising + internal errors +-------------------------------------------------*/ + +static void internal_error(const imgtool_module *module, const char *message) +{ +#ifdef MAME_DEBUG + printf("%s: %s\n", module->name, message); +#endif +} + + +/*------------------------------------------------- + normalize_filename - convert a filename to the + native format used by the module +-------------------------------------------------*/ + +static char *normalize_filename(imgtool_partition *partition, const char *src) +{ + imgtool_charset charset; + + /* get charset from module */ + charset = (imgtool_charset) (int) imgtool_partition_get_info_int(partition, IMGTOOLINFO_INT_CHARSET); + + /* and dupe it */ + return native_from_utf8(charset, src); +} + + + +/*------------------------------------------------- + imgtool_init - initializes the imgtool core +-------------------------------------------------*/ + +void imgtool_init(int omit_untested, void (*warn)(const char *message)) +{ + imgtoolerr_t err; + err = imgtool_create_cannonical_library(omit_untested, &global_imgtool_library); + assert(err == IMGTOOLERR_SUCCESS); + if (err == IMGTOOLERR_SUCCESS) + { + imgtool_library_sort(global_imgtool_library, ITLS_DESCRIPTION); + } + global_omit_untested = omit_untested; + global_warn = warn; +} + + + +/*------------------------------------------------- + imgtool_exit - closes out the imgtool core +-------------------------------------------------*/ + +void imgtool_exit(void) +{ + if (global_imgtool_library) + { + imgtool_library_close(global_imgtool_library); + global_imgtool_library = NULL; + } + global_warn = NULL; +} + + + +/*------------------------------------------------- + imgtool_find_module - looks up a module +-------------------------------------------------*/ + +const imgtool_module *imgtool_find_module(const char *modulename) +{ + return imgtool_library_findmodule(global_imgtool_library, modulename); +} + + + +/*------------------------------------------------- + imgtool_get_module_features - retrieves a + structure identifying this module's features + associated with an image +-------------------------------------------------*/ + +imgtool_module_features imgtool_get_module_features(const imgtool_module *module) +{ + imgtool_module_features features; + memset(&features, 0, sizeof(features)); + + if (module->create) + features.supports_create = 1; + if (module->open) + features.supports_open = 1; + if (module->read_sector) + features.supports_readsector = 1; + if (module->write_sector) + features.supports_writesector = 1; + return features; +} + + + +/*------------------------------------------------- + imgtool_warn - issues a warning +-------------------------------------------------*/ + +void imgtool_warn(const char *format, ...) +{ + va_list va; + char buffer[2000]; + + if (global_warn) + { + va_start(va, format); + vsprintf(buffer, format, va); + va_end(va); + global_warn(buffer); + } +} + + + +/*------------------------------------------------- + evaluate_module - evaluates a single file to + determine what module can best handle a file +-------------------------------------------------*/ + +static imgtoolerr_t evaluate_module(const char *fname, + const imgtool_module *module, float *result) +{ + imgtoolerr_t err; + imgtool_image *image = NULL; + imgtool_partition *partition = NULL; + imgtool_directory *imageenum = NULL; + imgtool_dirent ent; + float current_result; + + *result = 0.0; + + err = imgtool_image_open(module, fname, OSD_FOPEN_READ, &image); + if (err) + goto done; + + if (image) + { + current_result = module->open_is_strict ? 0.9 : 0.5; + + err = imgtool_partition_open(image, 0, &partition); + if (err) + goto done; + + err = imgtool_directory_open(partition, NULL, &imageenum); + if (err) + goto done; + + memset(&ent, 0, sizeof(ent)); + do + { + err = imgtool_directory_get_next(imageenum, &ent); + if (err) + goto done; + + if (ent.corrupt) + current_result = (current_result * 99 + 1.00) / 100; + else + current_result = (current_result + 1.00) / 2; + } + while(!ent.eof); + + *result = current_result; + } + +done: + if (ERRORCODE(err) == IMGTOOLERR_CORRUPTIMAGE) + err = IMGTOOLERR_SUCCESS; + if (imageenum) + imgtool_directory_close(imageenum); + if (partition) + imgtool_partition_close(partition); + if (image) + imgtool_image_close(image); + return err; +} + + + +/*------------------------------------------------- + imgtool_partition_image - retrieves the image + associated with this partition +-------------------------------------------------*/ + +imgtool_image *imgtool_partition_image(imgtool_partition *partition) +{ + return partition->image; +} + + + +/*------------------------------------------------- + imgtool_identify_file - attempts to determine the module + for any given image +-------------------------------------------------*/ + +imgtoolerr_t imgtool_identify_file(const char *fname, imgtool_module **modules, size_t count) +{ + imgtoolerr_t err = IMGTOOLERR_SUCCESS; + imgtool_library *library = global_imgtool_library; + imgtool_module *module = NULL; + imgtool_module *insert_module; + imgtool_module *temp_module; + size_t i = 0; + const char *extension; + float val, temp_val, *values = NULL; + + if (count <= 0) + { + err = IMGTOOLERR_UNEXPECTED; + goto done; + } + + for (i = 0; i < count; i++) + modules[i] = NULL; + if (count > 1) + count--; /* null terminate */ + + values = (float *) malloc(count * sizeof(*values)); + if (!values) + { + err = IMGTOOLERR_OUTOFMEMORY; + goto done; + } + for (i = 0; i < count; i++) + values[i] = 0.0; + + /* figure out the file extension, if any */ + extension = strrchr(fname, '.'); + if (extension) + extension++; + + /* iterate through all modules */ + while((module = imgtool_library_iterate(library, module)) != NULL) + { + if (!extension || image_find_extension(module->extensions, extension)) + { + err = evaluate_module(fname, module, &val); + if (err) + goto done; + + insert_module = module; + for (i = 0; (val > 0.0) && (i < count); i++) + { + if (val > values[i]) + { + temp_val = values[i]; + temp_module = modules[i]; + values[i] = val; + modules[i] = insert_module; + val = temp_val; + insert_module = temp_module; + } + } + } + } + + if (!modules[0]) + err = (imgtoolerr_t)(IMGTOOLERR_MODULENOTFOUND | IMGTOOLERR_SRC_IMAGEFILE); + +done: + if (values) + free(values); + return err; +} + + + +/*------------------------------------------------- + imgtool_image_get_sector_size - gets the size + of a particular sector on an image +-------------------------------------------------*/ + +imgtoolerr_t imgtool_image_get_sector_size(imgtool_image *image, UINT32 track, UINT32 head, + UINT32 sector, UINT32 *length) +{ + /* implemented? */ + if (!image->module->get_sector_size) + return (imgtoolerr_t )(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + + return image->module->get_sector_size(image, track, head, sector, length); +} + + + +/*------------------------------------------------- + imgtool_image_get_geometry - gets the geometry + of an image; note that this may disagree with + particular sectors; this is a common copy + protection scheme +-------------------------------------------------*/ + +imgtoolerr_t imgtool_image_get_geometry(imgtool_image *image, UINT32 *tracks, UINT32 *heads, UINT32 *sectors) +{ + UINT32 dummy; + + /* some sanitization, to make the callbacks easier to implement */ + if (!tracks) + tracks = &dummy; + if (!heads) + heads = &dummy; + if (!sectors) + sectors = &dummy; + *tracks = 0; + *heads = 0; + *sectors = 0; + + /* implemented? */ + if (!image->module->get_geometry) + return (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + + return image->module->get_geometry(image, tracks, heads, sectors); +} + + + +/*------------------------------------------------- + imgtool_image_read_sector - reads a sector on an image +-------------------------------------------------*/ + +imgtoolerr_t imgtool_image_read_sector(imgtool_image *image, UINT32 track, UINT32 head, + UINT32 sector, void *buffer, size_t len) +{ + /* implemented? */ + if (!image->module->read_sector) + return (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + + return image->module->read_sector(image, track, head, sector, buffer, len); +} + + + +/*------------------------------------------------- + imgtool_image_write_sector - writes a sector on an image +-------------------------------------------------*/ + +imgtoolerr_t imgtool_image_write_sector(imgtool_image *image, UINT32 track, UINT32 head, + UINT32 sector, const void *buffer, size_t len) +{ + /* implemented? */ + if (!image->module->write_sector) + return (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + + return image->module->write_sector(image, track, head, sector, buffer, len); +} + + + +/*------------------------------------------------- + imgtool_image_get_block_size - gets the size of + a standard block on an image +-------------------------------------------------*/ + +imgtoolerr_t imgtool_image_get_block_size(imgtool_image *image, UINT32 *length) +{ + /* implemented? */ + if (image->module->block_size == 0) + return (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + + *length = image->module->block_size; + return IMGTOOLERR_SUCCESS; +} + + + +/*------------------------------------------------- + imgtool_image_read_block - reads a standard + block on an image +-------------------------------------------------*/ + +imgtoolerr_t imgtool_image_read_block(imgtool_image *image, UINT64 block, void *buffer) +{ + /* implemented? */ + if (!image->module->read_block) + return (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + + return image->module->read_block(image, buffer, block); +} + + + +/*------------------------------------------------- + imgtool_image_write_block - writes a standard + block on an image +-------------------------------------------------*/ + +imgtoolerr_t imgtool_image_write_block(imgtool_image *image, UINT64 block, const void *buffer) +{ + /* implemented? */ + if (!image->module->write_block) + return (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + + return image->module->write_block(image, buffer, block); +} + + + +/*------------------------------------------------- + imgtool_image_clear_block - clears a standard + block on an image +-------------------------------------------------*/ + +imgtoolerr_t imgtool_image_clear_block(imgtool_image *image, UINT64 block, UINT8 data) +{ + imgtoolerr_t err; + UINT8 *block_data = NULL; + UINT32 length; + + err = imgtool_image_get_block_size(image, &length); + if (err) + goto done; + + block_data = (UINT8*)malloc(length); + if (!block_data) + { + err = (imgtoolerr_t)IMGTOOLERR_OUTOFMEMORY; + goto done; + } + memset(block_data, data, length); + + err = imgtool_image_write_block(image, block, block_data); + if (err) + goto done; + +done: + if (block_data) + free(block_data); + return err; +} + + + +/*------------------------------------------------- + imgtool_image_list_partitions - lists the + partitions on an image +-------------------------------------------------*/ + +imgtoolerr_t imgtool_image_list_partitions(imgtool_image *image, imgtool_partition_info *partitions, size_t len) +{ + /* implemented? */ + if (!image->module->list_partitions) + return (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + + memset(partitions, '\0', sizeof(*partitions) * len); + return image->module->list_partitions(image, partitions, len); +} + + + +/*------------------------------------------------- + imgtool_image_malloc - allocates memory associated with an + image +-------------------------------------------------*/ + +void *imgtool_image_malloc(imgtool_image *image, size_t size) +{ + return pool_malloc_lib(image->pool, size); +} + + + +/*------------------------------------------------- + imgtool_image_module - returns the module associated with + this image +-------------------------------------------------*/ + +const imgtool_module *imgtool_image_module(imgtool_image *img) +{ + return img->module; +} + + + +/*------------------------------------------------- + imgtool_image_extra_bytes - returns extra bytes on an image +-------------------------------------------------*/ + +void *imgtool_image_extra_bytes(imgtool_image *image) +{ + void *ptr = NULL; + if (image->module->image_extra_bytes > 0) + ptr = ((UINT8 *) image) + sizeof(*image); + assert(ptr); + return ptr; +} + + + +/*------------------------------------------------- + imgtool_image_rand - returns a random number +-------------------------------------------------*/ + +UINT64 imgtool_image_rand(imgtool_image *image) +{ + /* we can't use mame_rand() here */ +#ifdef rand +#undef rand +#endif + return ((UINT64) rand()) << 32 + | ((UINT64) rand()) << 0; +} + + + +/*************************************************************************** + + Imgtool partition management + +***************************************************************************/ + +static char *pool_strdup_allow_null(object_pool *pool, char *s) +{ + return s ? pool_strdup_lib(pool, s) : NULL; +} + + + +imgtoolerr_t imgtool_partition_open(imgtool_image *image, int partition_index, imgtool_partition **partition) +{ + imgtoolerr_t err = (imgtoolerr_t)IMGTOOLERR_SUCCESS; + imgtool_partition *p = NULL; + imgtool_class imgclass; + imgtool_partition_info partition_info[32]; + UINT64 base_block, block_count; + size_t partition_extra_bytes; + object_pool *pool; + imgtoolerr_t (*open_partition)(imgtool_partition *partition, UINT64 first_block, UINT64 block_count); + + if (image->module->list_partitions) + { + /* this image supports partitions */ + if ((partition_index < 0) || (partition_index >= ARRAY_LENGTH(partition_info))) + return IMGTOOLERR_INVALIDPARTITION; + + /* retrieve the info on the partitions */ + memset(partition_info, '\0', sizeof(partition_info)); + err = image->module->list_partitions(image, partition_info, ARRAY_LENGTH(partition_info)); + if (err) + return err; + + /* is this a valid partition */ + if (!partition_info[partition_index].get_info) + return IMGTOOLERR_INVALIDPARTITION; + + /* use this partition */ + memset(&imgclass, 0, sizeof(imgclass)); + imgclass.get_info = partition_info[partition_index].get_info; + base_block = partition_info[partition_index].base_block; + block_count = partition_info[partition_index].block_count; + } + else + { + /* this image does not support partitions */ + if (partition_index != 0) + return IMGTOOLERR_INVALIDPARTITION; + + /* identify the image class */ + imgclass = imgtool_image_module(image)->imgclass; + base_block = 0; + block_count = ~0; + } + + /* does this partition type have extra bytes? */ + partition_extra_bytes = imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_PARTITION_EXTRA_BYTES); + + /* allocate the new memory pool */ + pool = pool_alloc_lib(NULL); + if (!pool) + { + err = (imgtoolerr_t)IMGTOOLERR_OUTOFMEMORY; + goto done; + } + + /* allocate the new partition object */ + p = (imgtool_partition *) pool_malloc_lib(pool, sizeof(*p) + partition_extra_bytes); + if (!p) + { + err = (imgtoolerr_t)IMGTOOLERR_OUTOFMEMORY; + goto done; + } + memset(p, 0, sizeof(*p) + partition_extra_bytes); + p->pool = pool; + + /* fill out the structure */ + p->image = image; + p->partition_index = partition_index; + p->base_block = base_block; + p->block_count = block_count; + p->imgclass = imgclass; + p->partition_extra_bytes = partition_extra_bytes; + p->directory_extra_bytes = imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_DIRECTORY_EXTRA_BYTES); + p->path_separator = (char) imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_PATH_SEPARATOR); + p->alternate_path_separator = (char) imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_ALTERNATE_PATH_SEPARATOR); + p->prefer_ucase = imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_PREFER_UCASE) ? 1 : 0; + p->supports_creation_time = imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_SUPPORTS_CREATION_TIME) ? 1 : 0; + p->supports_lastmodified_time = imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_SUPPORTS_LASTMODIFIED_TIME) ? 1 : 0; + p->supports_bootblock = imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_SUPPORTS_BOOTBLOCK) ? 1 : 0; + p->begin_enum = (imgtoolerr_t (*)(imgtool_directory *, const char *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_BEGIN_ENUM); + p->next_enum = (imgtoolerr_t (*)(imgtool_directory *, imgtool_dirent *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_NEXT_ENUM); + p->free_space = (imgtoolerr_t (*)(imgtool_partition *, UINT64 *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_FREE_SPACE); + p->read_file = (imgtoolerr_t (*)(imgtool_partition *, const char *, const char *, imgtool_stream *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_READ_FILE); + p->write_file = (imgtoolerr_t (*)(imgtool_partition *, const char *, const char *, imgtool_stream *, option_resolution *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_WRITE_FILE); + p->delete_file = (imgtoolerr_t (*)(imgtool_partition *, const char *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_DELETE_FILE); + p->list_forks = (imgtoolerr_t (*)(imgtool_partition *, const char *, imgtool_forkent *, size_t)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_LIST_FORKS); + p->create_dir = (imgtoolerr_t (*)(imgtool_partition *, const char *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_CREATE_DIR); + p->delete_dir = (imgtoolerr_t (*)(imgtool_partition *, const char *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_DELETE_DIR); + p->list_attrs = (imgtoolerr_t (*)(imgtool_partition *, const char *, UINT32 *, size_t)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_LIST_ATTRS); + p->get_attrs = (imgtoolerr_t (*)(imgtool_partition *, const char *, const UINT32 *, imgtool_attribute *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_GET_ATTRS); + p->set_attrs = (imgtoolerr_t (*)(imgtool_partition *, const char *, const UINT32 *, const imgtool_attribute *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_SET_ATTRS); + p->attr_name = (imgtoolerr_t (*)(UINT32, const imgtool_attribute *, char *, size_t)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_ATTR_NAME); + p->get_iconinfo = (imgtoolerr_t (*)(imgtool_partition *, const char *, imgtool_iconinfo *)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_GET_ICON_INFO); + p->suggest_transfer = (imgtoolerr_t (*)(imgtool_partition *, const char *, imgtool_transfer_suggestion *, size_t)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_SUGGEST_TRANSFER); + p->get_chain = (imgtoolerr_t (*)(imgtool_partition *, const char *, imgtool_chainent *, size_t)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_GET_CHAIN); + p->writefile_optguide = (const option_guide *) imgtool_get_info_ptr(&imgclass, IMGTOOLINFO_PTR_WRITEFILE_OPTGUIDE); + p->writefile_optspec = pool_strdup_allow_null(p->pool, (char*)imgtool_get_info_ptr(&imgclass, IMGTOOLINFO_STR_WRITEFILE_OPTSPEC)); + + /* mask out if writing is untested */ + if (global_omit_untested && imgtool_get_info_int(&imgclass, IMGTOOLINFO_INT_WRITING_UNTESTED)) + { + p->write_file = NULL; + p->delete_file = NULL; + p->create_dir = NULL; + p->delete_dir = NULL; + p->writefile_optguide = NULL; + p->writefile_optspec = NULL; + } + + /* call the partition open function, if present */ + open_partition = (imgtoolerr_t (*)(imgtool_partition *, UINT64, UINT64)) imgtool_get_info_fct(&imgclass, IMGTOOLINFO_PTR_OPEN_PARTITION); + if (open_partition) + { + /* we have an open partition function */ + err = (*open_partition)(p, base_block, block_count); + if (err) + goto done; + } + +done: + *partition = err ? NULL : p; + return err; +} + + + +void imgtool_partition_close(imgtool_partition *partition) +{ + pool_free_lib(partition->pool); +} + + + +/*************************************************************************** + + Imgtool partition operations + +***************************************************************************/ + +/*------------------------------------------------- + imgtool_partition_get_attribute_name - retrieves the human readable + name for an attribute +-------------------------------------------------*/ + +void imgtool_partition_get_attribute_name(imgtool_partition *partition, UINT32 attribute, const imgtool_attribute *attr_value, + char *buffer, size_t buffer_len) +{ + imgtoolerr_t err = (imgtoolerr_t)IMGTOOLERR_UNIMPLEMENTED; + + buffer[0] = '\0'; + + if (attr_value) + { + if (partition->attr_name) + err = partition->attr_name(attribute, attr_value, buffer, buffer_len); + + if (err == (imgtoolerr_t)IMGTOOLERR_UNIMPLEMENTED) + { + switch(attribute & 0xF0000) + { + case IMGTOOLATTR_INT_FIRST: + snprintf(buffer, buffer_len, "%d", (int) attr_value->i); + break; + } + } + } + else + { + switch(attribute) + { + case IMGTOOLATTR_INT_MAC_TYPE: + snprintf(buffer, buffer_len, "File type"); + break; + case IMGTOOLATTR_INT_MAC_CREATOR: + snprintf(buffer, buffer_len, "File creator"); + break; + case IMGTOOLATTR_INT_MAC_FINDERFLAGS: + snprintf(buffer, buffer_len, "Finder flags"); + break; + case IMGTOOLATTR_INT_MAC_COORDX: + snprintf(buffer, buffer_len, "X coordinate"); + break; + case IMGTOOLATTR_INT_MAC_COORDY: + snprintf(buffer, buffer_len, "Y coordinate"); + break; + case IMGTOOLATTR_INT_MAC_FINDERFOLDER: + snprintf(buffer, buffer_len, "Finder folder"); + break; + case IMGTOOLATTR_INT_MAC_ICONID: + snprintf(buffer, buffer_len, "Icon ID"); + break; + case IMGTOOLATTR_INT_MAC_SCRIPTCODE: + snprintf(buffer, buffer_len, "Script code"); + break; + case IMGTOOLATTR_INT_MAC_EXTENDEDFLAGS: + snprintf(buffer, buffer_len, "Extended flags"); + break; + case IMGTOOLATTR_INT_MAC_COMMENTID: + snprintf(buffer, buffer_len, "Comment ID"); + break; + case IMGTOOLATTR_INT_MAC_PUTAWAYDIRECTORY: + snprintf(buffer, buffer_len, "Putaway directory"); + break; + case IMGTOOLATTR_TIME_CREATED: + snprintf(buffer, buffer_len, "Creation time"); + break; + case IMGTOOLATTR_TIME_LASTMODIFIED: + snprintf(buffer, buffer_len, "Last modified time"); + break; + } + } +} + + + +/*------------------------------------------------- + imgtool_validitychecks - checks the validity + of the imgtool modules +-------------------------------------------------*/ + +int imgtool_validitychecks(void) +{ + int error = 0; + int val; + imgtoolerr_t err = (imgtoolerr_t)IMGTOOLERR_SUCCESS; + const imgtool_module *module = NULL; + const option_guide *guide_entry; + imgtool_module_features features; + int created_library = FALSE; + + if (!global_imgtool_library) + { + imgtool_init(FALSE, NULL); + created_library = TRUE; + } + + while((module = imgtool_library_iterate(global_imgtool_library, module)) != NULL) + { + features = imgtool_get_module_features(module); + + if (!module->name) + { + printf("imgtool module %s has null 'name'\n", module->name); + error = 1; + } + if (!module->description) + { + printf("imgtool module %s has null 'description'\n", module->name); + error = 1; + } + if (!module->extensions) + { + printf("imgtool module %s has null 'extensions'\n", module->extensions); + error = 1; + } + +#if 0 + /* sanity checks on modules that do not support directories */ + if (!module->path_separator) + { + if (module->alternate_path_separator) + { + printf("imgtool module %s specified alternate_path_separator but not path_separator\n", module->name); + error = 1; + } + if (module->initial_path_separator) + { + printf("imgtool module %s specified initial_path_separator without directory support\n", module->name); + error = 1; + } + if (module->create_dir) + { + printf("imgtool module %s implements create_dir without directory support\n", module->name); + error = 1; + } + if (module->delete_dir) + { + printf("imgtool module %s implements delete_dir without directory support\n", module->name); + error = 1; + } + } +#endif + + /* sanity checks on sector operations */ + if (module->read_sector && !module->get_sector_size) + { + printf("imgtool module %s implements read_sector without supporting get_sector_size\n", module->name); + error = 1; + } + if (module->write_sector && !module->get_sector_size) + { + printf("imgtool module %s implements write_sector without supporting get_sector_size\n", module->name); + error = 1; + } + + /* sanity checks on creation options */ + if (module->createimage_optguide || module->createimage_optspec) + { + if (!module->create) + { + printf("imgtool module %s has creation options without supporting create\n", module->name); + error = 1; + } + if ((!module->createimage_optguide && module->createimage_optspec) + || (module->createimage_optguide && !module->createimage_optspec)) + { + printf("imgtool module %s does has partially incomplete creation options\n", module->name); + error = 1; + } + + if (module->createimage_optguide && module->createimage_optspec) + { + guide_entry = module->createimage_optguide; + while(guide_entry->option_type != OPTIONTYPE_END) + { + if (option_resolution_contains(module->createimage_optspec, guide_entry->parameter)) + { + switch(guide_entry->option_type) + { + case OPTIONTYPE_INT: + case OPTIONTYPE_ENUM_BEGIN: + err = (imgtoolerr_t)option_resolution_getdefault(module->createimage_optspec, + guide_entry->parameter, &val); + if (err) + goto done; + break; + + default: + break; + } + if (!guide_entry->identifier) + { + printf("imgtool module %s creation option %d has null identifier\n", + module->name, (int) (guide_entry - module->createimage_optguide)); + error = 1; + } + if (!guide_entry->display_name) + { + printf("imgtool module %s creation option %d has null display_name\n", + module->name, (int) (guide_entry - module->createimage_optguide)); + error = 1; + } + } + guide_entry++; + } + } + } + } + +done: + if (created_library) + imgtool_exit(); + if (err) + { + printf("imgtool: %s\n", imgtool_error(err)); + error = 1; + } + return error; +} + + + +/*------------------------------------------------- + imgtool_temp_str - provides a temporary string + buffer used for string passing +-------------------------------------------------*/ + +char *imgtool_temp_str(void) +{ + static int index; + static char temp_string_pool[32][256]; + return temp_string_pool[index++ % ARRAY_LENGTH(temp_string_pool)]; +} + + + +/*************************************************************************** + + Image handling functions + +***************************************************************************/ + +static imgtoolerr_t internal_open(const imgtool_module *module, const char *fname, + int read_or_write, option_resolution *createopts, imgtool_image **outimg) +{ + imgtoolerr_t err; + imgtool_stream *f = NULL; + imgtool_image *image = NULL; + object_pool *pool = NULL; + size_t size; + + if (outimg) + *outimg = NULL; + + /* is the requested functionality implemented? */ + if ((read_or_write == OSD_FOPEN_RW_CREATE) ? !module->create : !module->open) + { + err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + /* create a memory pool */ + pool = pool_alloc_lib(NULL); + if (!pool) + { + err = (imgtoolerr_t)(IMGTOOLERR_OUTOFMEMORY); + goto done; + } + + /* open the stream */ + f = stream_open(fname, read_or_write); + if (!f) + { + err = (imgtoolerr_t)(IMGTOOLERR_FILENOTFOUND | IMGTOOLERR_SRC_IMAGEFILE); + goto done; + } + + /* setup the image structure */ + size = sizeof(struct _imgtool_image) + module->image_extra_bytes; + image = (imgtool_image *) pool_malloc_lib(pool, size); + if (!image) + { + err = (imgtoolerr_t)IMGTOOLERR_OUTOFMEMORY; + goto done; + } + memset(image, '\0', size); + image->pool = pool; + image->module = module; + + /* actually call create or open */ + if (read_or_write == OSD_FOPEN_RW_CREATE) + err = module->create(image, f, createopts); + else + err = module->open(image, f); + if (err) + { + err = markerrorsource(err); + goto done; + } + +done: + if (err) + { + if (f) + stream_close(f); + if (pool) + pool_free_lib(pool); + image = NULL; + } + + if (outimg) + *outimg = image; + else if (image) + imgtool_image_close(image); + return err; +} + + + +/*------------------------------------------------- + imgtool_image_open - open an image +-------------------------------------------------*/ + +imgtoolerr_t imgtool_image_open(const imgtool_module *module, const char *fname, int read_or_write, imgtool_image **outimg) +{ + read_or_write = read_or_write ? OSD_FOPEN_RW : OSD_FOPEN_READ; + return internal_open(module, fname, read_or_write, NULL, outimg); +} + + + +/*------------------------------------------------- + imgtool_image_open_byname - open an image +-------------------------------------------------*/ + +imgtoolerr_t imgtool_image_open_byname(const char *modulename, const char *fname, int read_or_write, imgtool_image **outimg) +{ + const imgtool_module *module; + + module = imgtool_find_module(modulename); + if (!module) + return (imgtoolerr_t)(IMGTOOLERR_MODULENOTFOUND | IMGTOOLERR_SRC_MODULE); + + return imgtool_image_open(module, fname, read_or_write, outimg); +} + + + +/*------------------------------------------------- + imgtool_image_close - close an image +-------------------------------------------------*/ + +void imgtool_image_close(imgtool_image *image) +{ + if (image->module->close) + image->module->close(image); + pool_free_lib(image->pool); +} + + + +/*------------------------------------------------- + imgtool_image_create - creates an image +-------------------------------------------------*/ + +imgtoolerr_t imgtool_image_create(const imgtool_module *module, const char *fname, + option_resolution *opts, imgtool_image **image) +{ + imgtoolerr_t err; + option_resolution *alloc_resolution = NULL; + + /* allocate dummy options if necessary */ + if (!opts && module->createimage_optguide) + { + alloc_resolution = option_resolution_create(module->createimage_optguide, module->createimage_optspec); + if (!alloc_resolution) + { + err = (imgtoolerr_t)IMGTOOLERR_OUTOFMEMORY; + goto done; + } + opts = alloc_resolution; + } + if (opts) + option_resolution_finish(opts); + + err = internal_open(module, fname, OSD_FOPEN_RW_CREATE, opts, image); + if (err) + goto done; + +done: + if (alloc_resolution) + option_resolution_close(alloc_resolution); + return err; +} + + + +/*------------------------------------------------- + imgtool_image_create_byname - creates an image +-------------------------------------------------*/ + +imgtoolerr_t imgtool_image_create_byname(const char *modulename, const char *fname, + option_resolution *opts, imgtool_image **image) +{ + const imgtool_module *module; + + module = imgtool_find_module(modulename); + if (!module) + return (imgtoolerr_t)(IMGTOOLERR_MODULENOTFOUND | IMGTOOLERR_SRC_MODULE); + + return imgtool_image_create(module, fname, opts, image); +} + + + +/*------------------------------------------------- + imgtool_image_info - returns format specific information + about an image +-------------------------------------------------*/ + +imgtoolerr_t imgtool_image_info(imgtool_image *image, char *string, size_t len) +{ + if (len > 0) + { + string[0] = '\0'; + if (image->module->info) + image->module->info(image, string, len); + } + return IMGTOOLERR_SUCCESS; +} + + + +#define PATH_MUSTBEDIR 0x00000001 +#define PATH_LEAVENULLALONE 0x00000002 +#define PATH_CANBEBOOTBLOCK 0x00000004 + +/*------------------------------------------------- + cannonicalize_path - normalizes a path string + into a NUL delimited list +-------------------------------------------------*/ + +static imgtoolerr_t cannonicalize_path(imgtool_partition *partition, UINT32 flags, + const char **path, char **alloc_path) +{ + imgtoolerr_t err = (imgtoolerr_t)IMGTOOLERR_SUCCESS; + char *new_path = NULL; + char path_separator, alt_path_separator; + const char *s; + int in_path_separator, i, j; + + path_separator = partition->path_separator; + alt_path_separator = partition->alternate_path_separator; + + /* is this path NULL? if so, is that ignored? */ + if (!*path && (flags & PATH_LEAVENULLALONE)) + goto done; + + /* is this the special filename for bootblocks? */ + if (*path == FILENAME_BOOTBLOCK) + { + if (!(flags & PATH_CANBEBOOTBLOCK)) + err = (imgtoolerr_t)IMGTOOLERR_UNEXPECTED; + else if (!partition->supports_bootblock) + err = (imgtoolerr_t)IMGTOOLERR_FILENOTFOUND; + goto done; + } + + if (path_separator == '\0') + { + if (flags & PATH_MUSTBEDIR) + { + /* do we specify a path when paths are not supported? */ + if (*path && **path) + { + err = (imgtoolerr_t)(IMGTOOLERR_CANNOTUSEPATH | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + *path = NULL; /* normalize empty path */ + } + } + else + { + s = *path ? *path : ""; + + /* allocate space for a new cannonical path */ + new_path = (char*)malloc(strlen(s) + 4); + if (!new_path) + { + err = (imgtoolerr_t)IMGTOOLERR_OUTOFMEMORY; + goto done; + } + + /* copy the path */ + in_path_separator = TRUE; + i = j = 0; + do + { + if ((s[i] != '\0') && (s[i] != path_separator) && (s[i] != alt_path_separator)) + { + new_path[j++] = s[i]; + in_path_separator = FALSE; + } + else if (!in_path_separator) + { + new_path[j++] = '\0'; + in_path_separator = TRUE; + } + } + while(s[i++] != '\0'); + new_path[j++] = '\0'; + new_path[j++] = '\0'; + *path = new_path; + } + +done: + *alloc_path = new_path; + return err; +} + + + +static imgtoolerr_t cannonicalize_fork(imgtool_partition *partition, const char **fork) +{ + /* does this module support forks? */ + if (partition->list_forks) + { + /* this module supports forks; make sure that fork is non-NULL */ + if (!*fork) + *fork = ""; + } + else + { + /* this module does not support forks; make sure that fork is NULL */ + if (*fork) + return IMGTOOLERR_NOFORKS; + } + return IMGTOOLERR_SUCCESS; +} + + + +/*------------------------------------------------- + imgtool_partition_get_directory_entry - retrieves + the nth directory entry within a partition +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_get_directory_entry(imgtool_partition *partition, const char *path, int index, imgtool_dirent *ent) +{ + imgtoolerr_t err; + imgtool_directory *imgenum = NULL; + + if (index < 0) + { + err = (imgtoolerr_t)IMGTOOLERR_PARAMTOOSMALL; + goto done; + } + + err = imgtool_directory_open(partition, path, &imgenum); + if (err) + goto done; + + do + { + err = imgtool_directory_get_next(imgenum, ent); + if (err) + goto done; + + if (ent->eof) + { + err = (imgtoolerr_t)IMGTOOLERR_FILENOTFOUND; + goto done; + } + } + while(index--); + +done: + if (err) + memset(ent->filename, 0, sizeof(ent->filename)); + if (imgenum) + imgtool_directory_close(imgenum); + return err; +} + + + +/*------------------------------------------------- + imgtool_partition_get_file_size - returns free + space on a partition, in bytes +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_get_file_size(imgtool_partition *partition, const char *fname, UINT64 *filesize) +{ + imgtoolerr_t err; + imgtool_directory *imgenum; + imgtool_dirent ent; + const char *path; + + path = NULL; /* TODO: Need to parse off the path */ + + *filesize = -1; + memset(&ent, 0, sizeof(ent)); + + err = imgtool_directory_open(partition, path, &imgenum); + if (err) + goto done; + + do + { + err = imgtool_directory_get_next(imgenum, &ent); + if (err) + goto done; + + if (!core_stricmp(fname, ent.filename)) + { + *filesize = ent.filesize; + goto done; + } + } + while(ent.filename[0]); + + err = (imgtoolerr_t)IMGTOOLERR_FILENOTFOUND; + +done: + if (imgenum) + imgtool_directory_close(imgenum); + return err; +} + + + +/*------------------------------------------------- + imgtool_partition_list_file_attributes - identifies + all attributes on a file +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_list_file_attributes(imgtool_partition *partition, const char *path, UINT32 *attrs, size_t len) +{ + imgtoolerr_t err; + char *alloc_path = NULL; + char *new_fname = NULL; + + memset(attrs, 0, sizeof(*attrs) * len); + + if (!partition->list_attrs) + { + err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + new_fname = normalize_filename(partition, path); + if (new_fname == NULL) + { + err = (imgtoolerr_t)(IMGTOOLERR_BADFILENAME | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + path = new_fname; + + /* cannonicalize path */ + err = cannonicalize_path(partition, PATH_LEAVENULLALONE, &path, &alloc_path); + if (err) + goto done; + + err = partition->list_attrs(partition, path, attrs, len); + if (err) + goto done; + +done: + if (alloc_path != NULL) + free(alloc_path); + if (new_fname != NULL) + osd_free(new_fname); + return err; +} + + + +/*------------------------------------------------- + imgtool_partition_get_file_attributes - retrieves + attributes on a file +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_get_file_attributes(imgtool_partition *partition, const char *path, const UINT32 *attrs, imgtool_attribute *values) +{ + imgtoolerr_t err; + char *alloc_path = NULL; + char *new_fname = NULL; + + if (!partition->get_attrs) + { + err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + new_fname = normalize_filename(partition, path); + if (new_fname == NULL) + { + err = (imgtoolerr_t)(IMGTOOLERR_BADFILENAME | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + path = new_fname; + + /* cannonicalize path */ + err = cannonicalize_path(partition, PATH_LEAVENULLALONE, &path, &alloc_path); + if (err) + goto done; + + err = partition->get_attrs(partition, path, attrs, values); + if (err) + goto done; + +done: + if (alloc_path != NULL) + free(alloc_path); + if (new_fname != NULL) + osd_free(new_fname); + return err; +} + + + +/*------------------------------------------------- + imgtool_partition_put_file_attributes - sets + attributes on a file +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_put_file_attributes(imgtool_partition *partition, const char *path, const UINT32 *attrs, const imgtool_attribute *values) +{ + imgtoolerr_t err; + char *alloc_path = NULL; + + if (!partition->set_attrs) + { + err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + /* cannonicalize path */ + err = cannonicalize_path(partition, PATH_LEAVENULLALONE, &path, &alloc_path); + if (err) + goto done; + + err = partition->set_attrs(partition, path, attrs, values); + if (err) + goto done; + +done: + if (alloc_path) + free(alloc_path); + return err; +} + + + +/*------------------------------------------------- + imgtool_partition_get_file_attributes - retrieves + an attribute on a single file +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_get_file_attribute(imgtool_partition *partition, const char *path, UINT32 attr, imgtool_attribute *value) +{ + UINT32 attrs[2]; + attrs[0] = attr; + attrs[1] = 0; + return imgtool_partition_get_file_attributes(partition, path, attrs, value); +} + + + +/*------------------------------------------------- + imgtool_partition_put_file_attribute - sets + attributes on a single file +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_put_file_attribute(imgtool_partition *partition, const char *path, UINT32 attr, imgtool_attribute value) +{ + UINT32 attrs[2]; + attrs[0] = attr; + attrs[1] = 0; + return imgtool_partition_put_file_attributes(partition, path, attrs, &value); +} + + + +/*------------------------------------------------- + imgtool_partition_get_icon_info - retrieves the + icon for a file stored on a partition +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_get_icon_info(imgtool_partition *partition, const char *path, imgtool_iconinfo *iconinfo) +{ + imgtoolerr_t err; + char *alloc_path = NULL; + char *new_fname = NULL; + + if (!partition->get_iconinfo) + { + err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + new_fname = normalize_filename(partition, path); + if (new_fname == NULL) + { + err = (imgtoolerr_t)(IMGTOOLERR_BADFILENAME | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + path = new_fname; + + /* cannonicalize path */ + err = cannonicalize_path(partition, 0, &path, &alloc_path); + if (err) + goto done; + + memset(iconinfo, 0, sizeof(*iconinfo)); + err = partition->get_iconinfo(partition, path, iconinfo); + if (err) + goto done; + +done: + if (alloc_path) + free(alloc_path); + if (new_fname) + osd_free(new_fname); + return err; +} + + + +/*------------------------------------------------- + imgtool_partition_suggest_file_filters - suggests + a list of filters appropriate for a file on a + partition +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_suggest_file_filters(imgtool_partition *partition, const char *path, + imgtool_stream *stream, imgtool_transfer_suggestion *suggestions, size_t suggestions_length) +{ + imgtoolerr_t err; + int i, j; + char *alloc_path = NULL; + imgtoolerr_t (*check_stream)(imgtool_stream *stream, imgtool_suggestion_viability_t *viability); + size_t position; + + /* clear out buffer */ + memset(suggestions, 0, sizeof(*suggestions) * suggestions_length); + + if (!partition->suggest_transfer) + { + err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + /* cannonicalize path */ + err = cannonicalize_path(partition, PATH_LEAVENULLALONE, &path, &alloc_path); + if (err) + goto done; + + /* invoke the module's suggest call */ + err = partition->suggest_transfer(partition, path, suggestions, suggestions_length); + if (err) + goto done; + + /* Loop on resulting suggestions, and do the following: + * 1. Call check_stream if present, and remove disqualified streams + * 2. Fill in missing descriptions + */ + i = j = 0; + while(suggestions[i].viability) + { + if (stream && suggestions[i].filter) + { + check_stream = (imgtoolerr_t (*)(imgtool_stream *, imgtool_suggestion_viability_t *)) filter_get_info_fct(suggestions[i].filter, FILTINFO_PTR_CHECKSTREAM); + if (check_stream) + { + position = stream_tell(stream); + err = check_stream(stream, &suggestions[i].viability); + stream_seek(stream, position, SEEK_SET); + if (err) + goto done; + } + } + + /* the check_stream proc can remove the option by clearing out the viability */ + if (suggestions[i].viability) + { + /* we may have to move this suggestion, if one was removed */ + if (i != j) + memcpy(&suggestions[j], &suggestions[i], sizeof(*suggestions)); + + /* if the description is missing, fill it in */ + if (!suggestions[j].description) + { + if (suggestions[j].filter) + suggestions[j].description = filter_get_info_string(suggestions[i].filter, FILTINFO_STR_HUMANNAME); + else + suggestions[j].description = "Raw"; + } + + j++; + } + i++; + } + suggestions[j].viability = (imgtool_suggestion_viability_t)0; + +done: + if (alloc_path) + free(alloc_path); + return err; +} + + + +/*------------------------------------------------- + imgtool_partition_get_chain - retrieves the block + chain for a file or directory on a partition +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_get_chain(imgtool_partition *partition, const char *path, imgtool_chainent *chain, size_t chain_size) +{ + size_t i; + + assert(chain_size > 0); + + if (!partition->get_chain) + return (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + + /* initialize the chain array, so the module's get_chain function can be lazy */ + for (i = 0; i < chain_size; i++) + { + chain[i].level = 0; + chain[i].block = ~0; + } + + return partition->get_chain(partition, path, chain, chain_size - 1); +} + + + +/*------------------------------------------------- + imgtool_partition_get_chain_string - retrieves + the block chain for a file or directory on a + partition +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_get_chain_string(imgtool_partition *partition, const char *path, char *buffer, size_t buffer_len) +{ + imgtoolerr_t err; + imgtool_chainent chain[512]; + UINT64 last_block; + UINT8 cur_level = 0; + int len, i; + int comma_needed = FALSE; + + /* determine the last block identifier */ + chain[0].block = ~0; + last_block = chain[0].block; + + err = imgtool_partition_get_chain(partition, path, chain, ARRAY_LENGTH(chain)); + if (err) + return err; + + len = snprintf(buffer, buffer_len, "["); + buffer += len; + buffer_len -= len; + + for (i = 0; chain[i].block != last_block; i++) + { + while(cur_level < chain[i].level) + { + len = snprintf(buffer, buffer_len, " ["); + buffer += len; + buffer_len -= len; + cur_level++; + comma_needed = FALSE; + } + while(cur_level > chain[i].level) + { + len = snprintf(buffer, buffer_len, "]"); + buffer += len; + buffer_len -= len; + cur_level--; + } + + if (comma_needed) + { + len = snprintf(buffer, buffer_len, ", "); + buffer += len; + buffer_len -= len; + } + + len = snprintf(buffer, buffer_len, "%u", (unsigned) chain[i].block); + buffer += len; + buffer_len -= len; + comma_needed = TRUE; + } + + do + { + len = snprintf(buffer, buffer_len, "]"); + buffer += len; + buffer_len -= len; + } + while(cur_level-- > 0); + + return IMGTOOLERR_SUCCESS; +} + + + +/*------------------------------------------------- + imgtool_partition_get_free_space - returns the + amount of free space on a partition +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_get_free_space(imgtool_partition *partition, UINT64 *sz) +{ + imgtoolerr_t err; + UINT64 size; + + if (!partition->free_space) + return (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + + err = partition->free_space(partition, &size); + if (err) + return (imgtoolerr_t)(err | IMGTOOLERR_SRC_IMAGEFILE); + + if (sz) + *sz = size; + return IMGTOOLERR_SUCCESS; +} + + + +/*------------------------------------------------- + imgtool_partition_read_file - starts reading + from a file on a partition with a stream +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_read_file(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *destf, filter_getinfoproc filter) +{ + imgtoolerr_t err; + char *alloc_path = NULL; + union filterinfo u; + + if (!partition->read_file) + { + err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + if (filter) + { + /* use a filter */ + filter(FILTINFO_PTR_READFILE, &u); + if (!u.read_file) + { + err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + err = u.read_file(partition, filename, fork, destf); + if (err) + { + err = markerrorsource(err); + goto done; + } + } + else + { + /* cannonicalize path */ + err = cannonicalize_path(partition, PATH_CANBEBOOTBLOCK, &filename, &alloc_path); + if (err) + goto done; + + err = cannonicalize_fork(partition, &fork); + if (err) + goto done; + + /* invoke the actual module */ + err = partition->read_file(partition, filename, fork, destf); + if (err) + { + err = markerrorsource(err); + goto done; + } + } + +done: + if (alloc_path) + free(alloc_path); + return err; +} + + + +/*------------------------------------------------- + imgtool_partition_write_file - starts writing + to a new file on an image with a stream +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_write_file(imgtool_partition *partition, const char *filename, const char *fork, imgtool_stream *sourcef, option_resolution *opts, filter_getinfoproc filter) +{ + imgtoolerr_t err; + char *buf = NULL; + char *s; + option_resolution *alloc_resolution = NULL; + char *alloc_path = NULL; + UINT64 free_space; + UINT64 file_size; + union filterinfo u; + + if (!partition->write_file) + { + err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + if (filter) + { + /* use a filter */ + filter(FILTINFO_PTR_WRITEFILE, &u); + if (!u.write_file) + { + err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + err = u.write_file(partition, filename, fork, sourcef, opts); + if (err) + { + err = markerrorsource(err); + goto done; + } + } + else + { + /* does this partition prefer upper case file names? */ + if (partition->prefer_ucase) + { + buf = (char*)malloc(strlen(filename) + 1); + if (!buf) + { + err = (imgtoolerr_t)(IMGTOOLERR_OUTOFMEMORY); + goto done; + } + strcpy(buf, filename); + for (s = buf; *s; s++) + *s = toupper(*s); + filename = buf; + } + + /* cannonicalize path */ + err = cannonicalize_path(partition, PATH_CANBEBOOTBLOCK, &filename, &alloc_path); + if (err) + goto done; + + err = cannonicalize_fork(partition, &fork); + if (err) + goto done; + + /* allocate dummy options if necessary */ + if (!opts && partition->writefile_optguide) + { + alloc_resolution = option_resolution_create(partition->writefile_optguide, partition->writefile_optspec); + if (!alloc_resolution) + { + err = IMGTOOLERR_OUTOFMEMORY; + goto done; + } + opts = alloc_resolution; + } + if (opts) + option_resolution_finish(opts); + + /* if free_space is implemented; do a quick check to see if space is available */ + if (partition->free_space) + { + err = partition->free_space(partition, &free_space); + if (err) + { + err = markerrorsource(err); + goto done; + } + + file_size = stream_size(sourcef); + + if (file_size > free_space) + { + err = markerrorsource(IMGTOOLERR_NOSPACE); + goto done; + } + } + + /* actually invoke the write file handler */ + err = partition->write_file(partition, filename, fork, sourcef, opts); + if (err) + { + err = markerrorsource(err); + goto done; + } + } + +done: + if (buf) + free(buf); + if (alloc_path) + free(alloc_path); + if (alloc_resolution) + option_resolution_close(alloc_resolution); + return err; +} + + + +/*------------------------------------------------- + imgtool_partition_get_file - read a file from + an image, storing it into a native file +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_get_file(imgtool_partition *partition, const char *filename, const char *fork, + const char *dest, filter_getinfoproc filter) +{ + imgtoolerr_t err; + imgtool_stream *f; + char *new_fname = NULL; + char *alloc_dest = NULL; + const char *filter_extension = NULL; + + if (!dest) + { + /* determine the filter extension, if appropriate */ + if (filter != NULL) + filter_extension = filter_get_info_string(filter, FILTINFO_STR_EXTENSION); + + if (filter_extension != NULL) + { + alloc_dest = (char*)malloc(strlen(filename) + 1 + strlen(filter_extension) + 1); + if (!alloc_dest) + return IMGTOOLERR_OUTOFMEMORY; + + sprintf(alloc_dest, "%s.%s", filename, filter_extension); + dest = alloc_dest; + } + else + { + if (filename == FILENAME_BOOTBLOCK) + dest = "boot.bin"; + else + dest = filename; + } + } + + f = stream_open(dest, OSD_FOPEN_WRITE); + if (!f) + { + err = (imgtoolerr_t)(IMGTOOLERR_FILENOTFOUND | IMGTOOLERR_SRC_NATIVEFILE); + goto done; + } + + new_fname = normalize_filename(partition, filename); + if (new_fname == NULL) + { + err = (imgtoolerr_t)(IMGTOOLERR_BADFILENAME | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + err = imgtool_partition_read_file(partition, new_fname, fork, f, filter); + if (err) + goto done; + +done: + if (f != NULL) + stream_close(f); + if (alloc_dest != NULL) + free(alloc_dest); + if (new_fname != NULL) + osd_free(new_fname); + return err; +} + + + +/*------------------------------------------------- + imgtool_partition_put_file - read a native file + and store it on a partition +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_put_file(imgtool_partition *partition, const char *newfname, const char *fork, + const char *source, option_resolution *opts, filter_getinfoproc filter) +{ + imgtoolerr_t err; + imgtool_stream *f = NULL; + imgtool_charset charset; + char *alloc_newfname = NULL; + + if (!newfname) + newfname = (const char *) imgtool_basename((char *) source); + + charset = (imgtool_charset) (int) imgtool_partition_get_info_int(partition, IMGTOOLINFO_INT_CHARSET); + if (charset != IMGTOOL_CHARSET_UTF8) + { + /* convert to native format */ + alloc_newfname = native_from_utf8(charset, newfname); + if (alloc_newfname == NULL) + { + err = (imgtoolerr_t)(IMGTOOLERR_BADFILENAME | IMGTOOLERR_SRC_NATIVEFILE); + goto done; + } + + newfname = alloc_newfname; + } + + f = stream_open(source, OSD_FOPEN_READ); + if (f) + err = imgtool_partition_write_file(partition, newfname, fork, f, opts, filter); + else + err = (imgtoolerr_t)(IMGTOOLERR_FILENOTFOUND | IMGTOOLERR_SRC_NATIVEFILE); + +done: + /* clean up */ + if (f != NULL) + stream_close(f); + if (alloc_newfname != NULL) + osd_free(alloc_newfname); + return err; +} + + + +/*------------------------------------------------- + imgtool_partition_delete_file - delete a file + on a partition +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_delete_file(imgtool_partition *partition, const char *fname) +{ + imgtoolerr_t err; + char *alloc_path = NULL; + char *new_fname = NULL; + + if (!partition->delete_file) + { + err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + new_fname = normalize_filename(partition, fname); + if (new_fname == NULL) + { + err = (imgtoolerr_t)(IMGTOOLERR_BADFILENAME | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + fname = new_fname; + + /* cannonicalize path */ + err = cannonicalize_path(partition, 0, &fname, &alloc_path); + if (err) + goto done; + + err = partition->delete_file(partition, fname); + if (err) + { + err = markerrorsource(err); + goto done; + } + +done: + if (alloc_path) + free(alloc_path); + if (new_fname) + osd_free(new_fname); + return err; +} + + + +/*------------------------------------------------- + imgtool_partition_list_file_forks - lists all + forks on an image +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_list_file_forks(imgtool_partition *partition, const char *path, imgtool_forkent *ents, size_t len) +{ + imgtoolerr_t err; + char *alloc_path = NULL; + char *new_fname = NULL; + + if (!partition->list_forks) + { + err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + new_fname = normalize_filename(partition, path); + if (new_fname == NULL) + { + err = (imgtoolerr_t)(IMGTOOLERR_BADFILENAME | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + path = new_fname; + + /* cannonicalize path */ + err = cannonicalize_path(partition, 0, &path, &alloc_path); + if (err) + goto done; + + err = partition->list_forks(partition, path, ents, len); + if (err) + goto done; + +done: + if (alloc_path) + free(alloc_path); + if (new_fname) + osd_free(new_fname); + return err; +} + + + +/*------------------------------------------------- + imgtool_partition_create_directory - creates a + directory on a partition +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_create_directory(imgtool_partition *partition, const char *path) +{ + imgtoolerr_t err; + char *alloc_path = NULL; + char *new_path = NULL; + + /* implemented? */ + if (!partition->create_dir) + { + err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + new_path = normalize_filename(partition, path); + if (new_path == NULL) + { + err = (imgtoolerr_t)(IMGTOOLERR_BADFILENAME | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + path = new_path; + + /* cannonicalize path */ + err = cannonicalize_path(partition, PATH_MUSTBEDIR, &path, &alloc_path); + if (err) + goto done; + + err = partition->create_dir(partition, path); + if (err) + goto done; + +done: + if (alloc_path) + free(alloc_path); + if (new_path) + osd_free(new_path); + return err; +} + + + +/*------------------------------------------------- + imgtool_partition_delete_directory - deletes a + directory on a partition +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_delete_directory(imgtool_partition *partition, const char *path) +{ + imgtoolerr_t err; + char *alloc_path = NULL; + char *new_path = NULL; + + /* implemented? */ + if (!partition->delete_dir) + { + err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + new_path = normalize_filename(partition, path); + if (new_path == NULL) + { + err = (imgtoolerr_t)(IMGTOOLERR_BADFILENAME | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + path = new_path; + + /* cannonicalize path */ + err = cannonicalize_path(partition, PATH_MUSTBEDIR, &path, &alloc_path); + if (err) + goto done; + + err = partition->delete_dir(partition, path); + if (err) + goto done; + +done: + if (alloc_path) + free(alloc_path); + if (new_path) + osd_free(new_path); + return err; +} + + + +/*------------------------------------------------- + imgtool_partition_get_block_size - gets the + size of a standard block on a partition +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_get_block_size(imgtool_partition *partition, UINT32 *length) +{ + return imgtool_image_get_block_size(partition->image, length); +} + + + +/*------------------------------------------------- + imgtool_partition_read_block - reads a standard + block on a partition +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_read_block(imgtool_partition *partition, UINT64 block, void *buffer) +{ + if (block >= partition->block_count) + return IMGTOOLERR_SEEKERROR; + return imgtool_image_read_block(partition->image, block + partition->base_block, buffer); +} + + + +/*------------------------------------------------- + imgtool_partition_write_block - writes a + standard block on a partition +-------------------------------------------------*/ + +imgtoolerr_t imgtool_partition_write_block(imgtool_partition *partition, UINT64 block, const void *buffer) +{ + if (block >= partition->block_count) + return IMGTOOLERR_SEEKERROR; + return imgtool_image_write_block(partition->image, block + partition->base_block, buffer); +} + + + +/*------------------------------------------------- + imgtool_partition_get_features - retrieves a + structure identifying this partition's features + associated with an image +-------------------------------------------------*/ + +imgtool_partition_features imgtool_partition_get_features(imgtool_partition *partition) +{ + imgtool_partition_features features; + memset(&features, 0, sizeof(features)); + + if (partition->read_file) + features.supports_reading = 1; + if (partition->write_file) + features.supports_writing = 1; + if (partition->delete_file) + features.supports_deletefile = 1; + if (partition->path_separator) + features.supports_directories = 1; + if (partition->free_space) + features.supports_freespace = 1; + if (partition->create_dir) + features.supports_createdir = 1; + if (partition->delete_dir) + features.supports_deletedir = 1; + if (partition->supports_creation_time) + features.supports_creation_time = 1; + if (partition->supports_lastmodified_time) + features.supports_lastmodified_time = 1; + if (!features.supports_writing && !features.supports_createdir && !features.supports_deletefile && !features.supports_deletedir) + features.is_read_only = 1; + return features; +} + + + +/*------------------------------------------------- + imgtool_partition_get_info_ptr - retrieves a + pointer associated with a partition's format +-------------------------------------------------*/ + +void *imgtool_partition_get_info_ptr(imgtool_partition *partition, UINT32 state) +{ + return imgtool_get_info_ptr(&partition->imgclass, state); +} + + + +/*------------------------------------------------- + imgtool_partition_get_info_string - retrieves a + string associated with a partition's format +-------------------------------------------------*/ + +const char *imgtool_partition_get_info_string(imgtool_partition *partition, UINT32 state) +{ + return imgtool_get_info_string(&partition->imgclass, state); +} + + + +/*------------------------------------------------- + imgtool_partition_get_info_int - retrieves a + pointer associated with a partition's format +-------------------------------------------------*/ + +UINT64 imgtool_partition_get_info_int(imgtool_partition *partition, UINT32 state) +{ + return imgtool_get_info_int(&partition->imgclass, state); +} + + + +/*------------------------------------------------- + imgtool_partition_extra_bytes - returns extra + bytes on a partition +-------------------------------------------------*/ + +void *imgtool_partition_extra_bytes(imgtool_partition *partition) +{ + void *ptr = NULL; + if (partition->partition_extra_bytes > 0) + ptr = ((UINT8 *) partition) + sizeof(*partition); + assert(ptr); + return ptr; +} + + + +/*------------------------------------------------- + imgtool_partition_rand - returns random number +-------------------------------------------------*/ + +UINT64 imgtool_partition_rand(imgtool_partition *partition) +{ + return imgtool_image_rand(partition->image); +} + + + +/*************************************************************************** + + Path handling functions + +***************************************************************************/ + +/*------------------------------------------------- + imgtool_partition_get_root_path - retrieves + the path root of this partition +-------------------------------------------------*/ + +const char *imgtool_partition_get_root_path(imgtool_partition *partition) +{ + int initial_path_separator; + char path_separator; + char *buf; + int pos = 0; + + initial_path_separator = imgtool_partition_get_info_int(partition, IMGTOOLINFO_INT_INITIAL_PATH_SEPARATOR) ? 1 : 0; + path_separator = (char) imgtool_partition_get_info_int(partition, IMGTOOLINFO_INT_PATH_SEPARATOR); + buf = imgtool_temp_str(); + + if (initial_path_separator) + buf[pos++] = path_separator; + buf[pos] = '\0'; + return buf; +} + + + +/*------------------------------------------------- + imgtool_partition_path_concatenate - retrieves + a pointer associated with a partition's format +-------------------------------------------------*/ + +const char *imgtool_partition_path_concatenate(imgtool_partition *partition, const char *path1, const char *path2) +{ + char path_separator; + size_t len; + char *buffer; + size_t buffer_len; + + path_separator = (char) imgtool_partition_get_info_int(partition, IMGTOOLINFO_INT_PATH_SEPARATOR); + len = strlen(path1); + + /* prepare buffer */ + buffer = imgtool_temp_str(); + buffer_len = 256; + + if (!strcmp(path2, ".")) + { + /* keep the same directory */ + snprintf(buffer, buffer_len, "%s", path1); + } + else if (!strcmp(path2, "..")) + { + /* up one directory */ + while((len > 0) && (path1[len - 1] == path_separator)) + len--; + while((len > 0) && (path1[len - 1] != path_separator)) + len--; + while((len > 1) && (path1[len - 1] == path_separator)) + len--; + snprintf(buffer, buffer_len, "%s", path1); + buffer[len] = '\0'; + } + else + { + /* append a path */ + if ((*path1 != 0) && (path1[strlen(path1) - 1] != path_separator)) + snprintf(buffer, buffer_len, "%s%c%s", path1, path_separator, path2); + else + snprintf(buffer, buffer_len, "%s%s", path1, path2); + } + return buffer; +} + + + +/*------------------------------------------------- + imgtool_partition_get_base_name - retrieves + a base name for a partition specific path +-------------------------------------------------*/ + +const char *imgtool_partition_get_base_name(imgtool_partition *partition, const char *path) +{ + char path_separator; + const char *new_path = path; + int i; + + path_separator = (char) imgtool_partition_get_info_int(partition, IMGTOOLINFO_INT_PATH_SEPARATOR); + + for (i = 0; path[i]; i++) + { + if (path[i] == path_separator) + new_path = &path[i + 1]; + } + return new_path; +} + + + +/*************************************************************************** + + Directory handling functions + +***************************************************************************/ + +/*------------------------------------------------- + imgtool_directory_open - begins + enumerating files on a partition +-------------------------------------------------*/ + +imgtoolerr_t imgtool_directory_open(imgtool_partition *partition, const char *path, imgtool_directory **outenum) +{ + imgtoolerr_t err = (imgtoolerr_t)IMGTOOLERR_SUCCESS; + imgtool_directory *enumeration = NULL; + char *alloc_path = NULL; + char *new_path = NULL; + size_t size; + + /* sanity checks */ + assert(partition); + assert(outenum); + + *outenum = NULL; + + if (!partition->next_enum) + { + err = (imgtoolerr_t)(IMGTOOLERR_UNIMPLEMENTED | IMGTOOLERR_SRC_FUNCTIONALITY); + goto done; + } + + new_path = normalize_filename(partition, path); + path = new_path; + + err = cannonicalize_path(partition, PATH_MUSTBEDIR, &path, &alloc_path); + if (err) + goto done; + + size = sizeof(struct _imgtool_directory) + partition->directory_extra_bytes; + enumeration = (imgtool_directory *) malloc(size); + if (!enumeration) + { + err = (imgtoolerr_t)IMGTOOLERR_OUTOFMEMORY; + goto done; + } + memset(enumeration, '\0', size); + enumeration->partition = partition; + + if (partition->begin_enum) + { + err = partition->begin_enum(enumeration, path); + if (err) + { + err = markerrorsource(err); + goto done; + } + } + +done: + if (alloc_path != NULL) + free(alloc_path); + if (new_path != NULL) + osd_free(new_path); + if (err && (enumeration != NULL)) + { + free(enumeration); + enumeration = NULL; + } + *outenum = enumeration; + return err; +} + + + +/*------------------------------------------------- + imgtool_directory_close - closes a directory +-------------------------------------------------*/ + +void imgtool_directory_close(imgtool_directory *directory) +{ + imgtool_partition *partition; + partition = imgtool_directory_partition(directory); + if (partition->close_enum) + partition->close_enum(directory); + free(directory); +} + + + +/*------------------------------------------------- + imgtool_directory_get_next - continues + enumerating files within a partition +-------------------------------------------------*/ + +imgtoolerr_t imgtool_directory_get_next(imgtool_directory *directory, imgtool_dirent *ent) +{ + imgtoolerr_t err; + imgtool_partition *partition; + int charset; + + partition = imgtool_directory_partition(directory); + + /* This makes it so that drivers don't have to take care of clearing + * the attributes if they don't apply + */ + memset(ent, 0, sizeof(*ent)); + + err = partition->next_enum(directory, ent); + if (err) + return markerrorsource(err); + + charset = imgtool_partition_get_info_int(partition, IMGTOOLINFO_INT_CHARSET); + + if (charset) + { + char *new_fname = utf8_from_native((imgtool_charset)charset, ent->filename); + + if (!new_fname) + return IMGTOOLERR_BADFILENAME; + + strcpy(ent->filename, new_fname); + osd_free(new_fname); + } + + /* don't trust the module! */ + if (!partition->supports_creation_time && (ent->creation_time != 0)) + { + internal_error(NULL, "next_enum() specified creation_time, which is marked as unsupported by this module"); + return IMGTOOLERR_UNEXPECTED; + } + if (!partition->supports_lastmodified_time && (ent->lastmodified_time != 0)) + { + internal_error(NULL, "next_enum() specified lastmodified_time, which is marked as unsupported by this module"); + return IMGTOOLERR_UNEXPECTED; + } + if (!partition->path_separator && ent->directory) + { + internal_error(NULL, "next_enum() returned a directory, which is marked as unsupported by this module"); + return IMGTOOLERR_UNEXPECTED; + } + return IMGTOOLERR_SUCCESS; +} + + + +/*------------------------------------------------- + imgtool_directory_module - returns the module associated + with this directory +-------------------------------------------------*/ + +const imgtool_module *imgtool_directory_module(imgtool_directory *directory) +{ + return directory->partition->image->module; +} + + + +/*------------------------------------------------- + imgtool_directory_extrabytes - returns extra + bytes on a directory +-------------------------------------------------*/ + +void *imgtool_directory_extrabytes(imgtool_directory *directory) +{ + assert(directory->partition->directory_extra_bytes > 0); + return ((UINT8 *) directory) + sizeof(*directory); +} + + + +/*------------------------------------------------- + imgtool_directory_partition - returns the + partition associated with this directory +-------------------------------------------------*/ + +imgtool_partition *imgtool_directory_partition(imgtool_directory *directory) +{ + return directory->partition; +} + + + +/*------------------------------------------------- + imgtool_directory_image - returns the image + associated with this directory +-------------------------------------------------*/ + +imgtool_image *imgtool_directory_image(imgtool_directory *directory) +{ + return directory->partition->image; +} + + + +/*------------------------------------------------- + unknown_partition_get_info - represents an + unknown partition +-------------------------------------------------*/ + +void unknown_partition_get_info(const imgtool_class *imgclass, UINT32 state, union imgtoolinfo *info) +{ + switch(state) + { + /* --- the following bits of info are returned as NULL-terminated strings --- */ + case IMGTOOLINFO_STR_NAME: strcpy(info->s = imgtool_temp_str(), "unknown"); break; + case IMGTOOLINFO_STR_DESCRIPTION: strcpy(info->s = imgtool_temp_str(), "Unknown partition type"); break; + } +} |