Skip to content

Commit e12e3fe

Browse files
authored
feat: add StringReference.GetValue/GetRaw (Python parity) (#34)
Closes HIGH convenience gap #4. Python's StringReference exposes .value (decoded text) and .raw (bytes) (binaryview.py:510/:514); the C# StringReference is a handle-less Type/Start/Length carrier, so callers had to separately ReadData(Start, Length) and hand-decode per StringType. Add durable GetValue(this StringReference, BinaryView) and GetRaw(this StringReference, BinaryView) extension methods with a StringType -> Encoding table mirroring Python's _decodings (Ascii->ASCII, Utf8->UTF8, Utf16->Unicode/UTF-16LE, Utf32->UTF32LE). GetValue decodes with .NET's default replacement fallback, the equivalent of Python errors='replace'. The view is a parameter because StringReference does not own one (unlike Python); extending its shape would force a FromNative signature change threaded through the TakeStructArray pipelines, so composition-only extensions are cleaner.
1 parent 6ab8a80 commit e12e3fe

1 file changed

Lines changed: 51 additions & 0 deletions

File tree

‎NavigationExtensions.cs‎

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Collections.Generic;
33
using System.Runtime.InteropServices;
4+
using System.Text;
45

56
namespace BinaryNinja
67
{
@@ -635,6 +636,56 @@ public static bool Contains(this BinaryView view, ulong address)
635636
};
636637
}
637638

639+
// Maps each StringType to the .NET encoding Python's StringReference._decodings uses
640+
// (binaryview.py:491): Ascii->ascii, Utf8->utf-8, Utf16->utf-16, Utf32->utf-32. UTF-16 LE
641+
// is Encoding.Unicode and UTF-32 LE is Encoding.UTF32 on all platforms Binary Ninja runs on.
642+
private static readonly Dictionary<StringType, Encoding> s_stringDecodings =
643+
new Dictionary<StringType, Encoding>
644+
{
645+
{ StringType.AsciiString, Encoding.ASCII },
646+
{ StringType.Utf8String, Encoding.UTF8 },
647+
{ StringType.Utf16String, Encoding.Unicode },
648+
{ StringType.Utf32String, Encoding.UTF32 },
649+
};
650+
651+
/// <summary>
652+
/// The raw bytes of this string reference, mirroring Python <c>StringReference.raw</c>
653+
/// (binaryview.py:514): reads <see cref="StringReference.Length"/> bytes at
654+
/// <see cref="StringReference.Start"/> from <paramref name="view"/>. The view is taken as a
655+
/// parameter because <see cref="StringReference"/> is a handle-less value carrier and does
656+
/// not own one (unlike Python, where the reference stores the view).
657+
/// </summary>
658+
public static byte[] GetRaw(this StringReference stringReference, BinaryView view)
659+
{
660+
if (null == view)
661+
{
662+
throw new ArgumentNullException(nameof(view));
663+
}
664+
665+
return view.ReadData(stringReference.Start, stringReference.Length);
666+
}
667+
668+
/// <summary>
669+
/// The decoded text of this string reference, mirroring Python <c>StringReference.value</c>
670+
/// (binaryview.py:510): reads the bytes via <see cref="GetRaw"/> and decodes them according
671+
/// to <see cref="StringReference.Type"/>. Undecodable bytes are replaced rather than
672+
/// thrown, matching Python <c>errors='replace'</c>.
673+
/// </summary>
674+
public static string GetValue(this StringReference stringReference, BinaryView view)
675+
{
676+
byte[] raw = GetRaw(stringReference, view);
677+
678+
// Fall back to ASCII for an unexpected StringType, matching Python's dict lookup
679+
// semantics as closely as possible (Python would KeyError; the binding degrades
680+
// gracefully because the type is an open enum).
681+
s_stringDecodings.TryGetValue(stringReference.Type, out Encoding? foundEncoding);
682+
Encoding encoding = foundEncoding ?? Encoding.ASCII;
683+
684+
// .NET's default decoders use replacement fallback (U+FFFD / '?'), which is the
685+
// equivalent of Python errors='replace'.
686+
return encoding.GetString(raw);
687+
}
688+
638689
/// <summary>
639690
/// Every disassembly instruction line across the whole view, in
640691
/// view-block-then-instruction order. Mirrors Python <c>BinaryView.instructions</c>

0 commit comments

Comments
 (0)