using System; using System.Collections.Generic; using System.IO; using static BurnOutSharp.Builder.Extensions; namespace BurnOutSharp.Wrappers { public abstract class WrapperBase { #region Instance Variables /// /// Source of the original data /// protected DataSource _dataSource = DataSource.UNKNOWN; /// /// Source byte array data /// /// This is only populated if is protected byte[] _byteArrayData = null; /// /// Source byte array data offset /// /// This is only populated if is protected int _byteArrayOffset = -1; /// /// Source Stream data /// /// This is only populated if is protected Stream _streamData = null; #endregion #region Data /// /// Validate the backing data source /// /// True if the data source is valid, false otherwise protected bool DataSourceIsValid() { switch (_dataSource) { // Byte array data requires both a valid array and offset case DataSource.ByteArray: return _byteArrayData != null && _byteArrayOffset >= 0; // Stream data requires both a valid stream case DataSource.Stream: return _streamData != null && _streamData.CanRead && _streamData.CanSeek; // Everything else is invalid case DataSource.UNKNOWN: default: return false; } } /// /// Check if a data segment is valid in the data source /// /// Position in the source /// Length of the data to check /// True if the positional data is valid, false otherwise protected bool SegmentValid(int position, int length) { // Validate the data souece if (!DataSourceIsValid()) return false; switch (_dataSource) { case DataSource.ByteArray: return _byteArrayOffset + position + length <= _byteArrayData.Length; case DataSource.Stream: return position + length <= _streamData.Length; // Everything else is invalid case DataSource.UNKNOWN: default: return false; } } /// /// Read data from the source /// /// Position in the source to read from /// Length of the requested data /// Byte array containing the requested data, null on error protected byte[] ReadFromDataSource(int position, int length) { // Validate the data source if (!DataSourceIsValid()) return null; // Validate the requested segment if (!SegmentValid(position, length)) return null; // Read and return the data byte[] sectionData = null; switch (_dataSource) { case DataSource.ByteArray: sectionData = new byte[length]; Array.Copy(_byteArrayData, _byteArrayOffset + position, sectionData, 0, length); break; case DataSource.Stream: long currentLocation = _streamData.Position; _streamData.Seek(position, SeekOrigin.Begin); sectionData = _streamData.ReadBytes(length); _streamData.Seek(currentLocation, SeekOrigin.Begin); break; } return sectionData; } /// /// Read string data from the source /// /// Position in the source to read from /// Length of the requested data /// String list containing the requested data, null on error protected List ReadStringsFromDataSource(int position, int length) { // Read the data as a byte array first byte[] sourceData = ReadFromDataSource(position, length); if (sourceData == null) return null; // TODO: Complete implementation of string finding return null; } /// /// Get the ending offset of the source /// /// Value greater than 0 for a valid end of file, -1 on error protected int GetEndOfFile() { // Validate the data souece if (!DataSourceIsValid()) return -1; // Return the effective endpoint switch (_dataSource) { case DataSource.ByteArray: return _byteArrayData.Length - _byteArrayOffset; case DataSource.Stream: return (int)_streamData.Length; case DataSource.UNKNOWN: default: return -1; } } #endregion #region Printing /// /// Pretty print the Executable information /// public abstract void Print(); #endregion } }