summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mpq-bios.c16
-rw-r--r--mpq-errors.c4
-rw-r--r--mpq-errors.h4
-rw-r--r--mpq-file.c88
-rw-r--r--test-it.c19
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 <stdio.h>
#include <stdlib.h>
#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;