home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / wps / utils / atmfonts / pfm2afm / pfm2afm.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-11-30  |  16.7 KB  |  604 lines

  1. /*****************************************************************************/
  2. /*                                                                           */
  3. /*                               P F M 2 A F M                               */
  4. /*                                                                           */
  5. /*****************************************************************************/
  6.  
  7.  
  8. /* changes by m.schmidt (11/1992):
  9.    - bug fix for the names above code 128
  10.    - pfm-analysis
  11.    - Weight,Italics-Guessing
  12.    - wfont-name for FamilyName
  13.  
  14.    Manufacturing (dont forget the big stack!):
  15.     cl /AL /Zp /Lp pfm2afm.c /link /NOD /PM:VIO /ST:12000 os2.lib llibcep.lib
  16. */
  17.  
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <string.h>
  21.  
  22. #include "pfm2afm.h"
  23.  
  24. #define GUESS(name,what,where, what2) if (strstr(name,what)!=NULL) \
  25.                                         strcpy(where,what2);
  26.  
  27. void process_pfb(FILE *);
  28. void name_guessing(char *);
  29. void after_space_copy(char *, char *);
  30. void to_space_copy(char *, char *);
  31.  
  32. /* don't tell me anything about software-engeneering! 
  33.    better remove the globals for yourself! :-)  (ms) */
  34. extern const char *charname[];
  35. char ItalicAngle[100]= "";
  36. char FamilyName[100]= "";
  37. char Weight[100]= "";
  38. char FontBBox[100]= "";
  39.  
  40.  
  41.  
  42. void main (int argc, char *argv[])
  43. {
  44.    PFMHEADER                 pfmhead;
  45.    PFMEXTENSION              pfmextension;
  46.    EXTTEXTMETRIC             ext_text_metric;
  47.    char                      driver[255];
  48.    char                      pfb_name[255];
  49.    char                      afm_name[255];
  50.    char                      wfont_name[255];
  51.    char                      psfont_name[255];
  52.    FILE                      *fp, *fp2;
  53.    WORD                      *ext_tab;
  54.    int                       ext_entries;
  55.    KERNPAIR                  *kernpairs;
  56.    FILE                      *ofp;
  57.    int                       i;
  58.  
  59.    if (argc < 2)
  60.    {
  61.       printf ("Error dude\nNeed Parameter with pfm-file and \n");
  62.       printf ("optinal parameter with afm-file!\n");
  63.       printf ("SAY: PFM2AFM <pfm-file> [<afm-file>]\n");
  64.       exit (EXIT_FAILURE);
  65.    }
  66.  
  67.    if (NULL == (fp = fopen (argv[1], "rb")))
  68.    {
  69.       printf("ERROR: ");
  70.       perror (argv[1]);
  71.       exit (EXIT_FAILURE);
  72.    }
  73.  
  74.    if (argc>2) {
  75.       strcpy(afm_name, argv[2]);
  76.    }
  77.    else {
  78.       strcpy(afm_name, argv[1]);    /* Build pfb_file */
  79.       strcpy(afm_name+strlen(afm_name)-3, "afm");
  80.    }
  81.  
  82.    if (NULL == (ofp = fopen (afm_name, "w")))
  83.    {
  84.       printf("ERROR: ");
  85.       perror (afm_name);
  86.       exit (EXIT_FAILURE);
  87.    }
  88.  
  89.    strcpy(pfb_name, argv[1]);    /* Build pfb_file */
  90.    strcpy(pfb_name+strlen(pfb_name)-3, "pfb");
  91.    if (NULL == (fp2 = fopen (pfb_name, "rb")))
  92.    {
  93.       printf("WARNING: ");
  94.       perror (pfb_name);
  95.    }
  96.  
  97.    fread (&pfmhead, sizeof (pfmhead), 1, fp);
  98.    fread (&pfmextension, sizeof (pfmextension), 1, fp);
  99.  
  100.    fseek (fp, pfmhead.dfDevice, SEEK_SET);
  101.    fread (driver, 50, 1, fp);
  102.  
  103.    fseek (fp, pfmhead.dfFace, SEEK_SET);
  104.    fread (wfont_name, 50, 1, fp);
  105.  
  106.    fseek (fp, pfmextension.dfExtMetricsOffset, SEEK_SET);
  107.    fread (&ext_text_metric, sizeof (ext_text_metric), 1, fp);
  108.  
  109.    fseek (fp, pfmextension.dfDriverInfo, SEEK_SET);
  110.    fread (psfont_name, 50, 1, fp);
  111.  
  112.    ext_entries    =  pfmhead.dfLastChar - pfmhead.dfFirstChar + 1;
  113.    ext_tab        =  malloc (ext_entries * sizeof (WORD));
  114.    if (ext_tab == NULL)
  115.    {
  116.       perror ("malloc");
  117.       exit (EXIT_FAILURE);
  118.    }
  119.    fseek (fp, pfmextension.dfExtentTable, SEEK_SET);
  120.    fread (ext_tab, sizeof (WORD), ext_entries, fp);
  121.  
  122.    /* Try to get something from the pfb-file or from the name */
  123.    if (fp2!=NULL)
  124.        process_pfb(fp2);
  125.    name_guessing(psfont_name);
  126.  
  127.    fprintf (ofp, "StartFontMetrics 2.0\n");
  128.    fprintf (ofp, "Comment Generated by pfm2afm Public Domain ");
  129.    fprintf (ofp, "by Kevin Nickerson 1991\n");
  130.    fprintf (ofp, "Comment Bugfix and improved by Markus Schmidt 1992\n");
  131.    fprintf (ofp, "FontName %s\n", psfont_name);
  132.    fprintf (ofp, "FullName %s\n", psfont_name);
  133.    fprintf (ofp, "FamilyName %s\n", 
  134.                    (FamilyName[0]=='\0')?wfont_name:FamilyName);
  135.    fprintf (ofp, "Weight %s\n", (Weight[0]=='\0')?"standard":Weight); 
  136.    fprintf (ofp, "Notice This frees you from Windoze\n");
  137.    fprintf (ofp, "ItalicAngle %s\n", (ItalicAngle[0]=='\0')?"0.0":ItalicAngle);
  138.    fprintf (ofp, "IsFixedPitch false\n");
  139.    fprintf (ofp, "UnderlinePosition -%d\n", ext_text_metric.etmUnderlineOffset);
  140.    fprintf (ofp, "UnderlineThickness %d\n", ext_text_metric.etmUnderlineWidth);
  141.    fprintf (ofp, "Version 001.000\n");     /*hm*/
  142.    fprintf (ofp, "EncodingScheme AdobeStandardEncoding\n");
  143.    if (FontBBox[0]=='\0')
  144.        fprintf (ofp, "FontBBox %d %d %d %d\n",
  145.                   0,  ext_text_metric.etmLowerCaseDescent,
  146.                   pfmhead.dfMaxWidth,  ext_text_metric.etmCapHeight );
  147.    else 
  148.        fprintf (ofp, "FontBBox %s\n", FontBBox);
  149.    fprintf (ofp, "CapHeight %d\n", ext_text_metric.etmCapHeight );
  150.    fprintf (ofp, "XHeight %d\n", ext_text_metric.XHeight);
  151.    fprintf (ofp, "Descender %d\n", ext_text_metric.etmLowerCaseDescent);
  152.    fprintf (ofp, "Ascender %d\n", ext_text_metric.etmCapHeight);
  153.  
  154.  
  155.  
  156.    fprintf (ofp, "StartCharMetrics %d\n", ext_entries);
  157.    for (i = 0; i < ext_entries; i++)
  158.    {
  159.       fprintf (ofp, "C %d ; WX %d ; N %s ; B 0 0 1000 1000 ;\n",
  160.                     i + pfmhead.dfFirstChar,
  161.                     ext_tab[i],
  162.                     charname[i + pfmhead.dfFirstChar]);
  163.    }
  164.  
  165.    fprintf (ofp, "EndCharMetrics\n");
  166.    fprintf (ofp, "StartKernData\n");
  167.    fprintf (ofp, "StartKernPairs %d\n", ext_text_metric.etmKernPairs);
  168.    kernpairs = malloc (ext_text_metric.etmKernPairs * sizeof (KERNPAIR));
  169.    if (kernpairs == NULL)
  170.    {
  171.       perror ("malloc");
  172.       exit (EXIT_FAILURE);
  173.    }
  174.    fseek (fp, pfmextension.dfPairKernTable+2, SEEK_SET);
  175.    fread (kernpairs, sizeof (KERNPAIR), ext_text_metric.etmKernPairs, fp);
  176.    for (i = 0; i < (int) ext_text_metric.etmKernPairs; i++)
  177.    {
  178.       fprintf (ofp, "KPX %s %s %d\n", charname[kernpairs[i].kpPair.each[0]],
  179.                                       charname[kernpairs[i].kpPair.each[1]],
  180.                                       kernpairs[i].kpKernAmount);
  181.    }
  182.    
  183.    fprintf (ofp, "EndKernPairs\n");
  184.    fprintf (ofp, "EndKernData\n");
  185.    fprintf (ofp, "StartComposites 0\n");
  186.    fprintf (ofp, "EndComposites\n");
  187.    fprintf (ofp, "EndFontMetrics\n");
  188.  
  189.    fclose (fp);
  190.    if (fp2!=NULL)
  191.        fclose (fp2);
  192.    exit (EXIT_SUCCESS);
  193. }
  194.  
  195.  
  196.  
  197. /* PFB-File analysis by M. Schmidt (bix:shimoda), no copyrights, of course */
  198. /* quick and dirty, I know, it could be done with tables and loops,
  199.  * but I did't have the time */
  200.  
  201.  
  202. void process_pfb(FILE *f)
  203. {
  204.     char buffer[256];
  205.  
  206.     fread(buffer, 1, 6, f);    /* kill first 6 bytes */
  207.  
  208.     /* this loop is a little bit crude for binary files, I know */
  209.     while (!feof(f)) {
  210.         fgets(buffer, 256, f);
  211.         /* we 're interested in the /xxx lines */
  212.         if (buffer[0]=='/') {
  213.             if (strncmp(buffer, "/ItalicAngle", 12)==0) {
  214.                 after_space_copy(ItalicAngle, buffer);
  215.             }
  216.             else 
  217.             if (strncmp(buffer, "/Weight", 7)==0) {
  218.                 after_space_copy(Weight, buffer);
  219.             }
  220.             else 
  221.             if (strncmp(buffer, "/FamilyName", 10)==0) {
  222.                 after_space_copy(FamilyName, buffer);
  223.             }
  224.             else 
  225.             if (strncmp(buffer, "/FontBBox", 9)==0) {
  226.                 after_space_copy(FontBBox, buffer);
  227.             }
  228.  
  229.         }
  230.     }
  231. }
  232.  
  233.  
  234. /* put the word/expression after the keyword to "to" */
  235. void after_space_copy(char *to, char *from)
  236. {
  237.     char *p, *p1;
  238.     char tmpbuf[256];
  239.  
  240.     for (p= from; *p!=' ' && *p!='\t' && *p!='\0'; p++) {
  241.     }
  242.  
  243.     if (*p==' ' || *p=='\t')
  244.         p++;
  245.  
  246.     strcpy(tmpbuf, p);
  247.  
  248.     to_space_copy(to, tmpbuf);
  249. }
  250.  
  251.  
  252. /* copy one word, or one expr. in brackets etc. */
  253. void to_space_copy(char *to, char *from)
  254. {
  255.     char *p, c, e= ' ';
  256.  
  257.     c= from[0];
  258.     if (c=='(' || c=='[' || c=='{') {
  259.         from++;
  260.  
  261.         if (c=='[')
  262.             e= ']';
  263.  
  264.         if (c=='(')
  265.             e= ')';
  266.  
  267.         if (c=='{')
  268.             e= '}';
  269.     }
  270.  
  271.     for (p= from; *p!=e && *p!='\0'; p++) {
  272.         
  273.     }
  274.  
  275.     strncpy(to, from, p-from);
  276.     to[p-from]= '\0';
  277. }
  278.  
  279.  
  280. /* Try to guess weight or italicangle from the name */
  281. void name_guessing(char *name)
  282. {
  283.     if (Weight[0]=='\0') {
  284.             GUESS(name, "Bold", Weight, "Bold");
  285.             GUESS(name, "bold", Weight, "Bold");
  286.             GUESS(name, "Demi", Weight, "Bold");
  287.             GUESS(name, "demi", Weight, "Bold");
  288.             GUESS(name, "Heavy", Weight, "Heavy");
  289.             GUESS(name, "heavy", Weight, "Heavy");
  290.             GUESS(name, "Light", Weight, "Light");
  291.             GUESS(name, "light", Weight, "Light");
  292.             GUESS(name, "ExtraBold", Weight, "ExtraBold");
  293.             GUESS(name, "extraBold", Weight, "ExtraBold");
  294.     }
  295.  
  296.     if (ItalicAngle[0]=='\0') {
  297.             GUESS(name, "Italic", ItalicAngle, "20.0");
  298.             GUESS(name, "italic", ItalicAngle, "20.0");
  299.             GUESS(name, "Oblique", ItalicAngle, "20.0");
  300.             GUESS(name, "oblique", ItalicAngle, "20.0");
  301.     }
  302. }
  303.  
  304.  
  305.  
  306.  
  307.  
  308. /* Quite frankly, this has me puzzled.  The first 127 seem constant,
  309.    but the names of the characters past there seem to change with the
  310.    font.  Some of the fonts give the names in the ascii part.  If so,
  311.    you should use them.  Otherwise, these seem (after looking at a number
  312.    of fonts) to be the correct names. (kn) */   
  313.  
  314. /* This contained some bug in the orignal table (there were some 
  315.    blank etries missing (quite bad for a indexed table :-)). 
  316.    Does anyone know the names for the empty places? (ms)
  317. */
  318.  
  319. static const char *charname[] = 
  320. {
  321.     "null",   /* 0*/
  322.     "^A",     /* 1*/
  323.     "^B",     /* 2*/
  324.     "^C",     /* 3*/
  325.     "^D",     /* 4*/
  326.     "^E",     /* 5*/
  327.     "^F",     /* 6*/
  328.     "^G",     /* 7*/
  329.     "^H",     /* 8*/
  330.     "^I",     /* 9*/
  331.     "^J",     /*10*/
  332.     "^K",     /*11*/
  333.     "^L",     /*12*/
  334.     "^M",     /*13*/
  335.     "^N",     /*14*/
  336.     "^O",     /*15*/
  337.     "^P",     /*16*/
  338.     "^Q",     /*17*/
  339.     "^R",     /*18*/
  340.     "^S",     /*19*/
  341.     "^T",     /*20*/
  342.     "^U",     /*21*/
  343.     "^V",     /*22*/
  344.     "^W",     /*23*/
  345.     "^X",     /*24*/
  346.     "^Y",     /*25*/
  347.     "^Z",     /*26*/
  348.     "escape", /*27*/
  349.     "28",           /*28*/
  350.     "29",           /*29*/
  351.     "30",           /*30*/
  352.     "31",           /*31*/
  353.     "space",        /*32*/
  354.     "exclam",       /*33*/
  355.     "quotedbl",     /*34*/
  356.     "numbersign",   /*35*/
  357.     "dollar",       /*36*/ 
  358.     "percent",      /*37*/ 
  359.     "ampersand",    /*38*/ 
  360.     "quoteright",   /*39*/ 
  361.     "parenleft",    /*40*/ 
  362.     "parenright",   /*41*/ 
  363.     "asterisk",     /*42*/
  364.     "plus",         /*43*/
  365.     "comma",        /*44*/
  366.     "hyphen",       /*45*/
  367.     "period",       /*46*/
  368.     "slash",        /*47*/
  369.     "zero",         /*48*/
  370.     "one",          /*49*/
  371.     "two",          /*50*/
  372.     "three",        /*51*/
  373.     "four",         /*52*/
  374.     "five",         /*53*/
  375.     "six",          /*54*/
  376.     "seven",        /*55*/
  377.     "eight",        /*56*/
  378.     "nine",         /*57*/
  379.     "colon",        /*58*/ 
  380.     "semicolon",    /*59*/ 
  381.     "less",         /*60*/
  382.     "equal",        /*61*/
  383.     "greater",      /*62*/
  384.     "question",     /*63*/
  385.     "at",           /*64*/
  386.     "A",   /*65*/
  387.     "B",   /*66*/
  388.     "C",   /*67*/
  389.     "D",   /*68*/
  390.     "E",   /*69*/
  391.     "F",   /*70*/
  392.     "G",   /*71*/
  393.     "H",   /*72*/
  394.     "I",   /*73*/
  395.     "J",   /*74*/
  396.     "K",   /*75*/
  397.     "L",   /*76*/
  398.     "M",   /*77*/
  399.     "N",   /*78*/
  400.     "O",   /*79*/
  401.     "P",   /*80*/
  402.     "Q",   /*81*/
  403.     "R",   /*82*/
  404.     "S",   /*83*/
  405.     "T",   /*84*/
  406.     "U",   /*85*/
  407.     "V",   /*86*/
  408.     "W",   /*87*/
  409.     "X",   /*88*/
  410.     "Y",   /*89*/
  411.     "Z",   /*90*/
  412.     "bracketleft",  /*91*/ 
  413.     "backslash",    /*92*/ 
  414.     "bracketright", /*93*/ 
  415.     "asciicircum",  /*94*/ 
  416.     "underscore",   /*95*/ 
  417.     "grave",        /*96*/ 
  418.     "a",  /* 97*/
  419.     "b",  /* 98*/
  420.     "c",  /* 99*/
  421.     "d",  /*100*/
  422.     "e",  /*101*/
  423.     "f",  /*102*/
  424.     "g",  /*103*/
  425.     "h",  /*104*/
  426.     "i",  /*105*/
  427.     "j",  /*106*/
  428.     "k",  /*107*/
  429.     "l",  /*108*/
  430.     "m",  /*109*/
  431.     "n",  /*110*/
  432.     "o",  /*111*/
  433.     "p",  /*112*/
  434.     "q",  /*113*/
  435.     "r",  /*114*/
  436.     "s",  /*115*/
  437.     "t",     /*116*/
  438.     "u",     /*117*/
  439.     "v",     /*118*/
  440.     "w",     /*119*/
  441.     "x",     /*120*/
  442.     "y",     /*121*/
  443.     "z",     /*122*/
  444.     "braceleft",         /*123*/
  445.     "bar",               /*124*/
  446.     "braceright",        /*125*/
  447.     "asciitilde",        /*126*/
  448.     "127",
  449.     "grave",             /*128*/
  450.     "circumflex",        /*129*/
  451.     "tilde",             /*130*/
  452.     "dotlessi",          /*131*/
  453.     "florin",            /*132*/
  454.     "quotedblleft",      /*133*/
  455.     "quotedblright",     /*134*/
  456.     "guilsinglleft",     /*135*/
  457.     "guilsinglright",    /*136*/
  458.     "fi",                /*137*/
  459.     "fl",                /*138*/
  460.     "dagger",            /*139*/
  461.     "daggerdbl",         /*140*/
  462.     "endash",            /*141*/
  463.     "bullet",            /*142*/
  464.     "breve",             /*143*/
  465.     "quotedblbase",      /*144*/
  466.     "ellipsis",          /*145*/
  467.     "perthousand",       /*146*/
  468.     "trademark",         /*147*/
  469.     "",                  /*148*/
  470.     "",                  /*149*/
  471.     "",                  /*150*/
  472.     "",                  /*151*/
  473.     "divide",            /*152*/
  474.     "",                  /*153*/
  475.     "",                  /*154*/
  476.     "",                  /*155*/
  477.     "",                  /*156*/
  478.     "",                  /*157*/
  479.     "",                  /*158*/
  480.     "",                  /*159*/
  481.     "",                  /*160*/
  482.     "exclamdown",        /*161*/
  483.     "cent",              /*162*/
  484.     "sterling",          /*163*/
  485.     "currency",          /*164*/
  486.     "yen",               /*165*/
  487.     "brokenbar",         /*166*/
  488.     "section",           /*167*/
  489.     "dieresis",          /*168*/
  490.     "copyright",         /*169*/
  491.     "ordfeminine",       /*170*/
  492.     "guillemotleft",     /*171*/
  493.     "logicalnot",        /*172*/
  494.     "emdash",            /*173*/
  495.     "registered",        /*174*/
  496.     "",                     /*175*/
  497.     "ring",              /*176*/
  498.     "plusminus",         /*177*/
  499.     "twosuperior",       /*178*/
  500.     "threesuperior",     /*179*/
  501.     "acute",             /*180*/
  502.     "mu",                /*181*/
  503.     "paragraph",         /*182*/
  504.     "periodcentered",    /*183*/
  505.     "cedilla",           /*184*/
  506.     "onesuperior",       /*185*/
  507.     "ordmasculine",      /*186*/
  508.     "guillemotright",    /*187*/
  509.     "onequarter",        /*188*/
  510.     "onehalf",           /*189*/
  511.     "threequarters",     /*190*/
  512.     "questiondown",      /*191*/
  513.     "Agrave",            /*192*/
  514.     "Aacute",            /*193*/
  515.     "Acircumflex",       /*194*/
  516.     "Atilde",            /*195*/
  517.     "Adieresis",         /*196*/
  518.     "Aring",             /*197*/
  519.     "AE",                /*198*/
  520.     "Ccedilla",          /*199*/
  521.     "Egrave",            /*200*/
  522.     "Eacute",            /*201*/
  523.     "Ecircumflex",       /*202*/
  524.     "Edieresis",         /*203*/
  525.     "Igrave",            /*204*/
  526.     "Iacute",            /*205*/
  527.     "Icircumflex",       /*206*/
  528.     "Idieresis",         /*207*/
  529.     "Eth",               /*208*/
  530.     "Ntilde",            /*209*/
  531.     "Ograve",            /*210*/
  532.     "Oacute",            /*211*/
  533.     "Ocircumflex",       /*212*/
  534.     "Otilde",            /*213*/
  535.     "Odieresis",         /*214*/
  536.     "OE",                /*215*/
  537.     "Oslash",            /*216*/
  538.     "Ugrave",            /*217*/
  539.     "Uacute",            /*218*/
  540.     "Ucircumflex",       /*219*/
  541.     "Udieresis",         /*220*/
  542.     "Yacute",            /*221*/
  543.     "Thorn",             /*222*/
  544.     "germandbls",        /*223*/
  545.     "agrave",            /*224*/
  546.     "aacute",            /*225*/
  547.     "acircumflex",       /*226*/
  548.     "atilde",            /*227*/
  549.     "adieresis",         /*228*/
  550.     "aring",             /*229*/
  551.     "ae",                /*230*/
  552.     "ccedilla",          /*231*/
  553.     "egrave",            /*232*/
  554.     "eacute",            /*233*/
  555.     "ecircumflex",       /*234*/
  556.     "edieresis",         /*235*/
  557.     "igrave",            /*236*/
  558.     "iacute",            /*237*/
  559.     "icircumflex",       /*238*/
  560.     "idieresis",         /*239*/
  561.     "eth",               /*240*/
  562.     "ntilde",            /*241*/
  563.     "ograve",            /*242*/
  564.     "oacute",            /*243*/
  565.     "ocircumflex",       /*244*/
  566.     "otilde",            /*245*/
  567.     "odieresis",         /*246*/
  568.     "oe",                /*247*/
  569.     "oslash",            /*248*/
  570.     "ugrave",            /*249*/
  571.     "uacute",            /*250*/
  572.     "ucircumflex",       /*251*/
  573.     "udieresis",         /*252*/
  574.     "yacute",            /*253*/
  575.     "thorn",             /*254*/
  576.     "ydieresis",         /*255*/
  577.  
  578.  
  579.     "","","","","","","","","","","","","",
  580.     "","","","","","","","","","","","","",
  581.     "","","","","","","","","","","","","",
  582.     "","","","","","","","","","","","","",
  583.     "","","","","","","","","","","","","",
  584.     "","","","","","","","","","","","","",
  585.     "","","","","","","","","","","","","",
  586.     "","","","","","","","","","","","","",
  587.     "","","","","","","","","","","","","",
  588.     "","","","","","","","","","","","","",
  589.     "","","","","","","","","","","","","",
  590.     "","","","","","","","","","","","","",
  591.     "","","","","","","","","","","","","",
  592.     "","","","","","","","","","","","","",
  593.     "","","","","","","","","","","","","",
  594.     "","","","","","","","","","","","","",
  595.     "","","","","","","","","","","","","",
  596.     "","","","","","","","","","","","","",
  597.     "","","","","","","","","","","","","",
  598.     "","","","","","","","","","","","","",
  599.     "","","","","","","","","","","","","",
  600.     "","","","","","","","","","","","","",
  601.     "","","","","","","",""
  602. };
  603.  
  604.