summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPixel <pixel@nobis-crew.org>2009-08-04 11:03:27 -0700
committerPixel <pixel@nobis-crew.org>2009-08-04 11:07:09 -0700
commitd6323e7bd7f817c13ce992ef118cbcf4127ad076 (patch)
treeacb2b826f870bc6707fbfb1d3d4160ee0d425b9f
parenta1eb7179ba270ba5183ae3da7689261b03138fed (diff)
Adding stubs for MPQ writes.
-rw-r--r--mpq-bios.c116
-rw-r--r--mpq-bios.h1
-rw-r--r--mpq-errors.c2
-rw-r--r--mpq-errors.h2
4 files changed, 109 insertions, 12 deletions
diff --git a/mpq-bios.c b/mpq-bios.c
index 7ed56f8..cf9f581 100644
--- a/mpq-bios.c
+++ b/mpq-bios.c
@@ -29,6 +29,10 @@
#include "int-bios.h"
#include "errors.h"
+#ifndef MAX
+#define MAX(x,y) (((x)<(y))?(y):(x))
+#endif
+
/*
* MPQ header.
*/
@@ -112,6 +116,9 @@ typedef struct {
struct mpq_archive_t {
int fd;
int closeit;
+ int for_write;
+
+ uint64_t last_block;
uint32_t header_size;
uint32_t archive_size;
@@ -149,6 +156,27 @@ struct mpq_archive_t * mpqlib_open_archive(const char * fname) {
r = mpqlib_reopen_archive(fd);
if (r) {
r->closeit = 1;
+ r->for_write = 0;
+ } else {
+ close(fd);
+ }
+
+ return r;
+}
+
+struct mpq_archive_t * mpqlib_open_archive_for_writing(const char * fname) {
+ int fd;
+ struct mpq_archive_t * r;
+
+ if ((fd = open(fname, O_RDWR | O_LARGEFILE | O_BINARY)) == -1) {
+ __mpqlib_errno = MPQLIB_ERROR_OPEN;
+ return NULL;
+ }
+
+ r = mpqlib_reopen_archive(fd);
+ if (r) {
+ r->closeit = 1;
+ r->for_write = 1;
} else {
close(fd);
}
@@ -205,6 +233,10 @@ struct mpq_archive_t * mpqlib_reopen_archive(int fd) {
mpq_block_t * mpq_blocks;
uint16_t * mpq_extblocks = NULL;
int i;
+ uint64_t last_block = 0;
+#ifndef WIN32
+ int flags;
+#endif
__mpqlib_errno = MPQLIB_ERROR_NO_ERROR;
@@ -218,6 +250,13 @@ struct mpq_archive_t * mpqlib_reopen_archive(int fd) {
mpq_a->closeit = 0;
mpq_a->fd = fd;
+ mpq_a->for_write = 0;
+#ifndef WIN32
+ flags = fcntl(fd, F_GETFL);
+ if ((flags != -1) && (flags & O_RDWR)) {
+ mpq_a->for_write = 1;
+ }
+#endif
/* Reading the main header, and doing basic checks. */
if (read(fd, &mpq_h, STD_HEADER_SIZE) != STD_HEADER_SIZE)
@@ -330,8 +369,11 @@ struct mpq_archive_t * mpqlib_reopen_archive(int fd) {
mpq_a->blocks[i].block_size = mpq_blocks[i].block_size;
mpq_a->blocks[i].file_size = mpq_blocks[i].file_size;
mpq_a->blocks[i].flags = mpq_blocks[i].flags;
+ last_block = MAX(last_block, mpq_a->blocks[i].block_offset + mpq_a->blocks[i].block_size);
}
+ mpq_a->last_block = last_block;
+
/* All done, let's clean up and exit. */
if (mpq_extblocks)
free(mpq_extblocks);
@@ -377,18 +419,31 @@ void mpqlib_printtables(struct mpq_archive_t * mpq_a) {
}
}
-int mpqlib_find_hash_entry_by_name(struct mpq_archive_t * mpq_a, const char * name, uint32_t language, uint32_t platform) {
- uint32_t h, hA, hB;
-
- h = mpqlib_hash_filename(name);
- hA = mpqlib_hashA_filename(name);
- hB = mpqlib_hashB_filename(name);
+static hash_t * mpqlib_locate_hash_entry(struct mpq_archive_t * mpq_a, uint32_t h, uint32_t hA, uint32_t hB, uint32_t language, uint32_t platform) {
+ uint32_t i;
+
+ /* The hash table is a true one, pre-built. We can access it as-it, speeding up the searches drastically. */
+ for (i = h & (mpq_a->hash_table_entries - 1); i < mpq_a->hash_table_entries; i++) {
+ if ((mpq_a->hashs[i].file_path_hasha == hA) &&
+ (mpq_a->hashs[i].file_path_hashb == hB) &&
+ (mpq_a->hashs[i].language == language) &&
+ (mpq_a->hashs[i].platform == platform)) {
+ return mpq_a->hashs + i;
+ }
+ if (mpq_a->hashs[i].file_block_index == 0xffffffff)
+ return NULL;
+ }
- return mpqlib_find_hash_entry_by_hash(mpq_a, h, hA, hB, language, platform);
+ return NULL;
}
-
-int mpqlib_find_hash_entry_by_hash(struct mpq_archive_t * mpq_a, uint32_t h, uint32_t hA, uint32_t hB, uint32_t language, uint32_t platform) {
- int i;
+
+static hash_t * mpqlib_find_free_hash_entry_by_hash(struct mpq_archive_t * mpq_a, uint32_t h, uint32_t hA, uint32_t hB, uint32_t language, uint32_t platform) {
+ uint32_t i;
+
+ if (!mpq_a->for_write) {
+ __mpqlib_errno = MPQLIB_ERROR_READONLY;
+ return NULL;
+ }
/* The hash table is a true one, pre-built. We can access it as-it, speeding up the searches drastically. */
for (i = h & (mpq_a->hash_table_entries - 1); i < mpq_a->hash_table_entries; i++) {
@@ -396,12 +451,49 @@ int mpqlib_find_hash_entry_by_hash(struct mpq_archive_t * mpq_a, uint32_t h, uin
(mpq_a->hashs[i].file_path_hashb == hB) &&
(mpq_a->hashs[i].language == language) &&
(mpq_a->hashs[i].platform == platform)) {
- return mpq_a->hashs[i].file_block_index;
+ /* Full collision ?! */
+ __mpqlib_errno = MPQLIB_ERROR_UNKNOWN;
+ return NULL;
}
if (mpq_a->hashs[i].file_block_index == 0xffffffff)
- break;
+ return mpq_a->hashs + i;
}
+ __mpqlib_errno = MPQLIB_ERROR_TOO_MANY_FILES;
+ return NULL;
+}
+
+static hash_t * mpqlib_find_free_hash_entry_by_name(struct mpq_archive_t * mpq_a, const char * name, uint32_t language, uint32_t platform) {
+ if (!mpq_a->for_write) {
+ __mpqlib_errno = MPQLIB_ERROR_READONLY;
+ return NULL;
+ }
+
+ uint32_t h, hA, hB;
+
+ h = mpqlib_hash_filename(name);
+ hA = mpqlib_hashA_filename(name);
+ hB = mpqlib_hashB_filename(name);
+
+ return mpqlib_find_free_hash_entry_by_hash(mpq_a, h, hA, hB, language, platform);
+}
+
+int mpqlib_find_hash_entry_by_name(struct mpq_archive_t * mpq_a, const char * name, uint32_t language, uint32_t platform) {
+ uint32_t h, hA, hB;
+
+ h = mpqlib_hash_filename(name);
+ hA = mpqlib_hashA_filename(name);
+ hB = mpqlib_hashB_filename(name);
+
+ return mpqlib_find_hash_entry_by_hash(mpq_a, h, hA, hB, language, platform);
+}
+
+int mpqlib_find_hash_entry_by_hash(struct mpq_archive_t * mpq_a, uint32_t h, uint32_t hA, uint32_t hB, uint32_t language, uint32_t platform) {
+ hash_t * hash = mpqlib_locate_hash_entry(mpq_a, h, hA, hB, language, platform);
+
+ if (hash) {
+ return hash->file_block_index;
+ }
return -1;
}
diff --git a/mpq-bios.h b/mpq-bios.h
index c046f53..af58b93 100644
--- a/mpq-bios.h
+++ b/mpq-bios.h
@@ -30,6 +30,7 @@ extern "C" {
void mpqlib_init();
struct mpq_archive_t * mpqlib_open_archive(const char * fname);
+struct mpq_archive_t * mpqlib_open_archive_for_writing(const char * fname);
struct mpq_archive_t * mpqlib_reopen_archive(int fd);
void mpqlib_printtables(struct mpq_archive_t *);
void mpqlib_close_archive(struct mpq_archive_t *);
diff --git a/mpq-errors.c b/mpq-errors.c
index 856ae12..b052e3b 100644
--- a/mpq-errors.c
+++ b/mpq-errors.c
@@ -15,6 +15,8 @@ static const char * error_strings[] = {
"Imploded compression not supported yet.",
"File isn't flagged as compressed - not supported yet.",
"Compression error.",
+ "MPQ archive in read-only mode.",
+ "Too many files.",
};
static const char * wrong_errno = "Invalid error number - internal error.";
diff --git a/mpq-errors.h b/mpq-errors.h
index d9918c4..ada05f1 100644
--- a/mpq-errors.h
+++ b/mpq-errors.h
@@ -26,6 +26,8 @@ enum {
MPQLIB_ERROR_NOT_SUPPORTED,
MPQLIB_ERROR_NOT_COMPRESSED,
MPQLIB_ERROR_COMPRESSION,
+ MPQLIB_ERROR_READONLY,
+ MPQLIB_ERROR_TOO_MANY_FILES,
MPQLIB_ERRORS_MAX
};