def _decompress(self, stream: BinaryStream, key, compressionMethods: list): compressionMethod = compressionMethods[self.CompressionMethodIndex - 1] result = bytearray() if self.Encrypted: if key is None: raise InvalidEncryptionKey( "File is Encrypted and Key was not provided.") from Crypto.Cipher import AES decryptor = AES.new(bytearray().fromhex(key), AES.MODE_ECB) block: FPakCompressedBlock for block in self.CompressionBlocks: stream.seek(self.Offset + block.CompressedStart) uncompressed_size = min(self.CompressionBlockSize, self.UncompressedSize - len(result)) if self.Encrypted: buffer = stream.read( Align(self.CompressionBlockSize, AES.block_size)) buffer = decryptor.decrypt(buffer) else: buffer = stream.read(Align(self.CompressionBlockSize, 16)) # AES.block_size result += Decompress.Decompress(buffer, compressionMethod, uncompressed_size) return result
def __init__(self, reader: BinaryStream, ubulk: BinaryStream, bulkOffset: int) -> None: self.bCooked = reader.readInt32() != 0 self.BulkData = FByteBulkData(reader, ubulk, bulkOffset) self.SizeX = reader.readInt32() self.SizeY = reader.readInt32() self.SizeZ = reader.readInt32()
def serializeBuffer(self, reader: BinaryStream): stripFlags = FStripDataFlags(reader) self.positionVertexBuffer = FPositionVertexBuffer(reader) self.vertexBuffer = FStaticMeshVertexBuffer(reader) self.colorVertexBuffer = FColorVertexBuffer(reader) self.indexBuffer = FRawStaticIndexBuffer(reader) if not stripFlags.isClassDataStripped(CDSF_ReversedIndexBuffer): self.reversedIndexBuffer = FRawStaticIndexBuffer(reader) self.depthOnlyIndexBuffer = FRawStaticIndexBuffer(reader) if not stripFlags.isClassDataStripped(CDSF_ReversedIndexBuffer): self.reversedDepthOnlyIndexBuffer = FRawStaticIndexBuffer(reader) if not stripFlags.isEditorDataStripped(): self.wireframeIndexBuffer = FRawStaticIndexBuffer(reader) if not stripFlags.isClassDataStripped(CDSF_AdjancencyData): self.adjacencyIndexBuffer = FRawStaticIndexBuffer(reader) # UE 4.25+ if reader.game >= GAME_UE4(25) and not stripFlags.isClassDataStripped( CDSF_RaytracingResources): reader.readBulkTArray(reader.readByte) # Raw data # 25178 for i in range(len(self.sections)): FWeightedRandomSampler( reader) # FStaticMeshSectionAreaWeightedTriangleSampler FWeightedRandomSampler(reader) # FStaticMeshAreaWeightedSectionSampler
def __init__(self, reader: BinaryStream): self.MaterialInterface = reader.readObject() self.MaterialSlotName = reader.readFName() if FRenderingObjectVersion().get( reader ) >= FRenderingObjectVersion.TextureStreamingMeshUVChannelData: self.UVChannelData = FMeshUVChannelInfo(reader)
def __init__(self, reader: BinaryStream): self.stripFlags = FStripDataFlags(reader, Versions.VER_UE4_STATIC_SKELETAL_MESH_SERIALIZATION_FIX) self.stride = reader.readInt32() self.numVertices = reader.readInt32() if not self.stripFlags.isDataStrippedForServer() and self.numVertices > 0: self.data = reader.readBulkTArray(FColor, reader) else: self.data = []
def __init__(self, reader: BinaryStream, min_version=Versions.VER_UE4_REMOVED_STRIP_DATA): if reader.version >= min_version: self.globalStripFlags = reader.readByteToInt() self.classStripFlags = reader.readByteToInt() else: self.globalStripFlags = 0 self.classStripFlags = 0
def yeet(anything): if isinstance(anything, str): if not os.path.exists(anything): logger.error(f"{anything} not found") with open(anything, "rb") as f: data = f.read() return BinaryStream(io.BytesIO(data), size=len(data)) elif isinstance(anything, (bytes, bytearray)): return BinaryStream(io.BytesIO(anything), size=len(anything))
def __init__(self, reader: BinaryStream): self.TableNamespace = reader.readFString() self.KeysToMetadata = {} NumEntries = reader.readInt32() for i in range(NumEntries): key = reader.readFString() text = reader.readFString() self.KeysToMetadata[key] = text
def __init__(self, reader: BinaryStream, ubulk: BinaryStream, bulkOffset: int) -> None: self.Header = FByteBulkDataHeader(reader, bulkOffset) bulkDataFlags = self.Header.BulkDataFlags if self.Header.ElementCount == 0: self.Data = None elif (bulkDataFlags & EBulkDataFlags.BULKDATA_Unused) != 0: self.Data = None elif (bulkDataFlags & EBulkDataFlags.BULKDATA_OptionalPayload) != 0: self.Data = None elif (bulkDataFlags & EBulkDataFlags.BULKDATA_ForceInlinePayload) != 0: self.Data = reader.readBytes(self.Header.ElementCount) elif (bulkDataFlags & EBulkDataFlags.BULKDATA_PayloadInSeperateFile) != 0: # ubulk ubulk.seek(self.Header.OffsetInFile, 0) self.Data = ubulk.readBytes(self.Header.ElementCount) elif (bulkDataFlags & EBulkDataFlags.BULKDATA_PayloadAtEndOfFile) != 0: pos = reader.base_stream.tell() if self.Header.OffsetInFile + self.Header.ElementCount <= reader.size: reader.seek(self.Header.OffsetInFile, 0) self.Data = reader.readBytes(self.Header.ElementCount) else: self.Data = None reader.seek(pos, 0)
def __init__(self, reader: BinaryStream): self.X = reader.readUInt16() self.Y = reader.readUInt16() self.Z = reader.readUInt16() self.W = reader.readUInt16() if reader.game >= GAME_UE4(20): self.X = self.X ^ 0x8000 self.Y = self.Y ^ 0x8000 self.Z = self.Z ^ 0x8000 self.W = self.W ^ 0x8000
def get_data(self, stream: BinaryStream, key, compression_method): if self.CompressionMethodIndex == 0: stream.seek(self.Offset + self.StructSize, 0) if self.Encrypted: raise NotImplementedError("Encryption is not implemented") else: data: bytes = stream.readBytes(self.UncompressedSize) return BinaryStream(data) else: return BinaryStream( self._decompress(stream, key, compression_method))
def __init__(self, reader: BinaryStream, readType, tag): #TODO: handle enums self.position = reader.base_stream.tell() if readType == PropertyTagData.BaseProperty.ReadType.NORMAL: self.Value = reader.readByteToInt() elif readType == PropertyTagData.BaseProperty.ReadType.MAP: self.Value = reader.readUInt32() elif readType == PropertyTagData.BaseProperty.ReadType.ARRAY: self.Value = reader.readByteToInt() else: raise Exception(f"hmm {readType.name}")
def __init__(self, reader: BinaryStream, FileSize: int) -> None: reader = reader Offsets_to_Try = [self._SIZE, self._SIZE8, self._SIZE8A, self._SIZE9] for Offset in Offsets_to_Try: if FileSize - Offset > 0: reader.seek(FileSize - Offset, 0) info = self.Info(reader, Offset) if info.Version != EPakVersion.INVALID: return raise ParserException(f"Unknown Pak Format")
def __init__(self, reader: BinaryStream, Tag): NumKeystoRemove = reader.readInt32() for _ in range(NumKeystoRemove): PropertyTagData.BaseProperty.ReadAsObject( reader, Tag, Tag.Type, PropertyTagData.BaseProperty.ReadType.ARRAY) Entries = reader.readInt32() self.Value = [] for _ in range(Entries): value = PropertyTagData.BaseProperty.ReadAsObject( reader, Tag, Tag.Type, PropertyTagData.BaseProperty.ReadType.ARRAY) self.Value.append(value)
def __init__(self, reader: BinaryStream, Case_insensitive: bool): self.MountPoint = reader.readFString() if self.MountPoint.startswith("../../.."): self.MountPoint = self.MountPoint[8::] if Case_insensitive: self.MountPoint = self.MountPoint.lower() self.DirectoryEntries = reader.readTArray(FIoDirectoryIndexEntry, reader) self.FileEntries = reader.readTArray(FIoFileIndexEntry, reader) self.StringTable = reader.readTArray(reader.readFString)
def __init__(self, reader: BinaryStream) -> None: self.position = reader.base_stream.tell() length = reader.readInt32() for _ in range(length): self.Map[FGuid( reader).read()] = FLevelSequenceLegacyObjectReference(reader)
def IndexToEnum(self, reader: BinaryStream, tag: FPropertyTag, index: int): name = tag.EnumName if name is None: return str(index) if reader.has_unversioned_properties: enumVals = reader.getmappings().get_enum(name.string) return tag.EnumName.string + "::" + enumVals[index]
def __init__(self, reader: BinaryStream): self.MaterialIndex = reader.readInt32() self.FirstIndex = reader.readInt32() self.NumTriangles = reader.readInt32() self.MinVertexIndex = reader.readInt32() self.MaxVertexIndex = reader.readInt32() self.EnableCollision = reader.readBool() self.CastShadow = reader.readBool() self.ForceOpaque = reader.readBool() if FRenderingObjectVersion().get(reader) >= FRenderingObjectVersion.StaticMeshSectionForceOpaqueField else False self.VisibleInRayTracing = reader.readBool() if reader.game >= EUEVersion.GAME_UE4_26 else False
def __init__(self, reader: BinaryStream): self.ContainerId = FIoContainerId(reader) self.PackageCount = reader.readUInt32() self.Names = reader.readBytes(reader.readInt32()) self.NameHashes = reader.readBytes(reader.readInt32()) self.PackageIds = reader.readTArray(FPackageId, reader) self.StoreEntries = reader.readTArray(reader.readByteToInt)
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 __init__(self, reader: BinaryStream, tag: FPropertyTag, readType): self.position = reader.base_stream.tell() from .BaseProperty import ReadType if readType == ReadType.ZERO: #ZERO self.Value = FName(self.IndexToEnum(reader, tag, 0)) elif readType.value == 0: byteValue = 0 innerType = getattr(tag, "InnerType", None) if innerType is not None: from .BaseProperty import ReadAsValue byteValue = ReadAsValue(reader, tag.InnerData, innerType, 0) else: byteValue = reader.readByteToInt() self.Value = FName(self.IndexToEnum(reader, tag, byteValue)) else: self.Value = reader.readFName()
def _register_file(self, con_file, path): pak_name = con_file if pak_name.endswith(".pak"): # self.Paks[os.path.basename(pak_name)] = reader = PakReader.PakReader(path, self.caseinsensitive) return reader, os.path.basename(pak_name) # logger.debug(f"Registering PakFile: {path}") if pak_name.endswith(".utoc"): ucas_path = path[:-5] + ".ucas" logger.debug(f"Registering IoStore: {path[:-5]}") reader = IoStoreReader.FFileIoStoreReader(ucas_path, BinaryStream(path), BinaryStream(ucas_path), self.caseinsensitive) return reader, os.path.basename(pak_name) return None, None
def __init__(self, reader: BinaryStream) -> None: FlagVal = reader.readUInt32() try: self.Flags = ETextFlag(FlagVal) except: self.Flags = FlagVal self.HistoryType = ETextHistoryBase(reader.readSByte()) if self.HistoryType == ETextHistoryBase.Base: self.Text = Base(reader) elif self.HistoryType == ETextHistoryBase.NamedFormat: self.Text = NamedFormat(reader) elif self.HistoryType == ETextHistoryBase.StringTableEntry: self.Text = StringTableEntry(reader) elif self.HistoryType == ETextHistoryBase._None: self.Text = _None(reader) else: raise NotImplementedError(f"FText: Unsupported FText Type {self.HistoryType.name}")
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.Protocol = reader.readFString() self.Host = reader.readFString() self.Map = reader.readFString() self.Portal = reader.readFString() self.Op = reader.readTArray(reader.readFString) self.Port = reader.readInt32() self.Valid = reader.readInt32()
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, bulkOffset: int) -> None: self.BulkDataFlags = reader.readInt32() if (self.BulkDataFlags & EBulkDataFlags.BULKDATA_Size64Bit) != 0: self.ElementCount = reader.readInt64() self.SizeOnDisk = reader.readInt64() else: self.ElementCount = reader.readInt32() self.SizeOnDisk = reader.readInt32() self.OffsetInFile = reader.readInt64() if not (self.BulkDataFlags & EBulkDataFlags.BULKDATA_NoOffsetFixUp): # UE4.26 flag self.OffsetInFile += bulkOffset if (self.BulkDataFlags & EBulkDataFlags.BULKDATA_BadDataVersion) != 0: reader.seek(2)
def __init__(self, reader: BinaryStream, tag): # raise NotImplementedError("Map Prop") self.position = reader.base_stream.tell() NumKeysToRemove = reader.readInt32() if NumKeysToRemove != 0: for _ in range(NumKeysToRemove): PropertyTagData.BaseProperty.ReadAsValue( reader, tag, tag.InnerType, PropertyTagData.BaseProperty.ReadType.MAP) NumEntries = reader.readInt32() data = {} for _ in range(NumEntries): key = str( PropertyTagData.BaseProperty.ReadAsValue( reader, tag, tag.InnerType, PropertyTagData.BaseProperty.ReadType.MAP)) value = PropertyTagData.BaseProperty.ReadAsObject( reader, tag, tag.ValueType, PropertyTagData.BaseProperty.ReadType.MAP) data[key] = value # formatting tho self.Value = data
def __init__(self, File: str = "", Case_insensitive: bool = False, reader: Optional[BinaryStream] = None) -> None: self.MountPoint: str = "" if reader is not None: self.reader = reader self.size: int = reader.size else: self.reader: BinaryStream = BinaryStream(File) self.size: int = os.path.getsize(File) self.FileName: str = os.path.basename(File) self.Info = PakInfo(self.reader, self.size) self.NumEntries = -1 self.reader.seek(self.Info.IndexOffset, 0) self.MountArray = self.reader.readBytes(128) self.Case_insensitive: bool = Case_insensitive
def deserialize(self, reader: BinaryStream, ubulk: BinaryStream, ubulkOffset: int): self.SizeX = reader.readInt32() self.SizeY = reader.readInt32() self.NumSlices = reader.readInt32() # 1 for normal textures self.PixelFormat = EPixelFormat[reader.readFString()] self.FirstMipToSerialize = reader.readInt32() - 1 self.Mips = reader.readTArray_W_Arg(FTexture2DMipMap, reader, ubulk, ubulkOffset) if reader.game >= GAME_UE4(23): self.bIsVirtual = reader.readInt32() != 0 if self.bIsVirtual: raise NotImplementedError( "Virtual Textures ar not Not implemented")