Ejemplo n.º 1
0
        public FPakEntry(PakFileReader reader, string path, FArchive Ar) : base(reader)
        {
            Path = path;
            // FPakEntry is duplicated before each stored file, without a filename. So,
            // remember the serialized size of this structure to avoid recomputation later.
            var startOffset = Ar.Position;

            Offset           = Ar.Read <long>();
            CompressedSize   = Ar.Read <long>();
            UncompressedSize = Ar.Read <long>();
            Size             = UncompressedSize;

            if (reader.Info.Version < EPakFileVersion.PakFile_Version_FNameBasedCompressionMethod)
            {
                try
                {
                    CompressionMethod = reader.Info.CompressionMethods[Ar.Read <int>()];
                }
                catch
                {
                    CompressionMethod = CompressionMethod.Unknown;
                }
            }
            else if (reader.Info.Version == EPakFileVersion.PakFile_Version_FNameBasedCompressionMethod && !reader.Info.IsSubVersion)
            {
                CompressionMethod = reader.Info.CompressionMethods[Ar.Read <byte>()];
            }
            else
            {
                CompressionMethod = reader.Info.CompressionMethods[Ar.Read <int>()];
            }

            if (reader.Info.Version < EPakFileVersion.PakFile_Version_NoTimestamps)
            {
                Ar.Position += 8; // Timestamp
            }
            Ar.Position += 20;    // Hash
            if (reader.Info.Version >= EPakFileVersion.PakFile_Version_CompressionEncryption)
            {
                if (CompressionMethod != CompressionMethod.None)
                {
                    CompressionBlocks = Ar.ReadArray <FPakCompressedBlock>();
                }
                IsEncrypted          = Ar.ReadFlag();
                CompressionBlockSize = Ar.Read <uint>();
            }

            if (reader.Info.Version >= EPakFileVersion.PakFile_Version_RelativeChunkOffsets)
            {
                // Convert relative compressed offsets to absolute
                for (var i = 0; i < CompressionBlocks.Length; i++)
                {
                    CompressionBlocks[i].CompressedStart += Offset;
                    CompressionBlocks[i].CompressedEnd   += Offset;
                }
            }

            StructSize = (ushort)(Ar.Position - startOffset);
        }
Ejemplo n.º 2
0
        public static async Task PopulateMenu()
        {
            PopulateBase();

            await Task.Run(() =>
            {
                if (string.IsNullOrEmpty(Properties.Settings.Default.PakPath))
                {
                    Application.Current.Dispatcher.Invoke(delegate
                    {
                        var launcher = new FLauncher();
                        if ((bool)launcher.ShowDialog())
                        {
                            Properties.Settings.Default.PakPath = launcher.Path;
                            Properties.Settings.Default.Save();
                        }
                    });
                }

                // define the current game thank to the pak path
                Folders.SetGameName(Properties.Settings.Default.PakPath);

                // Add Pak Files
                if (Directory.Exists(Properties.Settings.Default.PakPath))
                {
                    string[] paks = Directory.GetFiles(Properties.Settings.Default.PakPath, "*.pak");
                    for (int i = 0; i < paks.Length; i++)
                    {
                        if (!Utils.Paks.IsFileReadLocked(new FileInfo(paks[i])))
                        {
                            PakFileReader pakFile = new PakFileReader(paks[i]);
                            DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PAK]", "[Registering]", $"{pakFile.FileName} with GUID {pakFile.Info.EncryptionKeyGuid.Hex}");
                            if (i == 0)
                            {
                                Globals.Game.Version    = pakFile.Info.Version;
                                Globals.Game.SubVersion = pakFile.Info.SubVersion;
                            }

                            Application.Current.Dispatcher.Invoke(delegate
                            {
                                MenuItems.pakFiles.Add(new PakMenuItemViewModel
                                {
                                    PakFile   = pakFile,
                                    IsEnabled = false
                                });
                            });
                        }
                        else
                        {
                            FConsole.AppendText(string.Format(Properties.Resources.PakFileLocked, Path.GetFileNameWithoutExtension(paks[i])), FColors.Red, true);
                            DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PAK]", "[Locked]", paks[i]);
                        }
                    }
                }
            });
        }
Ejemplo n.º 3
0
 public static void Set(this PakPropertiesViewModel vm, PakFileReader pakFileReader)
 {
     Application.Current.Dispatcher.Invoke(delegate
     {
         vm.PakName    = pakFileReader.FileName;
         vm.Version    = ((int)pakFileReader.Info.Version).ToString();
         vm.MountPoint = pakFileReader.MountPoint;
         vm.AesKey     = pakFileReader.AesKey?.ToStringKey();
         vm.Guid       = pakFileReader.Info.EncryptionKeyGuid.Hex;
         vm.FileCount  = (pakFileReader as IReadOnlyDictionary <string, FPakEntry>).Count.ToString();
     });
 }
Ejemplo n.º 4
0
        public void Initialize(string file = "", Stream[] stream = null !)
        {
            var ext = file.SubstringAfter('.');

            if (string.IsNullOrEmpty(ext))
            {
                return;
            }

            if (ext.Equals("pak", StringComparison.OrdinalIgnoreCase))
            {
                try
                {
                    var reader = new PakFileReader(file, stream[0], Versions)
                    {
                        IsConcurrent = true
                    };
                    if (reader.IsEncrypted && !_requiredKeys.ContainsKey(reader.Info.EncryptionKeyGuid))
                    {
                        _requiredKeys[reader.Info.EncryptionKeyGuid] = null;
                    }
                    _unloadedVfs[reader] = null;
                }
                catch (Exception e)
                {
                    Log.Warning(e.ToString());
                }
            }
            else if (ext.Equals("utoc", StringComparison.OrdinalIgnoreCase))
            {
                try
                {
                    var reader = new IoStoreReader(file, stream[0], stream[1], EIoStoreTocReadOptions.ReadDirectoryIndex, Versions)
                    {
                        IsConcurrent = true
                    };
                    if (reader.IsEncrypted && !_requiredKeys.ContainsKey(reader.Info.EncryptionKeyGuid))
                    {
                        _requiredKeys[reader.Info.EncryptionKeyGuid] = null;
                    }
                    _unloadedVfs[reader] = null;
                }
                catch (Exception e)
                {
                    Log.Warning(e.ToString());
                }
            }
        }
Ejemplo n.º 5
0
        private async void OpenPak(string filename)
        {
            Enabled            = false;
            pbProgress.Visible = true;
            reader?.Dispose();

            await Task.Run(() => reader = new PakFileReader(new FileStream(filename, FileMode.Open, FileAccess.Read)));

            BuildFilesTree();
            treeView.Enabled = btnExtractAll.Enabled = true;
            slblFile.Text    = Path.GetFileName(filename);
            slblFiles.Text   = $"Files: {reader.Files.Count}";

            pbProgress.Visible = false;
            Enabled            = true;
            this.filename      = filename;
            Text = $"{Path.GetFileName(filename)} - {TITLE}";
        }
Ejemplo n.º 6
0
        public static async Task PopulateMenu()
        {
            PopulateBase();

            if (string.IsNullOrEmpty(Properties.Settings.Default.PakPath))
            {
                var launcher = new FLauncher();
                if ((bool)launcher.ShowDialog())
                {
                    Properties.Settings.Default.PakPath = launcher.Path;
                    Properties.Settings.Default.Save();
                }
            }

            // define the current game thank to the pak path
            Folders.SetGameName(Properties.Settings.Default.PakPath);

            // Add Pak Files
            if (Directory.Exists(Properties.Settings.Default.PakPath))
            {
                foreach (string pak in Directory.GetFiles(Properties.Settings.Default.PakPath, "*.pak"))
                {
                    if (!Utils.Paks.IsFileReadLocked(new FileInfo(pak)))
                    {
                        PakFileReader pakFile = new PakFileReader(pak);
                        DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PAK]", "[Registering]", $"{pakFile.FileName} with GUID {pakFile.Info.EncryptionKeyGuid.Hex}");

                        MenuItems.pakFiles.Add(new PakMenuItemViewModel
                        {
                            PakFile   = pakFile,
                            IsEnabled = false
                        });
                    }
                    else
                    {
                        Globals.gNotifier.ShowCustomMessage(Properties.Resources.PakFiles, string.Format(Properties.Resources.PakFileLocked, Path.GetFileNameWithoutExtension(pak)));
                        DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PAK]", "[Locked]", pak);
                    }
                }
            }

            await Task.CompletedTask.ConfigureAwait(false);
        }
Ejemplo n.º 7
0
        public static async Task PopulateMenu()
        {
            PopulateBase();

            await Task.Run(async() =>
            {
                if (string.IsNullOrEmpty(Properties.Settings.Default.PakPath))
                {
                    await Application.Current.Dispatcher.InvokeAsync(delegate
                    {
                        var launcher = new FLauncher();
                        bool?result  = launcher.ShowDialog();
                        if (result.HasValue && result.Value)
                        {
                            Properties.Settings.Default.PakPath = launcher.Path;
                            Properties.Settings.Default.Save();
                        }
                    });
                }

                // Add Pak Files
                if (Properties.Settings.Default.PakPath.EndsWith(".manifest"))
                {
                    ManifestInfo manifestInfo = await ManifestGrabber.TryGetLatestManifestInfo().ConfigureAwait(false);
                    byte[] manifestData       = await manifestInfo.DownloadManifestDataAsync().ConfigureAwait(false);
                    Manifest manifest         = new Manifest(manifestData, new ManifestOptions
                    {
                        ChunkBaseUri        = new Uri("http://download.epicgames.com/Builds/Fortnite/CloudDir/ChunksV3/", UriKind.Absolute),
                        ChunkCacheDirectory = Directory.CreateDirectory(Path.Combine(Properties.Settings.Default.OutputPath, "PakChunks"))
                    });
                    int pakFiles = 0;

                    foreach (FileManifest fileManifest in manifest.FileManifests)
                    {
                        if (!_pakFileRegex.IsMatch(fileManifest.Name))
                        {
                            continue;
                        }

                        var pakFileName       = fileManifest.Name.Replace('/', '\\');
                        PakFileReader pakFile = new PakFileReader(pakFileName, fileManifest.GetStream());

                        if (pakFiles++ == 0)
                        {
                            // define the current game thank to the pak path
                            Folders.SetGameName(pakFileName);

                            Globals.Game.Version    = pakFile.Info.Version;
                            Globals.Game.SubVersion = pakFile.Info.SubVersion;
                        }

                        await Application.Current.Dispatcher.InvokeAsync(delegate
                        {
                            MenuItems.pakFiles.Add(new PakMenuItemViewModel
                            {
                                PakFile   = pakFile,
                                IsEnabled = false
                            });
                        });
                    }
                }
                else if (Directory.Exists(Properties.Settings.Default.PakPath))
                {
                    // define the current game thank to the pak path
                    Folders.SetGameName(Properties.Settings.Default.PakPath);

                    string[] paks = Directory.GetFiles(Properties.Settings.Default.PakPath, "*.pak");
                    for (int i = 0; i < paks.Length; i++)
                    {
                        if (!Utils.Paks.IsFileReadLocked(new FileInfo(paks[i])))
                        {
                            PakFileReader pakFile = new PakFileReader(paks[i]);
                            DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PAK]", "[Registering]", $"{pakFile.FileName} with GUID {pakFile.Info.EncryptionKeyGuid.Hex}");
                            if (i == 0)
                            {
                                Globals.Game.Version    = pakFile.Info.Version;
                                Globals.Game.SubVersion = pakFile.Info.SubVersion;
                            }

                            await Application.Current.Dispatcher.InvokeAsync(delegate
                            {
                                MenuItems.pakFiles.Add(new PakMenuItemViewModel
                                {
                                    PakFile   = pakFile,
                                    IsEnabled = false
                                });
                            });
                        }
                        else
                        {
                            FConsole.AppendText(string.Format(Properties.Resources.PakFileLocked, Path.GetFileNameWithoutExtension(paks[i])), FColors.Red, true);
                            DebugHelper.WriteLine("{0} {1} {2} {3}", "[FModel]", "[PAK]", "[Locked]", paks[i]);
                        }
                    }
                }
            });
        }
Ejemplo n.º 8
0
        public static async Task PopulateMenu()
        {
            PopulateBase();

            await Task.Run(async() =>
            {
                if (string.IsNullOrEmpty(Properties.Settings.Default.PakPath))
                {
                    await Application.Current.Dispatcher.InvokeAsync(delegate
                    {
                        var launcher = new FLauncher();
                        bool?result  = launcher.ShowDialog();
                        if (result.HasValue && result.Value)
                        {
                            Properties.Settings.Default.PakPath = launcher.Path;
                            Properties.Settings.Default.Save();
                        }
                    });
                }

                // Add Pak Files
                if (Properties.Settings.Default.PakPath.EndsWith("-fn.manifest"))
                {
                    ManifestInfo manifestInfo = await ManifestGrabber.TryGetLatestManifestInfo().ConfigureAwait(false);

                    if (manifestInfo == null)
                    {
                        throw new Exception("Failed to load latest manifest.");
                    }

                    DirectoryInfo chunksDir = Directory.CreateDirectory(Path.Combine(Properties.Settings.Default.OutputPath, "PakChunks"));
                    string manifestPath     = Path.Combine(chunksDir.FullName, manifestInfo.Filename);
                    byte[] manifestData;

                    if (File.Exists(manifestPath))
                    {
                        manifestData = await File.ReadAllBytesAsync(manifestPath);
                    }
                    else
                    {
                        manifestData = await manifestInfo.DownloadManifestDataAsync().ConfigureAwait(false);
                        await File.WriteAllBytesAsync(manifestPath, manifestData).ConfigureAwait(false);
                    }

                    Manifest manifest = new Manifest(manifestData, new ManifestOptions
                    {
                        ChunkBaseUri        = new Uri("http://download.epicgames.com/Builds/Fortnite/CloudDir/ChunksV3/", UriKind.Absolute),
                        ChunkCacheDirectory = Directory.CreateDirectory(Path.Combine(Properties.Settings.Default.OutputPath, "PakChunks"))
                    });
                    int pakFiles = 0;

                    foreach (FileManifest fileManifest in manifest.FileManifests)
                    {
                        if (!_pakFileRegex.IsMatch(fileManifest.Name))
                        {
                            continue;
                        }

                        var pakStream = fileManifest.GetStream();
                        if (pakStream.Length == 365)
                        {
                            continue;
                        }

                        var pakFileName = fileManifest.Name.Replace('/', '\\');
                        if (pakFileName.EndsWith(".pak"))
                        {
                            PakFileReader pakFile = new PakFileReader(pakFileName, pakStream);
                            if (pakFiles++ == 0)
                            {
                                // define the current game thank to the pak path
                                Folders.SetGameName(pakFileName);

                                Globals.Game.Version    = pakFile.Info.Version;
                                Globals.Game.SubVersion = pakFile.Info.SubVersion;
                            }

                            await Application.Current.Dispatcher.InvokeAsync(delegate
                            {
                                MenuItems.pakFiles.Add(new PakMenuItemViewModel
                                {
                                    PakFile   = pakFile,
                                    IsEnabled = false
                                });
                            });
                        }
                        else if (pakFileName.EndsWith(".ucas"))
                        {
                            var utocStream = manifest.FileManifests.FirstOrDefault(x => x.Name.Equals(fileManifest.Name.Replace(".ucas", ".utoc")));
                            var ioStore    = new FFileIoStoreReader(pakFileName.SubstringAfterLast('\\'), pakFileName.SubstringBeforeLast('\\'), utocStream.GetStream(), pakStream);
                            await Application.Current.Dispatcher.InvokeAsync(delegate
                            {
                                MenuItems.pakFiles.Add(new PakMenuItemViewModel
                                {
                                    IoStore   = ioStore,
                                    IsEnabled = false
                                });
                            });
                        }
                    }
                }
                else if (Properties.Settings.Default.PakPath.EndsWith("-val.manifest"))
                {
                    ValorantAPIManifest manifest = await ValorantAPIManifest.DownloadAndParse(Directory.CreateDirectory(Path.Combine(Properties.Settings.Default.OutputPath, "PakChunks"))).ConfigureAwait(false);

                    if (manifest == null)
                    {
                        throw new Exception("Failed to load latest manifest.");
                    }

                    for (int i = 0; i < manifest.Paks.Length; i++)
                    {
                        ValorantPak pak = manifest.Paks[i];

                        var pakFileName       = @$ "ShooterGame\Content\Paks\{pak.Name}";
                        PakFileReader pakFile = new PakFileReader(pakFileName, manifest.GetPakStream(i));

                        if (i == 0)
                        {
                            // define the current game thank to the pak path
                            Folders.SetGameName(pakFileName);

                            Globals.Game.Version    = pakFile.Info.Version;
                            Globals.Game.SubVersion = pakFile.Info.SubVersion;
                        }

                        await Application.Current.Dispatcher.InvokeAsync(delegate
                        {
                            MenuItems.pakFiles.Add(new PakMenuItemViewModel
                            {
                                PakFile   = pakFile,
                                IsEnabled = false
                            });
                        });
                    }
                }
Ejemplo n.º 9
0
        public FPakEntry(PakFileReader reader, string path, FArchive Ar) : base(reader)
        {
            Path = path;
            // FPakEntry is duplicated before each stored file, without a filename. So,
            // remember the serialized size of this structure to avoid recomputation later.
            var startOffset = Ar.Position;

            Offset           = Ar.Read <long>();
            CompressedSize   = Ar.Read <long>();
            UncompressedSize = Ar.Read <long>();
            Size             = UncompressedSize;

            if (reader.Info.Version < EPakFileVersion.PakFile_Version_FNameBasedCompressionMethod)
            {
                var LegacyCompressionMethod = Ar.Read <ECompressionFlags>();
                int CompressionMethodIndex;

                if (LegacyCompressionMethod == ECompressionFlags.COMPRESS_None)
                {
                    CompressionMethodIndex = 0;
                }
                else if (LegacyCompressionMethod == ECompressionFlags.COMPRESS_LZ4)
                {
                    CompressionMethodIndex = 4;
                }
                else if (LegacyCompressionMethod.HasFlag(ECompressionFlags.COMPRESS_ZLIB))
                {
                    CompressionMethodIndex = 1;
                }
                else if (LegacyCompressionMethod.HasFlag(ECompressionFlags.COMPRESS_GZIP))
                {
                    CompressionMethodIndex = 2;
                }
                else if (LegacyCompressionMethod.HasFlag(ECompressionFlags.COMPRESS_Custom))
                {
                    CompressionMethodIndex = 3;
                }
                else
                {
                    CompressionMethodIndex = -1;
                    //throw new ParserException("Found an unknown compression type in pak file, will need to be supported for legacy files");
                }

                CompressionMethod = CompressionMethodIndex == -1 ? CompressionMethod.Unknown : reader.Info.CompressionMethods[CompressionMethodIndex];
            }
            else if (reader.Info.Version == EPakFileVersion.PakFile_Version_FNameBasedCompressionMethod && !reader.Info.IsSubVersion)
            {
                CompressionMethod = reader.Info.CompressionMethods[Ar.Read <byte>()];
            }
            else
            {
                CompressionMethod = reader.Info.CompressionMethods[Ar.Read <int>()];
            }

            if (reader.Info.Version < EPakFileVersion.PakFile_Version_NoTimestamps)
            {
                Ar.Position += 8; // Timestamp
            }
            Ar.Position += 20;    // Hash
            if (reader.Info.Version >= EPakFileVersion.PakFile_Version_CompressionEncryption)
            {
                if (CompressionMethod != CompressionMethod.None)
                {
                    CompressionBlocks = Ar.ReadArray <FPakCompressedBlock>();
                }
                IsEncrypted          = Ar.ReadFlag();
                CompressionBlockSize = Ar.Read <uint>();
            }

            if (reader.Info.Version >= EPakFileVersion.PakFile_Version_RelativeChunkOffsets)
            {
                // Convert relative compressed offsets to absolute
                for (var i = 0; i < CompressionBlocks.Length; i++)
                {
                    CompressionBlocks[i].CompressedStart += Offset;
                    CompressionBlocks[i].CompressedEnd   += Offset;
                }
            }

            StructSize = (int)(Ar.Position - startOffset);
        }
Ejemplo n.º 10
0
        public unsafe FPakEntry(PakFileReader reader, string path, byte *data) : base(reader)
        {
            Path     = path;
            Versions = reader.Ar.Versions;

            // UE4 reference: FPakFile::DecodePakEntry()
            uint bitfield = *(uint *)data;

            data += sizeof(uint);

            CompressionBlockSize = 0;
            if ((bitfield & 0x3f) == 0x3f) // flag value to load a field
            {
                CompressionBlockSize = *(uint *)data;
                data += sizeof(uint);
            }
            else
            {
                // for backwards compatibility with old paks :
                CompressionBlockSize = (bitfield & 0x3f) << 11;
            }

            CompressionMethod = reader.Info.CompressionMethods[(int)((bitfield >> 23) & 0x3f)];

            // Offset follows - either 32 or 64 bit value
            if ((bitfield & 0x80000000) != 0)
            {
                Offset = *(uint *)data;
                data  += sizeof(uint);
            }
            else
            {
                Offset = *(long *)data; // Should be ulong
                data  += sizeof(long);
            }

            // The same for UncompressedSize
            if ((bitfield & 0x40000000) != 0)
            {
                UncompressedSize = *(uint *)data;
                data            += sizeof(uint);
            }
            else
            {
                UncompressedSize = *(long *)data; // Should be ulong
                data            += sizeof(long);
            }

            Size = UncompressedSize;

            // Size field
            if (CompressionMethod != CompressionMethod.None)
            {
                if ((bitfield & 0x20000000) != 0)
                {
                    CompressedSize = *(uint *)data;
                    data          += sizeof(uint);
                }
                else
                {
                    CompressedSize = *(long *)data;
                    data          += sizeof(long);
                }
            }
            else
            {
                CompressedSize = UncompressedSize;
            }

            // bEncrypted
            IsEncrypted = ((bitfield >> 22) & 1) != 0;

            // Compressed block count
            var blockCount = (bitfield >> 6) & 0xffff;

            // Compute StructSize: each file still have FPakEntry data prepended, and it should be skipped.
            StructSize = sizeof(long) * 3 + sizeof(int) * 2 + 1 + 20;
            // Take into account CompressionBlocks
            if (CompressionMethod != CompressionMethod.None)
            {
                StructSize += (ushort)(sizeof(int) + blockCount * 2 * sizeof(long));
            }

            // Compression information
            CompressionBlocks = new FPakCompressedBlock[blockCount];
            if (blockCount > 0)
            {
                // CompressionBlockSize
                if (UncompressedSize < 65536)
                {
                    CompressionBlockSize = (uint)UncompressedSize;
                }

                // CompressionBlocks
                if (blockCount == 1 && !IsEncrypted)
                {
                    ref var b = ref CompressionBlocks[0];
                    b.CompressedStart = Offset + StructSize;
                    b.CompressedEnd   = b.CompressedStart + CompressedSize;
                }
                else
                {
                    var currentOffset = Offset + StructSize;
                    var alignment     = IsEncrypted ? Aes.ALIGN : 1;

                    for (int blockIndex = 0; blockIndex < blockCount; blockIndex++)
                    {
                        var currentBlockSize = *(uint *)data;
                        data += sizeof(uint);

                        ref var block = ref CompressionBlocks[blockIndex];
                        block.CompressedStart = currentOffset;
                        block.CompressedEnd   = currentOffset + currentBlockSize;
                        currentOffset        += currentBlockSize.Align(alignment);
                    }
                }
Ejemplo n.º 11
0
        public unsafe FPakEntry(PakFileReader reader, string path, byte *data) : base(reader)
        {
            Path = path;

            // UE4 reference: FPakFile::DecodePakEntry()
            uint bitfield = *(uint *)data;

            data += sizeof(uint);

            uint compressionBlockSize;

            if ((bitfield & 0x3f) == 0x3f) // flag value to load a field
            {
                compressionBlockSize = *(uint *)data;
                data += sizeof(uint);
            }
            else
            {
                // for backwards compatibility with old paks :
                compressionBlockSize = (bitfield & 0x3f) << 11;
            }

            // Filter out the CompressionMethod.
            CompressionMethod = reader.Info.CompressionMethods[(int)((bitfield >> 23) & 0x3f)];

            // Test for 32-bit safe values. Grab it, or memcpy the 64-bit value
            // to avoid alignment exceptions on platforms requiring 64-bit alignment
            // for 64-bit variables.
            //
            // Read the Offset.
            var bIsOffset32BitSafe = (bitfield & (1 << 31)) != 0;

            if (bIsOffset32BitSafe)
            {
                Offset = *(uint *)data;
                data  += sizeof(uint);
            }
            else
            {
                Offset = *(long *)data; // Should be ulong
                data  += sizeof(long);
            }

            // Read the UncompressedSize.
            var bIsUncompressedSize32BitSafe = (bitfield & (1 << 30)) != 0;

            if (bIsUncompressedSize32BitSafe)
            {
                UncompressedSize = *(uint *)data;
                data            += sizeof(uint);
            }
            else
            {
                UncompressedSize = *(long *)data; // Should be ulong
                data            += sizeof(long);
            }

            Size = UncompressedSize;

            // Fill in the Size.
            if (CompressionMethod != CompressionMethod.None)
            {
                var bIsSize32BitSafe = (bitfield & (1 << 29)) != 0;
                if (bIsSize32BitSafe)
                {
                    CompressedSize = *(uint *)data;
                    data          += sizeof(uint);
                }
                else
                {
                    CompressedSize = *(long *)data;
                    data          += sizeof(long);
                }
            }
            else
            {
                // The Size is the same thing as the UncompressedSize when
                // CompressionMethod == CompressionMethod.None.
                CompressedSize = UncompressedSize;
            }

            // Filter the encrypted flag.
            Flags |= (bitfield & (1 << 22)) != 0 ? 1u : 0u;

            // This should clear out any excess CompressionBlocks that may be valid in the user's
            // passed in entry.
            var compressionBlocksCount = (bitfield >> 6) & 0xffff;

            CompressionBlocks = new FPakCompressedBlock[compressionBlocksCount];

            CompressionBlockSize = 0;
            if (compressionBlocksCount > 0)
            {
                CompressionBlockSize = compressionBlockSize;
                // Per the comment in Encode, if compressionBlocksCount == 1, we use UncompressedSize for CompressionBlockSize
                if (compressionBlocksCount == 1)
                {
                    CompressionBlockSize = (uint)UncompressedSize;
                }
            }

            // Compute StructSize: each file still have FPakEntry data prepended, and it should be skipped.
            StructSize = sizeof(long) * 3 + sizeof(int) * 2 + 1 + 20;
            // Take into account CompressionBlocks
            if (CompressionMethod != CompressionMethod.None)
            {
                StructSize += (int)(sizeof(int) + compressionBlocksCount * 2 * sizeof(long));
            }

            // Handle building of the CompressionBlocks array.
            if (compressionBlocksCount == 1 && !IsEncrypted)
            {
                // If the number of CompressionBlocks is 1, we didn't store any extra information.
                // Derive what we can from the entry's file offset and size.
                ref var b = ref CompressionBlocks[0];
                b.CompressedStart = Offset + StructSize;
                b.CompressedEnd   = b.CompressedStart + CompressedSize;
            }
Ejemplo n.º 12
0
        public void Initialize()
        {
            if (!_workingDirectory.Exists)
            {
                throw new ArgumentException("Given directory must exist", nameof(_workingDirectory));
            }

            var osFiles = new Dictionary <string, GameFile>();

            foreach (var file in _workingDirectory.EnumerateFiles("*.*", _searchOption))
            {
                var ext = file.Extension.SubstringAfter('.');
                if (!file.Exists || string.IsNullOrEmpty(ext))
                {
                    return;
                }

                if (ext.Equals("pak", StringComparison.OrdinalIgnoreCase))
                {
                    try
                    {
                        var reader = new PakFileReader(file, Game, Ver)
                        {
                            IsConcurrent = true
                        };
                        if (reader.IsEncrypted && !_requiredKeys.ContainsKey(reader.Info.EncryptionKeyGuid))
                        {
                            _requiredKeys[reader.Info.EncryptionKeyGuid] = null;
                        }
                        _unloadedVfs[reader] = null;
                    }
                    catch (Exception e)
                    {
                        Log.Warning(e.ToString());
                    }
                }
                else if (ext.Equals("utoc", StringComparison.OrdinalIgnoreCase))
                {
                    try
                    {
                        var reader = new IoStoreReader(file, EIoStoreTocReadOptions.ReadDirectoryIndex, Game, Ver)
                        {
                            IsConcurrent = true
                        };
                        if (reader.IsEncrypted && !_requiredKeys.ContainsKey(reader.Info.EncryptionKeyGuid))
                        {
                            _requiredKeys[reader.Info.EncryptionKeyGuid] = null;
                        }
                        _unloadedVfs[reader] = null;
                    }
                    catch (Exception e)
                    {
                        Log.Warning(e.ToString());
                    }
                }
                else
                {
                    // Register local file only if it has a known extension, we don't need every file
                    if (!GameFile.Ue4KnownExtensions.Contains(ext, StringComparer.OrdinalIgnoreCase))
                    {
                        continue;
                    }

                    var osFile = new OsGameFile(_workingDirectory, file, Game, Ver);
                    if (IsCaseInsensitive)
                    {
                        osFiles[osFile.Path.ToLowerInvariant()] = osFile;
                    }
                    else
                    {
                        osFiles[osFile.Path] = osFile;
                    }
                }
            }

            _files.AddFiles(osFiles);
        }