From 8feb553794efc2a328f8ce2beed5eeacc43238f4 Mon Sep 17 00:00:00 2001 From: pixel Date: Tue, 10 Jul 2007 09:17:51 +0000 Subject: mpq-file working. --- mpq-bios.c | 16 ++++++----- mpq-errors.c | 4 +++ mpq-errors.h | 4 +++ mpq-file.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++--------- test-it.c | 19 +++++++++++++ 5 files changed, 113 insertions(+), 18 deletions(-) diff --git a/mpq-bios.c b/mpq-bios.c index 4051627..8af3ef6 100644 --- a/mpq-bios.c +++ b/mpq-bios.c @@ -156,6 +156,8 @@ struct mpq_archive_t * mpqlib_reopen_archive(int fd) { uint16_t * mpq_extblocks = NULL; int i; + __mpqlib_errno = MPQLIB_ERROR_NO_ERROR; + /****TODO****/ /* Implement endianess a bit everywhere */ @@ -285,15 +287,15 @@ void mpqlib_printtables(struct mpq_archive_t * mpq_a) { int i; printf("Archive details:\n"); - printf("Header size: %8d\n", mpq_a->header_size); - printf("Archive size: %8d\n", mpq_a->archive_size); - printf("Format version: %8d\n", mpq_a->format_version); - printf("Sector size: %8d\n\n", mpq_a->sector_size); + printf("Header size: %10u\n", mpq_a->header_size); + printf("Archive size: %10u\n", mpq_a->archive_size); + printf("Format version: %10u\n", mpq_a->format_version); + printf("Sector size: %10u\n\n", mpq_a->sector_size); printf("Hash table offset: %016llX\n", mpq_a->hash_table_offset); printf("Block table offset: %016llX\n", mpq_a->block_table_offset); - printf("Hash table entries: %8d\n", mpq_a->hash_table_entries); - printf("Block table entries: %8d\n", mpq_a->block_table_entries); + printf("Hash table entries: %8u\n", mpq_a->hash_table_entries); + printf("Block table entries: %8u\n", mpq_a->block_table_entries); printf("Extended block table offset: %016llX\n\n\n", mpq_a->extended_block_table_offset); @@ -347,6 +349,8 @@ int __mpqlib_read(struct mpq_archive_t * mpq_a, void * buffer, uint32_t size) { } uint64_t mpqlib_ioctl(struct mpq_archive_t * mpq_a, enum mpqlib_ioctl_t command, int entry) { + __mpqlib_errno = MPQLIB_ERROR_NO_ERROR; + switch(command) { case MPQLIB_IOCTL_NO_ACTION: return 0; diff --git a/mpq-errors.c b/mpq-errors.c index 881e2b1..780b305 100644 --- a/mpq-errors.c +++ b/mpq-errors.c @@ -10,6 +10,10 @@ static const char * error_strings[] = { "File read error.", "Invalid ioctl.", "Invalid ioctl's file entry.", + "Entry isn't a file.", + "Imploded compression not supported yet.", + "File isn't flagged as compressed - not supported yet.", + "Compression error.", }; static const char * wrong_errno = "Invalid error number - internal error."; diff --git a/mpq-errors.h b/mpq-errors.h index 047d31d..f452904 100644 --- a/mpq-errors.h +++ b/mpq-errors.h @@ -21,6 +21,10 @@ enum { MPQLIB_ERROR_READ, MPQLIB_ERROR_INVALID_IOCTL, MPQLIB_ERROR_IOCTL_INVALID_ENTRY, + MPQLIB_ERROR_NOT_A_FILE, + MPQLIB_ERROR_NOT_SUPPORTED, + MPQLIB_ERROR_NOT_COMPRESSED, + MPQLIB_ERROR_COMPRESSION, MPQLIB_ERRORS_MAX }; diff --git a/mpq-file.c b/mpq-file.c index 9cc7788..d759109 100644 --- a/mpq-file.c +++ b/mpq-file.c @@ -4,8 +4,11 @@ #include "mpq-file.h" #include "mpq-errors.h" #include "int-bios.h" +#include "extract.h" #include "errors.h" +#define MPQ_BUFSIZ 16384 + struct mpq_file_t { struct mpq_archive_t * mpq_a; int entry; @@ -19,16 +22,38 @@ struct mpq_file_t { char * buffer; uint64_t * offsets; + uint32_t * sizes; }; struct mpq_file_t * mpqlib_open_file(struct mpq_archive_t * mpq_a, int entry) { struct mpq_file_t * r; + uint32_t o; + uint32_t flags; int i; + __mpqlib_errno = MPQLIB_ERROR_NO_ERROR; + if (mpqlib_ioctl(mpq_a, MPQLIB_IOCTL_ENTRY_EXISTS, entry)) { return NULL; } + flags = mpqlib_ioctl(mpq_a, MPQLIB_IOCTL_GET_FLAGS, entry); + + if (!(flags & MPQ_FLAGS_ISFILE)) { + __mpqlib_errno = MPQLIB_ERROR_NOT_A_FILE; + return NULL; + } + + if (flags & MPQ_FLAGS_IMPLODED) { + __mpqlib_errno = MPQLIB_ERROR_NOT_SUPPORTED; + return NULL; + } + + if (!(flags & MPQ_FLAGS_COMPRESSED)) { + __mpqlib_errno = MPQLIB_ERROR_NOT_COMPRESSED; + return NULL; + } + if (!(r = (struct mpq_file_t *) malloc(sizeof(struct mpq_file_t)))) { __mpqlib_errno = MPQLIB_ERROR_MEMORY; return NULL; @@ -43,16 +68,27 @@ struct mpq_file_t * mpqlib_open_file(struct mpq_archive_t * mpq_a, int entry) { } r->entry = entry; + r->mpq_a = mpq_a; r->file_size = mpqlib_ioctl(mpq_a, MPQLIB_IOCTL_GET_FILE_SIZE, entry); r->offset = mpqlib_ioctl(mpq_a, MPQLIB_IOCTL_GET_BLOCK_OFFSET, entry); r->number_of_sectors = r->file_size / r->sector_size; if ((r->remaining_bytes = (r->file_size % r->sector_size))) { r->number_of_sectors++; + } else { + r->remaining_bytes = r->sector_size; } r->current_sector = -1; r->cursor = 0; - if (!(r->offsets = (uint64_t *) malloc(r->number_of_sectors * sizeof(uint64_t)))) { + if (!(r->offsets = (uint64_t *) malloc((r->number_of_sectors + 1) * sizeof(uint64_t)))) { + free(r->buffer); + free(r); + __mpqlib_errno = MPQLIB_ERROR_MEMORY; + return NULL; + } + + if (!(r->sizes = (uint32_t *) malloc(r->number_of_sectors * sizeof(uint32_t)))) { + free(r->offsets); free(r->buffer); free(r); __mpqlib_errno = MPQLIB_ERROR_MEMORY; @@ -60,12 +96,15 @@ struct mpq_file_t * mpqlib_open_file(struct mpq_archive_t * mpq_a, int entry) { } __mpqlib_seek(mpq_a, r->offset); - for (i = 0; i < r->number_of_sectors; i++) { - uint32_t o; + for (i = 0; i <= r->number_of_sectors; i++) { __mpqlib_read(mpq_a, &o, 4); r->offsets[i] = r->offset + o; } + for (i = 0; i < r->number_of_sectors; i++) { + r->sizes[i] = r->offsets[i + 1] - r->offsets[i]; + } + return r; } @@ -81,21 +120,39 @@ struct mpq_file_t * mpqlib_open_filename(struct mpq_archive_t * mpq_a, const cha void mpqlib_close_file(struct mpq_file_t * mpq_f) { free(mpq_f->buffer); free(mpq_f->offsets); + free(mpq_f->sizes); free(mpq_f); } -static void cache_sector(struct mpq_file_t * mpq_f, int sector) { +static int cache_sector(struct mpq_file_t * mpq_f, int sector) { + static char in_buf[MPQ_BUFSIZ]; + int r = 1; + if (mpq_f->current_sector != sector) { + int il, ol; __mpqlib_seek(mpq_f->mpq_a, mpq_f->offsets[sector]); - __mpqlib_read(mpq_f->mpq_a, mpq_f->buffer, mpq_f->sector_size); + __mpqlib_read(mpq_f->mpq_a, in_buf, mpq_f->sizes[sector]); mpq_f->current_sector = sector; + + il = ol = sector == (mpq_f->number_of_sectors - 1) ? mpq_f->remaining_bytes : mpq_f->sector_size; + + r = __mpqlib_multi_decompress(mpq_f->buffer, &ol, in_buf, mpq_f->sizes[sector]); + + if (il != ol) + r = 0; } + + return r; } -uint32_t mpqlib_read(struct mpq_file_t * mpq_f, void * buffer, uint32_t size) { +uint32_t mpqlib_read(struct mpq_file_t * mpq_f, void * _buffer, uint32_t size) { + char * buffer = (char *) _buffer; int sector_begin, sector_end; + uint32_t cl_size; uint32_t offset_begin, offset_end; + __mpqlib_errno = MPQLIB_ERROR_NO_ERROR; + uint32_t first_sector_begins, last_sector_ends; if ((size + mpq_f->cursor) >= mpq_f->file_size) @@ -114,15 +171,22 @@ uint32_t mpqlib_read(struct mpq_file_t * mpq_f, void * buffer, uint32_t size) { last_sector_ends = mpq_f->sector_size; } + if (!cache_sector(mpq_f, sector_begin)) { + __mpqlib_errno = MPQLIB_ERROR_COMPRESSION; + return 0; + } + if (sector_begin == sector_end) { - cache_sector(mpq_f, sector_begin); memcpy(buffer, mpq_f->buffer + first_sector_begins, size); + mpq_f->cursor += size; return size; } - - /* ... */ - - return size; + + cl_size = mpq_f->sector_size - first_sector_begins; + memcpy(buffer, mpq_f->buffer + first_sector_begins, cl_size); + mpq_f->cursor += cl_size; + + return mpqlib_read(mpq_f, buffer + cl_size, size - cl_size) + cl_size; } uint32_t mpqlib_seek(struct mpq_file_t * mpq_f, int32_t offset, enum mpqlib_file_seek_t wheel) { @@ -142,7 +206,7 @@ uint32_t mpqlib_seek(struct mpq_file_t * mpq_f, int32_t offset, enum mpqlib_file offset = 0; if ((-offset) >= mpq_f->file_size) offset = -mpq_f->file_size; - mpq_f->cursor += offset; + mpq_f->cursor = mpq_f->file_size + offset; break; default: __mpqlib_errno = MPQLIB_ERROR_UNKNOWN; diff --git a/test-it.c b/test-it.c index 5a0b76b..f34d07f 100644 --- a/test-it.c +++ b/test-it.c @@ -1,11 +1,13 @@ #include #include #include "mpq-bios.h" +#include "mpq-file.h" #include "mpq-errors.h" int main(int argc, char ** argv) { struct mpq_archive_t * t1; char * fname = "test.mpq"; + struct mpq_file_t * f1; mpqlib_init(); @@ -21,6 +23,23 @@ int main(int argc, char ** argv) { mpqlib_printtables(t1); + f1 = mpqlib_open_filename(t1, "(listfile)"); + + if (f1) { + int size; + char * b; + printf("Found (listfile), trying to read.\n"); + size = mpqlib_seek(f1, 0, MPQLIB_SEEK_END); + mpqlib_seek(f1, 0, MPQLIB_SEEK_SET); + printf("Filesize seems to be: %d.\n", size); + b = (char *) malloc(size + 1); + b[size] = 0; + mpqlib_read(f1, b, size); + printf("Dumping:\n"); + printf("%s", b); + printf("\nDone.\n"); + } + mpqlib_close_archive(t1); return 0; -- cgit v1.2.3