Revision: 76
http://extractor-gtk.svn.sourceforge.net/extractor-gtk/?rev=76&view=rev
Author: someone-guy
Date: 2008-04-06 14:34:41 -0700 (Sun, 06 Apr 2008)
Log Message:
-----------
Extraction support for Metal Gear vox.dat
Modified Paths:
--------------
trunk/extractor/solid.c
Modified: trunk/extractor/solid.c
===================================================================
--- trunk/extractor/solid.c 2008-04-06 20:09:49 UTC (rev 75)
+++ trunk/extractor/solid.c 2008-04-06 21:34:41 UTC (rev 76)
@@ -60,15 +60,21 @@
return "bin";
}
+static int read_block_header(FILE *in, int *lang, int *type, uint32_t *len) {
+ *lang = read_be16(in);
+ *type = read_be16(in);
+ *len = read_be32(in);
+ return !feof(in);
+}
+
static file_t *get_list(FILE *in) {
int cnt = 0;
file_t *list = calloc(1, sizeof(file_t));
rewind(in);
while (cnt < MAX_FILES) {
- int lang = read_be16(in);
- int type = read_be16(in);
- uint32_t len = read_be32(in);
- if (feof(in)) break;
+ int lang, type;
+ uint32_t len;
+ if (!read_block_header(in, &lang, &type, &len)) break;
if (type == TYPE_INDEX) {
char ext[8];
read_be32(in); // unknown, always 0?
@@ -93,6 +99,74 @@
return list;
}
+//! quick and dirty hack to avoid overflow problems
+#define MAX_FILE_SZ (1024*1024*1024)
+
+static int do_extract(FILE *in, const file_t *file, FILE *outf, uint8_t *outb, int max_size) {
+ int extract_lang, extract_type;
+ int lang, type;
+ int extracted = 0;
+ int first = 1;
+ uint32_t len;
+ uint32_t skip;
+ if (!outb || max_size > MAX_FILE_SZ) max_size = MAX_FILE_SZ;
+ fseek(in, file->start, SEEK_SET);
+ read_block_header(in, &lang, &type, &len);
+ read_be32(in);
+ extract_lang = read_be16(in);
+ extract_type = read_be16(in);
+ fseek(in, len - 16, SEEK_CUR);
+ // skip remaining index entries
+ while (read_block_header(in, &lang, &type, &len) && type == TYPE_INDEX)
+ fseek(in, len - 8, SEEK_CUR);
+ while (type != TYPE_INDEX && type != TYPE_PADDING) {
+ skip = len - 8;
+ if (lang == extract_lang && type == extract_type) {
+ skip = 0;
+ len -= 16;
+ if (type == TYPE_AUDIO) {
+ uint32_t data_len;
+ read_be32(in);
+ data_len = read_be32(in);
+ if (data_len > len) data_len = len;
+
+ // first packet does not contain any data useful to us
+ if (first) data_len = 0;
+ first = 0;
+
+ skip = len - data_len;
+ len = data_len;
+ } else
+ fseek(in, 8, SEEK_CUR);
+
+ // some sanity checks
+ if (extracted >= max_size || len > max_size) break;
+ if (extracted + len > max_size) len = max_size - extracted;
+
+ // read data part
+ if (outf) fcopy(in, outf, len);
+ else if (outb) {
+ fread(outb, 1, len, in);
+ outb += len;
+ } else
+ fseek(in, len, SEEK_CUR);
+ extracted += len;
+ }
+ fseek(in, skip, SEEK_CUR);
+ if (!read_block_header(in, &lang, &type, &len))
+ break;
+ }
+ return extracted;
+}
+
+static int extract_file(FILE *in, const file_t *file, FILE *out) {
+ return do_extract(in, file, out, NULL, 0);
+}
+
+static int extract_mem(FILE *in, const file_t *file, uint8_t *out, int size) {
+ return do_extract(in, file, NULL, out, size);
+}
+
const fmt_desc_t solid_fmt = {
"MetalGear Solid: TS",
"MetalGear Solid: TS (vox.dat)",
@@ -100,6 +174,6 @@
check_file,
get_list,
default_free_list,
- default_extract_file,
- default_extract_mem,
+ extract_file,
+ extract_mem,
};
This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.
|