示例#1
0
def do_extract_tim(file_path):
    header = 2048  # 0x800

    print("Extracting {}".format(file_path))
    # Open TIM file
    tim_file = open(file_path, "rb").read()

    # 4bpp and 8bpp TIM file
    if tim_file[0:4] == b'\x01\x00\x00\x00':
        tim_tag = b'\x10\x00\x00\x00'
        tim_bpp = b''
        tim_clut_size = b''
        if tim_file[20:22] == b'\x10\x00':  # 4bpp
            tim_clut_size = ulong_to_bytes((bytes_to_uint(tim_file[24:26]) * 32 + 12))
            tim_bpp = b'\x08\x00\x00\x00'
        elif tim_file[20:22] == b'\x00\x01':  # 8bpp
            tim_clut_size = ulong_to_bytes((bytes_to_uint(tim_file[24:26]) * 512 + 12))
            tim_bpp = b'\x09\x00\x00\x00'
        tim_fb_pal_x = tim_file[12:14]
        tim_fb_pal_y = tim_file[16:18]
        tim_colors = tim_file[20:22]
        tim_clut_num = tim_file[24:26]
        cluts = tim_file[256:256 + (bytes_to_uint(tim_clut_size) - 12)]
        tim_img_size = ulong_to_bytes((bytes_to_uint(tim_file[36:40]) * bytes_to_uint(tim_file[40:44]) * 2 + 12))
        tim_fb_img_x = tim_file[28:30]
        tim_fb_img_y = tim_file[32:34]
        tim_width = tim_file[36:38]
        tim_height = tim_file[40:42]
        tim_pixel_data: bytes = tim_file[header:]

        # Reversing nibble order should fix MML PC TIM files
        # tim_pixel_data = bytes(((x << 4 & 0xF0) + (x >> 4)) for x in tim_pixel_data)

        ord_pixel_data = do_ord_pixel_data(tim_colors, tim_img_size, tim_width, tim_height, tim_pixel_data, encode=False)

        # Write the decoded TIM to file
        output_file = open(file_path.split(".")[0] + "_EXT.TIM", "wb")
        output_file.write(
            tim_tag + tim_bpp + tim_clut_size + tim_fb_pal_x + tim_fb_pal_y + tim_colors + tim_clut_num +
            cluts + tim_img_size + tim_fb_img_x + tim_fb_img_y + tim_width + tim_height + bytearray(ord_pixel_data)
        )
        output_file.close()

    elif tim_file[0:4] == b'\x09\x00\x00\x00':
        print("CLUT only TIM file")

    elif tim_file[0:4] == b'\x0A\x00\x00\x00':
        print("CLUT Patch inside TIM file")
示例#2
0
def do_extract_font(file_path):
    print("Extracting {}".format(file_path))
    # Open FONT file
    font_file = open(file_path, "rb").read()

    # Create Header of TIM
    tim_tag = b'\x10\x00\x00\x00'
    tim_bpp = b'\x08\x00\x00\x00'
    tim_clut_size = b'\x2c\x00\x00\x00'
    tim_fb_pal_x = b'\x00\x00'  # Not known but needed
    tim_fb_pal_y = b'\x00\x00'  # Not known but needed
    tim_colors = b'\x10\x00'
    tim_clut_num = b'\x01\x00'
    # Palette = #000, #FFF, #BBB, #888
    clut = b'\x00\x00\xFF\xFF\xF7\xDE\xEF\xBD\x00\x00\x00\x00\x00\x00\x00\x00' \
           b'\x00\x00\xFF\xFF\xF7\xDE\xEF\xBD\x00\x00\x00\x00\x00\x00\x00\x00'
    tim_img_size = ulong_to_bytes((img_width // 4) * img_height * 2 + 12)
    tim_fb_img_x = b'\x00\x00'  # Not known but needed
    tim_fb_img_y = b'\x00\x00'  # Not known but needed
    tim_width = b'\x40\x00'
    tim_height = b'\x00\x02'
    tim_pixel_data = font_file[2048:]

    decoded_pixel_data_top = [0] * ((bytes_to_uint(tim_img_size) - 12) // 2)
    decoded_pixel_data_bottom = [0] * ((bytes_to_uint(tim_img_size) - 12) // 2)
    offset = 0

    for y in range(0, img_height // 2, block_height):
        for x in range(0, img_width, block_width):
            for by in range(0, block_height):
                for bx in range(0, block_width, 2):
                    px = tim_pixel_data[offset]
                    a = px & 0x03
                    b = px & 0x30
                    c = (px >> 2) & 0x03
                    d = (px >> 2) & 0x30
                    decoded_pixel_data_top[((y + by) * (img_width // 2)) +
                                           ((x + bx) // 2)] = b + a
                    decoded_pixel_data_bottom[((y + by) * (img_width // 2)) +
                                              ((x + bx) // 2)] = d + c
                    offset += 1

    output_file = open(file_path.split(".")[0] + ".TIM", "wb")
    output_file.write(tim_tag + tim_bpp + tim_clut_size + tim_fb_pal_x +
                      tim_fb_pal_y + tim_colors + tim_clut_num + clut +
                      tim_img_size + tim_fb_img_x + tim_fb_img_y + tim_width +
                      tim_height + bytearray(decoded_pixel_data_top) +
                      bytearray(decoded_pixel_data_bottom))
    output_file.close()

    print("\nFound font. Extraction complete.")
示例#3
0
def do_insert_msg(original_msg, text_file):
    print("\nInserting {}".format(original_msg))
    # Open TXT file
    text = open(text_file, "r").read()

    # Open MSG file
    msg_file = open(original_msg, "rb+")
    # Read the actual file size
    msg_file.seek(4)
    file_size = bytes_to_uint(msg_file.read(4))

    # Read pointer table size
    msg_file.seek(header)
    ptr_tbl_size = bytes_to_uint(msg_file.read(2))
    ptr_table: list = [ptr_tbl_size]

    print("Pointer table size is {} blocks ({} bytes)".format(
        ptr_tbl_size // 2, ptr_tbl_size))

    i = 0
    current_block = 1
    encoded_block: list = []

    while i < len(text):
        # Skip the [Blocks] text but separate them for recalculating pointers
        c = text[i]

        if c == '[':
            # Find the end of the textual Block info and start of next
            block_end = text.find(']', i + 1)
            next_block_start = text.find('[', i + 1)

            # If there is no more blocks after, read until the end of the file
            if next_block_start == -1:
                text_block = text[block_end + 2:-2]
            # If there is another block after, read until the beginning of the next block
            else:
                text_block = text[
                    block_end + 2:next_block_start -
                    2]  # Remove the \n\n at beginning and end of block

            # Encode text block to list of bytes
            encoded_text_block = do_encode_text_block(text_block)
            encoded_block.append(encoded_text_block)

            if current_block != ptr_tbl_size // 2:
                # Append the size of the encoded block to the pointer table
                ptr_table.append(ptr_table[-1] + len(encoded_text_block))
                current_block += 1

        i += 1

    # Convert pointer table int to sequence of bytes
    ptr_table_bytes: bytes = b''
    for items in ptr_table:
        if not items == file_size:
            ptr_table_bytes += (uint_to_bytes(items))

    # Convert list of lists of encoded blocks to bytes
    encoded_block_bytes = bytes(
        [val for sublist in encoded_block for val in sublist])
    print("Encoded text data size is {} bytes".format(
        len(encoded_block_bytes)))

    # Get size of file
    msg_file_size = msg_file.seek(0, os.SEEK_END)
    # Get size of new file
    new_file_size = header + len(ptr_table_bytes) + len(encoded_block_bytes)

    # Check if the new size is within the limits. Else throw and exception
    if new_file_size > msg_file_size:
        print(
            "ERROR: New MSG file is {} bytes. Size limit is {} bytes.".format(
                new_file_size, msg_file_size))
        exit()
    else:
        # Write new data to the MSG file
        msg_file.seek(header)
        msg_file.write(ptr_table_bytes + encoded_block_bytes)
        # Get offset after writing pointer table and encoded text
        current_offset = msg_file.tell()
        # Write the new file size to the header
        msg_file.seek(4)
        msg_file.write(ulong_to_bytes(current_offset - header))
        msg_file.seek(current_offset)
        msg_file.seek(current_offset)

        # Fill the rest of the file with 00
        while current_offset < msg_file_size:
            msg_file.write(b'\x00')
            current_offset += 1

    msg_file.close()