/// ///<summary>Insert (or Append) a segment collection at a given offset</summary> /// public void Insert(SegmentCollection sc, long offset) { long mapping; Util.List <Segment> .Node node; Segment s = FindSegment(offset, out mapping, out node); // offset not found, check if we have to append if (s == null) { if ((node == null && offset == 0) || (node != null && offset == mapping + node.data.Size)) { Util.List <Segment> lst = sc.List; int N = lst.Count; Util.List <Segment> .Node n = lst.First; for (int i = 0; i < N; i++) { Append(n.data); n = n.next; } } return; } if (mapping == offset) // start of segment? // insert data from the current node backwards { Util.List <Segment> lst = sc.List; int N = lst.Count; Util.List <Segment> .Node n = lst.Last; for (int i = 0; i < N; i++) { node = InsertBefore(node, n.data); n = n.prev; } // update cache SetCache(node, mapping); } else //middle of segment { Segment s1 = s.SplitAt(offset - mapping); list.InsertAfter(node, s1); Util.List <Segment> lst = sc.List; int N = lst.Count; Util.List <Segment> .Node n = lst.First; for (int i = 0; i < N; i++) { node = InsertAfter(node, n.data); n = n.next; } } }
public SegmentCollection GetRange(long pos1, long pos2) { long mapping1, mapping2; Util.List <Segment> .Node node1; Util.List <Segment> .Node node2; // Find the segments of the end points. // Search for the ending point first so that we won't // have to invalidate the cache later Segment s2 = FindSegment(pos2, out mapping2, out node2); Segment s1 = FindSegment(pos1, out mapping1, out node1); if (s1 == null || s2 == null) { return(null); } if (ReferenceEquals(node1, node2)) { SegmentCollection scTemp = new SegmentCollection(); Segment seg = new Segment(s1.Buffer, pos1 - mapping1 + s1.Start, pos2 - mapping1 + s1.Start); scTemp.Append(seg); return(scTemp); } // try to split the ending segment Segment sl = new Segment(s2.Buffer, s2.Start, pos2 - mapping2 + s2.Start); // try to split the starting segment Segment sf = new Segment(s1.Buffer, pos1 - mapping1 + s1.Start, s1.End); SegmentCollection sc = new SegmentCollection(); // append the first segment sc.Append(sf); Util.List <Segment> .Node n = node1.next; // append to new and remove from old // all segments up to node2 while (ReferenceEquals(n, node2) == false) { sc.Append(new Segment(n.data.Buffer, n.data.Start, n.data.End)); n = n.next; } sc.Append(sl); return(sc); }
public override void Do() { if (seg == null) { return; } SegmentCollection tmp = new SegmentCollection(); // use copy of segment seg to protect it from alterations tmp.Append(new Segment(seg.Buffer, seg.Start, seg.End)); byteBuf.segCol.Insert(tmp, pos); byteBuf.size += seg.Size; }
///<summary> /// Close the file associated with the ByteBuffer ///</summary> public void CloseFile() { lock (LockObj) { // close the file buffer and dispose the file watcher if (fileBuf != null && fileOperationsAllowed) { fileBuf.Close(); fsw.Dispose(); fsw = null; segCol = null; // buffer is in an unreadable state... this.ReadAllowed = false; } } }
///<summary> /// Sets the file buffer and resets the segment collection ///</summary> private void LoadWithFile(string filename) { if (fileBuf == null) { fileBuf = new FileBuffer(filename, 0xffff); // 64KB buffer } else { fileBuf.Load(filename); } Segment s = new Segment(fileBuf, 0, fileBuf.Size - 1); segCol = new SegmentCollection(); segCol.Append(s); size = fileBuf.Size; SetupFSW(); }
public ByteBuffer() { segCol = new SegmentCollection(); undoDeque = new Deque <ByteBufferAction>(); redoDeque = new Deque <ByteBufferAction>(); size = 0; SaveCheckpoint = null; // name the buffer automatically autoFilename = Catalog.GetString("Untitled") + " " + ByteBuffer.autoNum; ByteBuffer.autoNum++; // set default permissions readAllowed = true; fileOperationsAllowed = true; modifyAllowed = true; saveFinishedEvent = new AutoResetEvent(false); useGLibIdle = false; emitEvents = true; maxUndoActions = -1; // unlimited undo tempDir = Path.GetTempPath(); }
protected override void DoOperation() { stageReached = SaveInPlaceStage.BeforeClose; // hold a reference to the bytebuffer's segment collection // because it is lost when the file is closed SegmentCollection segCol = byteBuffer.segCol; // close file if (!cancelled) { // close the file, make sure that File Operations // are temporarily allowed lock (byteBuffer.LockObj) { // CloseFile invalidates the file buffer, // so make sure undo/redo data stays valid byteBuffer.MakePrivateCopyOfUndoRedo(); byteBuffer.FileOperationsAllowed = true; byteBuffer.CloseFile(); byteBuffer.FileOperationsAllowed = false; } } // Open the file for editing fs = new FileStream(savePath, FileMode.Open, FileAccess.Write); stageReached = SaveInPlaceStage.BeforeWrite; const int blockSize = 0xffff; byte[] baTemp = new byte[blockSize]; // // Just save the changed parts... // Util.List <Segment> .Node node = segCol.List.First; // hold the mapping of the start of the current segment // (at which offset in the file it is mapped) long mapping = 0; while (node != null && !cancelled) { // Save the data in the node // in blocks of blockSize each Segment s = node.data; // if the segment belongs to the original buffer, skip it if (s.Buffer.GetType() == typeof(FileBuffer)) { mapping += s.Size; node = node.next; continue; } long len = s.Size; long nBlocks = len / blockSize; int last = (int)(len % blockSize); // bytes in last block long i; // move the file cursor to the current mapping fs.Seek(mapping, SeekOrigin.Begin); bytesSaved = mapping; // for every full block for (i = 0; i < nBlocks; i++) { s.Buffer.Read(baTemp, 0, s.Start + i * blockSize, blockSize); fs.Write(baTemp, 0, blockSize); bytesSaved = (i + 1) * blockSize; if (cancelled) { break; } } // if last non-full block is not empty if (last != 0 && !cancelled) { s.Buffer.Read(baTemp, 0, s.Start + i * blockSize, last); fs.Write(baTemp, 0, last); } mapping += s.Size; node = node.next; } fs.Close(); fs = null; }
///<summary>Delete a range from the collection</summary> public SegmentCollection DeleteRange(long pos1, long pos2) { long mapping1, mapping2; Util.List <Segment> .Node node1; Util.List <Segment> .Node node2; // Find the segments of the end points. // Search for the ending point first so that we won't // have to invalidate the cache later Segment s2 = FindSegment(pos2, out mapping2, out node2); Segment s1 = FindSegment(pos1, out mapping1, out node1); if (s1 == null || s2 == null) { return(null); } // ending segment == starting segment // needs special handling #region Special Handling if node1==node2 if (ReferenceEquals(node1, node2)) { bool remove_flag = false; // try to split segment at pos1 Segment s_f = s1.SplitAt(pos1 - mapping1); // if we can't, this means that pos1 is // at the beginning of the segment if (s_f == null) { s_f = s1; remove_flag = true; } // try to split s_f at pos2+1 // s_l is the ending part of s1 that we // should keep Segment s_l = s_f.SplitAt(pos2 - pos1 + 1); // if we can't split, this means that pos2 is // at the end of the segment, // otherwise add s_l after node1 (which contains s1) if (s_l != null) { list.InsertAfter(node1, s_l); } // if we should remove s1 if (remove_flag) { // try to set the cache if (node1.next != null) { SetCache(node1.next, mapping1); } else if (node1.prev != null) { Segment s = node1.prev.data; SetCache(node1.prev, mapping1 - s.Size); } else { InvalidateCache(); } list.Remove(node1); } //else leave the cache set as is (node1, mapping1) SegmentCollection s_c = new SegmentCollection(); s_c.Append(s_f); return(s_c); } #endregion // try to split the ending segment Segment sl = s2.SplitAt(pos2 - mapping2 + 1); // if we can't, this means that pos2 is the // at the end of the ending segment if (sl == null) { sl = s2; // set the whole segment for removal } else { list.InsertAfter(node2, sl); } Util.List <Segment> .Node n = node1.next; // try to split the starting segment Segment sf = s1.SplitAt(pos1 - mapping1); // if we can't, this means that pos1 is // at the beginning of the starting segment if (sf == null) { sf = s1; // try to set the cache if (node1.prev != null) { Segment s = node1.prev.data; SetCache(node1.prev, mapping1 - s.Size); } else { InvalidateCache(); } list.Remove(node1); // remove the whole segment } SegmentCollection sc = new SegmentCollection(); // append the first segment sc.Append(sf); // append to new and remove from old // all segments up to node2 while (ReferenceEquals(n, node2) == false) { sc.Append(n.data); Util.List <Segment> .Node p = n; n = n.next; // Remove() must be placed after n.next // because it sets n.next=null list.Remove(p); } // append and remove node2 list.Remove(n); sc.Append(n.data); return(sc); }
public override void Do() { del = byteBuf.segCol.DeleteRange(pos1, pos2); byteBuf.size -= pos2 - pos1 + 1; }