/// <summary> /// Reads a <see cref="byte"/> /// </summary> /// <param name="position">Position</param> /// <returns></returns> public abstract byte ReadByte(HexPosition position);
/// <summary> /// Reads a <see cref="sbyte"/> /// </summary> /// <param name="position">Position</param> /// <returns></returns> public abstract sbyte ReadSByte(HexPosition position);
/// <summary> /// Tries to read a <see cref="byte"/>. If there's no data, a value less than 0 is returned. /// </summary> /// <param name="position">Position</param> /// <returns></returns> public abstract int TryReadByte(HexPosition position);
/// <summary> /// Reads a <see cref="char"/> /// </summary> /// <param name="position">Position</param> /// <returns></returns> public char ReadChar(HexPosition position) => (char)ReadUInt16(position);
/// <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="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, bool fullSpan) => GetPreviousValidSpan(position, HexPosition.Zero, fullSpan);
// If the underlying stream is a memory stream, VirtualQueryEx() gets called but it only // scans forward and a simple loop results in extremely poor PERF, and the code appears // to have hung if the input position is in a big block with lots of data or lots of no data. HexPosition GetStartOfDataCore(HexPosition start, bool validData) { var bestGuess = start; var pos = start; ulong d = 0x10000; while (pos > HexPosition.Zero) { var testPos = pos >= d ? pos - d : HexPosition.Zero; var info = GetSpanInfo(testPos); if (d < 0x8000_0000_0000_0000) { d <<= 1; } if (info.HasData == validData && info.Span.End >= bestGuess) { bestGuess = info.Span.Start; pos = info.Span.Start; continue; } if (info.HasData != validData && info.Span.End == bestGuess) { return(bestGuess); } pos = info.Span.End; var lastCorrectDataPos = info.HasData == validData ? info.Span.Start : (HexPosition?)null; bool foundOppositeData = info.HasData != validData; for (;;) { if (pos >= bestGuess) { return(lastCorrectDataPos ?? bestGuess); } info = GetSpanInfo(pos); if (info.HasData == validData) { if (lastCorrectDataPos == null) { lastCorrectDataPos = info.Span.Start; } } else { lastCorrectDataPos = null; foundOppositeData = true; } if (info.Span.End >= bestGuess) { pos = lastCorrectDataPos ?? bestGuess; if (foundOppositeData) { return(pos); } bestGuess = pos; break; } pos = info.Span.End; } } return(bestGuess); }
/// <summary> /// Gets information about a position in the buffer. The returned info isn't /// normalized, there may be consecutive spans with the same flags. It's the /// responsibility of the caller to merge such spans. /// </summary> /// <param name="position">Position</param> /// <returns></returns> public abstract HexSpanInfo GetSpanInfo(HexPosition position);
/// <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="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, bool fullSpan) => GetNextValidSpan(position, HexPosition.MaxEndPosition, fullSpan);
/// <summary> /// Add <paramref name="value"/> /// </summary> /// <param name="value">Value to add</param> /// <returns></returns> public HexBufferPoint Add(HexPosition value) => new HexBufferPoint(Buffer, Position + value);
/// <summary> /// Subtract <paramref name="value"/> /// </summary> /// <param name="value">Value</param> /// <returns></returns> public HexBufferPoint Subtract(HexPosition value) => new HexBufferPoint(Buffer, Position - value);
/// <summary> /// Returns the offset as a string /// </summary> /// <param name="position">Position</param> /// <returns></returns> public abstract string GetFormattedOffset(HexPosition position);
/// <summary> /// Converts a logical position to a physical (stream) position /// </summary> /// <param name="logicalPosition">Logical position</param> /// <returns></returns> public abstract HexPosition ToPhysicalPosition(HexPosition logicalPosition);
/// <summary> /// Converts a physical (stream) position to a logical position /// </summary> /// <param name="physicalPosition">Physical (stream) position</param> /// <returns></returns> public abstract HexPosition ToLogicalPosition(HexPosition physicalPosition);
/// <summary> /// Returns a line /// </summary> /// <param name="lineNumber">Line number</param> /// <returns></returns> public abstract HexBufferLine GetLineFromLineNumber(HexPosition lineNumber);
/// <summary> /// Gets the buffer position of a line /// </summary> /// <param name="lineNumber">Line number</param> /// <returns></returns> public abstract HexBufferPoint GetBufferPositionFromLineNumber(HexPosition lineNumber);