diff --git a/BurnOutSharp.Wrappers/Enums.cs b/BurnOutSharp.Wrappers/Enums.cs
index c0a9b0f3..b74c374f 100644
--- a/BurnOutSharp.Wrappers/Enums.cs
+++ b/BurnOutSharp.Wrappers/Enums.cs
@@ -3,7 +3,7 @@ namespace BurnOutSharp.Wrappers
///
/// Location that the data originated from
///
- internal enum DataSource
+ public enum DataSource
{
///
/// Unknown origin / testing
diff --git a/BurnOutSharp.Wrappers/LinearExecutable.cs b/BurnOutSharp.Wrappers/LinearExecutable.cs
index f7321c30..a65865b6 100644
--- a/BurnOutSharp.Wrappers/LinearExecutable.cs
+++ b/BurnOutSharp.Wrappers/LinearExecutable.cs
@@ -1,9 +1,8 @@
using System.IO;
-// TODO: Create base class for all wrappers
namespace BurnOutSharp.Wrappers
{
- public class LinearExecutable
+ public class LinearExecutable : WrapperBase
{
#region Pass-Through Properties
@@ -285,29 +284,6 @@ namespace BurnOutSharp.Wrappers
///
private Models.LinearExecutable.Executable _executable;
- ///
- /// Source of the original data
- ///
- private DataSource _dataSource = DataSource.UNKNOWN;
-
- ///
- /// Source byte array data
- ///
- /// This is only populated if is
- private byte[] _byteArrayData = null;
-
- ///
- /// Source byte array data offset
- ///
- /// This is only populated if is
- private int _byteArrayOffset = -1;
-
- ///
- /// Source Stream data
- ///
- /// This is only populated if is
- private Stream _streamData = null;
-
#endregion
///
@@ -360,7 +336,7 @@ namespace BurnOutSharp.Wrappers
///
/// Pretty print the Linear Executable information
///
- public void Print()
+ public override void Print()
{
// TODO: Implement printing
}
diff --git a/BurnOutSharp.Wrappers/MSDOS.cs b/BurnOutSharp.Wrappers/MSDOS.cs
index 11625069..d9e95fa9 100644
--- a/BurnOutSharp.Wrappers/MSDOS.cs
+++ b/BurnOutSharp.Wrappers/MSDOS.cs
@@ -1,10 +1,9 @@
using System;
using System.IO;
-// TODO: Create base class for all wrappers
namespace BurnOutSharp.Wrappers
{
- public class MSDOS
+ public class MSDOS : WrapperBase
{
#region Pass-Through Properties
@@ -89,29 +88,6 @@ namespace BurnOutSharp.Wrappers
///
private Models.MSDOS.Executable _executable;
- ///
- /// Source of the original data
- ///
- private DataSource _dataSource = DataSource.UNKNOWN;
-
- ///
- /// Source byte array data
- ///
- /// This is only populated if is
- private byte[] _byteArrayData = null;
-
- ///
- /// Source byte array data offset
- ///
- /// This is only populated if is
- private int _byteArrayOffset = -1;
-
- ///
- /// Source Stream data
- ///
- /// This is only populated if is
- private Stream _streamData = null;
-
#endregion
///
@@ -164,7 +140,7 @@ namespace BurnOutSharp.Wrappers
///
/// Pretty print the MS-DOS executable information
///
- public void Print()
+ public override void Print()
{
Console.WriteLine("MS-DOS Executable Information:");
Console.WriteLine("-------------------------");
diff --git a/BurnOutSharp.Wrappers/NewExecutable.cs b/BurnOutSharp.Wrappers/NewExecutable.cs
index 2b7805f0..cb2d426c 100644
--- a/BurnOutSharp.Wrappers/NewExecutable.cs
+++ b/BurnOutSharp.Wrappers/NewExecutable.cs
@@ -4,10 +4,9 @@ using System.IO;
using System.Text;
using static BurnOutSharp.Builder.Extensions;
-// TODO: Create base class for all wrappers
namespace BurnOutSharp.Wrappers
{
- public class NewExecutable
+ public class NewExecutable : WrapperBase
{
#region Pass-Through Properties
@@ -217,29 +216,6 @@ namespace BurnOutSharp.Wrappers
///
private Models.NewExecutable.Executable _executable;
- ///
- /// Source of the original data
- ///
- private DataSource _dataSource = DataSource.UNKNOWN;
-
- ///
- /// Source byte array data
- ///
- /// This is only populated if is
- private byte[] _byteArrayData = null;
-
- ///
- /// Source byte array data offset
- ///
- /// This is only populated if is
- private int _byteArrayOffset = -1;
-
- ///
- /// Source Stream data
- ///
- /// This is only populated if is
- private Stream _streamData = null;
-
#endregion
///
@@ -292,7 +268,7 @@ namespace BurnOutSharp.Wrappers
///
/// Pretty print the New Executable information
///
- public void Print()
+ public override void Print()
{
Console.WriteLine("New Executable Information:");
Console.WriteLine("-------------------------");
diff --git a/BurnOutSharp.Wrappers/PortableExecutable.cs b/BurnOutSharp.Wrappers/PortableExecutable.cs
index 299b2ee0..0e2c8b91 100644
--- a/BurnOutSharp.Wrappers/PortableExecutable.cs
+++ b/BurnOutSharp.Wrappers/PortableExecutable.cs
@@ -5,10 +5,9 @@ using System.Text;
using System.Xml;
using static BurnOutSharp.Builder.Extensions;
-// TODO: Create base class for all wrappers
namespace BurnOutSharp.Wrappers
{
- public class PortableExecutable
+ public class PortableExecutable : WrapperBase
{
#region Pass-Through Properties
@@ -316,6 +315,33 @@ namespace BurnOutSharp.Wrappers
#region Extension Properties
+ ///
+ /// Array of sanitized section names
+ ///
+ public string[] SectionNames
+ {
+ get
+ {
+ // Use the cached data if possible
+ if (_sectionNames != null)
+ return _sectionNames;
+
+ // Otherwise, build and return the cached array
+ _sectionNames = new string[_executable.SectionTable.Length];
+ for (int i = 0; i < _sectionNames.Length; i++)
+ {
+ var section = _executable.SectionTable[i];
+
+ // TODO: Handle long section names with leading `/`
+ byte[] sectionNameBytes = section.Name;
+ string sectionNameString = Encoding.UTF8.GetString(sectionNameBytes).TrimEnd('\0');
+ _sectionNames[i] = sectionNameString;
+ }
+
+ return _sectionNames;
+ }
+ }
+
// TODO: Determine what extension properties are needed
#endregion
@@ -328,30 +354,7 @@ namespace BurnOutSharp.Wrappers
private Models.PortableExecutable.Executable _executable;
///
- /// Source of the original data
- ///
- private DataSource _dataSource = DataSource.UNKNOWN;
-
- ///
- /// Source byte array data
- ///
- /// This is only populated if is
- private byte[] _byteArrayData = null;
-
- ///
- /// Source byte array data offset
- ///
- /// This is only populated if is
- private int _byteArrayOffset = -1;
-
- ///
- /// Source Stream data
- ///
- /// This is only populated if is
- private Stream _streamData = null;
-
- ///
- /// Array of santiized section names
+ /// Array of sanitized section names
///
private string[] _sectionNames = null;
@@ -363,7 +366,7 @@ namespace BurnOutSharp.Wrappers
///
/// Cached raw section data
///
- private Dictionary _rawSectionData = null;
+ private readonly Dictionary _rawSectionData = new Dictionary();
#endregion
@@ -414,31 +417,6 @@ namespace BurnOutSharp.Wrappers
return wrapper;
}
- ///
- /// Get all section names from the executable
- ///
- /// A PE executable wrapper on success, null on failure
- public string[] GetSectionNames()
- {
- // Use the cached data if possible
- if (_sectionNames != null)
- return _sectionNames;
-
- // Otherwise, build and return the cached array
- _sectionNames = new string[_executable.SectionTable.Length];
- for (int i = 0; i < _sectionNames.Length; i++)
- {
- var section = _executable.SectionTable[i];
-
- // TODO: Handle long section names with leading `/`
- byte[] sectionNameBytes = section.Name;
- string sectionNameString = Encoding.UTF8.GetString(sectionNameBytes).TrimEnd('\0');
- _sectionNames[i] = sectionNameString;
- }
-
- return _sectionNames;
- }
-
///
/// Get raw section data from the source file
///
@@ -451,32 +429,15 @@ namespace BurnOutSharp.Wrappers
return null;
// Validate the data source
- switch (_dataSource)
- {
- // If we don't have a valid data source, we can't read the section data
- case DataSource.UNKNOWN:
- return null;
-
- // Byte array data requires both a valid array and offset
- case DataSource.ByteArray:
- if (_byteArrayData == null || _byteArrayOffset < 0)
- return null;
- break;
-
- // Stream data requires both a valid stream
- case DataSource.Stream:
- if (_streamData == null)
- return null;
- break;
- }
+ if (!DataSourceIsValid())
+ return null;
// Make sure the section exists
- string[] sectionNames = GetSectionNames();
- if (sectionNames == null)
+ if (SectionNames == null)
return null;
// Get the section index from the array
- int sectionIndex = Array.IndexOf(sectionNames, sectionName);
+ int sectionIndex = Array.IndexOf(SectionNames, sectionName);
if (sectionIndex < 0)
return null;
@@ -490,33 +451,11 @@ namespace BurnOutSharp.Wrappers
lock (_rawSectionsLock)
{
// If we already have cached data, just use that immediately
- if (_rawSectionData != null && _rawSectionData.ContainsKey(sectionName))
+ if (_rawSectionData.ContainsKey(sectionName))
return _rawSectionData[sectionName];
- // If the section dictionary doesn't exist, create it
- if (_rawSectionData == null)
- _rawSectionData = new Dictionary();
-
// Populate the raw section data based on the source
- byte[] sectionData = null;
- switch (_dataSource)
- {
- case DataSource.ByteArray:
- if (_byteArrayOffset + sectionAddress + sectionSize >= _byteArrayData.Length)
- return null;
- sectionData = new byte[sectionSize];
- Array.Copy(_byteArrayData, _byteArrayOffset + sectionAddress, sectionData, 0, sectionSize);
- break;
-
- case DataSource.Stream:
- if (sectionAddress + sectionSize >= _streamData.Length)
- return null;
- long currentLocation = _streamData.Position;
- _streamData.Seek(sectionAddress, SeekOrigin.Begin);
- sectionData = _streamData.ReadBytes((int)sectionSize);
- _streamData.Seek(currentLocation, SeekOrigin.Begin);
- break;
- }
+ byte[] sectionData = ReadFromDataSource((int)sectionAddress, (int)sectionSize);
// Cache and return the section data, even if null
_rawSectionData[sectionName] = sectionData;
@@ -527,7 +466,7 @@ namespace BurnOutSharp.Wrappers
///
/// Pretty print the New Executable information
///
- public void Print()
+ public override void Print()
{
Console.WriteLine("Portable Executable Information:");
Console.WriteLine("-------------------------");
diff --git a/BurnOutSharp.Wrappers/WrapperBase.cs b/BurnOutSharp.Wrappers/WrapperBase.cs
new file mode 100644
index 00000000..49ecdc7c
--- /dev/null
+++ b/BurnOutSharp.Wrappers/WrapperBase.cs
@@ -0,0 +1,135 @@
+using System;
+using System.IO;
+using static BurnOutSharp.Builder.Extensions;
+
+namespace BurnOutSharp.Wrappers
+{
+ public abstract class WrapperBase
+ {
+ #region Instance Variabled
+
+ ///
+ /// 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 souece
+ if (!DataSourceIsValid())
+ return null;
+
+ // Validate the requested segment
+ if (!SegmentValid(position, length))
+ return null;
+
+ // Read and retuen 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;
+ }
+
+ #endregion
+
+ #region Printing
+
+ ///
+ /// Pretty print the Executable information
+ ///
+ public abstract void Print();
+
+ #endregion
+ }
+}
\ No newline at end of file