User:Magicus/Magicus's Tools/Parse-u8.c
Jump to navigation
Jump to search
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)
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;
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);
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
if (type != 0x0000) {
ERROR("Unknown type");
}
fseek(fp, my_data_offset, SEEK_SET);
file_data = malloc(size);
fread(file_data, 1, size, fp);
write_file(file_data, size, name);
free(file_data);
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;
}