Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/monodevelop.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLluis Sanchez <llsan@microsoft.com>2019-02-15 20:12:13 +0300
committerLluis Sanchez <llsan@microsoft.com>2019-02-15 20:12:13 +0300
commit3f08768e1c48470d3c77365bf1225e2f48ad8fbc (patch)
tree31ac4323b208b15e2d94003474b4692957e12054 /main/src/addins/MonoDevelop.HexEditor
parentbdfc0bf3853e15761c4433af1a83362b6b81012d (diff)
Add basic service infrastructure
Diffstat (limited to 'main/src/addins/MonoDevelop.HexEditor')
-rw-r--r--main/src/addins/MonoDevelop.HexEditor/Mono.MHex.Data/ByteBuffer.cs275
-rw-r--r--main/src/addins/MonoDevelop.HexEditor/Mono.MHex.Data/ByteBufferModel.cs102
2 files changed, 377 insertions, 0 deletions
diff --git a/main/src/addins/MonoDevelop.HexEditor/Mono.MHex.Data/ByteBuffer.cs b/main/src/addins/MonoDevelop.HexEditor/Mono.MHex.Data/ByteBuffer.cs
new file mode 100644
index 0000000000..294c0d6b4c
--- /dev/null
+++ b/main/src/addins/MonoDevelop.HexEditor/Mono.MHex.Data/ByteBuffer.cs
@@ -0,0 +1,275 @@
+//
+// ByteBuffer.cs
+//
+// Author:
+// Lluis Sanchez <llsan@microsoft.com>
+//
+// Copyright (c) 2019 Microsoft
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Collections.Generic;
+
+namespace Mono.MHex.Data
+{
+ class ByteBuffer
+ {
+ PieceTable pieceTable = new PieceTable ();
+ ByteAddBuffer addBuffer = new ByteAddBuffer ();
+ IBuffer buffer = new ArrayBuffer (new byte [0]);
+ long lastChangeOffset;
+
+ class ByteAddBuffer : IBuffer
+ {
+ public List<byte> Bytes { get; } = new List<byte> ();
+
+ public long Length => Bytes.Count;
+
+ public byte [] GetBytes (long offset, int count)
+ {
+ byte [] result = new byte [count];
+ Bytes.CopyTo ((int)offset, result, 0, count);
+ return result;
+ }
+ }
+
+ public IBuffer Buffer {
+ get {
+ return this.buffer;
+ }
+ set {
+ this.buffer = value;
+ pieceTable.SetBuffer (buffer);
+ }
+ }
+
+ public IBuffer AddBuffer {
+ get {
+ return this.addBuffer;
+ }
+ }
+
+ public long Length {
+ get {
+ return pieceTable.Length;
+ }
+ }
+
+ public byte [] Bytes {
+ get {
+ return GetBytes (0, (int)Length);
+ }
+ }
+
+ public byte [] GetBytes (long offset, int count)
+ {
+ if (count == 0)
+ return new byte [0];
+ var node = pieceTable.GetTreeNodeAtOffset (offset);
+ if (node == null)
+ return new byte [0];
+ long nodeOffset = node.value.CalcOffset (node);
+ long nodeEndOffset = nodeOffset + node.value.Length;
+ if (offset + count < nodeEndOffset)
+ return node.value.GetBytes (this, nodeOffset, offset, count);
+ byte [] nodeBytes = node.value.GetBytes (this, nodeOffset, offset, (int)(nodeEndOffset - offset));
+
+ byte [] result = new byte [count];
+ if (nodeBytes.Length > 0) {
+ nodeBytes.CopyTo (result, 0);
+ GetBytes (offset + nodeBytes.Length, count - nodeBytes.Length).CopyTo (result, nodeBytes.Length);
+ }
+ return result;
+ }
+
+ public byte GetByte (long offset)
+ {
+ return GetBytes (offset, 1) [0];
+ }
+
+ public void Replace (long offset, long count, params byte [] data)
+ {
+ if (!isInUndo)
+ BeginAtomicUndo ();
+ if (count > 0)
+ pieceTable.Remove (offset, count);
+ if (data != null && data.Length > 0) {
+ int addBufferOffset = addBuffer.Bytes.Count;
+ long length = data.Length;
+ addBuffer.Bytes.AddRange (data);
+ pieceTable.Insert (offset, addBufferOffset, length);
+ }
+ lastChangeOffset = offset + data.Length;
+ OnReplaced (new ReplaceEventArgs (offset, count, data));
+ if (!isInUndo)
+ EndAtomicUndo ();
+ }
+
+ public void Insert (long offset, params byte [] data)
+ {
+ if (!isInUndo)
+ BeginAtomicUndo ();
+ int addBufferOffset = addBuffer.Bytes.Count;
+ long length = data.Length;
+ addBuffer.Bytes.AddRange (data);
+ pieceTable.Insert (offset, addBufferOffset, length);
+ lastChangeOffset = offset + data.Length;
+ OnReplaced (new ReplaceEventArgs (offset, 0, data));
+ if (!isInUndo)
+ EndAtomicUndo ();
+ }
+
+ public void Remove (ISegment segment)
+ {
+ Remove (segment.Offset, segment.Length);
+ }
+
+ public void Remove (long offset, long count)
+ {
+ if (!isInUndo)
+ BeginAtomicUndo ();
+ pieceTable.Remove (offset, count);
+ lastChangeOffset = offset;
+ OnReplaced (new ReplaceEventArgs (offset, count, null));
+ if (!isInUndo)
+ EndAtomicUndo ();
+ if (Length == 0)
+ Insert (0, new byte [] { 0 });
+ }
+
+ protected virtual void OnReplaced (ReplaceEventArgs args)
+ {
+ if (Replaced != null)
+ Replaced (this, args);
+ }
+
+ Stack<UndoOperation> undoStack = new Stack<UndoOperation> ();
+ Stack<UndoOperation> redoStack = new Stack<UndoOperation> ();
+ UndoOperation currentAtomicOperation;
+
+ bool isInUndo = false;
+ int atomicUndoLevel;
+
+ public bool CanUndo {
+ get {
+ return undoStack.Count > 0;
+ }
+ }
+
+ public bool CanRedo {
+ get {
+ return redoStack.Count > 0;
+ }
+ }
+
+ public void BeginAtomicUndo ()
+ {
+ if (currentAtomicOperation == null) {
+ currentAtomicOperation = new UndoOperation ();
+ currentAtomicOperation.undoNode = pieceTable.tree.Root.Clone ();
+ currentAtomicOperation.undoCaret = lastChangeOffset;
+ }
+ atomicUndoLevel++;
+ }
+
+ public void EndAtomicUndo ()
+ {
+ atomicUndoLevel--;
+
+ if (atomicUndoLevel == 0 && currentAtomicOperation != null) {
+ currentAtomicOperation.redoNode = pieceTable.tree.Root.Clone ();
+ currentAtomicOperation.redoCaret = lastChangeOffset;
+ undoStack.Push (currentAtomicOperation);
+ redoStack.Clear ();
+ currentAtomicOperation = null;
+ }
+ }
+
+ public void Undo ()
+ {
+ if (undoStack.Count <= 0)
+ return;
+ isInUndo = true;
+ UndoOperation operation = undoStack.Pop ();
+ operation.Undo (this);
+ redoStack.Push (operation);
+ isInUndo = false;
+ OnUndone (new UndoOperationEventArgs (operation.undoCaret));
+ }
+
+ internal protected virtual void OnUndone (UndoOperationEventArgs e)
+ {
+ EventHandler<UndoOperationEventArgs> handler = this.Undone;
+ if (handler != null)
+ handler (this, e);
+ }
+
+ public event EventHandler<UndoOperationEventArgs> Undone;
+
+ public void Redo ()
+ {
+ if (redoStack.Count <= 0)
+ return;
+ isInUndo = true;
+ UndoOperation operation = redoStack.Pop ();
+ operation.Redo (this);
+ undoStack.Push (operation);
+ isInUndo = false;
+ OnRedone (new UndoOperationEventArgs (operation.redoCaret));
+ }
+
+ internal protected virtual void OnRedone (UndoOperationEventArgs e)
+ {
+ EventHandler<UndoOperationEventArgs> handler = this.Redone;
+ if (handler != null)
+ handler (this, e);
+ }
+
+ public event EventHandler<UndoOperationEventArgs> Redone;
+
+ public event EventHandler<ReplaceEventArgs> Replaced;
+
+ public class UndoOperation
+ {
+ internal RedBlackTree<PieceTable.TreeNode>.RedBlackTreeNode undoNode;
+ internal long undoCaret;
+
+ internal RedBlackTree<PieceTable.TreeNode>.RedBlackTreeNode redoNode;
+ internal long redoCaret;
+
+ public UndoOperation ()
+ {
+ }
+
+ public virtual void Undo (ByteBuffer data)
+ {
+ if (undoNode == null)
+ throw new NullReferenceException ("undoNode == null");
+ data.pieceTable.tree.Root = undoNode;
+ }
+
+ public virtual void Redo (ByteBuffer data)
+ {
+ if (redoNode == null)
+ throw new NullReferenceException ("redoNode == null");
+ data.pieceTable.tree.Root = redoNode;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/main/src/addins/MonoDevelop.HexEditor/Mono.MHex.Data/ByteBufferModel.cs b/main/src/addins/MonoDevelop.HexEditor/Mono.MHex.Data/ByteBufferModel.cs
new file mode 100644
index 0000000000..89205fe6be
--- /dev/null
+++ b/main/src/addins/MonoDevelop.HexEditor/Mono.MHex.Data/ByteBufferModel.cs
@@ -0,0 +1,102 @@
+//
+// ByteBufferModel.cs
+//
+// Author:
+// Lluis Sanchez <llsan@microsoft.com>
+//
+// Copyright (c) 2019 Microsoft
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in
+// all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+// THE SOFTWARE.
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Threading.Tasks;
+using MonoDevelop.Ide.Gui.Documents;
+
+namespace Mono.MHex.Data
+{
+ class ByteBufferModel: FileModel
+ {
+ public ByteBuffer ByteBuffer => GetRepresentation<ByteBufferModelRepresentation> ().ByteBuffer;
+
+ public event EventHandler ByteBufferInstanceChanged;
+
+ protected override void OnRepresentationChanged ()
+ {
+ base.OnRepresentationChanged ();
+ ByteBufferInstanceChanged?.Invoke (this, EventArgs.Empty);
+ }
+
+ protected class ByteBufferModelRepresentation : FileModelRepresentation
+ {
+ ByteBuffer byteBuffer;
+
+ internal ByteBuffer ByteBuffer => byteBuffer;
+
+ protected override Stream OnGetContent ()
+ {
+ return new MemoryStream (byteBuffer.Bytes);
+ }
+
+ protected override async Task OnLoad ()
+ {
+ byteBuffer = new ByteBuffer ();
+ byteBuffer.Replaced += ByteBuffer_Replaced;
+ using (var stream = File.OpenRead (FilePath)) {
+ byteBuffer.Buffer = await ArrayBuffer.LoadAsync (stream);
+ }
+ }
+
+ protected override void OnCreateNew ()
+ {
+ byteBuffer = new ByteBuffer ();
+ byteBuffer.Buffer = new ArrayBuffer (new byte [0]);
+ }
+
+ protected override Task OnSave ()
+ {
+ File.WriteAllBytes (FilePath, byteBuffer.Bytes);
+ return Task.CompletedTask;
+ }
+
+ protected override async Task OnSetContent (Stream content)
+ {
+ byteBuffer.Buffer = await ArrayBuffer.LoadAsync (content);
+ }
+
+ void ByteBuffer_Replaced (object sender, ReplaceEventArgs e)
+ {
+ NotifyChanged ();
+ }
+ }
+ }
+
+ public class UndoOperationEventArgs : EventArgs
+ {
+ public long BufferOffset {
+ get;
+ private set;
+ }
+
+ public UndoOperationEventArgs (long offset)
+ {
+ this.BufferOffset = offset;
+ }
+ }
+}