def convert_txa(filename, out_dir): data = ConstBitStream(filename=filename) out_template = os.path.join( out_dir, os.path.splitext(os.path.basename(filename))[0]) try: os.makedirs(out_template) except: pass magic = data.read("bytes:4") size = data.read("uintle:32") indexed = data.read("uintle:32") chunks = data.read("uintle:32") dec_size = data.read("uintle:32") unk2 = data.read("uintle:32") unk3 = data.read("uintle:32") unk4 = data.read("uintle:32") print(size, chunks, indexed) for i in range(chunks): hdr_len = data.read("uintle:16") index = data.read("uintle:16") w = data.read("uintle:16") h = data.read("uintle:16") entry_off = data.read("uintle:32") entry_len = data.read("uintle:32") name = data.read("bytes:%d" % (hdr_len - 16)).strip("\0") print(name, index, w, h, entry_off, entry_len) temp_pos = data.bytepos data.bytepos = entry_off # If we are zero size, we're not compressed. if entry_len == 0: if indexed: size = 1024 + (w * h) chunk = bytearray(data.read(size * 8).bytes) else: print("???") else: chunk = data.read(entry_len * 8) chunk = decompress(chunk) data.bytepos = temp_pos w = adjust_w(w) if indexed: chunk, masked = get_indexed(chunk, w, h, crop=False) else: chunk = get_rgba(chunk, w, h, crop=False) chunk.save("%s/%s.png" % (out_template, name)) # dump_to_file(chunk, "temp%d.dat" % index) ################################################################################
def convert_pic_umi(filename, out_file): data = ConstBitStream(filename=filename) magic = data.read("bytes:4") size = data.read("uintle:32") ew = data.read("uintle:16") eh = data.read("uintle:16") width = data.read("uintle:16") height = data.read("uintle:16") unk1 = data.read("uintle:32") chunks = data.read("uintle:32") image = QImage(width, height, QImage.Format_ARGB32) image.fill(0) painter = QPainter(image) for i in range(chunks): version = data.read("uintle:32") x = data.read("uintle:16") y = data.read("uintle:16") w = data.read("uintle:16") h = data.read("uintle:16") offset = data.read("uintle:32") size = data.read("uintle:32") # if not i == 1: # continue print w, h, size, offset temp_pos = data.bytepos data.bytepos = offset chunk = data.read(size * 8) data.bytepos = temp_pos chunk = decompress_umi(chunk) chunk = adjust_scanline(chunk, w, h) dump_to_file(chunk) chunk = QImage(chunk, w, h, QImage.Format_ARGB32) chunk.fill(0) # chunk.save("test.bmp") painter.drawImage(QRectF(x, y, w, h), chunk, QRectF((chunk.rect()))) # break painter.end() image.save(out_file) ################################################################################
def png_to_gim(self, png_file, gim_file=None, quant_type=QuantizeType.auto): # So there's no confusion. png_file = os.path.abspath(png_file) if gim_file == None: gim_file = os.path.splitext(png_file)[0] + ".gim" png_file = self.quantize_png(png_file, quant_type) data = ConstBitStream(filename=png_file) data.bytepos = 0x18 options = ["-jar", "tools/gimexport.jar", png_file, gim_file, "3"] depth = data.read("int:8") color_type = data.read("int:8") if color_type == 3: # Indexed options.append("true") else: options.append("false") self.process.start("java", options) self.process.waitForFinished(-1)
def extractXMP(self, filename): xmpStr = "" # Can initialise from files, bytes, etc. try: s = ConstBitStream(filename = filename) # Search for ":xmpmeta" string in file keepSearching = True while keepSearching: keepSearching = False colonXmpmetaInHexStr = '0x3a786d706d657461' foundSt = s.find(colonXmpmetaInHexStr, bytealigned=True) if foundSt: byteStart = (int(foundSt[0])//8) # The start of data can be "<xmp:xmpmeta" or "<x:xmpmeta" s.bytepos = byteStart - 4 prevals = s.peeklist("4*uint:8") prestr = ''.join(chr(i) for i in prevals) # print (prestr, prestr[2:]) if prestr == "<xmp": byteStart = byteStart - 4 prefix = "0x3c2f786d70" # "<\xmp" in hex elif prestr[2:] == "<x": byteStart = byteStart - 2 prefix = "0x3c2f78" # "<\x" in hex else: # print ("Cont") keepSearching = True continue # print("Found start code at byte offset %d." % byteStart) foundEnd = s.find(prefix + colonXmpmetaInHexStr, bytealigned=True) if foundEnd: byteEnd = (int(foundEnd[0])//8) s.bytepos = byteStart # print("Found end code at byte offset %d." % byteEnd) xmpBytes = s.readlist(str(byteEnd-byteStart+len(prefix)//2+9) +"*uint:8") xmpStr = ''.join(chr(i) for i in xmpBytes) #if "Rating" in xmpStr: # print (xmpStr) except: xmpStr = "" return xmpStr
def parseRootPage(fpt, pageSize): """ parse necessary information about the database file and return a dictionary of table/index names and its corresponding root page @param fpt: the file pointer of the database file @param pageSize: the page size of the database """ # read in the whole root page into memory bitstream = ConstBitStream(readPage(1, fpt, pageSize)) readCounts(-1) numPages = bitstreamReadAtOffset(bitstream, int, 'bytes:4', 28) # skip th db header and thus locate btree page header from the beginning bitstream.bytepos = DATABASE_FILE_HEADER_SIZE # get the type of page from offset relative to DATABASE_FILE_HEADER_SIZE and read one byte only; reset back to offset DATABASE_FILE_HEADER_SIZE pageFlag = bitstreamReadAtOffset(bitstream, int, 'bytes:1', DATABASE_FILE_HEADER_SIZE) # read number of cells inside the rootpage at offset 3 relative to the begining of page header and read two bytes; reset back to offset DATABASE_FILE_HEADER_SIZE numTables = bitstreamReadAtOffset(bitstream, int, 'bytes:2', DATABASE_FILE_HEADER_SIZE + 3) tables = {} # jump to the cell pointer array relative to offset DATABASE_FILE_HEADER_SIZE for i in range(0, numTables): # read two bytes at a time as a pointer from the cell pointer array relative to the beginning of the array; reset back to the beginning of cell pointer array each iteration cellPosition = bitstreamReadAtOffset( bitstream, int, 'bytes:2', LEAF_BTREE_PAGE_HEADER_SIZE + DATABASE_FILE_HEADER_SIZE + i * 2) # goes to the sqlite master table and find out the root page number; sqlite_master table is a table btree page _, record = parse_cell_content(cellPosition, bitstream, pageFlag, fpt, pageSize, isSqliteMaster=True) # store the table/index name and its root page tables.setdefault(record[1], record[-2]) # return the root page num return tables
def convert_bup(filename, out_dir): #For some reason saving the path to a non-existant directory doesn't give an error! #for this reason, force creation of the output directory before converting. pathlib.Path(out_dir).mkdir(parents=True, exist_ok=True) filesize = None with open(filename, 'rb') as f: test = f.read() filesize = len(test) print("File is of size: ", filesize) rc = RegionChecker(filesize) data = ConstBitStream(filename=filename) out_template = os.path.join( out_dir, os.path.splitext(os.path.basename(filename))[0]) bytePosStart = data.bytepos magic = data.read("bytes:4") if conf.SWITCH: unk_header_1 = data.read("uintle:32") size = data.read("uintle:32") ew = data.read("uintle:16") eh = data.read("uintle:16") width = data.read("uintle:16") height = data.read("uintle:16") tbl1 = data.read("uintle:32") base_chunks = data.read("uintle:32") #num expressions in switch version exp_chunks = data.read("uintle:32") #unnknown on switch version if conf.SWITCH: unk_header_2 = data.read("uintle:32") #unknown in switch version rc.add(bytePosStart, data.bytepos) if conf.debug: print('---------- BUP HEADER -----------') print("magic: ", magic) if conf.SWITCH: print("unk1: ", unk_header_1) print("size: ", size) print("EW, EH: ", ew, eh) print("Width: ", width) print("Height: ", height) print("tbl1: ", tbl1) print("basechunks:", base_chunks) print("exp_chunks:", exp_chunks) print("Section ends at {}{}".format(hex(base_chunks), hex(exp_chunks))) if conf.SWITCH: print("Unk2: ", unk_header_2) print() if conf.SWITCH: skip_amount = 32 * 3 else: skip_amount = 32 # Dunno what this is for. print("Skipping {} bits in the tbl1 header".format(tbl1 * skip_amount)) bytePosStart = data.bytepos for i in range(tbl1): print(data.read(skip_amount)) rc.add(bytePosStart, data.bytepos) base = QImage(width, height, QImage.Format_ARGB32) # See Documentation - this is used to differentiate between a pixel which has # never been written to and a fully transparent pixel base.fill(TRANSPARENT_COLOR) for i in range(base_chunks): try: print('--------- Decoding Base Chunk [{}]----------'.format(i)) offset = data.read("uintle:32") print("Testing offset", offset) if conf.SWITCH: bothChunkSize = data.read("uintle:32") print("bothChunkSize", bothChunkSize) rc.add(offset, offset + bothChunkSize - 1) temp_pos = data.bytepos chunk, x, y, masked = process_chunk(data, offset, bothChunkSize) if conf.debug_extra: chunk.save("%s_%d_Base_Chunk_%s.png" % (out_template, i, str(masked))) if conf.SWITCH: base = blit_switch(chunk, base, x, y, masked, False) else: base = blit(chunk, base, x, y, masked) except Exception as e: print("FAILED:") data.bytepos = temp_pos print(e) # Save the base sprite (the full sprite minus the eyes/mouth usually) if conf.debug: base.save("%s_BASE.png" % (out_template)) #seems to be a padding of 3 * 4 = 12 bytes before the start of the expression section bytePosStart = data.bytepos if conf.SWITCH: skip_amount = 32 * 3 # Dunno what this is for. print("Skipping {} bytes before the expression header".format( skip_amount / 8)) print(data.read(skip_amount)) rc.add(bytePosStart, data.bytepos) for i in range(exp_chunks): print('--------- Decoding Expression Chunk [{}]----------'.format(i)) bytePosStart = data.bytepos # Name of the expression, like "Def1", "Ikari2" if conf.SWITCH: name_bytes = data.read("bytes:20") else: name_bytes = data.read("bytes:16") # Name is encoded using CP932 encoding name = name_bytes.strip(b'\0').decode("CP932") face_off = data.read("uintle:32") if conf.SWITCH: face_size = data.read("uintle:32") if conf.SWITCH: #there appear to be 24 zero bytes here always...not sure if i'm correct on this zero_bytes = data.read("bytes:24") for b in zero_bytes: if b != 0: print( "WARNING: Non-zero byte found in probably 24 zero padding bytes in character expression header" ) print("Zero padding bytes: ", zero_bytes) else: unk1 = data.read("uintle:32") unk2 = data.read("uintle:32") unk3 = data.read("uintle:32") mouth1_off = data.read("uintle:32") if conf.SWITCH: mouth1_size = data.read("uintle:32") mouth2_off = data.read("uintle:32") if conf.SWITCH: mouth2_size = data.read("uintle:32") mouth3_off = data.read("uintle:32") if conf.SWITCH: mouth3_size = data.read("uintle:32") rc.add(bytePosStart, data.bytepos) print('---------- Expression HEADER -----------') print("name: [{}]".format(name)) print("face_off: ", face_off) print("face_size: ", face_size) if conf.SWITCH: print("mouth1_size: ", mouth1_size) print("mouth2_size: ", mouth2_size) print("mouth3_size: ", mouth3_size) else: print("unk1: ", unk1) print("unk2: ", unk2) print("unk3: ", unk3) print("mouth1_off:", mouth1_off) print("mouth2_off:", mouth2_off) print("mouth3_off:", mouth3_off) print() if not face_off: png_save_path = "%s_%s.png" % (out_template, name) print("saved to {}".format(png_save_path)) base.save(png_save_path) # base.save("%s.png" % (out_template)) # return continue rc.add(face_off, face_off + face_size - 1) rc.add(mouth1_off, mouth1_off + mouth1_size - 1) rc.add(mouth2_off, mouth2_off + mouth2_size - 1) rc.add(mouth3_off, mouth3_off + mouth3_size - 1) face, x, y, masked = process_chunk( data, face_off, forceColorTable0ToBlackTransparent=True) if conf.debug: png_save_path = "%s_%s_FACE_%s.png" % (out_template, name, str(masked)) print("saved to {}".format(png_save_path)) face.save(png_save_path) if conf.SWITCH: exp_base = blit_switch(face, base, x, y, masked, True) else: exp_base = blit(face, base, x, y, masked) for j, mouth_off in enumerate([mouth1_off, mouth2_off, mouth3_off]): if not mouth_off: continue mouth, x, y, masked = process_chunk( data, mouth_off, forceColorTable0ToBlackTransparent=True) print("masked {}".format(masked)) if not mouth: continue if conf.SWITCH: exp = blit_switch(mouth, exp_base, x, y, masked, True) else: exp = blit(mouth, exp_base, x, y, masked) if conf.apply_post_filtering: fill_all(exp) png_save_path = "%s_%s_%d.png" % (out_template, name, j) print("saved exp to {}".format(png_save_path)) exp.save(png_save_path) if conf.debug: png_save_path = "%s_%s_%d_MOUTH_%s.png" % (out_template, name, j, str(masked)) print("saved to {}".format(png_save_path)) mouth.save(png_save_path) rc.get_regions()
def load(self, filename): filename = filename.lower() if not filename in MTB_DIR: _LOGGER.error("Invalid MTB file: %s" % filename) return self.filename = filename script_dir = MTB_DIR[filename] self.script_pack = ScriptPack(script_dir, common.editor_config.umdimage_dir) # --- MTB FORMAT --- # 12 bytes -- ??? # XX XX XX XX -- Table offset # 24 bytes -- ??? # # XX XX -- MTB Index # XX XX -- Char ID for sprites # XX XX -- Char ID for voices (chapter for voices is 0x63) # XX XX -- Initial sprite ID (?) mtb = ConstBitStream(filename=os.path.join( common.editor_config.umdimage_dir, self.filename)) mtb.read(12 * 8) table_offset = mtb.read("uintle:32") mtb.read(24 * 8) mtb_index = mtb.read("uintle:16") sprite_char = mtb.read("uintle:16") voice_char = mtb.read("uintle:16") sprite_id = mtb.read("uintle:16") sprite = SpriteId(SPRITE_TYPE.stand, sprite_char, sprite_id) # --- TABLE FORMAT --- # XX XX XX XX -- Number of files # # [for each line] # XX XX XX XX -- Offset (from table start) of voice info. # # -- Voice Info -- # XX XX -- File ID # XX XX -- Voice ID (with char ID above and the chapter ID 0x63, we know which voice file to use) mtb.bytepos = table_offset num_files = mtb.read("uintle:32") for i in range(num_files): voice_offset = mtb.read("uintle:32") # Store our position in the table so we can jump back to it. table_pos = mtb.bytepos mtb.bytepos = table_offset + voice_offset file_id = mtb.read("uintle:16") voice_id = mtb.read("uintle:16") # Chapter is 0x63, which is where the non-Trial voice samples are stored, # but I don't see the information actually recorded in the MTB files, # so I'm magic-numbering it here. voice = VoiceId(voice_char, 0x63, voice_id) self.script_pack[file_id].scene_info.sprite = sprite self.script_pack[file_id].scene_info.voice = voice # Restore it to our old position. mtb.bytepos = table_pos
print("Found movi signature at byte offset %X" % moviOffset) else: print "Signature movi not found" print ("Current bytepos %X" % s.bytepos) foundIdx1Offset = s.find('0x69647831', bytealigned=True) if foundIdx1Offset: idx1Offset = foundIdx1Offset[0] / 8 print("Found idx1 signature at byte offset %X" % idx1Offset) else: print "Signature idx1 not found" print ("Current bytepos %X" % s.bytepos) found01dcOffset = s.findall('0x30316463', bytealigned=True) for i in found01dcOffset: i = (i /8) + 8 print("%X" % i) s.bytepos = i print s.bytepos timeStamp = s.read(64).bin print timeStamp print ("Time is %d" % timeStamp) # print filetime_to_dt(timeStamp) # s.bytepos = i + 4 # print s.bytepos # timelow = s.read(32).Q # t = float(timehigh)*2**32 + timelow # print (t*1e-7 - 11644473600) # try: # while True: # found01dbOffset2 = s.readto('0x30316462') # _01dbOffsetList.append((s.bytepos))
trak.parse_boxes(bstr, recursive=False) mdia = None for trak_subbox in trak.boxes: if trak_subbox.header.type == b"mdia": mdia = trak_subbox else: if isinstance(trak_subbox, bx_def.ContainerBox): trak_subbox.parse_boxes(bstr) trak_subbox.load(bstr) # MOOV.TRAK.MDIA mdia_boxes_end = mdia.header.start_pos + mdia.header.box_size bstr.bytepos = mdia.boxes_start_pos for box_header in Parser.parse(bstr, headers_only=True): if bstr.bytepos >= mdia_boxes_end: break if box_header.type != b"hdlr": box = Parser.parse_box(bstr, box_header) box.load(bstr) else: # hdlr.name should finish with a b'\0'. If it doesn't, add one # Add a b'\0' for safety hdlr_bstr = BitStream(bytes(box_header)) hdlr_header = Parser.parse_header(hdlr_bstr) hdlr_header.box_size += 1