2 * Copyright © 2018 Ebrahim Byagowi
4 * This is part of HarfBuzz, a text shaping library.
6 * Permission is hereby granted, without written agreement and without
7 * license or royalty fees, to use, copy, modify, and distribute this
8 * software and its documentation for any purpose, provided that the
9 * above copyright notice and the following two paragraphs appear in
10 * all copies of this software.
12 * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR
13 * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
14 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN
15 * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
18 * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING,
19 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20 * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS
21 * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO
22 * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
25 #include "hb-static.cc"
28 #include "hb-open-type-private.hh"
30 template <typename Type, int Bytes> struct LEInt;
32 template <typename Type>
36 inline void set (Type V)
40 inline operator Type (void) const
46 template <typename Type>
50 inline void set (Type V)
52 v[1] = (V >> 8) & 0xFF;
55 inline operator Type (void) const
60 private: uint8_t v[2];
62 template <typename Type>
66 inline void set (Type V)
68 v[2] = (V >> 16) & 0xFF;
69 v[1] = (V >> 8) & 0xFF;
72 inline operator Type (void) const
78 private: uint8_t v[3];
80 template <typename Type>
84 inline void set (Type V)
86 v[3] = (V >> 24) & 0xFF;
87 v[2] = (V >> 16) & 0xFF;
88 v[1] = (V >> 8) & 0xFF;
91 inline operator Type (void) const
98 private: uint8_t v[4];
101 template <typename Type, unsigned int Size>
104 inline void set (Type i) { v.set (i); }
105 inline operator Type(void) const { return v; }
106 inline bool sanitize (OT::hb_sanitize_context_t *c) const
108 TRACE_SANITIZE (this);
109 return_trace (likely (c->check_struct (this)));
114 DEFINE_SIZE_STATIC (Size);
117 typedef LEIntType<uint8_t, 1> LEUINT8; /* 8-bit unsigned integer. */
118 typedef LEIntType<int8_t, 1> LEINT8; /* 8-bit signed integer. */
119 typedef LEIntType<uint16_t, 2> LEUINT16; /* 16-bit unsigned integer. */
120 typedef LEIntType<int16_t, 2> LEINT16; /* 16-bit signed integer. */
121 typedef LEIntType<uint32_t, 4> LEUINT32; /* 32-bit unsigned integer. */
122 typedef LEIntType<int32_t, 4> LEINT32; /* 32-bit signed integer. */
123 typedef LEIntType<uint32_t, 3> LEUINT24; /* 24-bit unsigned integer. */
128 inline bool sanitize (OT::hb_sanitize_context_t *c, unsigned int length) const
130 TRACE_SANITIZE (this);
131 return_trace (likely (c->check_struct (this) && c->check_range (this, length)));
134 // https://msdn.microsoft.com/en-us/library/cc194829.aspx
137 // dfCharSet possible values and the codepage they are indicating to
141 SHIFTJIS = 0x80, // 932
142 HANGUL = 0x81, // 949
143 GB2312 = 0x86, // 936
144 CHINESEBIG5 = 0x88, // 950
145 GREEK = 0xA1, // 1253
146 TURKISH = 0xA2, // 1254
147 HEBREW = 0xB1, // 1255
148 ARABIC = 0xB2, // 1256
149 BALTIC = 0xBA, // 1257
150 RUSSIAN = 0xCC, // 1251
156 inline const char* get_charset() const
159 case ANSI: return "ISO8859";
160 case DEFAULT: return "WinDefault";
161 case SYMBOL: return "Symbol";
162 case SHIFTJIS: return "JISX0208.1983";
163 case HANGUL: return "MSHangul";
164 case GB2312: return "GB2312.1980";
165 case CHINESEBIG5: return "Big5";
166 case GREEK: return "CP1253";
167 case TURKISH: return "CP1254";
168 case HEBREW: return "CP1255";
169 case ARABIC: return "CP1256";
170 case BALTIC: return "CP1257";
171 case RUSSIAN: return "CP1251";
172 case THAI: return "CP874";
173 case EE: return "CP1250";
174 case OEM: return "OEM";
175 default: return "Unknown";
179 inline unsigned int get_version () const
184 inline unsigned int get_weight () const
207 inline void dump () const
209 // With https://github.com/juanitogan/mkwinfont/blob/master/python/dewinfont.py help
210 // Should be implemented differently eventually, but for now
211 unsigned int ctstart;
213 if (dfVersion == 0x200)
220 return; // must of ".fon"s are version 2 and even dewinfont V1 implmentation doesn't seem correct
224 // unsigned int maxwidth = 0;
225 for (unsigned int i = dfFirstChar; i < dfLastChar; ++i)
227 unsigned int entry = ctstart + ctsize * (i-dfFirstChar);
228 unsigned int w = (uint16_t) OT::StructAtOffset<LEUINT16> (this, entry);
232 off = (uint16_t) OT::StructAtOffset<LEUINT16> (this, entry+2);
234 off = (uint32_t) OT::StructAtOffset<LEUINT32> (this, entry+2);
236 unsigned int widthbytes = (w + 7) / 8;
237 for (unsigned int j = 0; j < dfPixHeight; ++j)
239 for (unsigned int k = 0; k < widthbytes; ++k)
241 unsigned int bytepos = off + k * dfPixHeight + j;
242 const uint8_t b = (uint8_t) OT::StructAtOffset<LEINT8> (this, bytepos);
243 for (unsigned int a = 128; a > 0; a >>= 1)
244 printf (b & a ? "x" : ".");
255 LEUINT8 dfCopyright[60];
261 LEUINT16 dfInternalLeading;
262 LEUINT16 dfExternalLeading;
266 LEUINT16 dfWeight; // see weight_t
267 LEUINT8 dfCharSet; // see charset_t
269 LEUINT16 dfPixHeight;
270 LEUINT8 dfPitchAndFamily;
275 LEUINT8 dfDefaultChar;
277 LEUINT16 dfWidthBytes;
280 LEUINT32 dfBitsPointer;
281 LEUINT32 dfBitsOffset;
284 // LEUINT16 dfAspace;
285 // LEUINT16 dfBspace;
286 // LEUINT16 dfCspace;
287 // LEUINT32 dfColorPointer;
288 // LEUINT32 dfReserved1[4];
289 OT::UnsizedArrayOf<LEUINT8>
292 DEFINE_SIZE_ARRAY (118, dataZ);
297 friend struct NE_TYPEINFO;
299 inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base, unsigned int shift) const
301 TRACE_SANITIZE (this);
302 return_trace (likely (c->check_struct (this) &&
303 get_font (base, shift).sanitize (c, length << shift)));
306 inline const LE_FONTINFO16& get_font (const void *base, int shift) const
308 return OT::StructAtOffset<LE_FONTINFO16> (base, offset << shift);
311 enum resource_type_flag_t {
319 LEUINT16 offset; // Should be shifted with alignmentShiftCount before use
320 LEUINT16 length; // Should be shifted with alignmentShiftCount before use
321 LEUINT16 flags; // resource_type_flag_t
326 DEFINE_SIZE_STATIC (12);
331 inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base, unsigned int shift) const
333 TRACE_SANITIZE (this);
334 return_trace (c->check_struct (this) && resources.sanitize (c, count, base, shift));
337 inline unsigned int get_size (void) const
338 { return 8 + count * NE_NAMEINFO::static_size; }
340 inline const NE_TYPEINFO& next () const
342 const NE_TYPEINFO& next = OT::StructAfter<NE_TYPEINFO> (*this);
344 return Null(NE_TYPEINFO);
348 inline const LE_FONTINFO16& get_font (unsigned int idx, const void *base, int shift) const
351 return resources[idx].get_font (base, shift);
352 return Null(LE_FONTINFO16);
355 inline unsigned int get_count () const
360 inline unsigned int get_type_id () const
372 FONT_DIRECTORY = 0x8007,
374 ACCELERATOR_TABLE = 0x8009,
375 RESOURCE_DATA = 0x800a,
376 GROUP_CURSOR = 0x800c,
382 LEUINT16 type_id; // see type_id_t
385 OT::UnsizedArrayOf<NE_NAMEINFO>
388 DEFINE_SIZE_ARRAY (8, resources);
391 struct NE_RESOURCE_TABLE
393 inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base) const
395 TRACE_SANITIZE (this);
397 if (!c->check_struct (this))
398 return_trace (false);
400 const NE_TYPEINFO* n = &chain;
401 while (n != &Null(NE_TYPEINFO) && c->check_struct (n) && n->get_type_id () != 0)
403 if (n->get_type_id () == NE_TYPEINFO::FONT)
404 return_trace (n->sanitize (c, base, alignmentShiftCount));
407 return_trace (false);
410 inline unsigned int get_shift_value () const
412 return alignmentShiftCount;
415 inline const NE_TYPEINFO& get_fonts_entry () const
417 const NE_TYPEINFO* n = &chain;
418 while (n != &Null(NE_TYPEINFO) && n->get_type_id () != 0)
420 if (n->get_type_id () == NE_TYPEINFO::FONT)
424 return Null(NE_TYPEINFO);
428 LEUINT16 alignmentShiftCount;
430 // It is followed by an array of OT::ArrayOf<LEUINT8, LEUINT8> chars;
435 // https://github.com/wine-mirror/wine/blob/master/include/winnt.h#L2467
436 struct LE_IMAGE_OS2_HEADER
438 inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base) const
440 TRACE_SANITIZE (this);
441 return_trace (likely (c->check_struct (this) && (this+rsrctab).sanitize (c, base)));
444 inline const NE_RESOURCE_TABLE& get_resource_table () const
446 if (magic != 0x454E) // Only NE containers are support for now, NE == 0x454E
447 return Null(NE_RESOURCE_TABLE);
452 LEUINT16 magic; /* 00 NE signature 'NE' */
453 LEUINT8 ver; /* 02 Linker version number */
454 LEUINT8 rev; /* 03 Linker revision number */
455 LEUINT16 enttab; /* 04 Offset to entry table relative to NE */
456 LEUINT16 cbenttab; /* 06 Length of entry table in bytes */
457 LEUINT32 crc; /* 08 Checksum */
458 LEUINT16 flags; /* 0c Flags about segments in this file */
459 LEUINT16 autodata; /* 0e Automatic data segment number */
460 LEUINT16 heap; /* 10 Initial size of local heap */
461 LEUINT16 stack; /* 12 Initial size of stack */
462 LEUINT32 csip; /* 14 Initial CS:IP */
463 LEUINT32 sssp; /* 18 Initial SS:SP */
464 LEUINT16 cseg; /* 1c # of entries in segment table */
465 LEUINT16 cmod; /* 1e # of entries in module reference tab. */
466 LEUINT16 cbnrestab; /* 20 Length of nonresident-name table */
467 LEUINT16 segtab; /* 22 Offset to segment table */
468 OT::OffsetTo<NE_RESOURCE_TABLE, LEUINT16>
469 rsrctab; /* 24 Offset to resource table */
470 LEUINT16 restab; /* 26 Offset to resident-name table */
471 LEUINT16 modtab; /* 28 Offset to module reference table */
472 LEUINT16 imptab; /* 2a Offset to imported name table */
473 LEUINT32 nrestab; /* 2c Offset to nonresident-name table */
474 LEUINT16 cmovent; /* 30 # of movable entry points */
475 LEUINT16 align; /* 32 Logical sector alignment shift count */
476 LEUINT16 cres; /* 34 # of resource segments */
477 LEUINT8 exetyp; /* 36 Flags indicating target OS */
478 LEUINT8 flagsothers; /* 37 Additional information flags */
479 LEUINT16 pretthunks; /* 38 Offset to return thunks */
480 LEUINT16 psegrefbytes; /* 3a Offset to segment ref. bytes */
481 LEUINT16 swaparea; /* 3c Reserved by Microsoft */
482 LEUINT16 expver; /* 3e Expected Windows version number */
484 DEFINE_SIZE_STATIC (64);
487 struct LE_IMAGE_DOS_HEADER {
488 inline bool sanitize (OT::hb_sanitize_context_t *c) const
490 TRACE_SANITIZE (this);
491 return_trace (likely (c->check_struct (this) &&
492 get_os2_header ().sanitize (c, this)));
495 inline const LE_IMAGE_OS2_HEADER& get_os2_header () const
497 return this+e_lfanew;
501 LEUINT16 e_magic; // Magic number
502 LEUINT16 e_cblp; // Bytes on last page of file
503 LEUINT16 e_cp; // Pages in file
504 LEUINT16 e_crlc; // Relocations
505 LEUINT16 e_cparhdr; // Size of header in paragraphs
506 LEUINT16 e_minalloc; // Minimum extra paragraphs needed
507 LEUINT16 e_maxalloc; // Maximum extra paragraphs needed
508 LEUINT16 e_ss; // Initial (relative) SS value
509 LEUINT16 e_sp; // Initial SP value
510 LEUINT16 e_csum; // Checksum
511 LEUINT16 e_ip; // Initial IP value
512 LEUINT16 e_cs; // Initial (relative) CS value
513 LEUINT16 e_lfarlc; // File address of relocation table
514 LEUINT16 e_ovno; // Overlay number
515 LEUINT16 e_res_0; // Reserved words
516 LEUINT16 e_res_1; // Reserved words
517 LEUINT16 e_res_2; // Reserved words
518 LEUINT16 e_res_3; // Reserved words
519 LEUINT16 e_oemid; // OEM identifier (for e_oeminfo)
520 LEUINT16 e_oeminfo; // OEM information; e_oemid specific
521 LEUINT16 e_res2_0; // Reserved words
522 LEUINT16 e_res2_1; // Reserved words
523 LEUINT16 e_res2_2; // Reserved words
524 LEUINT16 e_res2_3; // Reserved words
525 LEUINT16 e_res2_4; // Reserved words
526 LEUINT16 e_res2_5; // Reserved words
527 LEUINT16 e_res2_6; // Reserved words
528 LEUINT16 e_res2_7; // Reserved words
529 LEUINT16 e_res2_8; // Reserved words
530 LEUINT16 e_res2_9; // Reserved words
531 OT::OffsetTo<LE_IMAGE_OS2_HEADER, LEUINT32>
532 e_lfanew; // File address of new exe header
534 DEFINE_SIZE_STATIC (64);
537 int main (int argc, char** argv) {
538 hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
540 OT::Sanitizer<LE_IMAGE_DOS_HEADER> sanitizer;
541 hb_blob_t *font_blob = sanitizer.sanitize (blob);
542 const LE_IMAGE_DOS_HEADER* dos_header = font_blob->as<LE_IMAGE_DOS_HEADER> ();
544 const NE_RESOURCE_TABLE &rtable = dos_header->get_os2_header ().get_resource_table ();
545 int shift = rtable.get_shift_value ();
546 const NE_TYPEINFO& entry = rtable.get_fonts_entry ();
547 for (unsigned int i = 0; i < entry.get_count (); ++i)
549 const LE_FONTINFO16& font = entry.get_font (i, dos_header, shift);
550 printf ("version: %x, weight: %d, charset: %s\n", font.get_version (),
551 font.get_weight (), font.get_charset ());