public void TestStringExtraction() { var source = new byte[] { // from map select 0x36, 0x37, 0x3A, 0x8D, 0x8E, 0xD6, 0x8E, 0xB3, 0x8E, 0xBE, 0x8E, 0xB2, 0x8E, 0xC9, 0x8E, 0xB7, 0x8E, 0xC9, 0x20, 0x8C, 0x8E, 0xC0, 0x8E, 0xDE, 0x8E, 0xDD, 0x8E, 0xBC, 0x8E, 0xDE, 0x8E, 0xAE, 0x8E, 0xDD, 0x20, 0x8E, 0xCE, 0x8E, 0xDE, 0x8E, 0xBD, 0x00, 0x00, 0x00, 0x36, 0x38, 0x3A, 0x8C, 0x8E, 0xC4, 0x8E, 0xDE, 0x8E, 0xC4, 0x8E, 0xDE, 0x8E, 0xDD, 0x8E, 0xBA, 0x8E, 0xDE, 0x20, 0x8E, 0xC0, 0x8E, 0xDE, 0x8E, 0xDD, 0x8E, 0xBC, 0x8E, 0xDE, 0x8E, 0xAE, 0x8E, 0xDD, 0x00, 0x00, 0x00, 0x36, 0x39, 0x3A, 0x8C, 0x8E, 0xC4, 0x8E, 0xDE, 0x8E, 0xC4, 0x8E, 0xDE, 0x8E, 0xDD, 0x8E, 0xBA, 0x8E, 0xDE, 0x20, 0x8E, 0xC0, 0x8E, 0xDE, 0x8E, 0xDD, 0x8E, 0xBC, 0x8E, 0xDE, 0x8E, 0xAE, 0x8E, 0xDD, 0x20, 0x8E, 0xCE, 0x8E, 0xDE, 0x8E, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x37, 0x30, 0x3A, 0x8D, 0x8E, 0xB7, 0x8E, 0xAE, 0x8E, 0xC0, 0x8E, 0xDE, 0x8E, 0xB2, 0x8E, 0xB7, 0x8E, 0xDE, 0x8E, 0xAE, 0x20, 0x8C, 0x8E, 0xC0, 0x8E, 0xDE, 0x8E, 0xDD, 0x8E, 0xBC, 0x8E, 0xDE, 0x8E, 0xAE, 0x8E, 0xDD, 0x00, 0x00, 0x00, 0x00, 0x37, 0x31, 0x3A, 0x8D, 0x8E, 0xB7, 0x8E, 0xAE, 0x8E, 0xC0, 0x8E, 0xDE, 0x8E, 0xB2, 0x8E, 0xB7, 0x8E, 0xDE, 0x8E, 0xAE, 0x20, 0x8C, 0x8E, 0xC0, 0x8E, 0xDE, 0x8E, 0xDD, 0x8E, 0xBC, 0x8E, 0xDE, 0x8E, 0xAE, 0x8E, 0xDD, 0x20, 0x8E, 0xCE, 0x8E, 0xDE, 0x8E, 0xBD, 0x00, // from code 0xA5, 0xD5, 0xA5, 0xA9, 0xA5, 0xEB, 0xA5, 0xC8, 0xA5, 0xDE, 0xA5, 0xCD, 0xA1, 0xBC, 0xA5, 0xB8, 0xA5, 0xE3, 0x3A, 0xC9, 0xD4, 0xCC, 0xC0, 0xA4, 0xCA, 0xA5, 0xE1, 0xA5, 0xC3, 0xA5, 0xBB, 0xA1, 0xBC, 0xA5, 0xB8, 0xA4, 0xF2, 0xBC, 0xF5, 0xBF, 0xAE, 0xA4, 0xB7, 0xA4, 0xDE, 0xA4, 0xB7, 0xA4, 0xBF, 0x0A, 0x00, }; var results = EucJp.ExtractEucJpStrings(source, EucJp.AsciiColorCode, EucJp.UnknownExtraChars) .ToArray(); Assert.AreEqual("67:ヨウセイノキノ ダンジョン ボス", results[0].String); Assert.AreEqual("68:ドドンゴ ダンジョン", results[1].String); Assert.AreEqual("69:ドドンゴ ダンジョン ボス", results[2].String); Assert.AreEqual("70:キョダイギョ ダンジョン", results[3].String); Assert.AreEqual("71:キョダイギョ ダンジョン ボス", results[4].String); Assert.AreEqual("フォルトマネージャ:不明なメッセージを受信しました\n", results[5].String); Assert.IsTrue(results.All(x => x.ContainsEucJpCharacters)); }
static void MainReal(string[] args) { Console.OutputEncoding = Encoding.UTF8; var extra = _operatingModes.Parse(args); switch (_mode) { case Mode.ShowHelp: Console.Error.WriteLine( typeof(Program) .GetFields(BindingFlags.NonPublic | BindingFlags.Static) .Where(f => f.FieldType == typeof(OptionSet)) .Select(f => f.GetValue(null) as OptionSet) .Select(x => { var ms = new MemoryStream(); using (var sw = new StreamWriter(ms)) x.WriteOptionDescriptions(sw); return(Encoding.UTF8.GetString(ms.ToArray())); }) .Join(Environment.NewLine.Dup(3)) ); break; case Mode.Signatures: { var files = _signatureOptions.Parse(extra); var sigs = new SignatureDatabase(SignaturesOptions.DatabasePath); var action = SignaturesOptions.SlowMode ? new Func <IEnumerable <InstructionWithPc>, IReadOnlyList <SignatureMatch> >(sigs.IdentifySlow) : (x => sigs.Identify(x, SignaturesOptions.Verify)); var results = files .Select(f => action( SignaturesOptions.MemDump ? File.ReadAllBytes(f).ToInstructions().WithPc(0x80000000) : new Rom(f).GetExecutable() )) .First(); if (!SignaturesOptions.ShortMode) { Console.WriteLine(JsonConvert.SerializeObject( !SignaturesOptions.UseHexAddrs ? (results as object) : results .Select(x => new { Start = string.Format("{0:X8}", x.Start), x.Size, Matches = x.Matches.Select(y => new { y.Name, Symbols = y.Symbols .Select(z => new { Key = string.Format("{0:X8}", z.Key), z.Value }) .ToDictionary(a => a.Key, a => a.Value) }) }), SignaturesOptions.IndentJson ? Formatting.Indented : Formatting.None )); } else { Console.WriteLine( string.Join( Environment.NewLine, results .ToShortForm(SignaturesOptions.ShowAll) .Select(g => string.Format("0x{0:x8},{1}", g.Key, string.Join("|", g.Value))) ) ); } } break; case Mode.ImportSignatures: var arFiles = _importSignatureOptions.Parse(extra); var stats = SignatureDatabase.ImportArchiveToDatabase( SignaturesOptions.DatabasePath, SignaturesOptions.CleanDatabase, arFiles.ToArray() ); Console.Error.WriteLine("{0} imported, {1} variants already present, {2} archives already present", stats.CountImported, stats.CountExisting, stats.ArchivesExisting); break; case Mode.Zelda64: { var files = _zelda64Modes.Parse(extra); switch (_zeldaMode) { case ZeldaMode.Extract: MainExtract(files.ToArray()); break; case ZeldaMode.DisassembleOverlay: MainDis(files.ToArray()); break; case ZeldaMode.DisassembleAllOverlays: var rom = new Rom(files[0]); var zrom = new Z64Rom(rom); foreach (var o in zrom.Overlays) { var p = o.File.Name; var ovl = new Overlay(o.VmaStart, o.File.Contents, _overlayOptions); Directory.CreateDirectory(p); File.WriteAllLines( Path.Combine(p, $"{o.File.Name}.S"), ovl.Disassemble(DisassemblyOptions.DebugPc) ); File.WriteAllText( Path.Combine(p, "conf.ld"), ovl.LinkerScript ); File.WriteAllText( Path.Combine(p, "Makefile"), OverlayCreator.GenerateMakefileForOvl(AppContext.BaseDirectory, o.File.Name, o.VmaStart) ); File.WriteAllBytes( Path.Combine(p, $"{o.File.Name}.ovl.orig"), o.File.Contents.ToArray() ); } break; case ZeldaMode.GenerateOverlayRelocs: Console.WriteLine( OverlayCreator.CreateCSourceFromOverlayRelocations( "__relocations", OverlayCreator.GetOverlayRelocationsFromElf(File.ReadAllBytes(files[0])) ) ); break; case ZeldaMode.DumpRelocations: Console.WriteLine( string.Join( Environment.NewLine, new[] { "ID Sec. loc Abs. addr Sym value Type Section Disassembly", //" 0 [0x0000001C/0x808FDEAC] (0x8090EE50) R_MIPS_HI16 .text lui $at,0x8091" }.Concat( LoadOverlay(files) .Relocations .Select((x, i) => string.Format("{0,5} {1}", i, x)) ) ) ); break; } } break; case Mode.EucJpStrings: { var files = _eucJpOptions.Parse(extra); var data = files .Select(x => new { x, data = File.ReadAllBytes(x) }) .Select(x => new { x.x, strings = EucJp.ExtractEucJpStrings(x.data, EucJp.AsciiColorCode, EucJp.UnknownExtraChars) .Where(y => !EucJpOptions.MinStringLength.HasValue || y.String.Length >= EucJpOptions.MinStringLength.Value) .Where(y => !EucJpOptions.OnlyForeign || y.ContainsEucJpCharacters) .Select(y => y.String) }); if (!EucJpOptions.Json) { foreach (var x in data.Select(y => y.strings)) { Console.WriteLine(x); } } else { Console.WriteLine( JsonConvert.SerializeObject( data.Select(x => new { Filename = x.x, Strings = x.strings }), Formatting.Indented ) ); } } break; case Mode.AsmPatch: { _asmPatchOptions.Parse(extra); var assembled = BuildAsmPatch(); if (!AsmPatchOptions.Gameshark) { byte[] input = ApplyAssembledInstructionsToRom( assembled, AsmPatchOptions.InputRom, AsmPatchOptions.OutputRom ); DumpAssembledValues(assembled); Console.Error.WriteLine("Patched {0} bytes.", assembled.Length * 4); if (string.IsNullOrWhiteSpace(AsmPatchOptions.BsdiffPath)) { break; } using (var patchOutput = File.OpenWrite(AsmPatchOptions.BsdiffPath)) deltaq.BsDiff.BsDiff.Create(File.ReadAllBytes(AsmPatchOptions.InputRom), input, patchOutput); Console.Error.WriteLine("`{0}` of size {1} bytes created.", AsmPatchOptions.BsdiffPath, new FileInfo(AsmPatchOptions.BsdiffPath).Length); } else { var codes = assembled .SelectMany(x => new[]