def _read_record(self, depth): record = lib.Manifest(self, header=[ ('data_offset', self.read(4)), ('data_size', self.read(4)), ('id', self.read(4)), ('filename_offset', self.read(4)), ('padding', self.expect(0x0, 4)), ]) position = self.file.tell() if record.int32('filename_offset') > 0: self.file.seek(record.int32('filename_offset')) record.filename = self.read_null_terminated_string() if record.int32('data_offset') > 0: record.path = lib.filesystem.normalize_filepath( record.filename, self.path) + ".dds" self.file.seek(record.int32('data_offset')) self.log( "Reading data, size = {}, filename = {}, actual filename = {}". format(record.int32('data_size'), record.filename, record.path), depth) data = self.read(record.int32('data_size')) lib.filesystem.write_data(record.path, data) self.file.seek(position) return record
def _read_record(self, depth): record = lib.Manifest(self, header=[ ("record_separator", self.expect(0x40, 4)), ('record_size', self.read(4)), ('record_offset', self.read(4)), ('id', self.read(4)), ('filename_offset', self.read(4)), ('redundant_size', self.read(4)), ]) if record.header['record_size'] != record.header['redundant_size']: raise ValueError("Data sizes don't match: {} != {}".format( record.header['record_size'], record.header['redundant_size'])) position = self.file.tell() self.file.seek(record.int32('filename_offset')) record.record_name = self.read_null_terminated_string() if not record.record_name: raise ValueError("Got empty record name") record.path = lib.filesystem.normalize_filepath( record.record_name, self.path) self.file.seek(position) return record
def extract_file(self, depth): self.log("Parsing file {}".format(self.path), depth) manifest = lib.Manifest( self, header=[ ("signature", self.expect(self.MAGIC_HEADER)), ("unknown1", self.expect(b"\xff\x00\x00\x00\x01\x00\x00\x00")), ("file_size", self.read(4)), ("bin_count", self.read(4)), ("bin_record_offset", self.read(4)), ]) manifest.records = [] manifest.bin_records = [] # self.log(self.to_int32(manifest['header']['file_size']), depth) for i in range(manifest.int32('bin_count')): self.log("Reading bin #{}".format(i), depth) bin_record = self._read_bin(depth) manifest.bin_records.append(bin_record) # Add ability to iterate over records for uniformity with BHF3File manifest.records += bin_record.records self.file.close() return manifest
def extract_file(self, depth): self.log("Reading file {}".format(self.path), depth) manifest = lib.Manifest( self, header=[ ("signature", self.expect(self.MAGIC_HEADER)), ("unknown1", self.expect(0x10000, 4)), ("dcs_offset", self.expect(0x18, 4)), ("dcp_offset", self.expect(0x24, 4)), ("redundant_dcp_offset", self.expect(0x24, 4)), ("dcs_header_size", self.expect(0x2c, 4)), ("dcs_signature", self.expect(b"DCS\x00")), ("uncompressed_size", self.read(4)), ("compressed_size", self.read(4)), ("dcp_signature", self.expect(b"DCP\x00")), ("dcp_method", self.expect(b"DFLT")), ("dca_offset", self.expect(0x20, 4)), ("compression_level", self.expect(0x09000000, 4)), ("unknown2", self.expect(0x0, 12)), ("zlib_version", self.expect(0x00010100, 4)), ("dca_signature", self.expect(b"DCA\x00")), ("dca_header_size", self.expect(0x8, 4)), ]) manifest.end_header_pos = self.file.tell() compressed_data = self.read(manifest.int32('compressed_size')) uncompressed_data = zlib.decompress(compressed_data) if len(uncompressed_data) != manifest.int32('uncompressed_size'): msg = "Expected uncompressed size {}, got {}".format( manifest.int32('uncompressed_size'), len(uncompressed_data)) raise ValueError(msg) uncompressed_filename = lib.filesystem.normalize_filepath( os.path.basename(self.path)[:-4], self.path) manifest.uncompressed_filename = uncompressed_filename file_cls = self.class_for_data(uncompressed_data) if file_cls: manifest.sub_manifest = file_cls( io.BytesIO(uncompressed_data), uncompressed_filename).extract_file(depth + 1) else: self.log( "Writing uncompressed data to {}".format( uncompressed_filename), depth) lib.filesystem.write_data(uncompressed_filename, uncompressed_data) return manifest
def _read_bin(self, depth): bin_record = lib.Manifest(self, header=[ ("record_count", self.read(4)), ("offset", self.read(4)), ]) bin_record.records = [] position = self.file.tell() self.file.seek(bin_record.int32('offset')) for i in range(bin_record.int32('record_count')): bin_record.records.append(self._read_record()) self.file.seek(position) return bin_record
def extract_file(self, depth): self.log("Reading file {}".format(self.path), depth) manifest = lib.Manifest(self, header=[ ('signature', self.expect(self.MAGIC_HEADER)), ("size_sum", self.read(4)), ("record_count", self.read(4)), ("flags", self.expect(0x20300, 4)), ]) manifest.records = [] for i in range(manifest.int32('record_count')): self.log("Reading record #{}".format(i), depth) manifest.records.append(self._read_record(depth + 1)) manifest.end_header_pos = self.file.tell() return manifest
def _read_record(self): record = lib.Manifest(self, header=[ ('record_hash', self.read(4)), ('record_size', self.read(4)), ('record_offset', self.read(4)), ('padding', self.expect(0x0, 4)), ]) record_hash = record.int32('record_hash') try: record.record_name = lib.filesystem.get_name_from_hash( record_hash).lstrip("/").replace("/", os.sep) except KeyError: raise ValueError( "Failed to find {} in name hash dict".format(record_hash)) record.path = lib.filesystem.normalize_filepath( record.record_name, self.path) return record
def extract_file(self, depth): self.log("Reading file {}".format(self.path), depth) manifest = lib.Manifest(self, header=[ ("signature", self.expect(self.MAGIC_HEADER)), ("id", self.expect(self.MAGIC_ID)), ("padding", self.expect(0x0, 6)), ]) if self.path.endswith(self.C4110_FILENAME): data = io.BytesIO(fixed_data.c4110_replacement.DATA) manifest.header_manifest = lib.BHF3File(data, self.path[:-3] + "bhd").extract_file(depth + 1) else: header_filename = lib.filesystem.find_bdt_header_filename(self.path, depth) if not header_filename: raise FileNotFoundError("Got no results searching for BHD for BDT {}".format(self.path)) self.log("Using header file {}".format(header_filename), depth) manifest.header_manifest = self._get_header_extractor(header_filename, depth).extract_file(depth + 1) self._extract_records(manifest.header_manifest.records, depth) return manifest
def _read_record(self, flags, depth): record = lib.Manifest(self, header=[ ("record_sep", self.expect(0x40, 4)), ('data_size', self.read(4)), ('data_offset', self.read(4)), ('id', self.read(4)), ("filename_offset", self.read(4)), ]) if flags in (0x74, 0x54): record.header['redundant_size'] = self.read(4) if record.header['redundant_size'] != record.header['data_size']: raise ValueError("Expected size {}, got {}".format( record.header['data_size'], record.header['redundant_size']) ) position = self.file.tell() if record.int32('filename_offset') > 0: self.file.seek(record.int32('filename_offset')) record.filename = self.read_null_terminated_string() record.path = lib.filesystem.normalize_filepath(record.filename, self.path) # self.log("got filename %s" % record['filename']) if record.int32('data_offset') > 0: self.file.seek(record.int32('data_offset')) self.log("Reading data, size = {}, filename = {}".format(record.int32('data_size'), record.filename), depth) data = self.read(record.int32('data_size')) file_cls = self.class_for_data(data) if file_cls: record.sub_manifest = file_cls(io.BytesIO(data), record.path).extract_file(depth + 1) else: self.log("Writing data to {}".format(record.path), depth) lib.filesystem.write_data(record.path, data) self.file.seek(position) return record
def extract_file(self, depth): self.log("Reading file {}".format(self.path), depth) manifest = lib.Manifest(self, header=[ ("signature", self.expect(self.MAGIC_HEADER)), ("id", self.read(8)), ("flags", self.read(4)), ("record_count", self.read(4)), ("header_size", self.read(4)), ("padding", self.expect(0x0, 8)), ]) manifest.records = [] if manifest.int32('flags') not in (0x74, 0x54, 0x70): raise ValueError("Invalid flags: {:02X}".format(manifest.int32('flags'))) for i in range(manifest.int32('record_count')): self.log("Reading record #{}".format(i), depth) manifest.records.append(self._read_record(manifest.int32('flags'), depth + 1)) manifest.end_header_pos = self.file.tell() return manifest
def extract_file(self, depth): self.log("Parsing file {}".format(self.path), depth) manifest = lib.Manifest(self, header=[ ("signature", self.expect(self.MAGIC_HEADER)), ("id", self.expect(b"07D7R6\x00\x00")), ("version", self.read(4)), ("record_count", self.read(4)), ("header_size", self.read(4)), ("padding", self.expect(0x0, 8)), ]) manifest.records = [] if manifest.int32('version') not in (0x74, 0x54): raise ValueError("Invalid version: {:02X}".format( manifest.int32('version'))) for i in range(manifest.int32('record_count')): manifest.records.append(self._read_record(depth)) self.file.close() return manifest