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. --- int-bios.h | 7 +-- mpq-bios.c | 9 ++-- mpq-bios.h | 1 + mpq-file.c | 144 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- mpq-file.h | 1 + 5 files changed, 153 insertions(+), 9 deletions(-) diff --git a/int-bios.h b/int-bios.h index 9fdee7e..c0b437b 100644 --- a/int-bios.h +++ b/int-bios.h @@ -1,12 +1,9 @@ #ifndef __INT_BIOS_H__ #define __INT_BIOS_H__ -#include -#include - #include "mpq-bios.h" -int __mpqlib_seek(struct mpq_archive_t *, off_t); -int __mpqlib_read(struct mpq_archive_t *, void *, size_t); +int __mpqlib_seek(struct mpq_archive_t *, uint64_t); +int __mpqlib_read(struct mpq_archive_t *, void *, uint32_t); #endif diff --git a/mpq-bios.c b/mpq-bios.c index abac013..4051627 100644 --- a/mpq-bios.c +++ b/mpq-bios.c @@ -336,13 +336,13 @@ int mpqlib_find_hash_entry_by_hash(struct mpq_archive_t * mpq_a, uint32_t hA, ui return -1; } -int __mpqlib_seek(struct mpq_archive_t * mpq_a, off_t off) { +int __mpqlib_seek(struct mpq_archive_t * mpq_a, uint64_t off) { if (lseek64(mpq_a->fd, off, SEEK_SET) != off) return 0; return 1; } -int __mpqlib_read(struct mpq_archive_t * mpq_a, void * buffer, size_t size) { +int __mpqlib_read(struct mpq_archive_t * mpq_a, void * buffer, uint32_t size) { return read_data(mpq_a, buffer, size); } @@ -354,15 +354,18 @@ uint64_t mpqlib_ioctl(struct mpq_archive_t * mpq_a, enum mpqlib_ioctl_t command, return mpq_a->format_version; case MPQLIB_IOCTL_GET_SECTOR_SIZE: return mpq_a->sector_size; + case MPQLIB_IOCTL_ENTRY_EXISTS: case MPQLIB_IOCTL_GET_BLOCK_OFFSET: case MPQLIB_IOCTL_GET_BLOCK_SIZE: case MPQLIB_IOCTL_GET_FILE_SIZE: case MPQLIB_IOCTL_GET_FLAGS: - if (entry >= mpq_a->block_table_entries) { + if ((entry >= mpq_a->block_table_entries) || (entry < 0)) { __mpqlib_errno = MPQLIB_ERROR_IOCTL_INVALID_ENTRY; return -1; } switch (command) { + case MPQLIB_IOCTL_ENTRY_EXISTS: + return 0; case MPQLIB_IOCTL_GET_BLOCK_OFFSET: return mpq_a->blocks[entry].block_offset; case MPQLIB_IOCTL_GET_BLOCK_SIZE: diff --git a/mpq-bios.h b/mpq-bios.h index 433f197..84f64ae 100644 --- a/mpq-bios.h +++ b/mpq-bios.h @@ -15,6 +15,7 @@ struct mpq_archive_t; enum mpqlib_ioctl_t { MPQLIB_IOCTL_NO_ACTION = 0, + MPQLIB_IOCTL_ENTRY_EXISTS, MPQLIB_IOCTL_GET_FORMAT_VERSION, MPQLIB_IOCTL_GET_SECTOR_SIZE, MPQLIB_IOCTL_GET_BLOCK_OFFSET, 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; +} diff --git a/mpq-file.h b/mpq-file.h index 53b514e..f9b17db 100644 --- a/mpq-file.h +++ b/mpq-file.h @@ -13,6 +13,7 @@ enum mpqlib_file_seek_t { struct mpq_file_t * mpqlib_open_file(struct mpq_archive_t * mpq_a, int entry); struct mpq_file_t * mpqlib_open_filename(struct mpq_archive_t * mpq_a, const char * fname); +void mpqlib_close(struct mpq_file_t * mpq_f); uint32_t mpqlib_read(struct mpq_file_t * mpq_f, void * buffer, uint32_t size); uint32_t mpqlib_seek(struct mpq_file_t * mpq_f, int32_t offset, enum mpqlib_file_seek_t); -- cgit v1.2.3