using System; using System.Diagnostics.Contracts; using System.Drawing; using ReClassNET.Controls; using ReClassNET.Extensions; using ReClassNET.Memory; using ReClassNET.UI; using ReClassNET.Util; namespace ReClassNET.Nodes { public class BitFieldNode : BaseNode { private int size; private int bits; /// Gets or sets the bit count. /// Possible values: 64, 32, 16, 8 public int Bits { get => bits; set { Contract.Ensures(bits > 0); Contract.Ensures(size > 0); if (value >= 64) { bits = 64; } else if (value >= 32) { bits = 32; } else if (value >= 16) { bits = 16; } else { bits = 8; } size = bits / 8; } } public override int MemorySize => size; public BitFieldNode() { Bits = IntPtr.Size * 8; LevelsOpen.DefaultValue = true; } public override void GetUserInterfaceInfo(out string name, out Image icon) { name = "Bitfield"; icon = Properties.Resources.B16x16_Button_Bits; } public override void CopyFromNode(BaseNode node) { base.CopyFromNode(node); Bits = node.MemorySize * 8; } /// /// Gets the underlaying node for the bit field. /// /// public BaseNumericNode GetUnderlayingNode() { switch (Bits) { case 8: return new UInt8Node(); case 16: return new UInt16Node(); case 32: return new UInt32Node(); case 64: return new UInt64Node(); } throw new Exception(); // TODO } /// Converts the memory value to a bit string. /// The process memory. /// The value converted to a bit string. private string ConvertValueToBitString(MemoryBuffer memory) { Contract.Requires(memory != null); Contract.Ensures(Contract.Result() != null); switch(bits) { case 64: return BitString.ToString(memory.ReadInt64(Offset)); case 32: return BitString.ToString(memory.ReadInt32(Offset)); case 16: return BitString.ToString(memory.ReadInt16(Offset)); default: return BitString.ToString(memory.ReadUInt8(Offset)); } } public override Size Draw(DrawContext context, int x, int y) { const int BitsPerBlock = 4; if (IsHidden && !IsWrapped) { return DrawHidden(context, x, y); } var origX = x; var origY = y; AddSelection(context, x, y, context.Font.Height); x = AddIconPadding(context, x); x = AddIconPadding(context, x); x = AddAddressOffset(context, x, y); x = AddText(context, x, y, context.Settings.TypeColor, HotSpot.NoneId, "Bits") + context.Font.Width; if (!IsWrapped) { x = AddText(context, x, y, context.Settings.NameColor, HotSpot.NameId, Name) + context.Font.Width; } x = AddOpenCloseIcon(context, x, y) + context.Font.Width; var tx = x - 3; for (var i = 0; i < bits; ++i) { var rect = new Rectangle(x + (i + i / BitsPerBlock) * context.Font.Width, y, context.Font.Width, context.Font.Height); AddHotSpot(context, rect, string.Empty, i, HotSpotType.Edit); } var value = ConvertValueToBitString(context.Memory); x = AddText(context, x, y, context.Settings.ValueColor, HotSpot.NoneId, value) + context.Font.Width; x += context.Font.Width; x = AddComment(context, x, y); DrawInvalidMemoryIndicatorIcon(context, y); AddContextDropDownIcon(context, y); AddDeleteIcon(context, y); if (LevelsOpen[context.Level]) { y += context.Font.Height; var format = new StringFormat(StringFormatFlags.DirectionVertical); using (var brush = new SolidBrush(context.Settings.ValueColor)) { var maxCharCount = bits + (bits / 4 - 1) - 1; for (int bitCount = 0, padding = 0; bitCount < bits; bitCount += 4, padding += 5) { context.Graphics.DrawString(bitCount.ToString(), context.Font.Font, brush, tx + (maxCharCount - padding) * context.Font.Width, y, format); } } y += 8; } return new Size(x - origX, y - origY + context.Font.Height); } public override int CalculateDrawnHeight(DrawContext context) { if (IsHidden && !IsWrapped) { return HiddenHeight; } var height = context.Font.Height; if (LevelsOpen[context.Level]) { height += context.Font.Height + 8; } return height; } public override void Update(HotSpot spot) { base.Update(spot); if (spot.Id >= 0 && spot.Id < bits) { if (spot.Text == "1" || spot.Text == "0") { var bit = bits - 1 - spot.Id; var add = bit / 8; bit = bit % 8; var val = spot.Memory.ReadUInt8(Offset + add); if (spot.Text == "1") { val |= (byte)(1 << bit); } else { val &= (byte)~(1 << bit); } spot.Process.WriteRemoteMemory(spot.Address + add, val); } } } } }