A .fon file is a 16-bit Windows NE
executable: an MS-DOS stub, then the NE header and its tables, but with no code or
data segments. It exists only to carry resources: one FONT resource per
size or style, each a complete font resource, and
one FONTDIR resource that lists them all, so that Windows can choose a font
without loading every one. Everything is little-endian.
Layout
0MZ header and stub with the NE header’s offset at0x3Cvaries…NE header; segment count 0, flags marking a library module64 bytes…Resource table: type 7 (FONTDIR) with one entry, type 8 (FONT) with one entry per font, often type 16 (version information)varies…Resident names: the module namevaries…Non-resident names: the FONTRES descriptionvaries…FONTDIR resourcevaries…FONT resources, one per font, each aligned to the resource alignmentvaries
.fon file.Resource types are written with the top bit set to mean a numbered type, so
FONTDIR appears as 0x8007 and FONT as
0x8008. Each FONT resource normally has a number as its ID
(again with the top bit set), and that number is the ordinal the font directory uses.
Resource offsets and lengths in the table are in units of 2n
bytes, where n is the alignment shift at the start of the resource table;
the lengths are rounded up, and the font’s own dfSize gives its exact
size.
The FONTRES description
The first entry of the non-resident name table, the module description, takes the form
FONTRES aspect,xres,yres : description
where xres and yres are the resolution in dots per inch the
fonts were made for and aspect is 100 × xres ÷ yres.
Examples from real files: FONTRES 100,96,96 : MS Sans Serif 8,10,12,14,18,24
(VGA), FONTRES 133,96,72 : Terminal (EGA) and FONTRES
200,96,48 : Terminal (CGA). The text after the colon is what font lists show
for the file. The resident name table holds the module name, such as
SSERIFE.
The FONTDIR resource
| Offset | Size | Name | Meaning |
|---|---|---|---|
0 | 2 | NumberOfFonts | How many fonts follow. |
2 | varies | entries | For each font: a 2-byte ordinal (the FONT resource’s ID) and a font directory entry. |
A font directory entry is a copy of the font’s header
from dfVersion to dfFace (109 bytes), then a 4-byte
dfReserved in place of dfBitsPointer,
dfBitsOffset and the reserved byte, then the device name and the face
name, each a zero-terminated string (the device name is just a zero byte for a
general font). The dfDevice and dfFace offsets inside
the copy still refer to the font resource, not to the directory.
Example
SSERIFEE.FON, MS Sans Serif for Central European languages, 66,464
bytes. The MZ header’s 0x3C field is 0x80, so the NE header
is at 128, and its resource table offset (at NE + 0x24) is
0x40, putting the table at 0xC0:
000000C0 04 00 07 80 01 00 00 00 00 00 19 00 31 00 50 0C ............1.P.
000000D0 7C 00 00 00 00 00 08 80 06 00 00 00 00 00 4A 00 |.............J.
000000E0 FD 00 30 1C 54 80 00 00 00 00 47 01 60 01 30 1C ..0.T.....G.`.0.
| File offset | Bytes | Meaning |
|---|---|---|
0xC0 | 04 00 | Alignment shift 4: resource offsets and lengths are in 16-byte units. |
0xC2 | 07 80 01 00 | Type FONTDIR, one resource. |
0xCA | 19 00 31 00 | At 0x19 × 16 = 0x190, 0x31 × 16 = 784 bytes. |
0xD0 | 7C 00 | Its ID has no top bit, so it is a name: at table offset 0x7C is the string FONTDIR. |
0xD6 | 08 80 06 00 | Type FONT, six resources. |
0xDE | 4A 00 FD 00 30 1C 54 80 | The first at 0x4A0, 4,048 bytes rounded, ID 0x8054: number 84. |
The other five fonts are numbers 85 to 89, and a type 16 (version information)
resource follows. The non-resident names at 0x151 begin with a length
byte of 56 and the text FONTRES 100,96,96 : MS Sans Serif
8,10,12,14,18,24 (VGA). The FONTDIR at 0x190 starts:
00000190 06 00 54 00 00 02 C3 0F 00 00 28 63 29 20 43 6F ..T.......(c) Co
…
000001F0 00 0B 00 20 FF 61 00 E7 00 00 00 00 00 B5 0F 00 ... .a..........
00000200 00 00 00 00 00 00 4D 53 20 53 61 6E 73 20 53 65 ......MS Sans Se
00000210 72 69 66 00 55 00 00 02 F8 15 00 00 28 63 29 20 rif.U.......(c)
Six fonts; the first is ordinal 84, and its entry repeats the header of the font at
0x4A0 (version 2.0, 4,035 bytes, 8 points, decoded on the
font resource page) up to
dfFace = 0xFB5 at 0x1FD. Then come the four
reserved bytes, an empty device name (00 at 0x205) and the
face name “MS Sans Serif”. The next entry, ordinal 85, starts at 0x214.