Skip to content

Instantly share code, notes, and snippets.

@robotarmy
Created February 14, 2013 22:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robotarmy/4956885 to your computer and use it in GitHub Desktop.
Save robotarmy/4956885 to your computer and use it in GitHub Desktop.
175 bool getEOTHeader(unsigned char* fontData, size_t fontSize, vector<uint8_t>& eotHeader, size_t& overlayDst, size_t& overlaySrc, size_t& overlayLength)
176 {
177 overlayDst = 0;
178 overlaySrc = 0;
179 overlayLength = 0;
180
181 size_t dataLength = fontSize;
182 const char* data = (const char *) fontData;
183
184 eotHeader.resize(sizeof(EOTPrefix));
185 EOTPrefix* prefix = reinterpret_cast<EOTPrefix*>(&eotHeader[0]);
186
187 prefix->fontDataSize = dataLength;
188 prefix->version = 0x00020001;
189 prefix->flags = 0;
190
191 if (dataLength < offsetof(sfntHeader, tables))
192 return false;
193
194 const sfntHeader* sfnt = reinterpret_cast<const sfntHeader*>(data);
195
196 if (dataLength < offsetof(sfntHeader, tables) + sfnt->numTables * sizeof(TableDirectoryEntry))
197 return false;
198
199 bool haveOS2 = false;
200 bool haveHead = false;
201 bool haveName = false;
202
203 const BigEndianUShort* familyName = 0;
204 unsigned short familyNameLength = 0;
205 const BigEndianUShort* subfamilyName = 0;
206 unsigned short subfamilyNameLength = 0;
207 const BigEndianUShort* fullName = 0;
208 unsigned short fullNameLength = 0;
209 const BigEndianUShort* versionString = 0;
210 unsigned short versionStringLength = 0;
211
212 for (unsigned i = 0; i < sfnt->numTables; i++) {
213 unsigned tableOffset = sfnt->tables[i].offset;
214 unsigned tableLength = sfnt->tables[i].length;
215
216 if (dataLength < tableOffset || dataLength < tableLength || dataLength < tableOffset + tableLength)
217 return false;
218
219 unsigned tableTag = sfnt->tables[i].tag;
220 switch (tableTag) {
221 case 'OS/2':
222 {
223 if (dataLength < tableOffset + sizeof(OS2Table))
224 return false;
225
226 haveOS2 = true;
227 const OS2Table* OS2 = reinterpret_cast<const OS2Table*>(data + tableOffset);
228 for (unsigned j = 0; j < 10; j++)
229 prefix->fontPANOSE[j] = OS2->panose[j];
230 prefix->italic = OS2->fsSelection & 0x01;
231 prefix->weight = OS2->weightClass;
232 // FIXME: Should use OS2->fsType, but some TrueType fonts set it to an over-restrictive value.
233 // Since ATS does not enforce this on Mac OS X, we do not enforce it either.
234 prefix->fsType = 0;
235 for (unsigned j = 0; j < 4; j++)
236 prefix->unicodeRange[j] = OS2->unicodeRange[j];
237 for (unsigned j = 0; j < 2; j++)
238 prefix->codePageRange[j] = OS2->codePageRange[j];
239 break;
240 }
241 case 'head':
242 {
243 if (dataLength < tableOffset + sizeof(headTable))
244 return false;
245
246 haveHead = true;
247 const headTable* head = reinterpret_cast<const headTable*>(data + tableOffset);
248 prefix->checkSumAdjustment = head->checkSumAdjustment;
249 break;
250 }
251 case 'name':
252 {
253 if (dataLength < tableOffset + offsetof(nameTable, nameRecords))
254 return false;
255
256 haveName = true;
257 const nameTable* name = reinterpret_cast<const nameTable*>(data + tableOffset);
258 for (int j = 0; j < name->count; j++) {
259 if (dataLength < tableOffset + offsetof(nameTable, nameRecords) + (j + 1) * sizeof(nameRecord))
260 return false;
261 if (name->nameRecords[j].platformID == 3 && name->nameRecords[j].encodingID == 1 && name->nameRecords[j].languageID == 0x0409) {
262 if (dataLength < tableOffset + name->stringOffset + name->nameRecords[j].offset + name->nameRecords[j].length)
263 return false;
264
265 unsigned short nameLength = name->nameRecords[j].length;
266 const BigEndianUShort* nameString = reinterpret_cast<const BigEndianUShort*>(data + tableOffset + name->stringOffset + name->nameRecords[j].offset);
267
268 switch (name->nameRecords[j].nameID) {
269 case 1:
270 familyNameLength = nameLength;
271 familyName = nameString;
272 break;
273 case 2:
274 subfamilyNameLength = nameLength;
275 subfamilyName = nameString;
276 break;
277 case 4:
278 fullNameLength = nameLength;
279 fullName = nameString;
280 break;
281 case 5:
282 versionStringLength = nameLength;
283 versionString = nameString;
284 break;
285 default:
286 break;
287 }
288 }
289 }
290 break;
291 }
292 default:
293 break;
294 }
295 if (haveOS2 && haveHead && haveName)
296 break;
297 }
298
299 prefix->charset = DEFAULT_CHARSET;
300 prefix->magicNumber = 0x504c;
301 prefix->reserved[0] = 0;
302 prefix->reserved[1] = 0;
303 prefix->reserved[2] = 0;
304 prefix->reserved[3] = 0;
305 prefix->padding1 = 0;
306
307 appendBigEndianStringToEOTHeader(eotHeader, familyName, familyNameLength);
308 appendBigEndianStringToEOTHeader(eotHeader, subfamilyName, subfamilyNameLength);
309 appendBigEndianStringToEOTHeader(eotHeader, versionString, versionStringLength);
310
311 // If possible, ensure that the family name is a prefix of the full name.
312 if (fullNameLength >= familyNameLength && memcmp(familyName, fullName, familyNameLength)) {
313 overlaySrc = reinterpret_cast<const char*>(fullName) - data;
314 overlayDst = reinterpret_cast<const char*>(familyName) - data;
315 overlayLength = familyNameLength;
316 }
317
318 appendBigEndianStringToEOTHeader(eotHeader, fullName, fullNameLength);
319
320 unsigned short padding = 0;
321 eotHeader.push_back(padding);
322 eotHeader.push_back(padding);
323
324 prefix = reinterpret_cast<EOTPrefix*>(&eotHeader[0]);
325 prefix->eotSize = eotHeader.size() + fontSize;
326
327 return true;
328 }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment