/// ///<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); }
///<summary>Inserts a segment before a node ///and merges them if possible</summary> private Util.List <Segment> .Node InsertBefore(Util.List <Segment> .Node n, Segment s) { if (n != null && n.data != null) { Segment ls = n.data; if ((s.Buffer == ls.Buffer) && (s.End + 1 == ls.Start)) { ls.Start = s.Start; return(n); } } return(list.InsertBefore(n, s)); }
///<summary>Append a segment to the collection</summary> public void Append(Segment s) { Util.List <Segment> .Node n = list.Last; if (n != null && n.data != null) { Segment ls = n.data; if ((s.Buffer == ls.Buffer) && (s.Start == ls.End + 1)) { ls.End = s.End; return; } } list.Append(s); }
protected override void DoOperation() { stageReached = SaveAsStage.BeforeCreate; if (!CheckFreeSpace(Path.GetDirectoryName(savePath), 0)) { string msg = string.Format(Catalog.GetString("There is not enough free space on the device to save file '{0}'."), savePath); throw new IOException(msg); } // try to open in append mode first, so that a sharing violation // doesn't end up with the file truncated (as opposed // to using FileMode.Create) fs = new FileStream(savePath, FileMode.Append, FileAccess.Write); fs.Close(); // do the actual create fs = new FileStream(savePath, FileMode.Create, FileAccess.Write); stageReached = SaveAsStage.BeforeWrite; const int blockSize = 0xffff; byte[] baTemp = new byte[blockSize]; // for every node Util.List <Segment> .Node node = byteBuffer.segCol.List.First; while (node != null && !cancelled) { // Save the data in the node // in blocks of blockSize each Segment s = node.data; long len = s.Size; long nBlocks = len / blockSize; int last = (int)(len % blockSize); // bytes in last block long i; // 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); } node = node.next; } fs.Close(); fs = null; }
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; }
private void SetCache(Util.List <Segment> .Node n, long map) { cachedNode = n; cachedMapping = map; }
private void InvalidateCache() { cachedNode = null; cachedMapping = 0; }
public SegmentCollection() { list = new Util.List <Segment>(); }
///<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); }
/// ///<summary>Find the segment that the given offset is mapped into</summary> /// public Segment FindSegment(long offset, out long OutMapping, out Util.List <Segment> .Node OutNode) { OutMapping = 0; OutNode = null; // if this is the first search // set up things if (cachedNode == null) { if (list.First == null) { return(null); } SetCache(list.First, 0); } Segment s = cachedNode.data; long curMapping = cachedMapping; Util.List <Segment> .Node curNode = cachedNode; // is the cached node the one we want? if (s.Contains(offset, curMapping) == true) { OutMapping = curMapping; OutNode = curNode; return(s); } // search towards the beginning if (offset < curMapping) { while (curNode.prev != null) { curNode = curNode.prev; s = curNode.data; curMapping -= s.Size; if (s.Contains(offset, curMapping) == true) { SetCache(curNode, curMapping); OutMapping = curMapping; OutNode = curNode; return(s); } } } else // search towards the end { while (curNode.next != null) { curMapping += s.Size; curNode = curNode.next; s = curNode.data; if (s.Contains(offset, curMapping) == true) { SetCache(curNode, curMapping); OutMapping = curMapping; OutNode = curNode; return(s); } } } // offset not found but return last accessed node info OutMapping = curMapping; OutNode = curNode; return(null); }