From 46796f4dafd400b1b4dc26b896483ce0854b85b3 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Sat, 24 May 2008 08:56:54 +0000 Subject: [PATCH] Improved buffer management of the hex editor. Now it uses a "StreamedList" --> a list with a file split up in single stream files. git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@3085 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../DisplayBindings/HexEditor/HexEditor.sln | 8 +- .../HexEditor/Project/HexEditor.csproj | 2 +- .../HexEditor/Project/Src/Editor.cs | 127 +++----- .../Project/Src/Util/BufferManager.cs | 221 ++++---------- .../HexEditor/Project/Src/Util/Change.cs | 134 -------- .../Project/Src/Util/ClipboardManager.cs | 51 ---- .../Project/Src/Util/StreamedList.cs | 287 ++++++++++++++++++ .../HexEditor/Project/Src/Util/UndoAction.cs | 2 +- .../HexEditor/Project/Src/Util/UndoManager.cs | 20 +- .../Project/Src/View/HexEditContainer.cs | 2 + .../HexEditor/Project/changes.txt | 5 +- 11 files changed, 422 insertions(+), 437 deletions(-) delete mode 100644 src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/Change.cs delete mode 100644 src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/ClipboardManager.cs create mode 100644 src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/StreamedList.cs diff --git a/src/AddIns/DisplayBindings/HexEditor/HexEditor.sln b/src/AddIns/DisplayBindings/HexEditor/HexEditor.sln index b83978550c..55e7902027 100644 --- a/src/AddIns/DisplayBindings/HexEditor/HexEditor.sln +++ b/src/AddIns/DisplayBindings/HexEditor/HexEditor.sln @@ -1,13 +1,15 @@  Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 -# SharpDevelop 3.0.0.2956 +# SharpDevelop 3.0.0.3014 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HexEditor", "Project\HexEditor.csproj", "{E618A9CD-A39F-4925-A538-E8A3FEF24E54}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.SharpDevelop", "..\..\..\Main\Base\Project\ICSharpCode.SharpDevelop.csproj", "{2748AD25-9C63-4E12-877B-4DCE96FBED54}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.Core", "..\..\..\Main\Core\Project\ICSharpCode.Core.csproj", "{35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HexEditor.Tests", "..\..\..\..\..\HexEditor.Tests\HexEditor.Tests.csproj", "{65F6998A-98F4-48BA-AE98-0CB5B38FDC58}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -26,5 +28,9 @@ Global {35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}.Release|Any CPU.Build.0 = Release|Any CPU {35CEF10F-2D4C-45F2-9DD1-161E0FEC583C}.Release|Any CPU.ActiveCfg = Release|Any CPU + {65F6998A-98F4-48BA-AE98-0CB5B38FDC58}.Debug|Any CPU.Build.0 = Debug|Any CPU + {65F6998A-98F4-48BA-AE98-0CB5B38FDC58}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {65F6998A-98F4-48BA-AE98-0CB5B38FDC58}.Release|Any CPU.Build.0 = Release|Any CPU + {65F6998A-98F4-48BA-AE98-0CB5B38FDC58}.Release|Any CPU.ActiveCfg = Release|Any CPU EndGlobalSection EndGlobal diff --git a/src/AddIns/DisplayBindings/HexEditor/Project/HexEditor.csproj b/src/AddIns/DisplayBindings/HexEditor/Project/HexEditor.csproj index 56673829e2..a36130b1f3 100644 --- a/src/AddIns/DisplayBindings/HexEditor/Project/HexEditor.csproj +++ b/src/AddIns/DisplayBindings/HexEditor/Project/HexEditor.csproj @@ -67,9 +67,9 @@ - + diff --git a/src/AddIns/DisplayBindings/HexEditor/Project/Src/Editor.cs b/src/AddIns/DisplayBindings/HexEditor/Project/Src/Editor.cs index 21521555e2..87dcf51b76 100644 --- a/src/AddIns/DisplayBindings/HexEditor/Project/Src/Editor.cs +++ b/src/AddIns/DisplayBindings/HexEditor/Project/Src/Editor.cs @@ -42,6 +42,8 @@ namespace HexEditor int underscorewidth, underscorewidth3, fontheight; bool insertmode, hexinputmode, selectionmode, handled, moved; + Point oldMousePos = new Point(0,0); + Settings settings; Rectangle[] selregion; @@ -52,6 +54,7 @@ namespace HexEditor public Caret Caret { get { return caret; } } + SelectionManager selection; UndoManager undoStack; @@ -135,10 +138,6 @@ namespace HexEditor } #region Measure functions - /* - * Code from SharpDevelop TextEditor - * */ - static int GetFontHeight(Font font) { int height1 = TextRenderer.MeasureText("_", font).Height; @@ -148,18 +147,10 @@ namespace HexEditor static int MeasureStringWidth(Graphics g, string word, Font font) { - // This code here provides better results than MeasureString! - // Example line that is measured wrong: - // txt.GetPositionFromCharIndex(txt.SelectionStart) - // (Verdana 10, highlighting makes GetP... bold) -> note the space between 'x' and '(' - // this also fixes "jumping" characters when selecting in non-monospace fonts - // [...] - // Replaced GDI+ measurement with GDI measurement: faster and even more exact return TextRenderer.MeasureText(g, word, font, new Size(short.MaxValue, short.MaxValue), TextFormatFlags.NoPadding | TextFormatFlags.NoPrefix | TextFormatFlags.PreserveGraphicsClipping).Width; } - #endregion /// @@ -412,8 +403,6 @@ namespace HexEditor protected override void OnMouseWheel(MouseEventArgs e) { base.OnMouseWheel(e); - - if (!this.VScrollBar.Enabled) return; @@ -458,13 +447,7 @@ namespace HexEditor moved = false; return; } - } else { - this.Invalidate(); } - caret.Offset = this.GetOffsetForPosition(e.Location, 3); - caret.SetToPosition(GetPositionForOffset(caret.Offset, 3)); - - this.Invalidate(); } /// @@ -496,9 +479,6 @@ namespace HexEditor this.charwidth = 1; this.caret.Width = 1; if (!insertmode) this.caret.Width = underscorewidth; - caret.Offset = this.GetOffsetForPosition(e.Location, 1); - caret.SetToPosition(GetPositionForOffset(caret.Offset, 1)); - this.Invalidate(); } #endregion @@ -1034,19 +1014,15 @@ namespace HexEditor if (selection.Start > selection.End) start = selection.End; buffer.RemoveBytes(start, Math.Abs(selection.End - selection.Start)); - buffer.SetBytes(start, this.Encoding.GetBytes(text.ToCharArray()), false); - UndoAction action = UndoAction.Overwrite; - - undoStack.AddUndoStep(new UndoStep(this.Encoding.GetBytes(text.ToCharArray()), old, caret.Offset, action)); + undoStack.AddOverwriteStep(caret.Offset, this.Encoding.GetBytes(text.ToCharArray()), old); caret.Offset = start + ClipboardManager.Paste().Length; selection.Clear(); } else { buffer.SetBytes(caret.Offset, this.Encoding.GetBytes(text.ToCharArray()), false); - UndoAction action = UndoAction.Remove; - undoStack.AddUndoStep(new UndoStep(this.Encoding.GetBytes(text.ToCharArray()), null, caret.Offset, action)); + undoStack.AddInsertStep(caret.Offset, this.Encoding.GetBytes(text.ToCharArray())); caret.Offset += ClipboardManager.Paste().Length; } @@ -1072,9 +1048,7 @@ namespace HexEditor buffer.RemoveBytes(selection.Start, Math.Abs(selection.End - selection.Start)); caret.Offset = selection.Start; - UndoAction action = UndoAction.Add; - - undoStack.AddUndoStep(new UndoStep(old, null, selection.Start, action)); + undoStack.AddInsertStep(selection.Start, old); selection.Clear(); } @@ -1084,7 +1058,6 @@ namespace HexEditor OnDocumentChanged(e2); } #endregion - #region TextProcessing /// @@ -1327,9 +1300,7 @@ namespace HexEditor buffer.RemoveBytes(start, Math.Abs(end - start)); caret.Offset = start; - UndoAction action = UndoAction.Add; - - undoStack.AddUndoStep(new UndoStep(bytes, null, start, action)); + undoStack.AddInsertStep(start, bytes); selection.Clear(); } else { @@ -1341,9 +1312,7 @@ namespace HexEditor if (GetLineForOffset(caret.Offset) < this.topline) this.topline = GetLineForOffset(caret.Offset); if (GetLineForOffset(caret.Offset) > this.topline + this.GetMaxVisibleLines() - 2) this.topline = GetLineForOffset(caret.Offset) - this.GetMaxVisibleLines() + 2; - UndoAction action = UndoAction.Add; - - undoStack.AddUndoStep(new UndoStep(new byte[] {b}, null, caret.Offset, action)); + undoStack.AddInsertStep(caret.Offset, new byte[] {b}); } } @@ -1357,10 +1326,8 @@ namespace HexEditor byte[] old = selection.GetSelectionBytes(); buffer.RemoveBytes(start, Math.Abs(selection.End - selection.Start)); caret.Offset = selection.Start; - - UndoAction action = UndoAction.Add; - - undoStack.AddUndoStep(new UndoStep(old, null, selection.Start, action)); + + undoStack.AddInsertStep(selection.Start, old); selection.Clear(); } else { @@ -1368,9 +1335,7 @@ namespace HexEditor buffer.RemoveByte(caret.Offset); - UndoAction action = UndoAction.Remove; - - undoStack.AddUndoStep(new UndoStep(new byte[] {b}, null, caret.Offset, action)); + undoStack.AddRemoveStep(caret.Offset, new byte[] {b}); if (GetLineForOffset(caret.Offset) < this.topline) this.topline = GetLineForOffset(caret.Offset); if (GetLineForOffset(caret.Offset) > this.topline + this.GetMaxVisibleLines() - 2) this.topline = GetLineForOffset(caret.Offset) - this.GetMaxVisibleLines() + 2; @@ -1457,16 +1422,11 @@ namespace HexEditor if (GetLineForOffset(caret.Offset) > this.topline + this.GetMaxVisibleLines() - 2) this.topline = GetLineForOffset(caret.Offset) - this.GetMaxVisibleLines() + 2; VScrollBar.Value = this.topline; - UndoAction action; - if (insertmode) { - action = UndoAction.Remove; - old = null; + undoStack.AddRemoveStep(caret.Offset, new byte[] {(byte)e.KeyChar}); } else { - action = UndoAction.Overwrite; + undoStack.AddOverwriteStep(caret.Offset, new byte[] {(byte)e.KeyChar}, old); } - - undoStack.AddUndoStep(new UndoStep(new byte[] {(byte)e.KeyChar}, old, caret.Offset - 1, action)); } caret.SetToPosition(GetPositionForOffset(caret.Offset, charwidth)); @@ -1581,9 +1541,7 @@ namespace HexEditor // if @in is like 4 or A then make 04 or 0A out of it. if (@in.Length == 1) @in = "0" + @in; - UndoAction action = UndoAction.Overwrite; - - undoStack.AddUndoStep(new UndoStep(new byte[] {(byte)(Convert.ToInt32(@in.Remove(1) + ((char)(input.KeyValue)).ToString(), 16))}, buffer.GetBytes(caret.Offset, 1), caret.Offset, action)); + undoStack.AddOverwriteStep(caret.Offset, new byte[] {(byte)(Convert.ToInt32(@in.Remove(1) + ((char)(input.KeyValue)).ToString(), 16))}, buffer.GetBytes(caret.Offset, 1)); @in = @in.Remove(1) + ((char)(input.KeyValue)).ToString(); hexinputmodepos = 0; @@ -1621,6 +1579,7 @@ namespace HexEditor if (hexinputmodepos == 1) { byte[] _old = buffer.GetBytes(caret.Offset, 1); @in = string.Format("{0:X}", buffer.GetByte(caret.Offset)); + if (@in.Length == 1) @in = "0" + @in; @in = @in.Remove(1) + ((char)(input.KeyValue)).ToString(); hexinputmodepos = 0; hexinputmode = false; @@ -1628,7 +1587,7 @@ namespace HexEditor caret.Offset++; if (insertmode) { - action = UndoAction.Add; + action = UndoAction.Insert; _old = null; } else { action = UndoAction.Overwrite; @@ -1645,7 +1604,7 @@ namespace HexEditor hexinputmodepos = 1; if (insertmode) { - action = UndoAction.Add; + action = UndoAction.Insert; _old = null; } else { action = UndoAction.Overwrite; @@ -1719,7 +1678,6 @@ namespace HexEditor /// private void HexEditGotFocus(object sender, EventArgs e) { - //LoadSettings(); this.Invalidate(); } @@ -1732,35 +1690,31 @@ namespace HexEditor void TextViewMouseDown(object sender, MouseEventArgs e) { this.activeView = this.textView; - this.hexinputmode = false; - this.hexinputmodepos = 0; if (e.Button == MouseButtons.Left) { if (selection.HasSomethingSelected) { selection.Start = 0; selection.End = 0; - PaintText(this.textView.CreateGraphics(), this.topline); } selectionmode = true; selection.Start = GetOffsetForPosition(e.Location, 1); } - - caret.Offset = GetOffsetForPosition(e.Location, 1); - caret.SetToPosition(GetPositionForOffset(caret.Offset, this.charwidth)); } void TextViewMouseMove(object sender, MouseEventArgs e) { - if ((e.Button == MouseButtons.Left) & selectionmode) { + if ((e.Button == MouseButtons.Left) && selectionmode && (e.Location != oldMousePos)) { int end = selection.End; selection.End = GetOffsetForPosition(e.Location, 1); this.activeView = this.textView; moved = true; selection.HasSomethingSelected = true; - if (end != selection.End) this.Invalidate(); - caret.Offset = GetOffsetForPosition(e.Location, 1); caret.SetToPosition(GetPositionForOffset(caret.Offset, this.charwidth)); + + this.Invalidate(); } + + oldMousePos = e.Location; } void TextViewMouseUp(object sender, MouseEventArgs e) @@ -1772,7 +1726,6 @@ namespace HexEditor selection.HasSomethingSelected = false; selectionmode = false; } - this.Invalidate(); } else { if (!moved) { selection.HasSomethingSelected = false; @@ -1785,38 +1738,36 @@ namespace HexEditor caret.SetToPosition(GetPositionForOffset(caret.Offset, this.charwidth)); selectionmode = false; + + this.Invalidate(); } void HexViewMouseDown(object sender, MouseEventArgs e) { this.activeView = this.hexView; - this.hexinputmode = false; - this.hexinputmodepos = 0; if (e.Button == MouseButtons.Left) { selectionmode = true; selection.Start = GetOffsetForPosition(e.Location, 3); selection.End = GetOffsetForPosition(e.Location, 3); - this.Invalidate(); - - caret.Offset = GetOffsetForPosition(e.Location, 3); - caret.SetToPosition(GetPositionForOffset(caret.Offset, this.charwidth)); } } void HexViewMouseMove(object sender, MouseEventArgs e) { - if ((e.Button == MouseButtons.Left) & selectionmode) { + if ((e.Button == MouseButtons.Left) && selectionmode && (e.Location != oldMousePos)) { int end = selection.End; selection.End = GetOffsetForPosition(e.Location, 3); selection.HasSomethingSelected = true; this.activeView = this.hexView; moved = true; - caret.SetToPosition(GetPositionForOffset(GetOffsetForPosition(e.Location, 3), 3)); - if (end != selection.End) this.Invalidate(); caret.Offset = GetOffsetForPosition(e.Location, 3); caret.SetToPosition(GetPositionForOffset(caret.Offset, this.charwidth)); + + this.Invalidate(); } + + oldMousePos = e.Location; } void HexViewMouseUp(object sender, MouseEventArgs e) @@ -1829,7 +1780,6 @@ namespace HexEditor selection.HasSomethingSelected = false; selectionmode = false; } - this.Invalidate(); } else { if (!moved) { selection.HasSomethingSelected = false; @@ -1841,6 +1791,8 @@ namespace HexEditor caret.Offset = GetOffsetForPosition(e.Location, 3); caret.SetToPosition(GetPositionForOffset(caret.Offset, this.charwidth)); selectionmode = false; + + this.Invalidate(); } #endregion @@ -1902,12 +1854,25 @@ namespace HexEditor line++; // calculate the char: horizontal position (X) divided by the width of one char - int ch = (int)Math.Round((float)position.X / (float)(charwidth * underscorewidth)); + float col = ((float)position.X / (float)(charwidth * underscorewidth)); + float diff = (float)col - (float)((int)col); + + int ch = diff >= 0.75f ? (int)col + 1 : (int)col; + if (ch > this.BytesPerLine) ch = this.BytesPerLine; if (ch < 0) ch = 0; + // calculate offset int offset = line * this.BytesPerLine + ch; + if ((diff > 0.35f) && (diff < 0.75f)) { + this.hexinputmodepos = 1; + this.hexinputmode = true; + } else { + this.hexinputmodepos = 0; + this.hexinputmode = false; + } + // check if (offset < 0) return 0; if (offset < this.buffer.BufferSize) { @@ -2009,4 +1974,4 @@ namespace HexEditor this.Invalidate(); } } -} +} \ No newline at end of file diff --git a/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/BufferManager.cs b/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/BufferManager.cs index b8b52a6ef7..3853000b62 100644 --- a/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/BufferManager.cs +++ b/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/BufferManager.cs @@ -8,6 +8,7 @@ using System; using System.IO; using System.Collections; +using System.Collections.Generic; using System.Text; using System.Windows.Forms; using System.Diagnostics; @@ -24,34 +25,19 @@ namespace HexEditor.Util /// public class BufferManager { - internal Control parent; + Editor parent; OpenedFile currentFile; - Stream stream; - /// - /// Currently used, but not good for really big files (like 590 MB) - /// - private ArrayList buffer; + StreamedList data; /// /// Creates a new BufferManager and attaches it to a control. /// /// The parent control to attach to. - public BufferManager(Control parent) + public BufferManager(Editor parent) { this.parent = parent; - - this.buffer = new ArrayList(); - } - - /// - /// Cleares the whole buffer. - /// - public void Clear() - { - this.buffer.Clear(); - parent.Invalidate(); - GC.Collect(); + this.data = new StreamedList(); } /// @@ -60,46 +46,32 @@ namespace HexEditor.Util public void Load(OpenedFile file, Stream stream) { this.currentFile = file; - this.stream = stream; - this.buffer.Clear(); - ((Editor)this.parent).Enabled = false; + this.data.Clear(); + this.data = new StreamedList(); + + stream.Position = 0; + byte[] bytes = new byte[512000]; if (File.Exists(currentFile.FileName)) { - try { - BinaryReader reader = new BinaryReader(this.stream, System.Text.Encoding.Default); - - while (reader.PeekChar() != -1) { - this.buffer.AddRange(reader.ReadBytes(524288)); - UpdateProgress((int)((this.buffer.Count * 100) / reader.BaseStream.Length)); + int count = 0; + do { + count = stream.Read(bytes, 0, bytes.Length); + if (count > 0) { + this.data.AddRange(bytes, count); + // Maybe not a good solution, but easier than implementing a complete thread + // A thread would need to reopen the file in the thread + // because it is closed after the CreateContentForFile() has + // finished. + Application.DoEvents(); + GC.Collect(); } - - reader.Close(); - } catch (IOException ex) { - MessageService.ShowError(ex, ex.Message); - } catch (ArgumentException ex) { - MessageService.ShowError(ex, ex.Message + "\n\n" + ex.StackTrace); - } + } while (count > 0); } else { MessageService.ShowError(new FileNotFoundException("The file " + currentFile.FileName + " doesn't exist!", currentFile.FileName), "The file " + currentFile.FileName + " doesn't exist!"); } this.parent.Invalidate(); - - UpdateProgress(100); - - if (this.parent.InvokeRequired) - this.parent.Invoke(new MethodInvoker( - delegate() {this.parent.Cursor = Cursors.Default;} - )); - else {this.parent.Cursor = Cursors.Default;} - - - ((Editor)this.parent).LoadingFinished(); - - ((Editor)this.parent).Enabled = true; - - this.parent.Invalidate(); } /// @@ -107,129 +79,43 @@ namespace HexEditor.Util /// public void Save(OpenedFile file, Stream stream) { - BinaryWriter writer = new BinaryWriter(stream); - writer.Write((byte[])this.buffer.ToArray( typeof (byte) )); - writer.Flush(); - } - - /// - /// Intern method used to load data in a separate thread. - /// - /// Currently not in use. - private void Load() - { - ((Editor)this.parent).Enabled = false; - - if (File.Exists(currentFile.FileName)) { - try { - BinaryReader reader = new BinaryReader(this.stream, System.Text.Encoding.Default); - - while (reader.PeekChar() != -1) { - this.buffer.AddRange(reader.ReadBytes(524288)); - UpdateProgress((int)((this.buffer.Count * 100) / reader.BaseStream.Length)); - } - - reader.Close(); - } catch (IOException ex) { - MessageService.ShowError(ex, ex.Message); - } catch (ArgumentException ex) { - MessageService.ShowError(ex, ex.Message + "\n\n" + ex.StackTrace); - } - } else { - MessageService.ShowError(new FileNotFoundException("The file " + currentFile.FileName + " doesn't exist!", currentFile.FileName), "The file " + currentFile.FileName + " doesn't exist!"); - } - - this.parent.Invalidate(); - - UpdateProgress(100); - - if (this.parent.InvokeRequired) - this.parent.Invoke(new MethodInvoker( - delegate() {this.parent.Cursor = Cursors.Default;} - )); - - ((Editor)this.parent).Enabled = true; - } - - /// - /// Used for threading to update the processbars and stuff. - /// - /// The current percentage of the process - private void UpdateProgress(int percentage) - { - Editor c = (Editor)this.parent; - - Application.DoEvents(); - - if (c.ProgressBar != null) { - if (percentage >= 100) { - if (c.InvokeRequired) - c.Invoke(new MethodInvoker( - delegate() {c.ProgressBar.Value = 100; c.ProgressBar.Visible = false;} - )); - else { - c.ProgressBar.Value = 100; - c.ProgressBar.Visible = false; } - } else { - if (c.InvokeRequired) - c.Invoke(new MethodInvoker( - delegate() {c.ProgressBar.Value = percentage; c.ProgressBar.Visible = true;} - )); - else { c.ProgressBar.Value = percentage; c.ProgressBar.Visible = true; } - } - } - } - - /// - /// Returns the current buffer as a byte[]. - /// - public byte[] Buffer { - get { - if (buffer == null) return new byte[0]; - return (byte[]) buffer.ToArray( typeof ( byte ) ); - } + this.data.ConcatenateTo(stream); } /// /// The size of the current buffer. /// public int BufferSize { - get { return buffer.Count; } + get { + return this.data.Count; + } } #region Methods - public byte[] GetBytes(int start, int count) { - if (buffer.Count == 0) return new byte[] {}; + if (this.BufferSize == 0) return new byte[] {}; if (start < 0) start = 0; - if (start >= buffer.Count) start = buffer.Count; + if (start >= this.BufferSize) start = this.BufferSize; if (count < 1) count = 1; - if (count >= (buffer.Count - start)) count = (buffer.Count - start); - return (byte[])(buffer.GetRange(start, count).ToArray( typeof ( byte ) )); + if (count >= (this.BufferSize - start)) count = (this.BufferSize - start); + + return this.data.GetRange(start, count); } public byte GetByte(int offset) { - if (buffer.Count == 0) return 0; + if (this.BufferSize == 0) return 0; if (offset < 0) offset = 0; - if (offset >= buffer.Count) offset = buffer.Count; - return (byte)buffer[offset]; - } - - public bool DeleteByte(int offset) - { - if ((offset < buffer.Count) & (offset > -1)) { - buffer.RemoveAt(offset); - return true; - } - return false; + if (offset >= this.BufferSize) offset = this.BufferSize; + + return this.data[offset]; } public bool RemoveByte(int offset) { - if ((offset < buffer.Count) & (offset > -1)) { - buffer.RemoveAt(offset); + if ((offset < this.BufferSize) & (offset > -1)) { + data.RemoveAt(offset); return true; } return false; @@ -237,34 +123,45 @@ namespace HexEditor.Util public bool RemoveBytes(int offset, int length) { - if (((offset < buffer.Count) && (offset > -1)) && ((offset + length) <= buffer.Count)) { - buffer.RemoveRange(offset, length); + if (((offset < this.BufferSize) && (offset > -1)) && ((offset + length) <= this.BufferSize)) { + if ((offset == 0) && (length == data.Count)) { + this.data.Clear(); + this.data = new StreamedList(); + } else { + this.data.RemoveRange(offset, length); + } return true; } return false; } - /// Not Tested! public void SetBytes(int start, byte[] bytes, bool overwrite) { if (overwrite) { - if (bytes.Length > buffer.Count) buffer.AddRange(new byte[bytes.Length - buffer.Count]); - buffer.SetRange(start, bytes); + foreach (byte b in bytes) + { + data[start] = b; + start++; + } } else { - buffer.InsertRange(start, bytes); + foreach (byte b in bytes) + { + data.Insert(start, b); + start++; + } } } public void SetByte(int position, byte @byte, bool overwrite) { if (overwrite) { - if (position > buffer.Count - 1) { - buffer.Add(@byte); + data[position] = @byte; + } else { + if (position == data.Count) { + data.Add(@byte); } else { - buffer[position] = @byte; + data.Insert(position, @byte); } - } else { - buffer.Insert(position, @byte); } } #endregion diff --git a/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/Change.cs b/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/Change.cs deleted file mode 100644 index 7aa07ec328..0000000000 --- a/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/Change.cs +++ /dev/null @@ -1,134 +0,0 @@ -// -// -// -// -// $Revision: 2984 $ -// - -using System; - -namespace HexEditor.Util -{ - /// - /// Description of Change. - /// - public class Change - { - int start, end; - byte[] data; - ChangeType type; - - public Change(int start, int end, byte[] data, ChangeType type) - { - this.start = start; - this.end = end; - this.data = data; - this.type = type; - } - - public int Start { - get { return start; } - set { start = value; } - } - - public int End { - get { return end; } - set { end = value; } - } - - public byte[] Data { - get { return data; } - set { data = value; } - } - - public ChangeType Type { - get { return type; } - set { type = value; } - } - - public void Merge(Change change) - { - byte[] tmp = new byte[0]; - - switch (change.type) { - case ChangeType.Delete: - - break; - case ChangeType.Insert: - if ((change.start + change.data.Length) < this.start) - this.Prepend(change); - else - if ((change.start + change.data.Length) > this.end) - this.Append(change); - else { - tmp = new byte[change.data.Length + this.data.Length]; - - for (int i = 0; i < (int)Math.Abs(change.start - this.start); i++) - { - tmp[i] = this.data[i]; - } - - int offset = (int)Math.Abs(change.start - this.start); - - for (int i = offset; i < offset + change.data.Length; i++) - { - tmp[i] = change.data[i - offset]; - } - - for (int i = offset + change.data.Length; i < (this.data.Length + offset + change.data.Length); i++) - { - tmp[i] = this.data[i - (offset + change.data.Length)]; - } - } - break; - case ChangeType.Overwrite: - - break; - } - - this.data = tmp; - } - - public void Append(Change change) - { - byte[] tmp = new byte[change.data.Length + this.data.Length]; - - for (int i = 0; i < this.data.Length; i++) - { - tmp[i] = this.data[i]; - } - - for (int i = 0; i < change.data.Length; i++) - { - tmp[i + this.data.Length] = change.data[i]; - } - - this.end = change.end; - - this.data = tmp; - } - - public void Prepend(Change change) - { - byte[] tmp = new byte[change.data.Length + this.data.Length]; - - for (int i = 0; i < change.data.Length; i++) - { - tmp[i] = change.data[i]; - } - - for (int i = 0; i < this.data.Length; i++) - { - tmp[i + change.data.Length] = this.data[i]; - } - - this.start = change.start; - - this.data = tmp; - } - } - - public enum ChangeType { - Delete, Insert, Overwrite - } -} diff --git a/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/ClipboardManager.cs b/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/ClipboardManager.cs deleted file mode 100644 index 8c891c7ccd..0000000000 --- a/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/ClipboardManager.cs +++ /dev/null @@ -1,51 +0,0 @@ -// -// -// -// -// $Revision$ -// - -using System; -using System.Windows.Forms; - -namespace HexEditor.Util -{ - /// - /// Manages the clipboard actions. - /// - public static class ClipboardManager - { - /// - /// Used to determine if text is in the clipboard or not. - /// - public static bool ContainsText { - get { return Clipboard.ContainsText(); } - } - - /// - /// Cleares the Clipboard. - /// - public static void Clear() - { - Clipboard.Clear(); - } - - /// - /// Copies text into the clipboard. - /// - /// The text to be copied to the clipboard. - public static void Copy(string text) - { - Clipboard.SetText(text); - } - - /// - /// Pastes the text. - /// - /// the text in the clipboard. - public static string Paste() - { - return Clipboard.GetText(); - } - } -} diff --git a/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/StreamedList.cs b/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/StreamedList.cs new file mode 100644 index 0000000000..4cb65df5ad --- /dev/null +++ b/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/StreamedList.cs @@ -0,0 +1,287 @@ +// +// +// +// +// $Revision: 2995 $ +// + +using System; +using System.Collections.Generic; +using System.IO; + +using ICSharpCode.Core; + +namespace HexEditor.Util +{ + public class StreamedList : IList + { + List streams; + + int maxStreamLength = 25 * 1024 * 1024; + + public StreamedList() + { + this.streams = new List(); + this.streams.Add(new FileStream(Path.GetTempFileName(), FileMode.Create)); + } + + ~StreamedList() + { + this.Clear(); + } + + private long GetStreamPosition(long index, out int streamNumber) + { + streamNumber = -1; + + // Convert 0-based to 1-based. + index++; + + if (index > 255) { + Console.WriteLine("Test"); + } + for (int i = 0; i < streams.Count; i++) { + LoggingService.Info("Länge stream " + i + ": " + streams[i].Length + " current index: " + index); + if (index <= streams[i].Length) { + streamNumber = i; + return index - 1; + } else { + index -= streams[i].Length; + } + } + + LoggingService.Info("Fail!"); + return -1; + } + + private int GetIndex(int position, int stream) + { + int index = 0; + + for (int i = 0; i < stream; i++) { + index += (int)streams[i].Length; + } + return index + position; + } + + private long GetLength() + { + long length = 0; + foreach (FileStream stream in streams) + { + length += stream.Length; + } + + return length; + } + + public byte this[int index] + { + get { + int stream = -1; + int newIndex = (int)GetStreamPosition((long)index, out stream); + + this.streams[stream].Position = newIndex; + return (byte)this.streams[stream].ReadByte(); + } + set { + int stream = -1; + index = (int)GetStreamPosition((long)index, out stream); + + this.streams[stream].Position = index; + this.streams[stream].WriteByte(value); + } + } + + public byte[] GetRange(int index, int count) + { + if (count == 0) + return new byte[0]; + int stream = -1; + int newIndex = (int)GetStreamPosition((long)index, out stream); + + this.streams[stream].Position = newIndex; + + byte[] data = new byte[count]; + + if (newIndex + count < this.streams[stream].Length) { + this.streams[stream].Read(data, 0, count); + } else { + int offset = (int)this.streams[stream].Length - newIndex; + this.streams[stream].Read(data, 0, offset); + if (stream < this.streams.Count - 1) { + stream++; + this.streams[stream].Read(data, offset, count - offset); + } + } + + return data; + } + + public int Count { + get { + return (int)GetLength(); + } + } + + public bool IsReadOnly { + get { + return false; + } + } + + public int IndexOf(byte item) + { + for(int i = 0; i < streams.Count; i++) + { + for (int j = 0; j < streams[i].Length; j++) { + streams[i].Position = j; + if (streams[i].ReadByte() == item) { + return GetIndex(j, i); + } + } + } + + return -1; + } + + public void Insert(int index, byte item) + { + int stream = -1; + index = (int)GetStreamPosition(index, out stream); + byte[] bytes = CopyTo(stream, index, (int)this.streams[stream].Length - index - 1); + + this.streams[stream].Position = index; + this.streams[stream].WriteByte(item); + this.streams[stream].SetLength(this.streams[stream].Length + 1); + this.streams[stream].Write(bytes, 0, bytes.Length); + } + + public void RemoveAt(int index) + { + int stream = -1; + int newIndex = (int)GetStreamPosition(index, out stream); + if (index == 0) + newIndex = 0; + + byte[] bytes = CopyTo(stream, newIndex + 1, (int)this.streams[stream].Length - newIndex - 1); + + this.streams[stream].Position = newIndex; + this.streams[stream].SetLength(this.streams[stream].Length - 1); + this.streams[stream].Write(bytes, 0, bytes.Length); + } + + public void RemoveRange(int start, int count) + { + int stream = -1; + int newIndex = (int)GetStreamPosition(start, out stream); + if (start == 0) + newIndex = 0; + + byte[] bytes = CopyTo(stream, newIndex + count, (int)this.streams[stream].Length - newIndex - count); + + this.streams[stream].Position = newIndex; + this.streams[stream].SetLength(this.streams[stream].Length - count); + this.streams[stream].Write(bytes, 0, bytes.Length); + } + + public void Add(byte item) + { + if (this.streams[this.streams.Count - 1].Length > maxStreamLength) { + this.streams.Add(new FileStream(Path.GetTempFileName(), FileMode.Create)); + } + + this.streams[this.streams.Count - 1].Position + = this.streams[this.streams.Count - 1].Length; + this.streams[this.streams.Count - 1].WriteByte(item); + } + + public void Clear() + { + foreach (FileStream s in streams) + { + s.Close(); + File.Delete(s.Name); + } + this.streams.Clear(); + } + + public bool Contains(byte item) + { + throw new NotImplementedException(); + } + + public void CopyTo(byte[] array, int arrayIndex) + { + throw new NotImplementedException(); + } + + private byte[] CopyTo(int stream, int start, int count) + { + byte[] data = new byte[count]; + + this.streams[stream].Position = start; + this.streams[stream].Read(data, 0, count); + + return data; + } + + public bool Remove(byte item) + { + throw new NotImplementedException(); + } + + public IEnumerator GetEnumerator() + { + throw new NotImplementedException(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() + { + throw new NotImplementedException(); + } + + public void AddRange(byte[] data) + { + if (this.streams[this.streams.Count - 1].Length > maxStreamLength) { + LoggingService.Info("Stream added!"); + this.streams.Add(new FileStream(Path.GetTempFileName(), FileMode.Create)); + } + + this.streams[this.streams.Count - 1].Position + = this.streams[this.streams.Count - 1].Length; + this.streams[this.streams.Count - 1].SetLength(this.streams[this.streams.Count - 1].Length + data.Length); + this.streams[this.streams.Count - 1].Write(data, 0, data.Length); + LoggingService.Info("Wrote " + data.Length + " bytes"); + } + + internal void AddRange(byte[] data, int readBytes) + { + if (this.streams[this.streams.Count - 1].Length > maxStreamLength) { + LoggingService.Info("Stream added!"); + this.streams.Add(new FileStream(Path.GetTempFileName(), FileMode.Create)); + } + + this.streams[this.streams.Count - 1].Position + = this.streams[this.streams.Count - 1].Length; + this.streams[this.streams.Count - 1].SetLength(this.streams[this.streams.Count - 1].Length + readBytes); + this.streams[this.streams.Count - 1].Write(data, 0, readBytes); + LoggingService.Info("Wrote " + readBytes + " bytes"); + } + + public void ConcatenateTo(Stream stream) + { + stream.SetLength(this.Count); + foreach (FileStream fs in this.streams) + { + fs.Position = 0; + byte[] tmp = new byte[fs.Length]; + + fs.Read(tmp, 0, tmp.Length); + + stream.Write(tmp, 0, tmp.Length); + } + } + } +} + diff --git a/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/UndoAction.cs b/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/UndoAction.cs index 4dde891b33..00327ad6df 100644 --- a/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/UndoAction.cs +++ b/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/UndoAction.cs @@ -14,6 +14,6 @@ namespace HexEditor.Util /// public enum UndoAction { - Add, Remove, Overwrite + Insert, Remove, Overwrite } } diff --git a/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/UndoManager.cs b/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/UndoManager.cs index 13088c76a8..bb41ccfb7b 100644 --- a/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/UndoManager.cs +++ b/src/AddIns/DisplayBindings/HexEditor/Project/Src/Util/UndoManager.cs @@ -45,7 +45,6 @@ namespace HexEditor.Util /// Adds a step to the stack. /// /// The step to add. - /// Used internally, don't use! internal void AddUndoStep(UndoStep step) { UndoStack.Push(step); @@ -56,6 +55,21 @@ namespace HexEditor.Util temp(this, new UndoEventArgs(step, false)); } + internal void AddOverwriteStep(int start, byte[] bytes, byte[] oldBytes) + { + this.AddUndoStep(new UndoStep(bytes, oldBytes, start, UndoAction.Overwrite)); + } + + internal void AddInsertStep(int start, byte[] bytes) + { + this.AddUndoStep(new UndoStep(bytes, null, start, UndoAction.Insert)); + } + + internal void AddRemoveStep(int start, byte[] bytes) + { + this.AddUndoStep(new UndoStep(bytes, null, start, UndoAction.Remove)); + } + /// /// Undoes the last step. /// @@ -68,7 +82,7 @@ namespace HexEditor.Util RedoStack.Push(step); UndoStack.Pop(); switch (step.Action) { - case UndoAction.Add : + case UndoAction.Insert : buffer.SetBytes(step.Start, step.GetBytes(), false); break; case UndoAction.Remove : @@ -99,7 +113,7 @@ namespace HexEditor.Util UndoStack.Push(step); RedoStack.Pop(); switch (step.Action) { - case UndoAction.Add : + case UndoAction.Insert : buffer.RemoveBytes(step.Start, step.GetBytes().Length); break; case UndoAction.Remove : diff --git a/src/AddIns/DisplayBindings/HexEditor/Project/Src/View/HexEditContainer.cs b/src/AddIns/DisplayBindings/HexEditor/Project/Src/View/HexEditContainer.cs index bff815137e..1b9587b908 100644 --- a/src/AddIns/DisplayBindings/HexEditor/Project/Src/View/HexEditContainer.cs +++ b/src/AddIns/DisplayBindings/HexEditor/Project/Src/View/HexEditContainer.cs @@ -44,6 +44,8 @@ namespace HexEditor.View ToolStripControlHost viewMode = new ToolStripControlHost(tCBViewMode); this.toolStrip1.Items.Insert(3, viewMode); + + tSTBCharsPerLine.Text = hexEditControl.BytesPerLine.ToString(); this.hexEditControl.ContextMenuStrip = MenuService.CreateContextMenu(this.hexEditControl, "/AddIns/HexEditor/Editor/ContextMenu"); tCBViewMode.SelectedIndex = 0; diff --git a/src/AddIns/DisplayBindings/HexEditor/Project/changes.txt b/src/AddIns/DisplayBindings/HexEditor/Project/changes.txt index eda2140214..b100dfb2f8 100644 --- a/src/AddIns/DisplayBindings/HexEditor/Project/changes.txt +++ b/src/AddIns/DisplayBindings/HexEditor/Project/changes.txt @@ -19,7 +19,6 @@ version: 0.0.2 Known bugs/Problems: -1) Might be good to be able to change individual hex parts of a byte. -2) Might be good if the next hex value to be typed in was highlighted +1) Might be good if the next hex value to be typed in was highlighted in the hex display. -3) Change data structures (crashes when opening big files) \ No newline at end of file +2) Change data structures (crashes when opening big files) \ No newline at end of file