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.'''
| + | これは、任天堂株式会社のCEOです。このサイトがダウンするか今の我々の利益の喪失を訴えて! |
− | | + | ==これは、任天堂株式会社のCEOです。このサイトがダウンするか今の我々の利益の喪失を訴えて!== |
− | <source lang="c">
| + | ===これは、任天堂株式会社のCEOです。このサイトがダウンするか今の我々の利益の喪失を訴えて!=== |
− | // parse-opening.c
| + | これは、任天堂株式会社のCEOです。このサイトがダウンするか今の我々の利益の喪失を訴えて! |
− | // Compile with:
| + | [[これは、任天堂株式会社のCEOです。このサイトがダウンするか今の我々の利益の喪失を訴えて!]] |
− | // gcc -g -DLARGE_FILES -D_FILE_OFFSET_BITS=64 -Wall -W -O2 -c -o parse-opening.o parse-opening.c
| |
− | // gcc -g -lcrypto parse-opening.o tools.o bn.o ec.o -o parse-opening
| |
− | // 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 1.0 Initial release
| |
− | | |
− | #define _GNU_SOURCE
| |
− | | |
− | #include <sys/types.h>
| |
− | #include <sys/stat.h>
| |
− | #include <unistd.h>
| |
− | | |
− | #include <string.h>
| |
− | #include <stdlib.h>
| |
− | #include <stdio.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 {
| |
− | u8 zeroes[0x40];
| |
− | u32 imet; // "IMET"
| |
− | u8 zero_six_zero_three[8]; // fixed, unknown purpose
| |
− | u32 sizes[3];
| |
− | u32 flag1;
| |
− | u16 name_jp[0x2a]; // might be empty
| |
− | u16 name_en[0x2a];
| |
− | u16 name_de[0x2a];
| |
− | u16 name_fr[0x2a];
| |
− | u16 name_es[0x2a];
| |
− | u16 name_it[0x2a];
| |
− | u16 name_nl[0x2a];
| |
− | u8 zeroes_2[0x348];
| |
− | u8 crypto[0x10];
| |
− | } imet_data_t;
| |
− | | |
− | typedef struct {
| |
− | u32 imd5_tag; // 0x494D4435 "IMD5";
| |
− | u32 size; // size of the rest of part B, starting from next field.
| |
− | u8 zeroes[8];
| |
− | u8 md5[16];
| |
− | u32 payload_tag; // 0x4C5A3737 "LZ77" if this is lz77
| |
− | u32 payload_data;
| |
− | } imd5_header_t;
| |
− | | |
− | 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 u8* decompress_lz77(u8 *data, size_t data_size, size_t* decompressed_size)
| |
− | {
| |
− | u8 *data_end;
| |
− | u8 *decompressed_data;
| |
− | size_t unpacked_size;
| |
− | u8 *in_ptr;
| |
− | u8 *out_ptr;
| |
− | u8 *out_end;
| |
− | | |
− | in_ptr = data;
| |
− | data_end = data + data_size;
| |
− | | |
− | // Assume this for now and grow when needed
| |
− | unpacked_size = data_size;
| |
− | | |
− | decompressed_data = malloc(unpacked_size);
| |
− | out_end = decompressed_data + unpacked_size;
| |
− |
| |
− | out_ptr = decompressed_data;
| |
− |
| |
− | while (in_ptr < data_end) {
| |
− | int bit;
| |
− | u8 bitmask = *in_ptr;
| |
− | | |
− | in_ptr++;
| |
− | for (bit = 0x80; bit != 0; bit >>= 1) {
| |
− | if (bitmask & bit) {
| |
− | // Next section is compressed
| |
− | u8 rep_length;
| |
− | u16 rep_offset;
| |
− |
| |
− | rep_length = (*in_ptr >> 4) + 3;
| |
− | rep_offset = *in_ptr & 0x0f;
| |
− | in_ptr++;
| |
− | rep_offset = *in_ptr | (rep_offset << 8);
| |
− | in_ptr++;
| |
− | if (out_ptr-decompressed_data < rep_offset) {
| |
− | ERROR("Inconsistency in LZ77 encoding");
| |
− | }
| |
− | | |
− | for ( ; rep_length > 0; rep_length--) {
| |
− | *out_ptr = out_ptr[-rep_offset-1];
| |
− | out_ptr++;
| |
− | if (out_ptr >= out_end) {
| |
− | // Need to grow buffer
| |
− | decompressed_data = realloc(decompressed_data, unpacked_size*2);
| |
− | out_ptr = decompressed_data + unpacked_size;
| |
− | unpacked_size *= 2;
| |
− | out_end = decompressed_data + unpacked_size;
| |
− | }
| |
− | }
| |
− | } else {
| |
− | // Just copy byte
| |
− | *out_ptr = *in_ptr;
| |
− | out_ptr++;
| |
− | if (out_ptr >= out_end) {
| |
− | // Need to grow buffer
| |
− | decompressed_data = realloc(decompressed_data, unpacked_size*2);
| |
− | out_ptr = decompressed_data + unpacked_size;
| |
− | unpacked_size *= 2;
| |
− | out_end = decompressed_data + unpacked_size;
| |
− | }
| |
− | in_ptr++;
| |
− | }
| |
− | }
| |
− | }
| |
− | | |
− | *decompressed_size = (out_ptr - decompressed_data);
| |
− | return decompressed_data;
| |
− | }
| |
− | | |
− | static void write_imd5_lz77(u8* data, size_t size, char* outname)
| |
− | {
| |
− | imd5_header_t* header = (imd5_header_t*) data;
| |
− | u32 tag;
| |
− | u32 size_in_imd5;
| |
− | u8 md5_calc[16];
| |
− | u8 *decompressed_data;
| |
− | size_t decompressed_size;
| |
− |
| |
− | tag = be32((u8*) &header->imd5_tag);
| |
− | if (tag != 0x494D4435) {
| |
− | ERROR("No IMD5 tag");
| |
− | }
| |
− |
| |
− | md5(data+32, size-32, md5_calc);
| |
− | if (memcmp(&header->md5, md5_calc, 0x10)) {
| |
− | ERROR("MD5 mismatch");
| |
− | }
| |
− | | |
− | size_in_imd5 = be32((u8*) &header->size);
| |
− | if (size_in_imd5 != size - 32) {
| |
− | ERROR("Size mismatch");
| |
− | }
| |
− | | |
− | tag = be32((u8*) &header->payload_tag);
| |
− | if (tag == 0x4C5A3737) {
| |
− | // "LZ77" - uncompress
| |
− | decompressed_data = decompress_lz77(data + sizeof(imd5_header_t), size - sizeof(imd5_header_t), &decompressed_size);
| |
− | write_file(decompressed_data, decompressed_size, outname);
| |
− | printf(", uncompressed %d bytes, md5 ok", decompressed_size);
| |
− |
| |
− | free(decompressed_data);
| |
− | } else {
| |
− | write_file(&header->payload_tag, size-32, outname);
| |
− | printf(", md5 ok");
| |
− | }
| |
− | }
| |
− | | |
− | 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);
| |
− | printf("%*s %s (%d bytes", dir_index, "", name, size);
| |
− | write_imd5_lz77(file_data, size, name);
| |
− | printf(")\n");
| |
− | current_offset += size;
| |
− | }
| |
− | | |
− | while (dir_stack[dir_index] == i+2 && dir_index > 0) {
| |
− | chdir("..");
| |
− | dir_index--;
| |
− | }
| |
− | }
| |
− | }
| |
− | | |
− | static void do_imet_header(void)
| |
− | {
| |
− | imet_data_t header;
| |
− | | |
− | fread(&header, 1, sizeof header, fp);
| |
− | | |
− | write_file(&header, sizeof(header), "header.imet");
| |
− | }
| |
− | | |
− | int main(int argc, char **argv)
| |
− | {
| |
− | char outdir_name[128];
| |
− | | |
− | if (argc == 3) {
| |
− | outdir = argv[2];
| |
− | } else if (argc != 2) {
| |
− | ERROR("Usage: parse-opening <file> [<outdir>]");
| |
− | } else {
| |
− | | |
− | snprintf(outdir_name, sizeof(outdir_name), "%s.out", 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_imet_header();
| |
− | do_U8_archive();
| |
− | | |
− | fclose(fp);
| |
− | | |
− | return 0;
| |
− | }
| |
− | </source>
| |
− | | |
− | ==See Also==
| |
− | [[LZ77]]
| |
− | [[Category:Local code]]
| |
− | [[Category:Software]] | |