diff --git a/BurnOutSharp.Builder/Extensions.cs b/BurnOutSharp.Builder/Extensions.cs
index 7836b558..2e7589e8 100644
--- a/BurnOutSharp.Builder/Extensions.cs
+++ b/BurnOutSharp.Builder/Extensions.cs
@@ -441,6 +441,75 @@ namespace BurnOutSharp.Builder
}
}
+ ///
+ /// Read resource data as a font group
+ ///
+ /// Resource data entry to parse into a font group
+ /// A filled font group on success, null on error
+ public static Models.PortableExecutable.FontGroupHeader AsFontGroup(this Models.PortableExecutable.ResourceDataEntry entry)
+ {
+ // If we have an invalid entry, just skip
+ if (entry?.Data == null)
+ return null;
+
+ // Initialize the iterator
+ int offset = 0;
+
+ // Create the output object
+ var fontGroupHeader = new Models.PortableExecutable.FontGroupHeader();
+
+ fontGroupHeader.NumberOfFonts = entry.Data.ReadUInt16(ref offset);
+ if (fontGroupHeader.NumberOfFonts > 0)
+ {
+ fontGroupHeader.DE = new Models.PortableExecutable.DirEntry[fontGroupHeader.NumberOfFonts];
+ for (int i = 0; i < fontGroupHeader.NumberOfFonts; i++)
+ {
+ var dirEntry = new Models.PortableExecutable.DirEntry();
+
+ dirEntry.FontOrdinal = entry.Data.ReadUInt16(ref offset);
+
+ dirEntry.Entry = new Models.PortableExecutable.FontDirEntry();
+ dirEntry.Entry.Version = entry.Data.ReadUInt16(ref offset);
+ dirEntry.Entry.Size = entry.Data.ReadUInt32(ref offset);
+ dirEntry.Entry.Copyright = entry.Data.ReadBytes(ref offset, 60);
+ dirEntry.Entry.Type = entry.Data.ReadUInt16(ref offset);
+ dirEntry.Entry.Points = entry.Data.ReadUInt16(ref offset);
+ dirEntry.Entry.VertRes = entry.Data.ReadUInt16(ref offset);
+ dirEntry.Entry.HorizRes = entry.Data.ReadUInt16(ref offset);
+ dirEntry.Entry.Ascent = entry.Data.ReadUInt16(ref offset);
+ dirEntry.Entry.InternalLeading = entry.Data.ReadUInt16(ref offset);
+ dirEntry.Entry.ExternalLeading = entry.Data.ReadUInt16(ref offset);
+ dirEntry.Entry.Italic = entry.Data.ReadByte(ref offset);
+ dirEntry.Entry.Underline = entry.Data.ReadByte(ref offset);
+ dirEntry.Entry.StrikeOut = entry.Data.ReadByte(ref offset);
+ dirEntry.Entry.Weight = entry.Data.ReadUInt16(ref offset);
+ dirEntry.Entry.CharSet = entry.Data.ReadByte(ref offset);
+ dirEntry.Entry.PixWidth = entry.Data.ReadUInt16(ref offset);
+ dirEntry.Entry.PixHeight = entry.Data.ReadUInt16(ref offset);
+ dirEntry.Entry.PitchAndFamily = entry.Data.ReadByte(ref offset);
+ dirEntry.Entry.AvgWidth = entry.Data.ReadUInt16(ref offset);
+ dirEntry.Entry.MaxWidth = entry.Data.ReadUInt16(ref offset);
+ dirEntry.Entry.FirstChar = entry.Data.ReadByte(ref offset);
+ dirEntry.Entry.LastChar = entry.Data.ReadByte(ref offset);
+ dirEntry.Entry.DefaultChar = entry.Data.ReadByte(ref offset);
+ dirEntry.Entry.BreakChar = entry.Data.ReadByte(ref offset);
+ dirEntry.Entry.WidthBytes = entry.Data.ReadUInt16(ref offset);
+ dirEntry.Entry.Device = entry.Data.ReadUInt32(ref offset);
+ dirEntry.Entry.Face = entry.Data.ReadUInt32(ref offset);
+ dirEntry.Entry.Reserved = entry.Data.ReadUInt32(ref offset);
+
+ // TODO: Determine how to read these two? Immediately after?
+ dirEntry.Entry.DeviceName = entry.Data.ReadString(ref offset);
+ dirEntry.Entry.FaceName = entry.Data.ReadString(ref offset);
+
+ fontGroupHeader.DE[i] = dirEntry;
+ }
+ }
+
+ // TODO: Implement entry parsing
+ return null;
+ }
+
///
/// Read resource data as a string table resource
///
diff --git a/BurnOutSharp.Models/PortableExecutable/DirEntry.cs b/BurnOutSharp.Models/PortableExecutable/DirEntry.cs
new file mode 100644
index 00000000..c777da3c
--- /dev/null
+++ b/BurnOutSharp.Models/PortableExecutable/DirEntry.cs
@@ -0,0 +1,21 @@
+namespace BurnOutSharp.Models.PortableExecutable
+{
+ ///
+ /// Contains the information necessary for an application to access a specific font. The structure
+ /// definition provided here is for explanation only; it is not present in any standard header file.
+ ///
+ ///
+ public class DirEntry
+ {
+ ///
+ /// A unique ordinal identifier for an individual font in a font resource group.
+ ///
+ public ushort FontOrdinal;
+
+ ///
+ /// The FONTDIRENTRY structure for the specified font directly follows the DIRENTRY structure
+ /// for that font.
+ ///
+ public FontDirEntry Entry;
+ }
+}
diff --git a/BurnOutSharp.Models/PortableExecutable/FontDirEntry.cs b/BurnOutSharp.Models/PortableExecutable/FontDirEntry.cs
new file mode 100644
index 00000000..69163c35
--- /dev/null
+++ b/BurnOutSharp.Models/PortableExecutable/FontDirEntry.cs
@@ -0,0 +1,174 @@
+namespace BurnOutSharp.Models.PortableExecutable
+{
+ ///
+ /// Contains information about an individual font in a font resource group. The structure definition
+ /// provided here is for explanation only; it is not present in any standard header file.
+ ///
+ ///
+ public class FontDirEntry
+ {
+ ///
+ /// A user-defined version number for the resource data that tools can use to read and write
+ /// resource files.
+ ///
+ public ushort Version;
+
+ ///
+ /// The size of the file, in bytes.
+ ///
+ public uint Size;
+
+ ///
+ /// The font supplier's copyright information.
+ ///
+ /// 60 characters
+ public byte[] Copyright;
+
+ ///
+ /// The type of font file.
+ ///
+ public ushort Type;
+
+ ///
+ /// The point size at which this character set looks best.
+ ///
+ public ushort Points;
+
+ ///
+ /// The vertical resolution, in dots per inch, at which this character set was digitized.
+ ///
+ public ushort VertRes;
+
+ ///
+ /// The horizontal resolution, in dots per inch, at which this character set was digitized.
+ ///
+ public ushort HorizRes;
+
+ ///
+ /// The distance from the top of a character definition cell to the baseline of the typographical
+ /// font.
+ ///
+ public ushort Ascent;
+
+ ///
+ /// The amount of leading inside the bounds set by the PixHeight member. Accent marks and other
+ /// diacritical characters can occur in this area.
+ ///
+ public ushort InternalLeading;
+
+ ///
+ /// The amount of extra leading that the application adds between rows.
+ ///
+ public ushort ExternalLeading;
+
+ ///
+ /// An italic font if not equal to zero.
+ ///
+ public byte Italic;
+
+ ///
+ /// An underlined font if not equal to zero.
+ ///
+ public byte Underline;
+
+ ///
+ /// A strikeout font if not equal to zero.
+ ///
+ public byte StrikeOut;
+
+ ///
+ /// The weight of the font in the range 0 through 1000. For example, 400 is roman and 700 is bold.
+ /// If this value is zero, a default weight is used. For additional defined values, see the
+ /// description of the LOGFONT structure.
+ ///
+ public ushort Weight;
+
+ ///
+ /// The character set of the font. For predefined values, see the description of the LOGFONT
+ /// structure.
+ ///
+ public byte CharSet;
+
+ ///
+ /// The width of the grid on which a vector font was digitized. For raster fonts, if the member
+ /// is not equal to zero, it represents the width for all the characters in the bitmap. If the
+ /// member is equal to zero, the font has variable-width characters.
+ ///
+ public ushort PixWidth;
+
+ ///
+ /// The height of the character bitmap for raster fonts or the height of the grid on which a
+ /// vector font was digitized.
+ ///
+ public ushort PixHeight;
+
+ ///
+ /// The pitch and the family of the font. For additional information, see the description of
+ /// the LOGFONT structure.
+ ///
+ public byte PitchAndFamily;
+
+ ///
+ /// The average width of characters in the font (generally defined as the width of the letter x).
+ /// This value does not include the overhang required for bold or italic characters.
+ ///
+ public ushort AvgWidth;
+
+ ///
+ /// The width of the widest character in the font.
+ ///
+ public ushort MaxWidth;
+
+ ///
+ /// The first character code defined in the font.
+ ///
+ public byte FirstChar;
+
+ ///
+ /// The last character code defined in the font.
+ ///
+ public byte LastChar;
+
+ ///
+ /// The character to substitute for characters not in the font.
+ ///
+ public byte DefaultChar;
+
+ ///
+ /// The character that will be used to define word breaks for text justification.
+ ///
+ public byte BreakChar;
+
+ ///
+ /// The number of bytes in each row of the bitmap. This value is always even so that the rows
+ /// start on word boundaries. For vector fonts, this member has no meaning.
+ ///
+ public ushort WidthBytes;
+
+ ///
+ /// The offset in the file to a null-terminated string that specifies a device name. For a
+ /// generic font, this value is zero.
+ ///
+ public uint Device;
+
+ ///
+ /// The offset in the file to a null-terminated string that names the typeface.
+ ///
+ public uint Face;
+
+ ///
+ /// This member is reserved.
+ ///
+ public uint Reserved;
+
+ ///
+ /// The name of the device if this font file is designated for a specific device.
+ ///
+ public string DeviceName;
+
+ ///
+ /// The typeface name of the font.
+ ///
+ public string FaceName;
+ }
+}
diff --git a/BurnOutSharp.Models/PortableExecutable/FontGroupHeader.cs b/BurnOutSharp.Models/PortableExecutable/FontGroupHeader.cs
new file mode 100644
index 00000000..07cd5eb8
--- /dev/null
+++ b/BurnOutSharp.Models/PortableExecutable/FontGroupHeader.cs
@@ -0,0 +1,21 @@
+namespace BurnOutSharp.Models.PortableExecutable
+{
+ ///
+ /// Contains the information necessary for an application to access a specific font. The structure
+ /// definition provided here is for explanation only; it is not present in any standard header file.
+ ///
+ ///
+ public class FontGroupHeader
+ {
+ ///
+ /// The number of individual fonts associated with this resource.
+ ///
+ public ushort NumberOfFonts;
+
+ ///
+ /// A structure that contains a unique ordinal identifier for each font in the resource. The DE
+ /// member is a placeholder for the variable-length array of DIRENTRY structures.
+ ///
+ public DirEntry[] DE;
+ }
+}