def showLevelDialog(self): """ Loads the level choosing dialog, along with sending the level data to loadLevel() """ levelSelect = ChooseLevelDialog(self.levelList) if levelSelect.exec_(): if levelSelect.absolutePath: path = levelSelect.stageName name = levelSelect.stageNamePath print('ok so path is ' + path) print('and our name is ' + name) custom = 1 else: path = self.gamePath + '/Pack/Static/Map/' + levelSelect.stageName + '.szs' custom = 0 if os.path.isfile(path): with open(path, 'rb') as f: data = f.read() if custom == 0: self.levelData = byml.BYML(sarc.extract(yaz0.decompress(data), levelSelect.stageName + '.byaml')) self.loadLevel(self.levelData.rootNode) self.setWindowTitle('Splat3D ALPHA v0.2 ' + os.path.basename(path) + ' (' + levelName(levelSelect.stageName) + ')') if custom == 1: self.levelData = byml.BYML(sarc.extract(yaz0.decompress(data), levelSelect.stageNamePath + '.byaml')) self.loadLevel(self.levelData.rootNode) self.setWindowTitle('Splat3D ALPHA v0.2 ' + os.path.basename(path) + ' (' + levelName(levelSelect.stageName[:-4]) + ')')
def from_file(cls, f): newarc = cls() print("ok") header = f.read(4) if header == b"Yaz0": # Decompress first print("Yaz0 header detected, decompressing...") start = time.time() tmp = BytesIO() f.seek(0) decompress(f, tmp) #with open("decompressed.bin", "wb") as g: # decompress(f,) f = tmp f.seek(0) header = f.read(4) print("Finished decompression.") print("Time taken:", time.time() - start) if header == b"RARC": pass else: raise RuntimeError("Unknown file header: {} should be Yaz0 or RARC".format(header)) size = read_uint32(f) f.read(4) #unknown data_offset = read_uint32(f) + 0x20 f.read(16) # Unknown node_count = read_uint32(f) f.read(8) # Unknown file_entry_offset = read_uint32(f) + 0x20 f.read(4) # Unknown stringtable_offset = read_uint32(f) + 0x20 f.read(8) # Unknown nodes = [] print("Archive has", node_count, " total directories") #print("data offset", hex(data_offset)) for i in range(node_count): nodetype = f.read(4) nodedata = f.read(4+2+2+4) nameoffset, unknown, entrycount, entryoffset = unpack(">IHHI", nodedata) if i == 0: dir_name = stringtable_get_name(f, stringtable_offset, nameoffset) else: dir_name = None nodes.append((dir_name, unknown, entrycount, entryoffset)) rootfoldername = nodes[0][0] newarc.root = Directory.from_node(f, rootfoldername, stringtable_offset, file_entry_offset, data_offset, nodes, 0) return newarc
def loadModel(self,newname): if self.inkGender == 1: gen = 1 else: gen = 0 if newname == 'StartPos' and gen == 1: newname = 'Player01' if newname == 'StartPos' and gen == 0: newname = 'Player00' name = ReplaceModel(newname, gen) paths = ('/Model/', '/Pack/Obj/Model/', '/Pack/ObjSmall/Model/', '/Pack/Enemy/Model/', '/Pack/Player/Model/') for objpath in paths: base = window.gamePath + str(objpath) + str(name) if os.path.isfile(str(base) + '.sarc'): ext = '.sarc' elif os.path.isfile(str(base) + '.szs'): ext = '.szs' else: kind = '(skipped)' continue if base == window.gamePath + '/Pack/ObjSmall/Model/Obj_DemoPlayer': return self.cubeList if os.path.isfile(str(base) + str(ext)): with open(base + ext, 'rb') as f: data = f.read() print('Loading model ' + name + '!') if data.startswith(b'Yaz0'): print('Decompressing Yaz0...') yaz0archive = yaz0.decompress(data) if b"Output.bfres" in yaz0archive: bfres = sarc.extract(yaz0archive, 'Output.bfres') model = fmdl.parse(bfres) return self.generateList(model) else: return self.cubeList else: print('Skipping yaz0 decompression') sarchive = data if b"Output.bfres" in sarchive: bfres = sarc.extract(sarchive, 'Output.bfres') model = fmdl.parse(bfres) return self.generateList(model) else: return self.cubeList break else: return self.cubeList
def showLevelDialog(self): if self.levelSelect.exec_(): with open( self.gamePath + '/StageData/' + self.levelSelect.currentLevel + 'Map1.szs', 'rb') as f: data = f.read() self.levelData = byml.BYML( sarc.extract(yaz0.decompress(data), self.levelSelect.currentLevel + 'Map.byml')) self.loadLevel(self.levelData.rootNode)
def loadModel(self, newname): if self.inkGender == 1: gen = 1 else: gen = 0 if newname == 'StartPos' and gen == 1: newname = 'Player01' if newname == 'StartPos' and gen == 0: newname = 'Player00' name = ReplaceModel(newname, gen) paths = ('/Model/', '/Pack/Obj/Model/', '/Pack/ObjSmall/Model/', '/Pack/Enemy/Model/', '/Pack/Player/Model/') for objpath in paths: base = window.gamePath + str(objpath) + str(name) if os.path.isfile(str(base) + '.sarc'): ext = '.sarc' elif os.path.isfile(str(base) + '.szs'): ext = '.szs' else: kind = '(skipped)' continue if base == window.gamePath + '/Pack/ObjSmall/Model/Obj_DemoPlayer': return self.cubeList if os.path.isfile(str(base) + str(ext)): with open(base + ext, 'rb') as f: data = f.read() print('Loading model ' + name + '!') if data.startswith(b'Yaz0'): print('Decompressing Yaz0...') yaz0archive = yaz0.decompress(data) if b"Output.bfres" in yaz0archive: bfres = sarc.extract(yaz0archive, 'Output.bfres') model = fmdl.parse(bfres) return self.generateList(model) else: return self.cubeList else: print('Skipping yaz0 decompression') sarchive = data if b"Output.bfres" in sarchive: bfres = sarc.extract(sarchive, 'Output.bfres') model = fmdl.parse(bfres) return self.generateList(model) else: return self.cubeList break else: return self.cubeList
def loadModel(self,name): if not os.path.isfile(window.gamePath+'/ObjectData/'+name+'.szs'): return self.cubeList with open(window.gamePath+'/ObjectData/'+name+'.szs','rb') as f: data = f.read() sarchive = yaz0.decompress(data) if sarc.contains(sarchive,name+'.bfres'): bfres = sarc.extract(sarchive,name+'.bfres') model = fmdl.parse(bfres) return self.generateList(model) return self.cubeList
def showLevelDialog(self): """ Loads the level choosing dialog, along with sending the level data to loadLevel() """ levelSelect = ChooseLevelDialog(self.levelList) if levelSelect.exec_(): if levelSelect.absolutePath: path = levelSelect.stageName name = levelSelect.stageNamePath print('ok so path is ' + path) print('and our name is ' + name) custom = 1 else: path = self.gamePath + '/Pack/Static/Map/' + levelSelect.stageName + '.szs' custom = 0 if os.path.isfile(path): with open(path, 'rb') as f: data = f.read() if custom == 0: self.levelData = byml.BYML( sarc.extract(yaz0.decompress(data), levelSelect.stageName + '.byaml')) self.loadLevel(self.levelData.rootNode) self.setWindowTitle('Splat3D ALPHA v0.2 ' + os.path.basename(path) + ' (' + levelName(levelSelect.stageName) + ')') if custom == 1: self.levelData = byml.BYML( sarc.extract(yaz0.decompress(data), levelSelect.stageNamePath + '.byaml')) self.loadLevel(self.levelData.rootNode) self.setWindowTitle('Splat3D ALPHA v0.2 ' + os.path.basename(path) + ' (' + levelName(levelSelect.stageName[:-4]) + ')')
def from_file(cls, f): newarc = cls() print("ok") header = f.read(4) if header == b"Yaz0": # Decompress first print("Yaz0 header detected, decompressing...") start = time.time() tmp = BytesIO() f.seek(0) decompress(f, tmp) #with open("decompressed.bin", "wb") as g: # decompress(f,) f = tmp f.seek(0) header = f.read(4) print("Finished decompression.") print("Time taken:", time.time() - start) if header == b"SARC": pass else: raise RuntimeError( "Unknown file header: {} should be Yaz0 or SARC".format( header)) header_size = read_uint16(f) assert read_uint16(f) == 0xFEFF # BOM: Big endian size = read_uint32(f) data_offset = read_uint32(f) version = read_uint16(f) reserved = read_uint16(f) print("Archive version", hex(version), "reserved:", reserved) # SFAT header sfat = f.read(4) assert sfat == b"SFAT" sfat_header_size = read_uint16(f) assert sfat_header_size == 0xC node_count = read_uint16(f) hash_key = read_uint32(f) assert hash_key == 0x65 nodes = [] for i in range(node_count): filehash = read_uint32(f) fileattr = read_uint32(f) node_data_start = read_uint32(f) node_data_end = read_uint32(f) nodes.append((fileattr, node_data_start, node_data_end, filehash)) # String table assert f.read(4) == b"SFNT" assert read_uint16(f) == 0x8 read_uint16(f) # reserved string_table_start = f.tell() for fileattr, start, end, hash in nodes: if fileattr & 0x01000000: stringoffset = (fileattr & 0xFFFF) * 4 path = stringtable_get_name(f, string_table_start, stringoffset) else: path = None file = File.from_node(path, fileattr, f, data_offset + start, data_offset + end) print(hash, calc_hash(path, 0x65)) if path is not None: assert path not in newarc.files newarc.files[path] = file else: newarc.unnamed_files.append(file) print(len(newarc.unnamed_files)) return newarc
import sys from yaz0 import decompress from io import BytesIO inputfile = sys.argv[1] with open(inputfile, "rb") as f: out = BytesIO() decompress(f, out) with open(inputfile + ".bin", "wb") as g: g.write(out.getvalue())
def check_sha1(game_path, build_path): #dol_path = game_path.joinpath("main.dol") #if not dol_path.exists(): # raise CheckException(f"File not found: '{dol_path}'") rel_path = game_path.joinpath("rel/Final/Release") if not rel_path.exists(): raise CheckException(f"Path not found: '{rel_path}'") rels_path = get_files_with_ext(rel_path, ".rel") rels_archive_path = game_path.joinpath("RELS.arc") if not rels_archive_path.exists(): raise CheckException(f"File not found: '{rels_archive_path}'") #LOG.debug(f"DOL Path: '{dol_path}'") LOG.debug(f"RELs Path: '{rel_path}' (found {len(rels_path)} RELs)") LOG.debug(f"RELs Archive Path: '{rels_archive_path}'") EXPECTED = {} #with dol_path.open('rb') as file: # data = file.read() # EXPECTED[0] = (str(dol_path), sha1_from_data(data),sha1_from_data(data),) EXPECTED[0] = ( "", "4997D93B9692620C40E90374A0F1DBF0E4889395", "4997D93B9692620C40E90374A0F1DBF0E4889395", ) for rel_filepath in rels_path: with rel_filepath.open('rb') as file: data = bytearray(file.read()) yaz0_data = data if struct.unpack('>I', data[:4])[0] == 0x59617A30: data = yaz0.decompress(io.BytesIO(data)) rel = librel.read(data) EXPECTED[rel.index] = ( str(rel_filepath), sha1_from_data(yaz0_data), sha1_from_data(data), ) with rels_archive_path.open('rb') as file: rarc = libarc.read(file.read()) for depth, file in rarc.files_and_folders: if not isinstance(file, libarc.File): continue if file.name.endswith(".rel"): data = file.data yaz0_data = data if struct.unpack('>I', data[:4])[0] == 0x59617A30: data = yaz0.decompress(io.BytesIO(data)) xxx_path = Path('build').joinpath(file.name) with xxx_path.open('wb') as write_file: write_file.write(data) rel = librel.read(data) EXPECTED[rel.index] = ( file.name, sha1_from_data(yaz0_data), sha1_from_data(data), ) if not build_path.exists(): raise CheckException(f"Path not found: '{build_path}'") build_dol_path = build_path.joinpath("main.dol") if not build_dol_path.exists(): raise CheckException(f"File not found: '{build_dol_path}'") build_rels_path = get_files_with_ext(build_path, ".rel") CURRENT = {} with build_dol_path.open('rb') as file: data = file.read() CURRENT[0] = ( str(build_dol_path), sha1_from_data(data), sha1_from_data(data), ) for rel_filepath in build_rels_path: with rel_filepath.open('rb') as file: data = bytearray(file.read()) yaz0_data = data if struct.unpack('>I', data[:4])[0] == 0x59617A30: data = yaz0.decompress(io.BytesIO(data)) rel = librel.read(data) CURRENT[rel.index] = ( str(rel_filepath), sha1_from_data(yaz0_data), sha1_from_data(data), ) expected_keys = set(EXPECTED.keys()) current_keys = set(CURRENT.keys()) match = expected_keys - current_keys if len(match) > 0: raise CheckException( f"Missing RELs (expected: {len(expected_keys)}, found: {len(current_keys)})" ) errors = 0 for key in expected_keys: if key in current_keys: expected = EXPECTED[key] current = CURRENT[key] if current[2] != expected[2]: errors += 1 LOG.error( f"{current[2]} {expected[2]} {current[0]} ({expected[0]})") if errors > 0: raise CheckException("NO MATCH!") return True
def showLevelDialog(self): if self.levelSelect.exec_(): with open(self.gamePath+'/StageData/'+self.levelSelect.currentLevel+'Map1.szs','rb') as f: data = f.read() self.levelData = byml.BYML(sarc.extract(yaz0.decompress(data),self.levelSelect.currentLevel+'Map.byml')) self.loadLevel(self.levelData.rootNode)
def loadStageList(self): with open(self.gamePath+'/SystemData/StageList.szs','rb') as f: data = f.read() self.worldList = byml.BYML(sarc.extract(yaz0.decompress(data),'StageList.byml')).rootNode
else: data.write(char * repeat) return data.getvalue() for i in xrange(100): data = create_random_data(string.ascii_lowercase, 100, repeat=10, repeatRandom=True) try: # Test 1: Test compression and decompression of strings. compressed_data = compress(data, 9) decompressed_data = decompress(compressed_data) assert data == decompressed_data # Test 2: Test compression and decompression of content in file-like objects. fileobj = StringIO(data) compressed_fileobj_data = compress_fileobj(fileobj, 9) decompressed_fileobj_data = decompress_fileobj(compressed_fileobj_data) assert data == decompressed_fileobj_data.getvalue() # Test 3: Test compression and decompression of content located in a file. with open(inputFilename, "w") as f: f.write(data) compress_file(inputFilename, outputPath=compressedFilename,
char = random.choice(charSet) if repeatRandom == True: repeat_random = random.randint(1, repeat) data.write(char*repeat_random) else: data.write(char*repeat) return data.getvalue() for i in xrange(100): data = create_random_data(string.ascii_lowercase, 100, repeat = 10, repeatRandom = True) try: # Test 1: Test compression and decompression of strings. compressed_data = compress(data, 9) decompressed_data = decompress(compressed_data) assert data == decompressed_data # Test 2: Test compression and decompression of content in file-like objects. fileobj = StringIO(data) compressed_fileobj_data = compress_fileobj(fileobj, 9) decompressed_fileobj_data = decompress_fileobj(compressed_fileobj_data) assert data == decompressed_fileobj_data.getvalue() # Test 3: Test compression and decompression of content located in a file. with open(inputFilename, "w") as f: f.write(data) compress_file(inputFilename, outputPath = compressedFilename, compressLevel = 9) decompress_file(compressedFilename, outputPath = decompressedFilename)
def dump(self, f): if self.is_yaz0_compressed: decompress(self, f, suppress_error=True) else: f.write(self.getvalue())
def read(buffer): # check if the rel is compressed if struct.unpack('>I', buffer[:4])[0] == 0x59617A30: buffer = yaz0.decompress(io.BytesIO(buffer)) header_size = 0x40 header = struct.unpack('>IIIIIIIIIIIIBBBBIII', buffer[:0x40]) align = 0 bssAlign = 0 if header[7] >= 2: v2 = struct.unpack('>II', buffer[0x40:0x48]) align = v2[0] bssAlign = v2[1] header_size += 0x8 fixSize = 0 if header[7] >= 3: v3 = struct.unpack('>I', buffer[0x48:0x4C]) fixSize = v3[0] header_size += 0x4 rel = REL(*header, align, bssAlign, fixSize) rel.data = buffer rel.sections = [] section_buffer = buffer[rel.sectionInfoOffset:] for i in range(rel.numSections): section_offset = 0x8 * i section = read_section(i, section_buffer[section_offset:]) rel.sections.append(section) addr = 0 for section in rel.sections: section.offset_padding = 0 section.first_padding = 0 section.addr = addr section.alignment = align addr += section.length for section in reversed(rel.sections): if section.offset > 0 and section.length > 0: offset_aligned = (section.offset + 15) & ~15 shift = offset_aligned - section.offset section.offset_padding += 0 # shift addr_aligned = (section.addr + 7) & ~7 shift = addr_aligned - section.addr section.first_padding += 0 # shift break for section in rel.sections: if section.offset > 0 and section.length > 0: section.data = buffer[section.offset:][:section.length + section.first_padding + section.offset_padding] for bss_section in rel.sections[1:]: if bss_section.data == None: bss_section.addr = (last_end + 7) & ~7 bss_section.alignment = bssAlign last_end = bss_section.addr + bss_section.length rel.relocations = [] imp_buffer = buffer[rel.impOffset:] for i in range(rel.impSize // 8): imp_offset = 0x8 * i module_id, rel_offset = struct.unpack('>II', imp_buffer[imp_offset:][:0x8]) section = None offset = 0 while True: relocation = read_relocation(module_id, buffer[rel_offset:]) rel_offset += 0x8 if relocation.type == R_PPC_NONE: continue if relocation.type == R_DOLPHIN_NOP: # NOP is used to simulate have long offset values, this is because # the offset field is limited to 2^16-1 values. Thus, any offsets # above 2^16 will be divided into a NOP + original relocation type. offset += relocation.offset continue if relocation.type == R_DOLPHIN_SECTION: section = rel.sections[relocation.section] offset = 0 continue assert section relocation.parent = section relocation.rel_offset = rel_offset - 0x8 relocation.relative_offset = relocation.offset relocation.offset += offset offset = relocation.offset assert relocation.type != R_DOLPHIN_MRKREF if relocation.type == R_DOLPHIN_END: break section.relocations.append(relocation) rel.relocations.append(relocation) return rel