/// <summary> /// Constructor /// </summary> /// <param name="start">Start position</param> /// <param name="end">End position</param> public HexBufferSpan(HexBufferPoint start, HexBufferPoint end) { if (start.Buffer != end.Buffer || start.Buffer == null) { throw new ArgumentException(); } if (end.Position < start.Position) { throw new ArgumentOutOfRangeException(nameof(end)); } Buffer = start.Buffer; Span = HexSpan.FromBounds(start, end); }
/// <summary> /// Gets information about a position in the stream /// </summary> /// <param name="position">Position</param> /// <param name="validSpan">Span of all valid data</param> /// <returns></returns> protected HexSpanInfo GetSpanInfo(HexPosition position, HexSpan validSpan) { if (position >= HexPosition.MaxEndPosition) { throw new ArgumentOutOfRangeException(nameof(position)); } if (position >= validSpan.End) { return(new HexSpanInfo(HexSpan.FromBounds(validSpan.End, HexPosition.MaxEndPosition), HexSpanInfoFlags.None)); } else if (position < validSpan.Start) { return(new HexSpanInfo(HexSpan.FromBounds(HexPosition.Zero, validSpan.Start), HexSpanInfoFlags.None)); } else { return(new HexSpanInfo(validSpan, HexSpanInfoFlags.HasData)); } }
/// <summary> /// Gets the previous valid span or null if there's none left. This includes the input /// (<paramref name="position"/>) if it happens to lie within this valid span. /// This method merges all consecutive valid spans. /// </summary> /// <param name="position">Start position to check</param> /// <param name="lowerBounds">End position</param> /// <param name="fullSpan">true if positions after <paramref name="position"/> should be included /// in the returned result. This could result in worse performance.</param> /// <returns></returns> public HexSpan?GetPreviousValidSpan(HexPosition position, HexPosition lowerBounds, bool fullSpan) { if (position >= HexPosition.MaxEndPosition) { throw new ArgumentOutOfRangeException(nameof(position)); } if (lowerBounds > HexPosition.MaxEndPosition) { throw new ArgumentOutOfRangeException(nameof(lowerBounds)); } bool checkForwards = true; while (position >= lowerBounds) { var info = GetSpanInfo(position); if (info.HasData) { var start = GetStartOfData(info.Span.Start, validData: true); var end = info.Span.End; if (fullSpan && checkForwards) { while (end < HexPosition.MaxEndPosition) { info = GetSpanInfo(end); if (!info.HasData) { break; } end = info.Span.End; } } return(HexSpan.FromBounds(start, end)); } checkForwards = false; position = GetStartOfData(info.Span.Start, validData: false); if (position == HexPosition.Zero) { break; } position = position - 1; } return(null); }
/// <summary> /// Gets the next valid span or null if there's none left. This includes the input /// (<paramref name="position"/>) if it happens to lie within this valid span. /// This method merges all consecutive valid spans. /// </summary> /// <param name="position">Start position to check</param> /// <param name="upperBounds">End position</param> /// <param name="fullSpan">true if positions before <paramref name="position"/> should be included /// in the returned result. This could result in worse performance.</param> /// <returns></returns> public HexSpan?GetNextValidSpan(HexPosition position, HexPosition upperBounds, bool fullSpan) { if (position >= HexPosition.MaxEndPosition) { throw new ArgumentOutOfRangeException(nameof(position)); } if (upperBounds > HexPosition.MaxEndPosition) { throw new ArgumentOutOfRangeException(nameof(upperBounds)); } bool checkBackwards = true; while (position < upperBounds) { var info = GetSpanInfo(position); if (info.HasData) { var start = info.Span.Start; var end = info.Span.End; // We use MaxEndPosition and not upperBounds here since we must merge // all consecutive spans even if some of them happen to be outside the // requested range. while (end < HexPosition.MaxEndPosition) { info = GetSpanInfo(end); if (!info.HasData) { break; } end = info.Span.End; } if (fullSpan && checkBackwards) { start = GetStartOfData(start, validData: true); } return(HexSpan.FromBounds(start, end)); } checkBackwards = false; position = info.Span.End; } return(null); }
IEnumerable <TextAndHexSpan> GetTextAndHexSpans(bool isColumnPresent, HexCellCollection collection, HexBufferSpan span, HexSpanSelectionFlags flags, VST.Span visibleSpan, VST.Span fullSpan) { if (span.IsDefault) { throw new ArgumentException(); } if (span.Buffer != Buffer) { throw new ArgumentException(); } if (!isColumnPresent) { yield break; } var overlapSpan = BufferSpan.Overlap(span); if (overlapSpan == null) { yield break; } if ((flags & (HexSpanSelectionFlags.Group0 | HexSpanSelectionFlags.Group1)) != 0) { bool group0 = (flags & HexSpanSelectionFlags.Group0) != 0; bool group1 = (flags & HexSpanSelectionFlags.Group1) != 0; IEnumerable <HexCell> cells; if ((flags & HexSpanSelectionFlags.AllCells) != 0) { cells = collection.GetCells(); overlapSpan = BufferSpan; } else if ((flags & HexSpanSelectionFlags.AllVisibleCells) != 0) { cells = collection.GetVisibleCells(); overlapSpan = BufferSpan; } else { cells = collection.GetCells(overlapSpan.Value); } HexCell firstCell = null; HexCell lastCell = null; foreach (var cell in cells) { if (!((cell.GroupIndex == 0 && group0) || (cell.GroupIndex == 1 && group1))) { continue; } if (firstCell == null) { firstCell = cell; lastCell = cell; } else if (lastCell.Index + 1 == cell.Index && lastCell.GroupIndex == cell.GroupIndex) { lastCell = cell; } else { yield return(Create(collection, firstCell, lastCell, overlapSpan.Value)); firstCell = lastCell = cell; } } if (firstCell != null) { yield return(Create(collection, firstCell, lastCell, overlapSpan.Value)); } yield break; } if ((flags & HexSpanSelectionFlags.AllVisibleCells) != 0) { yield return(new TextAndHexSpan(visibleSpan, BufferSpan)); yield break; } if ((flags & HexSpanSelectionFlags.AllCells) != 0) { yield return(new TextAndHexSpan(fullSpan, BufferSpan)); yield break; } if ((flags & HexSpanSelectionFlags.OneValue) != 0) { foreach (var cell in collection.GetCells(overlapSpan.Value)) { if (!cell.HasData) { continue; } var cellSpan = cell.GetSpan(flags); yield return(new TextAndHexSpan(cellSpan, new HexBufferSpan(Buffer, cell.BufferSpan))); } } else { int textStart = int.MaxValue; int textEnd = int.MinValue; var posStart = HexPosition.MaxValue; var posEnd = HexPosition.MinValue; foreach (var cell in collection.GetCells(overlapSpan.Value)) { if (!cell.HasData) { continue; } var cellSpan = cell.GetSpan(flags); textStart = Math.Min(textStart, cellSpan.Start); textEnd = Math.Max(textEnd, cellSpan.End); posStart = HexPosition.Min(posStart, cell.BufferStart); posEnd = HexPosition.Max(posEnd, cell.BufferEnd); } if (textStart > textEnd || posStart > posEnd) { yield break; } yield return(new TextAndHexSpan(VST.Span.FromBounds(textStart, textEnd), new HexBufferSpan(Buffer, HexSpan.FromBounds(posStart, posEnd)))); } }