From d6323e7bd7f817c13ce992ef118cbcf4127ad076 Mon Sep 17 00:00:00 2001 From: Pixel Date: Tue, 4 Aug 2009 11:03:27 -0700 Subject: Adding stubs for MPQ writes. --- mpq-bios.c | 116 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 104 insertions(+), 12 deletions(-) (limited to 'mpq-bios.c') diff --git a/mpq-bios.c b/mpq-bios.c index 7ed56f8..cf9f581 100644 --- a/mpq-bios.c +++ b/mpq-bios.c @@ -29,6 +29,10 @@ #include "int-bios.h" #include "errors.h" +#ifndef MAX +#define MAX(x,y) (((x)<(y))?(y):(x)) +#endif + /* * MPQ header. */ @@ -112,6 +116,9 @@ typedef struct { struct mpq_archive_t { int fd; int closeit; + int for_write; + + uint64_t last_block; uint32_t header_size; uint32_t archive_size; @@ -149,6 +156,27 @@ struct mpq_archive_t * mpqlib_open_archive(const char * fname) { r = mpqlib_reopen_archive(fd); if (r) { r->closeit = 1; + r->for_write = 0; + } else { + close(fd); + } + + return r; +} + +struct mpq_archive_t * mpqlib_open_archive_for_writing(const char * fname) { + int fd; + struct mpq_archive_t * r; + + if ((fd = open(fname, O_RDWR | O_LARGEFILE | O_BINARY)) == -1) { + __mpqlib_errno = MPQLIB_ERROR_OPEN; + return NULL; + } + + r = mpqlib_reopen_archive(fd); + if (r) { + r->closeit = 1; + r->for_write = 1; } else { close(fd); } @@ -205,6 +233,10 @@ struct mpq_archive_t * mpqlib_reopen_archive(int fd) { mpq_block_t * mpq_blocks; uint16_t * mpq_extblocks = NULL; int i; + uint64_t last_block = 0; +#ifndef WIN32 + int flags; +#endif __mpqlib_errno = MPQLIB_ERROR_NO_ERROR; @@ -218,6 +250,13 @@ struct mpq_archive_t * mpqlib_reopen_archive(int fd) { mpq_a->closeit = 0; mpq_a->fd = fd; + mpq_a->for_write = 0; +#ifndef WIN32 + flags = fcntl(fd, F_GETFL); + if ((flags != -1) && (flags & O_RDWR)) { + mpq_a->for_write = 1; + } +#endif /* Reading the main header, and doing basic checks. */ if (read(fd, &mpq_h, STD_HEADER_SIZE) != STD_HEADER_SIZE) @@ -330,8 +369,11 @@ struct mpq_archive_t * mpqlib_reopen_archive(int fd) { mpq_a->blocks[i].block_size = mpq_blocks[i].block_size; mpq_a->blocks[i].file_size = mpq_blocks[i].file_size; mpq_a->blocks[i].flags = mpq_blocks[i].flags; + last_block = MAX(last_block, mpq_a->blocks[i].block_offset + mpq_a->blocks[i].block_size); } + mpq_a->last_block = last_block; + /* All done, let's clean up and exit. */ if (mpq_extblocks) free(mpq_extblocks); @@ -377,18 +419,31 @@ void mpqlib_printtables(struct mpq_archive_t * mpq_a) { } } -int mpqlib_find_hash_entry_by_name(struct mpq_archive_t * mpq_a, const char * name, uint32_t language, uint32_t platform) { - uint32_t h, hA, hB; - - h = mpqlib_hash_filename(name); - hA = mpqlib_hashA_filename(name); - hB = mpqlib_hashB_filename(name); +static hash_t * mpqlib_locate_hash_entry(struct mpq_archive_t * mpq_a, uint32_t h, uint32_t hA, uint32_t hB, uint32_t language, uint32_t platform) { + uint32_t i; + + /* The hash table is a true one, pre-built. We can access it as-it, speeding up the searches drastically. */ + for (i = h & (mpq_a->hash_table_entries - 1); i < mpq_a->hash_table_entries; i++) { + if ((mpq_a->hashs[i].file_path_hasha == hA) && + (mpq_a->hashs[i].file_path_hashb == hB) && + (mpq_a->hashs[i].language == language) && + (mpq_a->hashs[i].platform == platform)) { + return mpq_a->hashs + i; + } + if (mpq_a->hashs[i].file_block_index == 0xffffffff) + return NULL; + } - return mpqlib_find_hash_entry_by_hash(mpq_a, h, hA, hB, language, platform); + return NULL; } - -int mpqlib_find_hash_entry_by_hash(struct mpq_archive_t * mpq_a, uint32_t h, uint32_t hA, uint32_t hB, uint32_t language, uint32_t platform) { - int i; + +static hash_t * mpqlib_find_free_hash_entry_by_hash(struct mpq_archive_t * mpq_a, uint32_t h, uint32_t hA, uint32_t hB, uint32_t language, uint32_t platform) { + uint32_t i; + + if (!mpq_a->for_write) { + __mpqlib_errno = MPQLIB_ERROR_READONLY; + return NULL; + } /* The hash table is a true one, pre-built. We can access it as-it, speeding up the searches drastically. */ for (i = h & (mpq_a->hash_table_entries - 1); i < mpq_a->hash_table_entries; i++) { @@ -396,12 +451,49 @@ int mpqlib_find_hash_entry_by_hash(struct mpq_archive_t * mpq_a, uint32_t h, uin (mpq_a->hashs[i].file_path_hashb == hB) && (mpq_a->hashs[i].language == language) && (mpq_a->hashs[i].platform == platform)) { - return mpq_a->hashs[i].file_block_index; + /* Full collision ?! */ + __mpqlib_errno = MPQLIB_ERROR_UNKNOWN; + return NULL; } if (mpq_a->hashs[i].file_block_index == 0xffffffff) - break; + return mpq_a->hashs + i; } + __mpqlib_errno = MPQLIB_ERROR_TOO_MANY_FILES; + return NULL; +} + +static hash_t * mpqlib_find_free_hash_entry_by_name(struct mpq_archive_t * mpq_a, const char * name, uint32_t language, uint32_t platform) { + if (!mpq_a->for_write) { + __mpqlib_errno = MPQLIB_ERROR_READONLY; + return NULL; + } + + uint32_t h, hA, hB; + + h = mpqlib_hash_filename(name); + hA = mpqlib_hashA_filename(name); + hB = mpqlib_hashB_filename(name); + + return mpqlib_find_free_hash_entry_by_hash(mpq_a, h, hA, hB, language, platform); +} + +int mpqlib_find_hash_entry_by_name(struct mpq_archive_t * mpq_a, const char * name, uint32_t language, uint32_t platform) { + uint32_t h, hA, hB; + + h = mpqlib_hash_filename(name); + hA = mpqlib_hashA_filename(name); + hB = mpqlib_hashB_filename(name); + + return mpqlib_find_hash_entry_by_hash(mpq_a, h, hA, hB, language, platform); +} + +int mpqlib_find_hash_entry_by_hash(struct mpq_archive_t * mpq_a, uint32_t h, uint32_t hA, uint32_t hB, uint32_t language, uint32_t platform) { + hash_t * hash = mpqlib_locate_hash_entry(mpq_a, h, hA, hB, language, platform); + + if (hash) { + return hash->file_block_index; + } return -1; } -- cgit v1.2.3