def test_roundtrip(): #assert False with open("lzss3.py", "rb") as f: indata = f.read() out = BytesIO() compress(indata, out) compressed_data = out.getvalue() assert len(compressed_data) < len(indata) decompressed_data = decompress(out.getvalue()) assert indata == decompressed_data #same as above, but with lz11 out = BytesIO() compress_nlz11(indata, out) compressed_data = out.getvalue() assert len(compressed_data) < len(indata) decompressed_data = decompress(out.getvalue()) assert indata == decompressed_data
def explore_2(data_section, out_dir): screen_meta_raw, screen_data = parse_section_data(data_section) screen_meta = parse_screen_meta(screen_meta_raw) data = BytesIO(screen_data) with open(out_dir + '/meta.txt', 'w') as meta_fd: for n, entry in enumerate(screen_meta): data.seek(entry.offset) if entry.flag2: chunk = decompress(data) else: chunk = data.read(entry.length) with open(out_dir + '/s2_{:04}.bin'.format(n), 'wb') as data_fd: data_fd.write(chunk) print('{0:04} 0x{1.offset:06x} {1.flag1:d} 0x{2:06x} {1.flag2:d}'. format(n, entry, len(chunk)), file=meta_fd)
def main(): parser = argparse.ArgumentParser() parser.add_argument("script_file", help="Target *.xml.lz file") # parser.add_argument("-a", "--annotate", action="store_true", # help="Replace ") args = parser.parse_args() with open(args.script_file, 'rb') as text_file: data = decompress(text_file) data = BytesIO(data) assert data.read(4) == b'1LMG' # Seek to and read message pointers data.seek(8) pointers_offset, = unpack('<H', data.read(2)) data.seek(pointers_offset + 0x34) assert data.read(4) == b'\x2a\x00\x00\x00' # Not sure of the significance message_count, = unpack('<L', data.read(4)) messages = [] Message = namedtuple('Message', ['label_offset', 'message_pointer']) for m in range(message_count): messages.append(Message(*unpack('<LL', data.read(8)))) labels_pointer = data.tell() # XXX Can I actually *find* this anywhere? for message in messages: # Find the label and print it as a header label = get_label(data, labels_pointer + message.label_offset) print(label) print('=' * len(label)) # Extract the actual message message = message_iterator(data, message.message_pointer) message = decode_message(message) print(message, end='\n\n')
def explore_compressed_sections(data_section, skip, file_size, out_dir): BYTE_ALIGNMENT = 4 last_offset = 0 offset = 0 with open(out_dir + '/meta.txt', 'w') as meta_fd: while offset < file_size: #while offset < 0x0104d8: try: chunk = decompress(data_section) size = len(chunk) offset_str = r'0x{0:06x}'.format(offset) with open(out_dir + '/' + offset_str + '.bin', 'wb') as output: output.write(chunk) print(offset_str + r': 0x{:06x} 0x{:06x}'.format(offset, size), file=meta_fd) last_offset = offset offset += BYTE_ALIGNMENT except: offset += BYTE_ALIGNMENT data_section.seek(offset)
def explore_3(data_section, out_dir): screen_meta_raw, screen_data = parse_section_data(data_section) screen_meta = parse_screen_meta(screen_meta_raw) data = BytesIO(screen_data) with open(out_dir + '/meta.txt', 'w') as meta_fd: for n, entry in enumerate(screen_meta): data.seek(entry.offset) if entry.flag2 or entry.length > 0x5000: chunk = decompress(data) else: chunk = data.read(entry.length) if chunk[:4] == b'RNAN': ext = 'rnan' else: ext = 'bin' with open(out_dir + '/s3_{:04}.{}'.format(n, ext), 'wb') as data_fd: data_fd.write(chunk) print( '{0:04} 0x{1.offset:06x} {1.flag1:d} 0x{2:06x} {1.flag2:d} {3:4}' .format(n, entry, len(chunk), ext), file=meta_fd)
for n, section in enumerate(data_sections): output = open('/tmp/cpac/{0}'.format(n), 'wb') output.write(section) # Rip a palette that goes with the Capcom logo data = BytesIO(data_sections[0]) data.seek(0x2d80) capcom_palette = palette.parse(data.read(0x200)) # Rip the Capcom logo data = BytesIO(data_sections[2]) data.seek(0xa00) # Pointer found at 0x14 tiles = decompress(data) tiles = split_into_tiles(tiles) data.seek(0xa00 + 0xde8) screen = Screen(decompress(data)) image = screen.image([capcom_palette], tiles) with open('/tmp/logo.ppm', 'w') as output: # PPM header output.write( 'P3\n' '256 192\n' '31\n' )
data_sections = parse_cpac(cpac_2d) for n, section in enumerate(data_sections): output = open('/tmp/cpac/{0}'.format(n), 'wb') output.write(section) # Rip a palette that goes with the Capcom logo data = BytesIO(data_sections[0]) data.seek(0x2d80) capcom_palette = palette.parse(data.read(0x200)) # Rip the Capcom logo data = BytesIO(data_sections[2]) data.seek(0xa00) # Pointer found at 0x14 tiles = decompress(data) tiles = split_into_tiles(tiles) data.seek(0xa00 + 0xde8) screen = Screen(decompress(data)) image = screen.image([capcom_palette], tiles) with open('/tmp/logo.ppm', 'w') as output: # PPM header output.write('P3\n' '256 192\n' '31\n') for row in image: for pixel in row: print(pixel.r, pixel.g, pixel.b, file=output, end=' ')
def main(): parser = argparse.ArgumentParser() parser.add_argument("cpac_file", help="Target cpac_2d.bin file") parser.add_argument("-o", "--out_dir", help="directory for output files", default="out") # parser.add_argument("-a", "--annotate", action="store_true", # help="Replace ") args = parser.parse_args() if not os.path.exists(args.out_dir): os.makedirs(args.out_dir) # Dump cpac_2d.bin's sections to separate files for easier individual # staring-down with open(args.cpac_file, 'rb') as cpac_2d: data_sections = parse_cpac(cpac_2d) data = BytesIO(data_sections[0]) pallete_meta_raw, pallete_data = parse_section_data(data) pallete_meta = parse_pallete_meta(pallete_meta_raw) data = BytesIO(data_sections[2]) screen_meta_raw, screen_data = parse_section_data(data) screen_meta = parse_screen_meta(screen_meta_raw) gray_palette = dummy_gray_palette() IMAGE_LIST = [ ImageEntry('capcom', pallete_meta[0], screen_meta[0], PaletteBits.EIGHT, screen_meta[1]), ImageEntry('mobiclip', pallete_meta[1], screen_meta[2], PaletteBits.EIGHT, screen_meta[3]), ImageEntry('nintendo', pallete_meta[2], screen_meta[4], PaletteBits.FOUR, screen_meta[5]), ImageEntry('title-jp', pallete_meta[11], screen_meta[6], PaletteBits.EIGHT, screen_meta[7]), ImageEntry('title-en', pallete_meta[12], screen_meta[8], PaletteBits.EIGHT, screen_meta[9]), # ??? 10 -20 metal Shutter affect? # CREDITS # palette ? ImageEntry('folder1', pallete_meta[20], screen_meta[301], PaletteBits.FOUR, screen_meta[302]), # palette ? ImageEntry('folder2', pallete_meta[20], screen_meta[303], PaletteBits.FOUR, screen_meta[304]), # palette ? ImageEntry('box', pallete_meta[20], screen_meta[305], PaletteBits.FOUR, screen_meta[306]), ] for i in range(28): for z in range(5): offset = 21 + i * 10 + z IMAGE_LIST.append( ImageEntry('credits{:02}-{}'.format(i, z), pallete_meta[22], screen_meta[offset], PaletteBits.FOUR, screen_meta[offset + 5])) # for i in range(30): # #if pallete_meta[i].length == 0x200: # #if pallete_meta[i].length == 0x20: # IMAGE_LIST.append( # ImageEntry('unknown'+str(i), pallete_meta[i], screen_meta[301], PaletteBits.FOUR, screen_meta[302]), # ) for image_meta in IMAGE_LIST: print("Loading " + image_meta.image_name) # Rip a palette if image_meta.palette_entry: pallete_size = image_meta.palette_entry.length pallete_offset = image_meta.palette_entry.offset data = BytesIO(pallete_data) data.seek(pallete_offset) image_palette = palette.parse(data.read(pallete_size)) print("\tPalette 0x{0:06x} {1} bytes {2} colors".format( pallete_offset, pallete_size, len(image_palette))) else: image_palette = gray_palette tile_offset = image_meta.tile_entry.offset screen_offset = image_meta.screen_entry.offset data = BytesIO(screen_data) data.seek(tile_offset) if image_meta.tile_entry.flag2: tiles = decompress(data) else: tiles = data.read(image_meta.tile_entry.length) # Is there another way to figure this out? #if screen.get_max_tile() > len(tiles) / 64: if image_meta.tile_palette_bits == PaletteBits.FOUR: tiles = split_into_8x8_tiles_4bit(tiles) else: tiles = split_into_8x8_tiles_8bit(tiles) max_palette = max([entry for tile in tiles for entry in tile]) print("\tTiles 0x{0:06x} {1} 8x8 tiles max palette {2}".format( tile_offset, len(tiles), max_palette)) data.seek(screen_offset) if image_meta.screen_entry.flag2: data = decompress(data) else: data = data.read(image_meta.screen_entry.length) screen = Screen(data) max_tile = max([ntfs.tile for ntfs in screen.ntfs]) # if len(screen.ntfs) != 256*192/64: # raise ValueError('invalid ntfs size {0}'.format(len(screen.ntfs))) print("\tScreen 0x{0:06x} 256x128 max tile {1}".format( screen_offset, max_tile)) image = screen.image([image_palette], tiles) with open(args.out_dir + '/' + image_meta.image_name + '.ppm', 'w') as output: image_to_ppm(image, output)
"""Yield the message at the given pointer, character by character. Each character is two bytes long and little endian. """ data.seek(pointer) while True: char, = unpack('<H', data.read(2)) if char == 0xfffe: raise StopIteration else: yield char with open(argv[1], 'rb') as text_file: data = decompress(text_file) data = BytesIO(data) assert data.read(4) == b'1LMG' # Seek to and read message pointers data.seek(8) pointers_offset, = unpack('<H', data.read(2)) data.seek(pointers_offset + 0x34) assert data.read(4) == b'\x2a\x00\x00\x00' # Not sure of the significance message_count, = unpack('<L', data.read(4)) messages = [] Message = namedtuple('Message', ['label_offset', 'message_pointer'])