ICUData.cpp
上传用户:zhuqijet
上传日期:2013-06-25
资源大小:10074k
文件大小:18k
源码类别:

词法分析

开发平台:

Visual C++

  1. /*
  2.  * The Apache Software License, Version 1.1
  3.  * 
  4.  * Copyright (c) 1999-2000 The Apache Software Foundation.  All rights
  5.  * reserved.
  6.  * 
  7.  * Redistribution and use in source and binary forms, with or without
  8.  * modification, are permitted provided that the following conditions
  9.  * are met:
  10.  * 
  11.  * 1. Redistributions of source code must retain the above copyright
  12.  *    notice, this list of conditions and the following disclaimer. 
  13.  * 
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in
  16.  *    the documentation and/or other materials provided with the
  17.  *    distribution.
  18.  * 
  19.  * 3. The end-user documentation included with the redistribution,
  20.  *    if any, must include the following acknowledgment:  
  21.  *       "This product includes software developed by the
  22.  *        Apache Software Foundation (http://www.apache.org/)."
  23.  *    Alternately, this acknowledgment may appear in the software itself,
  24.  *    if and wherever such third-party acknowledgments normally appear.
  25.  * 
  26.  * 4. The names "Xerces" and "Apache Software Foundation" must
  27.  *    not be used to endorse or promote products derived from this
  28.  *    software without prior written permission. For written 
  29.  *    permission, please contact apache@apache.org.
  30.  * 
  31.  * 5. Products derived from this software may not be called "Apache",
  32.  *    nor may "Apache" appear in their name, without prior written
  33.  *    permission of the Apache Software Foundation.
  34.  * 
  35.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
  36.  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  37.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  38.  * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
  39.  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  40.  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  41.  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
  42.  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  43.  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  44.  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  45.  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  46.  * SUCH DAMAGE.
  47.  * ====================================================================
  48.  * 
  49.  * This software consists of voluntary contributions made by many
  50.  * individuals on behalf of the Apache Software Foundation, and was
  51.  * originally based on software copyright (c) 1999, International
  52.  * Business Machines, Inc., http://www.ibm.com .  For more information
  53.  * on the Apache Software Foundation, please see
  54.  * <http://www.apache.org/>.
  55.  */
  56. /*
  57.  * $Log: ICUData.cpp,v $
  58.  * Revision 1.1  2000/03/17 23:58:00  roddey
  59.  * New utility for munging ICU UCM files and spitting out tables for
  60.  * our intrinsic encoders.
  61.  *
  62.  */
  63. // ---------------------------------------------------------------------------
  64. //  This program is designed to parse a standard ICU .UCM file and spit out
  65. //  a C++ code fragment that represents the tables required by the intrinsic
  66. //  XML parser transcoders.
  67. //
  68. //  The file format is pretty simple and this program is not intended to be
  69. //  industrial strength by any means. Its use by anyone but the author is
  70. //  at the user's own risk.
  71. //
  72. //  The code looks for the min/max bytes per character to know what kind of
  73. //  table to spit out, but for now only handles single char sets.
  74. // ---------------------------------------------------------------------------
  75. // ---------------------------------------------------------------------------
  76. //  Includes
  77. // ---------------------------------------------------------------------------
  78. #include    <ctype.h>
  79. #include    <stdio.h>
  80. #include    <stdlib.h>
  81. #include    <iostream.h>
  82. #include    <string.h>
  83. // ---------------------------------------------------------------------------
  84. //  Const data
  85. // ---------------------------------------------------------------------------
  86. static const unsigned int   gMaxInRecs = 1024;
  87. // ---------------------------------------------------------------------------
  88. //  Local data types
  89. // ---------------------------------------------------------------------------
  90. struct XlatRec
  91. {
  92.     unsigned short  uniVal;
  93.     unsigned char   cpVal;
  94. };
  95. // ---------------------------------------------------------------------------
  96. //  Local data
  97. //
  98. //  gInFile
  99. //  gOutFile
  100. //      These are the file stream for the input UCM file and the output file
  101. //      that we write the C++ code to.
  102. //
  103. //  fLineNum
  104. //      Used to track the current line number in the source file, for error
  105. //      reporting.
  106. //
  107. //  gMainTable
  108. //  gMainTableSz
  109. //      This is the table that is filled in from the original source document.
  110. //      We don't know how big it will be, but its not likely to be much more
  111. //      than 300 entries or so (256 output code points with some multiply
  112. //      mapped Unicode code points.) So we make it extra large and watch for
  113. //      possible overflow.
  114. //
  115. //      The size value is bumped up as we load entries into it during the
  116. //      parse of the file.
  117. //
  118. //  gMaxChar
  119. //  gMinChar
  120. //      The min/max chars that are used to represent a character. These are
  121. //      read from the header of the input file.
  122. //
  123. //  gRepChar
  124. //      The replacement character to be used. This is read from the header of
  125. //      the input file.
  126. // ---------------------------------------------------------------------------
  127. static FILE*            gInFile;
  128. static FILE*            gOutFile;
  129. static unsigned int     fLineNum;
  130. static XlatRec          gMainTable[gMaxInRecs];
  131. static unsigned int     gMainTableSz = 0;
  132. static unsigned int     gMaxChar;
  133. static unsigned int     gMinChar;
  134. static unsigned char    gRepChar = 1;
  135. // ---------------------------------------------------------------------------
  136. //  Local functions
  137. // ---------------------------------------------------------------------------
  138. static unsigned int getLine(        char* const     toFill
  139.                             , const unsigned int    maxChars
  140.                             , const bool            eofOk = false)
  141. {
  142.     while (true)
  143.     {
  144.         if (!fgets(toFill, maxChars, gInFile))
  145.         {
  146.             if (feof(gInFile))
  147.             {
  148.                 if (eofOk)
  149.                     return ~0UL;
  150.                 else
  151.                     cout << "Unexpected end of input at line: " << fLineNum << endl;
  152.             }
  153.              else
  154.             {
  155.                 cout << "Error processing input at line: " << fLineNum << endl;
  156.                 exit(1);
  157.             }
  158.         }
  159.         fLineNum++;
  160.         //
  161.         //  If its not a comment, then break out
  162.         //
  163.         if (toFill[0] != '#')
  164.             break;
  165.     }
  166.     //
  167.     //  There could be a trailing comment on this line, so lets get rid
  168.     //  of it. Search for a # char and put a null there.
  169.     //
  170.     char* endPtr = toFill;
  171.     while (*endPtr && (*endPtr != '#'))
  172.         endPtr++;
  173.     if (*endPtr == '#')
  174.         *endPtr = 0;
  175.     // Strip trailing whitespace
  176.     endPtr = toFill + (strlen(toFill) - 1);
  177.     while (isspace(*endPtr))
  178.         endPtr--;
  179.     *(endPtr + 1) = 0;
  180.     // And return the count of chars we got
  181.     return strlen(toFill);
  182. }
  183. static unsigned int extractVal(char* const srcStr)
  184. {
  185.     char* srcPtr = srcStr;
  186.     // Run forward to the first non-space
  187.     while (isspace(*srcPtr))
  188.         srcPtr++;
  189.     if (!*srcPtr)
  190.     {
  191.         cout << "Invalid numeric value on line: " << fLineNum << endl;
  192.         exit(1);
  193.     }
  194.     //
  195.     //  If it starts with , then its a hex value in the form xXX. Else its
  196.     //  just a decimal value.
  197.     //
  198.     unsigned int retVal;
  199.     char* endPtr;
  200.     if (*srcPtr == '\')
  201.     {
  202.         // Skip the \x and interpret as a hex value
  203.         srcPtr += 2;
  204.         retVal = (unsigned int)strtoul(srcPtr, &endPtr, 16);
  205.     }
  206.      else
  207.     {
  208.         retVal = (unsigned int)strtoul(srcPtr, &endPtr, 10);
  209.     }
  210.     // We should have translated up to the end of the string
  211.     if (*endPtr)
  212.     {
  213.         cout << "Invalid numeric value on line: " << fLineNum << endl;
  214.         exit(1);
  215.     }
  216.     return retVal;
  217. }
  218. static void loadTable()
  219. {
  220.     //
  221.     //  Just loop, reading lines at a time, until we either find the start
  222.     //  of the character table or hit the end of the file. Along the way, we
  223.     //  should see a few header values that we store away.
  224.     //
  225.     const unsigned int  tmpBufSz = 2048;
  226.     char                tmpBuf[tmpBufSz - 1];
  227.     while (getLine(tmpBuf, tmpBufSz))
  228.     {
  229.         //
  230.         //  Check for one of the special values we are intersted int. If
  231.         //  its CHARMAP, then we fall out of this loop.
  232.         //
  233.         if (!strcmp(tmpBuf, "CHARMAP"))
  234.             break;
  235.         if (!strncmp(tmpBuf, "<mb_cur_max>", 12))
  236.         {
  237.             gMaxChar = extractVal(&tmpBuf[12]);
  238.         }
  239.          else if (!strncmp(tmpBuf, "<mb_cur_min>", 12))
  240.         {
  241.             gMinChar = extractVal(&tmpBuf[12]);
  242.         }
  243.          else if (!strncmp(tmpBuf, "<subchar>", 9))
  244.         {
  245.             gRepChar = (char)extractVal(&tmpBuf[9]);
  246.         }
  247.     }
  248.     //
  249.     //  Ok, now we just run till we hit the "END CHARMAP" line. Each entry
  250.     //  will be in the form:
  251.     //
  252.     //      <UXXXX>     xXX
  253.     //
  254.     //  Where X is a hex number.
  255.     //
  256.     char* endPtr;
  257.     while (getLine(tmpBuf, tmpBufSz))
  258.     {
  259.         // Watch for the end of table
  260.         if (!strcmp(tmpBuf, "END CHARMAP"))
  261.             break;
  262.         // The absolute minium it could be is 12 chars
  263.         if (strlen(tmpBuf) < 12)
  264.         {
  265.             cout << "Line " << fLineNum << " is too short to hold a valid entry"
  266.                  << endl;
  267.             exit(1);
  268.         }
  269.         // Make sure the first token meets the criteria
  270.         if ((tmpBuf[0] != '<')
  271.         ||  (tmpBuf[1] != 'U')
  272.         ||  (tmpBuf[6] != '>'))
  273.         {
  274.             cout << "Line " << fLineNum << " has a badly formed Unicode value"
  275.                  << endl;
  276.             exit(1);
  277.         }
  278.         //
  279.         //  Looks reasonable so lets try to convert it. We can play tricks
  280.         //  with this buffer, so put a null over the > char.
  281.         //
  282.         tmpBuf[6] = 0;
  283.         const unsigned int uniVal = strtoul(&tmpBuf[2], &endPtr, 16);
  284.         if (*endPtr)
  285.         {
  286.             cout << "Invalid Unicode value on line " << fLineNum << endl;
  287.             exit(1);
  288.         }
  289.         //
  290.         //  Ok, lets search over to the second token. We have to find a \
  291.         //  character.
  292.         //
  293.         char* srcPtr = &tmpBuf[7];
  294.         while (*srcPtr && (*srcPtr != '\'))
  295.             srcPtr++;
  296.         // If we never found it, its in error
  297.         if (!*srcPtr)
  298.         {
  299.             cout << "Never found second token on line " << fLineNum << endl;
  300.             exit(1);
  301.         }
  302.         // Try to translate it
  303.         srcPtr += 2;
  304.         const unsigned int cpVal = strtoul(srcPtr, &endPtr, 16);
  305.         if (*endPtr)
  306.         {
  307.             cout << "Invalid code page value on line " << fLineNum << endl;
  308.             exit(1);
  309.         }
  310.         // Make sure that the values are within range
  311.         if (uniVal > 0xFFFF)
  312.         {
  313.             cout << "Unicode value is too big on line " << fLineNum << endl;
  314.             exit(1);
  315.         }
  316.         if (cpVal > 0xFF)
  317.         {
  318.             cout << "Code page value is too big on line " << fLineNum << endl;
  319.             exit(1);
  320.         }
  321.         // Looks reasonable, so add a new entry to the global table
  322.         gMainTable[gMainTableSz].uniVal = (unsigned short)uniVal;
  323.         gMainTable[gMainTableSz].cpVal = (unsigned char)cpVal;
  324.         gMainTableSz++;
  325.     }
  326. }
  327. int compFuncTo(const void* p1, const void* p2)
  328. {
  329.     const XlatRec* rec1 = (const XlatRec*)p1;
  330.     const XlatRec* rec2 = (const XlatRec*)p2;
  331.     return (int)rec1->uniVal - (int)rec2->uniVal;
  332. }
  333. int compFuncFrom(const void* p1, const void* p2)
  334. {
  335.     const XlatRec* rec1 = (const XlatRec*)p1;
  336.     const XlatRec* rec2 = (const XlatRec*)p2;
  337.     //
  338.     //  Since there can be multiple Unicode chars that map to a single
  339.     //  code page char, we have to handle the situationw here they are
  340.     //  equal specially. If the code page vals are equal, then the one
  341.     //  with the smaller Unicode code point is considered smaller.
  342.     //
  343.     if (rec1->cpVal == rec2->cpVal)
  344.         return (int)rec1->uniVal - (int)rec2->uniVal;
  345.     // Else use the code page value for sorting
  346.     return (int)rec1->cpVal - (int)rec2->cpVal;
  347. }
  348. static void formatSBTables()
  349. {
  350.     // For now, only handle single byte char sets
  351.     if ((gMinChar != 1) || (gMaxChar != 1))
  352.     {
  353.         cout << "formatSBTables can only handle single byte encodings"
  354.              << endl;
  355.         exit(1);
  356.     }
  357.     //
  358.     //  First, we want to sort the table by the code page value field. This
  359.     //  is the order required for the 'from' table to convert from the code
  360.     //  page to the internal Unicode format.
  361.     //
  362.     qsort(gMainTable, gMainTableSz, sizeof(gMainTable[0]), compFuncFrom);
  363.     //
  364.     //  Now spit out the header for the table. This is the same for all
  365.     //  of them, since they are static to the file and can just all have
  366.     //  the same name.
  367.     //
  368.     fprintf
  369.     (
  370.         gOutFile
  371.         , "static const XMLCh gFromTable[256] =n{n    "
  372.     );
  373.     //
  374.     //  Now for each unique entry in the cp value field, we want to put out
  375.     //  the Unicode value for that entry. Since we sorted them such that
  376.     //  dups have the one with the smaller Unicode value in the lower index,
  377.     //  we always hit the desired value first, and then can just skip over
  378.     //  a duplicate.
  379.     //
  380.     unsigned int curValue = 0;
  381.     unsigned int index;
  382.     for (index = 0; index < gMainTableSz; index++)
  383.     {
  384.         if (curValue)
  385.         {
  386.             if (!(curValue % 8))
  387.                 fprintf(gOutFile, "n  , ");
  388.             else
  389.                 fprintf(gOutFile, ", ");
  390.         }
  391.         if (curValue == gMainTable[index].cpVal)
  392.         {
  393.             fprintf(gOutFile, "0x%04X", (unsigned int)gMainTable[index].uniVal);
  394.             // If there is a dump, then skip it
  395.             if (index < gMainTableSz)
  396.             {
  397.                 if (gMainTable[index + 1].cpVal == curValue)
  398.                     index++;
  399.             }
  400.         }
  401.          else if (curValue < gMainTable[index].cpVal)
  402.         {
  403.             fprintf(gOutFile, "0xFFFF");
  404.         }
  405.          else
  406.         {
  407.             // Screwed up
  408.             cout << "Current value got above target valuen" << endl;
  409.             exit(1);
  410.         }
  411.         curValue++;
  412.         // If the current value goes over 256, we are in trouble
  413.         if (curValue > 256)
  414.         {
  415.             cout << "The code page value cannot be > 256 in SB moden" << endl;
  416.             exit(1);
  417.         }
  418.     }
  419.     // And print the trailer for this table
  420.     fprintf(gOutFile, "n};nn");
  421.     //
  422.     //  Now lets sort by the Unicode value field. This sort is used for
  423.     //  the 'to' table. The Unicode value is found by binary search and
  424.     //  used to map to the right output encoding value.
  425.     //
  426.     qsort(gMainTable, gMainTableSz, sizeof(gMainTable[0]), compFuncTo);
  427.     // Output the table ehader for this one
  428.     fprintf
  429.     (
  430.         gOutFile
  431.         , "static const XMLTransService::TransRec gToTable[] =n{n    "
  432.     );
  433.     for (index = 0; index < gMainTableSz; index++)
  434.     {
  435.         if (index)
  436.         {
  437.             if (!(index % 4))
  438.                 fprintf(gOutFile, "n  , ");
  439.             else
  440.                 fprintf(gOutFile, ", ");
  441.         }
  442.         fprintf
  443.         (
  444.             gOutFile
  445.             , "{ 0x%04X, 0x%02X }"
  446.             , (unsigned int)gMainTable[index].uniVal
  447.             , (unsigned int)gMainTable[index].cpVal
  448.         );
  449.     }
  450.     // Print the trailer for this table
  451.     fprintf(gOutFile, "n};n");
  452.     // And print out the table size constant
  453.     fprintf(gOutFile, "static const unsigned int gToTableSz = %d;n", gMainTableSz);
  454. }
  455. static void showUsage()
  456. {
  457.     cout << "ICUData inputUCMfile outputfilen" << endl;
  458. }
  459. // ---------------------------------------------------------------------------
  460. //  The parameters are:
  461. //
  462. //  argV[1] = The source UCM file
  463. //  argV[2] = The path to the output file
  464. // ---------------------------------------------------------------------------
  465. int main(int argC, char** argV)
  466. {
  467.     // We have to have 3 parameters
  468.     if (argC != 3)
  469.     {
  470.         showUsage();
  471.         return 1;
  472.     }
  473.     // Try to open the first file for input
  474.     gInFile = fopen(argV[1], "rt");
  475.     if (!gInFile)
  476.     {
  477.         cout << "Could not find input file: " << argV[1] << endl;
  478.         return 1;
  479.     }
  480.     // Try to open the second file for output (truncated)
  481.     gOutFile = fopen(argV[2], "wt+");
  482.     if (!gOutFile)
  483.     {
  484.         cout << "Could not create output file: " << argV[1] << endl;
  485.         return 1;
  486.     }
  487.     //
  488.     //  This will parse the file and load the table. It will also look for
  489.     //  a couple of key fields in the file header and store that data into
  490.     //  globals.
  491.     //
  492.     loadTable();
  493.     // If we didn't get any table entries, then give up
  494.     if (!gMainTableSz)
  495.     {
  496.         cout << "No translation table entries were found in the file" << endl;
  497.         return 1;
  498.     }
  499.     //
  500.     //  Ok, we got the data loaded. Now lets output the tables. This method
  501.     //  spit out both tables to the output file, in a format ready to be
  502.     //  incorporated directly into the source code.
  503.     //
  504.     formatSBTables();
  505.     // Close our files
  506.     fclose(gInFile);
  507.     fclose(gOutFile);
  508.     return 0;
  509. }