Exemplo n.º 1
0
        public void Save(Stream output, IList <IArchiveFileInfo> files)
        {
            using var bw = new BinaryWriterX(output);

            // Calculate offsets
            var fatOffset = NarcHeaderSize;
            var fntOffset = fatOffset + FatHeaderSize + files.Count * FatEntrySize;

            // Write FNT
            int fntSize;

            if (!_hasNames)
            {
                output.Position = fntOffset + 8;
                bw.Write(4);
                bw.Write(0x10000);
                fntSize = 0x10;
            }
            else
            {
                NdsSupport.WriteFnt(bw, fntOffset + 8, files);
                fntSize = (int)(bw.BaseStream.Position - fntOffset);
            }

            output.Position = fntOffset;
            bw.WriteType(new NarcFntHeader
            {
                chunkSize = fntSize
            });

            // Write GMIF
            var fatEntries = new List <FatEntry>();

            var gmifOffset = fntOffset + fntSize;

            output.Position = gmifOffset + 8;
            foreach (var file in files.Cast <FileIdArchiveFileInfo>().OrderBy(x => x.FileId))
            {
                var filePosition = output.Position;
                var writtenSize  = file.SaveFileData(output);

                fatEntries.Add(new FatEntry
                {
                    offset    = (int)filePosition - gmifOffset - 8,
                    endOffset = (int)(filePosition - gmifOffset - 8 + writtenSize)
                });
            }

            output.Position = gmifOffset;
            bw.WriteString("GMIF", Encoding.ASCII, false, false);
            bw.Write((int)(output.Length - gmifOffset));

            // Write FAT
            output.Position = fatOffset;
            bw.WriteType(new NarcFatHeader
            {
                chunkSize = FatHeaderSize + files.Count * FatEntrySize,
                fileCount = (short)files.Count
            });
            bw.WriteMultiple(fatEntries);

            // Write header
            output.Position = 0;
            bw.WriteType(new NarcHeader
            {
                fileSize = (int)output.Length
            });
        }
Exemplo n.º 2
0
        public void Save(Stream output, IList <IArchiveFileInfo> files)
        {
            var arm9File = (ArchiveFileInfo)files.First(x => x.FilePath.ToRelative() == Path.Combine("sys", "arm9.bin"));
            var arm7File = (ArchiveFileInfo)files.First(x => x.FilePath.ToRelative() == Path.Combine("sys", "arm7.bin"));
            var iconFile = (ArchiveFileInfo)files.FirstOrDefault(x => x.FilePath.ToRelative() == Path.Combine("sys", "banner.bin"));

            var arm9Overlays = files.Where(x => x.FilePath.ToRelative().IsInDirectory(Path.Combine("sys", "ovl"), false) &&
                                           x.FilePath.GetName().StartsWith("overlay9"))
                               .Cast <OverlayArchiveFileInfo>().ToArray();
            var arm7Overlays = files.Where(x => x.FilePath.ToRelative().IsInDirectory(Path.Combine("sys", "ovl"), false) &&
                                           x.FilePath.GetName().StartsWith("overlay7"))
                               .Cast <OverlayArchiveFileInfo>().ToArray();

            var arm9OverlayEntries = new List <OverlayEntry>();
            var arm7OverlayEntries = new List <OverlayEntry>();
            var fatEntries         = new List <FatEntry>();

            using var bw = new BinaryWriterX(output, true);

            // Write ARM9
            var arm9Offset = output.Position = 0x4000;
            var arm9Size   = arm9File.SaveFileData(output);

            if (_arm9Footer != null)
            {
                bw.WriteType(_arm9Footer);
            }
            bw.WriteAlignment(0x200, 0xFF);

            // Write ARM9 Overlays
            var arm9OverlayOffset   = output.Position;
            var arm9OverlaySize     = arm9Overlays.Length * OverlayEntrySize;
            var arm9OverlayPosition = (arm9OverlayOffset + arm9OverlaySize + 0x1FF) & ~0x1FF;

            foreach (var arm9Overlay in arm9Overlays.OrderBy(x => x.Entry.id))
            {
                output.Position = arm9OverlayPosition;
                var writtenSize = arm9Overlay.SaveFileData(output);
                bw.WriteAlignment(0x200, 0xFF);

                arm9Overlay.Entry.fileId = fatEntries.Count;
                arm9OverlayEntries.Add(arm9Overlay.Entry);

                fatEntries.Add(new FatEntry
                {
                    offset    = (int)arm9OverlayPosition,
                    endOffset = (int)(arm9OverlayPosition + writtenSize)
                });

                arm9OverlayPosition += (writtenSize + 0x1FF) & ~0x1FF;
            }

            output.Position = arm9OverlayOffset;
            bw.WriteMultiple(arm9OverlayEntries);
            bw.WriteAlignment(0x200, 0xFF);
            output.Position = arm9OverlayPosition;

            // Write ARM7
            var arm7Offset = output.Position = arm9OverlayPosition;
            var arm7Size   = arm7File.SaveFileData(output);

            // Write ARM7 Overlays
            var arm7OverlayOffset   = output.Position = arm7Offset + arm7Size;
            var arm7OverlaySize     = arm7Overlays.Length * OverlayEntrySize;
            var arm7OverlayPosition = (arm7OverlayOffset + arm7OverlaySize + 0x1FF) & ~0x1FF;

            foreach (var arm7Overlay in arm7Overlays)
            {
                output.Position = arm7OverlayPosition;
                var writtenSize = arm7Overlay.SaveFileData(output);
                bw.WriteAlignment(0x200, 0xFF);

                arm7Overlay.Entry.fileId = fatEntries.Count;
                arm7OverlayEntries.Add(arm7Overlay.Entry);

                fatEntries.Add(new FatEntry
                {
                    offset    = (int)arm7OverlayPosition,
                    endOffset = (int)(arm7OverlayPosition + writtenSize)
                });

                arm7OverlayPosition += (writtenSize + 0x1FF) & ~0x1FF;
            }

            output.Position = arm7OverlayOffset;
            bw.WriteMultiple(arm7OverlayEntries);
            bw.WriteAlignment(0x200, 0xFF);
            output.Position = arm7OverlayPosition;

            // Write FAT and FNT
            var romFiles = files.Where(x => !x.FilePath.ToRelative().IsInDirectory(Path.Combine("sys"), true)).ToArray();

            // Write FNT
            var fntOffset = arm7OverlayPosition;

            NdsSupport.WriteFnt(bw, (int)fntOffset, romFiles, arm9Overlays.Length + arm7Overlays.Length);

            var fntSize = bw.BaseStream.Position - fntOffset;

            bw.WriteAlignment(0x200, 0xFF);

            var fatOffset = bw.BaseStream.Position;
            var fatSize   = (files.Count - 3) * FatEntrySize;   // Not counting arm9.bin, arm7.bin, banner.bin

            // Write icon
            var iconOffset = (fatOffset + fatSize + 0x1FF) & ~0x1FF;
            var iconSize   = 0;

            if (iconFile != null)
            {
                output.Position = iconOffset;
                iconSize        = (int)iconFile.SaveFileData(output);

                bw.WriteAlignment(0x200, 0xFF);
            }

            // Write rom files
            var filePosition = (iconOffset + iconSize + 0x1FF) & ~0x1FF;

            foreach (var romFile in romFiles.Cast <FileIdArchiveFileInfo>().OrderBy(x => x.FileId))
            {
                output.Position = filePosition;

                var romFileSize = romFile.SaveFileData(output);

                fatEntries.Add(new FatEntry
                {
                    offset    = (int)filePosition,
                    endOffset = (int)(filePosition + romFileSize)
                });

                filePosition += (romFileSize + 0x1FF) & ~0x1FF;
            }

            // Write FAT
            bw.BaseStream.Position = fatOffset;
            bw.WriteMultiple(fatEntries);
            bw.WriteAlignment(0x200, 0xFF);

            // Write header
            output.Position = 0;

            if (_ndsHeader != null)
            {
                _ndsHeader.arm9Offset        = (int)arm9Offset;
                _ndsHeader.arm7Offset        = (int)arm7Offset;
                _ndsHeader.arm9OverlayOffset = (int)(arm9Overlays.Length > 0 ? arm9OverlayOffset : 0);
                _ndsHeader.arm7OverlayOffset = (int)(arm7Overlays.Length > 0 ? arm7OverlayOffset : 0);
                _ndsHeader.fntOffset         = (int)fntOffset;
                _ndsHeader.fatOffset         = (int)fatOffset;
                _ndsHeader.iconOffset        = (int)iconOffset;

                _ndsHeader.arm9Size        = (int)arm9Size;
                _ndsHeader.arm7Size        = (int)arm7Size;
                _ndsHeader.arm9OverlaySize = (int)(arm9Overlays.Length > 0 ? arm9OverlaySize : 0);
                _ndsHeader.arm7OverlaySize = (int)(arm7Overlays.Length > 0 ? arm7OverlaySize : 0);
                _ndsHeader.fntSize         = (int)fntSize;
                _ndsHeader.fatSize         = (int)fatSize;

                bw.WriteType(_ndsHeader);
            }
            else
            {
                _dsiHeader.arm9Offset        = (int)arm9Offset;
                _dsiHeader.arm7Offset        = (int)arm7Offset;
                _dsiHeader.arm9OverlayOffset = (int)(arm9Overlays.Length > 0 ? arm9OverlayOffset : 0);
                _dsiHeader.arm7OverlayOffset = (int)(arm7Overlays.Length > 0 ? arm7OverlayOffset : 0);
                _dsiHeader.fntOffset         = (int)fntOffset;
                _dsiHeader.fatOffset         = (int)fatOffset;
                _dsiHeader.iconOffset        = (int)iconOffset;

                _dsiHeader.arm9Size                 = (int)arm9Size;
                _dsiHeader.arm7Size                 = (int)arm7Size;
                _dsiHeader.arm9OverlaySize          = (int)(arm9Overlays.Length > 0 ? arm9OverlaySize : 0);
                _dsiHeader.arm7OverlaySize          = (int)(arm7Overlays.Length > 0 ? arm7OverlaySize : 0);
                _dsiHeader.fntSize                  = (int)fntSize;
                _dsiHeader.fatSize                  = (int)fatSize;
                _dsiHeader.extendedEntries.iconSize = iconSize;

                bw.WriteType(_dsiHeader);
            }
        }