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