private void ReadIndexUpdated(BinaryReader reader, FPakInfo info, byte[] aesKey) { MountPoint = reader.ReadFString(); if (MountPoint.StartsWith("../../..")) { MountPoint = MountPoint.Substring(8); } else { MountPoint = "/"; } var filesNum = reader.ReadInt32(); reader.ReadUInt64(); if (reader.ReadInt32() == 0) { throw new FileLoadException("No path hash index"); } //reader.ReadInt64(); //reader.ReadInt64(); reader.BaseStream.Position += 20L + 8L + 8L; if (reader.ReadInt32() == 0) { throw new FileLoadException("No directory index"); } var position = reader.ReadInt64(); var directoryIndexSize = reader.ReadInt64(); reader.BaseStream.Position += 20L; var encodedPakEntries = reader.ReadTArray(reader.ReadByte); var files = reader.ReadInt32(); if (files < 0) { throw new FileLoadException("Corrupt pak PrimaryIndex detected!"); } Reader.BaseStream.Position = position; var directoryIndexData = Reader.ReadBytes((int)directoryIndexSize); if (info.bEncryptedIndex != 0) { directoryIndexData = AESDecryptor.DecryptAES(directoryIndexData, aesKey); } var directoryIndexReader = new BinaryReader(new MemoryStream(directoryIndexData)); var directoryEntries = directoryIndexReader.ReadTArray(() => new FPakDirectoryEntry(directoryIndexReader)); var entries = new List <FPakEntry>(filesNum); foreach (var directoryEntry in directoryEntries) { foreach (var hashIndexEntry in directoryEntry.Entries) { string path = MountPoint + directoryEntry.Directory + hashIndexEntry.Filename; entries.Add(GetEntry(path, hashIndexEntry.Location, encodedPakEntries)); } } this.FileInfos = entries.ToArray(); }
public PakReader(Stream stream, string name, byte[] aes = null, bool ParseFiles = true) { Aes = aes; Stream = stream; Name = name; Reader = new BinaryReader(Stream); Stream.Seek(-FPakInfo.Size, SeekOrigin.End); FPakInfo info = new FPakInfo(Reader); if (info.Magic != FPakInfo.PAK_FILE_MAGIC) { DebugHelper.WriteLine(".PAKs: The file magic is invalid"); throw new FileLoadException("The file magic is invalid"); } if (info.Version > (int)PAK_VERSION.PAK_LATEST) { DebugHelper.WriteLine($".PAKs: WARNING: Pak file \"{Name}\" has unsupported version {info.Version}"); } if (info.bEncryptedIndex != 0) { if (Aes == null) { DebugHelper.WriteLine(".PAKs: The file has an encrypted index"); throw new FileLoadException("The file has an encrypted index"); } } // Read pak index Stream.Seek(info.IndexOffset, SeekOrigin.Begin); // Manage pak files with encrypted index BinaryReader infoReader = Reader; if (info.bEncryptedIndex != 0) { var InfoBlock = Reader.ReadBytes((int)info.IndexSize); InfoBlock = AESDecryptor.DecryptAES(InfoBlock, Aes); infoReader = new BinaryReader(new MemoryStream(InfoBlock)); int stringLen = infoReader.ReadInt32(); if (stringLen > 512 || stringLen < -512) { DebugHelper.WriteLine(".PAKs: The AES key is invalid"); throw new FileLoadException("The AES key is invalid"); } if (stringLen < 0) { infoReader.BaseStream.Seek((stringLen - 1) * 2, SeekOrigin.Current); ushort c = infoReader.ReadUInt16(); if (c != 0) { DebugHelper.WriteLine(".PAKs: The AES key is invalid"); throw new FileLoadException("The AES key is invalid"); } } else { infoReader.BaseStream.Seek(stringLen - 1, SeekOrigin.Current); byte c = infoReader.ReadByte(); if (c != 0) { DebugHelper.WriteLine(".PAKs: The AES key is invalid"); throw new FileLoadException("The AES key is invalid"); } } infoReader.BaseStream.Seek(0, SeekOrigin.Begin); } if (!ParseFiles) { return; } if (info.Version >= (int)PAK_VERSION.PAK_PATH_HASH_INDEX) { ReadIndexUpdated(infoReader, info, Aes); } else { MountPoint = infoReader.ReadFString(); if (MountPoint.StartsWith("../../..")) { MountPoint = MountPoint.Substring(8); } else { MountPoint = "/"; } FileInfos = new FPakEntry[infoReader.ReadInt32()]; for (int i = 0; i < FileInfos.Length; i++) { FileInfos[i] = new FPakEntry(infoReader, MountPoint, (PAK_VERSION)info.Version); } } }
public PakReader(Stream stream, string name, byte[] aes = null, bool ParseFiles = true) { Aes = aes; Stream = stream; Name = name; Reader = new BinaryReader(Stream); Stream.Seek(-FPakInfo.Size, SeekOrigin.End); FPakInfo info = new FPakInfo(Reader); if (info.Magic != FPakInfo.PAK_FILE_MAGIC) { throw new FileLoadException("The file magic is invalid"); } if (info.Version > (int)PAK_VERSION.PAK_LATEST) { Console.Error.WriteLine($"WARNING: Pak file \"{Name}\" has unsupported version {info.Version}"); } if (info.bEncryptedIndex != 0) { if (Aes == null) { throw new FileLoadException("The file has an encrypted index"); } } // Read pak index Stream.Seek(info.IndexOffset, SeekOrigin.Begin); // Manage pak files with encrypted index BinaryReader infoReader = Reader; if (info.bEncryptedIndex != 0) { var InfoBlock = Reader.ReadBytes((int)info.IndexSize); InfoBlock = AESDecryptor.DecryptAES(InfoBlock, (int)info.IndexSize, Aes, Aes.Length); infoReader = new BinaryReader(new MemoryStream(InfoBlock)); int stringLen = infoReader.ReadInt32(); if (stringLen > 512 || stringLen < -512) { throw new FileLoadException("The AES key is invalid"); } if (stringLen < 0) { infoReader.BaseStream.Seek((stringLen - 1) * 2, SeekOrigin.Current); ushort c = infoReader.ReadUInt16(); if (c != 0) { throw new FileLoadException("The AES key is invalid"); } } else { infoReader.BaseStream.Seek(stringLen - 1, SeekOrigin.Current); byte c = infoReader.ReadByte(); if (c != 0) { throw new FileLoadException("The AES key is invalid"); } } } if (!ParseFiles) { return; } // Pak index reading time :) infoReader.BaseStream.Seek(0, SeekOrigin.Begin); MountPoint = infoReader.ReadString(FPakInfo.MAX_PACKAGE_PATH); bool badMountPoint = false; if (!MountPoint.StartsWith("../../..")) { badMountPoint = true; } else { MountPoint = MountPoint.Substring(8); } if (MountPoint[0] != '/' || ((MountPoint.Length > 1) && (MountPoint[1] == '.'))) { badMountPoint = true; } if (badMountPoint) { Console.Error.WriteLine($"WARNING: Pak \"{Name}\" has strange mount point \"{MountPoint}\", mounting to root"); MountPoint = "/"; } FileInfos = new FPakEntry[infoReader.ReadInt32()]; for (int i = 0; i < FileInfos.Length; i++) { FileInfos[i] = new FPakEntry(infoReader, MountPoint, info.Version); } }