User:Magicus/Magicus's Tools/Parse-u8.c: Difference between revisions
Jump to navigation
Jump to search
Add instructions. |
Upgrading to version 1.0 which works. (Hey, wasn't I supposed to go to bed? ...) |
||
Line 1: | Line 1: | ||
'''Put this file in the same directory as a compiled version of [[Segher's Wii.git]] tools, since it depends on them.''' | '''Put this file in the same directory as a compiled version of [[Segher's Wii.git]] tools, since it depends on them.''' | ||
<pre> | <pre> | ||
Line 15: | Line 13: | ||
// Version 0.5 Beta version, just lists contents, doesn't yet extract files. | // Version 0.5 Beta version, just lists contents, doesn't yet extract files. | ||
// Version 1.0 Now extract files and re-create directory structure. | |||
#define _GNU_SOURCE | |||
#include <sys/stat.h> | #include <sys/stat.h> | ||
Line 37: | Line 37: | ||
static FILE *fp; | static FILE *fp; | ||
static char *outdir | static char *outdir; | ||
typedef struct | typedef struct | ||
Line 56: | Line 56: | ||
} U8_archive_header; | } U8_archive_header; | ||
static void write_file(void* data, size_t size, char* name) | |||
static void | |||
{ | { | ||
FILE *out; | FILE *out; | ||
out = fopen(name, "wb"); | |||
out = fopen( | |||
fwrite(data, 1, size, out); | fwrite(data, 1, size, out); | ||
fclose(out); | fclose(out); | ||
} | } | ||
Line 82: | Line 77: | ||
unsigned int i; | unsigned int i; | ||
u32 data_offset; | u32 data_offset; | ||
u32 current_offset; | |||
u16 dir_stack[16]; | |||
int dir_index = 0; | |||
fread(&header, 1, sizeof header, fp); | fread(&header, 1, sizeof header, fp); | ||
Line 97: | Line 95: | ||
data_offset = be32((u8*) &header.data_offset); | data_offset = be32((u8*) &header.data_offset); | ||
rest_size = data_offset - sizeof(header) - num_nodes*sizeof(U8_node); | rest_size = data_offset - sizeof(header) - (num_nodes+1)*sizeof(U8_node); | ||
string_table = malloc(rest_size); | string_table = malloc(rest_size); | ||
fread(string_table, 1, rest_size, fp); | fread(string_table, 1, rest_size, fp); | ||
current_offset = data_offset; | |||
for (i = 0; i < num_nodes; i++) { | for (i = 0; i < num_nodes; i++) { | ||
U8_node* node = &nodes[i]; | U8_node* node = &nodes[i]; | ||
u16 type = be16((u8*)&node->type); | u16 type = be16((u8*)&node->type); | ||
u16 name_offset = be16((u8*)&node->name_offset); | u16 name_offset = be16((u8*)&node->name_offset); | ||
u32 | u32 my_data_offset = be32((u8*)&node->data_offset); | ||
u32 size = be32((u8*)&node->size); | u32 size = be32((u8*)&node->size); | ||
char* name = (char*) &string_table[name_offset]; | char* name = (char*) &string_table[name_offset]; | ||
u8* file_data; | |||
if (type == 0x0100) { | if (type == 0x0100) { | ||
// Directory | |||
mkdir(name, 0777); | |||
chdir(name); | |||
dir_stack[++dir_index] = size; | |||
printf("%*s%s/\n", dir_index, "", name); | |||
} else { | } else { | ||
// Normal file | |||
u8 padding[32]; | |||
if (type != 0x0000) { | |||
ERROR("Unknown type"); | |||
} | |||
if (current_offset < my_data_offset) { | |||
int diff = my_data_offset - current_offset; | |||
if (diff > 32) { | |||
ERROR("Archive inconsistency, too much padding"); | |||
} | |||
fread(padding, 1, diff, fp); | |||
current_offset += diff; | |||
} | |||
file_data = malloc(size); | |||
fread(file_data, 1, size, fp); | |||
write_file(file_data, size, name); | |||
current_offset += size; | |||
printf("%*s %s (%d bytes)\n", dir_index, "", name, size); | |||
} | |||
while (dir_stack[dir_index] == i+2 && dir_index > 0) { | |||
chdir(".."); | |||
dir_index--; | |||
} | } | ||
} | } | ||
} | } | ||
Line 126: | Line 150: | ||
int main(int argc, char **argv) | int main(int argc, char **argv) | ||
{ | { | ||
char outdir_name[128]; | |||
if (argc == 3) { | if (argc == 3) { | ||
outdir = argv[2]; | outdir = argv[2]; | ||
} else if (argc != 2) { | } else if (argc != 2) { | ||
ERROR("Usage: parse-u8 <file> [<outdir>]"); | ERROR("Usage: parse-u8 <file> [<outdir>]"); | ||
} else { | |||
snprintf(outdir_name, sizeof(outdir_name), "%s.unpacked", basename(argv[1])); | |||
outdir_name[127] = '\0'; | |||
outdir = outdir_name; | |||
} | } | ||
printf("Extracting files to %s.\n", outdir); | |||
fp = fopen(argv[1], "rb"); | fp = fopen(argv[1], "rb"); | ||
mkdir(outdir, 0777); | |||
chdir(outdir); | |||
do_U8_archive(); | do_U8_archive(); | ||
Line 143: | Line 175: | ||
return 0; | return 0; | ||
} | } | ||
</pre> | </pre> |
Revision as of 04:25, 2 March 2008
Put this file in the same directory as a compiled version of Segher's Wii.git tools, since it depends on them.
// parse-u8.c // Compile with: // gcc -g -DLARGE_FILES -D_FILE_OFFSET_BITS=64 -Wall -W -O2 -c -o parse-u8.o parse-u8.c // gcc -g -lcrypto parse-u8.o tools.o bn.o ec.o -o parse-u8 // The other files are from segher's git repository, created by his Makefile. // Copyright 2008 Magicus <magicus@gmail.com> // Licensed under the terms of the GNU GPL, version 2 // http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt // Version 0.5 Beta version, just lists contents, doesn't yet extract files. // Version 1.0 Now extract files and re-create directory structure. #define _GNU_SOURCE #include <sys/stat.h> #include <sys/types.h> #include <string.h> #include <stdlib.h> #include <stdio.h> #include <unistd.h> #include "tools.h" #define ERROR(s) do { fprintf(stderr, s "\n"); exit(1); } while (0) // FIXME: this should really move to tools.c u16 be16(u8 *p) { return (p[0] << 8) | p[1]; } static FILE *fp; static char *outdir; typedef struct { u16 type; u16 name_offset; u32 data_offset; // == absolut offset från U.8- headerns början u32 size; // last included file num for directories } U8_node; typedef struct { u32 tag; // 0x55AA382D "U.8-" u32 rootnode_offset; // offset to root_node, always 0x20. u32 header_size; // size of header from root_node to end of string table. u32 data_offset; // offset to data -- this is rootnode_offset + header_size, aligned to 0x40. u8 zeroes[16]; } U8_archive_header; static void write_file(void* data, size_t size, char* name) { FILE *out; out = fopen(name, "wb"); fwrite(data, 1, size, out); fclose(out); } static void do_U8_archive(void) { U8_archive_header header; U8_node root_node; u32 tag; u32 num_nodes; U8_node* nodes; u8* string_table; size_t rest_size; unsigned int i; u32 data_offset; u32 current_offset; u16 dir_stack[16]; int dir_index = 0; fread(&header, 1, sizeof header, fp); tag = be32((u8*) &header.tag); if (tag != 0x55AA382D) { ERROR("No U8 tag"); } fread(&root_node, 1, sizeof(root_node), fp); num_nodes = be32((u8*) &root_node.size) - 1; printf("Number of files: %d\n", num_nodes); nodes = malloc(sizeof(U8_node) * (num_nodes)); fread(nodes, 1, num_nodes * sizeof(U8_node), fp); data_offset = be32((u8*) &header.data_offset); rest_size = data_offset - sizeof(header) - (num_nodes+1)*sizeof(U8_node); string_table = malloc(rest_size); fread(string_table, 1, rest_size, fp); current_offset = data_offset; for (i = 0; i < num_nodes; i++) { U8_node* node = &nodes[i]; u16 type = be16((u8*)&node->type); u16 name_offset = be16((u8*)&node->name_offset); u32 my_data_offset = be32((u8*)&node->data_offset); u32 size = be32((u8*)&node->size); char* name = (char*) &string_table[name_offset]; u8* file_data; if (type == 0x0100) { // Directory mkdir(name, 0777); chdir(name); dir_stack[++dir_index] = size; printf("%*s%s/\n", dir_index, "", name); } else { // Normal file u8 padding[32]; if (type != 0x0000) { ERROR("Unknown type"); } if (current_offset < my_data_offset) { int diff = my_data_offset - current_offset; if (diff > 32) { ERROR("Archive inconsistency, too much padding"); } fread(padding, 1, diff, fp); current_offset += diff; } file_data = malloc(size); fread(file_data, 1, size, fp); write_file(file_data, size, name); current_offset += size; printf("%*s %s (%d bytes)\n", dir_index, "", name, size); } while (dir_stack[dir_index] == i+2 && dir_index > 0) { chdir(".."); dir_index--; } } } int main(int argc, char **argv) { char outdir_name[128]; if (argc == 3) { outdir = argv[2]; } else if (argc != 2) { ERROR("Usage: parse-u8 <file> [<outdir>]"); } else { snprintf(outdir_name, sizeof(outdir_name), "%s.unpacked", basename(argv[1])); outdir_name[127] = '\0'; outdir = outdir_name; } printf("Extracting files to %s.\n", outdir); fp = fopen(argv[1], "rb"); mkdir(outdir, 0777); chdir(outdir); do_U8_archive(); fclose(fp); return 0; }