001/*
002 * $Id: Pfm2afm.java 4784 2011-03-15 08:33:00Z blowagie $
003 *
004 * This file is part of the iText (R) project.
005 * Copyright (c) 1998-2011 1T3XT BVBA
006 * Authors: Bruno Lowagie, Paulo Soares, et al.
007 *
008 * This program is free software; you can redistribute it and/or modify
009 * it under the terms of the GNU Affero General Public License version 3
010 * as published by the Free Software Foundation with the addition of the
011 * following permission added to Section 15 as permitted in Section 7(a):
012 * FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY 1T3XT,
013 * 1T3XT DISCLAIMS THE WARRANTY OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
014 *
015 * This program is distributed in the hope that it will be useful, but
016 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
017 * or FITNESS FOR A PARTICULAR PURPOSE.
018 * See the GNU Affero General Public License for more details.
019 * You should have received a copy of the GNU Affero General Public License
020 * along with this program; if not, see http://www.gnu.org/licenses or write to
021 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
022 * Boston, MA, 02110-1301 USA, or download the license from the following URL:
023 * http://itextpdf.com/terms-of-use/
024 *
025 * The interactive user interfaces in modified source and object code versions
026 * of this program must display Appropriate Legal Notices, as required under
027 * Section 5 of the GNU Affero General Public License.
028 *
029 * In accordance with Section 7(b) of the GNU Affero General Public License,
030 * a covered work must retain the producer line in every PDF that is created
031 * or manipulated using iText.
032 *
033 * You can be released from the requirements of the license by purchasing
034 * a commercial license. Buying such a license is mandatory as soon as you
035 * develop commercial activities involving the iText software without
036 * disclosing the source code of your own applications.
037 * These activities include: offering paid services to customers as an ASP,
038 * serving PDFs on the fly in a web application, shipping iText with a closed
039 * source product.
040 *
041 * For more information, please contact iText Software Corp. at this
042 * address: sales@itextpdf.com
043 */
044
045/********************************************************************
046 *                                                                  *
047 *  Title:  pfm2afm - Convert Windows .pfm files to .afm files      *
048 *                                                                  *
049 *  Author: Ken Borgendale   10/9/91  Version 1.0                   *
050 *                                                                  *
051 *  Function:                                                       *
052 *      Convert a Windows .pfm (Printer Font Metrics) file to a     *
053 *      .afm (Adobe Font Metrics) file.  The purpose of this is     *
054 *      to allow fonts put out for Windows to be used with OS/2.    *
055 *                                                                  *
056 *  Syntax:                                                         *
057 *      pfm2afm  infile  [outfile] -a                               *
058 *                                                                  *
059 *  Copyright:                                                      *
060 *      pfm2afm - Copyright (C) IBM Corp., 1991                     *
061 *                                                                  *
062 *      This code is released for public use as long as the         *
063 *      copyright remains intact.  This code is provided asis       *
064 *      without any warrenties, express or implied.                 *
065 *                                                                  *
066 *  Notes:                                                          *
067 *      1. Much of the information in the original .afm file is     *
068 *         lost when the .pfm file is created, and thus cannot be   *
069 *         reconstructed by this utility.  This is especially true  *
070 *         of data for characters not in the Windows character set. *
071 *                                                                  *
072 *      2. This module is coded to be compiled by the MSC 6.0.      *
073 *         For other compilers, be careful of the packing of the    *
074 *         PFM structure.                                           *
075 *                                                                  *
076 ********************************************************************/
077
078/********************************************************************
079 *                                                                  *
080 *  Modifications by Rod Smith, 5/22/96                             *
081 *                                                                  *
082 *  These changes look for the strings "italic", "bold", "black",   *
083 *  and "light" in the font's name and set the weight accordingly   *
084 *  and adds an ItalicAngle line with a value of "0" or "-12.00".   *
085 *  This allows OS/2 programs such as DeScribe to handle the bold   *
086 *  and italic attributes appropriately, which was not the case     *
087 *  when I used the original version on fonts from the KeyFonts     *
088 *  Pro 2002 font CD.                                               *
089 *                                                                  *
090 *  I've also increased the size of the buffer used to load the     *
091 *  .PFM file; the old size was inadequate for most of the fonts    *
092 *  from the SoftKey collection.                                    *
093 *                                                                  *
094 *  Compiled with Watcom C 10.6                                     *
095 *                                                                  *
096 ********************************************************************/
097 
098/********************************************************************
099 *                                                                  *
100 *  Further modifications, 4/21/98, by Rod Smith                    *
101 *                                                                  *
102 *  Minor changes to get the program to compile with gcc under      *
103 *  Linux (Red Hat 5.0, to be precise).  I had to add an itoa       *
104 *  function from the net (the function was buggy, so I had to fix  *
105 *  it, too!).  I also made the program more friendly towards       *
106 *  files with mixed-case filenames.                                *
107 *                                                                  *
108 ********************************************************************/
109
110/********************************************************************
111 *                                                                  *
112 *  1/31/2005, by Paulo Soares                                      *
113 *                                                                  *
114 *  This code was integrated into iText.                            * 
115 *  Note that the itoa function mentioned in the comment by Rod     *
116 *  Smith is no longer in the code because Java has native support  *
117 *  in PrintWriter to convert integers to strings                   *
118 *                                                                  *
119 ********************************************************************/
120
121/********************************************************************
122 *                                                                  *
123 *  7/16/2005, by Bruno Lowagie                                     *
124 *                                                                  *
125 *  I solved an Eclipse Warning.                                    *
126 *                                                                  *
127 ********************************************************************/
128
129/********************************************************************
130 *                                                                  *
131 *  9/14/2006, by Xavier Le Vourch                                  *
132 *                                                                  *
133 *  expand import clauses (import java.io.*)                        *                                           
134 *  the removal of an exception in readString was restored on 9/16  *
135 *                                                                  *
136 ********************************************************************/
137package com.itextpdf.text.pdf;
138
139import java.io.FileOutputStream;
140import java.io.IOException;
141import java.io.OutputStream;
142import java.io.OutputStreamWriter;
143import java.io.PrintWriter;
144import com.itextpdf.text.error_messages.MessageLocalization;
145
146/**
147 * Converts a PFM file into an AFM file.
148 */
149public final class Pfm2afm {
150    private RandomAccessFileOrArray in;
151    private PrintWriter out;
152    
153    /** Creates a new instance of Pfm2afm */
154    private Pfm2afm(RandomAccessFileOrArray in, OutputStream out) throws IOException {
155        this.in = in;
156        this.out = new PrintWriter(new OutputStreamWriter(out, "ISO-8859-1"));
157    }
158    
159    /**
160     * Converts a PFM file into an AFM file.
161     * @param in the PFM file
162     * @param out the AFM file
163     * @throws IOException on error
164     */    
165    public static void convert(RandomAccessFileOrArray in, OutputStream out) throws IOException {
166        Pfm2afm p = new Pfm2afm(in, out);
167        p.openpfm();
168        p.putheader();
169        p.putchartab();
170        p.putkerntab();
171        p.puttrailer();
172        p.out.flush();
173    }
174    
175    /*
176    public static void main(String[] args) {
177        try {
178            RandomAccessFileOrArray in = new RandomAccessFileOrArray(args[0]);
179            OutputStream out = new FileOutputStream(args[1]);
180            convert(in, out);
181            in.close();
182            out.close();
183        }
184        catch (Exception e) {
185            e.printStackTrace();
186        }
187    }
188    */
189    
190    private String readString(int n) throws IOException {
191        byte b[] = new byte[n];
192        in.readFully(b);
193        int k;
194        for (k = 0; k < b.length; ++k) {
195            if (b[k] == 0)
196                break;
197        }
198        return new String(b, 0, k, "ISO-8859-1");
199    }
200    
201    private String readString() throws IOException {
202        StringBuffer buf = new StringBuffer();
203        while (true) {
204            int c = in.read();
205            if (c <= 0)
206                break;
207            buf.append((char)c);
208        }
209        return buf.toString();
210    }
211    
212    private void outval(int n) {
213        out.print(' ');
214        out.print(n);
215    }
216    
217    /*
218     *  Output a character entry
219     */
220    private void  outchar(int code, int width, String name) {
221        out.print("C ");
222        outval(code);
223        out.print(" ; WX ");
224        outval(width);
225        if (name != null) {
226            out.print(" ; N ");
227            out.print(name);
228        }
229        out.print(" ;\n");
230    }
231    
232    private void openpfm() throws IOException {
233        in.seek(0);
234        vers = in.readShortLE();
235        h_len = in.readIntLE();
236        copyright = readString(60);
237        type = in.readShortLE();
238        points = in.readShortLE();
239        verres = in.readShortLE();
240        horres = in.readShortLE();
241        ascent = in.readShortLE();
242        intleading = in.readShortLE();
243        extleading = in.readShortLE();
244        italic = (byte)in.read();
245        uline = (byte)in.read();
246        overs = (byte)in.read();
247        weight = in.readShortLE();
248        charset = (byte)in.read();
249        pixwidth = in.readShortLE();
250        pixheight = in.readShortLE();
251        kind = (byte)in.read();
252        avgwidth = in.readShortLE();
253        maxwidth = in.readShortLE();
254        firstchar = in.read();
255        lastchar = in.read();
256        defchar = (byte)in.read();
257        brkchar = (byte)in.read();
258        widthby = in.readShortLE();
259        device = in.readIntLE();
260        face = in.readIntLE();
261        bits = in.readIntLE();
262        bitoff = in.readIntLE();
263        extlen = in.readShortLE();
264        psext = in.readIntLE();
265        chartab = in.readIntLE();
266        res1 = in.readIntLE();
267        kernpairs = in.readIntLE();
268        res2 = in.readIntLE();
269        fontname = in.readIntLE();
270        if (h_len != in.length() || extlen != 30 || fontname < 75 || fontname > 512)
271            throw new IOException(MessageLocalization.getComposedMessage("not.a.valid.pfm.file"));
272        in.seek(psext + 14);
273        capheight = in.readShortLE();
274        xheight = in.readShortLE();
275        ascender = in.readShortLE();
276        descender = in.readShortLE();
277    }
278    
279    private void putheader() throws IOException {
280        out.print("StartFontMetrics 2.0\n");
281        if (copyright.length() > 0)
282            out.print("Comment " + copyright + '\n');
283        out.print("FontName ");
284        in.seek(fontname);
285        String fname = readString();
286        out.print(fname);
287        out.print("\nEncodingScheme ");
288        if (charset != 0)
289            out.print("FontSpecific\n");
290        else
291            out.print("AdobeStandardEncoding\n");
292        /*
293         * The .pfm is missing full name, so construct from font name by
294         * changing the hyphen to a space.  This actually works in a lot
295         * of cases.
296         */
297        out.print("FullName " + fname.replace('-', ' '));
298        if (face != 0) {
299            in.seek(face);
300            out.print("\nFamilyName " + readString());
301        }
302
303        out.print("\nWeight ");
304        if (weight > 475 || fname.toLowerCase().indexOf("bold") >= 0)
305           out.print("Bold");
306        else if ((weight < 325 && weight != 0) || fname.toLowerCase().indexOf("light") >= 0)
307            out.print("Light");
308        else if (fname.toLowerCase().indexOf("black") >= 0)
309            out.print("Black");
310        else 
311            out.print("Medium");
312
313        out.print("\nItalicAngle ");
314        if (italic != 0 || fname.toLowerCase().indexOf("italic") >= 0)
315            out.print("-12.00");
316            /* this is a typical value; something else may work better for a
317               specific font */
318        else
319            out.print("0");
320
321        /*
322         *  The mono flag in the pfm actually indicates whether there is a
323         *  table of font widths, not if they are all the same.
324         */
325        out.print("\nIsFixedPitch ");
326        if ((kind & 1) == 0 ||                  /* Flag for mono */
327            avgwidth == maxwidth ) {  /* Avg width = max width */
328            out.print("true");
329            isMono = true;
330        }
331        else {
332            out.print("false");
333            isMono = false;
334        }
335
336        /*
337         * The font bounding box is lost, but try to reconstruct it.
338         * Much of this is just guess work.  The bounding box is required in
339         * the .afm, but is not used by the PM font installer.
340         */
341        out.print("\nFontBBox");
342        if (isMono)
343            outval(-20);      /* Just guess at left bounds */
344        else 
345            outval(-100);
346        outval(-(descender+5));  /* Descender is given as positive value */
347        outval(maxwidth+10);
348        outval(ascent+5);
349
350        /*
351         * Give other metrics that were kept
352         */
353        out.print("\nCapHeight");
354        outval(capheight);
355        out.print("\nXHeight");
356        outval(xheight);
357        out.print("\nDescender");
358        outval(-descender);
359        out.print("\nAscender");
360        outval(ascender);
361        out.print('\n');
362    }
363    
364    private void putchartab() throws IOException {
365        int count = lastchar - firstchar + 1;
366        int ctabs[] = new int[count];
367        in.seek(chartab);
368        for (int k = 0; k < count; ++k)
369            ctabs[k] = in.readUnsignedShortLE();
370        int back[] = new int[256];
371        if (charset == 0) {
372            for (int i = firstchar; i <= lastchar; ++i) {
373                if (Win2PSStd[i] != 0)
374                    back[Win2PSStd[i]] = i;
375            }
376        }
377        /* Put out the header */
378        out.print("StartCharMetrics");
379        outval(count);
380        out.print('\n');
381
382        /* Put out all encoded chars */
383        if (charset != 0) {
384        /*
385         * If the charset is not the Windows standard, just put out
386         * unnamed entries.
387         */
388            for (int i = firstchar; i <= lastchar; i++) {
389                if (ctabs[i - firstchar] != 0) {
390                    outchar(i, ctabs[i - firstchar], null);
391                }
392            }
393        }
394        else {
395            for (int i = 0; i < 256; i++) {
396                int j = back[i];
397                if (j != 0) {
398                    outchar(i, ctabs[j - firstchar], WinChars[j]);
399                    ctabs[j - firstchar] = 0;
400                }
401            }
402            /* Put out all non-encoded chars */
403            for (int i = firstchar; i <= lastchar; i++) {
404                if (ctabs[i - firstchar] != 0) {
405                    outchar(-1, ctabs[i - firstchar], WinChars[i]);
406                }
407            }
408        }
409        /* Put out the trailer */
410        out.print("EndCharMetrics\n");
411        
412    }
413    
414    private void putkerntab() throws IOException {
415        if (kernpairs == 0)
416            return;
417        in.seek(kernpairs);
418        int count = in.readUnsignedShortLE();
419        int nzero = 0;
420        int kerns[] = new int[count * 3];
421        for (int k = 0; k < kerns.length;) {
422            kerns[k++] = in.read();
423            kerns[k++] = in.read();
424            if ((kerns[k++] = in.readShortLE()) != 0)
425                ++nzero;
426        }
427        if (nzero == 0)
428            return;
429        out.print("StartKernData\nStartKernPairs");
430        outval(nzero);
431        out.print('\n');
432        for (int k = 0; k < kerns.length; k += 3) {
433            if (kerns[k + 2] != 0) {
434                out.print("KPX ");
435                out.print(WinChars[kerns[k]]);
436                out.print(' ');
437                out.print(WinChars[kerns[k + 1]]);
438                outval(kerns[k + 2]);
439                out.print('\n');
440            }
441        }
442        /* Put out trailer */
443        out.print("EndKernPairs\nEndKernData\n");
444    }
445    
446
447    private void  puttrailer() {
448        out.print("EndFontMetrics\n");
449    }
450
451    private short  vers;
452    private int   h_len;             /* Total length of .pfm file */
453    private String   copyright;   /* Copyright string [60]*/
454    private short  type;
455    private short  points;
456    private short  verres;
457    private short  horres;
458    private short  ascent;
459    private short  intleading;
460    private short  extleading;
461    private byte   italic;
462    private byte   uline;
463    private byte   overs;
464    private short  weight;
465    private byte   charset;         /* 0=windows, otherwise nomap */
466    private short  pixwidth;        /* Width for mono fonts */
467    private short  pixheight;
468    private byte   kind;            /* Lower bit off in mono */
469    private short  avgwidth;        /* Mono if avg=max width */
470    private short  maxwidth;        /* Use to compute bounding box */
471    private int   firstchar;       /* First char in table */
472    private int   lastchar;        /* Last char in table */
473    private byte   defchar;
474    private byte   brkchar;
475    private short  widthby;
476    private int   device;
477    private int   face;            /* Face name */
478    private int   bits;
479    private int   bitoff;
480    private short  extlen;
481    private int   psext;           /* PostScript extension */
482    private int   chartab;         /* Character width tables */
483    private int   res1;
484    private int   kernpairs;       /* Kerning pairs */
485    private int   res2;
486    private int   fontname;        /* Font name */
487
488/*
489 *  Some metrics from the PostScript extension
490 */
491    private short  capheight;       /* Cap height */
492    private short  xheight;         /* X height */
493    private short  ascender;        /* Ascender */
494    private short  descender;       /* Descender (positive) */
495
496    
497    private boolean isMono;
498/**
499 * Translate table from 1004 to psstd.  1004 is an extension of the
500 * Windows translate table used in PM.
501 */
502    private int Win2PSStd[] = {
503        0,   0,   0,   0, 197, 198, 199,   0, 202,   0,   205, 206, 207, 0,   0,   0,   // 00
504        0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   // 10
505        32,  33,  34,  35,  36,  37,  38, 169,  40,  41,  42,  43,  44,  45,  46,  47,  // 20
506        48,  49,  50,  51,  52,  53,  54,  55,  56,  57,  58,  59,  60,  61,  62,  63,  // 30
507        64,  65,  66,  67,  68,  69,  70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  // 40
508        80,  81,  82,  83,  84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  // 50
509        193, 97,  98,  99,  100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, // 60
510        112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, // 70
511        128, 0,   184, 166, 185, 188, 178, 179, 195, 189, 0,   172, 234, 0,   0,   0,   // 80
512        0,   96,  0,   170, 186, 183, 177, 208, 196, 0,   0,   173, 250, 0,   0,   0,   // 90
513        0,   161, 162, 163, 168, 165, 0,   167, 200, 0,   227, 171, 0,   0,   0,   197, // A0
514        0,   0,   0,   0,   194, 0,   182, 180, 203, 0,   235, 187, 0,   0,   0,   191, // B0
515        0,   0,   0,   0,   0,   0,   225, 0,   0,   0,   0,   0,   0,   0,   0,   0,   // C0
516        0,   0,   0,   0,   0,   0,   0,   0,   233, 0,   0,   0,   0,   0,   0,   251, // D0
517        0,   0,   0,   0,   0,   0,   241, 0,   0,   0,   0,   0,   0,   0,   0,   0,   // E0
518        0,   0,   0,   0,   0,   0,   0,   0,   249, 0,   0,   0,   0,   0,   0,   0    // F0
519    };
520    
521/**
522 *  Character class.  This is a minor attempt to overcome the problem that
523 *  in the pfm file, all unused characters are given the width of space.
524 *  Note that this array isn't used in iText.
525 */
526    private int WinClass[] = {
527        0, 0, 0, 0, 2, 2, 2, 0, 2, 0, 2, 2, 2, 0, 0, 0,   /* 00 */
528        0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   /* 10 */
529        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   /* 20 */
530        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   /* 30 */
531        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   /* 40 */
532        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   /* 50 */
533        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   /* 60 */
534        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2,   /* 70 */
535        0, 0, 2, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0,   /* 80 */
536        0, 3, 3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 2,   /* 90 */
537        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   /* a0 */
538        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   /* b0 */
539        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   /* c0 */
540        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   /* d0 */
541        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,   /* e0 */
542        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1   /* f0 */
543    };
544    
545/**
546 *  Windows character names.  Give a name to the used locations
547 *  for when the all flag is specified.
548 */
549    private String WinChars[] = {
550        "W00",              /*   00    */
551        "W01",              /*   01    */
552        "W02",              /*   02    */
553        "W03",              /*   03    */
554        "macron",           /*   04    */
555        "breve",            /*   05    */
556        "dotaccent",        /*   06    */
557        "W07",              /*   07    */
558        "ring",             /*   08    */
559        "W09",              /*   09    */
560        "W0a",              /*   0a    */
561        "W0b",              /*   0b    */
562        "W0c",              /*   0c    */
563        "W0d",              /*   0d    */
564        "W0e",              /*   0e    */
565        "W0f",              /*   0f    */
566        "hungarumlaut",     /*   10    */
567        "ogonek",           /*   11    */
568        "caron",            /*   12    */
569        "W13",              /*   13    */
570        "W14",              /*   14    */
571        "W15",              /*   15    */
572        "W16",              /*   16    */
573        "W17",              /*   17    */
574        "W18",              /*   18    */
575        "W19",              /*   19    */
576        "W1a",              /*   1a    */
577        "W1b",              /*   1b    */
578        "W1c",              /*   1c    */
579        "W1d",              /*   1d    */
580        "W1e",              /*   1e    */
581        "W1f",              /*   1f    */
582        "space",            /*   20    */
583        "exclam",           /*   21    */
584        "quotedbl",         /*   22    */
585        "numbersign",       /*   23    */
586        "dollar",           /*   24    */
587        "percent",          /*   25    */
588        "ampersand",        /*   26    */
589        "quotesingle",      /*   27    */
590        "parenleft",        /*   28    */
591        "parenright",       /*   29    */
592        "asterisk",         /*   2A    */
593        "plus",             /*   2B    */
594        "comma",            /*   2C    */
595        "hyphen",           /*   2D    */
596        "period",           /*   2E    */
597        "slash",            /*   2F    */
598        "zero",             /*   30    */
599        "one",              /*   31    */
600        "two",              /*   32    */
601        "three",            /*   33    */
602        "four",             /*   34    */
603        "five",             /*   35    */
604        "six",              /*   36    */
605        "seven",            /*   37    */
606        "eight",            /*   38    */
607        "nine",             /*   39    */
608        "colon",            /*   3A    */
609        "semicolon",        /*   3B    */
610        "less",             /*   3C    */
611        "equal",            /*   3D    */
612        "greater",          /*   3E    */
613        "question",         /*   3F    */
614        "at",               /*   40    */
615        "A",                /*   41    */
616        "B",                /*   42    */
617        "C",                /*   43    */
618        "D",                /*   44    */
619        "E",                /*   45    */
620        "F",                /*   46    */
621        "G",                /*   47    */
622        "H",                /*   48    */
623        "I",                /*   49    */
624        "J",                /*   4A    */
625        "K",                /*   4B    */
626        "L",                /*   4C    */
627        "M",                /*   4D    */
628        "N",                /*   4E    */
629        "O",                /*   4F    */
630        "P",                /*   50    */
631        "Q",                /*   51    */
632        "R",                /*   52    */
633        "S",                /*   53    */
634        "T",                /*   54    */
635        "U",                /*   55    */
636        "V",                /*   56    */
637        "W",                /*   57    */
638        "X",                /*   58    */
639        "Y",                /*   59    */
640        "Z",                /*   5A    */
641        "bracketleft",      /*   5B    */
642        "backslash",        /*   5C    */
643        "bracketright",     /*   5D    */
644        "asciicircum",      /*   5E    */
645        "underscore",       /*   5F    */
646        "grave",            /*   60    */
647        "a",                /*   61    */
648        "b",                /*   62    */
649        "c",                /*   63    */
650        "d",                /*   64    */
651        "e",                /*   65    */
652        "f",                /*   66    */
653        "g",                /*   67    */
654        "h",                /*   68    */
655        "i",                /*   69    */
656        "j",                /*   6A    */
657        "k",                /*   6B    */
658        "l",                /*   6C    */
659        "m",                /*   6D    */
660        "n",                /*   6E    */
661        "o",                /*   6F    */
662        "p",                /*   70    */
663        "q",                /*   71    */
664        "r",                /*   72    */
665        "s",                /*   73    */
666        "t",                /*   74    */
667        "u",                /*   75    */
668        "v",                /*   76    */
669        "w",                /*   77    */
670        "x",                /*   78    */
671        "y",                /*   79    */
672        "z",                /*   7A    */
673        "braceleft",        /*   7B    */
674        "bar",              /*   7C    */
675        "braceright",       /*   7D    */
676        "asciitilde",       /*   7E    */
677        "W7f",              /*   7F    */
678        "euro",             /*   80    */
679        "W81",              /*   81    */
680        "quotesinglbase",   /*   82    */
681        "florin",           /*   83    */
682        "quotedblbase",     /*   84    */
683        "ellipsis",         /*   85    */
684        "dagger",           /*   86    */
685        "daggerdbl",        /*   87    */
686        "circumflex",       /*   88    */
687        "perthousand",      /*   89    */
688        "Scaron",           /*   8A    */
689        "guilsinglleft",    /*   8B    */
690        "OE",               /*   8C    */
691        "W8d",              /*   8D    */
692        "Zcaron",           /*   8E    */
693        "W8f",              /*   8F    */
694        "W90",              /*   90    */
695        "quoteleft",        /*   91    */
696        "quoteright",       /*   92    */
697        "quotedblleft",     /*   93    */
698        "quotedblright",    /*   94    */
699        "bullet",           /*   95    */
700        "endash",           /*   96    */
701        "emdash",           /*   97    */
702        "tilde",            /*   98    */
703        "trademark",        /*   99    */
704        "scaron",           /*   9A    */
705        "guilsinglright",   /*   9B    */
706        "oe",               /*   9C    */
707        "W9d",              /*   9D    */
708        "zcaron",           /*   9E    */
709        "Ydieresis",        /*   9F    */
710        "reqspace",         /*   A0    */
711        "exclamdown",       /*   A1    */
712        "cent",             /*   A2    */
713        "sterling",         /*   A3    */
714        "currency",         /*   A4    */
715        "yen",              /*   A5    */
716        "brokenbar",        /*   A6    */
717        "section",          /*   A7    */
718        "dieresis",         /*   A8    */
719        "copyright",        /*   A9    */
720        "ordfeminine",      /*   AA    */
721        "guillemotleft",    /*   AB    */
722        "logicalnot",       /*   AC    */
723        "syllable",         /*   AD    */
724        "registered",       /*   AE    */
725        "macron",           /*   AF    */
726        "degree",           /*   B0    */
727        "plusminus",        /*   B1    */
728        "twosuperior",      /*   B2    */
729        "threesuperior",    /*   B3    */
730        "acute",            /*   B4    */
731        "mu",               /*   B5    */
732        "paragraph",        /*   B6    */
733        "periodcentered",   /*   B7    */
734        "cedilla",          /*   B8    */
735        "onesuperior",      /*   B9    */
736        "ordmasculine",     /*   BA    */
737        "guillemotright",   /*   BB    */
738        "onequarter",       /*   BC    */
739        "onehalf",          /*   BD    */
740        "threequarters",    /*   BE    */
741        "questiondown",     /*   BF    */
742        "Agrave",           /*   C0    */
743        "Aacute",           /*   C1    */
744        "Acircumflex",      /*   C2    */
745        "Atilde",           /*   C3    */
746        "Adieresis",        /*   C4    */
747        "Aring",            /*   C5    */
748        "AE",               /*   C6    */
749        "Ccedilla",         /*   C7    */
750        "Egrave",           /*   C8    */
751        "Eacute",           /*   C9    */
752        "Ecircumflex",      /*   CA    */
753        "Edieresis",        /*   CB    */
754        "Igrave",           /*   CC    */
755        "Iacute",           /*   CD    */
756        "Icircumflex",      /*   CE    */
757        "Idieresis",        /*   CF    */
758        "Eth",              /*   D0    */
759        "Ntilde",           /*   D1    */
760        "Ograve",           /*   D2    */
761        "Oacute",           /*   D3    */
762        "Ocircumflex",      /*   D4    */
763        "Otilde",           /*   D5    */
764        "Odieresis",        /*   D6    */
765        "multiply",         /*   D7    */
766        "Oslash",           /*   D8    */
767        "Ugrave",           /*   D9    */
768        "Uacute",           /*   DA    */
769        "Ucircumflex",      /*   DB    */
770        "Udieresis",        /*   DC    */
771        "Yacute",           /*   DD    */
772        "Thorn",            /*   DE    */
773        "germandbls",       /*   DF    */
774        "agrave",           /*   E0    */
775        "aacute",           /*   E1    */
776        "acircumflex",      /*   E2    */
777        "atilde",           /*   E3    */
778        "adieresis",        /*   E4    */
779        "aring",            /*   E5    */
780        "ae",               /*   E6    */
781        "ccedilla",         /*   E7    */
782        "egrave",           /*   E8    */
783        "eacute",           /*   E9    */
784        "ecircumflex",      /*   EA    */
785        "edieresis",        /*   EB    */
786        "igrave",           /*   EC    */
787        "iacute",           /*   ED    */
788        "icircumflex",      /*   EE    */
789        "idieresis",        /*   EF    */
790        "eth",              /*   F0    */
791        "ntilde",           /*   F1    */
792        "ograve",           /*   F2    */
793        "oacute",           /*   F3    */
794        "ocircumflex",      /*   F4    */
795        "otilde",           /*   F5    */
796        "odieresis",        /*   F6    */
797        "divide",           /*   F7    */
798        "oslash",           /*   F8    */
799        "ugrave",           /*   F9    */
800        "uacute",           /*   FA    */
801        "ucircumflex",      /*   FB    */
802        "udieresis",        /*   FC    */
803        "yacute",           /*   FD    */
804        "thorn",            /*   FE    */
805        "ydieresis"         /*   FF    */
806    };
807}