diff --git a/Form1.cs b/Form1.cs
index ed78f54..5b72e32 100644
--- a/Form1.cs
+++ b/Form1.cs
@@ -419,8 +419,6 @@ namespace NBTExplorer
_buttonDelete.Enabled = tag != null && node.Tag is TagNode;
_buttonEdit.Enabled = tag != null
&& node.Tag is TagNode
- && tag.GetTagType() != TagType.TAG_BYTE_ARRAY
- && tag.GetTagType() != TagType.TAG_INT_ARRAY
&& tag.GetTagType() != TagType.TAG_COMPOUND
&& tag.GetTagType() != TagType.TAG_LIST;
@@ -889,19 +887,35 @@ namespace NBTExplorer
if (tag == null)
return;
- if (tag.GetTagType() == TagType.TAG_BYTE_ARRAY ||
- tag.GetTagType() == TagType.TAG_LIST ||
+ if (tag.GetTagType() == TagType.TAG_LIST ||
tag.GetTagType() == TagType.TAG_COMPOUND)
return;
- EditValue form = new EditValue(tag);
- if (form.ShowDialog() == DialogResult.OK) {
- TreeNode baseNode = BaseNode(node);
- if (baseNode != null) {
- (baseNode.Tag as DataNode).Modified = true;
+ if (tag.GetTagType() == TagType.TAG_BYTE_ARRAY) {
+ HexEditor form = new HexEditor(GetTagNodeName(node), tag.ToTagByteArray().Data);
+ form.ShowDialog();
+ }
+ else if (tag.GetTagType() == TagType.TAG_INT_ARRAY) {
+ TagNodeIntArray iatag = tag.ToTagIntArray();
+ byte[] data = new byte[iatag.Length * 4];
+ for (int i = 0; i < iatag.Length; i++) {
+ byte[] buf = BitConverter.GetBytes(iatag.Data[i]);
+ Array.Copy(buf, 0, data, 4 * i, 4);
}
- node.Text = GetNodeText(node);
+ HexEditor form = new HexEditor(GetTagNodeName(node), data);
+ form.ShowDialog();
+ }
+ else {
+ EditValue form = new EditValue(tag);
+ if (form.ShowDialog() == DialogResult.OK) {
+ TreeNode baseNode = BaseNode(node);
+ if (baseNode != null) {
+ (baseNode.Tag as DataNode).Modified = true;
+ }
+
+ node.Text = GetNodeText(node);
+ }
}
}
diff --git a/HexEditor.Designer.cs b/HexEditor.Designer.cs
new file mode 100644
index 0000000..a3345ba
--- /dev/null
+++ b/HexEditor.Designer.cs
@@ -0,0 +1,106 @@
+namespace NBTExplorer
+{
+ partial class HexEditor
+ {
+ ///
+ /// Required designer variable.
+ ///
+ private System.ComponentModel.IContainer components = null;
+
+ ///
+ /// Clean up any resources being used.
+ ///
+ /// true if managed resources should be disposed; otherwise, false.
+ protected override void Dispose (bool disposing)
+ {
+ if (disposing && (components != null)) {
+ components.Dispose();
+ }
+ base.Dispose(disposing);
+ }
+
+ #region Windows Form Designer generated code
+
+ ///
+ /// Required method for Designer support - do not modify
+ /// the contents of this method with the code editor.
+ ///
+ private void InitializeComponent ()
+ {
+ this.hexBox1 = new Be.Windows.Forms.HexBox();
+ this.statusStrip1 = new System.Windows.Forms.StatusStrip();
+ this._curPositionLabel = new System.Windows.Forms.ToolStripStatusLabel();
+ this._buttonClose = new System.Windows.Forms.Button();
+ this.statusStrip1.SuspendLayout();
+ this.SuspendLayout();
+ //
+ // hexBox1
+ //
+ this.hexBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
+ | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.hexBox1.Font = new System.Drawing.Font("Courier New", 9F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
+ this.hexBox1.LineInfoForeColor = System.Drawing.Color.Empty;
+ this.hexBox1.LineInfoVisible = true;
+ this.hexBox1.Location = new System.Drawing.Point(12, 12);
+ this.hexBox1.Name = "hexBox1";
+ this.hexBox1.ReadOnly = true;
+ this.hexBox1.ShadowSelectionColor = System.Drawing.Color.FromArgb(((int)(((byte)(100)))), ((int)(((byte)(60)))), ((int)(((byte)(188)))), ((int)(((byte)(255)))));
+ this.hexBox1.Size = new System.Drawing.Size(492, 289);
+ this.hexBox1.TabIndex = 0;
+ this.hexBox1.VScrollBarVisible = true;
+ //
+ // statusStrip1
+ //
+ this.statusStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] {
+ this._curPositionLabel});
+ this.statusStrip1.Location = new System.Drawing.Point(0, 333);
+ this.statusStrip1.Name = "statusStrip1";
+ this.statusStrip1.Size = new System.Drawing.Size(516, 22);
+ this.statusStrip1.TabIndex = 1;
+ this.statusStrip1.Text = "statusStrip1";
+ //
+ // _curPositionLabel
+ //
+ this._curPositionLabel.AutoSize = false;
+ this._curPositionLabel.Name = "_curPositionLabel";
+ this._curPositionLabel.Size = new System.Drawing.Size(100, 17);
+ this._curPositionLabel.Text = "0000";
+ //
+ // _buttonClose
+ //
+ this._buttonClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
+ this._buttonClose.DialogResult = System.Windows.Forms.DialogResult.Cancel;
+ this._buttonClose.Location = new System.Drawing.Point(429, 307);
+ this._buttonClose.Name = "_buttonClose";
+ this._buttonClose.Size = new System.Drawing.Size(75, 23);
+ this._buttonClose.TabIndex = 2;
+ this._buttonClose.Text = "Close";
+ this._buttonClose.UseVisualStyleBackColor = true;
+ //
+ // HexEditor
+ //
+ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
+ this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ this.CancelButton = this._buttonClose;
+ this.ClientSize = new System.Drawing.Size(516, 355);
+ this.Controls.Add(this._buttonClose);
+ this.Controls.Add(this.statusStrip1);
+ this.Controls.Add(this.hexBox1);
+ this.Name = "HexEditor";
+ this.Text = "HexEditor";
+ this.statusStrip1.ResumeLayout(false);
+ this.statusStrip1.PerformLayout();
+ this.ResumeLayout(false);
+ this.PerformLayout();
+
+ }
+
+ #endregion
+
+ private Be.Windows.Forms.HexBox hexBox1;
+ private System.Windows.Forms.StatusStrip statusStrip1;
+ private System.Windows.Forms.ToolStripStatusLabel _curPositionLabel;
+ private System.Windows.Forms.Button _buttonClose;
+ }
+}
\ No newline at end of file
diff --git a/HexEditor.cs b/HexEditor.cs
new file mode 100644
index 0000000..50ec136
--- /dev/null
+++ b/HexEditor.cs
@@ -0,0 +1,49 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Text;
+using System.Windows.Forms;
+using Be.Windows.Forms;
+
+namespace NBTExplorer
+{
+ public partial class HexEditor : Form
+ {
+ public HexEditor (string tagName, byte[] data)
+ {
+ InitializeComponent();
+
+ this.Text = "Editing: " + tagName + " (Read Only)";
+
+ hexBox1.ByteProvider = new DynamicByteProvider(data);
+
+ hexBox1.HorizontalByteCountChanged += HexBox_HorizontalByteCountChanged;
+ hexBox1.CurrentLineChanged += HexBox_CurrentLineChanged;
+ hexBox1.CurrentPositionInLineChanged += HexBox_CurrentPositionInLineChanged;
+ }
+
+ private void HexBox_HorizontalByteCountChanged (object sender, EventArgs e)
+ {
+ UpdatePosition();
+ }
+
+ private void HexBox_CurrentLineChanged (object sender, EventArgs e)
+ {
+ UpdatePosition();
+ }
+
+ private void HexBox_CurrentPositionInLineChanged (object sender, EventArgs e)
+ {
+ UpdatePosition();
+ }
+
+ private void UpdatePosition ()
+ {
+ long pos = (hexBox1.CurrentLine - 1) * hexBox1.HorizontalByteCount + hexBox1.CurrentPositionInLine;
+
+ _curPositionLabel.Text = pos.ToString();
+ }
+ }
+}
diff --git a/HexEditor.resx b/HexEditor.resx
new file mode 100644
index 0000000..d26a846
--- /dev/null
+++ b/HexEditor.resx
@@ -0,0 +1,123 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
\ No newline at end of file
diff --git a/NBTExplorer.csproj b/NBTExplorer.csproj
index b76ba6c..8780080 100644
--- a/NBTExplorer.csproj
+++ b/NBTExplorer.csproj
@@ -43,8 +43,10 @@
..\Substrate\SubstrateCS\bin\Release\NET2\Substrate.dll
+
+
@@ -71,6 +73,12 @@
Form1.cs
+
+ Form
+
+
+ HexEditor.cs
+
@@ -86,6 +94,9 @@
Form1.cs
Designer
+
+ HexEditor.cs
+
ResXFileCodeGenerator
Resources.Designer.cs
@@ -101,6 +112,12 @@
+
+
+ {26C5F25F-B450-4CAF-AD8B-B8D11AE73457}
+ Be.Windows.Forms.HexBox
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ 17, 17
+
+
+ False
+
+
\ No newline at end of file
diff --git a/Vendor/Be.Windows.Forms.HexBox/HexBox.snk b/Vendor/Be.Windows.Forms.HexBox/HexBox.snk
new file mode 100644
index 0000000..8c59698
Binary files /dev/null and b/Vendor/Be.Windows.Forms.HexBox/HexBox.snk differ
diff --git a/Vendor/Be.Windows.Forms.HexBox/HexCasing.cs b/Vendor/Be.Windows.Forms.HexBox/HexCasing.cs
new file mode 100644
index 0000000..bf007ee
--- /dev/null
+++ b/Vendor/Be.Windows.Forms.HexBox/HexCasing.cs
@@ -0,0 +1,21 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Be.Windows.Forms
+{
+ ///
+ /// Specifies the case of hex characters in the HexBox control
+ ///
+ public enum HexCasing
+ {
+ ///
+ /// Converts all characters to uppercase.
+ ///
+ Upper = 0,
+ ///
+ /// Converts all characters to lowercase.
+ ///
+ Lower = 1
+ }
+}
diff --git a/Vendor/Be.Windows.Forms.HexBox/IByteProvider.cs b/Vendor/Be.Windows.Forms.HexBox/IByteProvider.cs
new file mode 100644
index 0000000..7847ae5
--- /dev/null
+++ b/Vendor/Be.Windows.Forms.HexBox/IByteProvider.cs
@@ -0,0 +1,75 @@
+using System;
+
+namespace Be.Windows.Forms
+{
+ ///
+ /// Defines a byte provider for HexBox control
+ ///
+ public interface IByteProvider
+ {
+ ///
+ /// Reads a byte from the provider
+ ///
+ /// the index of the byte to read
+ /// the byte to read
+ byte ReadByte(long index);
+ ///
+ /// Writes a byte into the provider
+ ///
+ /// the index of the byte to write
+ /// the byte to write
+ void WriteByte(long index, byte value);
+ ///
+ /// Inserts bytes into the provider
+ ///
+ ///
+ ///
+ /// This method must raise the LengthChanged event.
+ void InsertBytes(long index, byte[] bs);
+ ///
+ /// Deletes bytes from the provider
+ ///
+ /// the start index of the bytes to delete
+ /// the length of the bytes to delete
+ /// This method must raise the LengthChanged event.
+ void DeleteBytes(long index, long length);
+
+ ///
+ /// Returns the total length of bytes the byte provider is providing.
+ ///
+ long Length { get; }
+ ///
+ /// Occurs, when the Length property changed.
+ ///
+ event EventHandler LengthChanged;
+
+ ///
+ /// True, when changes are done.
+ ///
+ bool HasChanges();
+ ///
+ /// Applies changes.
+ ///
+ void ApplyChanges();
+ ///
+ /// Occurs, when bytes are changed.
+ ///
+ event EventHandler Changed;
+
+ ///
+ /// Returns a value if the WriteByte methods is supported by the provider.
+ ///
+ /// True, when it´s supported.
+ bool SupportsWriteByte();
+ ///
+ /// Returns a value if the InsertBytes methods is supported by the provider.
+ ///
+ /// True, when it´s supported.
+ bool SupportsInsertBytes();
+ ///
+ /// Returns a value if the DeleteBytes methods is supported by the provider.
+ ///
+ /// True, when it´s supported.
+ bool SupportsDeleteBytes();
+ }
+}
diff --git a/Vendor/Be.Windows.Forms.HexBox/MemoryDataBlock.cs b/Vendor/Be.Windows.Forms.HexBox/MemoryDataBlock.cs
new file mode 100644
index 0000000..9729267
--- /dev/null
+++ b/Vendor/Be.Windows.Forms.HexBox/MemoryDataBlock.cs
@@ -0,0 +1,87 @@
+using System;
+
+namespace Be.Windows.Forms
+{
+ internal sealed class MemoryDataBlock : DataBlock
+ {
+ byte[] _data;
+
+ public MemoryDataBlock(byte data)
+ {
+ _data = new byte[] { data };
+ }
+
+ public MemoryDataBlock(byte[] data)
+ {
+ if (data == null)
+ {
+ throw new ArgumentNullException("data");
+ }
+
+ _data = (byte[])data.Clone();
+ }
+
+ public override long Length
+ {
+ get
+ {
+ return _data.LongLength;
+ }
+ }
+
+ public byte[] Data
+ {
+ get
+ {
+ return _data;
+ }
+ }
+
+ public void AddByteToEnd(byte value)
+ {
+ byte[] newData = new byte[_data.LongLength + 1];
+ _data.CopyTo(newData, 0);
+ newData[newData.LongLength - 1] = value;
+ _data = newData;
+ }
+
+ public void AddByteToStart(byte value)
+ {
+ byte[] newData = new byte[_data.LongLength + 1];
+ newData[0] = value;
+ _data.CopyTo(newData, 1);
+ _data = newData;
+ }
+
+ public void InsertBytes(long position, byte[] data)
+ {
+ byte[] newData = new byte[_data.LongLength + data.LongLength];
+ if (position > 0)
+ {
+ Array.Copy(_data, 0, newData, 0, position);
+ }
+ Array.Copy(data, 0, newData, position, data.LongLength);
+ if (position < _data.LongLength)
+ {
+ Array.Copy(_data, position, newData, position + data.LongLength, _data.LongLength - position);
+ }
+ _data = newData;
+ }
+
+ public override void RemoveBytes(long position, long count)
+ {
+ byte[] newData = new byte[_data.LongLength - count];
+
+ if (position > 0)
+ {
+ Array.Copy(_data, 0, newData, 0, position);
+ }
+ if (position + count < _data.LongLength)
+ {
+ Array.Copy(_data, position + count, newData, position, newData.LongLength - position);
+ }
+
+ _data = newData;
+ }
+ }
+}
diff --git a/Vendor/Be.Windows.Forms.HexBox/NativeMethods.cs b/Vendor/Be.Windows.Forms.HexBox/NativeMethods.cs
new file mode 100644
index 0000000..e678da4
--- /dev/null
+++ b/Vendor/Be.Windows.Forms.HexBox/NativeMethods.cs
@@ -0,0 +1,27 @@
+using System;
+using System.Drawing;
+using System.Runtime.InteropServices;
+
+namespace Be.Windows.Forms
+{
+ internal static class NativeMethods
+ {
+ // Caret definitions
+ [DllImport("user32.dll", SetLastError=true)]
+ public static extern bool CreateCaret(IntPtr hWnd, IntPtr hBitmap, int nWidth, int nHeight);
+
+ [DllImport("user32.dll", SetLastError=true)]
+ public static extern bool ShowCaret(IntPtr hWnd);
+
+ [DllImport("user32.dll", SetLastError=true)]
+ public static extern bool DestroyCaret();
+
+ [DllImport("user32.dll", SetLastError=true)]
+ public static extern bool SetCaretPos(int X, int Y);
+
+ // Key definitions
+ public const int WM_KEYDOWN = 0x100;
+ public const int WM_KEYUP = 0x101;
+ public const int WM_CHAR = 0x102;
+ }
+}
diff --git a/Vendor/Be.Windows.Forms.HexBox/Properties/Resources.Designer.cs b/Vendor/Be.Windows.Forms.HexBox/Properties/Resources.Designer.cs
new file mode 100644
index 0000000..f23b8c5
--- /dev/null
+++ b/Vendor/Be.Windows.Forms.HexBox/Properties/Resources.Designer.cs
@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+//
+// This code was generated by a tool.
+// Runtime Version:4.0.30319.1
+//
+// Changes to this file may cause incorrect behavior and will be lost if
+// the code is regenerated.
+//
+//------------------------------------------------------------------------------
+
+namespace Be.Windows.Forms.Properties {
+ using System;
+
+
+ ///
+ /// A strongly-typed resource class, for looking up localized strings, etc.
+ ///
+ // This class was auto-generated by the StronglyTypedResourceBuilder
+ // class via a tool like ResGen or Visual Studio.
+ // To add or remove a member, edit your .ResX file then rerun ResGen
+ // with the /str option, or rebuild your VS project.
+ [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+ internal class Resources {
+
+ private static global::System.Resources.ResourceManager resourceMan;
+
+ private static global::System.Globalization.CultureInfo resourceCulture;
+
+ [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+ internal Resources() {
+ }
+
+ ///
+ /// Returns the cached ResourceManager instance used by this class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Resources.ResourceManager ResourceManager {
+ get {
+ if (object.ReferenceEquals(resourceMan, null)) {
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Be.Windows.Forms.Properties.Resources", typeof(Resources).Assembly);
+ resourceMan = temp;
+ }
+ return resourceMan;
+ }
+ }
+
+ ///
+ /// Overrides the current thread's CurrentUICulture property for all
+ /// resource lookups using this strongly typed resource class.
+ ///
+ [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+ internal static global::System.Globalization.CultureInfo Culture {
+ get {
+ return resourceCulture;
+ }
+ set {
+ resourceCulture = value;
+ }
+ }
+ }
+}
diff --git a/Vendor/Be.Windows.Forms.HexBox/Properties/Resources.resx b/Vendor/Be.Windows.Forms.HexBox/Properties/Resources.resx
new file mode 100644
index 0000000..7080a7d
--- /dev/null
+++ b/Vendor/Be.Windows.Forms.HexBox/Properties/Resources.resx
@@ -0,0 +1,120 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ text/microsoft-resx
+
+
+ 2.0
+
+
+ System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
+ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+
\ No newline at end of file
diff --git a/Vendor/Be.Windows.Forms.HexBox/Util.cs b/Vendor/Be.Windows.Forms.HexBox/Util.cs
new file mode 100644
index 0000000..1408878
--- /dev/null
+++ b/Vendor/Be.Windows.Forms.HexBox/Util.cs
@@ -0,0 +1,38 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Be.Windows.Forms
+{
+ static class Util
+ {
+ ///
+ /// Contains true, if we are in design mode of Visual Studio
+ ///
+ private static bool _designMode;
+
+ ///
+ /// Initializes an instance of Util class
+ ///
+ static Util()
+ {
+ _designMode = (System.Diagnostics.Process.GetCurrentProcess().ProcessName.ToLower() == "devenv");
+ }
+
+ ///
+ /// Gets true, if we are in design mode of Visual Studio
+ ///
+ ///
+ /// In Visual Studio 2008 SP1 the designer is crashing sometimes on windows forms.
+ /// The DesignMode property of Control class is buggy and cannot be used, so use our own implementation instead.
+ ///
+ public static bool DesignMode
+ {
+ get
+ {
+ return _designMode;
+ }
+ }
+
+ }
+}