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; + } + } + + } +}