Imported Upstream version 1.8.1
[platform/upstream/harfbuzz.git] / src / dump-fon.cc
1 /*
2  * Copyright © 2018  Ebrahim Byagowi
3  *
4  *  This is part of HarfBuzz, a text shaping library.
5  *
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.
11  *
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
16  * DAMAGE.
17  *
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.
23  */
24
25 #include "hb-static.cc"
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include "hb-open-type-private.hh"
29
30 template <typename Type, int Bytes> struct LEInt;
31
32 template <typename Type>
33 struct LEInt<Type, 1>
34 {
35   public:
36   inline void set (Type V)
37   {
38     v = V;
39   }
40   inline operator Type (void) const
41   {
42     return v;
43   }
44   private: uint8_t v;
45 };
46 template <typename Type>
47 struct LEInt<Type, 2>
48 {
49   public:
50   inline void set (Type V)
51   {
52     v[1] = (V >>  8) & 0xFF;
53     v[0] = (V      ) & 0xFF;
54   }
55   inline operator Type (void) const
56   {
57     return (v[1] <<  8)
58          + (v[0]      );
59   }
60   private: uint8_t v[2];
61 };
62 template <typename Type>
63 struct LEInt<Type, 3>
64 {
65   public:
66   inline void set (Type V)
67   {
68     v[2] = (V >> 16) & 0xFF;
69     v[1] = (V >>  8) & 0xFF;
70     v[0] = (V      ) & 0xFF;
71   }
72   inline operator Type (void) const
73   {
74     return (v[2] << 16)
75          + (v[1] <<  8)
76          + (v[0]      );
77   }
78   private: uint8_t v[3];
79 };
80 template <typename Type>
81 struct LEInt<Type, 4>
82 {
83   public:
84   inline void set (Type V)
85   {
86     v[3] = (V >> 24) & 0xFF;
87     v[2] = (V >> 16) & 0xFF;
88     v[1] = (V >>  8) & 0xFF;
89     v[0] = (V      ) & 0xFF;
90   }
91   inline operator Type (void) const
92   {
93     return (v[3] << 24)
94          + (v[2] << 16)
95          + (v[1] <<  8)
96          + (v[0]      );
97   }
98   private: uint8_t v[4];
99 };
100
101 template <typename Type, unsigned int Size>
102 struct LEIntType
103 {
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
107   {
108     TRACE_SANITIZE (this);
109     return_trace (likely (c->check_struct (this)));
110   }
111   protected:
112   LEInt<Type, Size> v;
113   public:
114   DEFINE_SIZE_STATIC (Size);
115 };
116
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. */
124
125
126 struct LE_FONTINFO16
127 {
128   inline bool sanitize (OT::hb_sanitize_context_t *c, unsigned int length) const
129   {
130     TRACE_SANITIZE (this);
131     return_trace (likely (c->check_struct (this) && c->check_range (this, length)));
132   }
133
134   // https://msdn.microsoft.com/en-us/library/cc194829.aspx
135   enum charset_t
136   {
137     // dfCharSet possible values and the codepage they are indicating to
138     ANSI        = 0x00, // 1252
139     DEFAULT     = 0x01, //
140     SYMBOL      = 0x02, //
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
151     THAI        = 0xDE, // 874
152     EE          = 0xEE, // 1250
153     OEM         = 0xFF  //
154   };
155
156   inline const char* get_charset() const
157   {
158     switch (dfCharSet) {
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";
176     }
177   }
178
179   inline unsigned int get_version () const
180   {
181     return dfVersion;
182   }
183
184   inline unsigned int get_weight () const
185   {
186     return dfWeight;
187   }
188
189   enum weight_t {
190     DONTCARE    = 0,
191     THIN        = 100,
192     EXTRALIGHT  = 200,
193     ULTRALIGHT  = 200,
194     LIGHT       = 300,
195     NORMAL      = 400,
196     REGULAR     = 400,
197     MEDIUM      = 500,
198     SEMIBOLD    = 600,
199     DEMIBOLD    = 600,
200     BOLD        = 700,
201     EXTRABOLD   = 800,
202     ULTRABOLD   = 800,
203     HEAVY       = 900,
204     BLACK       = 900
205   };
206
207   inline void dump () const
208   {
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;
212     unsigned int ctsize;
213     if (dfVersion == 0x200)
214     {
215       ctstart = 0x76;
216       ctsize = 4;
217     }
218     else
219     {
220       return; // must of ".fon"s are version 2 and even dewinfont V1 implmentation doesn't seem correct
221       ctstart = 0x94;
222       ctsize = 6;
223     }
224     // unsigned int maxwidth = 0;
225     for (unsigned int i = dfFirstChar; i < dfLastChar; ++i)
226     {
227       unsigned int entry = ctstart + ctsize * (i-dfFirstChar);
228       unsigned int w = (uint16_t) OT::StructAtOffset<LEUINT16> (this, entry);
229
230       unsigned int off;
231       if (ctsize == 4)
232         off = (uint16_t) OT::StructAtOffset<LEUINT16> (this, entry+2);
233       else
234         off = (uint32_t) OT::StructAtOffset<LEUINT32> (this, entry+2);
235
236       unsigned int widthbytes = (w + 7) / 8;
237       for (unsigned int j = 0; j < dfPixHeight; ++j)
238       {
239         for (unsigned int k = 0; k < widthbytes; ++k)
240         {
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" : ".");
245         }
246         printf ("\n");
247       }
248       printf ("\n\n");
249     }
250   }
251
252   protected:
253   LEUINT16      dfVersion;
254   LEUINT32      dfSize;
255   LEUINT8       dfCopyright[60];
256   LEUINT16      dfType;
257   LEUINT16      dfPoints;
258   LEUINT16      dfVertRes;
259   LEUINT16      dfHorizRes;
260   LEUINT16      dfAscent;
261   LEUINT16      dfInternalLeading;
262   LEUINT16      dfExternalLeading;
263   LEUINT8       dfItalic;
264   LEUINT8       dfUnderline;
265   LEUINT8       dfStrikeOut;
266   LEUINT16      dfWeight; // see weight_t
267   LEUINT8       dfCharSet;  // see charset_t
268   LEUINT16      dfPixWidth;
269   LEUINT16      dfPixHeight;
270   LEUINT8       dfPitchAndFamily;
271   LEUINT16      dfAvgWidth;
272   LEUINT16      dfMaxWidth;
273   LEUINT8       dfFirstChar;
274   LEUINT8       dfLastChar;
275   LEUINT8       dfDefaultChar;
276   LEUINT8       dfBreakChar;
277   LEUINT16      dfWidthBytes;
278   LEUINT32      dfDevice;
279   LEUINT32      dfFace;
280   LEUINT32      dfBitsPointer;
281   LEUINT32      dfBitsOffset;
282   LEUINT8       dfReserved;
283 //   LEUINT32   dfFlags;
284 //   LEUINT16   dfAspace;
285 //   LEUINT16   dfBspace;
286 //   LEUINT16   dfCspace;
287 //   LEUINT32   dfColorPointer;
288 //   LEUINT32   dfReserved1[4];
289   OT::UnsizedArrayOf<LEUINT8>
290                 dataZ;
291   public:
292   DEFINE_SIZE_ARRAY (118, dataZ);
293 };
294
295 struct NE_NAMEINFO
296 {
297   friend struct NE_TYPEINFO;
298
299   inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base, unsigned int shift) const
300   {
301     TRACE_SANITIZE (this);
302     return_trace (likely (c->check_struct (this) &&
303                           get_font (base, shift).sanitize (c, length << shift)));
304   }
305
306   inline const LE_FONTINFO16& get_font (const void *base, int shift) const
307   {
308     return OT::StructAtOffset<LE_FONTINFO16> (base, offset << shift);
309   }
310
311   enum resource_type_flag_t {
312     NONE     = 0x0000,
313     MOVEABLE = 0x0010,
314     PURE     = 0x0020,
315     PRELOAD  = 0x0040
316   };
317
318   protected:
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
322   LEUINT16      id;
323   LEUINT16      handle;
324   LEUINT16      usage;
325   public:
326   DEFINE_SIZE_STATIC (12);
327 };
328
329 struct NE_TYPEINFO
330 {
331   inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base, unsigned int shift) const
332   {
333     TRACE_SANITIZE (this);
334     return_trace (c->check_struct (this) && resources.sanitize (c, count, base, shift));
335   }
336
337   inline unsigned int get_size (void) const
338   { return 8 + count * NE_NAMEINFO::static_size; }
339
340   inline const NE_TYPEINFO& next () const
341   {
342     const NE_TYPEINFO& next = OT::StructAfter<NE_TYPEINFO> (*this);
343     if (type_id == 0)
344       return Null(NE_TYPEINFO);
345     return next;
346   }
347
348   inline const LE_FONTINFO16& get_font (unsigned int idx, const void *base, int shift) const
349   {
350     if (idx < count)
351       return resources[idx].get_font (base, shift);
352     return Null(LE_FONTINFO16);
353   }
354
355   inline unsigned int get_count () const
356   {
357     return count;
358   }
359
360   inline unsigned int get_type_id () const
361   {
362     return type_id;
363   }
364
365   enum type_id_t {
366     CURSOR              = 0x8001,
367     BITMAP              = 0x8002,
368     ICON                = 0x8003,
369     MENU                = 0x8004,
370     DIALOG              = 0x8005,
371     STRING              = 0x8006,
372     FONT_DIRECTORY      = 0x8007,
373     FONT                = 0x8008,
374     ACCELERATOR_TABLE   = 0x8009,
375     RESOURCE_DATA       = 0x800a,
376     GROUP_CURSOR        = 0x800c,
377     GROUP_ICON          = 0x800e,
378     VERSION             = 0x8010
379   };
380
381   protected:
382   LEUINT16      type_id; // see type_id_t
383   LEUINT16      count;
384   LEUINT32      resloader;
385   OT::UnsizedArrayOf<NE_NAMEINFO>
386                 resources;
387   public:
388   DEFINE_SIZE_ARRAY (8, resources);
389 };
390
391 struct NE_RESOURCE_TABLE
392 {
393   inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base) const
394   {
395     TRACE_SANITIZE (this);
396
397     if (!c->check_struct (this))
398       return_trace (false);
399
400     const NE_TYPEINFO* n = &chain;
401     while (n != &Null(NE_TYPEINFO) && c->check_struct (n) && n->get_type_id () != 0)
402     {
403       if (n->get_type_id () == NE_TYPEINFO::FONT)
404         return_trace (n->sanitize (c, base, alignmentShiftCount));
405       n = &n->next();
406     }
407     return_trace (false);
408   }
409
410   inline unsigned int get_shift_value () const
411   {
412     return alignmentShiftCount;
413   }
414
415   inline const NE_TYPEINFO& get_fonts_entry () const
416   {
417     const NE_TYPEINFO* n = &chain;
418     while (n != &Null(NE_TYPEINFO) && n->get_type_id () != 0)
419     {
420       if (n->get_type_id () == NE_TYPEINFO::FONT)
421         return *n;
422       n = &n->next();
423     }
424     return Null(NE_TYPEINFO);
425   }
426
427   protected:
428   LEUINT16      alignmentShiftCount;
429   NE_TYPEINFO   chain;
430   // It is followed by an array of OT::ArrayOf<LEUINT8, LEUINT8> chars;
431   public:
432   DEFINE_SIZE_MIN (2);
433 };
434
435 // https://github.com/wine-mirror/wine/blob/master/include/winnt.h#L2467
436 struct LE_IMAGE_OS2_HEADER
437 {
438   inline bool sanitize (OT::hb_sanitize_context_t *c, const void *base) const
439   {
440     TRACE_SANITIZE (this);
441     return_trace (likely (c->check_struct (this) && (this+rsrctab).sanitize (c, base)));
442   }
443
444   inline const NE_RESOURCE_TABLE& get_resource_table () const
445   {
446     if (magic != 0x454E) // Only NE containers are support for now, NE == 0x454E
447       return Null(NE_RESOURCE_TABLE);
448     return this+rsrctab;
449   }
450
451   protected:
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 */
483   public:
484   DEFINE_SIZE_STATIC (64);
485 };
486
487 struct LE_IMAGE_DOS_HEADER {
488   inline bool sanitize (OT::hb_sanitize_context_t *c) const
489   {
490     TRACE_SANITIZE (this);
491     return_trace (likely (c->check_struct (this) &&
492                           get_os2_header ().sanitize (c, this)));
493   }
494
495   inline const LE_IMAGE_OS2_HEADER& get_os2_header () const
496   {
497     return this+e_lfanew;
498   }
499
500   protected:
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
533   public:
534   DEFINE_SIZE_STATIC (64);
535 };
536
537 int main (int argc, char** argv) {
538   hb_blob_t *blob = hb_blob_create_from_file (argv[1]);
539
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> ();
543
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)
548   {
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 ());
552     // font.dump ();
553   }
554   return 0;
555 }