home *** CD-ROM | disk | FTP | other *** search
/ PC Pro 2005 June (DVD) / DPPRO0605DVD.iso / dotNETSDK / SETUP.EXE / netfxsd1.cab / FL_utf_c________.3643236F_FC70_11D3_A536_0090278A1BB8 < prev    next >
Encoding:
Text File  |  2002-05-06  |  24.1 KB  |  970 lines

  1. /*++
  2.  
  3. Copyright (c) Microsoft Corporation  All rights reserved.
  4.  
  5. Module Name:
  6.  
  7.     utf.c
  8.  
  9. Abstract:
  10.  
  11.     This file contains functions that convert UTF strings to Unicode
  12.     strings and Unicode string to UTF strings.
  13.  
  14.     External Routines found in this file:
  15.       UTFCPInfo
  16.       UTFToUnicode
  17.       UnicodeToUTF
  18.  
  19. Revision History:
  20.  
  21.     02-06-96    JulieB    Created.
  22.  
  23. --*/
  24.  
  25.  
  26.  
  27. //
  28. //  Include Files.
  29. //
  30.  
  31. #include <ole2.h>
  32. #define NlsStrLenW(x) lstrlenW(x)
  33. #include "utf.h"
  34.  
  35.  
  36.  
  37.  
  38. //
  39. //  Forward Declarations.
  40. //
  41.  
  42. int
  43. UTF7ToUnicode(
  44.     LPCSTR lpSrcStr,
  45.     int cchSrc,
  46.     LPWSTR lpDestStr,
  47.     int cchDest);
  48.  
  49. int
  50. UTF8ToUnicode(
  51.     LPCSTR lpSrcStr,
  52.     int cchSrc,
  53.     LPWSTR lpDestStr,
  54.     int cchDest);
  55.  
  56. int
  57. UnicodeToUTF7(
  58.     LPCWSTR lpSrcStr,
  59.     int cchSrc,
  60.     LPSTR lpDestStr,
  61.     int cchDest);
  62.  
  63. int
  64. UnicodeToUTF8(
  65.     LPCWSTR lpSrcStr,
  66.     int cchSrc,
  67.     LPSTR lpDestStr,
  68.     int cchDest);
  69.  
  70.  
  71.  
  72. //-------------------------------------------------------------------------//
  73. //                           EXTERNAL ROUTINES                             //
  74. //-------------------------------------------------------------------------//
  75.  
  76.  
  77. ////////////////////////////////////////////////////////////////////////////
  78. //
  79. //  UTFCPInfo
  80. //
  81. //  Gets the CPInfo for the given UTF code page.
  82. //
  83. //  10-23-96    JulieB    Created.
  84. ////////////////////////////////////////////////////////////////////////////
  85.  
  86. BOOL UTFCPInfo(
  87.     UINT CodePage,
  88.     LPCPINFO lpCPInfo,
  89.     BOOL fExVer)
  90. {
  91.     int ctr;
  92.  
  93.  
  94.     //
  95.     //  Invalid Parameter Check:
  96.     //     - validate code page
  97.     //     - lpCPInfo is NULL
  98.     //
  99.     if ( (CodePage < CP_UTF7) || (CodePage > CP_UTF8) ||
  100.          (lpCPInfo == NULL) )
  101.     {
  102.         SetLastError(ERROR_INVALID_PARAMETER);
  103.         return (0);
  104.     }
  105.  
  106.     switch (CodePage)
  107.     {
  108.         case ( CP_UTF7 ) :
  109.         {
  110.             lpCPInfo->MaxCharSize = 5;
  111.             break;
  112.         }
  113.         case ( CP_UTF8 ) :
  114.         {
  115.             lpCPInfo->MaxCharSize = 3;
  116.             break;
  117.         }
  118.     }
  119.  
  120.     (lpCPInfo->DefaultChar)[0] = '?';
  121.     (lpCPInfo->DefaultChar)[1] = (BYTE)0;
  122.  
  123.     for (ctr = 0; ctr < MAX_LEADBYTES; ctr++)
  124.     {
  125.         (lpCPInfo->LeadByte)[ctr] = (BYTE)0;
  126.     }
  127.  
  128.     if (fExVer)
  129.     {
  130.         LPCPINFOEXW lpCPInfoEx = (LPCPINFOEXW)lpCPInfo;
  131.  
  132.         lpCPInfoEx->UnicodeDefaultChar = L'?';
  133.         lpCPInfoEx->CodePage = CodePage;
  134.     }
  135.  
  136.     return (TRUE);
  137. }
  138.  
  139. ////////////////////////////////////////////////////////////////////////////
  140. //
  141. //  UTFToUnicode
  142. //
  143. //  Maps a UTF character string to its wide character string counterpart.
  144. //
  145. //  02-06-96    JulieB    Created.
  146. ////////////////////////////////////////////////////////////////////////////
  147.  
  148. int UTFToUnicode(
  149.     UINT CodePage,
  150.     DWORD dwFlags,
  151.     LPCSTR lpMultiByteStr,
  152.     int cchMultiByte,
  153.     LPWSTR lpWideCharStr,
  154.     int cchWideChar)
  155. {
  156.     int rc = 0;
  157.  
  158.  
  159.     //
  160.     //  Invalid Parameter Check:
  161.     //     - validate code page
  162.     //     - length of MB string is 0
  163.     //     - wide char buffer size is negative
  164.     //     - MB string is NULL
  165.     //     - length of WC string is NOT zero AND
  166.     //         (WC string is NULL OR src and dest pointers equal)
  167.     //
  168.     if ( (CodePage < CP_UTF7) || (CodePage > CP_UTF8) ||
  169.          (cchMultiByte == 0) || (cchWideChar < 0) ||
  170.          (lpMultiByteStr == NULL) ||
  171.          ((cchWideChar != 0) &&
  172.           ((lpWideCharStr == NULL) ||
  173.            (lpMultiByteStr == (LPSTR)lpWideCharStr))) )
  174.     {
  175.         SetLastError(ERROR_INVALID_PARAMETER);
  176.         return (0);
  177.     }
  178.  
  179.     //
  180.     //  Invalid Flags Check:
  181.     //     - flags not 0
  182.     //
  183.     if (dwFlags != 0)
  184.     {
  185.         SetLastError(ERROR_INVALID_FLAGS);
  186.         return (0);
  187.     }
  188.  
  189.     //
  190.     //  If cchMultiByte is -1, then the string is null terminated and we
  191.     //  need to get the length of the string.  Add one to the length to
  192.     //  include the null termination.  (This will always be at least 1.)
  193.     //
  194.     if (cchMultiByte <= -1)
  195.     {
  196.         cchMultiByte = (int)(strlen(lpMultiByteStr) + 1);
  197.     }
  198.  
  199.     switch (CodePage)
  200.     {
  201.         case ( CP_UTF7 ) :
  202.         {
  203.             rc = UTF7ToUnicode( lpMultiByteStr,
  204.                                 cchMultiByte,
  205.                                 lpWideCharStr,
  206.                                 cchWideChar );
  207.             break;
  208.         }
  209.         case ( CP_UTF8 ) :
  210.         {
  211.             rc = UTF8ToUnicode( lpMultiByteStr,
  212.                                 cchMultiByte,
  213.                                 lpWideCharStr,
  214.                                 cchWideChar );
  215.             break;
  216.         }
  217.     }
  218.  
  219.     return (rc);
  220. }
  221.  
  222.  
  223. ////////////////////////////////////////////////////////////////////////////
  224. //
  225. //  UnicodeToUTF
  226. //
  227. //  Maps a Unicode character string to its UTF string counterpart.
  228. //
  229. //  02-06-96    JulieB    Created.
  230. ////////////////////////////////////////////////////////////////////////////
  231.  
  232. int UnicodeToUTF(
  233.     UINT CodePage,
  234.     DWORD dwFlags,
  235.     LPCWSTR lpWideCharStr,
  236.     int cchWideChar,
  237.     LPSTR lpMultiByteStr,
  238.     int cchMultiByte,
  239.     LPCSTR lpDefaultChar,
  240.     LPBOOL lpUsedDefaultChar)
  241. {
  242.     int rc = 0;
  243.  
  244.  
  245.     //
  246.     //  Invalid Parameter Check:
  247.     //     - validate code page
  248.     //     - length of WC string is 0
  249.     //     - multibyte buffer size is negative
  250.     //     - WC string is NULL
  251.     //     - length of WC string is NOT zero AND
  252.     //         (MB string is NULL OR src and dest pointers equal)
  253.     //     - lpDefaultChar and lpUsedDefaultChar not NULL
  254.     //
  255.     if ( (CodePage < CP_UTF7) || (CodePage > CP_UTF8) ||
  256.          (cchWideChar == 0) || (cchMultiByte < 0) ||
  257.          (lpWideCharStr == NULL) ||
  258.          ((cchMultiByte != 0) &&
  259.           ((lpMultiByteStr == NULL) ||
  260.            (lpWideCharStr == (LPWSTR)lpMultiByteStr))) ||
  261.          (lpDefaultChar != NULL) || (lpUsedDefaultChar != NULL) )
  262.     {
  263.         SetLastError(ERROR_INVALID_PARAMETER);
  264.         return (0);
  265.     }
  266.  
  267.     //
  268.     //  Invalid Flags Check:
  269.     //     - flags not 0
  270.     //
  271.     if (dwFlags != 0)
  272.     {
  273.         SetLastError(ERROR_INVALID_FLAGS);
  274.         return (0);
  275.     }
  276.  
  277.     //
  278.     //  If cchWideChar is -1, then the string is null terminated and we
  279.     //  need to get the length of the string.  Add one to the length to
  280.     //  include the null termination.  (This will always be at least 1.)
  281.     //
  282.     if (cchWideChar <= -1)
  283.     {
  284.         cchWideChar = NlsStrLenW(lpWideCharStr) + 1;
  285.     }
  286.  
  287.     switch (CodePage)
  288.     {
  289.         case ( CP_UTF7 ) :
  290.         {
  291.             rc = UnicodeToUTF7( lpWideCharStr,
  292.                                 cchWideChar,
  293.                                 lpMultiByteStr,
  294.                                 cchMultiByte );
  295.             break;
  296.         }
  297.         case ( CP_UTF8 ) :
  298.         {
  299.             rc = UnicodeToUTF8( lpWideCharStr,
  300.                                 cchWideChar,
  301.                                 lpMultiByteStr,
  302.                                 cchMultiByte );
  303.             break;
  304.         }
  305.     }
  306.  
  307.     return (rc);
  308. }
  309.  
  310.  
  311.  
  312.  
  313. //-------------------------------------------------------------------------//
  314. //                           INTERNAL ROUTINES                             //
  315. //-------------------------------------------------------------------------//
  316.  
  317.  
  318. ////////////////////////////////////////////////////////////////////////////
  319. //
  320. //  UTF7ToUnicode
  321. //
  322. //  Maps a UTF-7 character string to its wide character string counterpart.
  323. //
  324. //  02-06-96    JulieB    Created.
  325. ////////////////////////////////////////////////////////////////////////////
  326.  
  327. int UTF7ToUnicode(
  328.     LPCSTR lpSrcStr,
  329.     int cchSrc,
  330.     LPWSTR lpDestStr,
  331.     int cchDest)
  332. {
  333.     LPCSTR pUTF7 = lpSrcStr;
  334.     BOOL fShift = FALSE;
  335.     DWORD dwBit = 0;              // 32-bit buffer to hold temporary bits
  336.     int iPos = 0;                 // 6-bit position pointer in the buffer
  337.     int cchWC = 0;                // # of Unicode code points generated
  338.  
  339.  
  340.     while ((cchSrc--) && ((cchDest == 0) || (cchWC < cchDest)))
  341.     {
  342.         if (*pUTF7 > ASCII)
  343.         {
  344.             //
  345.             //  Error - non ASCII char, so zero extend it.
  346.             //
  347.             if (cchDest)
  348.             {
  349.                 lpDestStr[cchWC] = (WCHAR)*pUTF7;
  350.             }
  351.             cchWC++;
  352.         }
  353.         else if (!fShift)
  354.         {
  355.             //
  356.             //  Not in shifted sequence.
  357.             //
  358.             if (*pUTF7 == SHIFT_IN)
  359.             {
  360.                 if (cchSrc && (pUTF7[1] == SHIFT_OUT))
  361.                 {
  362.                     //
  363.                     //  "+-" means "+"
  364.                     //
  365.                     if (cchDest)
  366.                     {
  367.                         lpDestStr[cchWC] = (WCHAR)*pUTF7;
  368.                     }
  369.                     pUTF7++;
  370.                     cchSrc--;
  371.                     cchWC++;
  372.                 }
  373.                 else
  374.                 {
  375.                     //
  376.                     //  Start a new shift sequence.
  377.                     //
  378.                     fShift = TRUE;
  379.                 }
  380.             }
  381.             else
  382.             {
  383.                 //
  384.                 //  No need to shift.
  385.                 //
  386.                 if (cchDest)
  387.                 {
  388.                     lpDestStr[cchWC] = (WCHAR)*pUTF7;
  389.                 }
  390.                 cchWC++;
  391.             }
  392.         }
  393.         else
  394.         {
  395.             //
  396.             //  Already in shifted sequence.
  397.             //
  398.             if (nBitBase64[*pUTF7] == -1)
  399.             {
  400.                 //
  401.                 //  Any non Base64 char also ends shift state.
  402.                 //
  403.                 if (*pUTF7 != SHIFT_OUT)
  404.                 {
  405.                     //
  406.                     //  Not "-", so write it to the buffer.
  407.                     //
  408.                     if (cchDest)
  409.                     {
  410.                         lpDestStr[cchWC] = (WCHAR)*pUTF7;
  411.                     }
  412.                     cchWC++;
  413.                 }
  414.  
  415.                 //
  416.                 //  Reset bits.
  417.                 //
  418.                 fShift = FALSE;
  419.                 dwBit = 0;
  420.                 iPos = 0;
  421.             }
  422.             else
  423.             {
  424.                 //
  425.                 //  Store the bits in the 6-bit buffer and adjust the
  426.                 //  position pointer.
  427.                 //
  428.                 dwBit |= ((DWORD)nBitBase64[*pUTF7]) << (26 - iPos);
  429.                 iPos += 6;
  430.             }
  431.  
  432.             //
  433.             //  Output the 16-bit Unicode value.
  434.             //
  435.             while (iPos >= 16)
  436.             {
  437.                 if (cchDest)
  438.                 {
  439.                     if (cchWC < cchDest)
  440.                     {
  441.                         lpDestStr[cchWC] = (WCHAR)(dwBit >> 16);
  442.                     }
  443.                     else
  444.                     {
  445.                         break;
  446.                     }
  447.                 }
  448.                 cchWC++;
  449.  
  450.                 dwBit <<= 16;
  451.                 iPos -= 16;
  452.             }
  453.             if (iPos >= 16)
  454.             {
  455.                 //
  456.                 //  Error - buffer too small.
  457.                 //
  458.                 cchSrc++;
  459.                 break;
  460.             }
  461.         }
  462.  
  463.         pUTF7++;
  464.     }
  465.  
  466.     //
  467.     //  Make sure the destination buffer was large enough.
  468.     //
  469.     if (cchDest && (cchSrc >= 0))
  470.     {
  471.         SetLastError(ERROR_INSUFFICIENT_BUFFER);
  472.         return (0);
  473.     }
  474.  
  475.     //
  476.     //  Return the number of Unicode characters written.
  477.     //
  478.     return (cchWC);
  479. }
  480.  
  481.  
  482. ////////////////////////////////////////////////////////////////////////////
  483. //
  484. //  UTF8ToUnicode
  485. //
  486. //  Maps a UTF-8 character string to its wide character string counterpart.
  487. //
  488. //  02-06-96    JulieB    Created.
  489. ////////////////////////////////////////////////////////////////////////////
  490.  
  491. int UTF8ToUnicode(
  492.     LPCSTR lpSrcStr,
  493.     int cchSrc,
  494.     LPWSTR lpDestStr,
  495.     int cchDest)
  496. {
  497.     int nTB = 0;                   // # trail bytes to follow
  498.     int cchWC = 0;                 // # of Unicode code points generated
  499.     LPCSTR pUTF8 = lpSrcStr;
  500.     char UTF8;
  501.  
  502.  
  503.     while ((cchSrc--) && ((cchDest == 0) || (cchWC < cchDest)))
  504.     {
  505.         //
  506.         //  See if there are any trail bytes.
  507.         //
  508.         if (BIT7(*pUTF8) == 0)
  509.         {
  510.             //
  511.             //  Found ASCII.
  512.             //
  513.             if (cchDest)
  514.             {
  515.                 lpDestStr[cchWC] = (WCHAR)*pUTF8;
  516.             }
  517.             cchWC++;
  518.         }
  519.         else if (BIT6(*pUTF8) == 0)
  520.         {
  521.             //
  522.             //  Found a trail byte.
  523.             //  Note : Ignore the trail byte if there was no lead byte.
  524.             //
  525.             if (nTB != 0)
  526.             {
  527.                 //
  528.                 //  Decrement the trail byte counter.
  529.                 //
  530.                 nTB--;
  531.  
  532.                 //
  533.                 //  Make room for the trail byte and add the trail byte
  534.                 //  value.
  535.                 //
  536.                 if (cchDest)
  537.                 {
  538.                     lpDestStr[cchWC] <<= 6;
  539.                     lpDestStr[cchWC] |= LOWER_6_BIT(*pUTF8);
  540.                 }
  541.  
  542.                 if (nTB == 0)
  543.                 {
  544.                     //
  545.                     //  End of sequence.  Advance the output counter.
  546.                     //
  547.                     cchWC++;
  548.                 }
  549.             }
  550.         }
  551.         else
  552.         {
  553.             //
  554.             //  Found a lead byte.
  555.             //
  556.             if (nTB > 0)
  557.             {
  558.                 //
  559.                 //  Error - previous sequence not finished.
  560.                 //
  561.                 nTB = 0;
  562.                 cchWC++;
  563.             }
  564.             else
  565.             {
  566.                 //
  567.                 //  Calculate the number of bytes to follow.
  568.                 //  Look for the first 0 from left to right.
  569.                 //
  570.                 UTF8 = *pUTF8;
  571.                 while (BIT7(UTF8) != 0)
  572.                 {
  573.                     UTF8 <<= 1;
  574.                     nTB++;
  575.                 }
  576.  
  577.                 //
  578.                 //  Store the value from the first byte and decrement
  579.                 //  the number of bytes to follow.
  580.                 //
  581.                 if (cchDest)
  582.                 {
  583.                     lpDestStr[cchWC] = UTF8 >> nTB;
  584.                 }
  585.                 nTB--;
  586.             }
  587.         }
  588.  
  589.         pUTF8++;
  590.     }
  591.  
  592.     //
  593.     //  Make sure the destination buffer was large enough.
  594.     //
  595.     if (cchDest && (cchSrc >= 0))
  596.     {
  597.         SetLastError(ERROR_INSUFFICIENT_BUFFER);
  598.         return (0);
  599.     }
  600.  
  601.     //
  602.     //  Return the number of Unicode characters written.
  603.     //
  604.     return (cchWC);
  605. }
  606.  
  607.  
  608. ////////////////////////////////////////////////////////////////////////////
  609. //
  610. //  UnicodeToUTF7
  611. //
  612. //  Maps a Unicode character string to its UTF-7 string counterpart.
  613. //
  614. //  02-06-96    JulieB    Created.
  615. ////////////////////////////////////////////////////////////////////////////
  616.  
  617. int UnicodeToUTF7(
  618.     LPCWSTR lpSrcStr,
  619.     int cchSrc,
  620.     LPSTR lpDestStr,
  621.     int cchDest)
  622. {
  623.     LPCWSTR lpWC = lpSrcStr;
  624.     BOOL fShift = FALSE;
  625.     DWORD dwBit = 0;              // 32-bit buffer
  626.     int iPos = 0;                 // 6-bit position in buffer
  627.     int cchU7 = 0;                // # of UTF7 chars generated
  628.  
  629.  
  630.     while ((cchSrc--) && ((cchDest == 0) || (cchU7 < cchDest)))
  631.     {
  632.         if ((*lpWC > ASCII) || (fShiftChar[*lpWC]))
  633.         {
  634.             //
  635.             //  Need shift.  Store 16 bits in buffer.
  636.             //
  637.             dwBit |= ((DWORD)*lpWC) << (16 - iPos);
  638.             iPos += 16;
  639.  
  640.             if (!fShift)
  641.             {
  642.                 //
  643.                 //  Not in shift state, so add "+".
  644.                 //
  645.                 if (cchDest)
  646.                 {
  647.                     lpDestStr[cchU7] = SHIFT_IN;
  648.                 }
  649.                 cchU7++;
  650.  
  651.                 //
  652.                 //  Go into shift state.
  653.                 //
  654.                 fShift = TRUE;
  655.             }
  656.  
  657.             //
  658.             //  Output 6 bits at a time as Base64 chars.
  659.             //
  660.             while (iPos >= 6)
  661.             {
  662.                 if (cchDest)
  663.                 {
  664.                     if (cchU7 < cchDest)
  665.                     {
  666.                         //
  667.                         //  26 = 32 - 6
  668.                         //
  669.                         lpDestStr[cchU7] = cBase64[(int)(dwBit >> 26)];
  670.                     }
  671.                     else
  672.                     {
  673.                         break;
  674.                     }
  675.                 }
  676.  
  677.                 cchU7++;
  678.                 dwBit <<= 6;           // remove from bit buffer
  679.                 iPos -= 6;             // adjust position pointer
  680.             }
  681.             if (iPos >= 6)
  682.             {
  683.                 //
  684.                 //  Error - buffer too small.
  685.                 //
  686.                 cchSrc++;
  687.                 break;
  688.             }
  689.         }
  690.         else
  691.         {
  692.             //
  693.             //  No need to shift.
  694.             //
  695.             if (fShift)
  696.             {
  697.                 //
  698.                 //  End the shift sequence.
  699.                 //
  700.                 fShift = FALSE;
  701.  
  702.                 if (iPos != 0)
  703.                 {
  704.                     //
  705.                     //  Some bits left in dwBit.
  706.                     //
  707.                     if (cchDest)
  708.                     {
  709.                         if ((cchU7 + 1) < cchDest)
  710.                         {
  711.                             lpDestStr[cchU7++] = cBase64[(int)(dwBit >> 26)];
  712.                             lpDestStr[cchU7++] = SHIFT_OUT;
  713.                         }
  714.                         else
  715.                         {
  716.                             //
  717.                             //  Error - buffer too small.
  718.                             //
  719.                             cchSrc++;
  720.                             break;
  721.                         }
  722.                     }
  723.                     else
  724.                     {
  725.                         cchU7 += 2;
  726.                     }
  727.  
  728.                     dwBit = 0;         // reset bit buffer
  729.                     iPos  = 0;         // reset postion pointer
  730.                 }
  731.                 else
  732.                 {
  733.                     //
  734.                     //  Simply end the shift sequence.
  735.                     //
  736.                     if (cchDest)
  737.                     {
  738.                         lpDestStr[cchU7++] = SHIFT_OUT;
  739.                     }
  740.                     else
  741.                     {
  742.                         cchU7++;
  743.                     }
  744.                 }
  745.             }
  746.  
  747.             //
  748.             //  Write the character to the buffer.
  749.             //  If the character is "+", then write "+-".
  750.             //
  751.             if (cchDest)
  752.             {
  753.                 if (cchU7 < cchDest)
  754.                 {
  755.                     lpDestStr[cchU7++] = (char)*lpWC;
  756.  
  757.                     if (*lpWC == SHIFT_IN)
  758.                     {
  759.                         if (cchU7 < cchDest)
  760.                         {
  761.                             lpDestStr[cchU7++] = SHIFT_OUT;
  762.                         }
  763.                         else
  764.                         {
  765.                             //
  766.                             //  Error - buffer too small.
  767.                             //
  768.                             cchSrc++;
  769.                             break;
  770.                         }
  771.                     }
  772.                 }
  773.                 else
  774.                 {
  775.                     //
  776.                     //  Error - buffer too small.
  777.                     //
  778.                     cchSrc++;
  779.                     break;
  780.                 }
  781.             }
  782.             else
  783.             {
  784.                 cchU7++;
  785.  
  786.                 if (*lpWC == SHIFT_IN)
  787.                 {
  788.                     cchU7++;
  789.                 }
  790.             }
  791.         }
  792.  
  793.         lpWC++;
  794.     }
  795.  
  796.     //
  797.     //  See if we're still in the shift state.
  798.     //
  799.     if (fShift)
  800.     {
  801.         if (iPos != 0)
  802.         {
  803.             //
  804.             //  Some bits left in dwBit.
  805.             //
  806.             if (cchDest)
  807.             {
  808.                 if ((cchU7 + 1) < cchDest)
  809.                 {
  810.                     lpDestStr[cchU7++] = cBase64[(int)(dwBit >> 26)];
  811.                     lpDestStr[cchU7++] = SHIFT_OUT;
  812.                 }
  813.                 else
  814.                 {
  815.                     //
  816.                     //  Error - buffer too small.
  817.                     //
  818.                     cchSrc++;
  819.                 }
  820.             }
  821.             else
  822.             {
  823.                 cchU7 += 2;
  824.             }
  825.         }
  826.         else
  827.         {
  828.             //
  829.             //  Simply end the shift sequence.
  830.             //
  831.             if (cchDest)
  832.             {
  833.                 lpDestStr[cchU7++] = SHIFT_OUT;
  834.             }
  835.             else
  836.             {
  837.                 cchU7++;
  838.             }
  839.         }
  840.     }
  841.  
  842.     //
  843.     //  Make sure the destination buffer was large enough.
  844.     //
  845.     if (cchDest && (cchSrc >= 0))
  846.     {
  847.         SetLastError(ERROR_INSUFFICIENT_BUFFER);
  848.         return (0);
  849.     }
  850.  
  851.     //
  852.     //  Return the number of UTF-7 characters written.
  853.     //
  854.     return (cchU7);
  855. }
  856.  
  857.  
  858. ////////////////////////////////////////////////////////////////////////////
  859. //
  860. //  UnicodeToUTF8
  861. //
  862. //  Maps a Unicode character string to its UTF-8 string counterpart.
  863. //
  864. //  02-06-96    JulieB    Created.
  865. ////////////////////////////////////////////////////////////////////////////
  866.  
  867. int UnicodeToUTF8(
  868.     LPCWSTR lpSrcStr,
  869.     int cchSrc,
  870.     LPSTR lpDestStr,
  871.     int cchDest)
  872. {
  873.     LPCWSTR lpWC = lpSrcStr;
  874.     int cchU8 = 0;                // # of UTF8 chars generated
  875.  
  876.  
  877.     while ((cchSrc--) && ((cchDest == 0) || (cchU8 < cchDest)))
  878.     {
  879.         if (*lpWC <= ASCII)
  880.         {
  881.             //
  882.             //  Found ASCII.
  883.             //
  884.             if (cchDest)
  885.             {
  886.                 lpDestStr[cchU8] = (char)*lpWC;
  887.             }
  888.             cchU8++;
  889.         }
  890.         else if (*lpWC <= UTF8_2_MAX)
  891.         {
  892.             //
  893.             //  Found 2 byte sequence if < 0x07ff (11 bits).
  894.             //
  895.             if (cchDest)
  896.             {
  897.                 if ((cchU8 + 1) < cchDest)
  898.                 {
  899.                     //
  900.                     //  Use upper 5 bits in first byte.
  901.                     //  Use lower 6 bits in second byte.
  902.                     //
  903.                     lpDestStr[cchU8++] = UTF8_1ST_OF_2 | (*lpWC >> 6);
  904.                     lpDestStr[cchU8++] = UTF8_TRAIL    | LOWER_6_BIT(*lpWC);
  905.                 }
  906.                 else
  907.                 {
  908.                     //
  909.                     //  Error - buffer too small.
  910.                     //
  911.                     cchSrc++;
  912.                     break;
  913.                 }
  914.             }
  915.             else
  916.             {
  917.                 cchU8 += 2;
  918.             }
  919.         }
  920.         else
  921.         {
  922.             //
  923.             //  Found 3 byte sequence.
  924.             //
  925.             if (cchDest)
  926.             {
  927.                 if ((cchU8 + 2) < cchDest)
  928.                 {
  929.                     //
  930.                     //  Use upper  4 bits in first byte.
  931.                     //  Use middle 6 bits in second byte.
  932.                     //  Use lower  6 bits in third byte.
  933.                     //
  934.                     lpDestStr[cchU8++] = UTF8_1ST_OF_3 | (*lpWC >> 12);
  935.                     lpDestStr[cchU8++] = UTF8_TRAIL    | MIDDLE_6_BIT(*lpWC);
  936.                     lpDestStr[cchU8++] = UTF8_TRAIL    | LOWER_6_BIT(*lpWC);
  937.                 }
  938.                 else
  939.                 {
  940.                     //
  941.                     //  Error - buffer too small.
  942.                     //
  943.                     cchSrc++;
  944.                     break;
  945.                 }
  946.             }
  947.             else
  948.             {
  949.                 cchU8 += 3;
  950.             }
  951.         }
  952.  
  953.         lpWC++;
  954.     }
  955.  
  956.     //
  957.     //  Make sure the destination buffer was large enough.
  958.     //
  959.     if (cchDest && (cchSrc >= 0))
  960.     {
  961.         SetLastError(ERROR_INSUFFICIENT_BUFFER);
  962.         return (0);
  963.     }
  964.  
  965.     //
  966.     //  Return the number of UTF-8 characters written.
  967.     //
  968.     return (cchU8);
  969. }
  970.