/* Copyright (C) 2014-2019 de4dot@gmail.com This file is part of dnSpy dnSpy is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. dnSpy is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with dnSpy. If not, see . */ using System; using System.Text; namespace dnSpy.Contracts.Hex { /// /// Contains a and a /// public readonly struct HexBufferSpan : IEquatable { /// /// true if this is a default instance that hasn't been initialized /// public bool IsDefault => Buffer is null; /// /// Gets the buffer /// public HexBuffer Buffer { get; } /// /// Gets the span /// public HexSpan Span { get; } /// /// Gets the length /// public HexPosition Length => Span.Length; /// /// true if this span covers everything from 0 to 2^64-1, inclusive /// public bool IsFull => Span.IsFull; /// /// true if it's an empty span /// public bool IsEmpty => Span.IsEmpty; /// /// Gets the start point /// public HexBufferPoint Start => new HexBufferPoint(Buffer, Span.Start); /// /// Gets the end point. This can be 0 if the last byte is at position 2^64-1 /// public HexBufferPoint End => new HexBufferPoint(Buffer, Span.End); /// /// Constructor /// /// Buffer /// Span public HexBufferSpan(HexBuffer buffer, HexSpan span) { Buffer = buffer ?? throw new ArgumentNullException(nameof(buffer)); Span = span; } /// /// Constructor /// /// Buffer /// Start point /// Length public HexBufferSpan(HexBuffer buffer, HexPosition start, ulong length) { Buffer = buffer ?? throw new ArgumentNullException(nameof(buffer)); Span = new HexSpan(start, length); } /// /// Constructor /// /// Start position /// End position public HexBufferSpan(HexBufferPoint start, HexBufferPoint end) { if (start.Buffer != end.Buffer || start.Buffer is null) throw new ArgumentException(); if (end.Position < start.Position) throw new ArgumentOutOfRangeException(nameof(end)); Buffer = start.Buffer; Span = HexSpan.FromBounds(start, end); } /// /// Constructor /// /// Start point /// Length public HexBufferSpan(HexBufferPoint start, ulong length) { if (start.Buffer is null) throw new ArgumentException(); Buffer = start.Buffer; Span = new HexSpan(start, length); } /// /// Creates a new instance /// /// Start point /// End point public static HexBufferSpan FromBounds(HexBufferPoint start, HexBufferPoint end) => new HexBufferSpan(start, end); /// /// Converts this instance to a /// /// public static implicit operator HexSpan(HexBufferSpan hexBufferSpan) => hexBufferSpan.Span; /// /// Gets the data /// /// public byte[] GetData() => Buffer.ReadBytes(Span); /// /// Returns true if lies within this span /// /// Point /// public bool Contains(HexBufferPoint point) { if (point.Buffer != Buffer) throw new ArgumentException(); return Span.Contains(point); } /// /// Returns true if lies within this span /// /// Span /// public bool Contains(HexSpan span) => Span.Contains(span); /// /// Returns true if lies within this span /// /// Span /// public bool Contains(HexBufferSpan span) { if (span.Buffer != Buffer) throw new ArgumentException(); return Span.Contains(span.Span); } /// /// Returns true if lies within this span /// /// Position /// public bool Contains(HexPosition position) => Span.Contains(position); /// /// Returns true if this instances overlaps with /// /// /// public bool OverlapsWith(HexSpan span) => Span.OverlapsWith(span); /// /// Returns true if this instances overlaps with /// /// /// public bool OverlapsWith(HexBufferSpan span) { if (span.Buffer != Buffer) throw new ArgumentException(); return Span.OverlapsWith(span.Span); } /// /// Gets the overlap with or null if there's none /// /// Span /// public HexBufferSpan? Overlap(HexSpan span) { var res = Span.Overlap(span); if (res is null) return null; return new HexBufferSpan(Buffer, res.Value); } /// /// Gets the overlap with or null if there's none /// /// Span /// public HexBufferSpan? Overlap(HexBufferSpan span) { if (span.Buffer != Buffer) throw new ArgumentException(); var res = Span.Overlap(span.Span); if (res is null) return null; return new HexBufferSpan(Buffer, res.Value); } /// /// Returns true if intersects with this instance /// /// Span /// public bool IntersectsWith(HexSpan span) => Span.IntersectsWith(span); /// /// Returns true if intersects with this instance /// /// Span /// public bool IntersectsWith(HexBufferSpan span) { if (span.Buffer != Buffer) throw new ArgumentException(); return Span.IntersectsWith(span.Span); } /// /// Returns the intersection or null if there's none /// /// Span /// public HexBufferSpan? Intersection(HexSpan span) { var res = Span.Intersection(span); if (res is null) return null; return new HexBufferSpan(Buffer, res.Value); } /// /// Returns the intersection or null if there's none /// /// Span /// public HexBufferSpan? Intersection(HexBufferSpan span) { if (span.Buffer != Buffer) throw new ArgumentException(); var res = Span.Intersection(span.Span); if (res is null) return null; return new HexBufferSpan(Buffer, res.Value); } /// /// operator ==() /// /// /// /// public static bool operator ==(HexBufferSpan a, HexBufferSpan b) => a.Equals(b); /// /// operator !=() /// /// /// /// public static bool operator !=(HexBufferSpan a, HexBufferSpan b) => !a.Equals(b); /// /// Equals() /// /// Other instance /// public bool Equals(HexBufferSpan other) => Buffer == other.Buffer && Span == other.Span; /// /// Equals() /// /// Object /// public override bool Equals(object? obj) => obj is HexBufferSpan && Equals((HexBufferSpan)obj); /// /// GetHashCode() /// /// public override int GetHashCode() => (Buffer?.GetHashCode() ?? 0) ^ Span.GetHashCode(); /// /// ToString() /// /// public override string ToString() { if (Buffer is null) return "uninit"; const int maxBytes = 16; const string ellipsis = "..."; bool tooMuchData = Length > maxBytes; var sb = new StringBuilder(); sb.Append(Span.ToString()); sb.Append("_'"); var pos = Span.Start; for (int i = 0; i < Length && i < maxBytes; i++) { var c = pos < HexPosition.MaxEndPosition ? Buffer.TryReadByte(pos++) : -1; sb.Append(c < 0 ? "??" : c.ToString("X2")); } if (tooMuchData) sb.Append(ellipsis); sb.Append("'"); return sb.ToString(); } } }