public bool UnpackNode(FileInfoKey nodeKey, string filePath) { ulong offset = DataOffset + (ulong)nodeKey.SegmentIndex * GTVolumeTOC.SEGMENT_SIZE; uint uncompressedSize = nodeKey.UncompressedSize; if (!IsPatchVolume) { if (NoUnpack) { return(false); } Stream.Position = (long)offset; if (nodeKey.Flags.HasFlag(FileInfoFlags.Compressed)) { if (!MiscUtils.DecryptCheckCompression(Stream, Keyset, nodeKey.FileIndex, uncompressedSize)) { Program.Log($"[X] Failed to decompress file ({filePath}) while unpacking file info key {nodeKey.FileIndex}", forceConsolePrint: true); return(false); } Directory.CreateDirectory(Path.GetDirectoryName(filePath)); Stream.Position -= 8; MiscUtils.DecryptAndInflateToFile(Keyset, Stream, nodeKey.FileIndex, uncompressedSize, filePath, false); } else { Directory.CreateDirectory(Path.GetDirectoryName(filePath)); MiscUtils.DecryptToFile(Keyset, Stream, nodeKey.FileIndex, uncompressedSize, filePath, false); } } else { string patchFilePath = PDIPFSPathResolver.GetPathFromSeed(nodeKey.FileIndex); string localPath = this.PatchVolumeFolder + "/" + patchFilePath; if (NoUnpack) { return(false); } /* I'm really not sure if there's a better way to do this. * Volume files, at least nodes don't seem to even store any special flag whether * it is located within an actual volume file or a patch volume. The only thing that is different is the sector index.. Sometimes node index when it's updated * It's slow, but somewhat works I guess.. * */ if (!File.Exists(localPath)) { return(false); } Program.Log($"[:] Unpacking: {patchFilePath} -> {filePath}"); using var fs = new FileStream(localPath, FileMode.Open); if (fs.Length >= 7) { Span <byte> magic = stackalloc byte[6]; fs.Read(magic); if (Encoding.ASCII.GetString(magic).StartsWith("BSDIFF")) { Program.Log($"[X] Detected BSDIFF file for {filePath} ({patchFilePath}), can not unpack yet. (fileID {nodeKey.FileIndex})", forceConsolePrint: true); return(false); } fs.Position = 0; } if (nodeKey.Flags.HasFlag(FileInfoFlags.Compressed)) { if (!MiscUtils.DecryptCheckCompression(fs, Keyset, nodeKey.FileIndex, uncompressedSize)) { Program.Log($"[X] Failed to decompress file {filePath} ({patchFilePath}) while unpacking file info key {nodeKey.FileIndex}", forceConsolePrint: true); return(false); } Directory.CreateDirectory(Path.GetDirectoryName(filePath)); fs.Position = 0; MiscUtils.DecryptAndInflateToFile(Keyset, fs, nodeKey.FileIndex, filePath); } else { Directory.CreateDirectory(Path.GetDirectoryName(filePath)); MiscUtils.DecryptToFile(Keyset, fs, nodeKey.FileIndex, filePath); } } return(true); }