Support for SC1 format.
git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@2727 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
+307
-135
@@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
#include <assert.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/mman.h>
|
#include <sys/mman.h>
|
||||||
@@ -37,12 +38,18 @@ struct options {
|
|||||||
char list;
|
char list;
|
||||||
char print;
|
char print;
|
||||||
char verbose;
|
char verbose;
|
||||||
|
enum {
|
||||||
|
Type_sc1, // PC version of SC1
|
||||||
|
Type_pc, // PC version of SC2
|
||||||
|
Type_3do, // 3DO version of SC2
|
||||||
|
} type;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
index_header *readIndex(const uint8 *buf);
|
index_header *readIndex(const struct options *opts, const uint8 *buf);
|
||||||
void printIndex(const index_header *h, const uint8 *buf, FILE *out);
|
void printIndex(const struct options *opts, const index_header *h,
|
||||||
char *get_file_name(const uint8 *buf, const index_header *h,
|
const uint8 *buf, FILE *out);
|
||||||
|
char *getFileName(const uint8 *buf, const index_header *h,
|
||||||
uint16 file_index);
|
uint16 file_index);
|
||||||
void writeFiles(const index_header *h, const uint8 *data, const char *path);
|
void writeFiles(const index_header *h, const uint8 *data, const char *path);
|
||||||
void parse_arguments(int argc, char *argv[], struct options *opts);
|
void parse_arguments(int argc, char *argv[], struct options *opts);
|
||||||
@@ -78,9 +85,9 @@ main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
close(in);
|
close(in);
|
||||||
|
|
||||||
h = readIndex(buf);
|
h = readIndex(&opts, buf);
|
||||||
if (opts.print)
|
if (opts.print)
|
||||||
printIndex(h, buf, stdout);
|
printIndex(&opts, h, buf, stdout);
|
||||||
|
|
||||||
if (opts.list)
|
if (opts.list)
|
||||||
listResources(h, buf, stdout);
|
listResources(h, buf, stdout);
|
||||||
@@ -89,8 +96,8 @@ main(int argc, char *argv[]) {
|
|||||||
size_t len;
|
size_t len;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
|
|
||||||
if (!h->res_flags) {
|
if (!h->packaged) {
|
||||||
fprintf(stderr, "Error: Cannot unpack data from unpackaged "
|
fprintf(stderr, "Error: Cannot unpack data from non-packaged "
|
||||||
"file.\n");
|
"file.\n");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
@@ -125,7 +132,12 @@ main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
void
|
void
|
||||||
usage() {
|
usage() {
|
||||||
fprintf(stderr, "unpkg [-o outputdir] [-v] [-l listfile] <infile>\n");
|
fprintf(stderr, "unpkg [-o <outputdir>] [-l] [-p] [-v] <infile>\n"
|
||||||
|
"\t-o unpack to 'outputdir'\n"
|
||||||
|
"\t-l list the resources\n"
|
||||||
|
"\t-p print the index\n"
|
||||||
|
"\t-t package file type; one of \"sc1\", \"pc\", or \"3do\"\n"
|
||||||
|
"\t-v verbose mode\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -133,8 +145,9 @@ parse_arguments(int argc, char *argv[], struct options *opts) {
|
|||||||
char ch;
|
char ch;
|
||||||
|
|
||||||
memset(opts, '\0', sizeof (struct options));
|
memset(opts, '\0', sizeof (struct options));
|
||||||
|
opts->type = Type_3do;
|
||||||
while (1) {
|
while (1) {
|
||||||
ch = getopt(argc, argv, "hlo:pv");
|
ch = getopt(argc, argv, "hlo:pt:v");
|
||||||
if (ch == -1)
|
if (ch == -1)
|
||||||
break;
|
break;
|
||||||
switch(ch) {
|
switch(ch) {
|
||||||
@@ -147,6 +160,25 @@ parse_arguments(int argc, char *argv[], struct options *opts) {
|
|||||||
case 'p':
|
case 'p':
|
||||||
opts->print = 1;
|
opts->print = 1;
|
||||||
break;
|
break;
|
||||||
|
case 't':
|
||||||
|
if (strcmp(optarg, "sc1") == 0 ||
|
||||||
|
strcmp(optarg, "SC1") == 0) {
|
||||||
|
opts->type = Type_sc1;
|
||||||
|
} else if (strcmp(optarg, "pc") == 0 ||
|
||||||
|
strcmp(optarg, "PC") == 0) {
|
||||||
|
opts->type = Type_pc;
|
||||||
|
} else if (strcmp(optarg, "3do") == 0 ||
|
||||||
|
strcmp(optarg, "3DO") == 0) {
|
||||||
|
opts->type = Type_3do;
|
||||||
|
fprintf(stderr, "3DO package files are not yet "
|
||||||
|
"supported.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Invalid package file type.\n");
|
||||||
|
usage();
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 'v':
|
case 'v':
|
||||||
opts->verbose = 1;
|
opts->verbose = 1;
|
||||||
break;
|
break;
|
||||||
@@ -167,21 +199,42 @@ parse_arguments(int argc, char *argv[], struct options *opts) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
index_header *
|
index_header *
|
||||||
readIndex(const uint8 *buf) {
|
readIndex(const struct options *opts, const uint8 *buf) {
|
||||||
index_header *h;
|
index_header *h;
|
||||||
|
uint16 res_flags;
|
||||||
const uint8 *bufptr;
|
const uint8 *bufptr;
|
||||||
|
|
||||||
h = malloc(sizeof (index_header));
|
h = malloc(sizeof (index_header));
|
||||||
h->res_flags = MAKE_WORD(buf[0x00], buf[0x01]) ? 1 : 0;
|
res_flags = MAKE_WORD(buf[0x00], buf[0x01]);
|
||||||
h->packmem_list_offs =
|
h->packaged = ((res_flags & 0x1) == 0x1) ? true : false;
|
||||||
MAKE_DWORD(buf[0x02], buf[0x03], buf[0x04], buf[0x05]);
|
switch (opts->type) {
|
||||||
h->path_list_offs =
|
case Type_sc1:
|
||||||
MAKE_DWORD(buf[0x06], buf[0x07], buf[0x08], buf[0x09]);
|
h->path_list_offs =
|
||||||
h->file_list_offs =
|
MAKE_DWORD(buf[0x02], buf[0x03], buf[0x04], buf[0x05]);
|
||||||
MAKE_DWORD(buf[0x0a], buf[0x0b], buf[0x0c], buf[0x0d]);
|
h->file_list_offs =
|
||||||
h->num_packages = MAKE_WORD(buf[0x0e], buf[0x0f]);
|
MAKE_DWORD(buf[0x06], buf[0x07], buf[0x08], buf[0x09]);
|
||||||
h->num_types = MAKE_WORD(buf[0x10], buf[0x11]);
|
h->packmem_list_offs =
|
||||||
h->header_len = MAKE_DWORD(buf[0x12], buf[0x13], buf[0x14], buf[0x15]);
|
MAKE_DWORD(buf[0x0a], buf[0x0b], buf[0x0c], buf[0x0d]);
|
||||||
|
h->num_types = MAKE_WORD(buf[0x0e], buf[0x0f]);
|
||||||
|
h->num_packages = MAKE_WORD(buf[0x12], buf[0x13]);
|
||||||
|
h->header_len = 0;
|
||||||
|
break;
|
||||||
|
case Type_pc:
|
||||||
|
abort(); // Not supported
|
||||||
|
break;
|
||||||
|
case Type_3do:
|
||||||
|
h->packmem_list_offs =
|
||||||
|
MAKE_DWORD(buf[0x02], buf[0x03], buf[0x04], buf[0x05]);
|
||||||
|
h->path_list_offs =
|
||||||
|
MAKE_DWORD(buf[0x06], buf[0x07], buf[0x08], buf[0x09]);
|
||||||
|
h->file_list_offs =
|
||||||
|
MAKE_DWORD(buf[0x0a], buf[0x0b], buf[0x0c], buf[0x0d]);
|
||||||
|
h->num_packages = MAKE_WORD(buf[0x0e], buf[0x0f]);
|
||||||
|
h->num_types = MAKE_WORD(buf[0x10], buf[0x11]);
|
||||||
|
h->header_len = MAKE_DWORD(
|
||||||
|
buf[0x12], buf[0x13], buf[0x14], buf[0x15]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
bufptr = buf + 0x16;
|
bufptr = buf + 0x16;
|
||||||
h->package_list = malloc(h->num_packages * sizeof (package_desc));
|
h->package_list = malloc(h->num_packages * sizeof (package_desc));
|
||||||
@@ -221,65 +274,72 @@ readIndex(const uint8 *buf) {
|
|||||||
{
|
{
|
||||||
int i, j;
|
int i, j;
|
||||||
int num_types, num_instances;
|
int num_types, num_instances;
|
||||||
uint32 temp;
|
|
||||||
|
|
||||||
for (i = 0; i < h->num_packages; i++) {
|
for (i = 0; i < h->num_packages; i++) {
|
||||||
|
package_desc *package = &h->package_list[i];
|
||||||
|
|
||||||
uint32 next_offset;
|
uint32 next_offset;
|
||||||
if (h->res_flags) {
|
if (h->packaged) {
|
||||||
// packaged
|
// One file name per package
|
||||||
char *temp;
|
char *temp;
|
||||||
temp = get_file_name(buf, h, h->package_list[i].file_index);
|
temp = getFileName(buf, h, package->file_index);
|
||||||
h->package_list[i].filename =
|
package->filename = (temp == NULL) ? NULL : strdup(temp);
|
||||||
(temp == NULL) ? NULL : strdup(temp);
|
|
||||||
} else {
|
} else {
|
||||||
// not packaged
|
// File name is specified per resource instance.
|
||||||
h->package_list[i].filename = NULL;
|
package->filename = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
num_types = h->package_list[i].num_types;
|
num_types = package->num_types;
|
||||||
h->package_list[i].type_list =
|
package->type_list = malloc(num_types * sizeof (packtype_desc));
|
||||||
malloc(num_types * sizeof (packtype_desc));
|
|
||||||
for (j = 0; j < num_types; j++) {
|
for (j = 0; j < num_types; j++) {
|
||||||
|
packtype_desc *type = &package->type_list[j];
|
||||||
|
uint32 temp;
|
||||||
|
|
||||||
temp = MAKE_DWORD(bufptr[0], bufptr[1], bufptr[2], bufptr[3]);
|
temp = MAKE_DWORD(bufptr[0], bufptr[1], bufptr[2], bufptr[3]);
|
||||||
h->package_list[i].type_list[j].type = GET_TYPE(temp);
|
type->type = GET_TYPE(temp);
|
||||||
h->package_list[i].type_list[j].first_instance =
|
type->first_instance = GET_INSTANCE(temp);
|
||||||
GET_INSTANCE(temp);
|
type->num_instances = GET_PACKAGE(temp);
|
||||||
h->package_list[i].type_list[j].num_instances =
|
|
||||||
GET_PACKAGE(temp);
|
|
||||||
bufptr += 4;
|
bufptr += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (h->res_flags) {
|
next_offset = package->data_loc;
|
||||||
// packaged
|
|
||||||
next_offset = h->package_list[i].data_loc;
|
|
||||||
}
|
|
||||||
for (j = 0; j < num_types; j++) {
|
for (j = 0; j < num_types; j++) {
|
||||||
|
packtype_desc *type = &package->type_list[j];
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
num_instances = h->package_list[i].type_list[j].num_instances;
|
num_instances = type->num_instances;
|
||||||
h->package_list[i].type_list[j].instances =
|
type->instances =
|
||||||
malloc(sizeof (packdef_instance) * num_instances);
|
malloc(sizeof (packdef_instance) * num_instances);
|
||||||
for (k = 0; k < num_instances; k++) {
|
for (k = 0; k < num_instances; k++) {
|
||||||
if (h->res_flags) {
|
packdef_instance *instance = &type->instances[k];
|
||||||
// packaged
|
|
||||||
h->package_list[i].type_list[j].instances[k].size =
|
if (h->packaged) {
|
||||||
4 * MAKE_WORD(bufptr[0], bufptr[1]);
|
switch (opts->type) {
|
||||||
h->package_list[i].type_list[j].instances[k].offset =
|
case Type_sc1:
|
||||||
next_offset;
|
instance->size =
|
||||||
h->package_list[i].type_list[j].instances[k].
|
MAKE_WORD(bufptr[0], bufptr[1]);
|
||||||
filename = NULL;
|
break;
|
||||||
next_offset += h->package_list[i].type_list[j].
|
case Type_pc:
|
||||||
instances[k].size;
|
abort(); // Not yet supported.
|
||||||
|
break;
|
||||||
|
case Type_3do:
|
||||||
|
instance->size =
|
||||||
|
4 * MAKE_WORD(bufptr[0], bufptr[1]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
instance->offset = next_offset;
|
||||||
|
next_offset += instance->size;
|
||||||
|
instance->filename = NULL;
|
||||||
|
// File name is specified per package.
|
||||||
} else {
|
} else {
|
||||||
char *temp;
|
char *temp;
|
||||||
h->package_list[i].type_list[j].instances[k].size = 0;
|
instance->size = 0;
|
||||||
h->package_list[i].type_list[j].instances[k].offset =
|
instance->offset = 0;
|
||||||
0;
|
temp = getFileName(buf, h,
|
||||||
temp = get_file_name(buf, h,
|
|
||||||
MAKE_WORD(bufptr[0], bufptr[1]));
|
MAKE_WORD(bufptr[0], bufptr[1]));
|
||||||
h->package_list[i].type_list[j].instances[k].
|
instance->filename = (temp == NULL) ?
|
||||||
filename = (temp == NULL) ?
|
|
||||||
NULL : strdup(temp);
|
NULL : strdup(temp);
|
||||||
|
|
||||||
}
|
}
|
||||||
bufptr += 2;
|
bufptr += 2;
|
||||||
} // for k
|
} // for k
|
||||||
@@ -290,23 +350,47 @@ readIndex(const uint8 *buf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
printIndex(const index_header *h, const uint8 *buf, FILE *out) {
|
printIndex(const struct options *opts, const index_header *h,
|
||||||
|
const uint8 *buf, FILE *out) {
|
||||||
const uint8 *bufptr;
|
const uint8 *bufptr;
|
||||||
|
|
||||||
fprintf(out, "0x00000000 File type: %s\n",
|
fprintf(out, "0x00000000 File type: %s\n",
|
||||||
h->res_flags ? "packaged" : "not packaged");
|
h->packaged ? "packaged" : "not packaged");
|
||||||
fprintf(out, "0x00000002 packmem_list_offs: 0x%08x\n",
|
switch (opts->type) {
|
||||||
h->packmem_list_offs);
|
case Type_sc1:
|
||||||
fprintf(out, "0x00000006 path_list_offs: 0x%08x\n",
|
fprintf(out, "0x00000002 path_list_offs: 0x%08x\n",
|
||||||
h->path_list_offs);
|
h->path_list_offs);
|
||||||
fprintf(out, "0x0000000a file_list_offs: 0x%08x\n",
|
fprintf(out, "0x00000006 file_list_offs: 0x%08x\n",
|
||||||
h->file_list_offs);
|
h->file_list_offs);
|
||||||
fprintf(out, "0x0000000e Number of packages: %d\n",
|
fprintf(out, "0x0000000a packmem_list_offs: 0x%08x\n",
|
||||||
h->num_packages);
|
h->packmem_list_offs);
|
||||||
fprintf(out, "0x00000010 Number of package types: %d\n",
|
fprintf(out, "0x0000000e Number of package types: %d\n",
|
||||||
h->num_types);
|
h->num_types);
|
||||||
fprintf(out, "0x00000012 Header length: 0x%08x\n",
|
fprintf(out, "0x00000010 Unknown: 0x%04x\n",
|
||||||
h->header_len);
|
MAKE_WORD(buf[0x10], buf[0x11]));
|
||||||
|
fprintf(out, "0x00000012 Number of packages: %d\n",
|
||||||
|
h->num_packages);
|
||||||
|
fprintf(out, "0x00000013 Unknown: 0x%04x\n",
|
||||||
|
MAKE_WORD(buf[0x13], buf[0x14]));
|
||||||
|
break;
|
||||||
|
case Type_pc:
|
||||||
|
abort(); // Not supported
|
||||||
|
break;
|
||||||
|
case Type_3do:
|
||||||
|
fprintf(out, "0x00000002 packmem_list_offs: 0x%08x\n",
|
||||||
|
h->packmem_list_offs);
|
||||||
|
fprintf(out, "0x00000006 path_list_offs: 0x%08x\n",
|
||||||
|
h->path_list_offs);
|
||||||
|
fprintf(out, "0x0000000a file_list_offs: 0x%08x\n",
|
||||||
|
h->file_list_offs);
|
||||||
|
fprintf(out, "0x0000000e Number of packages: %d\n",
|
||||||
|
h->num_packages);
|
||||||
|
fprintf(out, "0x00000010 Number of package types: %d\n",
|
||||||
|
h->num_types);
|
||||||
|
fprintf(out, "0x00000012 Header length: 0x%08x\n",
|
||||||
|
h->header_len);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
bufptr = buf + 0x16;
|
bufptr = buf + 0x16;
|
||||||
fprintf(out, "0x00000016 package info:\n");
|
fprintf(out, "0x00000016 package info:\n");
|
||||||
@@ -353,19 +437,18 @@ printIndex(const index_header *h, const uint8 *buf, FILE *out) {
|
|||||||
int num_types, num_instances;
|
int num_types, num_instances;
|
||||||
|
|
||||||
for (i = 0; i < h->num_packages; i++) {
|
for (i = 0; i < h->num_packages; i++) {
|
||||||
if (h->res_flags) {
|
package_desc *package = &h->package_list[i];
|
||||||
// packaged
|
|
||||||
|
if (h->packaged) {
|
||||||
fprintf(out, "0x%08x Package #%d (%s):\n",
|
fprintf(out, "0x%08x Package #%d (%s):\n",
|
||||||
bufptr - buf, i + 1,
|
bufptr - buf, i + 1, (package->filename == NULL) ?
|
||||||
(h->package_list[i].filename == NULL) ?
|
"<<INTERNAL>>" : package->filename);
|
||||||
"<<UNNAMED>>" : h->package_list[i].filename);
|
|
||||||
} else {
|
} else {
|
||||||
// not packaged
|
|
||||||
fprintf(out, "0x%08x Package #%d:\n",
|
fprintf(out, "0x%08x Package #%d:\n",
|
||||||
bufptr - buf, i + 1);
|
bufptr - buf, i + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
num_types = h->package_list[i].num_types;
|
num_types = package->num_types;
|
||||||
for (j = 0; j < num_types; j++) {
|
for (j = 0; j < num_types; j++) {
|
||||||
fprintf(out, "0x%08x Type #%d: type %d, "
|
fprintf(out, "0x%08x Type #%d: type %d, "
|
||||||
"%d instances starting with #%d\n",
|
"%d instances starting with #%d\n",
|
||||||
@@ -377,30 +460,28 @@ printIndex(const index_header *h, const uint8 *buf, FILE *out) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (j = 0; j < num_types; j++) {
|
for (j = 0; j < num_types; j++) {
|
||||||
|
packtype_desc *type = &package->type_list[j];
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
num_instances = h->package_list[i].type_list[j].num_instances;
|
num_instances = type->num_instances;
|
||||||
for (k = 0; k < num_instances; k++) {
|
for (k = 0; k < num_instances; k++) {
|
||||||
if (h->res_flags) {
|
packdef_instance *instance = &type->instances[k];
|
||||||
// packaged
|
|
||||||
|
if (h->packaged) {
|
||||||
fprintf(out, "0x%08x Instance #%d of "
|
fprintf(out, "0x%08x Instance #%d of "
|
||||||
"type %d: size %d bytes\n", bufptr - buf,
|
"type %d: size %d bytes\n", bufptr - buf,
|
||||||
k + h->package_list[i].type_list[j].
|
k + type->first_instance, type->type,
|
||||||
first_instance,
|
instance->size);
|
||||||
h->package_list[i].type_list[j].type,
|
|
||||||
h->package_list[i].type_list[j].instances[k].
|
|
||||||
size);
|
|
||||||
} else {
|
} else {
|
||||||
fprintf(out, "0x%08x Instance #%d of "
|
fprintf(out, "0x%08x Instance #%d of "
|
||||||
"type %d: %s\n", bufptr - buf,
|
"type %d: %s\n", bufptr - buf,
|
||||||
k + h->package_list[i].type_list[j].
|
k + type->first_instance, type->type,
|
||||||
first_instance,
|
(instance->filename == NULL) ?
|
||||||
h->package_list[i].type_list[j].type,
|
"<<UNNAMED>>" : instance->filename);
|
||||||
(h->package_list[i].type_list[j].instances[k].
|
// NB. NULL filenames should not occur for
|
||||||
filename == NULL) ? "<<UNNAMED>>" :
|
// non-packaged files.
|
||||||
h->package_list[i].type_list[j].instances[k].
|
|
||||||
filename);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bufptr += 2;
|
bufptr += 2;
|
||||||
} // for k
|
} // for k
|
||||||
} // for j
|
} // for j
|
||||||
@@ -415,29 +496,27 @@ listResources(const index_header *h, const uint8 *buf, FILE *out) {
|
|||||||
char *filename;
|
char *filename;
|
||||||
|
|
||||||
for (i = 0; i < h->num_packages; i++) {
|
for (i = 0; i < h->num_packages; i++) {
|
||||||
if (h->res_flags) {
|
package_desc *package = &h->package_list[i];
|
||||||
// packaged
|
|
||||||
filename = (h->package_list[i].filename == NULL) ?
|
if (h->packaged) {
|
||||||
"<<UNNAMED>>" : h->package_list[i].filename;
|
// One filename for all resources in a package.
|
||||||
|
filename = (package->filename == NULL) ?
|
||||||
|
"<<INTERNAL>>" : package->filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
num_types = h->package_list[i].num_types;
|
num_types = package->num_types;
|
||||||
for (j = 0; j < num_types; j++) {
|
for (j = 0; j < num_types; j++) {
|
||||||
|
packtype_desc *type = &package->type_list[j];
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
num_instances = h->package_list[i].type_list[j].num_instances;
|
num_instances = type->num_instances;
|
||||||
for (k = 0; k < num_instances; k++) {
|
for (k = 0; k < num_instances; k++) {
|
||||||
if (!h->res_flags) {
|
packdef_instance *instance = &type->instances[k];
|
||||||
filename = (h->package_list[i].type_list[j].instances[k].
|
if (!h->packaged)
|
||||||
filename == NULL) ? "<<UNNAMED>>" :
|
filename = (instance->filename == NULL) ?
|
||||||
h->package_list[i].type_list[j].instances[k].
|
"<<UNNAMED>>" : instance->filename;
|
||||||
filename;
|
fprintf(out, "0x%08x %s\n", MAKE_RESOURCE(i + 1, type->type,
|
||||||
}
|
type->first_instance + k), filename);
|
||||||
fprintf(out, "0x%08x %s\n",
|
|
||||||
MAKE_RESOURCE(i + 1,
|
|
||||||
h->package_list[i].type_list[j].type,
|
|
||||||
h->package_list[i].type_list[j].first_instance + k),
|
|
||||||
filename);
|
|
||||||
} // for k
|
} // for k
|
||||||
} // for j
|
} // for j
|
||||||
} // for i
|
} // for i
|
||||||
@@ -445,8 +524,8 @@ listResources(const index_header *h, const uint8 *buf, FILE *out) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
char *
|
char *
|
||||||
get_file_name(const uint8 *buf, const index_header *h, uint16 file_index) {
|
getFileName(const uint8 *buf, const index_header *h, uint16 file_index) {
|
||||||
static char result[MAXPATHLEN];
|
static char result[PATH_MAX];
|
||||||
char *ptr;
|
char *ptr;
|
||||||
file_info *fi;
|
file_info *fi;
|
||||||
uint16 path_offset;
|
uint16 path_offset;
|
||||||
@@ -484,7 +563,7 @@ writeFile(const char *file, const uint8 *data, size_t len) {
|
|||||||
// check if all the path components exist
|
// check if all the path components exist
|
||||||
{
|
{
|
||||||
const char *ptr;
|
const char *ptr;
|
||||||
char path[MAXPATHLEN];
|
char path[PATH_MAX];
|
||||||
|
|
||||||
ptr = file;
|
ptr = file;
|
||||||
if (ptr[0] == '/')
|
if (ptr[0] == '/')
|
||||||
@@ -515,10 +594,10 @@ writeFile(const char *file, const uint8 *data, size_t len) {
|
|||||||
ssize_t written;
|
ssize_t written;
|
||||||
written = write(fd, data, len);
|
written = write(fd, data, len);
|
||||||
if (written < 0) {
|
if (written < 0) {
|
||||||
if (errno != EINTR) {
|
if (errno == EINTR)
|
||||||
perror("write failed");
|
continue;
|
||||||
exit(1);
|
perror("write failed");
|
||||||
}
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
len -= written;
|
len -= written;
|
||||||
data += written;
|
data += written;
|
||||||
@@ -526,43 +605,136 @@ writeFile(const char *file, const uint8 *data, size_t len) {
|
|||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If everything is ok, 0 is returned.
|
||||||
|
// Returns -1 on error, in which case errno is set.
|
||||||
|
int
|
||||||
|
copyFileSegment(const char *src, FILE *inFile, size_t offset,
|
||||||
|
const char *dest, size_t size) {
|
||||||
|
FILE *outFile;
|
||||||
|
#define BUFSIZE 4096
|
||||||
|
uint8 buf[BUFSIZE];
|
||||||
|
|
||||||
|
if (fseek(inFile, offset, SEEK_SET) == -1) {
|
||||||
|
int savedErrno = errno;
|
||||||
|
fprintf(stderr, "Seeking in input file %s (to %ld) failed: %s.\n",
|
||||||
|
src, (long int) offset, strerror(errno));
|
||||||
|
errno = savedErrno;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
outFile = fopen(dest, "wb");
|
||||||
|
if (outFile == NULL) {
|
||||||
|
int savedErrno = errno;
|
||||||
|
fprintf(stderr, "Opening output file %s failed: %s.\n",
|
||||||
|
dest, strerror(errno));
|
||||||
|
errno = savedErrno;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (size > 0) {
|
||||||
|
size_t toRead;
|
||||||
|
size_t numRead;
|
||||||
|
size_t numWritten;
|
||||||
|
|
||||||
|
toRead = sizeof buf;
|
||||||
|
if (toRead > size)
|
||||||
|
toRead = size;
|
||||||
|
|
||||||
|
do {
|
||||||
|
numRead = fread(buf, 1, toRead, inFile);
|
||||||
|
} while (ferror(inFile) && errno == EINTR);
|
||||||
|
if (numRead != toRead) {
|
||||||
|
if (ferror(inFile)) {
|
||||||
|
int savedErrno = errno;
|
||||||
|
fprintf(stderr, "Error reading file %s: %s.\n", src,
|
||||||
|
strerror(errno));
|
||||||
|
fclose(outFile);
|
||||||
|
errno = savedErrno;
|
||||||
|
return -1;
|
||||||
|
} else {
|
||||||
|
// EOF
|
||||||
|
assert(feof(inFile));
|
||||||
|
fprintf(stderr, "Unexpected end-of-file while reading "
|
||||||
|
"file %s.\n", src);
|
||||||
|
fclose(outFile);
|
||||||
|
errno = EIO;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
numWritten = fwrite(buf, 1, numRead, outFile);
|
||||||
|
} while (ferror(outFile) && errno == EINTR);
|
||||||
|
if (numWritten != numRead) {
|
||||||
|
int savedErrno = errno;
|
||||||
|
fprintf(stderr, "Error writing to file %s: %s.\n", dest,
|
||||||
|
strerror(errno));
|
||||||
|
fclose(outFile);
|
||||||
|
errno = savedErrno;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
size -= numWritten;
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(outFile);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only for packaged files.
|
||||||
void
|
void
|
||||||
writeFiles(const index_header *h, const uint8 *data, const char *path) {
|
writeFiles(const index_header *h, const uint8 *data, const char *path) {
|
||||||
int i;
|
int i;
|
||||||
char filename[MAXPATHLEN];
|
char filename[PATH_MAX];
|
||||||
int num_types, num_instances;
|
int num_types, num_instances;
|
||||||
|
|
||||||
for (i = 0; i < h->num_packages; i++) {
|
for (i = 0; i < h->num_packages; i++) {
|
||||||
|
package_desc *package = &h->package_list[i];
|
||||||
int j;
|
int j;
|
||||||
|
FILE *inFile = NULL;
|
||||||
|
|
||||||
|
if (package->filename != NULL) {
|
||||||
|
inFile = fopen(package->filename, "rb");
|
||||||
|
if (inFile == NULL) {
|
||||||
|
fprintf(stderr, "Error: Could not open input file %s.\n",
|
||||||
|
package->filename);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
num_types = h->package_list[i].num_types;
|
num_types = h->package_list[i].num_types;
|
||||||
for (j = 0; j < num_types; j++) {
|
for (j = 0; j < num_types; j++) {
|
||||||
|
packtype_desc *type = &package->type_list[j];
|
||||||
int k;
|
int k;
|
||||||
|
|
||||||
num_instances = h->package_list[i].type_list[j].num_instances;
|
num_instances = type->num_instances;
|
||||||
for (k = 0; k < num_instances; k++) {
|
for (k = 0; k < num_instances; k++) {
|
||||||
sprintf(filename, "%s/%08x",
|
packdef_instance *instance = &type->instances[k];
|
||||||
path,
|
sprintf(filename, "%s/%08x", path,
|
||||||
MAKE_RESOURCE(i + 1,
|
MAKE_RESOURCE(i + 1, type->type,
|
||||||
h->package_list[i].type_list[j].type,
|
type->first_instance + k));
|
||||||
h->package_list[i].type_list[j].first_instance + k));
|
|
||||||
#if 0
|
#if 0
|
||||||
sprintf(filename, "%s/%08x=%03x-%02x-%03x",
|
sprintf(filename, "%s/%08x=%03x-%02x-%03x",
|
||||||
path,
|
path,
|
||||||
MAKE_RESOURCE(i + 1,
|
MAKE_RESOURCE(i + 1, type->type,
|
||||||
h->package_list[i].type_list[j].type,
|
type->first_instance + k), i + 1, type->type,
|
||||||
h->package_list[i].type_list[j].first_instance + k),
|
type->first_instance + k);
|
||||||
i + 1,
|
|
||||||
h->package_list[i].type_list[j].type,
|
|
||||||
h->package_list[i].type_list[j].first_instance + k);
|
|
||||||
#endif
|
#endif
|
||||||
writeFile(filename,
|
if (package->filename != NULL) {
|
||||||
&data[h->package_list[i].type_list[j].instances[k].
|
// Resource is contained in a different file.
|
||||||
offset],
|
copyFileSegment(instance->filename, inFile,
|
||||||
h->package_list[i].type_list[j].instances[k].size);
|
instance->offset, filename, instance->size);
|
||||||
|
} else {
|
||||||
|
// Resource is contained in this package file itself.
|
||||||
|
writeFile(filename, &data[instance->offset],
|
||||||
|
instance->size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (inFile != NULL)
|
||||||
|
fclose(inFile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -13,6 +13,7 @@
|
|||||||
* along with this program; if not, write to the Free Software
|
* along with this program; if not, write to the Free Software
|
||||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||||
*/
|
*/
|
||||||
|
#include <stdbool.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
typedef unsigned char uint8;
|
typedef unsigned char uint8;
|
||||||
@@ -73,7 +74,7 @@ typedef struct {
|
|||||||
} package_desc;
|
} package_desc;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8 res_flags;
|
bool packaged;
|
||||||
uint32 packmem_list_offs;
|
uint32 packmem_list_offs;
|
||||||
uint32 path_list_offs;
|
uint32 path_list_offs;
|
||||||
uint32 file_list_offs;
|
uint32 file_list_offs;
|
||||||
|
|||||||
Reference in New Issue
Block a user