Пример #1
0
        public async Task CanRebuildRomfs(string filename)
        {
            var fs = new PhysicalFileSystem();

            using (var originalRom = new ThreeDsRom())
            {
                await originalRom.OpenFile(filename);

                using (var newRom = new ThreeDsRom(await RomFs.Build("/RomFS", originalRom)))
                {
                    await AssertDirectoriesEqual("/RomFS", originalRom, "/RomFS", newRom);
                }
            }
        }
Пример #2
0
        public async void ExeFsHashesValid(string filename)
        {
            using var rom = new ThreeDsRom();
            await rom.OpenFile(filename);

            rom.Partitions.Should().NotBeNull();

            foreach (var partition in rom.Partitions)
            {
                if (partition.ExeFs != null)
                {
                    partition.ExeFs.AreAllHashesValid().Should().Be(true);
                }
            }
        }
Пример #3
0
        private async Task AssertDirectoriesEqual(string directory1, ThreeDsRom fileSystem1, string directory2, ThreeDsRom filesystem2)
        {
            // Assume directory1 is good. It's sourced by a regular, non-rebuilt ROM, which should be covered by its own tests.
            await(fileSystem1 as IFileSystem).GetFiles(directory1, "*", false).RunAsyncForEach(async file =>
            {
                var otherFile = Path.Combine(directory2, file.Replace(directory1, "").TrimStart('/'));

                var data1 = await fileSystem1.GetFileReference(file).ReadArrayAsync();
                var data2 = await filesystem2.GetFileReference(otherFile).ReadArrayAsync();

                data1.Length.Should().Be(data2.Length, $"because file '{file}' should have the same size as file '{otherFile}' in both directories");

                UnsafeCompare(data1, data2).Should().BeTrue();
            });
        }
Пример #4
0
        public async Task CanRebuildRomfs(string filename)
        {
            using var originalRom = new ThreeDsRom();
            await originalRom.OpenFile(filename);

            for (int i = 0; i < originalRom.Partitions.Length; i++)
            {
                var partition = originalRom.Partitions[i]?.RomFs;
                if (partition != null)
                {
                    var romFsDirName = "/" + originalRom.GetRomFsDirectoryName(i);
                    using var newRom = new ThreeDsRom(await RomFs.Build(romFsDirName, originalRom), i);
                    await AssertDirectoriesEqual(romFsDirName, originalRom, romFsDirName, newRom);
                }
            }
        }
Пример #5
0
        public async Task CanRebuildExefs(string filename)
        {
            using var originalRom = new ThreeDsRom();
            await originalRom.OpenFile(filename);

            for (int i = 0; i < originalRom.Partitions.Length; i++)
            {
                var exefs = originalRom.Partitions[i]?.ExeFs;
                if (exefs != null)
                {
                    var exeFsDirName = "/" + ThreeDsRom.GetExeFsDirectoryName(i);
                    using var data   = new BinaryFile(exefs.ToByteArray());
                    using var newRom = new ThreeDsRom(await ExeFs.Load(data), i);
                    await AssertDirectoriesEqual(exeFsDirName, originalRom, exeFsDirName, newRom);
                }
            }
        }
Пример #6
0
        public async Task CanRebuildExheader(string filename)
        {
            using var originalRom = new ThreeDsRom();
            await originalRom.OpenFile(filename);

            for (int i = 0; i < originalRom.Partitions.Length; i++)
            {
                if (originalRom.Partitions[i]?.ExHeader != null)
                {
                    var exheader     = originalRom.Partitions[i].ExHeader;
                    var exheaderData = exheader.ToByteArray();
                    using var exheaderBinary = new BinaryFile(exheaderData);
                    var newExheader = await NcchExtendedHeader.Load(exheaderBinary);

                    newExheader.Should().NotBeNull();
                    newExheader.Should().BeEquivalentTo(exheader, $"because the exheader in partition {i} should have been rebuilt correctly");
                }
            }
        }
Пример #7
0
        public async Task VerifyFileSystemInterface(string filename)
        {
            using var rom = new ThreeDsRom();
            await rom.OpenFile(filename);

            var romAsProvider = rom as IFileSystem;
            var files         = romAsProvider.GetFiles("/", "*", false);

            foreach (var file in files)
            {
                romAsProvider.FileExists(file).Should().BeTrue("File '" + file + "' should exist");
            }

            var directories = romAsProvider.GetDirectories("/", false);

            foreach (var dir in directories)
            {
                romAsProvider.DirectoryExists(dir).Should().BeTrue("File '" + dir + "' should exist");
            }
        }
Пример #8
0
        public async void ReadsNcchPartitions(string filename)
        {
            using var rom = new ThreeDsRom();
            await rom.OpenFile(filename);

            rom.Partitions.Should().NotBeNull();

            foreach (var partition in rom.Partitions)
            {
                if (partition.Header != null)
                {
                    partition.Header.Magic.Should().Be("NCCH");
                    if (partition.RomFs != null)
                    {
                        partition.RomFs.Header.Should().NotBeNull();
                        partition.RomFs.Header.Magic.Should().Be("IVFC");
                        partition.RomFs.Header.MagicNumber.Should().Be(0x10000);
                    }
                }
            }
        }
Пример #9
0
        public async Task ExtractRomFsFiles(string filename)
        {
            var progressReportToken = new ProgressReportToken();

            using var rom = new ThreeDsRom();

            await rom.OpenFile(filename);

            var extractionTask = rom.ExtractFiles("./extracted-" + Path.GetFileName(filename), progressReportToken);

            //// Awaiting the task and handling the progressReportToken makes everything wait on Debug.WriteLine, slowing things down a lot
            //// So we asynchronously poll
            //while (!extractionTask.IsCompleted && !extractionTask.IsFaulted)
            //{
            //    Debug.WriteLine("Extraction progress: " + Math.Round(progressReportToken.Progress * 100, 2).ToString());
            //    await Task.Delay(200);
            //}

            await extractionTask;

            Debug.WriteLine("Extraction complete!");
        }
Пример #10
0
        public async Task CanRebuildNcchPartitions(string filename)
        {
            using var originalRom = new ThreeDsRom();
            await originalRom.OpenFile(filename);

            var originalRomFs = originalRom as IFileSystem;

            for (int i = 0; i < originalRom.Partitions.Length; i++)
            {
                if (originalRom.Partitions[i]?.Header != null)
                {
                    var romFsDirName        = "/" + originalRom.GetRomFsDirectoryName(i);
                    var exeFsDirName        = "/" + ThreeDsRom.GetExeFsDirectoryName(i);
                    var headerFilename      = "/" + ThreeDsRom.GetHeaderFileName(i);
                    var exHeaderFilename    = "/" + ThreeDsRom.GetExHeaderFileName(i);
                    var plainRegionFilename = "/" + ThreeDsRom.GetPlainRegionFileName(i);
                    var logoFilename        = "/" + ThreeDsRom.GetLogoFileName(i);
                    if (!originalRomFs.FileExists(exHeaderFilename))
                    {
                        exHeaderFilename = null;
                    }
                    if (!originalRomFs.DirectoryExists(romFsDirName))
                    {
                        romFsDirName = null;
                    }
                    if (!originalRomFs.DirectoryExists(exeFsDirName))
                    {
                        exeFsDirName = null;
                    }
                    if (!originalRomFs.DirectoryExists(plainRegionFilename))
                    {
                        plainRegionFilename = null;
                    }
                    if (!originalRomFs.DirectoryExists(logoFilename))
                    {
                        logoFilename = null;
                    }

                    var tempFilename = "ncch-rebuild-" + Path.GetFileName(filename) + ".cxi";
                    try
                    {
                        using var newPartition = await NcchPartition.Build(headerFilename, exHeaderFilename, exeFsDirName, romFsDirName, plainRegionFilename, logoFilename, originalRom);

                        using var savedPartitionStream = new FileStream(tempFilename, FileMode.OpenOrCreate);
                        using var savedPartitionFile   = new BinaryFile(savedPartitionStream);
                        long fileSize = (long)Math.Pow(2, Math.Ceiling(Math.Log(newPartition.Header.RomFsSize * 0x200) / Math.Log(2)));
                        savedPartitionFile.SetLength(fileSize);
                        await newPartition.WriteBinary(savedPartitionFile);

                        using var rebuiltPartition = await NcchPartition.Load(savedPartitionFile);

                        using var newRom = new ThreeDsRom(rebuiltPartition, i);
                        if (romFsDirName != null)
                        {
                            await AssertDirectoriesEqual(romFsDirName, originalRom, romFsDirName, newRom);
                        }
                        if (exeFsDirName != null)
                        {
                            await AssertDirectoriesEqual(exeFsDirName, originalRom, exeFsDirName, newRom);
                        }

                        if (exHeaderFilename != null)
                        {
                            var originalFile = (originalRom as IFileSystem).ReadAllBytes(exHeaderFilename);
                            var newFile      = (newRom as IFileSystem).ReadAllBytes(exHeaderFilename);
                            UnsafeCompare(originalFile, newFile).Should().BeTrue();
                        }
                        if (plainRegionFilename != null)
                        {
                            var originalFile = (originalRom as IFileSystem).ReadAllBytes(plainRegionFilename);
                            var newFile      = (newRom as IFileSystem).ReadAllBytes(plainRegionFilename);
                            UnsafeCompare(originalFile, newFile).Should().BeTrue();
                        }
                        if (logoFilename != null)
                        {
                            var originalFile = (originalRom as IFileSystem).ReadAllBytes(logoFilename);
                            var newFile      = (newRom as IFileSystem).ReadAllBytes(logoFilename);
                            UnsafeCompare(originalFile, newFile).Should().BeTrue();
                        }
                    }
                    finally
                    {
                        if (File.Exists(tempFilename))
                        {
                            // Comment this line out to keep it around for debugging purposes
                            //File.Delete(tempFilename);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Loads a ROM from the given path if supported
        /// </summary>
        /// <param name="path"></param>
        /// <param name="fileSystem"></param>
        /// <returns>The ROM that was loaded, or null if the given path is not supported</returns>
        public static async Task <IModTarget?> LoadRom(string path, IFileSystem fileSystem)
        {
            if (fileSystem.FileExists(path))
            {
                bool is3dsRom;

                BinaryFile?file        = null;
                bool       disposeFile = true;
                try
                {
                    file     = new BinaryFile(path, fileSystem);
                    is3dsRom = await ThreeDsRom.IsThreeDsRom(file).ConfigureAwait(false);

                    if (is3dsRom)
                    {
                        var rom = await ThreeDsRom.Load(file).ConfigureAwait(false);

                        // To-do: check title ID to ensure it's a PSMD ROM
                        // For now, just assume it's supported by our class

                        disposeFile = false;
                        return(new PsmdRom(rom));
                    }
                    else
                    {
                        return(null);
                    }
                }
                finally
                {
                    if (disposeFile && file != null)
                    {
                        file.Dispose();
                    }
                }
            }
            else if (fileSystem.DirectoryExists(path))
            {
                // Is it a Switch ROM or a 3DS ROM?
                // To-do: check title ID to ensure it's the correct type of ROM
                if (fileSystem.FileExists(Path.Combine(path, "ExeFS", "code.bin")))
                {
                    // It's a 3DS ROM
                    return(new PsmdRom(path, fileSystem));
                }
                else if (fileSystem.FileExists(Path.Combine(path, "exefs", "main")))
                {
                    // It's a Switch ROM
                    return(new RtdxRom(path, fileSystem));
                }
                else
                {
                    // We couldn't find the executable and can make no conclusion
                    return(null);
                }
            }
            else
            {
                return(null);
            }
        }