/*
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();
}
}
}