summaryrefslogtreecommitdiff
path: root/mpq-file.c
diff options
context:
space:
mode:
authorpixel <pixel>2007-07-09 20:26:02 +0000
committerpixel <pixel>2007-07-09 20:26:02 +0000
commite3be7db2c856dc67286a5c873f65af1f40126f46 (patch)
treefbd889e3edcbdf061ea5b292401cd2e9a9d63e42 /mpq-file.c
parenta47cbe621febe11586f22c28a4507d74930d1737 (diff)
mpq-file almost done.
Diffstat (limited to 'mpq-file.c')
-rw-r--r--mpq-file.c144
1 files changed, 143 insertions, 1 deletions
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 <stdlib.h>
+#include <memory.h>
#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;
+}