using System;
using System.IO;
using System.Xml;
using System.Xml.Serialization;
namespace SabreTools.Skippers.Tests
{
///
/// Test that uses a byte mask OR against data
///
[XmlType("or")]
public class OrTest : Test
{
#region Fields
///
/// File offset to run the test
///
/// Either numeric or the literal "EOF"
[XmlAttribute("offset")]
public string? Offset
{
get => _offset == null ? "EOF" : _offset.Value.ToString();
set
{
if (value == null || value.ToLowerInvariant() == "eof")
_offset = null;
else
_offset = Convert.ToInt64(value, fromBase: 16);
}
}
///
/// Static value to be checked at the offset
///
/// Hex string representation of a byte array
[XmlAttribute("value")]
public string? Value
{
get => _value == null ? string.Empty : BitConverter.ToString(_value).Replace("-", string.Empty);
set => _value = ParseByteArrayFromHex(value);
}
///
/// Determines whether a pass or failure is expected
///
[XmlAttribute("result")]
public bool Result { get; set; } = true;
///
/// Byte mask to be applied to the tested bytes
///
/// Hex string representation of a byte array
[XmlAttribute("mask")]
public string? Mask
{
get => _mask == null ? string.Empty : BitConverter.ToString(_mask).Replace("-", string.Empty);
set => _mask = ParseByteArrayFromHex(value);
}
#endregion
#region Private instance variables
///
/// File offset to run the test
///
/// null is EOF
private long? _offset;
///
/// Static value to be checked at the offset
///
private byte[]? _value;
///
/// Byte mask to be applied to the tested bytes
///
private byte[]? _mask;
#endregion
///
public override bool Passes(Stream input)
{
// If we have an invalid mask
if (_mask == null || _mask.Length == 0)
return false;
// If we have an invalid value
if (_value == null || _value.Length == 0)
return false;
// Seek to the correct position, if possible
if (!Seek(input, _offset))
return false;
bool result = true;
try
{
// Then apply the mask if it exists
byte[] read = new byte[_mask.Length];
input.Read(read, 0, _mask.Length);
byte[] masked = new byte[_mask.Length];
for (int i = 0; i < read.Length; i++)
{
masked[i] = (byte)(read[i] | _mask[i]);
}
// Finally, compare it against the value
for (int i = 0; i < _value.Length; i++)
{
if (masked[i] != _value[i])
{
result = false;
break;
}
}
}
catch
{
result = false;
}
// Return if the expected and actual results match
return result == Result;
}
}
}