summaryrefslogtreecommitdiff
path: root/mpq-file.c
diff options
context:
space:
mode:
authorpixel <pixel>2007-07-10 09:17:51 +0000
committerpixel <pixel>2007-07-10 09:17:51 +0000
commit8feb553794efc2a328f8ce2beed5eeacc43238f4 (patch)
treee1e210e854290078586ea88763b9751a8d6d08a9 /mpq-file.c
parente3be7db2c856dc67286a5c873f65af1f40126f46 (diff)
mpq-file working.
Diffstat (limited to 'mpq-file.c')
-rw-r--r--mpq-file.c88
1 files changed, 76 insertions, 12 deletions
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;