Difference between revisions of "User:Magicus/Magicus's Tools/Parse-u8.c"

From WiiBrew
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.'''
 
: Sorry for the beta status, it's 2 am and I need to get some sleep ;-) but I thought it was better I released what I've done so far. Feel free to improve it. [[User:Magicus|Magicus]] 17:00, 1 March 2008 (PST)
 
  
 
<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 = "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 write_part(void* data, size_t size, char* name)
 
 
{
 
{
 
FILE *out;
 
FILE *out;
char filename[128];
 
  
  snprintf(filename, sizeof(filename), "%s_%s.bin", gamename, name);
+
out = fopen(name, "wb");
  filename[127] = '\0';
 
out = fopen(filename, "wb");
 
 
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 data_offset = be32((u8*)&node->data_offset);
+
     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];
     char* premarker;
+
     u8* file_data;
    char* postmarker;
 
 
      
 
      
 
     if (type == 0x0100) {
 
     if (type == 0x0100) {
       premarker = "";
+
       // Directory
       postmarker = "/";
+
      mkdir(name, 0777);
 +
      chdir(name);
 +
      dir_stack[++dir_index] = size;
 +
       printf("%*s%s/\n", dir_index, "", name);
 
     } else {
 
     } else {
       premarker = " ";
+
       // Normal file
       postmarker = "";
+
      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--;
 
     }
 
     }
   
 
    printf("%s%s%s (%d) offset: %x\n", premarker, name, postmarker, size, data_offset);
 
 
}
 
}
 
}
 
}
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);
+
  mkdir(outdir, 0777);
//  chdir(outdir);
+
  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;
}