From f1a3d484c6660f72a1d9b67dc1806604adfb53bb Mon Sep 17 00:00:00 2001 From: Gleb Mazovetskiy Date: Mon, 1 Nov 2021 10:07:25 +0000 Subject: [PATCH] Add `libmpq__archive_dup` This allows the user to duplicate an existing archive information, e.g. for reading from multiple threads. --- libmpq/mpq.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++ libmpq/mpq.h | 1 + 2 files changed, 61 insertions(+) diff --git a/libmpq/mpq.c b/libmpq/mpq.c index ec2ba79..3dbe107 100644 --- a/libmpq/mpq.c +++ b/libmpq/mpq.c @@ -346,6 +346,66 @@ int32_t libmpq__archive_open(mpq_archive_s **mpq_archive, const char *mpq_filena return result; } +/* duplicates an mpq archive. */ +int32_t libmpq__archive_dup(mpq_archive_s *orig_archive, const char *mpq_filename, mpq_archive_s **mpq_archive) { + int32_t result = 0; + + if ((*mpq_archive = calloc(1, sizeof(mpq_archive_s))) == NULL) { + + /* archive struct could not be allocated */ + return LIBMPQ_ERROR_MALLOC; + } + + /* check if file exists and is readable */ + if (((*mpq_archive)->fp = fopen_utf8(mpq_filename)) == NULL) { + + /* file could not be opened. */ + result = errno == ENOENT ? LIBMPQ_ERROR_EXIST : LIBMPQ_ERROR_OPEN; + goto error; + } + + (*mpq_archive)->block_size = orig_archive->block_size; + (*mpq_archive)->archive_offset = orig_archive->archive_offset; + (*mpq_archive)->mpq_header = orig_archive->mpq_header; + (*mpq_archive)->mpq_header_ex = orig_archive->mpq_header_ex; + (*mpq_archive)->files = orig_archive->files; + + const mpq_header_s *header = &(*mpq_archive)->mpq_header; + + /* allocate memory for the block table, hash table, file and block table to file mapping. */ + if (((*mpq_archive)->mpq_block = malloc(header->block_table_count * sizeof(mpq_block_s))) == NULL || + ((*mpq_archive)->mpq_block_ex = malloc(header->block_table_count * sizeof(mpq_block_ex_s))) == NULL || + ((*mpq_archive)->mpq_hash = malloc(header->hash_table_count * sizeof(mpq_hash_s))) == NULL || + ((*mpq_archive)->mpq_file = calloc(header->block_table_count, sizeof(mpq_file_s))) == NULL || + ((*mpq_archive)->mpq_map = malloc(header->block_table_count * sizeof(mpq_map_s))) == NULL) { + + /* memory allocation problem. */ + result = LIBMPQ_ERROR_MALLOC; + goto error; + } + + memcpy((*mpq_archive)->mpq_block, orig_archive->mpq_block, header->block_table_count * sizeof(mpq_block_s)); + memcpy((*mpq_archive)->mpq_block_ex, orig_archive->mpq_block_ex, header->block_table_count * sizeof(mpq_block_ex_s)); + memcpy((*mpq_archive)->mpq_hash, orig_archive->mpq_hash, header->block_table_count * sizeof(mpq_hash_s)); + memcpy((*mpq_archive)->mpq_map, orig_archive->mpq_map, header->block_table_count * sizeof(mpq_map_s)); + + return LIBMPQ_SUCCESS; +error: + if ((*mpq_archive)->fp) + fclose((*mpq_archive)->fp); + + free((*mpq_archive)->mpq_map); + free((*mpq_archive)->mpq_file); + free((*mpq_archive)->mpq_hash); + free((*mpq_archive)->mpq_block); + free((*mpq_archive)->mpq_block_ex); + free(*mpq_archive); + + *mpq_archive = NULL; + + return result; +} + /* this function close the file descriptor, free the decryption buffer and the file list. */ int32_t libmpq__archive_close(mpq_archive_s *mpq_archive) { diff --git a/libmpq/mpq.h b/libmpq/mpq.h index ce147a8..525afba 100644 --- a/libmpq/mpq.h +++ b/libmpq/mpq.h @@ -71,6 +71,7 @@ extern LIBMPQ_API const char *libmpq__strerror(int32_t return_code); /* generic mpq archive information. */ extern LIBMPQ_API int32_t libmpq__archive_open(mpq_archive_s **mpq_archive, const char *mpq_filename, libmpq__off_t archive_offset); extern LIBMPQ_API int32_t libmpq__archive_close(mpq_archive_s *mpq_archive); +extern LIBMPQ_API int32_t libmpq__archive_dup(mpq_archive_s *orig_archive, const char *mpq_filename, mpq_archive_s **mpq_archive); extern LIBMPQ_API int32_t libmpq__archive_size_packed(mpq_archive_s *mpq_archive, libmpq__off_t *packed_size); extern LIBMPQ_API int32_t libmpq__archive_size_unpacked(mpq_archive_s *mpq_archive, libmpq__off_t *unpacked_size); extern LIBMPQ_API int32_t libmpq__archive_offset(mpq_archive_s *mpq_archive, libmpq__off_t *offset);