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-file.c | 88 +++++++++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 76 insertions(+), 12 deletions(-) (limited to 'mpq-file.c') 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; -- cgit v1.2.3