private async Task AddDlc(string path) { if (!File.Exists(path) || Dlcs.FirstOrDefault(x => x.ContainerPath == path) != null) { return; } using (FileStream containerFile = File.OpenRead(path)) { PartitionFileSystem pfs = new PartitionFileSystem(containerFile.AsStorage()); bool containsDlc = false; VirtualFileSystem.ImportTickets(pfs); foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca")) { using var ncaFile = new UniqueRef <IFile>(); pfs.OpenFile(ref ncaFile.Ref(), fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); Nca nca = TryCreateNca(ncaFile.Get.AsStorage(), path); if (nca == null) { continue; } if (nca.Header.ContentType == NcaContentType.PublicData) { if ((nca.Header.TitleId & 0xFFFFFFFFFFFFE000) != TitleId) { break; } Dlcs.Add(new DlcModel(nca.Header.TitleId.ToString("X16"), path, fileEntry.FullPath, true)); containsDlc = true; } } if (!containsDlc) { await ContentDialogHelper.CreateErrorDialog(this, LocaleManager.Instance["DialogDlcNoDlcErrorMessage"]); } } }
public void AddAocItem(ulong titleId, string containerPath, string ncaPath, bool enabled) { if (!_aocData.TryAdd(titleId, new AocItem(containerPath, ncaPath, enabled))) { Logger.Warning?.Print(LogClass.Application, $"Duplicate AddOnContent detected. TitleId {titleId:X16}"); } else { Logger.Info?.Print(LogClass.Application, $"Found AddOnContent with TitleId {titleId:X16}"); using (FileStream fileStream = File.OpenRead(containerPath)) using (PartitionFileSystem pfs = new PartitionFileSystem(fileStream.AsStorage())) { _virtualFileSystem.ImportTickets(pfs); } } }
public static void ProcessPk11(Context ctx) { using (var file = new FileStream(ctx.Options.InFile, FileMode.Open, FileAccess.Read)) { var package1 = new Package1(ctx.Keyset, file.AsStorage()); string outDir = ctx.Options.OutDir; if (outDir != null) { Directory.CreateDirectory(outDir); package1.Pk11.OpenWarmboot().WriteAllBytes(Path.Combine(outDir, "Warmboot.bin"), ctx.Logger); package1.Pk11.OpenNxBootloader().WriteAllBytes(Path.Combine(outDir, "NX_Bootloader.bin"), ctx.Logger); package1.Pk11.OpenSecureMonitor().WriteAllBytes(Path.Combine(outDir, "Secure_Monitor.bin"), ctx.Logger); package1.OpenDecryptedPackage().WriteAllBytes(Path.Combine(outDir, "Decrypted.bin"), ctx.Logger); } } }
public static ResultCode OpenFileSystemFromInternalFile(ServiceCtx context, string fullPath, out IFileSystem openedFileSystem) { openedFileSystem = null; DirectoryInfo archivePath = new DirectoryInfo(fullPath).Parent; while (string.IsNullOrWhiteSpace(archivePath.Extension)) { archivePath = archivePath.Parent; } if (archivePath.Extension == ".nsp" && File.Exists(archivePath.FullName)) { FileStream pfsFile = new FileStream( archivePath.FullName.TrimEnd(Path.DirectorySeparatorChar), FileMode.Open, FileAccess.Read); try { PartitionFileSystem nsp = new PartitionFileSystem(pfsFile.AsStorage()); ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet); string filename = fullPath.Replace(archivePath.FullName, string.Empty).TrimStart('\\'); using var ncaFile = new UniqueRef <LibHac.Fs.Fsa.IFile>(); Result result = nsp.OpenFile(ref ncaFile.Ref(), filename.ToU8Span(), OpenMode.Read); if (result.IsFailure()) { return((ResultCode)result.Value); } return(OpenNcaFs(context, fullPath, ncaFile.Release().AsStorage(), out openedFileSystem)); } catch (HorizonResultException ex) { return((ResultCode)ex.ResultValue.Value); } } return(ResultCode.PathDoesNotExist); }
public void LoadXci(string xciFile) { FileStream file = new FileStream(xciFile, FileMode.Open, FileAccess.Read); Xci xci = new Xci(_fileSystem.KeySet, file.AsStorage()); if (!xci.HasPartition(XciPartitionType.Secure)) { Logger.PrintError(LogClass.Loader, "Unable to load XCI: Could not find XCI secure partition"); return; } PartitionFileSystem securePartition = xci.OpenPartition(XciPartitionType.Secure); Nca mainNca = null; Nca patchNca = null; Nca controlNca = null; try { (mainNca, patchNca, controlNca) = GetGameData(securePartition); } catch (Exception e) { Logger.PrintError(LogClass.Loader, $"Unable to load XCI: {e.Message}"); return; } if (mainNca == null) { Logger.PrintError(LogClass.Loader, "Unable to load XCI: Could not find Main NCA"); return; } _contentManager.LoadEntries(_device); _contentManager.ClearAocData(); _contentManager.AddAocData(securePartition, xciFile, mainNca.Header.TitleId); LoadNca(mainNca, patchNca, controlNca); }
public static void ProcessIni1(Context ctx) { using (var file = new FileStream(ctx.Options.InFile, FileMode.Open, FileAccess.Read)) { var ini1 = new Ini1(file.AsStorage()); string outDir = ctx.Options.OutDir; if (outDir != null) { Directory.CreateDirectory(outDir); foreach (Kip kip in ini1.Kips) { kip.OpenRawFile().WriteAllBytes(Path.Combine(outDir, $"{kip.Header.Name}.kip1")); } } } }
public void LoadXci(string xciFile) { FileStream file = new FileStream(xciFile, FileMode.Open, FileAccess.Read); Xci xci = new Xci(KeySet, file.AsStorage()); (Nca mainNca, Nca patchNca, Nca controlNca) = GetXciGameData(xci); if (mainNca == null) { Logger.PrintError(LogClass.Loader, "Unable to load XCI"); return; } ContentManager.LoadEntries(Device); LoadNca(mainNca, patchNca, controlNca); }
private void AddUpdate(string path, bool showErrorDialog = true) { if (File.Exists(path)) { using (FileStream file = new FileStream(path, FileMode.Open, FileAccess.Read)) { PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage()); _virtualFileSystem.ImportTickets(nsp); foreach (DirectoryEntryEx fileEntry in nsp.EnumerateEntries("/", "*.nca")) { nsp.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); try { Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage()); if ($"{nca.Header.TitleId.ToString("x16")[..^3]}000" == _titleId)
public void LoadNca(Nca mainNca, Nca patchNca, Nca controlNca) { if (mainNca.Header.ContentType != NcaContentType.Program) { Logger.PrintError(LogClass.Loader, "Selected NCA is not a \"Program\" NCA"); return; } IStorage dataStorage = null; IFileSystem codeFs = null; if (File.Exists(Path.Combine(Device.FileSystem.GetBasePath(), "games", mainNca.Header.TitleId.ToString("x16"), "updates.json"))) { using (Stream stream = File.OpenRead(Path.Combine(Device.FileSystem.GetBasePath(), "games", mainNca.Header.TitleId.ToString("x16"), "updates.json"))) { IJsonFormatterResolver resolver = CompositeResolver.Create(StandardResolver.AllowPrivateSnakeCase); string updatePath = JsonSerializer.Deserialize <TitleUpdateMetadata>(stream, resolver).Selected; if (File.Exists(updatePath)) { FileStream file = new FileStream(updatePath, FileMode.Open, FileAccess.Read); PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage()); foreach (DirectoryEntryEx ticketEntry in nsp.EnumerateEntries("/", "*.tik")) { Result result = nsp.OpenFile(out IFile ticketFile, ticketEntry.FullPath.ToU8Span(), OpenMode.Read); if (result.IsSuccess()) { Ticket ticket = new Ticket(ticketFile.AsStream()); KeySet.ExternalKeySet.Add(new RightsId(ticket.RightsId), new AccessKey(ticket.GetTitleKey(KeySet))); } } foreach (DirectoryEntryEx fileEntry in nsp.EnumerateEntries("/", "*.nca")) { nsp.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); Nca nca = new Nca(KeySet, ncaFile.AsStorage()); if ($"{nca.Header.TitleId.ToString("x16")[..^3]}000" != mainNca.Header.TitleId.ToString("x16"))
private void AddUpdate(string path) { if (File.Exists(path)) { using (FileStream file = new FileStream(path, FileMode.Open, FileAccess.Read)) { PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage()); try { (Nca patchNca, Nca controlNca) = ApplicationLoader.GetGameUpdateDataFromPartition(_virtualFileSystem, nsp, _titleId, 0); if (controlNca != null && patchNca != null) { ApplicationControlProperty controlData = new ApplicationControlProperty(); using var nacpFile = new UniqueRef <IFile>(); controlNca.OpenFileSystem(NcaSectionType.Data, IntegrityCheckLevel.None).OpenFile(ref nacpFile.Ref(), "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure(); nacpFile.Get.Read(out _, 0, SpanHelpers.AsByteSpan(ref controlData), ReadOption.None).ThrowIfFailure(); RadioButton radioButton = new RadioButton($"Version {controlData.DisplayVersion.ToString()} - {path}"); radioButton.JoinGroup(_noUpdateRadioButton); _availableUpdatesBox.Add(radioButton); _radioButtonToPathDictionary.Add(radioButton, path); radioButton.Show(); radioButton.Active = true; } else { GtkDialog.CreateErrorDialog("The specified file does not contain an update for the selected title!"); } } catch (Exception exception) { GtkDialog.CreateErrorDialog($"{exception.Message}. Errored File: {path}"); } } } }
public void LoadNsp(string nspFile) { FileStream file = new FileStream(nspFile, FileMode.Open, FileAccess.Read); Pfs nsp = new Pfs(file.AsStorage(false)); foreach (PfsFileEntry ticketEntry in nsp.Files.Where(x => x.Name.EndsWith(".tik"))) { Ticket ticket = new Ticket(nsp.OpenFile(ticketEntry).AsStream()); if (!KeySet.TitleKeys.ContainsKey(ticket.RightsId)) { KeySet.TitleKeys.Add(ticket.RightsId, ticket.GetTitleKey(KeySet)); } } Nca mainNca = null; Nca controlNca = null; foreach (PfsFileEntry ncaFile in nsp.Files.Where(x => x.Name.EndsWith(".nca"))) { Nca nca = new Nca(KeySet, nsp.OpenFile(ncaFile), true); if (nca.Header.ContentType == ContentType.Program) { mainNca = nca; } else if (nca.Header.ContentType == ContentType.Control) { controlNca = nca; } } if (mainNca != null) { LoadNca(mainNca, controlNca); return; } Logger.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided NSP file"); }
private static bool IsUpdateApplied(string titleId, out string version) { string jsonPath = Path.Combine(_virtualFileSystem.GetBasePath(), "games", titleId, "updates.json"); if (File.Exists(jsonPath)) { using (Stream stream = File.OpenRead(jsonPath)) { IJsonFormatterResolver resolver = CompositeResolver.Create(StandardResolver.AllowPrivateSnakeCase); string updatePath = JsonSerializer.Deserialize <TitleUpdateMetadata>(stream, resolver).Selected; if (!File.Exists(updatePath)) { version = ""; return(false); } using (FileStream file = new FileStream(updatePath, FileMode.Open, FileAccess.Read)) { PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage()); foreach (DirectoryEntryEx ticketEntry in nsp.EnumerateEntries("/", "*.tik")) { Result result = nsp.OpenFile(out IFile ticketFile, ticketEntry.FullPath.ToU8Span(), OpenMode.Read); if (result.IsSuccess()) { Ticket ticket = new Ticket(ticketFile.AsStream()); _virtualFileSystem.KeySet.ExternalKeySet.Add(new RightsId(ticket.RightsId), new AccessKey(ticket.GetTitleKey(_virtualFileSystem.KeySet))); } } foreach (DirectoryEntryEx fileEntry in nsp.EnumerateEntries("/", "*.nca")) { nsp.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage()); if ($"{nca.Header.TitleId.ToString("x16")[..^3]}000" != titleId)
public void LoadNsp(string nspFile) { FileStream file = new FileStream(nspFile, FileMode.Open, FileAccess.Read); PartitionFileSystem nsp = new PartitionFileSystem(file.AsStorage()); Nca mainNca = null; Nca patchNca = null; Nca controlNca = null; try { (mainNca, patchNca, controlNca) = GetGameData(nsp); } catch (Exception e) { Logger.PrintError(LogClass.Loader, $"Unable to load NSP: {e.Message}"); return; } if (mainNca == null) { Logger.PrintError(LogClass.Loader, "Unable to load NSP: Could not find Main NCA"); return; } if (mainNca != null) { _contentManager.ClearAocData(); _contentManager.AddAocData(nsp, nspFile, mainNca.Header.TitleId); LoadNca(mainNca, patchNca, controlNca); return; } // This is not a normal NSP, it's actually a ExeFS as a NSP LoadExeFs(nsp); }
private long OpenFileSystemFromInternalFile(ServiceCtx context, string fullPath) { DirectoryInfo archivePath = new DirectoryInfo(fullPath).Parent; while (string.IsNullOrWhiteSpace(archivePath.Extension)) { archivePath = archivePath.Parent; } if (archivePath.Extension == ".nsp" && File.Exists(archivePath.FullName)) { FileStream pfsFile = new FileStream( archivePath.FullName.TrimEnd(Path.DirectorySeparatorChar), FileMode.Open, FileAccess.Read); try { PartitionFileSystem nsp = new PartitionFileSystem(pfsFile.AsStorage()); ImportTitleKeysFromNsp(nsp, context.Device.System.KeySet); string filename = fullPath.Replace(archivePath.FullName, string.Empty).TrimStart('\\'); if (nsp.FileExists(filename)) { return(OpenNcaFs(context, fullPath, nsp.OpenFile(filename, OpenMode.Read).AsStorage())); } } catch (HorizonResultException ex) { return(ex.ResultValue.Value); } } return(MakeError(ErrorModule.Fs, FsErr.PathDoesNotExist)); }
// OpenFileSystemWithId(nn::fssrv::sf::FileSystemType filesystem_type, nn::ApplicationId tid, buffer<bytes<0x301>, 0x19, 0x301> path) // -> object<nn::fssrv::sf::IFileSystem> contentFs public ResultCode OpenFileSystemWithId(ServiceCtx context) { FileSystemType fileSystemType = (FileSystemType)context.RequestData.ReadInt32(); long titleId = context.RequestData.ReadInt64(); string switchPath = ReadUtf8String(context); string fullPath = context.Device.FileSystem.SwitchPathToSystemPath(switchPath); if (!File.Exists(fullPath)) { if (fullPath.Contains(".")) { ResultCode result = FileSystemProxyHelper.OpenFileSystemFromInternalFile(context, fullPath, out FileSystemProxy.IFileSystem fileSystem); if (result == ResultCode.Success) { MakeObject(context, fileSystem); } return(result); } return(ResultCode.PathDoesNotExist); } FileStream fileStream = new FileStream(fullPath, FileMode.Open, FileAccess.Read); string extension = Path.GetExtension(fullPath); if (extension == ".nca") { ResultCode result = FileSystemProxyHelper.OpenNcaFs(context, fullPath, fileStream.AsStorage(), out FileSystemProxy.IFileSystem fileSystem); if (result == ResultCode.Success) { MakeObject(context, fileSystem); } return(result); } else if (extension == ".nsp") { ResultCode result = FileSystemProxyHelper.OpenNsp(context, fullPath, out FileSystemProxy.IFileSystem fileSystem); if (result == ResultCode.Success) { MakeObject(context, fileSystem); } return(result); } return(ResultCode.InvalidInput); }
public static Title processXci(string filename) { Title title = new Title(); using (var filestream = new FileStream(filename, FileMode.Open, FileAccess.Read)) { Xci xci; string biggestNca = null, controlNca = null; try { xci = new Xci(keyset, filestream.AsStorage()); title.distribution = Title.Distribution.Cartridge; } catch (InvalidDataException) { return(null); } log?.WriteLine("Processing XCI {0}", filename); if (xci.RootPartition?.Files.Length > 0) { title.structure.Add(Title.Structure.RootPartition); } if (xci.UpdatePartition?.Files.Length > 0) { title.structure.Add(Title.Structure.UpdatePartition); } if (xci.NormalPartition?.Files.Length > 0) { title.structure.Add(Title.Structure.NormalPartition); } if (xci.SecurePartition?.Files.Length > 0) { PfsFileEntry[] fileEntries = xci.SecurePartition.Files; foreach (PfsFileEntry entry in fileEntries) { if (entry.Name.EndsWith(".cnmt.nca")) { using (var cnmtNca = xci.SecurePartition.OpenFile(entry)) { var nca = processCnmtNca(cnmtNca, ref title); if (nca.Item1 != null && (nca.Item2 != null || title.type == TitleType.AddOnContent)) { (biggestNca, controlNca) = nca; } } title.structure.Add(Title.Structure.CnmtNca); } } if (!String.IsNullOrEmpty(biggestNca)) { using (var biggest = xci.SecurePartition.OpenFile(biggestNca)) { processBiggestNca(biggest, ref title); } } if (!String.IsNullOrEmpty(controlNca)) { using (var control = xci.SecurePartition.OpenFile(controlNca)) { processControlNca(control, ref title); } } title.structure.Add(Title.Structure.SecurePartition); } if (xci.LogoPartition?.Files.Length > 0) { title.structure.Add(Title.Structure.LogoPartition); } } if (title.type == TitleType.Application || title.type == TitleType.Patch) { if (versionList.TryGetValue(title.titleIDApplication, out uint version)) { title.latestVersion = version; } } log?.WriteLine("XCI information for {0}: [{1}] {2}", filename, title.titleID, title.titleName); return(title); }
public static Title processNsp(string filename) { Title title = new Title(); using (var filestream = new FileStream(filename, FileMode.Open, FileAccess.Read)) { Pfs pfs; string biggestNca = null, controlNca = null; try { pfs = new Pfs(filestream.AsStorage()); title.distribution = Title.Distribution.Digital; } catch (InvalidDataException) { return(null); } log?.WriteLine("Processing NSP {0}", filename); PfsFileEntry[] fileEntries = pfs.Files; foreach (PfsFileEntry entry in fileEntries) { if (entry.Name.EndsWith(".cnmt.xml")) { using (var cnmtXml = pfs.OpenFile(entry)) { (biggestNca, controlNca) = processCnmtXml(cnmtXml, ref title); } title.structure.Add(Title.Structure.CnmtXml); } else if (entry.Name.EndsWith(".cnmt.nca")) { using (var cnmtNca = pfs.OpenFile(entry)) { var nca = processCnmtNca(cnmtNca, ref title); if (nca.Item1 != null && (nca.Item2 != null || title.type == TitleType.AddOnContent)) { (biggestNca, controlNca) = nca; } } title.structure.Add(Title.Structure.CnmtNca); } else if (entry.Name.EndsWith(".cert")) { title.structure.Add(Title.Structure.Cert); } else if (entry.Name.EndsWith(".tik")) { title.structure.Add(Title.Structure.Tik); } else if (entry.Name.EndsWith(".legalinfo.xml")) { title.structure.Add(Title.Structure.LegalinfoXml); } else if (entry.Name.EndsWith(".nacp.xml")) { using (var nacpXml = pfs.OpenFile(entry)) { processNacpXml(nacpXml, ref title); } title.structure.Add(Title.Structure.NacpXml); } else if (entry.Name.EndsWith(".programinfo.xml")) { title.structure.Add(Title.Structure.PrograminfoXml); } else if (entry.Name.Equals("cardspec.xml")) { title.structure.Add(Title.Structure.CardspecXml); } else if (entry.Name.Equals("authoringtoolinfo.xml")) { title.structure.Add(Title.Structure.AuthoringtoolinfoXml); } } if (!String.IsNullOrEmpty(biggestNca)) { using (var biggest = pfs.OpenFile(biggestNca)) { processBiggestNca(biggest, ref title); } } if (!String.IsNullOrEmpty(controlNca)) { using (var control = pfs.OpenFile(controlNca)) { processControlNca(control, ref title); } } } if (title.type == TitleType.Application || title.type == TitleType.Patch) { if (versionList.TryGetValue(title.titleIDApplication, out uint version)) { title.latestVersion = version; } } log?.WriteLine("NSP information for {0}: [{1}] {2}", filename, title.titleID, title.titleName); return(title); }
public void LoadNsp(string nspFile) { FileStream file = new FileStream(nspFile, FileMode.Open, FileAccess.Read); Pfs nsp = new Pfs(file.AsStorage(false)); foreach (PfsFileEntry ticketEntry in nsp.Files.Where(x => x.Name.EndsWith(".tik"))) { Ticket ticket = new Ticket(nsp.OpenFile(ticketEntry).AsStream()); if (!KeySet.TitleKeys.ContainsKey(ticket.RightsId)) { KeySet.TitleKeys.Add(ticket.RightsId, ticket.GetTitleKey(KeySet)); } } Nca mainNca = null; Nca controlNca = null; foreach (PfsFileEntry ncaFile in nsp.Files.Where(x => x.Name.EndsWith(".nca"))) { Nca nca = new Nca(KeySet, nsp.OpenFile(ncaFile), true); if (nca.Header.ContentType == ContentType.Program) { mainNca = nca; } else if (nca.Header.ContentType == ContentType.Control) { controlNca = nca; } } if (mainNca != null) { LoadNca(mainNca, controlNca); return; } // This is not a normal NSP, it's actually a ExeFS as a NSP Npdm metaData = null; PfsFileEntry npdmFile = nsp.Files.FirstOrDefault(x => x.Name.Equals("main.npdm")); if (npdmFile != null) { Logger.PrintInfo(LogClass.Loader, $"Loading main.npdm..."); metaData = new Npdm(nsp.OpenFile(npdmFile).AsStream()); } else { Logger.PrintWarning(LogClass.Loader, $"NPDM file not found, using default values!"); metaData = GetDefaultNpdm(); } List <IExecutable> staticObjects = new List <IExecutable>(); void LoadNso(string searchPattern) { PfsFileEntry entry = nsp.Files.FirstOrDefault(x => x.Name.Equals(searchPattern)); if (entry != null) { Logger.PrintInfo(LogClass.Loader, $"Loading {entry.Name}..."); NxStaticObject staticObject = new NxStaticObject(nsp.OpenFile(entry).AsStream()); staticObjects.Add(staticObject); } } CurrentTitle = metaData.Aci0.TitleId.ToString("x16"); LoadNso("rtld"); LoadNso("main"); LoadNso("subsdk*"); LoadNso("sdk"); ContentManager.LoadEntries(); if (staticObjects.Count == 0) { Logger.PrintError(LogClass.Loader, "Could not find an Application NCA in the provided NSP file"); } else { ProgramLoader.LoadStaticObjects(this, metaData, staticObjects.ToArray()); } }
public static void LoadApplications(List <string> appDirs, Keyset keySet, TitleLanguage desiredTitleLanguage, FileSystemClient fsClient = null, VirtualFileSystem vfs = null) { int numApplicationsFound = 0; int numApplicationsLoaded = 0; _keySet = keySet; _desiredTitleLanguage = desiredTitleLanguage; // Builds the applications list with paths to found applications List <string> applications = new List <string>(); foreach (string appDir in appDirs) { if (Directory.Exists(appDir) == false) { Logger.PrintWarning(LogClass.Application, $"The \"game_dirs\" section in \"Config.json\" contains an invalid directory: \"{appDir}\""); continue; } foreach (string app in Directory.GetFiles(appDir, "*.*", SearchOption.AllDirectories)) { if ((Path.GetExtension(app) == ".xci") || (Path.GetExtension(app) == ".nro") || (Path.GetExtension(app) == ".nso") || (Path.GetFileName(app) == "hbl.nsp")) { applications.Add(app); numApplicationsFound++; } else if ((Path.GetExtension(app) == ".nsp") || (Path.GetExtension(app) == ".pfs0")) { try { bool hasMainNca = false; PartitionFileSystem nsp = new PartitionFileSystem(new FileStream(app, FileMode.Open, FileAccess.Read).AsStorage()); foreach (DirectoryEntryEx fileEntry in nsp.EnumerateEntries("/", "*.nca")) { nsp.OpenFile(out IFile ncaFile, fileEntry.FullPath, OpenMode.Read).ThrowIfFailure(); Nca nca = new Nca(_keySet, ncaFile.AsStorage()); int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program); if (nca.Header.ContentType == NcaContentType.Program && !nca.Header.GetFsHeader(dataIndex).IsPatchSection()) { hasMainNca = true; } } if (!hasMainNca) { continue; } } catch (InvalidDataException) { Logger.PrintWarning(LogClass.Application, $"{app}: The header key is incorrect or missing and therefore the NCA header content type check has failed."); } applications.Add(app); numApplicationsFound++; } else if (Path.GetExtension(app) == ".nca") { try { Nca nca = new Nca(_keySet, new FileStream(app, FileMode.Open, FileAccess.Read).AsStorage()); int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program); if (nca.Header.ContentType != NcaContentType.Program || nca.Header.GetFsHeader(dataIndex).IsPatchSection()) { continue; } } catch (InvalidDataException) { Logger.PrintWarning(LogClass.Application, $"{app}: The header key is incorrect or missing and therefore the NCA header content type check has failed."); } applications.Add(app); numApplicationsFound++; } } } // Loops through applications list, creating a struct and then firing an event containing the struct for each application foreach (string applicationPath in applications) { double fileSize = new FileInfo(applicationPath).Length * 0.000000000931; string titleName = "Unknown"; string titleId = "0000000000000000"; string developer = "Unknown"; string version = "0"; string saveDataPath = null; byte[] applicationIcon = null; using (FileStream file = new FileStream(applicationPath, FileMode.Open, FileAccess.Read)) { if ((Path.GetExtension(applicationPath) == ".nsp") || (Path.GetExtension(applicationPath) == ".pfs0") || (Path.GetExtension(applicationPath) == ".xci")) { try { PartitionFileSystem pfs; if (Path.GetExtension(applicationPath) == ".xci") { Xci xci = new Xci(_keySet, file.AsStorage()); pfs = xci.OpenPartition(XciPartitionType.Secure); } else { pfs = new PartitionFileSystem(file.AsStorage()); } // Store the ControlFS in variable called controlFs IFileSystem controlFs = GetControlFs(pfs); // If this is null then this is probably not a normal NSP, it's probably an ExeFS as an NSP if (controlFs == null) { applicationIcon = _nspIcon; Result result = pfs.OpenFile(out IFile npdmFile, "/main.npdm", OpenMode.Read); if (result != ResultFs.PathNotFound) { Npdm npdm = new Npdm(npdmFile.AsStream()); titleName = npdm.TitleName; titleId = npdm.Aci0.TitleId.ToString("x16"); } } else { // Creates NACP class from the NACP file controlFs.OpenFile(out IFile controlNacpFile, "/control.nacp", OpenMode.Read).ThrowIfFailure(); Nacp controlData = new Nacp(controlNacpFile.AsStream()); // Get the title name, title ID, developer name and version number from the NACP version = controlData.DisplayVersion; titleName = controlData.Descriptions[(int)_desiredTitleLanguage].Title; if (string.IsNullOrWhiteSpace(titleName)) { titleName = controlData.Descriptions.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Title)).Title; } titleId = controlData.PresenceGroupId.ToString("x16"); if (string.IsNullOrWhiteSpace(titleId)) { titleId = controlData.SaveDataOwnerId.ToString("x16"); } if (string.IsNullOrWhiteSpace(titleId)) { titleId = (controlData.AddOnContentBaseId - 0x1000).ToString("x16"); } developer = controlData.Descriptions[(int)_desiredTitleLanguage].Developer; if (string.IsNullOrWhiteSpace(developer)) { developer = controlData.Descriptions.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Developer)).Developer; } // Read the icon from the ControlFS and store it as a byte array try { controlFs.OpenFile(out IFile icon, $"/icon_{_desiredTitleLanguage}.dat", OpenMode.Read).ThrowIfFailure(); using (MemoryStream stream = new MemoryStream()) { icon.AsStream().CopyTo(stream); applicationIcon = stream.ToArray(); } } catch (HorizonResultException) { foreach (DirectoryEntryEx entry in controlFs.EnumerateEntries("/", "*")) { if (entry.Name == "control.nacp") { continue; } controlFs.OpenFile(out IFile icon, entry.FullPath, OpenMode.Read).ThrowIfFailure(); using (MemoryStream stream = new MemoryStream()) { icon.AsStream().CopyTo(stream); applicationIcon = stream.ToArray(); } if (applicationIcon != null) { break; } } if (applicationIcon == null) { applicationIcon = Path.GetExtension(applicationPath) == ".xci" ? _xciIcon : _nspIcon; } } } } catch (MissingKeyException exception) { applicationIcon = Path.GetExtension(applicationPath) == ".xci" ? _xciIcon : _nspIcon; Logger.PrintWarning(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}"); } catch (InvalidDataException) { applicationIcon = Path.GetExtension(applicationPath) == ".xci" ? _xciIcon : _nspIcon; Logger.PrintWarning(LogClass.Application, $"The header key is incorrect or missing and therefore the NCA header content type check has failed. Errored File: {applicationPath}"); } } else if (Path.GetExtension(applicationPath) == ".nro") { BinaryReader reader = new BinaryReader(file); byte[] Read(long position, int size) { file.Seek(position, SeekOrigin.Begin); return(reader.ReadBytes(size)); } file.Seek(24, SeekOrigin.Begin); int assetOffset = reader.ReadInt32(); if (Encoding.ASCII.GetString(Read(assetOffset, 4)) == "ASET") { byte[] iconSectionInfo = Read(assetOffset + 8, 0x10); long iconOffset = BitConverter.ToInt64(iconSectionInfo, 0); long iconSize = BitConverter.ToInt64(iconSectionInfo, 8); ulong nacpOffset = reader.ReadUInt64(); ulong nacpSize = reader.ReadUInt64(); // Reads and stores game icon as byte array applicationIcon = Read(assetOffset + iconOffset, (int)iconSize); // Creates memory stream out of byte array which is the NACP using (MemoryStream stream = new MemoryStream(Read(assetOffset + (int)nacpOffset, (int)nacpSize))) { // Creates NACP class from the memory stream Nacp controlData = new Nacp(stream); // Get the title name, title ID, developer name and version number from the NACP version = controlData.DisplayVersion; titleName = controlData.Descriptions[(int)_desiredTitleLanguage].Title; if (string.IsNullOrWhiteSpace(titleName)) { titleName = controlData.Descriptions.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Title)).Title; } titleId = controlData.PresenceGroupId.ToString("x16"); if (string.IsNullOrWhiteSpace(titleId)) { titleId = controlData.SaveDataOwnerId.ToString("x16"); } if (string.IsNullOrWhiteSpace(titleId)) { titleId = (controlData.AddOnContentBaseId - 0x1000).ToString("x16"); } developer = controlData.Descriptions[(int)_desiredTitleLanguage].Developer; if (string.IsNullOrWhiteSpace(developer)) { developer = controlData.Descriptions.ToList().Find(x => !string.IsNullOrWhiteSpace(x.Developer)).Developer; } } } else { applicationIcon = _nroIcon; } } // If its an NCA or NSO we just set defaults else if ((Path.GetExtension(applicationPath) == ".nca") || (Path.GetExtension(applicationPath) == ".nso")) { applicationIcon = Path.GetExtension(applicationPath) == ".nca" ? _ncaIcon : _nsoIcon; titleName = Path.GetFileNameWithoutExtension(applicationPath); } } ApplicationMetadata appMetadata = LoadAndSaveMetaData(titleId); if (ulong.TryParse(titleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNum)) { SaveDataFilter filter = new SaveDataFilter(); filter.SetUserId(new UserId(1, 0)); filter.SetTitleId(new TitleId(titleIdNum)); Result result = fsClient.FindSaveDataWithFilter(out SaveDataInfo saveDataInfo, SaveDataSpaceId.User, ref filter); if (result.IsSuccess()) { saveDataPath = Path.Combine(vfs.GetNandPath(), $"user/save/{saveDataInfo.SaveDataId:x16}"); } } ApplicationData data = new ApplicationData() { Favorite = appMetadata.Favorite, Icon = applicationIcon, TitleName = titleName, TitleId = titleId, Developer = developer, Version = version, TimePlayed = ConvertSecondsToReadableString(appMetadata.TimePlayed), LastPlayed = appMetadata.LastPlayed, FileExtension = Path.GetExtension(applicationPath).ToUpper().Remove(0, 1), FileSize = (fileSize < 1) ? (fileSize * 1024).ToString("0.##") + "MB" : fileSize.ToString("0.##") + "GB", Path = applicationPath, SaveDataPath = saveDataPath }; numApplicationsLoaded++; OnApplicationAdded(new ApplicationAddedEventArgs() { AppData = data, NumAppsFound = numApplicationsFound, NumAppsLoaded = numApplicationsLoaded }); } }
private void AddButton_Clicked(object sender, EventArgs args) { FileChooserNative fileChooser = new FileChooserNative("Select DLC files", this, FileChooserAction.Open, "Add", "Cancel") { SelectMultiple = true }; FileFilter filter = new FileFilter() { Name = "Switch Game DLCs" }; filter.AddPattern("*.nsp"); fileChooser.AddFilter(filter); if (fileChooser.Run() == (int)ResponseType.Accept) { foreach (string containerPath in fileChooser.Filenames) { if (!File.Exists(containerPath)) { return; } using (FileStream containerFile = File.OpenRead(containerPath)) { PartitionFileSystem pfs = new PartitionFileSystem(containerFile.AsStorage()); bool containsDlc = false; _virtualFileSystem.ImportTickets(pfs); TreeIter?parentIter = null; foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca")) { pfs.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); Nca nca = TryCreateNca(ncaFile.AsStorage(), containerPath); if (nca == null) { continue; } if (nca.Header.ContentType == NcaContentType.PublicData) { if ((nca.Header.TitleId & 0xFFFFFFFFFFFFE000).ToString("x16") != _titleId) { break; } parentIter ??= ((TreeStore)_dlcTreeView.Model).AppendValues(true, "", containerPath); ((TreeStore)_dlcTreeView.Model).AppendValues(parentIter.Value, true, nca.Header.TitleId.ToString("X16"), fileEntry.FullPath); containsDlc = true; } } if (!containsDlc) { GtkDialog.CreateErrorDialog("The specified file does not contain DLC for the selected title!"); } } } } fileChooser.Dispose(); }
public static void LoadApplications(List <string> appDirs, VirtualFileSystem virtualFileSystem, Language desiredTitleLanguage) { int numApplicationsFound = 0; int numApplicationsLoaded = 0; _loadingError = false; _virtualFileSystem = virtualFileSystem; _desiredTitleLanguage = desiredTitleLanguage; // Builds the applications list with paths to found applications List <string> applications = new List <string>(); foreach (string appDir in appDirs) { if (!Directory.Exists(appDir)) { Logger.PrintWarning(LogClass.Application, $"The \"game_dirs\" section in \"Config.json\" contains an invalid directory: \"{appDir}\""); continue; } foreach (string app in GetFilesInDirectory(appDir)) { if ((Path.GetExtension(app).ToLower() == ".nsp") || (Path.GetExtension(app).ToLower() == ".pfs0") || (Path.GetExtension(app).ToLower() == ".xci") || (Path.GetExtension(app).ToLower() == ".nca") || (Path.GetExtension(app).ToLower() == ".nro") || (Path.GetExtension(app).ToLower() == ".nso")) { applications.Add(app); numApplicationsFound++; } } } // Loops through applications list, creating a struct and then firing an event containing the struct for each application foreach (string applicationPath in applications) { double fileSize = new FileInfo(applicationPath).Length * 0.000000000931; string titleName = "Unknown"; string titleId = "0000000000000000"; string developer = "Unknown"; string version = "0"; string saveDataPath = null; byte[] applicationIcon = null; BlitStruct <ApplicationControlProperty> controlHolder = new BlitStruct <ApplicationControlProperty>(1); try { using (FileStream file = new FileStream(applicationPath, FileMode.Open, FileAccess.Read)) { if ((Path.GetExtension(applicationPath).ToLower() == ".nsp") || (Path.GetExtension(applicationPath).ToLower() == ".pfs0") || (Path.GetExtension(applicationPath).ToLower() == ".xci")) { try { PartitionFileSystem pfs; bool isExeFs = false; if (Path.GetExtension(applicationPath).ToLower() == ".xci") { Xci xci = new Xci(_virtualFileSystem.KeySet, file.AsStorage()); pfs = xci.OpenPartition(XciPartitionType.Secure); } else { pfs = new PartitionFileSystem(file.AsStorage()); // If the NSP doesn't have a main NCA, decrement the number of applications found and then continue to the next application. bool hasMainNca = false; foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*")) { if (Path.GetExtension(fileEntry.FullPath).ToLower() == ".nca") { pfs.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage()); int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program); if (nca.Header.ContentType == NcaContentType.Program && !nca.Header.GetFsHeader(dataIndex).IsPatchSection()) { hasMainNca = true; break; } } else if (Path.GetFileNameWithoutExtension(fileEntry.FullPath) == "main") { isExeFs = true; } } if (!hasMainNca && !isExeFs) { numApplicationsFound--; continue; } } if (isExeFs) { applicationIcon = _nspIcon; Result result = pfs.OpenFile(out IFile npdmFile, "/main.npdm".ToU8Span(), OpenMode.Read); if (ResultFs.PathNotFound.Includes(result)) { Npdm npdm = new Npdm(npdmFile.AsStream()); titleName = npdm.TitleName; titleId = npdm.Aci0.TitleId.ToString("x16"); } } else { // Store the ControlFS in variable called controlFs GetControlFsAndTitleId(pfs, out IFileSystem controlFs, out titleId); ReadControlData(controlFs, controlHolder.ByteSpan); // Creates NACP class from the NACP file controlFs.OpenFile(out IFile controlNacpFile, "/control.nacp".ToU8Span(), OpenMode.Read).ThrowIfFailure(); // Get the title name, title ID, developer name and version number from the NACP version = IsUpdateApplied(titleId, out string updateVersion) ? updateVersion : controlHolder.Value.DisplayVersion.ToString(); GetNameIdDeveloper(ref controlHolder.Value, out titleName, out _, out developer); // Read the icon from the ControlFS and store it as a byte array try { controlFs.OpenFile(out IFile icon, $"/icon_{_desiredTitleLanguage}.dat".ToU8Span(), OpenMode.Read).ThrowIfFailure(); using (MemoryStream stream = new MemoryStream()) { icon.AsStream().CopyTo(stream); applicationIcon = stream.ToArray(); } } catch (HorizonResultException) { foreach (DirectoryEntryEx entry in controlFs.EnumerateEntries("/", "*")) { if (entry.Name == "control.nacp") { continue; } controlFs.OpenFile(out IFile icon, entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); using (MemoryStream stream = new MemoryStream()) { icon.AsStream().CopyTo(stream); applicationIcon = stream.ToArray(); } if (applicationIcon != null) { break; } } if (applicationIcon == null) { applicationIcon = Path.GetExtension(applicationPath).ToLower() == ".xci" ? _xciIcon : _nspIcon; } } } } catch (MissingKeyException exception) { applicationIcon = Path.GetExtension(applicationPath).ToLower() == ".xci" ? _xciIcon : _nspIcon; Logger.PrintWarning(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}"); } catch (InvalidDataException) { applicationIcon = Path.GetExtension(applicationPath).ToLower() == ".xci" ? _xciIcon : _nspIcon; Logger.PrintWarning(LogClass.Application, $"The header key is incorrect or missing and therefore the NCA header content type check has failed. Errored File: {applicationPath}"); } catch (Exception exception) { Logger.PrintWarning(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}"); Logger.PrintDebug(LogClass.Application, exception.ToString()); numApplicationsFound--; _loadingError = true; continue; } } else if (Path.GetExtension(applicationPath).ToLower() == ".nro") { BinaryReader reader = new BinaryReader(file); byte[] Read(long position, int size) { file.Seek(position, SeekOrigin.Begin); return(reader.ReadBytes(size)); } try { file.Seek(24, SeekOrigin.Begin); int assetOffset = reader.ReadInt32(); if (Encoding.ASCII.GetString(Read(assetOffset, 4)) == "ASET") { byte[] iconSectionInfo = Read(assetOffset + 8, 0x10); long iconOffset = BitConverter.ToInt64(iconSectionInfo, 0); long iconSize = BitConverter.ToInt64(iconSectionInfo, 8); ulong nacpOffset = reader.ReadUInt64(); ulong nacpSize = reader.ReadUInt64(); // Reads and stores game icon as byte array applicationIcon = Read(assetOffset + iconOffset, (int)iconSize); // Read the NACP data Read(assetOffset + (int)nacpOffset, (int)nacpSize).AsSpan().CopyTo(controlHolder.ByteSpan); // Get the title name, title ID, developer name and version number from the NACP version = controlHolder.Value.DisplayVersion.ToString(); GetNameIdDeveloper(ref controlHolder.Value, out titleName, out titleId, out developer); } else { applicationIcon = _nroIcon; titleName = Path.GetFileNameWithoutExtension(applicationPath); } } catch { Logger.PrintWarning(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}"); numApplicationsFound--; continue; } } else if (Path.GetExtension(applicationPath).ToLower() == ".nca") { try { Nca nca = new Nca(_virtualFileSystem.KeySet, new FileStream(applicationPath, FileMode.Open, FileAccess.Read).AsStorage()); int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program); if (nca.Header.ContentType != NcaContentType.Program || nca.Header.GetFsHeader(dataIndex).IsPatchSection()) { numApplicationsFound--; continue; } } catch (InvalidDataException) { Logger.PrintWarning(LogClass.Application, $"The NCA header content type check has failed. This is usually because the header key is incorrect or missing. Errored File: {applicationPath}"); } catch { Logger.PrintWarning(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}"); numApplicationsFound--; _loadingError = true; continue; } applicationIcon = _ncaIcon; titleName = Path.GetFileNameWithoutExtension(applicationPath); } // If its an NSO we just set defaults else if (Path.GetExtension(applicationPath).ToLower() == ".nso") { applicationIcon = _nsoIcon; titleName = Path.GetFileNameWithoutExtension(applicationPath); } } } catch (IOException exception) { Logger.PrintWarning(LogClass.Application, exception.Message); numApplicationsFound--; _loadingError = true; continue; } ApplicationMetadata appMetadata = LoadAndSaveMetaData(titleId); if (ulong.TryParse(titleId, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out ulong titleIdNum)) { SaveDataFilter filter = new SaveDataFilter(); filter.SetUserId(new UserId(1, 0)); filter.SetProgramId(new TitleId(titleIdNum)); Result result = virtualFileSystem.FsClient.FindSaveDataWithFilter(out SaveDataInfo saveDataInfo, SaveDataSpaceId.User, ref filter); if (result.IsSuccess()) { saveDataPath = Path.Combine(virtualFileSystem.GetNandPath(), "user", "save", saveDataInfo.SaveDataId.ToString("x16")); } } ApplicationData data = new ApplicationData { Favorite = appMetadata.Favorite, Icon = applicationIcon, TitleName = titleName, TitleId = titleId, Developer = developer, Version = version, TimePlayed = ConvertSecondsToReadableString(appMetadata.TimePlayed), LastPlayed = appMetadata.LastPlayed, FileExtension = Path.GetExtension(applicationPath).ToUpper().Remove(0, 1), FileSize = (fileSize < 1) ? (fileSize * 1024).ToString("0.##") + "MB" : fileSize.ToString("0.##") + "GB", Path = applicationPath, SaveDataPath = saveDataPath, ControlHolder = controlHolder }; numApplicationsLoaded++; OnApplicationAdded(new ApplicationAddedEventArgs() { AppData = data }); OnApplicationCountUpdated(new ApplicationCountUpdatedEventArgs() { NumAppsFound = numApplicationsFound, NumAppsLoaded = numApplicationsLoaded }); } OnApplicationCountUpdated(new ApplicationCountUpdatedEventArgs() { NumAppsFound = numApplicationsFound, NumAppsLoaded = numApplicationsLoaded }); if (_loadingError) { Gtk.Application.Invoke(delegate { GtkDialog.CreateErrorDialog("One or more files encountered could not be loaded, check logs for more info."); }); } }
public void LoadApplications(List <string> appDirs, Language desiredTitleLanguage) { int numApplicationsFound = 0; int numApplicationsLoaded = 0; _desiredTitleLanguage = desiredTitleLanguage; _cancellationToken = new CancellationTokenSource(); // Builds the applications list with paths to found applications List <string> applications = new List <string>(); try { foreach (string appDir in appDirs) { if (_cancellationToken.Token.IsCancellationRequested) { return; } if (!Directory.Exists(appDir)) { Logger.Warning?.Print(LogClass.Application, $"The \"game_dirs\" section in \"Config.json\" contains an invalid directory: \"{appDir}\""); continue; } foreach (string app in GetFilesInDirectory(appDir)) { if (_cancellationToken.Token.IsCancellationRequested) { return; } string extension = Path.GetExtension(app).ToLower(); if ((extension == ".nsp") || (extension == ".pfs0") || (extension == ".xci") || (extension == ".nca") || (extension == ".nro") || (extension == ".nso")) { applications.Add(app); numApplicationsFound++; } } } // Loops through applications list, creating a struct and then firing an event containing the struct for each application foreach (string applicationPath in applications) { if (_cancellationToken.Token.IsCancellationRequested) { return; } double fileSize = new FileInfo(applicationPath).Length * 0.000000000931; string titleName = "Unknown"; string titleId = "0000000000000000"; string developer = "Unknown"; string version = "0"; byte[] applicationIcon = null; BlitStruct <ApplicationControlProperty> controlHolder = new BlitStruct <ApplicationControlProperty>(1); try { string extension = Path.GetExtension(applicationPath).ToLower(); using (FileStream file = new FileStream(applicationPath, FileMode.Open, FileAccess.Read)) { if (extension == ".nsp" || extension == ".pfs0" || extension == ".xci") { try { PartitionFileSystem pfs; bool isExeFs = false; if (extension == ".xci") { Xci xci = new Xci(_virtualFileSystem.KeySet, file.AsStorage()); pfs = xci.OpenPartition(XciPartitionType.Secure); } else { pfs = new PartitionFileSystem(file.AsStorage()); // If the NSP doesn't have a main NCA, decrement the number of applications found and then continue to the next application. bool hasMainNca = false; foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*")) { if (Path.GetExtension(fileEntry.FullPath).ToLower() == ".nca") { using var ncaFile = new UniqueRef <IFile>(); pfs.OpenFile(ref ncaFile.Ref(), fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile.Get.AsStorage()); int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program); // Some main NCAs don't have a data partition, so check if the partition exists before opening it if (nca.Header.ContentType == NcaContentType.Program && !(nca.SectionExists(NcaSectionType.Data) && nca.Header.GetFsHeader(dataIndex).IsPatchSection())) { hasMainNca = true; break; } } else if (Path.GetFileNameWithoutExtension(fileEntry.FullPath) == "main") { isExeFs = true; } } if (!hasMainNca && !isExeFs) { numApplicationsFound--; continue; } } if (isExeFs) { applicationIcon = _nspIcon; using var npdmFile = new UniqueRef <IFile>(); Result result = pfs.OpenFile(ref npdmFile.Ref(), "/main.npdm".ToU8Span(), OpenMode.Read); if (ResultFs.PathNotFound.Includes(result)) { Npdm npdm = new Npdm(npdmFile.Get.AsStream()); titleName = npdm.TitleName; titleId = npdm.Aci0.TitleId.ToString("x16"); } } else { GetControlFsAndTitleId(pfs, out IFileSystem controlFs, out titleId); // Check if there is an update available. if (IsUpdateApplied(titleId, out IFileSystem updatedControlFs)) { // Replace the original ControlFs by the updated one. controlFs = updatedControlFs; } ReadControlData(controlFs, controlHolder.ByteSpan); GetGameInformation(ref controlHolder.Value, out titleName, out _, out developer, out version); // Read the icon from the ControlFS and store it as a byte array try { using var icon = new UniqueRef <IFile>(); controlFs.OpenFile(ref icon.Ref(), $"/icon_{_desiredTitleLanguage}.dat".ToU8Span(), OpenMode.Read).ThrowIfFailure(); using (MemoryStream stream = new MemoryStream()) { icon.Get.AsStream().CopyTo(stream); applicationIcon = stream.ToArray(); } } catch (HorizonResultException) { foreach (DirectoryEntryEx entry in controlFs.EnumerateEntries("/", "*")) { if (entry.Name == "control.nacp") { continue; } using var icon = new UniqueRef <IFile>(); controlFs.OpenFile(ref icon.Ref(), entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); using (MemoryStream stream = new MemoryStream()) { icon.Get.AsStream().CopyTo(stream); applicationIcon = stream.ToArray(); } if (applicationIcon != null) { break; } } if (applicationIcon == null) { applicationIcon = extension == ".xci" ? _xciIcon : _nspIcon; } } } } catch (MissingKeyException exception) { applicationIcon = extension == ".xci" ? _xciIcon : _nspIcon; Logger.Warning?.Print(LogClass.Application, $"Your key set is missing a key with the name: {exception.Name}"); } catch (InvalidDataException) { applicationIcon = extension == ".xci" ? _xciIcon : _nspIcon; Logger.Warning?.Print(LogClass.Application, $"The header key is incorrect or missing and therefore the NCA header content type check has failed. Errored File: {applicationPath}"); } catch (Exception exception) { Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. File: '{applicationPath}' Error: {exception}"); numApplicationsFound--; continue; } } else if (extension == ".nro") { BinaryReader reader = new BinaryReader(file); byte[] Read(long position, int size) { file.Seek(position, SeekOrigin.Begin); return(reader.ReadBytes(size)); } try { file.Seek(24, SeekOrigin.Begin); int assetOffset = reader.ReadInt32(); if (Encoding.ASCII.GetString(Read(assetOffset, 4)) == "ASET") { byte[] iconSectionInfo = Read(assetOffset + 8, 0x10); long iconOffset = BitConverter.ToInt64(iconSectionInfo, 0); long iconSize = BitConverter.ToInt64(iconSectionInfo, 8); ulong nacpOffset = reader.ReadUInt64(); ulong nacpSize = reader.ReadUInt64(); // Reads and stores game icon as byte array applicationIcon = Read(assetOffset + iconOffset, (int)iconSize); // Read the NACP data Read(assetOffset + (int)nacpOffset, (int)nacpSize).AsSpan().CopyTo(controlHolder.ByteSpan); GetGameInformation(ref controlHolder.Value, out titleName, out titleId, out developer, out version); } else { applicationIcon = _nroIcon; titleName = Path.GetFileNameWithoutExtension(applicationPath); } } catch { Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}"); numApplicationsFound--; continue; } } else if (extension == ".nca") { try { Nca nca = new Nca(_virtualFileSystem.KeySet, new FileStream(applicationPath, FileMode.Open, FileAccess.Read).AsStorage()); int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program); if (nca.Header.ContentType != NcaContentType.Program || (nca.SectionExists(NcaSectionType.Data) && nca.Header.GetFsHeader(dataIndex).IsPatchSection())) { numApplicationsFound--; continue; } } catch (InvalidDataException) { Logger.Warning?.Print(LogClass.Application, $"The NCA header content type check has failed. This is usually because the header key is incorrect or missing. Errored File: {applicationPath}"); } catch { Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}"); numApplicationsFound--; continue; } applicationIcon = _ncaIcon; titleName = Path.GetFileNameWithoutExtension(applicationPath); } // If its an NSO we just set defaults else if (extension == ".nso") { applicationIcon = _nsoIcon; titleName = Path.GetFileNameWithoutExtension(applicationPath); } } } catch (IOException exception) { Logger.Warning?.Print(LogClass.Application, exception.Message); numApplicationsFound--; continue; } ApplicationMetadata appMetadata = LoadAndSaveMetaData(titleId); if (appMetadata.LastPlayed != "Never" && !DateTime.TryParse(appMetadata.LastPlayed, out _)) { Logger.Warning?.Print(LogClass.Application, $"Last played datetime \"{appMetadata.LastPlayed}\" is invalid for current system culture, skipping (did current culture change?)"); appMetadata.LastPlayed = "Never"; } ApplicationData data = new ApplicationData { Favorite = appMetadata.Favorite, Icon = applicationIcon, TitleName = titleName, TitleId = titleId, Developer = developer, Version = version, TimePlayed = ConvertSecondsToReadableString(appMetadata.TimePlayed), LastPlayed = appMetadata.LastPlayed, FileExtension = Path.GetExtension(applicationPath).ToUpper().Remove(0, 1), FileSize = (fileSize < 1) ? (fileSize * 1024).ToString("0.##") + "MB" : fileSize.ToString("0.##") + "GB", Path = applicationPath, ControlHolder = controlHolder }; numApplicationsLoaded++; OnApplicationAdded(new ApplicationAddedEventArgs() { AppData = data }); OnApplicationCountUpdated(new ApplicationCountUpdatedEventArgs() { NumAppsFound = numApplicationsFound, NumAppsLoaded = numApplicationsLoaded }); } OnApplicationCountUpdated(new ApplicationCountUpdatedEventArgs() { NumAppsFound = numApplicationsFound, NumAppsLoaded = numApplicationsLoaded }); } finally { _cancellationToken.Dispose(); _cancellationToken = null; } }
public void LoadEntries() { _contentDictionary = new SortedDictionary <(ulong, NcaContentType), string>(); foreach (StorageId storageId in Enum.GetValues(typeof(StorageId))) { string contentDirectory = null; string contentPathString = null; string registeredDirectory = null; try { contentPathString = LocationHelper.GetContentRoot(storageId); contentDirectory = LocationHelper.GetRealPath(_device.FileSystem, contentPathString); registeredDirectory = Path.Combine(contentDirectory, "registered"); } catch (NotSupportedException) { continue; } Directory.CreateDirectory(registeredDirectory); LinkedList <LocationEntry> locationList = new LinkedList <LocationEntry>(); void AddEntry(LocationEntry entry) { locationList.AddLast(entry); } foreach (string directoryPath in Directory.EnumerateDirectories(registeredDirectory)) { if (Directory.GetFiles(directoryPath).Length > 0) { string ncaName = new DirectoryInfo(directoryPath).Name.Replace(".nca", string.Empty); using (FileStream ncaFile = new FileStream(Directory.GetFiles(directoryPath)[0], FileMode.Open, FileAccess.Read)) { Nca nca = new Nca(_device.System.KeySet, ncaFile.AsStorage()); string switchPath = contentPathString + ":/" + ncaFile.Name.Replace(contentDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar); // Change path format to switch's switchPath = switchPath.Replace('\\', '/'); LocationEntry entry = new LocationEntry(switchPath, 0, (long)nca.Header.TitleId, nca.Header.ContentType); AddEntry(entry); _contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName); } } } foreach (string filePath in Directory.EnumerateFiles(contentDirectory)) { if (Path.GetExtension(filePath) == ".nca") { string ncaName = Path.GetFileNameWithoutExtension(filePath); using (FileStream ncaFile = new FileStream(filePath, FileMode.Open, FileAccess.Read)) { Nca nca = new Nca(_device.System.KeySet, ncaFile.AsStorage()); string switchPath = contentPathString + ":/" + filePath.Replace(contentDirectory, string.Empty).TrimStart(Path.DirectorySeparatorChar); // Change path format to switch's switchPath = switchPath.Replace('\\', '/'); LocationEntry entry = new LocationEntry(switchPath, 0, (long)nca.Header.TitleId, nca.Header.ContentType); AddEntry(entry); _contentDictionary.Add((nca.Header.TitleId, nca.Header.ContentType), ncaName); } } } if (_locationEntries.ContainsKey(storageId) && _locationEntries[storageId]?.Count == 0) { _locationEntries.Remove(storageId); } if (!_locationEntries.ContainsKey(storageId)) { _locationEntries.Add(storageId, locationList); } } TimeManager.Instance.InitializeTimeZone(_device); }
public static void Process(Context ctx) { using (var file = new FileStream(ctx.Options.InFile, FileMode.Open, FileAccess.Read)) { var xci = new Xci(ctx.Keyset, file.AsStorage()); ctx.Logger.LogMessage(xci.Print()); if (ctx.Options.RootDir != null) { xci.RootPartition?.Extract(ctx.Options.RootDir, ctx.Logger); } if (ctx.Options.UpdateDir != null) { xci.UpdatePartition?.Extract(ctx.Options.UpdateDir, ctx.Logger); } if (ctx.Options.NormalDir != null) { xci.NormalPartition?.Extract(ctx.Options.NormalDir, ctx.Logger); } if (ctx.Options.SecureDir != null) { xci.SecurePartition?.Extract(ctx.Options.SecureDir, ctx.Logger); } if (ctx.Options.LogoDir != null) { xci.LogoPartition?.Extract(ctx.Options.LogoDir, ctx.Logger); } if (ctx.Options.OutDir != null && xci.RootPartition != null) { XciPartition root = xci.RootPartition; if (root == null) { ctx.Logger.LogMessage("Could not find root partition"); return; } foreach (PfsFileEntry sub in root.Files) { var subPfs = new Pfs(root.OpenFile(sub)); string subDir = Path.Combine(ctx.Options.OutDir, sub.Name); subPfs.Extract(subDir, ctx.Logger); } } if (ctx.Options.ExefsOutDir != null || ctx.Options.ExefsOut != null) { Nca mainNca = GetXciMainNca(xci, ctx); if (mainNca == null) { ctx.Logger.LogMessage("Could not find Program NCA"); return; } NcaSection exefsSection = mainNca.Sections[(int)ProgramPartitionType.Code]; if (exefsSection == null) { ctx.Logger.LogMessage("NCA has no ExeFS section"); return; } if (ctx.Options.ExefsOutDir != null) { mainNca.ExtractSection(exefsSection.SectionNum, ctx.Options.ExefsOutDir, ctx.Options.IntegrityLevel, ctx.Logger); } if (ctx.Options.ExefsOut != null) { mainNca.ExportSection(exefsSection.SectionNum, ctx.Options.ExefsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger); } } if (ctx.Options.RomfsOutDir != null || ctx.Options.RomfsOut != null) { Nca mainNca = GetXciMainNca(xci, ctx); if (mainNca == null) { ctx.Logger.LogMessage("Could not find Program NCA"); return; } NcaSection romfsSection = mainNca.Sections.FirstOrDefault(x => x.Type == SectionType.Romfs); if (romfsSection == null) { ctx.Logger.LogMessage("NCA has no RomFS section"); return; } if (ctx.Options.RomfsOutDir != null) { var romfs = new Romfs(mainNca.OpenSection(romfsSection.SectionNum, false, ctx.Options.IntegrityLevel, true)); romfs.Extract(ctx.Options.RomfsOutDir, ctx.Logger); } if (ctx.Options.RomfsOut != null) { mainNca.ExportSection(romfsSection.SectionNum, ctx.Options.RomfsOut, ctx.Options.Raw, ctx.Options.IntegrityLevel, ctx.Logger); } } } }
private DlcWindow(Builder builder, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : base(builder.GetObject("_dlcWindow").Handle) { builder.Autoconnect(this); _titleId = titleId; _virtualFileSystem = virtualFileSystem; _dlcJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleId, "dlc.json"); _baseTitleInfoLabel.Text = $"DLC Available for {titleName} [{titleId.ToUpper()}]"; try { _dlcContainerList = JsonHelper.DeserializeFromFile <List <DlcContainer> >(_dlcJsonPath); } catch { _dlcContainerList = new List <DlcContainer>(); } _dlcTreeView.Model = new TreeStore(typeof(bool), typeof(string), typeof(string)); CellRendererToggle enableToggle = new CellRendererToggle(); enableToggle.Toggled += (sender, args) => { _dlcTreeView.Model.GetIter(out TreeIter treeIter, new TreePath(args.Path)); bool newValue = !(bool)_dlcTreeView.Model.GetValue(treeIter, 0); _dlcTreeView.Model.SetValue(treeIter, 0, newValue); if (_dlcTreeView.Model.IterChildren(out TreeIter childIter, treeIter)) { do { _dlcTreeView.Model.SetValue(childIter, 0, newValue); }while (_dlcTreeView.Model.IterNext(ref childIter)); } }; _dlcTreeView.AppendColumn("Enabled", enableToggle, "active", 0); _dlcTreeView.AppendColumn("TitleId", new CellRendererText(), "text", 1); _dlcTreeView.AppendColumn("Path", new CellRendererText(), "text", 2); foreach (DlcContainer dlcContainer in _dlcContainerList) { if (File.Exists(dlcContainer.Path)) { // The parent tree item has its own "enabled" check box, but it's the actual // nca entries that store the enabled / disabled state. A bit of a UI inconsistency. // Maybe a tri-state check box would be better, but for now we check the parent // "enabled" box if all child NCAs are enabled. Usually fine since each nsp has only one nca. bool areAllContentPacksEnabled = dlcContainer.DlcNcaList.TrueForAll((nca) => nca.Enabled); TreeIter parentIter = ((TreeStore)_dlcTreeView.Model).AppendValues(areAllContentPacksEnabled, "", dlcContainer.Path); using FileStream containerFile = File.OpenRead(dlcContainer.Path); PartitionFileSystem pfs = new PartitionFileSystem(containerFile.AsStorage()); _virtualFileSystem.ImportTickets(pfs); foreach (DlcNca dlcNca in dlcContainer.DlcNcaList) { using var ncaFile = new UniqueRef <IFile>(); pfs.OpenFile(ref ncaFile.Ref(), dlcNca.Path.ToU8Span(), OpenMode.Read).ThrowIfFailure(); Nca nca = TryCreateNca(ncaFile.Get.AsStorage(), dlcContainer.Path); if (nca != null) { ((TreeStore)_dlcTreeView.Model).AppendValues(parentIter, dlcNca.Enabled, nca.Header.TitleId.ToString("X16"), dlcNca.Path); } } } else { // DLC file moved or renamed. Allow the user to remove it without crashing the whole dialog. TreeIter parentIter = ((TreeStore)_dlcTreeView.Model).AppendValues(false, "", $"(MISSING) {dlcContainer.Path}"); } } }
public static Title processXci(string filename) { Title title = new Title(); using (var filestream = new FileStream(filename, FileMode.Open, FileAccess.Read)) { Xci xci; string biggestNca = null, controlNca = null; try { xci = new Xci(keyset, filestream.AsStorage()); title.distribution = Title.Distribution.Cartridge; log?.WriteLine("Processing XCI {0}", filename); if (xci.RootPartition?.Files.Length > 0) { title.structure.Add(Title.Structure.RootPartition); } if (xci.UpdatePartition?.Files.Length > 0) { PfsFileEntry[] fileEntries = xci.UpdatePartition.Files; List <string> cnmtNca = fileEntries.Select(x => x.Name).Where(x => x.EndsWith(".cnmt.nca")).Intersect(Title.SystemUpdate.Keys).ToList(); if (cnmtNca.Any()) { uint systemUpdate = unchecked ((uint)-1); Title.SystemUpdate.TryGetValue(cnmtNca.First(), out systemUpdate); title.systemUpdate = systemUpdate; } title.structure.Add(Title.Structure.UpdatePartition); } if (xci.NormalPartition?.Files.Length > 0) { title.structure.Add(Title.Structure.NormalPartition); } if (xci.SecurePartition?.Files.Length > 0) { PfsFileEntry[] fileEntries = xci.SecurePartition.Files; foreach (PfsFileEntry entry in fileEntries) { if (entry.Name.EndsWith(".cnmt.nca")) { try { using (var cnmtNca = xci.SecurePartition.OpenFile(entry)) { var nca = processCnmtNca(cnmtNca, ref title); if (nca.Item1 != null && (nca.Item2 != null || title.type == TitleType.AddOnContent)) { (biggestNca, controlNca) = nca; } } } catch (FileNotFoundException) { if (xci.SecurePartition.FileExists(entry.Name.Replace(".nca", ".ncz"))) { title.error = "Unsupported Format: Compressed NCA"; } } title.structure.Add(Title.Structure.CnmtNca); } else if (entry.Name.EndsWith(".cert")) { title.structure.Add(Title.Structure.Cert); } else if (entry.Name.EndsWith(".tik")) { try { using (var tik = xci.SecurePartition.OpenFile(entry)) { if (entry.Name.Split('.')[0].TryToBytes(out byte[] rightsId)) { processTik(tik, rightsId, ref keyset, out byte[] titleKey); title.titleKey = BitConverter.ToString(titleKey).Replace("-", "").ToUpper(); } } } catch (FileNotFoundException) { if (xci.SecurePartition.FileExists(entry.Name.Replace(".nca", ".ncz"))) { title.error = "Unsupported Format: Compressed NCA"; } } title.structure.Add(Title.Structure.Tik); } } if (!String.IsNullOrEmpty(biggestNca)) { try { using (var biggest = xci.SecurePartition.OpenFile(biggestNca)) { processBiggestNca(biggest, ref title); } } catch (FileNotFoundException) { if (xci.SecurePartition.FileExists(biggestNca.Replace(".nca", ".ncz"))) { title.error = "Unsupported Format: Compressed NCA"; } } } if (!String.IsNullOrEmpty(controlNca)) { try { using (var control = xci.SecurePartition.OpenFile(controlNca)) { processControlNca(control, ref title); } } catch (FileNotFoundException) { if (xci.SecurePartition.FileExists(controlNca.Replace(".nca", ".ncz"))) { title.error = "Unsupported Format: Compressed NCA"; } } } title.structure.Add(Title.Structure.SecurePartition); } if (xci.LogoPartition?.Files.Length > 0) { title.structure.Add(Title.Structure.LogoPartition); } } catch (InvalidDataException) { return(null); } } if (title.type == TitleType.Application || title.type == TitleType.Patch) { if (versionList.TryGetValue(title.baseTitleID, out uint version)) { title.latestVersion = version; } } log?.WriteLine("XCI information for {0}: [{1}] {2}", filename, title.titleID, title.titleName); return(title); }
private DlcWindow(Builder builder, VirtualFileSystem virtualFileSystem, string titleId, string titleName) : base(builder.GetObject("_dlcWindow").Handle) { builder.Autoconnect(this); _titleId = titleId; _virtualFileSystem = virtualFileSystem; _dlcJsonPath = System.IO.Path.Combine(AppDataManager.GamesDirPath, _titleId, "dlc.json"); _baseTitleInfoLabel.Text = $"DLC Available for {titleName} [{titleId.ToUpper()}]"; try { _dlcContainerList = JsonHelper.DeserializeFromFile <List <DlcContainer> >(_dlcJsonPath); } catch { _dlcContainerList = new List <DlcContainer>(); } _dlcTreeView.Model = new TreeStore(typeof(bool), typeof(string), typeof(string)); CellRendererToggle enableToggle = new CellRendererToggle(); enableToggle.Toggled += (sender, args) => { _dlcTreeView.Model.GetIter(out TreeIter treeIter, new TreePath(args.Path)); bool newValue = !(bool)_dlcTreeView.Model.GetValue(treeIter, 0); _dlcTreeView.Model.SetValue(treeIter, 0, newValue); if (_dlcTreeView.Model.IterChildren(out TreeIter childIter, treeIter)) { do { _dlcTreeView.Model.SetValue(childIter, 0, newValue); }while (_dlcTreeView.Model.IterNext(ref childIter)); } }; _dlcTreeView.AppendColumn("Enabled", enableToggle, "active", 0); _dlcTreeView.AppendColumn("TitleId", new CellRendererText(), "text", 1); _dlcTreeView.AppendColumn("Path", new CellRendererText(), "text", 2); foreach (DlcContainer dlcContainer in _dlcContainerList) { TreeIter parentIter = ((TreeStore)_dlcTreeView.Model).AppendValues(false, "", dlcContainer.Path); using FileStream containerFile = File.OpenRead(dlcContainer.Path); PartitionFileSystem pfs = new PartitionFileSystem(containerFile.AsStorage()); _virtualFileSystem.ImportTickets(pfs); foreach (DlcNca dlcNca in dlcContainer.DlcNcaList) { pfs.OpenFile(out IFile ncaFile, dlcNca.Path.ToU8Span(), OpenMode.Read).ThrowIfFailure(); Nca nca = TryCreateNca(ncaFile.AsStorage(), dlcContainer.Path); if (nca != null) { ((TreeStore)_dlcTreeView.Model).AppendValues(parentIter, dlcNca.Enabled, nca.Header.TitleId.ToString("X16"), dlcNca.Path); } } } }
public static Title processNsp(string filename) { Title title = new Title(); using (var filestream = new FileStream(filename, FileMode.Open, FileAccess.Read)) { Pfs pfs; string biggestNca = null, controlNca = null; try { pfs = new Pfs(filestream.AsStorage()); title.distribution = Title.Distribution.Digital; log?.WriteLine("Processing NSP {0}", filename); PfsFileEntry[] fileEntries = pfs.Files; foreach (PfsFileEntry entry in fileEntries) { if (entry.Name.EndsWith(".cnmt.xml")) { try { using (var cnmtXml = pfs.OpenFile(entry)) { (biggestNca, controlNca) = processCnmtXml(cnmtXml, ref title); } } catch (FileNotFoundException) { } title.structure.Add(Title.Structure.CnmtXml); } else if (entry.Name.EndsWith(".cnmt.nca")) { try { using (var cnmtNca = pfs.OpenFile(entry)) { var nca = processCnmtNca(cnmtNca, ref title); if (nca.Item1 != null && (nca.Item2 != null || title.type == TitleType.AddOnContent)) { (biggestNca, controlNca) = nca; } } } catch (FileNotFoundException) { if (pfs.FileExists(entry.Name.Replace(".nca", ".ncz"))) { title.error = "Unsupported Format: Compressed NCA"; } } title.structure.Add(Title.Structure.CnmtNca); } else if (entry.Name.EndsWith(".cert")) { title.structure.Add(Title.Structure.Cert); } else if (entry.Name.EndsWith(".tik")) { try { using (var tik = pfs.OpenFile(entry)) { if (entry.Name.Split('.')[0].TryToBytes(out byte[] rightsId)) { processTik(tik, rightsId, ref keyset, out byte[] titleKey); title.titleKey = BitConverter.ToString(titleKey).Replace("-", "").ToUpper(); } } } catch (FileNotFoundException) { if (pfs.FileExists(entry.Name.Replace(".nca", ".ncz"))) { title.error = "Unsupported Format: Compressed NCA"; } } title.structure.Add(Title.Structure.Tik); } else if (entry.Name.EndsWith(".legalinfo.xml")) { title.structure.Add(Title.Structure.LegalinfoXml); } else if (entry.Name.EndsWith(".nacp.xml")) { try { using (var nacpXml = pfs.OpenFile(entry)) { processNacpXml(nacpXml, ref title); } } catch (FileNotFoundException) { } title.structure.Add(Title.Structure.NacpXml); } else if (entry.Name.EndsWith(".programinfo.xml")) { title.structure.Add(Title.Structure.PrograminfoXml); } else if (entry.Name.Equals("cardspec.xml")) { title.structure.Add(Title.Structure.CardspecXml); } else if (entry.Name.Equals("authoringtoolinfo.xml")) { title.structure.Add(Title.Structure.AuthoringtoolinfoXml); } } if (!String.IsNullOrEmpty(biggestNca)) { try { using (var biggest = pfs.OpenFile(biggestNca)) { processBiggestNca(biggest, ref title); } } catch (FileNotFoundException) { if (pfs.FileExists(biggestNca.Replace(".nca", ".ncz"))) { title.error = "Unsupported Format: Compressed NCA"; } } } if (!String.IsNullOrEmpty(controlNca)) { try { using (var control = pfs.OpenFile(controlNca)) { processControlNca(control, ref title); } } catch (FileNotFoundException) { if (pfs.FileExists(controlNca.Replace(".nca", ".ncz"))) { title.error = "Unsupported Format: Compressed NCA"; } } } } catch (InvalidDataException) { return(null); } } if (title.type == TitleType.Application || title.type == TitleType.Patch) { if (versionList.TryGetValue(title.baseTitleID, out uint version)) { title.latestVersion = version; } } log?.WriteLine("NSP information for {0}: [{1}] {2}", filename, title.titleID, title.titleName); return(title); }
private void ExtractSection(NcaSectionType ncaSectionType) { FileChooserDialog fileChooser = new FileChooserDialog("Choose the folder to extract into", null, FileChooserAction.SelectFolder, "Cancel", ResponseType.Cancel, "Extract", ResponseType.Accept); fileChooser.SetPosition(WindowPosition.Center); int response = fileChooser.Run(); string destination = fileChooser.Filename; fileChooser.Dispose(); if (response == (int)ResponseType.Accept) { Thread extractorThread = new Thread(() => { string sourceFile = _gameTableStore.GetValue(_rowIter, 9).ToString(); Gtk.Application.Invoke(delegate { _dialog = new MessageDialog(null, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Cancel, null) { Title = "Ryujinx - NCA Section Extractor", Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png"), SecondaryText = $"Extracting {ncaSectionType} section from {System.IO.Path.GetFileName(sourceFile)}...", WindowPosition = WindowPosition.Center }; int dialogResponse = _dialog.Run(); if (dialogResponse == (int)ResponseType.Cancel || dialogResponse == (int)ResponseType.DeleteEvent) { _cancel = true; _dialog.Dispose(); } }); using (FileStream file = new FileStream(sourceFile, FileMode.Open, FileAccess.Read)) { Nca mainNca = null; Nca patchNca = null; if ((System.IO.Path.GetExtension(sourceFile).ToLower() == ".nsp") || (System.IO.Path.GetExtension(sourceFile).ToLower() == ".pfs0") || (System.IO.Path.GetExtension(sourceFile).ToLower() == ".xci")) { PartitionFileSystem pfs; if (System.IO.Path.GetExtension(sourceFile) == ".xci") { Xci xci = new Xci(_virtualFileSystem.KeySet, file.AsStorage()); pfs = xci.OpenPartition(XciPartitionType.Secure); } else { pfs = new PartitionFileSystem(file.AsStorage()); } foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*.nca")) { pfs.OpenFile(out IFile ncaFile, fileEntry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); Nca nca = new Nca(_virtualFileSystem.KeySet, ncaFile.AsStorage()); if (nca.Header.ContentType == NcaContentType.Program) { int dataIndex = Nca.GetSectionIndexFromType(NcaSectionType.Data, NcaContentType.Program); if (nca.Header.GetFsHeader(dataIndex).IsPatchSection()) { patchNca = nca; } else { mainNca = nca; } } } } else if (System.IO.Path.GetExtension(sourceFile).ToLower() == ".nca") { mainNca = new Nca(_virtualFileSystem.KeySet, file.AsStorage()); } if (mainNca == null) { Logger.PrintError(LogClass.Application, "Extraction failed. The main NCA was not present in the selected file."); Gtk.Application.Invoke(delegate { GtkDialog.CreateErrorDialog("Extraction failed. The main NCA was not present in the selected file."); }); return; } int index = Nca.GetSectionIndexFromType(ncaSectionType, mainNca.Header.ContentType); IFileSystem ncaFileSystem = patchNca != null ? mainNca.OpenFileSystemWithPatch(patchNca, index, IntegrityCheckLevel.ErrorOnInvalid) : mainNca.OpenFileSystem(index, IntegrityCheckLevel.ErrorOnInvalid); FileSystemClient fsClient = _virtualFileSystem.FsClient; string source = DateTime.Now.ToFileTime().ToString().Substring(10); string output = DateTime.Now.ToFileTime().ToString().Substring(10); fsClient.Register(source.ToU8Span(), ncaFileSystem); fsClient.Register(output.ToU8Span(), new LocalFileSystem(destination)); (Result? resultCode, bool canceled) = CopyDirectory(fsClient, $"{source}:/", $"{output}:/"); if (!canceled) { if (resultCode.Value.IsFailure()) { Logger.PrintError(LogClass.Application, $"LibHac returned error code: {resultCode.Value.ErrorCode}"); Gtk.Application.Invoke(delegate { _dialog?.Dispose(); GtkDialog.CreateErrorDialog("Extraction failed. Read the log file for further information."); }); } else if (resultCode.Value.IsSuccess()) { Gtk.Application.Invoke(delegate { _dialog?.Dispose(); MessageDialog dialog = new MessageDialog(null, DialogFlags.DestroyWithParent, MessageType.Info, ButtonsType.Ok, null) { Title = "Ryujinx - NCA Section Extractor", Icon = new Gdk.Pixbuf(Assembly.GetExecutingAssembly(), "Ryujinx.Ui.assets.Icon.png"), SecondaryText = "Extraction has completed successfully.", WindowPosition = WindowPosition.Center }; dialog.Run(); dialog.Dispose(); }); } } fsClient.Unmount(source.ToU8Span()); fsClient.Unmount(output.ToU8Span()); } }); extractorThread.Name = "GUI.NcaSectionExtractorThread"; extractorThread.IsBackground = true; extractorThread.Start(); } }
public byte[] GetApplicationIcon(string applicationPath) { byte[] applicationIcon = null; try { // Look for icon only if applicationPath is not a directory if (!Directory.Exists(applicationPath)) { string extension = Path.GetExtension(applicationPath).ToLower(); using (FileStream file = new FileStream(applicationPath, FileMode.Open, FileAccess.Read)) { if (extension == ".nsp" || extension == ".pfs0" || extension == ".xci") { try { PartitionFileSystem pfs; bool isExeFs = false; if (extension == ".xci") { Xci xci = new(_virtualFileSystem.KeySet, file.AsStorage()); pfs = xci.OpenPartition(XciPartitionType.Secure); } else { pfs = new PartitionFileSystem(file.AsStorage()); foreach (DirectoryEntryEx fileEntry in pfs.EnumerateEntries("/", "*")) { if (Path.GetFileNameWithoutExtension(fileEntry.FullPath) == "main") { isExeFs = true; } } } if (isExeFs) { applicationIcon = _nspIcon; } else { // Store the ControlFS in variable called controlFs GetControlFsAndTitleId(pfs, out IFileSystem controlFs, out _); // Read the icon from the ControlFS and store it as a byte array try { using var icon = new UniqueRef <IFile>(); controlFs.OpenFile(ref icon.Ref(), $"/icon_{_desiredTitleLanguage}.dat".ToU8Span(), OpenMode.Read).ThrowIfFailure(); using (MemoryStream stream = new MemoryStream()) { icon.Get.AsStream().CopyTo(stream); applicationIcon = stream.ToArray(); } } catch (HorizonResultException) { foreach (DirectoryEntryEx entry in controlFs.EnumerateEntries("/", "*")) { if (entry.Name == "control.nacp") { continue; } using var icon = new UniqueRef <IFile>(); controlFs.OpenFile(ref icon.Ref(), entry.FullPath.ToU8Span(), OpenMode.Read).ThrowIfFailure(); using (MemoryStream stream = new MemoryStream()) { icon.Get.AsStream().CopyTo(stream); applicationIcon = stream.ToArray(); } if (applicationIcon != null) { break; } } if (applicationIcon == null) { applicationIcon = extension == ".xci" ? _xciIcon : _nspIcon; } } } } catch (MissingKeyException) { applicationIcon = extension == ".xci" ? _xciIcon : _nspIcon; } catch (InvalidDataException) { applicationIcon = extension == ".xci" ? _xciIcon : _nspIcon; } catch (Exception exception) { Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. File: '{applicationPath}' Error: {exception}"); } } else if (extension == ".nro") { BinaryReader reader = new(file); byte[] Read(long position, int size) { file.Seek(position, SeekOrigin.Begin); return(reader.ReadBytes(size)); } try { file.Seek(24, SeekOrigin.Begin); int assetOffset = reader.ReadInt32(); if (Encoding.ASCII.GetString(Read(assetOffset, 4)) == "ASET") { byte[] iconSectionInfo = Read(assetOffset + 8, 0x10); long iconOffset = BitConverter.ToInt64(iconSectionInfo, 0); long iconSize = BitConverter.ToInt64(iconSectionInfo, 8); // Reads and stores game icon as byte array applicationIcon = Read(assetOffset + iconOffset, (int)iconSize); } else { applicationIcon = _nroIcon; } } catch { Logger.Warning?.Print(LogClass.Application, $"The file encountered was not of a valid type. Errored File: {applicationPath}"); } } else if (extension == ".nca") { applicationIcon = _ncaIcon; } // If its an NSO we just set defaults else if (extension == ".nso") { applicationIcon = _nsoIcon; } } } } catch (Exception) { Logger.Warning?.Print(LogClass.Application, $"Could not retrieve a valid icon for the app. Default icon will be used. Errored File: {applicationPath}"); } return(applicationIcon ?? _ncaIcon); }