home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / anwor032.zip / antiword.0.32 / chartrans.c < prev    next >
C/C++ Source or Header  |  2001-08-21  |  10KB  |  390 lines

  1. /*
  2.  * chartrans.c
  3.  * Copyright (C) 1999-2001 A.J. van Os; Released under GPL
  4.  *
  5.  * Description:
  6.  * Translate Word characters to local representation
  7.  */
  8.  
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #include <ctype.h>
  12. #include "antiword.h"
  13.  
  14. static const unsigned short usCp1252[] = {
  15.     0x20ac,    '?', 0x201a, 0x0192, 0x201e, 0x2026, 0x2020, 0x2021,
  16.     0x02c6, 0x2030, 0x0160, 0x2039, 0x0152,    '?', 0x017D,    '?',
  17.        '?', 0x2018, 0x2019, 0x201c, 0x201d, 0x2022, 0x2013, 0x2014,
  18.     0x02dc, 0x2122, 0x0161, 0x203a, 0x0153,    '?', 0x017e, 0x0178,
  19. };
  20.  
  21. static const unsigned short usMacRoman[] = {
  22.     0x00c4, 0x00c5, 0x00c7, 0x00c9, 0x00d1, 0x00d6, 0x00dc, 0x00e1,
  23.     0x00e0, 0x00e2, 0x00e4, 0x00e3, 0x00e5, 0x00e7, 0x00e9, 0x00e8,
  24.     0x00ea, 0x00eb, 0x00ed, 0x00ec, 0x00ee, 0x00ef, 0x00f1, 0x00f3,
  25.     0x00f2, 0x00f4, 0x00f6, 0x00f5, 0x00fa, 0x00f9, 0x00fb, 0x00fc,
  26.     0x2020, 0x00b0, 0x00a2, 0x00a3, 0x00a7, 0x2022, 0x00b6, 0x00df,
  27.     0x00ae, 0x00a9, 0x2122, 0x00b4, 0x00a8, 0x2260, 0x00c6, 0x00d8,
  28.     0x221e, 0x00b1, 0x2264, 0x2265, 0x00a5, 0x00b5, 0x2202, 0x2211,
  29.     0x220f, 0x03c0, 0x222b, 0x00aa, 0x00ba, 0x2126, 0x00e6, 0x00f8,
  30.     0x00bf, 0x00a1, 0x00ac, 0x221a, 0x0192, 0x2248, 0x2206, 0x00ab,
  31.     0x00bb, 0x2026, 0x00a0, 0x00c0, 0x00c3, 0x00d5, 0x0152, 0x0153,
  32.     0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0x00f7, 0x25ca,
  33.     0x00ff, 0x0178, 0x2044, 0x00a4, 0x2039, 0x203a, 0xfb01, 0xfb02,
  34.     0x2021, 0x00b7, 0x201a, 0x201e, 0x2030, 0x00c2, 0x00ca, 0x00c1,
  35.     0x00cb, 0x00c8, 0x00cd, 0x00ce, 0x00cf, 0x00cc, 0x00d3, 0x00d4,
  36.        '?', 0x00d2, 0x00da, 0x00db, 0x00d9, 0x0131, 0x02c6, 0x02dc,
  37.     0x00af, 0x02d8, 0x02d9, 0x02da, 0x00b8, 0x02dd, 0x02db, 0x02c7,
  38. };
  39.  
  40. typedef struct char_table_tag {
  41.     unsigned short    usLocal;
  42.     unsigned short    usUnicode;
  43. } char_table_type;
  44.  
  45. static char_table_type atCharTable[128];
  46.  
  47.  
  48. /*
  49.  * iCompare - compare two records
  50.  *
  51.  * Compares two records. For use by qsort(3C) and bsearch(3C).
  52.  *
  53.  * returns -1 if rec1 < rec2, 0 if rec1 == rec2, 1 if rec1 > rec2
  54.  */
  55. static int
  56. iCompare(const void *vpRecord1, const void *vpRecord2)
  57. {
  58.     unsigned short    usUnicode1, usUnicode2;
  59.  
  60.     usUnicode1 = ((char_table_type *)vpRecord1)->usUnicode;
  61.     usUnicode2 = ((char_table_type *)vpRecord2)->usUnicode;
  62.  
  63.     if (usUnicode1 < usUnicode2) {
  64.         return -1;
  65.     }
  66.     if (usUnicode1 > usUnicode2) {
  67.         return 1;
  68.     }
  69.     return 0;
  70. } /* end of iCompare */
  71.  
  72. /*
  73.  * bReadCharacterMappingTable - read the mapping table
  74.  *
  75.  * Read the character mapping table from file and have the contents sorted
  76.  *
  77.  * returns TRUE if successful, otherwise FALSE
  78.  */
  79. BOOL
  80. bReadCharacterMappingTable(const char *szFilename)
  81. {
  82.     FILE    *pFile;
  83.     char    *pcTmp;
  84.     unsigned long    ulUnicode;
  85.     unsigned int    uiLocal;
  86.     int    iFields;
  87.     char    szLine[81];
  88.  
  89.     DBG_MSG(szFilename);
  90.  
  91.     fail(szFilename == NULL);
  92.  
  93.     if (szFilename == NULL || szFilename[0] == '\0') {
  94.         return FALSE;
  95.     }
  96.     pFile = fopen(szFilename, "r");
  97.     if (pFile == NULL) {
  98.         DBG_MSG(szFilename);
  99.         return FALSE;
  100.     }
  101.     (void)memset(atCharTable, 0, sizeof(atCharTable));
  102.  
  103.     while (fgets(szLine, (int)sizeof(szLine), pFile)) {
  104.         if (szLine[0] == '#' ||
  105.             szLine[0] == '\r' ||
  106.             szLine[0] == '\n') {
  107.             /* Comment or empty line */
  108.             continue;
  109.         }
  110.         iFields = sscanf(szLine, "%x %lx %*s", &uiLocal, &ulUnicode);
  111.         if (iFields != 2) {
  112.             pcTmp = strchr(szLine, '\r');
  113.             if (pcTmp != NULL) {
  114.                 *pcTmp = '\0';
  115.             }
  116.             pcTmp = strchr(szLine, '\n');
  117.             if (pcTmp != NULL) {
  118.                 *pcTmp = '\0';
  119.             }
  120.             werr(0, "Syntax error in: '%s'", szLine);
  121.             continue;
  122.         }
  123.         if (uiLocal > 0xff || ulUnicode > 0xffff) {
  124.             werr(0, "Syntax error in: '%02x %04x'",
  125.                     uiLocal, ulUnicode);
  126.             continue;
  127.         }
  128.         if (uiLocal >= 0x80) {
  129.             atCharTable[uiLocal - 0x80].usLocal =
  130.                         (unsigned short)uiLocal;
  131.             atCharTable[uiLocal - 0x80].usUnicode =
  132.                         (unsigned short)ulUnicode;
  133.         }
  134.     }
  135.     (void)fclose(pFile);
  136.  
  137.     DBG_HEX(atCharTable[0].usUnicode);
  138.     DBG_HEX(atCharTable[elementsof(atCharTable)-1].usUnicode);
  139.  
  140.     qsort(atCharTable,
  141.         elementsof(atCharTable), sizeof(atCharTable[0]),
  142.         iCompare);
  143.  
  144.     DBG_HEX(atCharTable[0].usUnicode);
  145.     DBG_HEX(atCharTable[elementsof(atCharTable)-1].usUnicode);
  146.  
  147.     return TRUE;
  148. } /* end of bReadCharacterMappingTable */
  149.  
  150. /*
  151.  * ulTranslateCharacters - Translate characters to local representation
  152.  *
  153.  * Translate all characters to local representation
  154.  *
  155.  * returns the translated character
  156.  */
  157. unsigned long
  158. ulTranslateCharacters(unsigned short usChar,
  159.     long lFileOffset, BOOL bToUTF8, BOOL bMacWord6)
  160. {
  161.     char_table_type    tKey;
  162.     char_table_type    *pTmp;
  163.  
  164.     if (bMacWord6) {
  165.         /* Translate special Macintosh characters */
  166.         if (usChar >= 0x80 && usChar <= 0xff) {
  167.             usChar = usMacRoman[usChar - 0x80];
  168.         }
  169.     } else {
  170.         /* Translate implementation defined characters */
  171.         if (usChar >= 0x80 && usChar <= 0x9f) {
  172.             usChar = usCp1252[usChar - 0x80];
  173.         }
  174.     }
  175.  
  176.     /* Microsoft Unicode to real Unicode */
  177.     switch (usChar) {
  178.     case UNICODE_MS_DIAMOND:
  179.         usChar = UNICODE_DIAMOND;
  180.         break;
  181.     case UNICODE_MS_UNDERTIE:
  182.         usChar = UNICODE_UNDERTIE;
  183.         break;
  184.     case UNICODE_MS_BLACK_SQUARE:
  185.         usChar = UNICODE_BLACK_SQUARE;
  186.         break;
  187.     case UNICODE_MS_BULLET1:
  188.     case UNICODE_MS_BULLET2:
  189.         usChar = UNICODE_BULLET;
  190.         break;
  191.     case UNICODE_MS_COPYRIGHT_SIGN:
  192.         usChar = UNICODE_COPYRIGHT_SIGN;
  193.         break;
  194.     default:
  195.         break;
  196.     }
  197.  
  198.     /* Characters with a special meaning in Word */
  199.     switch (usChar) {
  200.     case IGNORE_CHARACTER:
  201.     case ANNOTATION:
  202.     case FRAME:
  203.     case WORD_SOFT_HYPHEN:
  204.     case UNICODE_HYPHENATION_POINT:
  205.         return IGNORE_CHARACTER;
  206.     case PICTURE:
  207.     case TABLE_SEPARATOR:
  208.     case TAB:
  209.     case HARD_RETURN:
  210.     case FORM_FEED:
  211.     case PAR_END:
  212.     case COLUMN_FEED:
  213.         return usChar;
  214.     case FOOTNOTE_OR_ENDNOTE:
  215.         NO_DBG_HEX(lFileOffset);
  216.         switch (eGetNotetype(lFileOffset)) {
  217.         case notetype_is_footnote:
  218.             return FOOTNOTE_CHAR;
  219.         case notetype_is_endnote:
  220.             return ENDNOTE_CHAR;
  221.         default:
  222.             return UNKNOWN_NOTE_CHAR;
  223.         }
  224.     case WORD_UNBREAKABLE_JOIN:
  225.         return OUR_UNBREAKABLE_JOIN;
  226.     default:
  227.         break;
  228.     }
  229.  
  230.     if (!bToUTF8) {
  231.         /* Latin characters in an oriental text */
  232.         if (usChar >= 0xff01 && usChar <= 0xff5e) {
  233.             usChar -= 0xfee0;
  234.         }
  235.     }
  236.  
  237.     /* US ASCII */
  238.     if (usChar < 0x80) {
  239.         if (usChar < 0x20 || (usChar >= 0x7f && usChar < 0xa0)) {
  240.             DBG_HEX(usChar);
  241.             DBG_FIXME();
  242.             return IGNORE_CHARACTER;
  243.         }
  244.         return usChar;
  245.     }
  246.  
  247.     if (bToUTF8) {
  248.         /* Untranslated Unicode character */
  249.         return usChar;
  250.     }
  251.  
  252.     /* Unicode to local representation */
  253.     tKey.usUnicode = usChar;
  254.     tKey.usLocal = 0;
  255.     pTmp = (char_table_type *)bsearch(&tKey,
  256.             atCharTable,
  257.             elementsof(atCharTable), sizeof(atCharTable[0]),
  258.             iCompare);
  259.     if (pTmp != NULL) {
  260.         return pTmp->usLocal;
  261.     }
  262.  
  263.     /* Fancy characters to simple US ASCII */
  264.     switch (usChar) {
  265.     case UNICODE_SMALL_F_HOOK:
  266.         return (unsigned long)'f';
  267.     case UNICODE_MODIFIER_CIRCUMFLEX:
  268.         return (unsigned long)'^';
  269.     case UNICODE_SMALL_TILDE:
  270.     case UNICODE_TILDE_OPERATOR:
  271.         return (unsigned long)'~';
  272.     case UNICODE_EN_QUAD:
  273.     case UNICODE_EM_QUAD:
  274.     case UNICODE_EN_SPACE:
  275.     case UNICODE_EM_SPACE:
  276.     case UNICODE_THREE_PER_EM_SPACE:
  277.     case UNICODE_FOUR_PER_EM_SPACE:
  278.     case UNICODE_SIX_PER_EM_SPACE:
  279.     case UNICODE_FIGURE_SPACE:
  280.     case UNICODE_PUNCTUATION_SPACE:
  281.     case UNICODE_THIN_SPACE:
  282.     case UNICODE_HAIR_SPACE:
  283.     case UNICODE_ZERO_WIDTH_SPACE:
  284.         return (unsigned long)' ';
  285.     case UNICODE_LEFT_DOUBLE_QMARK:
  286.     case UNICODE_RIGHT_DOUBLE_QMARK:
  287.     case UNICODE_DOUBLE_LOW_9_QMARK:
  288.     case UNICODE_DOUBLE_HIGH_REV_9_QMARK:
  289.     case UNICODE_DOUBLE_PRIME:
  290.         return (unsigned long)'"';
  291.     case UNICODE_LEFT_SINGLE_QMARK:
  292.     case UNICODE_RIGHT_SINGLE_QMARK:
  293.     case UNICODE_SINGLE_LOW_9_QMARK:
  294.     case UNICODE_SINGLE_HIGH_REV_9_QMARK:
  295.     case UNICODE_PRIME:
  296.         return (unsigned long)'\'';
  297.     case UNICODE_HYPHEN:
  298.     case UNICODE_NON_BREAKING_HYPHEN:
  299.     case UNICODE_FIGURE_DASH:
  300.     case UNICODE_EN_DASH:
  301.     case UNICODE_EM_DASH:
  302.     case UNICODE_HORIZONTAL_BAR:
  303.     case UNICODE_MINUS_SIGN:
  304.         return (unsigned long)'-';
  305.     case UNICODE_DOUBLE_VERTICAL_LINE:
  306.         return (unsigned long)'|';
  307.     case UNICODE_DOUBLE_LOW_LINE:
  308.         return (unsigned long)'_';
  309.     case UNICODE_DAGGER:
  310.         return (unsigned long)'-';
  311.     case UNICODE_DOUBLE_DAGGER:
  312.         return (unsigned long)'=';
  313.     case UNICODE_BULLET:
  314.         return OUR_BULLET;
  315.     case UNICODE_ONE_DOT_LEADER:
  316.         return (unsigned long)'.';
  317.     case UNICODE_ELLIPSIS:
  318.         return (unsigned long)'.';
  319.     case UNICODE_SINGLE_LEFT_ANGLE_QMARK:
  320.         return (unsigned long)'<';
  321.     case UNICODE_SINGLE_RIGHT_ANGLE_QMARK:
  322.         return (unsigned long)'>';
  323.     case UNICODE_UNDERTIE:
  324.         return (unsigned long)'-';
  325.     case UNICODE_EURO_SIGN:
  326.         return (unsigned long)'E';
  327.     case UNICODE_DIAMOND:
  328.         return (unsigned long)'-';
  329.     case UNICODE_FRACTION_SLASH:
  330.     case UNICODE_DIVISION_SLASH:
  331.         return (unsigned long)'/';
  332.     case UNICODE_ASTERISK_OPERATOR:
  333.         return (unsigned long)'*';
  334.     case UNICODE_RATIO:
  335.         return (unsigned long)':';
  336.     case UNICODE_BLACK_SQUARE:
  337.         return (unsigned long)'+';
  338.     default:
  339.         break;
  340.     }
  341.  
  342.     if (usChar == UNICODE_TRADEMARK_SIGN) {
  343.         /*
  344.          * No local representation, it doesn't look like anything in
  345.          * US-ASCII and a question mark does more harm than good.
  346.          */
  347.         return IGNORE_CHARACTER;
  348.     }
  349.  
  350.     if (usChar >= 0xa0 && usChar <= 0xff) {
  351.         /* Word 6 and 7 don't use Unicode */
  352.         return usChar;
  353.     }
  354.  
  355.     DBG_HEX_C(usChar < 0x3000 || usChar >= 0xd800, lFileOffset);
  356.     DBG_HEX_C(usChar < 0x3000 || usChar >= 0xd800, usChar);
  357.     DBG_MSG_C(usChar >= 0xe000 && usChar < 0xf900, "Private Use Area");
  358.  
  359.     /* Untranslated Unicode character */
  360.     return (unsigned long)'?';
  361. } /* end of ulTranslateCharacters */
  362.  
  363. /*
  364.  * ulToUpper - convert letter to upper case
  365.  *
  366.  * This function converts a letter to upper case. Unlike toupper(3) this
  367.  * function is independent from the settings of locale. This comes in handy
  368.  * for people who have to read Word documents in more than one language or
  369.  * contain more than one language.
  370.  *
  371.  * returns the converted letter, or ulChar if the conversion was not possible.
  372.  */
  373. unsigned long
  374. ulToUpper(unsigned long ulChar)
  375. {
  376.     if (ulChar < 0x80) {
  377.         /* US ASCII: use standard function */
  378.         return (unsigned long)toupper((int)ulChar);
  379.     }
  380.     if (ulChar >= 0xe0 && ulChar <= 0xfe && ulChar != 0xf7) {
  381.         /*
  382.          * Lower case accented characters
  383.          * 0xf7 is Division sign; 0xd7 is Multiplication sign
  384.          * 0xff is y with diaeresis; 0xdf is Sharp s
  385.          */
  386.         return ulChar & ~0x20;
  387.     }
  388.     return ulChar;
  389. } /* end of ulToUpper */
  390.