From e3be7db2c856dc67286a5c873f65af1f40126f46 Mon Sep 17 00:00:00 2001 From: pixel Date: Mon, 9 Jul 2007 20:26:02 +0000 Subject: mpq-file almost done. --- mpq-file.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 143 insertions(+), 1 deletion(-) (limited to 'mpq-file.c') diff --git a/mpq-file.c b/mpq-file.c index 2fc372b..9cc7788 100644 --- a/mpq-file.c +++ b/mpq-file.c @@ -1,12 +1,154 @@ +#include +#include #include "mpq-bios.h" #include "mpq-file.h" +#include "mpq-errors.h" +#include "int-bios.h" +#include "errors.h" struct mpq_file_t { struct mpq_archive_t * mpq_a; int entry; int number_of_sectors; int remaining_bytes; - char * buffer; int current_sector; uint32_t cursor; + uint64_t offset; + uint32_t file_size; + uint32_t sector_size; + + char * buffer; + uint64_t * offsets; }; + +struct mpq_file_t * mpqlib_open_file(struct mpq_archive_t * mpq_a, int entry) { + struct mpq_file_t * r; + int i; + + if (mpqlib_ioctl(mpq_a, MPQLIB_IOCTL_ENTRY_EXISTS, entry)) { + return NULL; + } + + if (!(r = (struct mpq_file_t *) malloc(sizeof(struct mpq_file_t)))) { + __mpqlib_errno = MPQLIB_ERROR_MEMORY; + return NULL; + } + + r->sector_size = mpqlib_ioctl(mpq_a, MPQLIB_IOCTL_GET_SECTOR_SIZE, 0); + + if (!(r->buffer = malloc(r->sector_size))) { + free(r); + __mpqlib_errno = MPQLIB_ERROR_MEMORY; + return NULL; + } + + r->entry = entry; + 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++; + } + r->current_sector = -1; + r->cursor = 0; + + if (!(r->offsets = (uint64_t *) malloc(r->number_of_sectors * sizeof(uint64_t)))) { + free(r->buffer); + free(r); + __mpqlib_errno = MPQLIB_ERROR_MEMORY; + return NULL; + } + + __mpqlib_seek(mpq_a, r->offset); + for (i = 0; i < r->number_of_sectors; i++) { + uint32_t o; + __mpqlib_read(mpq_a, &o, 4); + r->offsets[i] = r->offset + o; + } + + return r; +} + +struct mpq_file_t * mpqlib_open_filename(struct mpq_archive_t * mpq_a, const char * fname) { + int e; + + if ((e = mpqlib_find_hash_entry_by_name(mpq_a, fname, 0, 0)) < 0) + return NULL; + + return mpqlib_open_file(mpq_a, e); +} + +void mpqlib_close_file(struct mpq_file_t * mpq_f) { + free(mpq_f->buffer); + free(mpq_f->offsets); + free(mpq_f); +} + +static void cache_sector(struct mpq_file_t * mpq_f, int sector) { + if (mpq_f->current_sector != sector) { + __mpqlib_seek(mpq_f->mpq_a, mpq_f->offsets[sector]); + __mpqlib_read(mpq_f->mpq_a, mpq_f->buffer, mpq_f->sector_size); + mpq_f->current_sector = sector; + } +} + +uint32_t mpqlib_read(struct mpq_file_t * mpq_f, void * buffer, uint32_t size) { + int sector_begin, sector_end; + uint32_t offset_begin, offset_end; + + uint32_t first_sector_begins, last_sector_ends; + + if ((size + mpq_f->cursor) >= mpq_f->file_size) + size = mpq_f->file_size - mpq_f->cursor; + + offset_begin = mpq_f->cursor; + sector_begin = offset_begin / mpq_f->sector_size; + first_sector_begins = offset_begin % mpq_f->sector_size; + + offset_end = size + mpq_f->cursor; + sector_end = offset_end / mpq_f->sector_size; + last_sector_ends = offset_end % mpq_f->sector_size; + + if (!(offset_end % mpq_f->sector_size)) { + sector_end--; + last_sector_ends = mpq_f->sector_size; + } + + if (sector_begin == sector_end) { + cache_sector(mpq_f, sector_begin); + memcpy(buffer, mpq_f->buffer + first_sector_begins, size); + return size; + } + + /* ... */ + + return size; +} + +uint32_t mpqlib_seek(struct mpq_file_t * mpq_f, int32_t offset, enum mpqlib_file_seek_t wheel) { + switch (wheel) { + case MPQLIB_SEEK_SET: + if (offset < 0) + offset = 0; + mpq_f->cursor = offset; + break; + case MPQLIB_SEEK_CUR: + if ((-offset) >= mpq_f->cursor) + offset = -mpq_f->cursor; + mpq_f->cursor += offset; + break; + case MPQLIB_SEEK_END: + if (offset > 0) + offset = 0; + if ((-offset) >= mpq_f->file_size) + offset = -mpq_f->file_size; + mpq_f->cursor += offset; + break; + default: + __mpqlib_errno = MPQLIB_ERROR_UNKNOWN; + return 0xffffffff; + } + if (mpq_f->cursor >= mpq_f->file_size) + mpq_f->cursor = mpq_f->file_size; + return mpq_f->cursor; +} -- cgit v1.2.3