private static SwitchFs OpenSdCard(string path, IProgressReport logger = null) { SwitchFs switchFs; Keyset keyset = OpenKeyset(); var baseFs = new LocalFileSystem(path); if (Directory.Exists(Path.Combine(path, "Nintendo", "Contents", "registered"))) { logger?.LogMessage("Treating path as SD card storage"); switchFs = SwitchFs.OpenSdCard(keyset, baseFs); } else if (Directory.Exists(Path.Combine(path, "Contents", "registered"))) { logger?.LogMessage("Treating path as NAND storage"); switchFs = SwitchFs.OpenNandPartition(keyset, baseFs); } else { logger?.LogMessage("Treating path as a directory of loose NCAs"); switchFs = SwitchFs.OpenNcaDirectory(keyset, baseFs); } return(switchFs); }
private static void ReadTitleKeys(Keyset keyset, string filename, IProgressReport progress = null) { if (filename == null) { return; } using (var reader = new StreamReader(new FileStream(filename, FileMode.Open, FileAccess.Read))) { string line; while ((line = reader.ReadLine()) != null) { string[] splitLine; // Some people use pipes as delimiters if (line.Contains('|')) { splitLine = line.Split('|'); } else { splitLine = line.Split(',', '='); } if (splitLine.Length < 2) { continue; } if (!splitLine[0].Trim().TryToBytes(out byte[] rightsId)) { progress?.LogMessage($"Invalid rights ID \"{splitLine[0].Trim()}\" in title key file"); continue; } if (!splitLine[1].Trim().TryToBytes(out byte[] titleKey)) { progress?.LogMessage($"Invalid title key \"{splitLine[1].Trim()}\" in title key file"); continue; } if (rightsId.Length != TitleKeySize) { progress?.LogMessage($"Rights ID {rightsId.ToHexString()} had incorrect size {rightsId.Length}. (Expected {TitleKeySize})"); continue; } if (titleKey.Length != TitleKeySize) { progress?.LogMessage($"Title key {titleKey.ToHexString()} had incorrect size {titleKey.Length}. (Expected {TitleKeySize})"); continue; } keyset.TitleKeys[rightsId] = titleKey; } } }
public static void PrintAllTables(BdatStringCollection bdats, string jsonDir, IProgressReport progress = null) { progress?.LogMessage("Writing BDAT tables as JSON"); progress?.SetTotal(bdats.Tables.Count); string bdatHtmlDir = Path.Combine(jsonDir, "json"); Directory.CreateDirectory(bdatHtmlDir); foreach (string tableName in bdats.Tables.Keys) { string outDir = bdatHtmlDir; string tableFilename = bdats[tableName].Filename; string json = PrintTable(bdats[tableName]); if (tableFilename != null) { outDir = Path.Combine(outDir, tableFilename); } string filename = Path.Combine(outDir, tableName + ".json"); Directory.CreateDirectory(outDir); File.WriteAllText(filename, json); progress?.ReportAdd(1); } }
public IEnumerable <byte[]> EnumerateFiles(IProgressReport progress = null) { FileListTab[] fileListTabs = Table20.FileList; progress?.SetTotal(fileListTabs.Length); for (int i = 0; i < fileListTabs.Length; i++) { bool success = false; byte[] data = new byte[0]; try { data = GetFileFromIndex(i); success = true; } catch (Exception) { progress?.LogMessage($"Error getting file {i}"); } if (success) { yield return(data); } progress?.ReportAdd(1); } }
public static Validity VerifySection(this Nca nca, Nca patchNca, int index, IProgressReport logger = null, bool quiet = false) { NcaFsHeader sect = nca.Header.GetFsHeader(index); NcaHashType hashType = sect.HashType; if (hashType != NcaHashType.Sha256 && hashType != NcaHashType.Ivfc) { return(Validity.Unchecked); } var stream = nca.OpenStorageWithPatch(patchNca, index, IntegrityCheckLevel.IgnoreOnInvalid) as HierarchicalIntegrityVerificationStorage; if (stream == null) { return(Validity.Unchecked); } if (!quiet) { logger?.LogMessage($"Verifying section {index}..."); } Validity validity = stream.Validate(true, logger); return(validity); }
public static bool AddHashIfExists(string value, bool addToAllHashList = true, IProgressReport progress = null) { value = value.ToLowerInvariant(); uint hash = Archive.Crc32(value); long key = (long)value.Length << 32 | hash; if (addToAllHashList) { AllHashStrings[key] = value; } if (Hashes.Contains(key) && !HashStrings.ContainsKey(key) && !value.Contains('%')) { HashStrings[key] = value; NewStrings[key] = value; if (progress == null) { Console.WriteLine($"Found new hash {value}"); } else { progress.LogMessage($"Found new hash {value}"); } return(true); } return(false); }
private void DecryptKeyblobs(IProgressReport logger = null) { var cmac = new byte[0x10]; var expectedCmac = new byte[0x10]; var counter = new byte[0x10]; for (int i = 0; i < UsedKeyblobCount; i++) { if (KeyblobKeys[i].IsEmpty() || KeyblobMacKeys[i].IsEmpty() || EncryptedKeyblobs[i].IsEmpty()) { continue; } Array.Copy(EncryptedKeyblobs[i], expectedCmac, 0x10); CryptoOld.CalculateAesCmac(KeyblobMacKeys[i], EncryptedKeyblobs[i], 0x10, cmac, 0, 0xa0); if (!Util.ArraysEqual(cmac, expectedCmac)) { logger?.LogMessage($"Warning: Keyblob MAC {i:x2} is invalid. Are SBK/TSEC key correct?"); } Array.Copy(EncryptedKeyblobs[i], 0x10, counter, 0, 0x10); Aes.DecryptCtr128(EncryptedKeyblobs[i].AsSpan(0x20), Keyblobs[i], KeyblobKeys[i], counter); } }
public static void CopyDirectory(this IDirectory source, IDirectory dest, IProgressReport logger = null, CreateFileOptions options = CreateFileOptions.None) { IFileSystem sourceFs = source.ParentFileSystem; IFileSystem destFs = dest.ParentFileSystem; foreach (DirectoryEntry entry in source.Read()) { string subSrcPath = PathTools.Normalize(source.FullPath + '/' + entry.Name); string subDstPath = PathTools.Normalize(dest.FullPath + '/' + entry.Name); if (entry.Type == DirectoryEntryType.Directory) { destFs.CreateDirectory(subDstPath); IDirectory subSrcDir = sourceFs.OpenDirectory(subSrcPath, OpenDirectoryMode.All); IDirectory subDstDir = destFs.OpenDirectory(subDstPath, OpenDirectoryMode.All); subSrcDir.CopyDirectory(subDstDir, logger, options); } if (entry.Type == DirectoryEntryType.File) { destFs.CreateFile(subDstPath, entry.Size, options); using (IFile srcFile = sourceFs.OpenFile(subSrcPath, OpenMode.Read)) using (IFile dstFile = destFs.OpenFile(subDstPath, OpenMode.Write | OpenMode.Append)) { logger?.LogMessage(subSrcPath); srcFile.CopyTo(dstFile, logger); } } } }
private void DecryptKeyblobs(IProgressReport logger = null) { var cmac = new byte[0x10]; var expectedCmac = new byte[0x10]; var counter = new byte[0x10]; for (int i = 0; i < UsedKeyblobCount; i++) { if (KeyblobKeys[i].IsEmpty() || KeyblobMacKeys[i].IsEmpty() || EncryptedKeyblobs[i].IsEmpty()) { continue; } Array.Copy(EncryptedKeyblobs[i], expectedCmac, 0x10); Crypto.CalculateAesCmac(KeyblobMacKeys[i], EncryptedKeyblobs[i], 0x10, cmac, 0, 0xa0); if (!Util.ArraysEqual(cmac, expectedCmac)) { logger?.LogMessage($"Warning: Keyblob MAC {i:x2} is invalid. Are SBK/TSEC key correct?"); } Array.Copy(EncryptedKeyblobs[i], 0x10, counter, 0, 0x10); using (var keyblobDec = new Aes128CtrStorage( new MemoryStorage(EncryptedKeyblobs[i], 0x20, Keyblobs[i].Length), KeyblobKeys[i], counter, false)) { keyblobDec.Read(Keyblobs[i], 0); } } }
public static void CopyDirectory(this FileSystemManager fs, string sourcePath, string destPath, CreateFileOptions options = CreateFileOptions.None, IProgressReport logger = null) { using (DirectoryHandle sourceHandle = fs.OpenDirectory(sourcePath, OpenDirectoryMode.All)) { foreach (DirectoryEntry entry in fs.ReadDirectory(sourceHandle)) { string subSrcPath = PathTools.Normalize(PathTools.Combine(sourcePath, entry.Name)); string subDstPath = PathTools.Normalize(PathTools.Combine(destPath, entry.Name)); if (entry.Type == DirectoryEntryType.Directory) { fs.EnsureDirectoryExists(subDstPath); fs.CopyDirectory(subSrcPath, subDstPath, options, logger); } if (entry.Type == DirectoryEntryType.File) { logger?.LogMessage(subSrcPath); fs.CreateOrOverwriteFile(subDstPath, entry.Size, options); fs.CopyFile(subSrcPath, subDstPath, logger); } } } }
private static void CopyDirectoryWithProgressInternal(FileSystemClient fs, string sourcePath, string destPath, CreateFileOptions options, IProgressReport logger) { fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath, OpenDirectoryMode.All).ThrowIfFailure(); using (sourceHandle) { foreach (DirectoryEntryEx entry in fs.EnumerateEntries(sourcePath, "*", SearchOptions.Default)) { string subSrcPath = PathTools.Normalize(PathTools.Combine(sourcePath, entry.Name)); string subDstPath = PathTools.Normalize(PathTools.Combine(destPath, entry.Name)); if (entry.Type == DirectoryEntryType.Directory) { fs.EnsureDirectoryExists(subDstPath); CopyDirectoryWithProgressInternal(fs, subSrcPath, subDstPath, options, logger); } if (entry.Type == DirectoryEntryType.File) { logger?.LogMessage(subSrcPath); fs.CreateOrOverwriteFile(subDstPath, entry.Size, options); CopyFileWithProgress(fs, subSrcPath, subDstPath, logger); } } } }
private static Result CopyDirectoryWithProgressInternal(FileSystemClient fs, U8Span sourcePath, U8Span destPath, CreateFileOptions options, IProgressReport logger) { string sourcePathStr = sourcePath.ToString(); string destPathStr = destPath.ToString(); Result rc = fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath, OpenDirectoryMode.All); if (rc.IsFailure()) { return(rc); } try { foreach (DirectoryEntryEx entry in fs.EnumerateEntries(sourcePathStr, "*", SearchOptions.Default)) { string subSrcPath = PathTools.Normalize(PathTools.Combine(sourcePathStr, entry.Name)); string subDstPath = PathTools.Normalize(PathTools.Combine(destPathStr, entry.Name)); if (entry.Type == DirectoryEntryType.Directory) { fs.EnsureDirectoryExists(subDstPath); rc = CopyDirectoryWithProgressInternal(fs, subSrcPath.ToU8Span(), subDstPath.ToU8Span(), options, logger); if (rc.IsFailure()) { return(rc); } } if (entry.Type == DirectoryEntryType.File) { logger?.LogMessage(subSrcPath); rc = fs.CreateOrOverwriteFile(subDstPath, entry.Size, options); if (rc.IsFailure()) { return(rc); } rc = CopyFileWithProgress(fs, subSrcPath.ToU8Span(), subDstPath.ToU8Span(), logger); if (rc.IsFailure()) { return(rc); } } } } finally { if (sourceHandle.IsValid) { fs.CloseDirectory(sourceHandle); } } return(Result.Success); }
public static void PrintSeparateTables(BdatStringCollection bdats, string htmlDir, IProgressReport progress = null) { progress?.LogMessage("Writing BDAT tables as HTML"); progress?.SetTotal(bdats.Tables.Count); string bdatHtmlDir = Path.Combine(htmlDir, "bdat"); Directory.CreateDirectory(bdatHtmlDir); if (bdats.Game == Game.XB2) { PrintIndex(bdats, htmlDir); } PrintBdatIndex(bdats, bdatHtmlDir); foreach (string tableName in bdats.Tables.Keys) { string outDir = bdatHtmlDir; string tableFilename = bdats[tableName].Filename; string indexPath = tableFilename == null ? "index.html" : "../index.html"; var sb = new Indenter(2); sb.AppendLine("<!DOCTYPE html>"); sb.AppendLineAndIncrease("<html>"); sb.AppendLineAndIncrease("<head>"); sb.AppendLine("<meta charset=\"utf-8\" />"); sb.AppendLine($"<title>{tableName}</title>"); sb.AppendLineAndIncrease("<style>"); sb.AppendLine(CssSticky); sb.AppendLine(CssSortable); sb.DecreaseAndAppendLine("</style>"); sb.DecreaseAndAppendLine("</head>"); sb.AppendLineAndIncrease("<body>"); sb.AppendLine($"<a href=\"{indexPath}\">Return to BDAT index</a><br/>"); sb.AppendLine("<input type=\"button\" value=\"Open all references\" onclick=\"openAll(true)\" />"); sb.AppendLine("<input type=\"button\" value=\"Close all references\" onclick=\"openAll(false)\" />"); PrintTable(bdats[tableName], sb); sb.AppendLineAndIncrease("<script>"); sb.AppendLine(JsOpenAll); sb.AppendLine(JsSortable); sb.AppendLine(JsAnchor); sb.DecreaseAndAppendLine("</script>"); sb.DecreaseAndAppendLine("</body>"); sb.DecreaseAndAppendLine("</html>"); if (tableFilename != null) { outDir = Path.Combine(outDir, tableFilename); } string filename = Path.Combine(outDir, tableName + ".html"); Directory.CreateDirectory(outDir); File.WriteAllText(filename, sb.ToString()); progress?.ReportAdd(1); } }
public Crack(string path, IProgressReport progress = null) { Progress = progress; if (Directory.Exists(path)) { Path = path; } else { Progress?.LogMessage($"Directory {path} does not exist."); } }
private static void ReadMainKeys(Keyset keyset, string filename, Dictionary <string, KeyValue> keyDict, IProgressReport logger = null) { if (filename == null) { return; } using (var reader = new StreamReader(new FileStream(filename, FileMode.Open, FileAccess.Read))) { string line; while ((line = reader.ReadLine()) != null) { string[] a = line.Split(',', '='); if (a.Length != 2) { continue; } string key = a[0].Trim(); string valueStr = a[1].Trim(); if (!keyDict.TryGetValue(key, out KeyValue kv)) { logger?.LogMessage($"Failed to match key {key}"); continue; } byte[] value = valueStr.ToBytes(); if (value.Length != kv.Size) { logger?.LogMessage($"Key {key} had incorrect size {value.Length}. (Expected {kv.Size})"); continue; } byte[] dest = kv.GetKey(keyset); Array.Copy(value, dest, value.Length); } } }
public static void GenerateBdatHtml(IFileSystem fs, string outDir, IProgressReport progress) { var bdats = new BdatTables(fs, true, progress); BdatStringCollection tablesStr = DeserializeStrings.DeserializeTables(bdats, progress); Metadata.ApplyMetadata(tablesStr); HtmlGen.PrintSeparateTables(tablesStr, Path.Combine(outDir, BdatDir), progress); JsonGen.PrintAllTables(tablesStr, Path.Combine(outDir, JsonDir), progress); BdatCollection tables = Deserialize.DeserializeTables(bdats, progress); string dataDir = Path.Combine(outDir, DataDir); progress.SetTotal(0); progress.LogMessage("Creating salvaging tables"); Directory.CreateDirectory(dataDir); string salvaging = SalvagingTable.Print(tables); File.WriteAllText(Path.Combine(dataDir, "salvaging.html"), salvaging); progress.LogMessage("Creating enemy tables"); using (var writer = new StreamWriter(Path.Combine(dataDir, "enemies.csv"))) { Enemies.PrintEnemies(tables, writer); } progress.LogMessage("Creating achievement tables"); using (var writer = new StreamWriter(Path.Combine(dataDir, "achievements.csv"))) { Achievements.PrintAchievements(tables, writer); } string gmkDir = Path.Combine(outDir, GmkDir); MapInfo[] gimmicks = ReadGmk.ReadAll(fs, tables, progress); progress.LogMessage("Writing map info and gimmick data"); ExportMap.ExportCsv(gimmicks, gmkDir); }
public static Result CopyDirectory(this IFileSystem sourceFs, IFileSystem destFs, string sourcePath, string destPath, IProgressReport logger = null, CreateFileOptions options = CreateFileOptions.None) { Result rc; foreach (DirectoryEntryEx entry in sourceFs.EnumerateEntries(sourcePath, "*", SearchOptions.Default)) { string subSrcPath = PathTools.Normalize(PathTools.Combine(sourcePath, entry.Name)); string subDstPath = PathTools.Normalize(PathTools.Combine(destPath, entry.Name)); if (entry.Type == DirectoryEntryType.Directory) { destFs.EnsureDirectoryExists(subDstPath); rc = sourceFs.CopyDirectory(destFs, subSrcPath, subDstPath, logger, options); if (rc.IsFailure()) { return(rc); } } if (entry.Type == DirectoryEntryType.File) { destFs.CreateOrOverwriteFile(subDstPath, entry.Size, options); rc = sourceFs.OpenFile(out IFile srcFile, subSrcPath.ToU8Span(), OpenMode.Read); if (rc.IsFailure()) { return(rc); } using (srcFile) { rc = destFs.OpenFile(out IFile dstFile, subDstPath.ToU8Span(), OpenMode.Write | OpenMode.AllowAppend); if (rc.IsFailure()) { return(rc); } using (dstFile) { logger?.LogMessage(subSrcPath); srcFile.CopyTo(dstFile, logger); } } } } return(Result.Success); }
public GuessAdx(string path, string executable, IProgressReport progress = null) { Progress = progress; Progress?.SetTotal(0x1000); if (Directory.Exists(path)) { EncryptionType = LoadFiles(Directory.GetFiles(path, "*.adx")); } else if (File.Exists(path)) { EncryptionType = LoadFiles(path); } else { Progress?.LogMessage($"{path} does not exist."); } switch (EncryptionType) { case 8: int[] primes = Common.GetPrimes(0x8000); // .NET returns the bitwise complement of the index of the first element // smaller than the search value if it is not found in the array int start = ~Array.BinarySearch(primes, 0x4000); PossibleMultipliers = new int[0x400]; Array.Copy(primes, start, PossibleMultipliers, 0, 0x400); PossibleIncrements = PossibleMultipliers; PossibleSeeds = new HashSet <int>(PossibleMultipliers); ValidationMask = 0xE000; MaxSeed = 0x8000; break; case 9: PossibleSeeds = new HashSet <int>(Enumerable.Range(0, 0x2000)); PossibleMultipliers = Enumerable.Range(0, 0x2000).Where(x => (x & 3) == 1).ToArray(); PossibleIncrements = Enumerable.Range(0, 0x2000).Where(x => (x & 1) == 1).ToArray(); ValidationMask = 0x1000; MaxSeed = 0x2000; break; } if (EncryptionType == 8 && executable != null) { KeyStrings = LoadStrings(executable, path); } }
// Benchmarks encrypting each block separately, initializing a new cipher object for each one private static void CipherBenchmarkSeparate(ReadOnlySpan <byte> src, Span <byte> dst, CipherTaskSeparate function, int iterations, string label, bool dotNetCrypto, IProgressReport logger) { Debug.Assert(src.Length == dst.Length); var watch = new Stopwatch(); double[] runTimes = new double[iterations]; ReadOnlySpan <byte> key1 = stackalloc byte[0x10]; ReadOnlySpan <byte> key2 = stackalloc byte[0x10]; ReadOnlySpan <byte> iv = stackalloc byte[0x10]; logger.SetTotal(iterations); const int blockSize = BlockSizeSeparate; int blockCount = src.Length / blockSize; for (int i = 0; i < iterations; i++) { watch.Restart(); for (int b = 0; b < blockCount; b++) { function(src.Slice(b * blockSize, blockSize), dst.Slice(b * blockSize, blockSize), key1, key2, iv, dotNetCrypto); } watch.Stop(); logger.ReportAdd(1); runTimes[i] = watch.Elapsed.TotalSeconds; } logger.SetTotal(0); long srcSize = src.Length; double fastestRun = runTimes.Min(); double averageRun = runTimes.Average(); double slowestRun = runTimes.Max(); string fastestRate = Utilities.GetBytesReadable((long)(srcSize / fastestRun)); string averageRate = Utilities.GetBytesReadable((long)(srcSize / averageRun)); string slowestRate = Utilities.GetBytesReadable((long)(srcSize / slowestRun)); logger.LogMessage($"{label}{averageRate}/s, fastest run: {fastestRate}/s, slowest run: {slowestRate}/s"); }
public static BdatStringCollection DeserializeTables(BdatTables tables, IProgressReport progress = null) { var collection = new BdatStringCollection { Bdats = tables }; progress?.LogMessage("Parsing BDAT tables"); progress?.SetTotal(tables.Tables.Length); foreach (BdatTable table in tables.Tables) { var items = new BdatStringItem[table.ItemCount]; var stringTable = new BdatStringTable { Collection = collection, Name = table.Name, BaseId = table.BaseId, Members = table.Members, Items = items, Filename = table.Filename }; if (tables.DisplayFields.TryGetValue(table.Name, out string displayMember)) { stringTable.DisplayMember = displayMember; } for (int i = 0; i < table.ItemCount; i++) { BdatStringItem item = ReadItem(table, i); item.Table = stringTable; item.Id = table.BaseId + i; if (displayMember != null) { item.Display = item[displayMember]; } items[i] = item; } collection.Add(stringTable); progress?.ReportAdd(1); } return(collection); }
public static BdatCollection DeserializeTables(BdatTables files, IProgressReport progress = null) { progress?.LogMessage("Deserializing BDAT tables"); progress?.SetTotal(files.Tables.Length); var tables = new BdatCollection(); foreach (BdatTable table in files.Tables) { ReadTable(table, tables); progress?.ReportAdd(1); } ReadFunctions.SetReferences(tables); return(tables); }
private static Ticket[] GetTickets(Keyset keyset, Nand nand, IProgressReport logger = null) { var tickets = new List <Ticket>(); FatFileSystemProvider system = nand.OpenSystemPartition(); IFile saveE1File = system.OpenFile("/save/80000000000000E1", OpenMode.Read); tickets.AddRange(ReadTickets(keyset, saveE1File.AsStream())); IFile saveE2 = system.OpenFile("/save/80000000000000E2", OpenMode.Read); tickets.AddRange(ReadTickets(keyset, saveE2.AsStream())); logger?.LogMessage($"Found {tickets.Count} tickets"); return(tickets.ToArray()); }
private static Ticket[] GetTickets(Keyset keyset, Nand nand, IProgressReport logger = null) { var tickets = new List <Ticket>(); NandPartition system = nand.OpenSystemPartition(); Stream saveE1File = system.OpenFile("save\\80000000000000E1", FileMode.Open, FileAccess.Read); tickets.AddRange(ReadTickets(keyset, saveE1File)); Stream saveE2 = system.OpenFile("save\\80000000000000E2", FileMode.Open, FileAccess.Read); tickets.AddRange(ReadTickets(keyset, saveE2)); logger?.LogMessage($"Found {tickets.Count} tickets"); return(tickets.ToArray()); }
private static void CipherBenchmarkBlocked(ReadOnlySpan <byte> src, Span <byte> dst, Func <ICipher> cipherGenerator, int iterations, string label, IProgressReport logger) { cipherGenerator().Transform(src, dst); var watch = new Stopwatch(); double[] runTimes = new double[iterations]; logger.SetTotal(iterations); int blockCount = src.Length / BlockSizeBlocked; for (int i = 0; i < iterations; i++) { ICipher cipher = cipherGenerator(); watch.Restart(); for (int b = 0; b < blockCount; b++) { cipher.Transform(src.Slice(b * BlockSizeBlocked, BlockSizeBlocked), dst.Slice(b * BlockSizeBlocked, BlockSizeBlocked)); } watch.Stop(); logger.ReportAdd(1); runTimes[i] = watch.Elapsed.TotalSeconds; } logger.SetTotal(0); long srcSize = src.Length; double fastestRun = runTimes.Min(); double averageRun = runTimes.Average(); double slowestRun = runTimes.Max(); string fastestRate = Utilities.GetBytesReadable((long)(srcSize / fastestRun)); string averageRate = Utilities.GetBytesReadable((long)(srcSize / averageRun)); string slowestRate = Utilities.GetBytesReadable((long)(srcSize / slowestRun)); logger.LogMessage($"{label}{averageRate}/s, fastest run: {fastestRate}/s, slowest run: {slowestRate}/s"); }
public static Result CopyDirectory(this FileSystemClient fs, string sourcePath, string destPath, CreateFileOptions options = CreateFileOptions.None, IProgressReport logger = null) { Result rc = fs.OpenDirectory(out DirectoryHandle sourceHandle, sourcePath.ToU8Span(), OpenDirectoryMode.All); if (rc.IsFailure()) { return(rc); } using (sourceHandle) { foreach (DirectoryEntryEx entry in fs.EnumerateEntries(sourcePath, "*", SearchOptions.Default)) { string subSrcPath = PathTools.Normalize(PathTools.Combine(sourcePath, entry.Name)); string subDstPath = PathTools.Normalize(PathTools.Combine(destPath, entry.Name)); if (entry.Type == DirectoryEntryType.Directory) { fs.EnsureDirectoryExists(subDstPath); rc = fs.CopyDirectory(subSrcPath, subDstPath, options, logger); if (rc.IsFailure()) { return(rc); } } if (entry.Type == DirectoryEntryType.File) { logger?.LogMessage(subSrcPath); fs.CreateOrOverwriteFile(subDstPath, entry.Size, options); rc = fs.CopyFile(subSrcPath, subDstPath, logger); if (rc.IsFailure()) { return(rc); } } } } return(Result.Success); }
public static void Extract(FileArchive archive, string outDir, IProgressReport progress = null) { FileInfo[] fileInfos = archive.FileInfo.Where(x => !string.IsNullOrWhiteSpace(x.Filename)).ToArray(); progress?.SetTotal(fileInfos.Length); progress?.LogMessage("Extracting ARD archive"); foreach (FileInfo fileInfo in fileInfos) { string filename = Path.Combine(outDir, fileInfo.Filename.TrimStart('/')); string dir = Path.GetDirectoryName(filename) ?? throw new InvalidOperationException(); Directory.CreateDirectory(dir); using (var outStream = new FileStream(filename, FileMode.Create, FileAccess.Write)) { archive.OutputFile(fileInfo, outStream); } progress?.ReportAdd(1); } }
public static void Extract(this Romfs romfs, string outDir, IProgressReport logger = null) { foreach (RomfsFile file in romfs.Files) { Stream stream = romfs.OpenFile(file); string outName = outDir + file.FullPath; string dir = Path.GetDirectoryName(outName); if (!string.IsNullOrWhiteSpace(dir)) { Directory.CreateDirectory(dir); } using (var outFile = new FileStream(outName, FileMode.Create, FileAccess.ReadWrite)) { logger?.LogMessage(file.FullPath); stream.CopyStream(outFile, stream.Length, logger); } } }
public static void Extract(this Pfs pfs, string outDir, IProgressReport logger = null) { foreach (PfsFileEntry file in pfs.Header.Files) { Stream stream = pfs.OpenFile(file); string outName = Path.Combine(outDir, file.Name); string dir = Path.GetDirectoryName(outName); if (!string.IsNullOrWhiteSpace(dir)) { Directory.CreateDirectory(dir); } using (var outFile = new FileStream(outName, FileMode.Create, FileAccess.ReadWrite)) { logger?.LogMessage(file.Name); stream.CopyStream(outFile, stream.Length, logger); } } }
public static void Extract(this Savefile save, string outDir, IProgressReport logger = null) { foreach (FileEntry file in save.Files) { IStorage storage = save.OpenFile(file); string outName = outDir + file.FullPath; string dir = Path.GetDirectoryName(outName); if (!string.IsNullOrWhiteSpace(dir)) { Directory.CreateDirectory(dir); } using (var outFile = new FileStream(outName, FileMode.Create, FileAccess.ReadWrite)) { logger?.LogMessage(file.FullPath); storage.CopyToStream(outFile, storage.Length, logger); } } }
public static void ExtractTextures(string[] filenames, string outDir, IProgressReport progress = null) { progress?.SetTotal(filenames.Length); foreach (string filename in filenames) { try { byte[] file = File.ReadAllBytes(filename); string name = Path.GetFileNameWithoutExtension(filename); ExportWilayTextures(file, name, outDir, progress); } catch (Exception ex) { progress?.LogMessage($"{ex.Message} {filename}"); } progress?.ReportAdd(1); } }