public static byte[] GetFirmwareData(Switch Device)
        {
            byte[] Data        = null;
            long   TitleId     = 0x0100000000000809;
            string ContentPath = Device.System.ContentManager.GetInstalledContentPath(TitleId, StorageId.NandSystem, ContentType.Data);

            if (string.IsNullOrWhiteSpace(ContentPath))
            {
                return(null);
            }

            string     FirmwareTitlePath = Device.FileSystem.SwitchPathToSystemPath(ContentPath);
            FileStream FirmwareStream    = File.Open(FirmwareTitlePath, FileMode.Open, FileAccess.Read);
            Nca        FirmwareContent   = new Nca(Device.System.KeySet, FirmwareStream, false);
            Stream     RomFsStream       = FirmwareContent.OpenSection(0, false, Device.System.FsIntegrityCheckLevel);

            if (RomFsStream == null)
            {
                return(null);
            }

            Romfs FirmwareRomFs = new Romfs(RomFsStream);

            using (MemoryStream MemoryStream = new MemoryStream())
            {
                using (Stream FirmwareFile = FirmwareRomFs.OpenFile("/file"))
                {
                    FirmwareFile.CopyTo(MemoryStream);
                }

                Data = MemoryStream.ToArray();
            }

            FirmwareContent.Dispose();
            FirmwareStream.Dispose();

            return(Data);
        }
Esempio n. 2
0
        public static byte[] GetFirmwareData(Switch device)
        {
            byte[] data        = null;
            long   titleId     = 0x0100000000000809;
            string contentPath = device.System.ContentManager.GetInstalledContentPath(titleId, StorageId.NandSystem, ContentType.Data);

            if (string.IsNullOrWhiteSpace(contentPath))
            {
                return(null);
            }

            string     firmwareTitlePath = device.FileSystem.SwitchPathToSystemPath(contentPath);
            FileStream firmwareStream    = File.Open(firmwareTitlePath, FileMode.Open, FileAccess.Read);
            Nca        firmwareContent   = new Nca(device.System.KeySet, firmwareStream, false);
            Stream     romFsStream       = firmwareContent.OpenSection(0, false, device.System.FsIntegrityCheckLevel);

            if (romFsStream == null)
            {
                return(null);
            }

            Romfs firmwareRomFs = new Romfs(romFsStream);

            using (MemoryStream memoryStream = new MemoryStream())
            {
                using (Stream firmwareFile = firmwareRomFs.OpenFile("/file"))
                {
                    firmwareFile.CopyTo(memoryStream);
                }

                data = memoryStream.ToArray();
            }

            firmwareContent.Dispose();
            firmwareStream.Dispose();

            return(data);
        }
Esempio n. 3
0
        public static void Main(string[] cmdArgs)
        {
            OptionSet optionSet = new OptionSet
            {
                { "h|help", "Show this message and exit", _ => ShowHelp = true },
                { "v|dev=", "Load production keys as development keys\n(optional)", _ => IsDev = true },
                { "p|prodkeys=", "Path to a file containing switch production keys.\n(optional)", s => ProdKeyPath = s },
                { "k|titlekeys=", "Path to a file containing switch title keys.\n(optional)", s => TitleKeyPath = s },
                { "l|level=", "zStd compression level used to compress the file.", s => CompressionLevel = byte.Parse(s) },
                { "f|framesize=", "Size of a frame used to split a file.", s => FrameSize = uint.Parse(s) },
                { "t|temp=", "The directory to use for storing temp files.\n(Defaults to OS temp)", s => TempPath = s },
                { "o|output=", "The directory to output the compressed file.\n(Defaults to the same dir as input file)", s => OutDirectoryPath = s }
            };

            List <string> args = optionSet.Parse(cmdArgs);

            if (ShowHelp)
            {
                Console.WriteLine("ZcaTool - Copyright (c) 2020 Xpl0itR");
                Console.WriteLine("Usage: ZcaTool(.exe) [options] <path>");
                Console.WriteLine("Options:");
                optionSet.WriteOptionDescriptions(Console.Out);
                return;
            }

            if (args.Count < 1 || !File.Exists(args[0]))
            {
                throw new Exception("Input file does not exist!");
            }

            if (CompressionLevel < 1 || CompressionLevel > 22)
            {
                throw new Exception("You must enter a valid compression level!");
            }

            KeySet = LoadKeySet();
            OutDirectoryPath ??= Path.GetDirectoryName(args[0]);

            using (IStorage inStorage = new LocalStorage(args[0], FileAccess.Read))
            {
                string fileName = Path.GetFileNameWithoutExtension(args[0]);
                inStorage.GetSize(out long inSize);
                IStorage outStorage = null;

                Stopwatch stopwatch = Stopwatch.StartNew();
                switch (Path.GetExtension(args[0]).ToLower())
                {
                case ".nca":
                    Console.WriteLine($"Compressing {Path.GetFileName(args[0])} [{PrettyFileSize(inSize)}] with ZStandard compression level: {CompressionLevel} and frame size: {FrameSize}");
                    fileName += ".zca";
                    break;

                case ".zca":
                    Console.WriteLine($"Decompressing {Path.GetFileName(args[0])} [{PrettyFileSize(inSize)}]");
                    outStorage = new Nca(KeySet, new ZraDecompressionStream(inStorage.AsStream()).AsStorage()).OpenEncryptedNca();
                    fileName  += ".nca";
                    break;

                case ".nsp":
                    Console.WriteLine($"Compressing {Path.GetFileName(args[0])} [{PrettyFileSize(inSize)}] with ZStandard compression level: {CompressionLevel} and frame size: {FrameSize}");
                    outStorage = ProcessPartitionFileSystem(new PartitionFileSystem(inStorage), PartitionFileSystemType.Standard, true);
                    fileName  += ".zsp";
                    break;

                case ".zsp":
                    Console.WriteLine($"Decompressing {Path.GetFileName(args[0])} [{PrettyFileSize(inSize)}]");
                    outStorage = ProcessPartitionFileSystem(new PartitionFileSystem(inStorage), PartitionFileSystemType.Standard, false);
                    fileName  += ".nsp";
                    break;

                case ".xci":
                    Console.WriteLine($"Compressing {Path.GetFileName(args[0])} [{PrettyFileSize(inSize)}] with ZStandard compression level: {CompressionLevel} and frame size: {FrameSize}");
                    outStorage = ProcessXci(inStorage, true);
                    fileName  += ".zci";
                    break;

                case ".zci":
                    Console.WriteLine($"Decompressing {Path.GetFileName(args[0])} [{PrettyFileSize(inSize)}]");
                    outStorage = ProcessXci(inStorage, false);
                    fileName  += ".xci";
                    break;

                default:
                    throw new Exception("Input file was not of a valid format!");
                }

                long   outSize;
                string filePath = Path.Join(OutDirectoryPath, fileName);
                using (FileStream outStream = File.OpenWrite(filePath))
                {
                    if (Path.GetExtension(args[0]).ToLower() == ".nca")
                    {
                        (IStorage processedNca, byte[] metaBuffer) = ProcessNca(inStorage);
                        processedNca.GetSize(out long ncaLength);

                        using (ZraCompressionStream compressionStream = new ZraCompressionStream(outStream, (ulong)ncaLength, CompressionLevel, FrameSize, metaBuffer, true))
                        {
                            processedNca.CopyToStream(compressionStream, (int)FrameSize);
                        }
                    }
                    else
                    {
                        outStorage.CopyToStream(outStream);
                        outStorage?.Dispose();
                    }

                    outSize = outStream.Length;
                }
                stopwatch.Stop();

                Console.WriteLine($"Out file: {filePath} [{PrettyFileSize(outSize)}]");
                Console.WriteLine($"Time taken: {decimal.Round((decimal)stopwatch.ElapsedMilliseconds / 1000, 2)}s ({stopwatch.ElapsedMilliseconds}ms)");
                Console.WriteLine($"Size Reduction: {decimal.Truncate(100 - (decimal)outSize / inSize * 100)}%");
            }

            Console.WriteLine("Cleaning temp files...");
            ZraCompressionStorageHack.CleanTempFiles();
            Console.WriteLine("Done!");
        }
Esempio n. 4
0
        public void EnsureInitialized(ContentManager ContentManager)
        {
            if (FontData == null)
            {
                Device.Memory.FillWithZeros(PhysicalAddress, Horizon.FontSize);

                uint FontOffset = 0;

                FontInfo CreateFont(string Name)
                {
                    if (ContentManager.TryGetFontTitle(Name, out long FontTitle))
                    {
                        string ContentPath = ContentManager.GetInstalledContentPath(FontTitle, StorageId.NandSystem, ContentType.Data);
                        string FontPath    = Device.FileSystem.SwitchPathToSystemPath(ContentPath);

                        if (!string.IsNullOrWhiteSpace(FontPath))
                        {
                            int FileIndex = 0;

                            //Use second file in Chinese Font title for standard
                            if (Name == "FontChineseSimplified")
                            {
                                FileIndex = 1;
                            }

                            FileStream NcaFileStream = new FileStream(FontPath, FileMode.Open, FileAccess.Read);
                            Nca        Nca           = new Nca(Device.System.KeySet, NcaFileStream, false);
                            NcaSection RomfsSection  = Nca.Sections.FirstOrDefault(x => x?.Type == SectionType.Romfs);
                            Romfs      Romfs         = new Romfs(Nca.OpenSection(RomfsSection.SectionNum, false, Device.System.FsIntegrityCheckLevel));
                            Stream     FontFile      = Romfs.OpenFile(Romfs.Files[FileIndex]);

                            byte[] Data = DecryptFont(FontFile);

                            FontInfo Info = new FontInfo((int)FontOffset, Data.Length);

                            WriteMagicAndSize(PhysicalAddress + FontOffset, Data.Length);

                            FontOffset += 8;

                            uint Start = FontOffset;

                            for (; FontOffset - Start < Data.Length; FontOffset++)
                            {
                                Device.Memory.WriteByte(PhysicalAddress + FontOffset, Data[FontOffset - Start]);
                            }

                            NcaFileStream.Dispose();
                            Nca.Dispose();

                            return(Info);
                        }
                    }

                    string FontFilePath = Path.Combine(FontsPath, Name + ".ttf");

                    if (File.Exists(FontFilePath))
                    {
                        byte[] Data = File.ReadAllBytes(FontFilePath);

                        FontInfo Info = new FontInfo((int)FontOffset, Data.Length);

                        WriteMagicAndSize(PhysicalAddress + FontOffset, Data.Length);

                        FontOffset += 8;

                        uint Start = FontOffset;

                        for (; FontOffset - Start < Data.Length; FontOffset++)
                        {
                            Device.Memory.WriteByte(PhysicalAddress + FontOffset, Data[FontOffset - Start]);
                        }

                        return(Info);
                    }
                    else
                    {
                        throw new InvalidSystemResourceException($"Font \"{Name}.ttf\" not found. Please provide it in \"{FontsPath}\".");
                    }
                }

                FontData = new Dictionary <SharedFontType, FontInfo>()
                {
                    { SharedFontType.JapanUsEurope, CreateFont("FontStandard") },
                    { SharedFontType.SimplifiedChinese, CreateFont("FontChineseSimplified") },
                    { SharedFontType.SimplifiedChineseEx, CreateFont("FontExtendedChineseSimplified") },
                    { SharedFontType.TraditionalChinese, CreateFont("FontChineseTraditional") },
                    { SharedFontType.Korean, CreateFont("FontKorean") },
                    { SharedFontType.NintendoEx, CreateFont("FontNintendoExtended") }
                };

                if (FontOffset > Horizon.FontSize)
                {
                    throw new InvalidSystemResourceException(
                              $"The sum of all fonts size exceed the shared memory size. " +
                              $"Please make sure that the fonts don't exceed {Horizon.FontSize} bytes in total. " +
                              $"(actual size: {FontOffset} bytes).");
                }
            }
        }
Esempio n. 5
0
        public void LoadEntries()
        {
            ContentDictionary = new SortedDictionary <(ulong, ContentType), 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 NEx)
                {
                    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, false);

                            string SwitchPath = Path.Combine(ContentPathString + ":",
                                                             NcaFile.Name.Replace(ContentDirectory, string.Empty).TrimStart('\\'));

                            // 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);

                            NcaFile.Close();
                            Nca.Dispose();
                            NcaFile.Dispose();
                        }
                    }
                }

                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, false);

                            string SwitchPath = Path.Combine(ContentPathString + ":",
                                                             FilePath.Replace(ContentDirectory, string.Empty).TrimStart('\\'));

                            // 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);

                            NcaFile.Close();
                            Nca.Dispose();
                            NcaFile.Dispose();
                        }
                    }
                }

                if (LocationEntries.ContainsKey(StorageId) && LocationEntries[StorageId]?.Count == 0)
                {
                    LocationEntries.Remove(StorageId);
                }

                if (!LocationEntries.ContainsKey(StorageId))
                {
                    LocationEntries.Add(StorageId, LocationList);
                }
            }
        }
Esempio n. 6
0
        public void LoadEntries()
        {
            _contentDictionary = new SortedDictionary <(ulong, ContentType), 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, false);

                            string switchPath = Path.Combine(contentPathString + ":",
                                                             ncaFile.Name.Replace(contentDirectory, string.Empty).TrimStart('\\'));

                            // 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);

                            ncaFile.Close();
                            nca.Dispose();
                            ncaFile.Dispose();
                        }
                    }
                }

                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, false);

                            string switchPath = Path.Combine(contentPathString + ":",
                                                             filePath.Replace(contentDirectory, string.Empty).TrimStart('\\'));

                            // 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);

                            ncaFile.Close();
                            nca.Dispose();
                            ncaFile.Dispose();
                        }
                    }
                }

                if (_locationEntries.ContainsKey(storageId) && _locationEntries[storageId]?.Count == 0)
                {
                    _locationEntries.Remove(storageId);
                }

                if (!_locationEntries.ContainsKey(storageId))
                {
                    _locationEntries.Add(storageId, locationList);
                }
            }
        }