[Extractor-gtk-cvslog] SF.net SVN: extractor-gtk: [76] trunk/extractor/solid.c
Extract files from unusual archive formats
Brought to you by:
someone-guy
From: <som...@us...> - 2008-04-06 21:34:43
|
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. |