Exemplo n.º 1
0
        public static async Task <RomFs> Load(IBinaryDataAccessor data)
        {
            var header = new RomFsHeader(await data.ReadArrayAsync(0, 0x6B));
            var romfs  = new RomFs(data, header);
            await romfs.Initialize();

            return(romfs);
        }
Exemplo n.º 2
0
        /// <summary>
        /// Builds a new ROM file system from the given directory
        /// </summary>
        /// <param name="directory">Directory from which to load the files</param>
        /// <param name="fileSystem">File system from which to load the files</param>
        /// <returns>A newly built ROM file system</returns>
        public static async Task <RomFs> Build(string directory, IFileSystem fileSystem, ProcessingProgressedToken?progressToken = null)
        {
            Stream?stream       = null;
            string?tempFilename = null;

            try
            {
                // A memory stream is faster, but an internal limitation means it's unsuitable for files larger than 2GB
                // We'll fall back to a file stream if our raw data won't fit within 2GB minus 400 MB (for safety, since there's still metadata, hashes, and other partitions)
                if (fileSystem.GetDirectoryLength(directory) < (int.MaxValue - (400 * Math.Pow(1024, 2))))
                {
                    stream = new MemoryStream();
                }
                else
                {
                    // Do not use IFileSystem; this is for temporary storage since RAM isn't an option
                    tempFilename = Path.GetTempFileName();
                    stream       = File.Open(tempFilename, FileMode.OpenOrCreate, FileAccess.ReadWrite);
                }

                RomFsBuilder.RomFsBuilder.BuildRomFS(directory, fileSystem, stream, progressToken);

                BinaryFile data;
                if (stream is FileStream)
                {
                    // We want the BinaryFile class to own the file so it will dispose of it properly
                    // So let's dispose our copy and let it re-open it however it sees fit
                    // And instead of a BinaryFile, use a FileDeletingBinaryFile to delete the file on dispose

                    stream.Dispose();
                    stream = null;

                    if (string.IsNullOrEmpty(tempFilename))
                    {
                        // The developer (probably me) made a mistake
                        throw new Exception("Temporary file not found");
                    }

                    data = new FileDeletingBinaryFile(tempFilename);
                }
                else if (stream is MemoryStream memoryStream)
                {
                    try
                    {
                        // Faster but maybe more memory-intensive
                        var memoryStreamArray = memoryStream.ToArray();
                        data = new BinaryFile(memoryStreamArray);
                    }
                    catch (OutOfMemoryException)
                    {
                        // Slower but more reliable
                        data = new BinaryFile(memoryStream);
                    }
                }
                else
                {
                    // The developer (probably me) made a mistake
                    throw new Exception("Unexpected type of stream in RomFs.Build");
                }

                var header = new RomFsHeader(await data.ReadArrayAsync(0, 0x6B));
                var romFs  = new RomFs(data, header);
                await romFs.Initialize();

                return(romFs);
            }
            finally
            {
                stream?.Dispose();
            }
        }