Example #1
0
 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()
Example #2
0
    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
Example #3
0
    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()
Example #4
0
    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
Example #5
0
 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
Example #6
0
 def __init__(self, reader: BinaryStream):
     self.position = reader.base_stream.tell()
     self.Value = int.from_bytes(reader.readByte(), "little")
Example #7
0
    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