static void Dump(FamicomDumperConnection dumper, string fileName, string mapperName, int prgSize, int chrSize, string unifName, string unifAuthor)
        {
            var mapper = GetMapper(mapperName);

            if (mapper.Number >= 0)
            {
                Console.WriteLine("Using mapper: #{0} ({1})", mapper.Number, mapper.Name);
            }
            else
            {
                Console.WriteLine("Using mapper: {0}", mapper.Name);
            }
            Console.WriteLine("Dumping...");
            List <byte> prg = new List <byte>();
            List <byte> chr = new List <byte>();

            prgSize = prgSize >= 0 ? prgSize : mapper.DefaultPrgSize;
            chrSize = chrSize >= 0 ? chrSize : mapper.DefaultChrSize;
            Console.WriteLine("PRG memory size: {0}K", prgSize / 1024);
            mapper.DumpPrg(dumper, prg, prgSize);
            while (prg.Count % 0x4000 != 0)
            {
                prg.Add(0);
            }
            Console.WriteLine("CHR memory size: {0}K", chrSize / 1024);
            mapper.DumpChr(dumper, chr, chrSize);
            while (chr.Count % 0x2000 != 0)
            {
                chr.Add(0);
            }
            byte[] mirroringRaw             = dumper.GetMirroring();
            NesFile.MirroringType mirroring = NesFile.MirroringType.Unknown_none;
            if (mirroringRaw.Length == 1)
            {
                mirroring = (NesFile.MirroringType)mirroringRaw[0];
                Console.WriteLine("Mirroring: " + mirroring);
            }
            else if (mirroringRaw.Length == 4)
            {
                switch (string.Format("{0:X2}{1:X2}{2:X2}{3:X2}", mirroringRaw[0], mirroringRaw[1], mirroringRaw[2], mirroringRaw[3]))
                {
                case "00000101":
                    mirroring = NesFile.MirroringType.Horizontal;     // Horizontal
                    break;

                case "00010001":
                    mirroring = NesFile.MirroringType.Vertical;     // Vertical
                    break;

                case "00000000":
                    mirroring = NesFile.MirroringType.OneScreenA;     // One-screen A
                    break;

                case "01010101":
                    mirroring = NesFile.MirroringType.OneScreenB;     // One-screen B
                    break;

                default:
                    mirroring = NesFile.MirroringType.Unknown_none;     // Unknown
                    break;
                }
                Console.WriteLine("Mirroring: {0} ({1:X2} {2:X2} {3:X2} {4:X2})", mirroring, mirroringRaw[0], mirroringRaw[1], mirroringRaw[2], mirroringRaw[3]);
            }
            Console.WriteLine("Saving to {0}...", fileName);
            if (mapper.Number >= 0)
            {
                var nesFile = new NesFile();
                nesFile.Mapper    = (byte)mapper.Number;
                nesFile.Mirroring = mirroring;
                nesFile.TvSystem  = NesFile.TvSystemType.Ntsc;
                nesFile.PRG       = prg.ToArray();
                nesFile.CHR       = chr.ToArray();
                nesFile.Save(fileName);
            }
            else
            {
                var unifFile = new UnifFile();
                unifFile.Version = 4;
                unifFile.Mapper  = mapper.UnifName;
                if (unifName != null)
                {
                    unifFile.Fields["NAME"] = UnifFile.StringToUTF8N(unifName);
                }
                unifFile.Fields["PRG0"] = prg.ToArray();
                if (chr.Count > 0)
                {
                    unifFile.Fields["CHR0"] = chr.ToArray();
                }
                unifFile.Fields["MIRR"] = new byte[] { 5 }; // mapper controlled
                unifFile.Save(fileName, unifAuthor);
            }
        }