Example #1
0
        // Create a new ROM.
        public ROM(string filePath, string conversionPath)
        {
            // Build system.
            if (!conversionPath.Equals(""))
            {
                Directory.CreateDirectory(conversionPath);
                ConversionInfo = new ConversionInfo(conversionPath);
            }

            // Read the file.
            using (Stream s = new FileStream(filePath, FileMode.Open)) {
                // Read general data.
                BinaryReader r = new BinaryReader(s);
                GameTitle            = r.ReadFixedLen(0xC);
                GameCode             = r.ReadFixedLen(0x4);
                MakerCode            = r.ReadFixedLen(0x2);
                UnitCode             = (UnitCode)r.ReadByte();
                EncryptionSeedSelect = r.ReadByte();
                DeviceCapacity       = r.ReadByte();
                r.ReadBytes(7);
                Revision = r.ReadUInt16();
                Version  = r.ReadByte();
                Flags    = r.ReadByte();
                uint arm9Offset = r.ReadUInt32();
                Arm9EntryAddress = r.ReadUInt32();
                Arm9LoadAddress  = r.ReadUInt32();
                uint arm9Size   = r.ReadUInt32();
                uint arm7Offset = r.ReadUInt32();
                Arm7EntryAddress = r.ReadUInt32();
                Arm7LoadAddress  = r.ReadUInt32();
                uint arm7Size          = r.ReadUInt32();
                uint fntOffset         = r.ReadUInt32();
                uint fntSize           = r.ReadUInt32();
                uint fatOffset         = r.ReadUInt32();
                uint fatSize           = r.ReadUInt32();
                uint arm9OverlayOffset = r.ReadUInt32();
                uint arm9OverlayLength = r.ReadUInt32();
                uint arm7OverlayOffset = r.ReadUInt32();
                uint arm7OverlayLength = r.ReadUInt32();
                NormalCardControlRegisterSettings = r.ReadUInt32();
                SecureCardControlRegisterSettings = r.ReadUInt32();
                uint iconBannerOffset = r.ReadUInt32();
                SecureAreaCRC         = r.ReadUInt16();
                SecureTransferTimeout = r.ReadUInt16();
                Arm9Autoload          = r.ReadUInt32();
                Arm7Autoload          = r.ReadUInt32();
                SecureDisable         = r.ReadUInt64();
                uint romSize = r.ReadUInt32() + 0x88;
                HeaderSize = r.ReadUInt32();

                // Read logo.
                r.BaseStream.Position = 0xC0;
                NintendoLogo          = r.ReadBytes(0x9C);
                r.ReadUInt16(); // Nintendo logo CRC. It is literally just the CRC of the logo.
                r.ReadUInt16(); // Header CRC. It is the CRC of everything up to this point (0 to 0x15E).

                // Get banner.
                r.BaseStream.Position = iconBannerOffset;
                ushort bannerVersion = r.ReadUInt16();
                r.BaseStream.Position -= 2;
                Banner = r.ReadBytes((int)BANNER_LENGTHS[bannerVersion]);

                // Code binaries.
                r.BaseStream.Position = arm9Offset;
                Arm9 = r.ReadBytes((int)arm9Size);
                r.BaseStream.Position = arm7Offset;
                Arm7 = r.ReadBytes((int)arm7Size);

                // Get overlays.
                Arm9Overlays = Overlay.LoadOverlays(r, arm9OverlayOffset, arm9OverlayLength);
                Arm7Overlays = Overlay.LoadOverlays(r, arm7OverlayOffset, arm7OverlayLength);
                for (int i = 0; i < Arm9Overlays.Count; i++)
                {
                    r.BaseStream.Position = fatOffset + Arm9Overlays[i].FileId * 8;
                    uint fileStart = r.ReadUInt32();
                    uint fileEnd   = r.ReadUInt32();
                    r.BaseStream.Position = fileStart;
                    Arm9Overlays[i].Data  = r.ReadBytes((int)(fileEnd - fileStart));
                }
                for (int i = 0; i < Arm7Overlays.Count; i++)
                {
                    r.BaseStream.Position = fatOffset + Arm7Overlays[i].FileId * 8;
                    uint fileStart = r.ReadUInt32();
                    uint fileEnd   = r.ReadUInt32();
                    r.BaseStream.Position = fileStart;
                    Arm7Overlays[i].Data  = r.ReadBytes((int)(fileEnd - fileStart));
                }

                // Read filesystem.
                Filesystem = new Filesystem(r, fntOffset, fntSize, fatOffset, fatSize, !conversionPath.Equals(""), ConversionInfo);

                // Dispose.
                r.Dispose();
            }
        }
Example #2
0
        // Pack a ROM.
        public void Pack(string romFolder)
        {
            // File reading content.
            byte[] ReadFile(string path)
            {
                return(System.IO.File.ReadAllBytes(romFolder + "/" + path));
            }

            string[] ReadFileList(string path)
            {
                return(System.IO.File.ReadAllLines(romFolder + "/" + path));
            }

            T ReadJSON <T>(string path)
            {
                return(JsonConvert.DeserializeObject <T>(System.IO.File.ReadAllText(romFolder + "/" + path)));
            }

            List <ushort> validFileIds = new List <ushort>();

            void VerifyFiles(IEnumerable <ushort> fileIds)
            {
                foreach (var u in fileIds)
                {
                    if (validFileIds.Contains(u))
                    {
                        throw new Exception("ERROR: Duplicate overlay file ID in use: 0x" + u.ToString("X"));
                    }
                    else
                    {
                        validFileIds.Add(u);
                    }
                }
            }

            // Get header info and copy it.
            ROM headerInfo = ReadJSON <ROM>("__ROM__/header.json");

            GameTitle            = headerInfo.GameTitle;
            GameCode             = headerInfo.GameCode;
            MakerCode            = headerInfo.MakerCode;
            UnitCode             = headerInfo.UnitCode;
            EncryptionSeedSelect = headerInfo.EncryptionSeedSelect;
            DeviceCapacity       = headerInfo.DeviceCapacity;
            Revision             = headerInfo.Revision;
            Version          = headerInfo.Version;
            Flags            = headerInfo.Flags;
            Arm9EntryAddress = headerInfo.Arm9EntryAddress;
            Arm9LoadAddress  = headerInfo.Arm9LoadAddress;
            Arm7EntryAddress = headerInfo.Arm7EntryAddress;
            Arm7LoadAddress  = headerInfo.Arm7LoadAddress;
            NormalCardControlRegisterSettings = headerInfo.NormalCardControlRegisterSettings;
            SecureCardControlRegisterSettings = headerInfo.SecureCardControlRegisterSettings;
            SecureAreaCRC         = headerInfo.SecureAreaCRC;
            SecureTransferTimeout = headerInfo.SecureTransferTimeout;
            Arm9Autoload          = headerInfo.Arm9Autoload;
            Arm7Autoload          = headerInfo.Arm7Autoload;
            SecureDisable         = headerInfo.SecureDisable;
            HeaderSize            = headerInfo.HeaderSize;

            // Get the Nintendo logo and banner.
            NintendoLogo = ReadFile("__ROM__/nintendoLogo.bin");
            Banner       = ReadFile("__ROM__/banner.bin");

            // Fetch Arm payloads.
            Arm9 = ReadFile("__ROM__/arm9.bin");
            Arm7 = ReadFile("__ROM__/arm7.bin");

            // Get overlays.
            Arm9Overlays = ReadJSON <List <Overlay> >("__ROM__/arm9Overlays.json");
            VerifyFiles(Arm9Overlays.Select(x => x.FileId));
            Arm7Overlays = ReadJSON <List <Overlay> >("__ROM__/arm7Overlays.json");
            VerifyFiles(Arm7Overlays.Select(x => x.FileId));
            foreach (var o in Arm9Overlays)
            {
                o.Data = ReadFile("__ROM__/Arm9/" + o.Id + ".bin");
            }
            foreach (var o in Arm7Overlays)
            {
                o.Data = ReadFile("__ROM__/Arm7/" + o.Id + ".bin");
            }

            // Read files.
            ushort currFolderId = 1;

            string[] fileList = ReadFileList("__ROM__/files.txt");
            Dictionary <string, Folder> folders = new Dictionary <string, Folder>();

            Filesystem = new Filesystem();
            folders.Add("", Filesystem);
            foreach (var s in fileList)
            {
                AddFileToFilesystem(s);
            }

            // Add a file to the filesystem.
            void AddFileToFilesystem(string s)
            {
                // First get its properties.
                string[] fileProperties = s.Split(' ');
                string   filePath       = fileProperties[0];

                if (!filePath.StartsWith("../"))
                {
                    throw new Exception("ERROR: All files must be relative to parent directory \"../\"");
                }
                else
                {
                    filePath = filePath.Substring(3);
                }

                // Get file ID.
                ushort fileId = (ushort)Helper.ReadStringNumber(fileProperties[1]);

                if (validFileIds.Contains(fileId))
                {
                    throw new Exception("ERROR: File ../" + filePath + " uses duplicate file ID 0x" + fileId.ToString("X"));
                }
                else
                {
                    validFileIds.Add(fileId);
                }

                // Proper file name and folder path.
                string fileName   = filePath;
                string folderPath = "";

                while (fileName.Contains('/'))
                {
                    folderPath += "/" + fileName.Substring(0, fileName.IndexOf('/'));
                    fileName    = fileName.Substring(fileName.IndexOf('/') + 1);
                }
                if (folderPath.StartsWith("/"))
                {
                    folderPath = folderPath.Substring(1);
                }

                // New file.
                File f = new File();

                f.Name = fileName;
                f.Id   = fileId;
                f.Data = new GenericFile()
                {
                    Data = ReadFile(filePath)
                };

                // Finally add the file to the folder.
                AddFileToFolder(f, folderPath);
            }

            // Add a file to a folder.
            void AddFileToFolder(File f, string folderPath)
            {
                // First check if the folder exists.
                if (!folders.ContainsKey(folderPath))
                {
                    AppendFolder(folderPath);
                }

                // Add the file to the folder.
                folders[folderPath].Files.Add(f);
            }

            // Append a folder.
            void AppendFolder(string folderPath)
            {
                string folderName     = folderPath;
                string baseFolderPath = "";

                while (folderName.Contains('/'))
                {
                    baseFolderPath += "/" + folderName.Substring(0, folderName.IndexOf('/'));
                    folderName      = folderName.Substring(folderName.IndexOf('/') + 1);
                }
                if (baseFolderPath.StartsWith("/"))
                {
                    baseFolderPath = baseFolderPath.Substring(1);
                }
                if (!folders.ContainsKey(baseFolderPath))
                {
                    AppendFolder(baseFolderPath);
                }
                Folder f = new Folder()
                {
                    Id = currFolderId++, Name = folderName
                };

                folders[baseFolderPath].Folders.Add(f);
                folders.Add(folderPath, f);
            }

            // Fix first file IDs.
            foreach (var f in folders.Values)
            {
                // f.Files = f.Files.OrderBy(x => x.Name).ToList(); = I don't think this should be done.
                if (f.Files.Count > 0)
                {
                    f.FirstFileId = f.Files.OrderBy(x => x.Id).ElementAt(0).Id;
                }
            }

            // Fix folders with no files.
            void FixFolders(Folder f)
            {
                foreach (var folder in f.Folders)
                {
                    FixFolders(folder);
                }
                if (f.Files.Count == 0)
                {
                    f.FirstFileId = f.Folders[0].FirstFileId;
                }
            }

            FixFolders(folders[""]);
        }