diff --git a/NavigationExtensions.cs b/NavigationExtensions.cs index 563792e..4563a28 100644 --- a/NavigationExtensions.cs +++ b/NavigationExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Runtime.InteropServices; +using System.Text; namespace BinaryNinja { @@ -635,6 +636,56 @@ public static bool Contains(this BinaryView view, ulong address) }; } + // Maps each StringType to the .NET encoding Python's StringReference._decodings uses + // (binaryview.py:491): Ascii->ascii, Utf8->utf-8, Utf16->utf-16, Utf32->utf-32. UTF-16 LE + // is Encoding.Unicode and UTF-32 LE is Encoding.UTF32 on all platforms Binary Ninja runs on. + private static readonly Dictionary s_stringDecodings = + new Dictionary + { + { StringType.AsciiString, Encoding.ASCII }, + { StringType.Utf8String, Encoding.UTF8 }, + { StringType.Utf16String, Encoding.Unicode }, + { StringType.Utf32String, Encoding.UTF32 }, + }; + + /// + /// The raw bytes of this string reference, mirroring Python StringReference.raw + /// (binaryview.py:514): reads bytes at + /// from . The view is taken as a + /// parameter because is a handle-less value carrier and does + /// not own one (unlike Python, where the reference stores the view). + /// + public static byte[] GetRaw(this StringReference stringReference, BinaryView view) + { + if (null == view) + { + throw new ArgumentNullException(nameof(view)); + } + + return view.ReadData(stringReference.Start, stringReference.Length); + } + + /// + /// The decoded text of this string reference, mirroring Python StringReference.value + /// (binaryview.py:510): reads the bytes via and decodes them according + /// to . Undecodable bytes are replaced rather than + /// thrown, matching Python errors='replace'. + /// + public static string GetValue(this StringReference stringReference, BinaryView view) + { + byte[] raw = GetRaw(stringReference, view); + + // Fall back to ASCII for an unexpected StringType, matching Python's dict lookup + // semantics as closely as possible (Python would KeyError; the binding degrades + // gracefully because the type is an open enum). + s_stringDecodings.TryGetValue(stringReference.Type, out Encoding? foundEncoding); + Encoding encoding = foundEncoding ?? Encoding.ASCII; + + // .NET's default decoders use replacement fallback (U+FFFD / '?'), which is the + // equivalent of Python errors='replace'. + return encoding.GetString(raw); + } + /// /// Every disassembly instruction line across the whole view, in /// view-block-then-instruction order. Mirrors Python BinaryView.instructions