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; } } }