home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: Graphics / Graphics.zip / povsrc31.zip / uniutils.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-04-08  |  11.6 KB  |  400 lines

  1. /*
  2.  * File: uniutils.c
  3.  *
  4.  * Author: Jon A. Cruz
  5.  *         joncruz@geocities.com
  6.  *
  7.  *
  8.  * Module that contains various routines to handle Unicode strings.
  9.  *
  10.  *
  11.  * Includes a simple implementation of UTF-8 to UCS-2 conversion routine.
  12.  * ( described in RFC 2279 )
  13.  *
  14.  *
  15.  *     Jan 23, 1999 - Initial version
  16.  */
  17.  
  18. #include <stdlib.h>
  19. #include <string.h>
  20.  
  21. #include "frame.h"
  22. #include "povray.h"
  23. #include "uniutils.h"
  24.  
  25. #define MASK_1_BYTE 0x80
  26. #define MASK_2_BYTE 0xe0
  27. #define MASK_3_BYTE 0xf0
  28. #define MASK_4_BYTE 0xf8
  29. #define MASK_5_BYTE 0xfc
  30. #define MASK_6_BYTE 0xfe
  31. #define MASK_TRAIL_BYTE 0xc0
  32.  
  33. #define VAL_1_BYTE 0x00
  34. #define VAL_2_BYTE 0xc0
  35. #define VAL_3_BYTE 0xe0
  36. #define VAL_4_BYTE 0xf0
  37. #define VAL_5_BYTE 0xf8
  38. #define VAL_6_BYTE 0xfc
  39. #define VAL_TRAIL_BYTE 0x80
  40.  
  41. #define REPLACEMENT_CHARACTER 0xfffd
  42. /*YS*/
  43. #ifdef MACOS
  44.     int pov_stricmp (char *s1,char *s2);
  45.     #define STRICMP pov_stricmp
  46. #else
  47.     #ifdef UNIX
  48.           #define STRICMP strcasecmp
  49.     #else
  50.         #define STRICMP stricmp
  51.     #endif
  52. #endif    
  53. /*YS*/
  54.  
  55. /*
  56. Name: ECMA-cyrillic                                      [RFC1345,KXS2]
  57. MIBenum: 77
  58. Source: ECMA registry
  59. Alias: iso-ir-111
  60. Alias: csISO111ECMACyrillic
  61. */
  62.  
  63. #define ENCODING_UTF8       0   /* "UTF-8" - RFC2279 */
  64. #define ENCODING_8859_1     1   /* "ISO-8859-1" - RFC1345 */
  65. #define ENCODING_APPLEBYTE  2   /* "" */
  66. #define ENCODING_CP1252     3   /* "windows-1251" ("Cp1252") guess. */
  67. #define ENCODING_MAC_ROMAN  4   /* "macintosh" ("mac") - RFC1345 */
  68.  
  69. /*
  70.  * Warning: Need to keep these in sync
  71.  */
  72. #define _UNIUTILS_FIRST_ENCODING ENCODING_UTF8
  73. #define _UNIUTILS_LAST_ENCODING ENCODING_MAC_ROMAN
  74.  
  75.  
  76. typedef struct _EncodingNamer {
  77.     int encoding;
  78.     char *name;
  79. } EncodingNamer;
  80.  
  81. /*YS*/
  82. int charToWide( const unsigned char *pszString, wchar_t *pwDstBuff, int sbDstBuff );
  83. int cp1252ToWide( const unsigned char *pszString, wchar_t *pwDstBuff, int sbDstBuff );
  84. int macRomanToWide( const unsigned char *pszString, wchar_t *pwDstBuff, int sbDstBuff );
  85. /*YS*/
  86. /*
  87.  
  88.     IANA MIME prefered  Java
  89.     "UTF-8"             "UTF8"
  90.     "ISO-8859-1"        "ISO8859_1"
  91.     "windows-1252"      "Cp1252"
  92.     "macintosh"         "MacRoman"
  93.  
  94. */
  95. EncodingNamer _matchNames[] = {
  96.     {ENCODING_UTF8, "utf8"},
  97.     {ENCODING_UTF8, "utf-8"},
  98.     {ENCODING_8859_1, "iso8859_1"},
  99.     {ENCODING_8859_1, "iso-8859-1"},
  100. /*    {ENCODING_APPLEBYTE, "applebyte"},    need to wait on this until font glyph cacheing is fixed
  101. */
  102.     {ENCODING_CP1252, "cp1252"},
  103.     {ENCODING_CP1252, "cp-1252"},
  104.     {ENCODING_CP1252, "windows-1252"},
  105.     {ENCODING_MAC_ROMAN, "macroman"},
  106.     {ENCODING_MAC_ROMAN, "macintosh"},
  107.     {ENCODING_MAC_ROMAN, "mac"},
  108.     {ENCODING_INVALID, NULL},
  109. };
  110.  
  111. /*
  112.  * Converts UTF-8 to UCS-2 (16-bit Unicode)
  113.  * 
  114.  * Note: This code will currently drop all UCS-4 characters.
  115.  * However, the code is started faily simply, and has some of the work
  116.  * alredy done for those characters (UTF-8 sequences over 3 bytes in length)
  117.  */
  118. int uniUtf8ToWide( const unsigned char *pszUtf8, wchar_t *pwDstBuff, int sbDstBuff ) {
  119.     int newChars = 0;
  120.     unsigned char byteVal;
  121.     unsigned char bitMask;
  122.     wchar_t uniVal;
  123.     int sequenceLength;
  124.     int isGood;
  125.     int i;
  126.     const unsigned char *pszCurr;
  127.  
  128.     if ( pszUtf8 == NULL
  129.         || ( ( sbDstBuff != 0 ) && !pwDstBuff)
  130.         || sbDstBuff < 0
  131.         ) {
  132.  
  133.         goto EXIT_ERR;
  134.     }
  135.  
  136.     if ( pszUtf8 != NULL ) {
  137.         pszCurr = pszUtf8;
  138.         while( pszCurr && *pszCurr ) {
  139.             byteVal = *pszCurr;
  140.             pszCurr++;
  141.             if ( byteVal & 0x80 ) {
  142.                 isGood = 1;
  143.  
  144.                 /* is a sequence byte */
  145.                 if ( ( byteVal & MASK_2_BYTE ) == VAL_2_BYTE ) {
  146.                     sequenceLength = 2;
  147.                     bitMask = (unsigned char)~MASK_2_BYTE;
  148.                 } else if ( ( byteVal & MASK_3_BYTE ) == VAL_3_BYTE ) {
  149.                     sequenceLength = 3;
  150.                     bitMask = (unsigned char)~MASK_3_BYTE;
  151.                 } else if ( ( byteVal & MASK_4_BYTE ) == VAL_4_BYTE ) {
  152.                     sequenceLength = 4;
  153.                     bitMask = (unsigned char)~MASK_4_BYTE;
  154.                 } else if ( ( byteVal & MASK_5_BYTE ) == VAL_5_BYTE ) {
  155.                     sequenceLength = 5;
  156.                     bitMask = (unsigned char)~MASK_5_BYTE;
  157.                 } else if ( ( byteVal & MASK_6_BYTE ) == VAL_6_BYTE ) {
  158.                     sequenceLength = 6;
  159.                     bitMask = (unsigned char)~MASK_6_BYTE;
  160.                 } else {
  161.                     /* 0xfe and 0xff are illegal UTF-8 chars .*/
  162.                     sequenceLength = 0;
  163.                 }
  164.  
  165.                 if ( sequenceLength < 2 || sequenceLength > 3 ) {
  166.                     isGood = 0;
  167.                 } else {
  168.                     for ( i = 0; i < sequenceLength - 1; i++ ) {
  169.                         if ( (pszCurr[i] == 0)
  170.                             || ( (pszCurr[i] & MASK_TRAIL_BYTE) != VAL_TRAIL_BYTE )
  171.                             ) {
  172.                             isGood = 0;
  173.                             break;
  174.                         }
  175.  
  176.                     }
  177.                 }
  178.  
  179.                 if ( isGood ) {
  180.                     uniVal = (wchar_t)(byteVal & bitMask);
  181.                     for ( i = 0; i < sequenceLength - 1; i++ ) {
  182.                         uniVal <<= 6;
  183.                         uniVal |= ( pszCurr[i] & (~MASK_TRAIL_BYTE) );
  184.                     }
  185.                 } else {
  186.                     uniVal = REPLACEMENT_CHARACTER;
  187.                 }
  188.  
  189.                 /* Now, skip to either the next lead byte, or the null terminator */
  190.                 while ( *pszCurr && ( ( (*pszCurr) & MASK_TRAIL_BYTE ) == VAL_TRAIL_BYTE ) ) {
  191.                     pszCurr++;
  192.                 }
  193.             } else {
  194.                 uniVal = (wchar_t)byteVal;
  195.             }
  196.             if ( newChars < sbDstBuff ) {
  197.                 pwDstBuff[ newChars ] = uniVal;
  198.             }
  199.             newChars++;
  200.         }
  201.     }
  202.  
  203.     return newChars;
  204. EXIT_ERR:
  205.     return -1;
  206. }
  207.  
  208.  
  209. /*
  210.  * This might be for 8859-1 to UCS2, or bytes to Apple Font.
  211.  */
  212. int charToWide( const unsigned char *pszString, wchar_t *pwDstBuff, int sbDstBuff ) {
  213.     int newChars = 0;
  214.  
  215.     if ( pszString == NULL
  216.         || ( ( sbDstBuff != 0 ) && !pwDstBuff)
  217.         || sbDstBuff < 0
  218.         ) {
  219.  
  220.         goto EXIT_ERR;
  221.     }
  222.  
  223.     if ( pszString != NULL ) {
  224.         while ( pszString[ newChars ] ) {
  225.             if ( newChars < sbDstBuff ) {
  226.                 pwDstBuff[ newChars ] = 0x00ff & (wchar_t)pszString[ newChars ];
  227.             }
  228.             newChars++;
  229.         }
  230.     }
  231.  
  232.     return newChars;
  233. EXIT_ERR:
  234.     return -1;
  235.  
  236. }
  237.  
  238. int cp1252ToWide( const unsigned char *pszString, wchar_t *pwDstBuff, int sbDstBuff ) {
  239.     int newChars = 0;
  240.     wchar_t trickyOnes[] = {
  241.         0x20AC, 0xfffd, 0x201A, 0x0192, 0x201E, 0x2026, 0x2020, 0x2021,
  242.         0x02C6, 0x2030, 0x0160, 0x2039, 0x0152, 0xfffd, 0x017D, 0xfffd,
  243.         0xfffd, 0x2018, 0x2019, 0x201C, 0x201D, 0x2022, 0x2013, 0x2014,
  244.         0x02DC, 0x2122, 0x0161, 0x203A, 0x0153, 0xfffd, 0x017E, 0x0178,
  245.     };
  246.  
  247.     if ( pszString == NULL
  248.         || ( ( sbDstBuff != 0 ) && !pwDstBuff)
  249.         || sbDstBuff < 0
  250.         ) {
  251.  
  252.         goto EXIT_ERR;
  253.     }
  254.  
  255.     if ( pszString != NULL ) {
  256.         while ( pszString[ newChars ] ) {
  257.             if ( newChars < sbDstBuff ) {
  258.                 if ( pszString[ newChars ] < 0x80
  259.                     || 0x9f < pszString[ newChars ] ) {
  260.                     pwDstBuff[ newChars ] = 0x00ff & (wchar_t)pszString[ newChars ];
  261.                 } else {
  262.                     pwDstBuff[ newChars ] = trickyOnes[ pszString[ newChars ] - 0x80 ];
  263.                 }
  264.             }
  265.             newChars++;
  266.         }
  267.     }
  268.  
  269.     return newChars;
  270. EXIT_ERR:
  271.     return -1;
  272.  
  273. }
  274.  
  275. /* Mac Roman mapping drawn from */
  276. /* ftp://ftp.unicode.org/Public/MAPPINGS/VENDORS/APPLE/ROMAN.TXT updated 1998-Aug-18 */
  277.  
  278. int macRomanToWide( const unsigned char *pszString, wchar_t *pwDstBuff, int sbDstBuff ) {
  279.     int newChars = 0;
  280.     wchar_t trickyOnes[] = {
  281.         0x00C4, 0x00C5, 0x00C7, 0x00C9, 0x00D1, 0x00D6, 0x00DC, 0x00E1,
  282.         0x00E0, 0x00E2, 0x00E4, 0x00E3, 0x00E5, 0x00E7, 0x00E9, 0x00E8,
  283.         0x00EA, 0x00EB, 0x00ED, 0x00EC, 0x00EE, 0x00EF, 0x00F1, 0x00F3,
  284.         0x00F2, 0x00F4, 0x00F6, 0x00F5, 0x00FA, 0x00F9, 0x00FB, 0x00FC,
  285.         0x2020, 0x00B0, 0x00A2, 0x00A3, 0x00A7, 0x2022, 0x00B6, 0x00DF,
  286.         0x00AE, 0x00A9, 0x2122, 0x00B4, 0x00A8, 0x2260, 0x00C6, 0x00D8,
  287.         0x221E, 0x00B1, 0x2264, 0x2265, 0x00A5, 0x00B5, 0x2202, 0x2211,
  288.         0x220F, 0x03C0, 0x222B, 0x00AA, 0x00BA, 0x03A9, 0x00E6, 0x00F8,
  289.         0x00BF, 0x00A1, 0x00AC, 0x221A, 0x0192, 0x2248, 0x2206, 0x00AB,
  290.         0x00BB, 0x2026, 0x00A0, 0x00C0, 0x00C3, 0x00D5, 0x0152, 0x0153,
  291.         0x2013, 0x2014, 0x201C, 0x201D, 0x2018, 0x2019, 0x00F7, 0x25CA,
  292.         0x00FF, 0x0178, 0x2044, 0x20AC, 0x2039, 0x203A, 0xFB01, 0xFB02,
  293.         0x2021, 0x00B7, 0x201A, 0x201E, 0x2030, 0x00C2, 0x00CA, 0x00C1,
  294.         0x00CB, 0x00C8, 0x00CD, 0x00CE, 0x00CF, 0x00CC, 0x00D3, 0x00D4,
  295.         0xF8FF, 0x00D2, 0x00DA, 0x00DB, 0x00D9, 0x0131, 0x02C6, 0x02DC,
  296.         0x00AF, 0x02D8, 0x02D9, 0x02DA, 0x00B8, 0x02DD, 0x02DB, 0x02C7,
  297.     };
  298.  
  299.     if ( pszString == NULL
  300.         || ( ( sbDstBuff != 0 ) && !pwDstBuff)
  301.         || sbDstBuff < 0
  302.         ) {
  303.  
  304.         goto EXIT_ERR;
  305.     }
  306.  
  307.     if ( pszString != NULL ) {
  308.         while ( pszString[ newChars ] ) {
  309.             if ( newChars < sbDstBuff ) {
  310.                 if ( pszString[ newChars ] < 0x80 ) {
  311.                     pwDstBuff[ newChars ] = 0x00ff & (wchar_t)pszString[ newChars ];
  312.                 } else {
  313.                     pwDstBuff[ newChars ] = trickyOnes[ pszString[ newChars ] - 0x80 ];
  314.                 }
  315.             }
  316.             newChars++;
  317.         }
  318.     }
  319.  
  320.     return newChars;
  321. EXIT_ERR:
  322.     return -1;
  323.  
  324. }
  325.  
  326.  
  327. int uniGetEncodingByName( char *str ) {
  328.     int encoding;
  329.     int i;
  330.  
  331.     if ( str == NULL ) {
  332.         encoding = ENCODING_INVALID;
  333.     } else {
  334.         for ( i = 0; _matchNames[i].encoding != ENCODING_INVALID; i++ ) {
  335.         /*YS*/
  336.         /*declared STRICMP for Mac platform*/ 
  337.             if ( STRICMP( _matchNames[i].name, str ) == 0 ) {
  338.         /*YS*/
  339.                 encoding = _matchNames[i].encoding;
  340.                 break;
  341.             }
  342.         }
  343.     }
  344.  
  345.     return encoding;
  346. }
  347.  
  348.  
  349. int uniGetDefaultEncoding( void ) {
  350.     return ENCODING_UTF8;
  351. }
  352.  
  353. int uniIsEncodingValid( int encoding ) {
  354.     int isGood;
  355.  
  356.     if ( _UNIUTILS_FIRST_ENCODING <= encoding && encoding <= _UNIUTILS_LAST_ENCODING ) {
  357.         isGood = 1;
  358.     } else {
  359.         isGood = 0;
  360.     }
  361.  
  362.     return isGood;
  363. }
  364.  
  365. int uniIsAppleByte( int encoding ) {
  366.     int retVal;
  367.  
  368.     if ( encoding == ENCODING_APPLEBYTE ) {
  369.         retVal = 1;
  370.     } else {
  371.         retVal = 0;
  372.     }
  373.  
  374.     return retVal;
  375. }
  376.  
  377. int uniBytesToChars( const unsigned char *pszString, wchar_t *pwDstBuff, int sbDstBuff, int encoding ) {
  378.     int retVal = -1;
  379.  
  380.     switch ( encoding ) {
  381.         case ENCODING_UTF8:
  382.             retVal = uniUtf8ToWide( pszString, pwDstBuff, sbDstBuff );
  383.             break;
  384.         case ENCODING_8859_1:
  385.         case ENCODING_APPLEBYTE:
  386.             retVal = charToWide( pszString, pwDstBuff, sbDstBuff );
  387.             break;
  388.         case ENCODING_CP1252:
  389.             retVal = cp1252ToWide( pszString, pwDstBuff, sbDstBuff );
  390.             break;
  391.         case ENCODING_MAC_ROMAN:
  392.             retVal = macRomanToWide( pszString, pwDstBuff, sbDstBuff );
  393.             break;
  394.         default:
  395.             retVal = -1;
  396.     }
  397.  
  398.     return retVal;
  399. }
  400.