// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team // // 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.Windows.Forms; using ICSharpCode.AvalonEdit.Utils; using ICSharpCode.Core; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Workbench; namespace HexEditor.Util { /// /// Manages the data loaded into the hex editor. /// public class BufferManager { internal Control parent; OpenedFile currentFile; Stream stream; /// /// Currently used, but not good for really big files (like 590 MB) /// Rope buffer; /// /// Creates a new BufferManager and attaches it to a control. /// /// The parent control to attach to. public BufferManager(Control parent) { this.parent = parent; this.buffer = new Rope(); } /// /// Cleares the whole buffer. /// public void Clear() { this.buffer.Clear(); parent.Invalidate(); GC.Collect(); } /// /// Loads the data from a stream. /// public void Load(OpenedFile file, Stream stream) { this.currentFile = file; this.stream = stream; this.buffer.Clear(); ((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 / (double)reader.BaseStream.Length) * 100); } reader.Close(); } catch (OutOfMemoryException) { MessageService.ShowErrorFormatted("${res:FileUtilityService.FileSizeTooBig}"); } } else { MessageService.ShowErrorFormatted("${res:Fileutility.CantFindFileError}", currentFile.FileName); } 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(); } /// /// Writes all data to a stream. /// public void Save(OpenedFile file, Stream stream) { BinaryWriter writer = new BinaryWriter(stream); writer.Write(this.buffer.ToArray()); writer.Flush(); } /// /// 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; 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 buffer.ToArray(); } } /// /// The size of the current buffer. /// public int BufferSize { get { return buffer.Count; } } #region Methods public byte[] GetBytes(int start, int count) { if (buffer.Count == 0) return new byte[] {}; if (start < 0) start = 0; if (start >= buffer.Count) start = buffer.Count; if (count < 1) count = 1; if (count >= (buffer.Count - start)) count = (buffer.Count - start); return buffer.GetRange(start, count).ToArray(); } public byte GetByte(int offset) { if (buffer.Count == 0) return 0; if (offset < 0) offset = 0; if (offset >= buffer.Count) offset = buffer.Count - 1; return (byte)buffer[offset]; } public bool DeleteByte(int offset) { if ((offset < buffer.Count) & (offset > -1)) { buffer.RemoveAt(offset); return true; } return false; } public bool RemoveByte(int offset) { if ((offset < buffer.Count) & (offset > -1)) { buffer.RemoveAt(offset); return true; } return false; } public bool RemoveBytes(int offset, int length) { if (((offset < buffer.Count) && (offset > -1)) && ((offset + length) <= buffer.Count)) { buffer.RemoveRange(offset, length); return true; } return false; } public void SetBytes(int start, byte[] bytes, bool overwrite) { if (overwrite) { if (bytes.Length > buffer.Count) buffer.AddRange(new byte[bytes.Length - buffer.Count]); for (int i = start; i < start + bytes.Length; i++) buffer[i] = bytes[i - start]; } else { buffer.InsertRange(start, bytes); } } public void SetByte(int position, byte @byte, bool overwrite) { if (overwrite) { if (position > buffer.Count - 1) { buffer.Add(@byte); } else { buffer[position] = @byte; } } else { buffer.Insert(position, @byte); } } #endregion } }