Exemplo n.º 1
0
	def decompress_datafile(self, datafile_id: int):
		"""This is the decompression method

		Given a numerical id of a datafile that is present in the forge file, this method will decompress that datafile, storing
		the data in the pyUbiForgeMain instance which was given to this class. It will populate self.datafiles[datafile_id].files
		with mappings from numerical id to file_name for each file within the datafile. It will also add the datafile id to
		self.new_datafiles so that external applications (such as the UI wrapper ACExplorer) will know which datafiles have been
		decompressed and have data to be added to the UI.
		"""
		repoulate_tree = self.datafiles[datafile_id].files == {}
		if datafile_id == 0 or datafile_id > 2 ** 40:
			return
		uncompressed_data_list = []

		forge_file = open(os.path.join(self.pyUbiForge.CONFIG.game_folder(self.pyUbiForge.game_identifier), self.forge_file_name), 'rb')
		forge_file.seek(self.datafiles[datafile_id].raw_data_offset)
		raw_data_chunk = FileObjectDataWrapper.from_binary(self.pyUbiForge, forge_file.read(self.datafiles[datafile_id].raw_data_size))
		forge_file.close()
		header = raw_data_chunk.read_str(8)
		format_version = 128
		if header == b'\x33\xAA\xFB\x57\x99\xFA\x04\x10':  # if compressed
			format_version, uncompressed_data_list = self._read_compressed_data_section(raw_data_chunk)
			if format_version == 128:
				if raw_data_chunk.read_str(8) == b'\x33\xAA\xFB\x57\x99\xFA\x04\x10':
					_, uncompressed_data_list_ = self._read_compressed_data_section(raw_data_chunk)
					uncompressed_data_list += uncompressed_data_list_
				else:
					raise Exception('Compression Issue. Second compression block not found')
			if len(raw_data_chunk.read_rest()) != 0:
				raise Exception('Compression Issue. More data found')
		else:
			raw_data_chunk_rest = header + raw_data_chunk.read_rest()
			if b'\x33\xAA\xFB\x57\x99\xFA\x04\x10' in raw_data_chunk_rest:
				raise Exception('Compression Issue')
			else:
				uncompressed_data_list.append(raw_data_chunk_rest)  # The file is not compressed

		if format_version == 0:
			self.pyUbiForge.temp_files.add(datafile_id, self.forge_file_name, datafile_id, 0, self.datafiles[datafile_id].file_name, raw_file=b''.join(uncompressed_data_list))
			self.datafiles[datafile_id].files[datafile_id] = self.datafiles[datafile_id].file_name

		elif format_version == 128:
			uncompressed_data = FileObjectDataWrapper.from_binary(self.pyUbiForge, b''.join(uncompressed_data_list))

			file_count = uncompressed_data.read_uint_16()
			index_table = []
			for _ in range(file_count):
				index_table.append(uncompressed_data.read_struct('QIH'))  # file_id, data_size (file_size + header), extra16_count (for next line)
				uncompressed_data.seek(index_table[-1][2] * 2, 1)
			for index in range(file_count):
				file_type, file_size, file_name_size = uncompressed_data.read_struct('3I')
				file_id = index_table[index][0]
				file_name = uncompressed_data.read_str(file_name_size).decode("utf-8")
				check_byte = uncompressed_data.read_uint_8()
				if check_byte == 1:
					uncompressed_data.seek(3, 1)
					unk_count = uncompressed_data.read_uint_32()
					uncompressed_data.seek(12 * unk_count, 1)
				elif check_byte != 0:
					raise Exception('Either something has gone wrong or a new value has been found here')

				raw_file = uncompressed_data.read_str(file_size)

				if file_name == '':
					file_name = f'{file_id:016X}'
				self.pyUbiForge.temp_files.add(file_id, self.forge_file_name, datafile_id, file_type, file_name, raw_file=raw_file)
				self.datafiles[datafile_id].files[file_id] = file_name
				if self.pyUbiForge.CONFIG['writeToDisk']:
					folder = os.path.join(
						self.pyUbiForge.CONFIG['dumpFolder'],
						self.pyUbiForge.game_identifier,
						self.forge_file_name,
						self.datafiles[datafile_id].file_name,
						f'{file_type:08X}'
					)
					if os.path.isfile(os.path.join(folder, f'{file_name}.{self.pyUbiForge.game_identifier.lower()}')):
						duplicate = 1
						while os.path.isfile(os.path.join(folder, f'{file_name}_{duplicate}.{self.pyUbiForge.game_identifier.lower()}')):
							duplicate += 1
						path = os.path.join(folder, f'{file_name}_{duplicate}.{self.pyUbiForge.game_identifier.lower()}')
					else:
						path = os.path.join(folder, f'{file_name}.{self.pyUbiForge.game_identifier.lower()}')
					if not os.path.isdir(folder):
						os.makedirs(folder)
					try:
						open(path, 'wb').write(raw_file)
					except Exception as e:
						self.pyUbiForge.log.warn(__name__, f'Error saving temporary file with path "{path}"\n{e}')

		else:
			raise Exception('Format version not known. Please let the creator know where you found this.')

		if repoulate_tree:
			self.new_datafiles.append(datafile_id)
Exemplo n.º 2
0
	def file(self) -> FileObjectDataWrapper:
		"""The raw data wrapped up in a custom data wrapper.
		See FileObjectDataWrapper for more information.
		"""
		return FileObjectDataWrapper.from_binary(self._pyUbiForge, self._raw_file)