unicode.cxx
Upload User: caisha3
Upload Date: 2013-09-21
Package Size: 208739k
Code Size: 9k
Category:

Windows Develop

Development Platform:

Visual C++

  1. //+------------------------------------------------------------------------
  2. //
  3. //  Microsoft Forms
  4. //  Copyright (C) Microsoft Corporation, 1992 - 1995.
  5. //
  6. //  File:       unicode.cxx
  7. //
  8. //  Contents:   Support for Unicode character set encoding
  9. //
  10. //-------------------------------------------------------------------------
  11. #include "headers.hxx"
  12. #ifndef X_WCHDEFS_H_
  13. #define X_WCHDEFS_H_
  14. #include "wchdefs.h"
  15. #endif
  16. #ifndef X_ENCODE_HXX_
  17. #define X_ENCODE_HXX_
  18. #include "encode.hxx"
  19. #endif
  20. static const TCHAR s_chUnknown = _T('?');
  21. //+-----------------------------------------------------------------------
  22. //
  23. //  Member:     WideCharFromUcs2
  24. //
  25. //  Synopsis:   Convert from UCS-2 to Unicode
  26. //
  27. //------------------------------------------------------------------------
  28. HRESULT
  29. CEncodeReader::WideCharFromUcs2( BOOL fReadEof, int * pcch )
  30. {
  31.     HRESULT hr;
  32.     size_t cb = (_cbBuffer - (_pbBufferPtr - _pbBuffer)) & ~1;
  33.     int cch = cb / sizeof(WCHAR);
  34.     TCHAR * p;
  35.     hr = THR( MakeRoomForChars( cch ) );
  36.     if (hr)
  37.         goto Cleanup;
  38.     memcpy( _pchEnd, _pbBufferPtr, cb );
  39.     // Replace private use area characters
  40.     
  41.     p = _pchEnd + cch;
  42.     while (p-- > _pchEnd)
  43.     {
  44.         if (!IsValidWideChar(*p))
  45.             *p = s_chUnknown;
  46.     }
  47.     *pcch = cch;
  48.     _pbBufferPtr += cb;
  49. Cleanup:
  50.     RRETURN(hr);
  51. }
  52. //+-----------------------------------------------------------------------
  53. //
  54. //  Member:     UnicodeFromWideChar
  55. //
  56. //  Synopsis:   Convert from Unicode to UCS-2
  57. //
  58. //------------------------------------------------------------------------
  59. HRESULT
  60. CEncodeWriter::UnicodeFromWideChar( BOOL fReadEof, int * pcb )
  61. {
  62.     HRESULT hr;
  63.     int     cb = _cchBuffer * sizeof(TCHAR);
  64.     hr = THR(MakeRoomForChars(cb));
  65.     if( hr )
  66.         goto Cleanup;
  67.     memcpy( _pbBuffer + _cbBuffer, _pchBuffer, cb );
  68.     *pcb = cb;
  69.     _cbBuffer += cb;
  70. Cleanup:
  71.     RRETURN( hr );
  72. }
  73. #ifndef WINCE
  74. //+-----------------------------------------------------------------------
  75. //
  76. //  Member:     WideCharFromUtf8
  77. //
  78. //  Synopsis:   Convert from UTF-8 to Unicode
  79. //
  80. //------------------------------------------------------------------------
  81. // Unicode value                                UTF-8 value
  82. //
  83. // 0000 0000 0xxx xxxx                          0xxx xxxx
  84. // 0000 0yyy yyxx xxxx                          110y yyyy 10xx xxxx   
  85. // zzzz yyyy yyxx xxxx                          1110 zzzz 10yy yyyy 10xx xxxx
  86. // 1101 10ww wwzz zzyy + 1101 11yy yyxx xxxx    1111 0uuu 10uu zzzz 10yy yyyy 10xx xxxxx (uuuuu = wwww + 1)
  87. static int aiByteCountForLeadNibble[16] =
  88. {
  89.     1,  // 0000
  90.     1,  // 0001
  91.     1,  // 0010
  92.     1,  // 0011
  93.     1,  // 0100
  94.     1,  // 0101
  95.     1,  // 0110
  96.     1,  // 0111
  97.     1,  // 1000
  98.     1,  // 1001
  99.     1,  // 1010
  100.     1,  // 1011
  101.     2,  // 1100
  102.     2,  // 1101
  103.     3,  // 1110
  104.     4   // 1111
  105. };
  106. HRESULT
  107. CEncodeReader::WideCharFromUtf8( BOOL fReadEof, int * pcch )
  108. {
  109.     HRESULT hr;
  110.     unsigned char * pb;
  111.     unsigned char * pbStop;
  112.     WCHAR * pchDst;
  113.     int cch;
  114.     // First determine the destination size (cch).
  115.     // Note that pbStop is adjust to the last character boundary.
  116.     for (pb = _pbBufferPtr, pbStop = _pbBuffer + _cbBuffer, cch = 0; pb < pbStop;)
  117.     {
  118.         unsigned char t = *pb;
  119.         size_t bytes = aiByteCountForLeadNibble[t>>4];
  120.         if (pb + bytes > pbStop)
  121.         {
  122.             pbStop = pb;
  123.             break;
  124.         }
  125.         else
  126.         {
  127.             pb += bytes;
  128.         }
  129.         cch += 1 + (bytes>>2); // surrogates need an extra wchar
  130.     }
  131.     
  132.     hr = THR( MakeRoomForChars( cch ) );
  133.     if (hr)
  134.         goto Cleanup;
  135.     // Now decode
  136.     for (pchDst  = _pchEnd, pb = _pbBufferPtr; pb < pbStop;)
  137.     {
  138.         unsigned char t = *pb;
  139.         size_t bytes = aiByteCountForLeadNibble[t>>4];
  140.         WCHAR ch = 0;
  141.         switch (bytes)
  142.         {
  143.             case 1:
  144.                 *pchDst++ = WCHAR(*pb++);           // 0x0000 - 0x007f
  145.                 break;
  146.             case 3:
  147.                 ch  = WCHAR(*pb++ & 0x0f) << 12;    // 0x0800 - 0xffff
  148.                 // fall through
  149.             case 2:
  150.                 ch |= WCHAR(*pb++ & 0x3f) << 6;     // 0x0080 - 0x07ff
  151.                 ch |= WCHAR(*pb++ & 0x3f);
  152.                 if (IsValidWideChar(ch))
  153.                 {
  154.                     *pchDst++ = ch;
  155.                 }
  156.                 else
  157.                 {
  158.                     *pchDst++ = s_chUnknown;
  159.                 }
  160.                 break;
  161.                     
  162.             case 4:                                 // 0xd800 - 0xdfff (Surrogates)
  163.                 ch  = WCHAR(*pb++ & 0x07) << 2;
  164.                 ch |= WCHAR(*pb & 0x30) >> 4;
  165.                 ch  = (ch - 1) << 6;                // ch == 0000 00ww ww00 0000
  166.                 ch |= WCHAR(*pb++ & 0x0f) << 2;     // ch == 0000 00ww wwzz zz00
  167.                 ch |= WCHAR(*pb & 0x30) >> 4;       // ch == 0000 00ww wwzz zzyy
  168.                 *pchDst++ = 0xD800 + ch;
  169.                 Assert(IsHighSurrogateChar(pchDst[-1]));
  170.                 ch  = WCHAR(*pb++ & 0x0f) << 6;     // ch == 0000 00yy yy00 0000
  171.                 ch |= WCHAR(*pb++ & 0x3f);          // ch == 0000 00yy yyxx xxxx
  172.                 *pchDst++ = 0xDC00 + ch;
  173.                 Assert(IsLowSurrogateChar(pchDst[-1]));
  174.                 break;
  175.         }
  176.         WHEN_DBG( cch -= (bytes == 4) ? 2 : 1 );
  177.     }
  178.     Assert( cch == 0 );
  179.     *pcch = pchDst - _pchEnd;
  180.     _pbBufferPtr = pbStop;
  181. Cleanup:
  182.     RRETURN(hr);
  183. }
  184. //+-----------------------------------------------------------------------
  185. //
  186. //  Member:     Utf8FromWideChar
  187. //
  188. //  Synopsis:   Convert from Unicode to UTF-8
  189. //
  190. //------------------------------------------------------------------------
  191. static TCHAR s_cUtf8FirstSignal[5] = {0x00, 0x00, 0xC0, 0xE0, 0xF0};
  192. HRESULT
  193. CEncodeWriter::Utf8FromWideChar( BOOL fReadEof, int * pcch )
  194. {
  195.     HRESULT hr;
  196.     TCHAR* pch = _pchBuffer, *pchStop = _pchBuffer + _cchBuffer;
  197.     unsigned char* pbDst;
  198.     const  TCHAR cMask   = 0xBF;
  199.     const  TCHAR cSignal = 0x80;
  200.     int    cb;
  201.     // First make a pass to see how many characters we will be converting.
  202.     for( cb = 0; pch < pchStop; )
  203.     {
  204.         const TCHAR ch = *pch++;
  205.         if (ch < 0x800)
  206.         {
  207.             cb += (ch < 0x80) ? 1 : 2;
  208.         }
  209.         else
  210.         {
  211. #ifndef NO_UTF16
  212.             if (!IsHighSurrogateChar(ch))
  213.             {
  214.                 cb += 3;
  215.             }
  216.             else
  217.             {
  218.                 // BUGBUG (cthrash) If a surrogate pair is split at pchStop boundary,
  219.                 // we should wait emitting any multibyte chars until we have more data.
  220.                 // Nevertheless, utf-8 converters should be written in such a way that
  221.                 // surrogate chars can be stored as one four-byte sequence or two three-
  222.                 // byte sequences.  So ignore the issue for now.
  223.                 if (pch == pchStop || !IsLowSurrogateChar(*pch))
  224.                 {
  225.                     cb += 3;
  226.                 }
  227.                 else
  228.                 {
  229.                     pch++;
  230.                     cb += 4;
  231.                 }
  232.             }
  233. #else
  234.             cb += 3;
  235. #endif
  236.         }
  237.     }
  238.     hr = THR( MakeRoomForChars( cb ) );
  239.     if( hr )
  240.         goto Cleanup;
  241.     // Now encode Utf8
  242.     
  243.     for (pbDst  = _pbBuffer + _cbBuffer, pch = _pchBuffer; pch < pchStop;)
  244.     {
  245.         DWORD ch = DWORD(*pch++); // UCS4
  246.         size_t cbTotal;
  247.         if (ch < 0x800)
  248.         {
  249.             cbTotal = (ch < 0x80) ? 1 : 2;
  250.         }
  251.         else
  252.         {
  253. #ifndef NO_UTF16
  254.             if (   IsHighSurrogateChar(ch)
  255.                 && pch < pchStop
  256.                 && IsLowSurrogateChar(*pch))
  257.             {
  258.                 const DWORD ch2 = DWORD(*pch++);
  259.                 ch = 0x10000 + ((ch & 0x3ff) << 10) + (ch2 & 0x3ff);
  260.                 cbTotal = 4;
  261.             }
  262.             else
  263.             {
  264.                 cbTotal = 3;
  265.             }
  266. #else
  267.             cbTotal = 3;
  268. #endif
  269.         }
  270.         pbDst += cbTotal;
  271.         
  272.         switch (cbTotal)
  273.         {
  274.             case 4: *--pbDst = (ch | cSignal) & cMask; ch >>= 6;
  275.             case 3: *--pbDst = (ch | cSignal) & cMask; ch >>= 6;
  276.             case 2: *--pbDst = (ch | cSignal) & cMask; ch >>= 6;
  277.             case 1: *--pbDst = (ch | s_cUtf8FirstSignal[ cbTotal ]);
  278.         }
  279.         pbDst += cbTotal;
  280.     }
  281.     *pcch = cb;                    // return number of bytes converted
  282.     _cbBuffer += cb;
  283. Cleanup:
  284.     RRETURN( hr );
  285. }
  286. #endif  // WINCE