mirror of
https://github.com/jaquadro/NBTExplorer.git
synced 2025-01-10 01:46:24 +00:00
291 lines
9.5 KiB
C#
291 lines
9.5 KiB
C#
using System;
|
|
using System.Windows.Forms;
|
|
using Be.Windows.Forms;
|
|
using System.IO;
|
|
using System.Collections.Generic;
|
|
using System.ComponentModel;
|
|
using System.Text;
|
|
|
|
namespace NBTExplorer.Windows
|
|
{
|
|
public partial class HexEditor : Form
|
|
{
|
|
private int _bytesPerElem;
|
|
private byte[] _data;
|
|
private bool _modified;
|
|
DynamicByteProvider _byteProvider;
|
|
|
|
private class FixedByteProvider : DynamicByteProvider
|
|
{
|
|
public FixedByteProvider (byte[] data)
|
|
: base(data)
|
|
{ }
|
|
|
|
public override bool SupportsInsertBytes ()
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public HexEditor (string tagName, byte[] data, int bytesPerElem)
|
|
{
|
|
InitializeComponent();
|
|
|
|
this.Text = "Editing: " + tagName;
|
|
|
|
_bytesPerElem = bytesPerElem;
|
|
_curPositionLabel.Text = "0x0000";
|
|
_curElementLabel.Text = "Element 0";
|
|
|
|
_data = new byte[data.Length];
|
|
Array.Copy(data, _data, data.Length);
|
|
|
|
_byteProvider = new DynamicByteProvider(_data);
|
|
_byteProvider.Changed += (o, e) => { _modified = true; };
|
|
|
|
hexBox1.ByteProvider = _byteProvider;
|
|
|
|
hexBox1.HorizontalByteCountChanged += HexBox_HorizontalByteCountChanged;
|
|
hexBox1.CurrentLineChanged += HexBox_CurrentLineChanged;
|
|
hexBox1.CurrentPositionInLineChanged += HexBox_CurrentPositionInLineChanged;
|
|
hexBox1.InsertActiveChanged += HexBox_InsertActiveChanged;
|
|
|
|
hexBox1.ReadOnly = false;
|
|
}
|
|
|
|
public byte[] Data
|
|
{
|
|
get { return _data; }
|
|
}
|
|
|
|
public bool Modified
|
|
{
|
|
get { return _modified; }
|
|
}
|
|
|
|
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 HexBox_InsertActiveChanged (object sender, EventArgs e)
|
|
{
|
|
if (hexBox1.InsertActive)
|
|
_insertStateLabel.Text = "Insert";
|
|
else
|
|
_insertStateLabel.Text = "Overwrite";
|
|
}
|
|
|
|
private void UpdatePosition ()
|
|
{
|
|
long pos = (hexBox1.CurrentLine - 1) * hexBox1.HorizontalByteCount + hexBox1.CurrentPositionInLine - 1;
|
|
|
|
_curPositionLabel.Text = "0x" + pos.ToString("X4");
|
|
_curElementLabel.Text = "Element " + pos / _bytesPerElem;
|
|
}
|
|
|
|
private void Apply ()
|
|
{
|
|
if (_data.Length != _byteProvider.Length)
|
|
_data = new byte[_byteProvider.Length];
|
|
|
|
for (int i = 0; i < _data.Length; i++) {
|
|
_data[i] = _byteProvider.Bytes[i];
|
|
}
|
|
|
|
DialogResult = DialogResult.OK;
|
|
Close();
|
|
}
|
|
|
|
private String RawToText (byte[] data)
|
|
{
|
|
StringBuilder builder = new StringBuilder();
|
|
|
|
for (int i = 0; i < data.Length; i += _bytesPerElem) {
|
|
if (data.Length - i < _bytesPerElem)
|
|
break;
|
|
|
|
switch (_bytesPerElem) {
|
|
case 1:
|
|
builder.AppendLine(((sbyte)data[i]).ToString());
|
|
break;
|
|
|
|
case 2:
|
|
builder.AppendLine(BitConverter.ToInt16(data, i).ToString());
|
|
break;
|
|
|
|
case 4:
|
|
builder.AppendLine(BitConverter.ToInt32(data, i).ToString());
|
|
break;
|
|
|
|
case 8:
|
|
builder.AppendLine(BitConverter.ToInt64(data, i).ToString());
|
|
break;
|
|
}
|
|
}
|
|
|
|
return builder.ToString();
|
|
}
|
|
|
|
private byte[] TextToRaw (string text)
|
|
{
|
|
string[] items = text.Split(null as char[], StringSplitOptions.RemoveEmptyEntries);
|
|
byte[] data = new byte[_bytesPerElem * items.Length];
|
|
|
|
for (int i = 0; i < items.Length; i++) {
|
|
int index = i * _bytesPerElem;
|
|
|
|
switch (_bytesPerElem) {
|
|
case 1:
|
|
sbyte val1;
|
|
if (sbyte.TryParse(items[i], out val1))
|
|
data[index] = (byte)val1;
|
|
break;
|
|
|
|
case 2:
|
|
short val2;
|
|
if (short.TryParse(items[i], out val2)) {
|
|
byte[] buffer = BitConverter.GetBytes(val2);
|
|
Array.Copy(buffer, 0, data, index, 2);
|
|
}
|
|
break;
|
|
|
|
case 4:
|
|
int val4;
|
|
if (int.TryParse(items[i], out val4)) {
|
|
byte[] buffer = BitConverter.GetBytes(val4);
|
|
Array.Copy(buffer, 0, data, index, 4);
|
|
}
|
|
break;
|
|
|
|
case 8:
|
|
long val8;
|
|
if (long.TryParse(items[i], out val8)) {
|
|
byte[] buffer = BitConverter.GetBytes(val8);
|
|
Array.Copy(buffer, 0, data, index, 8);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
private void ImportRaw (string path)
|
|
{
|
|
try {
|
|
using (FileStream fstr = File.OpenRead(path)) {
|
|
_data = new byte[fstr.Length];
|
|
fstr.Read(_data, 0, (int)fstr.Length);
|
|
|
|
_byteProvider = new DynamicByteProvider(_data);
|
|
_byteProvider.Changed += (o, e) => { _modified = true; };
|
|
|
|
hexBox1.ByteProvider = _byteProvider;
|
|
_modified = true;
|
|
}
|
|
}
|
|
catch (Exception e) {
|
|
MessageBox.Show("Failed to import data from \"" + path + "\"\n\nException: " + e.Message);
|
|
}
|
|
}
|
|
|
|
private void ImportText (string path)
|
|
{
|
|
try {
|
|
using (FileStream fstr = File.OpenRead(path)) {
|
|
byte[] raw = new byte[fstr.Length];
|
|
fstr.Read(raw, 0, (int)fstr.Length);
|
|
|
|
string text = System.Text.Encoding.UTF8.GetString(raw, 0, raw.Length);
|
|
_data = TextToRaw(text);
|
|
|
|
_byteProvider = new DynamicByteProvider(_data);
|
|
_byteProvider.Changed += (o, e) => { _modified = true; };
|
|
|
|
hexBox1.ByteProvider = _byteProvider;
|
|
_modified = true;
|
|
}
|
|
}
|
|
catch (Exception e) {
|
|
MessageBox.Show("Failed to import data from \"" + path + "\"\n\nException: " + e.Message);
|
|
}
|
|
}
|
|
|
|
private void ExportRaw (string path)
|
|
{
|
|
try {
|
|
using (FileStream fstr = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None)) {
|
|
byte[] data = _byteProvider.Bytes.ToArray();
|
|
fstr.Write(data, 0, data.Length);
|
|
}
|
|
}
|
|
catch (Exception e) {
|
|
MessageBox.Show("Failed to export data to \"" + path + "\"\n\nException: " + e.Message);
|
|
}
|
|
}
|
|
|
|
private void ExportText (string path)
|
|
{
|
|
try {
|
|
using (FileStream fstr = File.Open(path, FileMode.Create, FileAccess.Write, FileShare.None)) {
|
|
string text = RawToText(_byteProvider.Bytes.ToArray());
|
|
byte[] data = System.Text.Encoding.UTF8.GetBytes(text);
|
|
fstr.Write(data, 0, data.Length);
|
|
}
|
|
}
|
|
catch (Exception e) {
|
|
MessageBox.Show("Failed to export data to \"" + path + "\"\n\nException: " + e.Message);
|
|
}
|
|
}
|
|
|
|
private void _buttonOK_Click (object sender, EventArgs e)
|
|
{
|
|
Apply();
|
|
}
|
|
|
|
private void _buttonImport_Click (object sender, EventArgs e)
|
|
{
|
|
using (OpenFileDialog ofd = new OpenFileDialog()) {
|
|
ofd.RestoreDirectory = true;
|
|
ofd.Multiselect = false;
|
|
ofd.Filter = "Binary Data|*|Text Data (*.txt)|*.txt";
|
|
ofd.FilterIndex = 0;
|
|
|
|
if (ofd.ShowDialog() == DialogResult.OK) {
|
|
if (Path.GetExtension(ofd.FileName) == ".txt")
|
|
ImportText(ofd.FileName);
|
|
else
|
|
ImportRaw(ofd.FileName);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void _buttonExport_Click (object sender, EventArgs e)
|
|
{
|
|
using (SaveFileDialog sfd = new SaveFileDialog()) {
|
|
sfd.RestoreDirectory = true;
|
|
sfd.Filter = "Binary Data|*|Text Data (*.txt)|*.txt";
|
|
sfd.FilterIndex = 0;
|
|
sfd.OverwritePrompt = true;
|
|
|
|
if (sfd.ShowDialog() == DialogResult.OK) {
|
|
if (Path.GetExtension(sfd.FileName) == ".txt")
|
|
ExportText(sfd.FileName);
|
|
else
|
|
ExportRaw(sfd.FileName);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|