Example #1
0
char *load_utf_string_table(FILE *infile, const long offset)
{
    const struct utf_query_result result = query_utf_nofail(infile, offset, NULL);

    const size_t string_table_size = result.data_offset - result.string_table_offset;
    const long string_table_offset = offset + 8 + result.string_table_offset;
    char *string_table = malloc(string_table_size + 1);

    CHECK_ERRNO (!string_table, "malloc");
    memset(string_table, 0, string_table_size+1);
    get_bytes_seek(string_table_offset, infile,
                   (unsigned char *)string_table, string_table_size);

    return string_table;
}
Example #2
0
uint8_t * get_whole_file(FILE *infile, long *file_size_p)
{
    const long file_size = get_file_size(infile);

    if (file_size_p)
    {
        *file_size_p = file_size;
    }

    uint8_t *indata = malloc(file_size);
    CHECK_ERRNO(!indata, "malloc");

    // dump whole file
    get_bytes_seek(0, infile, indata, file_size);

    return indata;
}
Example #3
0
long uncompress(reader_t *infile, long offset, long input_size, FILE *outfile)
{
    unsigned char *output_buffer = NULL;
    CHECK_ERROR( !(
          (get_32_le_seek(offset+0x00, infile) == 0 &&
           get_32_le_seek(offset+0x04, infile) == 0) ||
          (get_64_be_seek(offset+0x00, infile) == CRILAYLA_sig)
        ), "didn't find 0 or CRILAYLA signature for compressed data");

    const long uncompressed_size = 
        get_32_le_seek(offset+0x08, infile);

    const long uncompressed_header_offset =
        offset + get_32_le_seek(offset+0x0C, infile)+0x10;

    CHECK_ERROR( uncompressed_header_offset + 0x100 != offset + input_size, "size mismatch");

    output_buffer = malloc(uncompressed_size + 0x100);
    CHECK_ERROR(!output_buffer, "malloc");

    get_bytes_seek(uncompressed_header_offset, infile, output_buffer, 0x100);

    const long input_end = offset + input_size - 0x100 - 1;
    long input_offset = input_end;
    const long output_end = 0x100 + uncompressed_size - 1;
    uint8_t bit_pool = 0;
    int bits_left = 0;
    long bytes_output = 0;

    while ( bytes_output < uncompressed_size )
    {
        if (GET_NEXT_BITS(1))
        {
            long backreference_offset =
                output_end-bytes_output+GET_NEXT_BITS(13)+3;
            long backreference_length = 3;

            // decode variable length coding for length
            enum { vle_levels = 4 };
            int vle_lens[vle_levels] = { 2, 3, 5, 8 };
            int vle_level;
            for (vle_level = 0; vle_level < vle_levels; vle_level++)
            {
                int this_level = GET_NEXT_BITS(vle_lens[vle_level]);
                backreference_length += this_level;
                if (this_level != ((1 << vle_lens[vle_level])-1)) break;
            }
            if (vle_level == vle_levels)
            {
                int this_level;
                do
                {
                    this_level = GET_NEXT_BITS(8);
                    backreference_length += this_level;
                } while (this_level == 255);
            }

            //printf("0x%08lx backreference to 0x%lx, length 0x%lx\n", output_end-bytes_output, backreference_offset, backreference_length);
            for (int i=0;i<backreference_length;i++)
            {
                output_buffer[output_end-bytes_output] = output_buffer[backreference_offset--];
                bytes_output++;
            }
        }
        else
        {
            // verbatim byte
            output_buffer[output_end-bytes_output] = GET_NEXT_BITS(8);
            //printf("0x%08lx verbatim byte\n", output_end-bytes_output);
            bytes_output++;
        }
    }

    put_bytes_seek(0, outfile, output_buffer, 0x100 + uncompressed_size);
    free(output_buffer);

    return 0x100 + bytes_output;
}
Example #4
0
void analyze_Huf8(FILE *infile, FILE *outfile, long file_length)
{
    unsigned char *decode_table = NULL;
    int decode_table_size;
    long decoded_length;
    int symbol_count;

    /* read header */
    {
        unsigned char buf[5];
        get_bytes_seek(0, infile, buf, 5);
        CHECK_ERROR (buf[0] != 0x28, "not 8-bit Huffman");
        decoded_length = read_24_le(&buf[1]);
        symbol_count = buf[4] + 1;
    }

    /* allocate decode table */
    decode_table_size = symbol_count * 2 - 1;
    decode_table = malloc(decode_table_size);
    CHECK_ERRNO(decode_table == NULL, "malloc");

    /* read decode table */
    get_bytes(infile, decode_table, decode_table_size);

#if 0
    printf("encoded size = %ld bytes (%d header + %ld body)\n",
            file_length, 5 + decode_table_size,
            file_length - (5 + decode_table_size));
    printf("decoded size = %ld bytes\n", decoded_length);
#endif

    /* decode */
    {
        uint32_t bits;
        int bits_left = 0;
        int table_offset = 0;
        long bytes_decoded = 0;

        while ( bytes_decoded < decoded_length )
        {
            if (bits_left == 0)
            {
                bits = get_32_le(infile);
                bits_left = 32;
            }

            int current_bit = ((bits & 0x80000000) != 0);
            int next_offset = ((table_offset + 1) / 2 * 2) + 1 +
                (decode_table[table_offset] & 0x3f) * 2 +
                (current_bit ? 1 : 0);

#if 0
            printf("%d %02x %lx => %lx\n", current_bit,
                    decode_table[table_offset],
                    (unsigned long)table_offset,
                    (unsigned long)next_offset);
#endif

            CHECK_ERROR (next_offset >= decode_table_size,
                    "reading past end of decode table");

            if ((!current_bit && (decode_table[table_offset] & 0x80)) ||
                ( current_bit && (decode_table[table_offset] & 0x40)))
            {
                CHECK_FILE(
                    fwrite(&decode_table[next_offset], 1, 1, outfile) != 1,
                    outfile, "fwrite");
                bytes_decoded++;
#if 0
                printf("%02x\n", decode_table[next_offset]);
                return;
#endif
                next_offset = 0;
            }

            CHECK_ERROR (next_offset == table_offset,
                    "stuck in a loop somehow");
            table_offset = next_offset;
            bits_left--;
            bits <<= 1;
        }
    }

#if 0
    printf("done\n");
#endif
}
Example #5
0
struct utf_query_result analyze_utf(FILE *infile, const long offset, int indent, int print, const struct utf_query *query)
{
    unsigned char buf[4];
    struct utf_table_info table_info;
    char *string_table = NULL;
    struct utf_column_info * schema = NULL;
    struct utf_query_result result;

    result.valid = 0;

    if (print)
    {
        fprintf_indent(stdout, indent);
        printf("{\n");
    }

    indent += INDENT_LEVEL;

    table_info.table_offset = offset;

    /* check header */
    static const char UTF_signature[4] = "@UTF"; /* intentionally unterminated */
    get_bytes_seek(offset, infile, buf, 4);
    if (memcmp(buf, UTF_signature, sizeof(UTF_signature)))
    {
        if (print)
        {
            fprintf_indent(stdout, indent);
            printf("not a @UTF table at %08" PRIx32 "\n", (uint32_t)offset);
        }
        goto cleanup;
    }

    /* get table size */
    table_info.table_size = get_32_be(infile);

    table_info.schema_offset = 0x20;
    table_info.rows_offset = get_32_be(infile);
    table_info.string_table_offset = get_32_be(infile);
    table_info.data_offset = get_32_be(infile);
    const uint32_t table_name_string = get_32_be(infile);
    table_info.columns = get_16_be(infile);
    table_info.row_width = get_16_be(infile);
    table_info.rows = get_32_be(infile);

    /* allocate for string table */
    const int string_table_size =
        table_info.data_offset-table_info.string_table_offset;
    string_table = malloc(string_table_size+1);
    CHECK_ERRNO(!string_table, "malloc");
    table_info.string_table = string_table;
    memset(string_table, 0, string_table_size+1);

    /* load schema */
    schema = malloc(sizeof(struct utf_column_info) * table_info.columns);
    CHECK_ERRNO(!schema, "malloc");
    {
        int i;
        for (i = 0; i < table_info.columns; i++)
        {
            schema[i].type = get_byte(infile);
            schema[i].column_name = string_table + get_32_be(infile);

            if ((schema[i].type & COLUMN_STORAGE_MASK) == COLUMN_STORAGE_CONSTANT)
            {
                schema[i].constant_offset = ftell(infile);
                switch (schema[i].type & COLUMN_TYPE_MASK)
                {
                case COLUMN_TYPE_STRING:
                    get_32_be(infile);
                    break;
                case COLUMN_TYPE_8BYTE:
                case COLUMN_TYPE_DATA:
                    get_32_be(infile);
                    get_32_be(infile);
                    break;
                case COLUMN_TYPE_FLOAT:
                case COLUMN_TYPE_4BYTE2:
                case COLUMN_TYPE_4BYTE:
                    get_32_be(infile);
                    break;
                case COLUMN_TYPE_2BYTE2:
                case COLUMN_TYPE_2BYTE:
                    get_16_be(infile);
                    break;
                case COLUMN_TYPE_1BYTE2:
                case COLUMN_TYPE_1BYTE:
                    get_byte(infile);
                    break;
                default:
                    CHECK_ERROR(1, "unknown type for constant");
                }
            }
        }
    }

    table_info.schema = schema;

    /* read string table */
    get_bytes_seek(table_info.string_table_offset+8+offset,
                   infile, (unsigned char *)string_table, string_table_size);
    table_info.table_name = table_info.string_table+table_name_string;

#if 0
    if (print)
    {
        fprintf_table_info(stdout, &table_info, indent);
    }
#endif

    /* fill in the default stuff */
    result.valid = 1;
    result.found = 0;
    result.rows = table_info.rows;
    result.name_offset = table_name_string;
    result.string_table_offset = table_info.string_table_offset;
    result.data_offset = table_info.data_offset;

    /* explore the values */
    if (query || print) {
        int i, j;

        for (i = 0; i < table_info.rows; i++)
        {
            if (!print && query && i != query->index) continue;

            uint32_t row_offset =
                table_info.table_offset + 8 + table_info.rows_offset +
                i * table_info.row_width;
            const uint32_t row_start_offset = row_offset;

            if (print)
            {
                fprintf_indent(stdout, indent);
                printf("%s[%d] = {\n", table_info.table_name, i);
            }
            indent += INDENT_LEVEL;
            for (j = 0; j < table_info.columns; j++)
            {
                uint8_t type = table_info.schema[j].type;
                long constant_offset = table_info.schema[j].constant_offset;
                int constant = 0;

                int qthis = (query && i == query->index &&
                             !strcmp(table_info.schema[j].column_name, query->name));

                if (print)
                {
                    fprintf_indent(stdout, indent);
#if 1
                    printf("%08x %02x %s = ", row_offset-row_start_offset, type, table_info.schema[j].column_name);
#else
                    printf("%s = ", table_info.schema[j].column_name);
#endif
                }

                if (qthis)
                {
                    result.found = 1;
                    result.type = schema[j].type & COLUMN_TYPE_MASK;
                }

                switch (schema[j].type & COLUMN_STORAGE_MASK)
                {
                case COLUMN_STORAGE_PERROW:
                    break;
                case COLUMN_STORAGE_CONSTANT:
                    constant = 1;
                    break;
                case COLUMN_STORAGE_ZERO:
                    if (print)
                    {
                        printf("UNDEFINED\n");
                    }
                    if (qthis)
                    {
                        memset(&result.value, 0,
                               sizeof(result.value));
                    }
                    continue;
                default:
                    CHECK_ERROR(1, "unknown storage class");
                }

                if (1)
                {
                    long data_offset;
                    int bytes_read;

                    if (constant)
                    {
                        data_offset = constant_offset;
                        if (print)
                        {
                            printf("constant ");
                        }
                    }
                    else
                    {
                        data_offset = row_offset;
                    }

                    switch (type & COLUMN_TYPE_MASK)
                    {
                    case COLUMN_TYPE_STRING:
                    {
                        uint32_t string_offset;
                        string_offset = get_32_be_seek(data_offset, infile);
                        bytes_read = 4;
                        if (print)
                        {
                            printf("\"%s\"\n", table_info.string_table + string_offset);
                        }
                        if (qthis)
                        {
                            result.value.value_string = string_offset;
                        }
                    }
                    break;
                    case COLUMN_TYPE_DATA:
                    {
                        uint32_t vardata_offset, vardata_size;

                        vardata_offset = get_32_be_seek(data_offset, infile);
                        vardata_size = get_32_be(infile);
                        bytes_read = 8;
                        if (print)
                        {
                            printf("[0x%08" PRIx32 "]", vardata_offset);
                            printf(" (size 0x%08" PRIx32 ")\n", vardata_size);
                        }
                        if (qthis)
                        {
                            result.value.value_data.offset = vardata_offset;
                            result.value.value_data.size = vardata_size;
                        }

                        if (vardata_size != 0 && print)
                        {
                            /* assume that the data is another table */
                            analyze_utf(infile,
                                        table_info.table_offset + 8 +
                                        table_info.data_offset +
                                        vardata_offset,
                                        indent,
                                        print,
                                        NULL
                                       );
                        }
                    }
                    break;

                    case COLUMN_TYPE_8BYTE:
                    {
                        uint64_t value =
                            get_64_be_seek(data_offset, infile);
                        if (print)
                        {
                            printf("0x%" PRIx64 "\n", value);
                        }
                        if (qthis)
                        {
                            result.value.value_u64 = value;
                        }
                        bytes_read = 8;
                        break;
                    }
                    case COLUMN_TYPE_4BYTE2:
                        if (print)
                        {
                            printf("type 2 ");
                        }
                    case COLUMN_TYPE_4BYTE:
                    {
                        uint32_t value =
                            get_32_be_seek(data_offset, infile);
                        if (print)
                        {
                            printf("%" PRId32 "\n", value);
                        }
                        if (qthis)
                        {
                            result.value.value_u32 = value;
                        }
                        bytes_read = 4;
                    }
                    break;
                    case COLUMN_TYPE_2BYTE2:
                        if (print)
                        {
                            printf("type 2 ");
                        }
                    case COLUMN_TYPE_2BYTE:
                    {
                        uint16_t value =
                            get_16_be_seek(data_offset, infile);
                        if (print)
                        {
                            printf("%" PRId16 "\n", value);
                        }
                        if (qthis)
                        {
                            result.value.value_u16 = value;
                        }
                        bytes_read = 2;
                    }
                    break;
                    case COLUMN_TYPE_FLOAT:
                        if (sizeof(float) == 4)
                        {
                            union {
                                float float_value;
                                uint32_t int_value;
                            } int_float;

                            int_float.int_value = get_32_be_seek(data_offset, infile);
                            if (print)
                            {
                                printf("%f\n", int_float.float_value);
                            }
                            if (qthis)
                            {
                                result.value.value_float = int_float.float_value;
                            }
                        }
                        else
                        {
                            get_32_be_seek(data_offset, infile);
                            if (print)
                            {
                                printf("float\n");
                            }
                            if (qthis)
                            {
                                CHECK_ERROR(1, "float is wrong size, can't return");
                            }
                        }
                        bytes_read = 4;
                        break;
                    case COLUMN_TYPE_1BYTE2:
                        if (print)
                        {
                            printf("type 2 ");
                        }
                    case COLUMN_TYPE_1BYTE:
                    {
                        uint8_t value =
                            get_byte_seek(data_offset, infile);
                        if (print)
                        {
                            printf("%" PRId8 "\n", value);
                        }
                        if (qthis)
                        {
                            result.value.value_u8 = value;
                        }
                        bytes_read = 1;
                    }
                    break;
                    default:
                        CHECK_ERROR(1, "unknown normal type");
                    }

                    if (!constant)
                    {
                        row_offset += bytes_read;
                    }
                } /* useless if end */
            } /* column for loop end */
            indent -= INDENT_LEVEL;
            if (print)
            {
                fprintf_indent(stdout,indent);
                printf("}\n");
            }

            CHECK_ERROR(row_offset - row_start_offset != table_info.row_width,
                        "column widths do now add up to row width");

            if (query && !print && i >= query->index) break;
        } /* row for loop end */
    } /* explore values block end */

cleanup:
    indent -= INDENT_LEVEL;
    if (print)
    {
        fprintf_indent(stdout, indent);
        printf("}\n");
    }

    if (string_table)
    {
        free(string_table);
        string_table = NULL;
    }

    if (schema)
    {
        free(schema);
        schema = NULL;
    }

    return result;
}
Example #6
0
void process_dir_list(long dir_offset, long table_size, long data_size, FILE *infile)
{
    long data_offset = dir_offset + table_size;

    const uint32_t dir_count = get_32_le_seek(dir_offset, infile);
    dir_offset += 4;

    // offset to info on files
    long file_offset = dir_offset;

    // advance file offset to where file info starts
    for (uint32_t i = 0; i < dir_count; i++)
    {
        CHECK_ERROR(file_offset >= data_offset, "read beyond table");
        const uint32_t name_size = get_32_le_seek(file_offset, infile);
        file_offset += 4 + name_size;
    }

    // dirs
    for (uint32_t i = 0; i < dir_count; i++)
    {
        CHECK_ERROR(dir_offset >= data_offset, "read beyond table");

        const uint32_t dir_name_size = get_32_le_seek(dir_offset, infile);
        dir_offset +=4 ;

        dump(infile, stdout, dir_offset, dir_name_size);
        printf("\n");
        dir_offset += dir_name_size;

        if (file_offset == data_offset) break;

        const uint32_t file_count = get_32_le_seek(file_offset, infile);
        file_offset += 4;

        // contents of dir
        for (uint32_t j = 0; j < file_count; j++)
        {
            CHECK_ERROR(file_offset >= data_offset, "read beyond table");
            const uint32_t file_name_size = get_32_le_seek(file_offset, infile);
            file_offset += 4;

            printf("  ");
            dump(infile, stdout, file_offset, file_name_size);
            file_offset += file_name_size;

            CHECK_ERROR(get_32_le_seek(file_offset, infile) != 0, "zernooo");
            const uint32_t offset = get_32_le_seek(file_offset+4, infile)+data_offset;
            const uint32_t size = get_32_le_seek(file_offset+8, infile);
            printf(": offset 0x%"PRIx32" size 0x%"PRIx32"\n",offset,size);
            {
                unsigned char namebuf[file_name_size+1];
                get_bytes_seek(file_offset-file_name_size,infile,namebuf,file_name_size);
                namebuf[file_name_size-1]='\0';
                FILE *outfile = fopen((char*)namebuf,"wb");
                CHECK_ERRNO(outfile == NULL,"fopen");
                dump(infile, outfile, offset+0x38, size-0x38);
                CHECK_ERRNO(fclose(outfile) == EOF,"fclose");
            }
            file_offset += 0xc;
        }
    }
}
Example #7
0
void analyze_CPK(FILE *infile, long file_length, struct cpk_file *file, int new_file_count)
{
    const long CpkHeader_offset = 0x0;
    char *toc_string_table = NULL;

    /* check header */
    {
        unsigned char buf[4];
        static const char CPK_signature[4] = "CPK "; /* intentionally unterminated */
        get_bytes_seek(CpkHeader_offset, infile, buf, 4);
        CHECK_ERROR (memcmp(buf, CPK_signature, sizeof(CPK_signature)), "CPK signature not found");
    }

    /* check CpkHeader */
    {
        struct utf_query_result result = query_utf_nofail(infile, CpkHeader_offset+0x10, NULL);

        CHECK_ERROR (result.rows != 1, "wrong number of rows in CpkHeader");
    }

    /* get TOC offset */
    long toc_offset = query_utf_8byte(infile, CpkHeader_offset+0x10, 0, "TocOffset");

    /* get content offset */
    long content_offset = query_utf_8byte(infile, CpkHeader_offset+0x10, 0, "ContentOffset");

    /* get file count from CpkHeader */
    long CpkHeader_count = query_utf_4byte(infile, CpkHeader_offset+0x10, 0, "Files");

	#ifdef DEBUG
		printf("(Debug)TocOffset: %d\n(Debug)ContentOffset: %d\n(Debug)Files(Count): %d\n",toc_offset,content_offset,CpkHeader_count);
	#endif

    /* check TOC header */
    {
        unsigned char buf[4];
        static const char TOC_signature[4] = "TOC "; /* intentionally unterminated */
        get_bytes_seek(toc_offset, infile, buf, 4);
        CHECK_ERROR (memcmp(buf, TOC_signature, sizeof(TOC_signature)), "TOC signature not found");
    }

    /* get TOC entry count, string table offset */
    long toc_entries;
    long toc_string_table_offset;
    long toc_string_table_size;
    {
        struct utf_query_result result = query_utf_nofail(infile, toc_offset+0x10, NULL);

        toc_entries = result.rows;
        toc_string_table_offset = toc_offset + 0x10 + 8 + result.string_table_offset;
        toc_string_table_size = result.data_offset - result.string_table_offset;
    }

	#ifdef DEBUG
		printf("(Debug)TocEntries: %d\n(Debug)TocStringTableOffset: %d\n(Debug)TocStringTableSize:%d\n",toc_entries,toc_string_table_offset,toc_string_table_size);
	#endif

    /* check that counts match */
    CHECK_ERROR( toc_entries != CpkHeader_count, "CpkHeader file count and TOC entry count do not match" );

    /* load string table */
    toc_string_table = malloc(toc_string_table_size + 1);
    {
        CHECK_ERRNO(!toc_string_table, "malloc");
        memset(toc_string_table, 0, toc_string_table_size+1);
        get_bytes_seek(toc_string_table_offset, infile,
                (unsigned char *)toc_string_table, toc_string_table_size);
    }

    /* find files in cpk */
    for (int i = 0; i < toc_entries; i++)
    {
        /* get file name */
        const char *file_name = query_utf_string(infile, toc_offset+0x10, i, "FileName", toc_string_table);
        
		const char *dir_name=query_utf_string(infile,toc_offset+0x10,i,"DirName",toc_string_table);
		
		/* to query a file with relative path, remember to free it */
		char* query_file=malloc(strlen(dir_name)+strlen(file_name)+2);

		strcpy(query_file,dir_name);

		char sep[]="/";
		
		strcat(query_file,sep);

		strcat(query_file,file_name);

        int entry_num = contains_file_name(query_file, file, new_file_count);
        if (entry_num >= 0)
        {
			#ifdef DEBUG
				printf("(Debug)FileName length:%d\n(Debug)DirName length:%d\n",strlen(file_name),strlen(dir_name));
				printf("(Debug)query file location:%s\n",query_file);
			#endif

            printf("Found %s/%s in cpk\n",dir_name, file_name);

            /* get file offset */
            file[entry_num].orig_offset = content_offset + query_utf_8byte(infile, toc_offset+0x10, i, "FileOffset");

            /* get file size */
            file[entry_num].orig_size = query_utf_4byte(infile, toc_offset+0x10, i, "FileSize");

            /* save index */
            file[entry_num].index = i;
            file[entry_num].found = 1;
			#ifdef DEBUG
				printf("(Debug)EntryNum:%d\n",entry_num);
			#endif
         }

		/* free the query_file to avoid leak */
		if(query_file)
			free(query_file);
    }

    sort_by_offset(file, new_file_count);
 
    FILE *outfile = fopen("out.cpk", "w+b");

    printf("Starting file copy\n");
    long current = 0;
    for (int i = 0; i < new_file_count; i++)
    {
        if (file[i].found)
        {
            /* copy from infile to start of current new file */
            dump(infile, outfile, current, file[i].orig_offset-current);
            current = file[i].orig_offset;
            
            /* open new file and copy data */
            FILE *newfile = fopen(file[i].location, "rb");
            CHECK_ERRNO(!newfile, "fopen");
            CHECK_ERRNO(fseek(newfile, 0 , SEEK_END) != 0, "fseek");
            file[i].new_size = ftell(newfile);
            CHECK_ERRNO(file_length == -1, "ftell");
            rewind(infile);
            printf("Copying %s(file name:%s)\n", file[i].location,file[i].filename);
            dump(newfile, outfile, 0, file[i].new_size);
            printf("Finished copying %s(file name:%s)\n", file[i].location,file[i].filename);
            fclose(newfile);
            
            /* update information */
            current += file[i].orig_size;
            file[i].copied = 1;
            file[i].offset_diff = file[i].new_size -file[i].orig_size;
        }
    }
     
    /* copy remaining data */
    dump(infile, outfile, current, file_length-current);
    printf("Finished file copy\n");
     
    /* fix toc_offset */
    toc_offset = fix_offset(outfile, CpkHeader_offset+0x10, 0, 0, "TocOffset", file, new_file_count);
    printf("Fixed toc offset\n");

    /* fix file offsets */
    for (int i = 0; i < toc_entries; i++)
        fix_offset(outfile, toc_offset+0x10, content_offset, i, "FileOffset", file, new_file_count);
    printf("Fixed file offsets\n");

    /* fix file sizes */
    for (int i = 0; i < new_file_count; i++)
        fix_file_sizes(outfile, toc_offset+0x10, file, i);

    printf("Finished replacing files and fixing data\n");
    CHECK_ERRNO(fclose(outfile) != 0, "fclose");

    if (toc_string_table)
    {
        free(toc_string_table);
        toc_string_table = NULL;
    }
}