def __init__(self, reader: BinaryStream): # probably crash self.position = reader.base_stream.tell() self.InterpMode = ERichCurveInterpMode( int.from_bytes(reader.readByte(), byteorder="little")) self.TangentMode = ERichCurveTangentMode( int.from_bytes(reader.readByte(), byteorder="little")) self.TangentWeightMode = ERichCurveTangentWeightMode( int.from_bytes(reader.readByte(), byteorder="little")) self.KeyTime = reader.readFloat() self.KeyValue = reader.readFloat() self.ArriveTangent = reader.readFloat() self.ArriveTangentWeight = reader.readFloat() self.LeaveTangent = reader.readFloat() self.LeaveTangentWeight = reader.readFloat()
def Info(self, reader: BinaryStream, offset): self.EncryptionKeyGuid = FGuid(reader).read() self.bEncryptedIndex = reader.readByte() != b'\x00' magic = reader.readUInt32() if magic != self.PAK_FILE_MAGIC: self.Version = EPakVersion.INVALID self.SubVersion = 0 self.IndexOffset = 0 self.IndexSize = 0 self.IndexHash = None self.CompressionMethods = None return self self.Version = EPakVersion(reader.readInt32()) # FGame.Version = self.Version # FGame.SubVersion = self.SubVersion self.SubVersion = 1 if offset == self._SIZE8A and self.Version == EPakVersion.FNAME_BASED_COMPRESSION_METHOD else 0 self.IndexOffset = reader.readInt64() self.IndexSize = reader.readInt64() self.IndexHash = FSHAHash(reader) if self.Version == EPakVersion.FROZEN_INDEX: reader.readByte() # bIndexIsFrozen if self.Version.value < EPakVersion.FNAME_BASED_COMPRESSION_METHOD.value: self.CompressionMethods = ["Zlib", "Gzip", "Oodle", "LZ4"] else: BufferSize: int = self.COMPRESSION_METHOD_NAME_LEN * 4 Methods: bytes = reader.readBytes(BufferSize) MethodList = [] for i in range(4): if int(Methods[i * self.COMPRESSION_METHOD_NAME_LEN]) != 0: methods = Methods byteIndex = i * self.COMPRESSION_METHOD_NAME_LEN byteCount = self.COMPRESSION_METHOD_NAME_LEN decoded = methods[byteIndex:byteCount].decode("utf-8") MethodList.append(decoded) self.CompressionMethods = MethodList if self.Version.value < EPakVersion.INDEX_ENCRYPTION.value: self.bEncryptedIndex = False if self.Version.value < EPakVersion.ENCRYPTION_KEY_GUID.value: self.EncryptionKeyGuid = FGuid().construct(0, 0, 0, 0) return self
def __init__(self, reader: BinaryStream): magic = reader.readBytes(16) if magic != bytes(self._TocMagic, "utf-8"): raise Exceptions.InvalidMagic("invalid utoc magic") self.Version = EIoStoreTocVersion(reader.readByteToInt()) self.Reserved0 = reader.readByte() self.Reserved1 = reader.readUInt16() self.TocHeaderSize = reader.readUInt32() self.TocEntryCount = reader.readUInt32() self.TocCompressedBlockEntryCount = reader.readUInt32() self.TocCompressedBlockEntrySize = reader.readUInt32() self.CompressionMethodNameCount = reader.readUInt32() self.CompressionMethodNameLength = reader.readUInt32() self.CompressionBlockSize = reader.readUInt32() self.DirectoryIndexSize = reader.readUInt32() self.PartitionCount = reader.readUInt32() self.ContainerId = FIoContainerId(reader) self.EncryptionKeyGuid = FGuid(reader) self.ContainerFlags = reader.readByteToInt() try: self.ContainerFlags = EIoContainerFlags(self.ContainerFlags).value except: pass self.Reserved3 = reader.readByteToInt() self.Reserved4 = reader.readUInt16() self.Reserved5 = reader.readUInt32() self.PartitionSize = reader.readUInt64()
def ReadDirectoryIndex(self, key: Optional[str] = None): self._aeskey = key starttime = time.time() if self.HasDirectoryIndex: if not self.IsEncrypted: IndexReader = BinaryStream(io.BytesIO(self._directoryIndexBuffer), len(self._directoryIndexBuffer)) else: if not CrytoAval: raise ImportError( "Failed to Import \"pycryptodome\", Index is Encrypted it is required for decryption.") if self._aeskey is None: raise InvalidEncryptionKey("Index is Encrypted and Key was not provided.") bytekey = bytearray.fromhex(self._aeskey) decryptor = AES.new(bytekey, AES.MODE_ECB) IndexReader = BinaryStream(io.BytesIO(decryptor.decrypt(self._directoryIndexBuffer)), len(self._directoryIndexBuffer)) stringLen = IndexReader.readInt32() if stringLen > 512 or stringLen < -512: raise ValueError(f"Provided key didn't work with {self.FileName}") if stringLen < 0: IndexReader.base_stream.seek((stringLen - 1) * 2, 1) if IndexReader.readUInt16() != 0: raise ValueError(f"Provided key didn't work with {self.FileName}") else: IndexReader.base_stream.seek(stringLen - 1, 1) if int.from_bytes(IndexReader.readByte(), "little") != 0: raise ValueError(f"Provided key didn't work with {self.FileName}") IndexReader.seek(0, 0) del self.TocResource.DirectoryIndexBuffer del self._directoryIndexBuffer self._directory_index = FIoDirectoryIndexResource(IndexReader, self.caseinSensitive) self.ContainerFile.MountPoint = self._directory_index.MountPoint firstEntry = self.GetChildDirectory(FIoDirectoryIndexHandle(FIoDirectoryIndexHandle.Root)) tempFiles: Dict[str, FIoStoreEntry] Chunks: Dict[str, str] tempFiles, Chunks = self.ReadIndex("", firstEntry) # TODO use Chunks IDs files = UpdateIndex(self.FileName, self.ContainerFile, tempFiles) time_taken = round(time.time() - starttime, 2) logger.info("{} contains {} files, mount point: {}, version: {}, in: {}s".format (self.FileName, len(tempFiles), self._directory_index.MountPoint, self.TocResource.Header.Version, time_taken)) del self._directory_index return files, Chunks
def __init__(self, reader: BinaryStream): self.position = reader.base_stream.tell() self.Min = Vector.FVector2D(reader) self.Max = Vector.FVector2D(reader) self.bIsValid = reader.readByte() != 0
def __init__(self, reader: BinaryStream): self.position = reader.base_stream.tell() self.Value = int.from_bytes(reader.readByte(), "little")
def ReadIndex(self, key: str = None): self.AesKey = key starttime = time.time() self.reader.seek(self.Info.IndexOffset, 0) if not self.Info.bEncryptedIndex: IndexReader = self.reader else: if not CrytoAval: raise ImportError( "Failed to Import \"pycryptodome\", Index is Encrypted it is required for decryption." ) if key is None: raise InvalidEncryptionKey( "Index is Encrypted and Key was not provided.") bytekey = bytearray.fromhex(key) decryptor = AES.new(bytekey, AES.MODE_ECB) IndexReader = BinaryStream( io.BytesIO( decryptor.decrypt( self.reader.readBytes(self.Info.IndexSize)))) stringLen = IndexReader.readInt32() if stringLen > 512 or stringLen < -512: raise InvalidEncryptionKey( f"Provided key didn't work with {self.FileName}") if stringLen < 0: IndexReader.base_stream.seek((stringLen - 1) * 2, 1) if IndexReader.readUInt16() != 0: raise InvalidEncryptionKey( f"Provided key didn't work with {self.FileName}") else: IndexReader.base_stream.seek(stringLen - 1, 1) if int.from_bytes(IndexReader.readByte(), "little") != 0: raise InvalidEncryptionKey( f"Provided key didn't work with {self.FileName}") IndexReader.seek(0, 0) if self.Info.Version.value >= EPakVersion.PATH_HASH_INDEX.value: index = self.ReadUpdatedIndex(IndexReader, key, self.Case_insensitive) else: self.MountPoint = IndexReader.readFString() or "" if self.MountPoint.startswith("../../.."): self.MountPoint = self.MountPoint[8::] # if self.Case_insensitive: # self.MountPoint = self.MountPoint.lower() self.NumEntries = IndexReader.readInt32() tempfiles: Dict[str, FPakEntry] = {} for _ in range(self.NumEntries): entry = FPakEntry(IndexReader, self.Info.Version, self.Info.SubVersion, self.FileName) if self.Case_insensitive: tempfiles[self.MountPoint.lower() + entry.Name.lower()] = entry else: tempfiles[self.MountPoint + entry.Name] = entry index = UpdateIndex(self.FileName, self, tempfiles) del tempfiles time_taken = round(time.time() - starttime, 2) logger.info( f"{self.FileName} contains {self.NumEntries} files, mount point: {self.MountPoint}, version: {self.Info.Version.value}, in: {time_taken}s" ) return index