Ejemplo n.º 1
0
def do_insert_tim(original_tim, edited_tim):
    header = 2048  # 0x800

    print("Inserting {}".format(original_tim))
    # Open TIM file
    original_tim = open(original_tim, "rb+")
    edited_tim = open(edited_tim, "rb").read()

    # Check if TIM file
    if edited_tim[0:4] == b'\x10\x00\x00\x00' and any(bpp in edited_tim[4:6] for bpp in (b'\x08\x00', b'\x09\x00')):

        # Check if it is a 4bpp or 8bpp TIM
        tim_colors: int = 0
        if edited_tim[16:18] == b'\x10\x00':  # 16 colors, 4bpp
            tim_colors: int = 16
        elif edited_tim[16:18] == b'\x00\x01':  # 256 colors, 8bpp
            tim_colors: int = 256
        # Read CLUT size to derive offsets for required TIM information
        tim_clut_size: int = bytes_to_uint(edited_tim[8:12])
        # Derive needed information
        tim_img_size: int = bytes_to_uint(edited_tim[tim_clut_size + 8: tim_clut_size + 12])
        tim_width: int = bytes_to_uint(edited_tim[tim_clut_size + 16: tim_clut_size + 18])
        tim_height: int = bytes_to_uint(edited_tim[tim_clut_size + 18: tim_clut_size + 20])
        tim_pixel_data: bytes = edited_tim[tim_clut_size + 20:]

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

        original_tim.seek(header)
        original_tim.write(bytearray(ord_pixel_data))
        original_tim.close()
Ejemplo n.º 2
0
def do_ord_pixel_data(tim_colors, tim_img_size, tim_width, tim_height, tim_pixel_data, encode=None):

    timcolors: int = 0
    timw: int = 0
    timh: int = 0
    ord_pixel_data: list = []

    if not encode:
        timcolors = bytes_to_uint(tim_colors)
        timh = bytes_to_uint(tim_height)
        timw = bytes_to_uint(tim_width)
        ord_pixel_data = [0] * (bytes_to_uint(tim_img_size) - 12)
    elif encode:
        timcolors = tim_colors
        timh = tim_height
        timw = tim_width
        ord_pixel_data = [0] * (tim_img_size - 12)

    blockw = 64
    blockh = 32

    rofs = 0

    if timcolors == 16:
        inc = 2
        blockw = blockw * 2
        timw = timw * 4  # Multiply by 4 to get the real width

        for y in range(0, timh, blockh):
            for x in range(0, timw, blockw):
                for by in range(0, blockh):
                    for bx in range(0, blockw, inc):
                        if not encode:
                            px = tim_pixel_data[rofs]
                            ord_pixel_data[((y + by) * (timw // 2)) + ((x + bx) // 2)] = px
                        else:
                            px = tim_pixel_data[((y + by) * (timw // 2)) + ((x + bx) // 2)]
                            ord_pixel_data[rofs] = px
                        rofs += 1
        return ord_pixel_data

    elif timcolors == 256:
        inc = 1
        timw = timw * 2  # Multiply by 2 to get the real width

        for y in range(0, timh, blockh):
            for x in range(0, timw, blockw):
                for by in range(0, blockh):
                    for bx in range(0, blockw, inc):
                        if not encode:
                            px = tim_pixel_data[rofs]
                            ord_pixel_data[((y + by) * timw) + (x + bx)] = px
                        else:
                            px = tim_pixel_data[((y + by) * timw) + (x + bx)]
                            ord_pixel_data[rofs] = px
                        rofs += 1
        return ord_pixel_data
Ejemplo n.º 3
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.")
Ejemplo n.º 4
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")
Ejemplo n.º 5
0
def do_extract_msg(file_path):
    print("\nExtracting {}".format(file_path))
    # Open MSG file
    msg_file = open(file_path, "rb").read()
    # Read the actual file size
    file_size = bytes_to_uint(msg_file[4:8])
    # Read pointer table size
    ptr_tbl_size = bytes_to_uint(msg_file[header:header + 2])
    # Read pointer table data
    ptr_tbl_data = msg_file[header:header + ptr_tbl_size]

    print("Pointer table contains {} blocks".format(int(ptr_tbl_size // 2)))

    output_file = open(file_path + ".txt", "w")

    ptr_tbl_offset = 0
    block_number = 0

    while ptr_tbl_offset < ptr_tbl_size:
        block_start_offset = header + bytes_to_uint(
            ptr_tbl_data[ptr_tbl_offset:ptr_tbl_offset + 2])
        # Accounting for the 0x0000 at the end of each block so -2
        block_end_offset = header + bytes_to_uint(
            ptr_tbl_data[ptr_tbl_offset + 2:ptr_tbl_offset + 4]) - 2
        # If we reached the end of the offset table, use the file size for the last bank
        if block_end_offset == 2048 - 2:
            # Accounting for the 0x0000 at the end of each block so -2
            block_end_offset = header + file_size - 2

        block_data = msg_file[block_start_offset:block_end_offset]

        # Write each block with offset information (add 2 to block end offset to account for 0x0000)
        output_file.write("[Block {:02X}, String: {:04X}-{:04X}]\n".format(
            block_number, block_start_offset, block_end_offset + 2))

        output_file.write(do_decode_block(block_data) + "\n\n")

        ptr_tbl_offset += 2
        block_number += 1

    output_file.close()
Ejemplo n.º 6
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()