ichrcnv.cpp
Upload User: xhy777
Upload Date: 2007-02-14
Package Size: 24088k
Code Size: 78k
Category:

Windows Kernel

Development Platform:

Visual C++

  1. #include "private.h"
  2. #include "detcbase.h"
  3. #include "codepage.h"
  4. #include "detcjpn.h"
  5. #include "detckrn.h"
  6. #include "fechrcnv.h"
  7. #include "ichrcnv.h"
  8. #include "cpdetect.h"
  9. #define CONV_UU     12
  10. #define CONV_UUW    10
  11. #define CONV_UUWI   9
  12. #define CONV_UW     6
  13. #define CONV_UWI    5
  14. #define CONV_WI     3
  15. #define MAX_CHAR_SIZE   4
  16. #define MAPUSERDEF(x) (((x) == 50000) ? 1252 : (x))
  17. #define CONVERT_IS_VALIDCODEPAGE(x) (((x) == CP_USER_DEFINED) ? TRUE: IsValidCodePage(x))
  18. #define CONV_CHK_NLS 0x00000001
  19. struct ENCODINGINFO
  20. {
  21.     DWORD       dwEncoding;
  22.     DWORD       dwCodePage;
  23.     BYTE        bTypeUUIW;
  24.     CP_STATE    nCP_State ;                 // whether this is a valid windows codepage  ?
  25.     DWORD       dwFlags;                    // give us more flexibilities to handle different encodings differently
  26. };
  27. static WCHAR UniocdeSignature = { 0xFFFE } ;
  28. /*
  29.     Bit 4 (16) - Unicode <-> Internet Encoding
  30.     Bit 3 (8) - UTF8, UTF7
  31.     Bit 2 (4) - Unicode
  32.     Bit 1 (2) - Windows CodePage
  33.     Bit 0 (1) - Internet Encoding
  34.      P.S. if bit 4 is set, it means it should convert between Unicode and Internet
  35.      Encoding directly, no intermediate step - Windows CodePage
  36. */
  37. // these codepages including Unicode need special convertor
  38. static struct ENCODINGINFO aEncodingInfo[] =
  39. {
  40.     {  CP_JPN_SJ,            932,       0x02,   INVALID_CP,     0 }, // W-Japanese Shift JIS
  41.     {  CP_CHN_GB,            936,       0x02,   INVALID_CP,     0 }, // W-Simplified Chinese
  42.     {  CP_KOR_5601,          949,       0x02,   INVALID_CP,     0 }, // W-Krean Unified Hangul
  43.     {  CP_TWN,               950,       0x02,   INVALID_CP,     0 }, // W-Traditional Chinese
  44.     {  CP_UCS_2,               0,       0x04,   INVALID_CP,     0 }, // U-Unicode 
  45.     {  CP_UCS_2_BE,            0,       0x04,   INVALID_CP,     0 }, // U-Unicode Big Endian
  46.     {  CP_1252,             1252,       0x02,   INVALID_CP,     0 }, // W-Latin 1
  47.     {  CP_20127,            1252,       0x11,   INVALID_CP,     CONV_CHK_NLS }, // US ASCII
  48.     {  CP_ISO_8859_1,       1252,       0x11,   INVALID_CP,     CONV_CHK_NLS }, // I-ISO 8859-1 Latin 1 
  49.     {  CP_ISO_8859_15,      1252,       0x11,   INVALID_CP,     CONV_CHK_NLS }, // I-ISO 8859-1 Latin 1 
  50.     {  CP_AUTO,             1252,       0x01,   INVALID_CP,     0 }, // General auto detect 
  51.     {  CP_ISO_2022_JP,       932,       0x01,   INVALID_CP,     0 }, // I-ISO 2022-JP No Halfwidth Katakana 
  52.     {  CP_ISO_2022_JP_ESC,   932,       0x01,   INVALID_CP,     0 }, // I-ISO 2022-JP w/esc Halfwidth Katakana 
  53.     {  CP_ISO_2022_JP_SIO,   932,       0x01,   INVALID_CP,     0 }, // I-ISO 2022-JP w/sio Halfwidth Katakana 
  54.     {  CP_ISO_2022_KR,       949,       0x01,   INVALID_CP,     0 }, // I-ISO 2022-KR
  55.     {  CP_ISO_2022_TW,       950,       0x01,   INVALID_CP,     0 }, // I-ISO 2022-TW
  56.     {  CP_ISO_2022_CH,       936,       0x01,   INVALID_CP,     0 }, // I-ISO 2022-CH
  57.     {  CP_JP_AUTO,           932,       0x01,   INVALID_CP,     0 }, // JP auto detect 
  58.     {  CP_CHS_AUTO,          936,       0x01,   INVALID_CP,     0 }, // Simplified Chinese auto detect 
  59.     {  CP_KR_AUTO,           949,       0x01,   INVALID_CP,     0 }, // KR auto detect 
  60.     {  CP_CHT_AUTO,          950,       0x01,   INVALID_CP,     0 }, // Traditional Chinese auto detect 
  61.     {  CP_CYRILLIC_AUTO,    1251,       0x01,   INVALID_CP,     0 }, // Cyrillic auto detect 
  62.     {  CP_GREEK_AUTO,       1253,       0x01,   INVALID_CP,     0 }, // Greek auto detect 
  63.     {  CP_ARABIC_AUTO,      1256,       0x01,   INVALID_CP,     0 }, // Arabic auto detect 
  64.     {  CP_EUC_JP,            932,       0x01,   INVALID_CP,     0 }, // EUC Japanese 
  65.     {  CP_EUC_CH,            936,       0x01,   INVALID_CP,     0 }, // EUC Chinese 
  66.     {  CP_EUC_KR,            949,       0x01,   INVALID_CP,     0 }, // EUC Korean
  67.     {  CP_EUC_TW,            950,       0x01,   INVALID_CP,     0 }, // EUC Taiwanese 
  68.     {  CP_CHN_HZ,            936,       0x01,   INVALID_CP,     0 }, // Simplify Chinese HZ-GB 
  69.     {  CP_UTF_7,               0,       0x08,   INVALID_CP,     0 }, // U-UTF7 
  70.     {  CP_UTF_8,               0,       0x08,   INVALID_CP,     0 }, // U-UTF8 
  71. };
  72. // HTML name entity table for Latin-1 Supplement - from 0x00A0-0x00FF
  73. #define NAME_ENTITY_OFFSET  0x00A0
  74. #define NAME_ENTITY_MAX     0x00FF
  75. #define NAME_ENTITY_ENTRY   96
  76. static CHAR *g_lpstrNameEntity[NAME_ENTITY_ENTRY] =
  77. {
  78.     "&nbsp;",   // "&#160;" -- no-break space = non-breaking space,
  79.     "&iexcl;",  // "&#161;" -- inverted exclamation mark, U+00A1 ISOnum -->
  80.     "&cent;",   // "&#162;" -- cent sign, U+00A2 ISOnum -->
  81.     "&pound;",  // "&#163;" -- pound sign, U+00A3 ISOnum -->
  82.     "&curren;", // "&#164;" -- currency sign, U+00A4 ISOnum -->
  83.     "&yen;",    // "&#165;" -- yen sign = yuan sign, U+00A5 ISOnum -->
  84.     "&brvbar;", // "&#166;" -- broken bar = broken vertical bar,
  85.     "&sect;",   // "&#167;" -- section sign, U+00A7 ISOnum -->
  86.     "&uml;",    // "&#168;" -- diaeresis = spacing diaeresis,
  87.     "&copy;",   // "&#169;" -- copyright sign, U+00A9 ISOnum -->
  88.     "&ordf;",   // "&#170;" -- feminine ordinal indicator, U+00AA ISOnum -->
  89.     "&laquo;",  // "&#171;" -- left-pointing double angle quotation mark
  90.     "&not;",    // "&#172;" -- not sign = discretionary hyphen,
  91.     "&shy;",    // "&#173;" -- soft hyphen = discretionary hyphen,
  92.     "&reg;",    // "&#174;" -- registered sign = registered trade mark sign,
  93.     "&macr;",   // "&#175;" -- macron = spacing macron = overline
  94.     "&deg;",    // "&#176;" -- degree sign, U+00B0 ISOnum -->
  95.     "&plusmn;", // "&#177;" -- plus-minus sign = plus-or-minus sign,
  96.     "&sup2;",   // "&#178;" -- superscript two = superscript digit two
  97.     "&sup3;",   // "&#179;" -- superscript three = superscript digit three
  98.     "&acute;",  // "&#180;" -- acute accent = spacing acute,
  99.     "&micro;",  // "&#181;" -- micro sign, U+00B5 ISOnum -->
  100.     "&para;",   // "&#182;" -- pilcrow sign = paragraph sign,
  101.     "&middot;", // "&#183;" -- middle dot = Georgian comma
  102.     "&cedil;",  // "&#184;" -- cedilla = spacing cedilla, U+00B8 ISOdia -->
  103.     "&sup1;",   // "&#185;" -- superscript one = superscript digit one,
  104.     "&ordm;",   // "&#186;" -- masculine ordinal indicator,
  105.     "&raquo;",  // "&#187;" -- right-pointing double angle quotation mark
  106.     "&frac14;", // "&#188;" -- vulgar fraction one quarter
  107.     "&frac12;", // "&#189;" -- vulgar fraction one half
  108.     "&frac34;", // "&#190;" -- vulgar fraction three quarters
  109.     "&iquest;", // "&#191;" -- inverted question mark
  110.     "&Agrave;", // "&#192;" -- latin capital letter A with grave
  111.     "&Aacute;", // "&#193;" -- latin capital letter A with acute,
  112.     "&Acirc;",  // "&#194;" -- latin capital letter A with circumflex,
  113.     "&Atilde;", // "&#195;" -- latin capital letter A with tilde,
  114.     "&Auml;",   // "&#196;" -- latin capital letter A with diaeresis,
  115.     "&Aring;",  // "&#197;" -- latin capital letter A with ring above
  116.     "&AElig;",  // "&#198;" -- latin capital letter AE
  117.     "&Ccedil;", // "&#199;" -- latin capital letter C with cedilla,
  118.     "&Egrave;", // "&#200;" -- latin capital letter E with grave,
  119.     "&Eacute;", // "&#201;" -- latin capital letter E with acute,
  120.     "&Ecirc;",  // "&#202;" -- latin capital letter E with circumflex,
  121.     "&Euml;",   // "&#203;" -- latin capital letter E with diaeresis,
  122.     "&Igrave;", // "&#204;" -- latin capital letter I with grave,
  123.     "&Iacute;", // "&#205;" -- latin capital letter I with acute,
  124.     "&Icirc;",  // "&#206;" -- latin capital letter I with circumflex,
  125.     "&Iuml;",   // "&#207;" -- latin capital letter I with diaeresis,
  126.     "&ETH;",    // "&#208;" -- latin capital letter ETH, U+00D0 ISOlat1 -->
  127.     "&Ntilde;", // "&#209;" -- latin capital letter N with tilde,
  128.     "&Ograve;", // "&#210;" -- latin capital letter O with grave,
  129.     "&Oacute;", // "&#211;" -- latin capital letter O with acute,
  130.     "&Ocirc;",  // "&#212;" -- latin capital letter O with circumflex,
  131.     "&Otilde;", // "&#213;" -- latin capital letter O with tilde,
  132.     "&Ouml;",   // "&#214;" -- latin capital letter O with diaeresis,
  133.     "&times;",  // "&#215;" -- multiplication sign, U+00D7 ISOnum -->
  134.     "&Oslash;", // "&#216;" -- latin capital letter O with stroke
  135.     "&Ugrave;", // "&#217;" -- latin capital letter U with grave,
  136.     "&Uacute;", // "&#218;" -- latin capital letter U with acute,
  137.     "&Ucirc;",  // "&#219;" -- latin capital letter U with circumflex,
  138.     "&Uuml;",   // "&#220;" -- latin capital letter U with diaeresis,
  139.     "&Yacute;", // "&#221;" -- latin capital letter Y with acute,
  140.     "&THORN;",  // "&#222;" -- latin capital letter THORN,
  141.     "&szlig;",  // "&#223;" -- latin small letter sharp s = ess-zed,
  142.     "&agrave;", // "&#224;" -- latin small letter a with grave
  143.     "&aacute;", // "&#225;" -- latin small letter a with acute,
  144.     "&acirc;",  // "&#226;" -- latin small letter a with circumflex,
  145.     "&atilde;", // "&#227;" -- latin small letter a with tilde,
  146.     "&auml;",   // "&#228;" -- latin small letter a with diaeresis,
  147.     "&aring;",  // "&#229;" -- latin small letter a with ring above
  148.     "&aelig;",  // "&#230;" -- latin small letter ae
  149.     "&ccedil;", // "&#231;" -- latin small letter c with cedilla,
  150.     "&egrave;", // "&#232;" -- latin small letter e with grave,
  151.     "&eacute;", // "&#233;" -- latin small letter e with acute,
  152.     "&ecirc;",  // "&#234;" -- latin small letter e with circumflex,
  153.     "&euml;",   // "&#235;" -- latin small letter e with diaeresis,
  154.     "&igrave;", // "&#236;" -- latin small letter i with grave,
  155.     "&iacute;", // "&#237;" -- latin small letter i with acute,
  156.     "&icirc;",  // "&#238;" -- latin small letter i with circumflex,
  157.     "&iuml;",   // "&#239;" -- latin small letter i with diaeresis,
  158.     "&eth;",    // "&#240;" -- latin small letter eth, U+00F0 ISOlat1 -->
  159.     "&ntilde;", // "&#241;" -- latin small letter n with tilde,
  160.     "&ograve;", // "&#242;" -- latin small letter o with grave,
  161.     "&oacute;", // "&#243;" -- latin small letter o with acute,
  162.     "&ocirc;",  // "&#244;" -- latin small letter o with circumflex,
  163.     "&otilde;", // "&#245;" -- latin small letter o with tilde,
  164.     "&ouml;",   // "&#246;" -- latin small letter o with diaeresis,
  165.     "&divide;", // "&#247;" -- division sign, U+00F7 ISOnum -->
  166.     "&oslash;", // "&#248;" -- latin small letter o with stroke,
  167.     "&ugrave;", // "&#249;" -- latin small letter u with grave,
  168.     "&uacute;", // "&#250;" -- latin small letter u with acute,
  169.     "&ucirc;",  // "&#251;" -- latin small letter u with circumflex,
  170.     "&uuml;",   // "&#252;" -- latin small letter u with diaeresis,
  171.     "&yacute;", // "&#253;" -- latin small letter y with acute,
  172.     "&thorn;",  // "&#254;" -- latin small letter thorn with,
  173.     "&yuml;",   // "&#255;" -- latin small letter y with diaeresis,
  174. };
  175. #ifdef MORE_NAME_ENTITY   // in case we decide to do more name entity latter
  176. // Additional HTML 4.0 name entity table for CP 1252 extension character set
  177. #define CP1252EXT_BASE  (UINT)0x0080
  178. #define CP1252EXT_MAX   (UINT)0x009F
  179. #define NONUNI          0xFFFF
  180. #define UNDEFCHAR       "???????"
  181. #define CP1252EXT_NCR_SIZE  7
  182. struct NAME_ENTITY_EXT
  183. {
  184.     UWORD     uwUniCode;
  185.     LPCTSTR   lpszNameEntity;
  186. };
  187. static struct NAME_ENTITY_EXT aNameEntityExt[] =
  188. {
  189. //      UniCode  NCR_Enty          Name_Enty        CP1252Ext  Comment
  190.     {   0x20AC,  "&#8364;"  },  // "&euro;"    },  // &#128;  #EURO SIGN
  191. //  {   NONUNI,  UNDEFCHAR  },  // "&;"        },  // &#129;  #UNDEFINED
  192.     {   0x201A,  "&#8218;"  },  // "&sbquo;"   },  // &#130;  #SINGLE LOW-9 QUOTATION MARK
  193.     {   0x0192,  "&#0402;"  },  // "&fnof;"    },  // &#131;  #LATIN SMALL LETTER F WITH HOOK
  194.     {   0x201E,  "&#8222;"  },  // "&bdquo;"   },  // &#132;  #DOUBLE LOW-9 QUOTATION MARK
  195.     {   0x2026,  "&#8230;"  },  // "&hellip;"  },  // &#133;  #HORIZONTAL ELLIPSIS
  196.     {   0x2020,  "&#8224;"  },  // "&dagger;"  },  // &#134;  #DAGGER
  197.     {   0x2021,  "&#8225;"  },  // "&Dagger;"  },  // &#135;  #DOUBLE DAGGER
  198.     {   0x02C6,  "&#0710;"  },  // "&circ;"    },  // &#136;  #MODIFIER LETTER CIRCUMFLEX ACCENT
  199.     {   0x2030,  "&#8240;"  },  // "&permil;"  },  // &#137;  #PER MILLE SIGN
  200.     {   0x0160,  "&#0352;"  },  // "&Scaron;"  },  // &#138;  #LATIN CAPITAL LETTER S WITH CARON
  201.     {   0x2039,  "&#8249;"  },  // "&lsaquo;"  },  // &#139;  #SINGLE LEFT-POINTING ANGLE QUOTATION MARK
  202.     {   0x0152,  "&#0338;"  },  // "&OElig;"   },  // &#140;  #LATIN CAPITAL LIGATURE OE
  203. //  {   NONUNI,  UNDEFCHAR  },  // "&;"        },  // &#141;  #UNDEFINED
  204.     {   0x017D,  "&#0381;"  },  // "&;"        },  // &#142;  #LATIN CAPITAL LETTER Z WITH CARON, ***no name entity defined in HTML 4.0***
  205. //  {   NONUNI,  UNDEFCHAR  },  // "&;"        },  // &#143;  #UNDEFINED
  206. //  {   NONUNI,  UNDEFCHAR  },  // "&;"        },  // &#144;  #UNDEFINED
  207.     {   0x2018,  "&#8216;"  },  // "&lsquo;"   },  // &#145;  #LEFT SINGLE QUOTATION MARK
  208.     {   0x2019,  "&#8217;"  },  // "&rsquo;"   },  // &#146;  #RIGHT SINGLE QUOTATION MARK
  209.     {   0x201C,  "&#8220;"  },  // "&ldquo;"   },  // &#147;  #LEFT DOUBLE QUOTATION MARK
  210.     {   0x201D,  "&#8221;"  },  // "&rdquo;"   },  // &#148;  #RIGHT DOUBLE QUOTATION MARK
  211.     {   0x2022,  "&#8226;"  },  // "&bull;"    },  // &#149;  #BULLET
  212.     {   0x2013,  "&#8211;"  },  // "&ndash;"   },  // &#150;  #EN DASH
  213.     {   0x2014,  "&#8212;"  },  // "&mdash;"   },  // &#151;  #EM DASH
  214.     {   0x20DC,  "&#0732;"  },  // "&tilde;"   },  // &#152;  #SMALL TILDE
  215.     {   0x2122,  "&#8482;"  },  // "&trade;"   },  // &#153;  #TRADE MARK SIGN
  216.     {   0x0161,  "&#0353;"  },  // "&scaron;"  },  // &#154;  #LATIN SMALL LETTER S WITH CARON
  217.     {   0x203A,  "&#8250;"  },  // "&rsaquo;"  },  // &#155;  #SINGLE RIGHT-POINTING ANGLE QUOTATION MARK
  218.     {   0x0153,  "&#0339;"  },  // "&oelig;"   },  // &#156;  #LATIN SMALL LIGATURE OE
  219. //  {   NONUNI,  UNDEFCHAR  },  // "&;"        },  // &#157;  #UNDEFINED
  220.     {   0x017E,  "&#0382;"  },  // "&;"        },  // &#158;  #LATIN SMALL LETTER Z WITH CARON, ***no name entity defined in HTML 4.0***
  221.     {   0x0178,  "&#0376;"  },  // "&Yuml;"    },  // &#159;  #LATIN CAPITAL LETTER Y WITH DIAERESIS
  222. };
  223. #endif
  224. HRESULT WINAPI DoConvertINetString(LPDWORD lpdwMode, BOOL fInbound, UINT uCodePage, int nCodeSet, LPCSTR lpSrcStr, LPINT lpnSrcSize, LPSTR lpDestStr, int cchDest, LPINT lpnSize);
  225. /******************************************************************************
  226. *****************************   U T I L I T I E S   ***************************
  227. ******************************************************************************/
  228. void DataByteSwap(LPSTR DataBuf, int len )
  229. {
  230.     int i ;
  231.     UCHAR tmpData ;
  232.     if ( len )
  233.         for ( i = 0 ; i < len-1 ; i+=2 )
  234.         {
  235.             tmpData = DataBuf[i] ;
  236.             DataBuf[i] = DataBuf[i+1] ;
  237.             DataBuf[i+1] = tmpData ;
  238.         }
  239.     return ;
  240. }
  241. void CheckUnicodeDataType(DWORD dwDstEncoding, LPSTR DataBuf, int len )
  242. {
  243.     
  244.     if ( DataBuf && len )
  245.     {
  246.         if ( dwDstEncoding == CP_UCS_2_BE )
  247.             DataByteSwap(DataBuf,len);
  248.     }
  249.     return ;
  250. }
  251. /******************************************************************************
  252. ******************   C O N V E R T   I N E T   S T R I N G   ******************
  253. ******************************************************************************/
  254. HRESULT CICharConverter::UnicodeToMultiByteEncoding(DWORD dwDstEncoding, LPCSTR lpSrcStr, LPINT lpnSrcSize,
  255.     LPSTR lpDstStr, LPINT lpnDstSize, DWORD dwFlag, WCHAR *lpFallBack)
  256. {
  257.     int nBuffSize = 0, i ;
  258.     BOOL UseDefChar = FALSE ;
  259.     LPSTR lpDefFallBack = NULL ;
  260.     UCHAR DefaultCharBuff[3]; // possible DBCS + null    
  261.     HRESULT hr = E_FAIL;
  262.     int _nDstSize = *lpnDstSize;    
  263.     if ( _dwUnicodeEncoding == CP_UCS_2_BE && _cvt_count == 0 )
  264.     {
  265.        if ( _lpUnicodeStr = (LPSTR)LocalAlloc(LPTR, *lpnSrcSize ) )
  266.        {
  267.           MoveMemory(_lpUnicodeStr, lpSrcStr, *lpnSrcSize ) ;
  268.           lpSrcStr = _lpUnicodeStr ;
  269.        }
  270.        else
  271.        {
  272.           hr = E_OUTOFMEMORY;
  273.           goto EXIT;
  274.        }
  275.     }
  276.     CheckUnicodeDataType(_dwUnicodeEncoding, (LPSTR) lpSrcStr, *lpnSrcSize);
  277.     if ( *lpnSrcSize )
  278.         nBuffSize = *lpnSrcSize / sizeof(WCHAR);
  279.     // We force to use MLang NO_BEST_FIT_CHAR check on ISCII encoding since system don't accept default chars
  280.     if (IS_ISCII_CP(dwDstEncoding) && (dwFlag & MLCONVCHARF_USEDEFCHAR))
  281.         dwFlag |= MLCONVCHARF_NOBESTFITCHARS;
  282.     if ( lpFallBack && ( dwFlag & MLCONVCHARF_USEDEFCHAR ))
  283.     {
  284.         // only take SBCS, no DBCS character
  285.         if ( 1 == WideCharToMultiByte(MAPUSERDEF(dwDstEncoding), 0,
  286.                                (LPCWSTR)lpFallBack, 1,
  287.                                (LPSTR)DefaultCharBuff, sizeof(DefaultCharBuff), NULL, NULL ))
  288.             lpDefFallBack = (LPSTR) DefaultCharBuff;        
  289.     }
  290.     if(!(*lpnDstSize = WideCharToMultiByte(MAPUSERDEF(dwDstEncoding), 0,
  291.                                            (LPCWSTR)lpSrcStr, nBuffSize,
  292.                                            lpDstStr, *lpnDstSize, IS_ISCII_CP(dwDstEncoding)? NULL:(LPCSTR)lpDefFallBack, IS_ISCII_CP(dwDstEncoding)? NULL:&UseDefChar)))
  293.     {
  294.         hr = E_FAIL;
  295.         goto EXIT;
  296.     }
  297.     if ( !_cvt_count ) // save SrcSize if it is the first time conversion
  298.         _nSrcSize = nBuffSize * sizeof(WCHAR);
  299.     if (*lpnDstSize)
  300.     {
  301.         if (dwFlag & ( MLCONVCHARF_NCR_ENTITIZE | MLCONVCHARF_NAME_ENTITIZE | MLCONVCHARF_NOBESTFITCHARS ))
  302.         {
  303.             char    *lpDstStrTmp = lpDstStr;
  304.             WCHAR   *lpwStrTmp = NULL;
  305.             WCHAR   *lpwStrTmpSave = NULL;
  306.             char    *lpDstStrTmp2 = NULL;
  307.             char    *lpDstStrTmp2Save = NULL;
  308.             int     cCount, ConvCount = 0, nCount = 0;
  309.             WCHAR   *lpwSrcStrTmp = (WCHAR *)lpSrcStr;
  310.             int     *lpBCharOffset = NULL;
  311.             int     *lpBCharOffsetSave = NULL;
  312.             if (!(lpwStrTmpSave = lpwStrTmp = (WCHAR *)LocalAlloc(LPTR, _nSrcSize)))
  313.             {
  314.                 hr = E_OUTOFMEMORY;
  315.                 goto ENTITIZE_DONE;
  316.             }
  317.             // Make sure we have real converted buffer to check BEST_FIT_CHAR and DEFAULT_CHAR
  318.             if (!_nDstSize)
  319.             {
  320.                 lpDstStrTmp2Save = lpDstStrTmp2 = (char *)LocalAlloc(LPTR, *lpnDstSize);
  321.                 if (lpDstStrTmp2)
  322.                 {
  323.                     WideCharToMultiByte(MAPUSERDEF(dwDstEncoding), 0,
  324.                                (LPCWSTR)lpSrcStr, nBuffSize,
  325.                                lpDstStrTmp2, *lpnDstSize, NULL, NULL );
  326.                 }
  327.                 else
  328.                 {
  329.                     hr = E_OUTOFMEMORY;
  330.                     goto ENTITIZE_DONE;
  331.                 }
  332.             }
  333. //BUGBUG: dest. buffer size is too big
  334.             if (nBuffSize == 
  335.                 MultiByteToWideChar(MAPUSERDEF(dwDstEncoding), 0, _nDstSize? lpDstStr : lpDstStrTmp2, *lpnDstSize, lpwStrTmp, _nSrcSize))
  336.             {
  337.                 // Pre scan to get number of best fit chars.
  338.                 for (i=0; i<nBuffSize; i++)
  339.                 {
  340.                     // make special case for ?(yen sign) in Shift-JIS
  341.                     if (*lpwStrTmp++ != *lpwSrcStrTmp++)
  342.                     {
  343.                         if ((dwDstEncoding == CP_JPN_SJ) && (*(lpwSrcStrTmp - 1) == 0x00A5))
  344.                             *(lpwStrTmp - 1) = 0x00A5;
  345.                         else
  346.                             nCount ++;
  347.                     }
  348.                 }
  349.                 lpwSrcStrTmp -= nBuffSize;
  350.                 lpwStrTmp -= nBuffSize;
  351.                 if (nCount)
  352.                 {
  353.                     int j = 0;
  354.                     if (!(dwFlag & ( MLCONVCHARF_NCR_ENTITIZE | MLCONVCHARF_NAME_ENTITIZE | MLCONVCHARF_USEDEFCHAR)))
  355.                     {
  356.                         hr = E_FAIL;
  357.                         goto ENTITIZE_DONE;
  358.                     }
  359.                     if (!(lpBCharOffsetSave = lpBCharOffset = (int *) LocalAlloc(LPTR, nCount*sizeof(int))))
  360.                     {
  361.                         hr = E_OUTOFMEMORY;
  362.                         goto ENTITIZE_DONE;
  363.                     }
  364.                     // Record the offset position of each best fit char.
  365.                     for (i=0; i<nBuffSize; i++)
  366.                     {
  367.                         if (*lpwStrTmp++ != *lpwSrcStrTmp++)
  368.                         {
  369.                             *lpBCharOffset = i-j;
  370.                             lpBCharOffset++;
  371.                             j = i+1;
  372.                         }
  373.                     }
  374.                     lpBCharOffset -= nCount;
  375.                     lpwSrcStrTmp -= nBuffSize;
  376.                     lpwStrTmp -= nBuffSize;
  377.                     for (i=0; i<nCount; i++)
  378.                     {
  379.                         BOOL bIsSurrogatePair = FALSE;
  380.                         if (*lpBCharOffset)
  381.                         {
  382. //BUGBUG: dest. buffer size is too big
  383.                             cCount = WideCharToMultiByte(MAPUSERDEF(dwDstEncoding), 0,
  384.                                    (LPCWSTR)lpwSrcStrTmp, *lpBCharOffset,
  385.                                    lpDstStrTmp,  _nDstSize ? (*lpBCharOffset)*2 : 0, NULL, NULL );
  386.                             ConvCount += cCount;
  387.                             if (_nDstSize)
  388.                             {
  389.                                 lpDstStrTmp += cCount;
  390.                             }
  391.                             lpwSrcStrTmp += *lpBCharOffset;
  392.                         }
  393.                         BOOL fConverted = FALSE;
  394.                         // check if unconvertable character falls in NAME ENTITY area
  395.                         if (dwFlag & MLCONVCHARF_NAME_ENTITIZE)
  396.                         {
  397.                             // for beta2, make assmption that name entity implys NCR.
  398.                             dwFlag |= MLCONVCHARF_NCR_ENTITIZE;
  399. #ifdef MORE_NAME_ENTITY   // in case we decide do more name entity latter
  400.                             BOOL      fDoNEnty = FALSE;
  401.                             LPCTSTR   lpszNEnty = NULL;
  402.                             // check if character is in the Latin-1 Supplement range
  403.                             if ((*lpwSrcStrTmp >= NAME_ENTITY_OFFSET) && (*lpwSrcStrTmp <= NAME_ENTITY_MAX ))
  404.                             {
  405.                                 fDoNEnty = TRUE;
  406.                                 lpszNEnty = g_lpstrNameEntity[(*lpwSrcStrTmp) - NAME_ENTITY_OFFSET];
  407.                             }
  408.                             // check if character is in the additional name entity table for CP 1252 extension
  409.                             if (!fDoNEnty)
  410.                             {
  411.                                 for (int idx = 0; idx < ARRAYSIZE(aNameEntityExt); idx++)
  412.                                     if (*lpwSrcStrTmp == aNameEntityExt[idx].uwUniCode)
  413.                                     {
  414.                                         fDoNEnty = TRUE;
  415.                                         lpszNEnty = aNameEntityExt[idx].lpszNameEntity;
  416.                                         break;
  417.                                     }
  418.                             }
  419.                             if (fDoNEnty)
  420.                             {
  421.                                 cCount = lstrlenA(lpszNEnty);
  422.                                 if (_nDstSize)
  423.                                 {
  424.                                     CopyMemory(lpDstStrTmp, lpszNEnty, cCount);
  425.                                     lpDstStrTmp += cCount ;
  426.                                 }
  427.                                 ConvCount += cCount;
  428.                                 fConverted = TRUE;
  429.                             }
  430. #else
  431.                             // check if character is in the Latin-1 Supplement range
  432.                             if ((*lpwSrcStrTmp >= NAME_ENTITY_OFFSET)
  433.                                 && (*lpwSrcStrTmp < ARRAYSIZE(g_lpstrNameEntity)+NAME_ENTITY_OFFSET))
  434.                                 
  435.                             {
  436.                                 LPCTSTR   lpszNEnty = NULL;
  437.                                 if (!(lpszNEnty = g_lpstrNameEntity[(*lpwSrcStrTmp) - NAME_ENTITY_OFFSET]))
  438.                                 {
  439. #ifdef DEBUG
  440.                                     AssertMsg((BOOL)FALSE, "Name entity table broken"); 
  441. #endif
  442.                                     hr = E_FAIL;
  443.                                     goto ENTITIZE_DONE;
  444.                                 }
  445.                                     cCount = lstrlenA(lpszNEnty);
  446.                                     if (_nDstSize)
  447.                                     {
  448.                                         CopyMemory(lpDstStrTmp, lpszNEnty, cCount);
  449.                                         lpDstStrTmp += cCount ;
  450.                                     }
  451.                                 
  452.                                 ConvCount += cCount;
  453.                                 fConverted = TRUE;
  454.                             }
  455. #endif
  456.                         }
  457.                         // check if NCR requested
  458.                         if ((!fConverted) && (dwFlag & MLCONVCHARF_NCR_ENTITIZE))
  459.                         {
  460.                             if ((nCount-i >= 2) &&
  461.                                 (*lpwSrcStrTmp >= 0xD800 && *lpwSrcStrTmp <= 0xDBFF) &&
  462.                                 (*(lpwSrcStrTmp+1) >= 0xDC00 && *(lpwSrcStrTmp+1) <= 0xDFFF))
  463.                                 bIsSurrogatePair = TRUE;
  464.                             else
  465.                                 bIsSurrogatePair = FALSE;
  466.                           
  467.                             if (_nDstSize)
  468.                             {
  469.                                 lpDstStrTmp[0] = '&' ;
  470.                                 lpDstStrTmp[1] = '#' ;
  471.                                 lpDstStrTmp += 2 ;
  472.                                 // If it is a Unicode surrogates pair, we convert it to real Unicode value
  473.                                 if (bIsSurrogatePair)
  474.                                 {
  475.                                     DWORD dwUnicode = ((*lpwSrcStrTmp - 0xD800) << 10) + *(lpwSrcStrTmp+1) - 0xDC00 + 0x10000;
  476.                                     _ultoa( dwUnicode, (char*)lpDstStrTmp, 10);
  477.                                 }
  478.                                 else
  479.                                     _ultoa( *lpwSrcStrTmp, (char*)lpDstStrTmp, 10);
  480.                                 cCount = lstrlenA(lpDstStrTmp);
  481.                                 lpDstStrTmp += cCount;
  482.                                 ConvCount += cCount;
  483.                                 *(lpDstStrTmp++) = ';' ;
  484.                             }
  485.                             else
  486.                             {
  487.                                 char szTmpString[10];
  488.                                 if (bIsSurrogatePair)
  489.                                 {
  490.                                     DWORD dwUnicode = ((*lpwSrcStrTmp - 0xD800) << 10) + *(lpwSrcStrTmp+1) - 0xDC00 + 0x10000;
  491.                                     _ultoa( dwUnicode, szTmpString, 10);
  492.                                 }
  493.                                 else
  494.                                     _ultoa( *lpwSrcStrTmp, szTmpString, 10);
  495.                                 ConvCount += lstrlenA(szTmpString);
  496.                             }
  497.                         
  498.                             fConverted = TRUE;
  499.                             ConvCount += 3;                    
  500.                         }
  501.                         // handle MLCONVCHARF_USEDEFCHAR here - less priority and default method
  502.                         if (!fConverted)
  503.                         {
  504.                             if (_nDstSize)
  505.                             {
  506.                                 *lpDstStrTmp = lpDefFallBack ? *lpDefFallBack : '?';
  507.                                 lpDstStrTmp++;
  508.                             }
  509.                             ConvCount++;
  510.                             if (!UseDefChar)
  511.                                 UseDefChar = TRUE;
  512.                         }
  513.                         lpBCharOffset++;
  514.                         lpwSrcStrTmp++;
  515.                         // Skip next character if it is a Unicode surrogates pair
  516.                         if (bIsSurrogatePair)
  517.                         {
  518.                             lpBCharOffset++;
  519.                             lpwSrcStrTmp++;
  520.                             i++;
  521.                         }
  522.                     }
  523.                     lpBCharOffset -= nCount ;
  524.                 }
  525.                 int nRemain = (*lpnSrcSize - (int)((char*)lpwSrcStrTmp - (char *)lpSrcStr))/sizeof(WCHAR);
  526. //BUGBUG: dest. buffer size is too big
  527.                 ConvCount += WideCharToMultiByte(MAPUSERDEF(dwDstEncoding), 0,
  528.                                    (LPCWSTR)lpwSrcStrTmp, nRemain,
  529.                                    lpDstStrTmp, _nDstSize ? nRemain*2 : 0, NULL, NULL );
  530.                 *lpnDstSize = ConvCount ;
  531.                 hr = S_OK;
  532.             } 
  533.             else
  534.             {
  535.                 hr = E_FAIL;
  536.             }
  537. ENTITIZE_DONE:
  538.             if (lpwStrTmpSave)
  539.                 LocalFree(lpwStrTmpSave);
  540.             if (lpDstStrTmp2Save)
  541.                 LocalFree(lpDstStrTmp2Save);
  542.             if (lpBCharOffsetSave)
  543.                 LocalFree(lpBCharOffsetSave);
  544.         }
  545.         else
  546.         {
  547.             hr = S_OK;
  548.         }       
  549.         if (S_OK == hr && UseDefChar)
  550.             hr = S_FALSE;
  551.     }
  552.     else
  553.     {
  554.         hr = E_FAIL;
  555.     }
  556. EXIT:
  557.     return hr;
  558. }
  559. HRESULT CICharConverter::UTF78ToUnicode(LPDWORD lpdwMode, LPCSTR lpSrcStr, LPINT lpnSrcSize,
  560.     LPSTR lpDstStr, LPINT lpnDstSize)
  561. {
  562.     HRESULT hr ;
  563.     hr = DoConvertINetString(lpdwMode, TRUE, CP_UCS_2, _dwUTFEncoding, lpSrcStr, lpnSrcSize, lpDstStr, *lpnDstSize, lpnDstSize);
  564.     if ( !_cvt_count ) // save SrcSize if it is the first time conversion
  565.         _nSrcSize = *lpnSrcSize ;
  566.     CheckUnicodeDataType(_dwUnicodeEncoding, lpDstStr, *lpnDstSize);
  567.     return hr ;
  568. }
  569. HRESULT CICharConverter::UnicodeToUTF78(LPDWORD lpdwMode, LPCSTR lpSrcStr, LPINT lpnSrcSize,
  570.     LPSTR lpDstStr, LPINT lpnDstSize)
  571. {
  572.     HRESULT hr ;
  573.     if ( _dwUnicodeEncoding == CP_UCS_2_BE && _cvt_count == 0 )
  574.     {
  575.        if ( _lpUnicodeStr = (LPSTR)LocalAlloc(LPTR, *lpnSrcSize ) )
  576.        {
  577.           MoveMemory(_lpUnicodeStr, lpSrcStr, *lpnSrcSize ) ;
  578.           lpSrcStr = _lpUnicodeStr ;
  579.        }
  580.        else
  581.         return E_OUTOFMEMORY ;
  582.     }
  583.     CheckUnicodeDataType(_dwUnicodeEncoding, (LPSTR) lpSrcStr, *lpnSrcSize);
  584.     hr = DoConvertINetString(lpdwMode, FALSE, CP_UCS_2, _dwUTFEncoding, lpSrcStr, lpnSrcSize, lpDstStr, *lpnDstSize, lpnDstSize);
  585.     if ( !_cvt_count ) // save SrcSize if it is the first time conversion
  586.         _nSrcSize = *lpnSrcSize ;
  587.     return hr ;
  588. }
  589. HRESULT CICharConverter::UnicodeToWindowsCodePage(LPCSTR lpSrcStr, LPINT lpnSrcSize,
  590.     LPSTR lpDstStr, LPINT lpnDstSize, DWORD dwFlag, WCHAR *lpFallBack)
  591. {
  592.     HRESULT hr ;
  593.     hr = UnicodeToMultiByteEncoding(_dwWinCodePage,lpSrcStr,lpnSrcSize,lpDstStr,lpnDstSize,dwFlag,lpFallBack);
  594.     return hr ;
  595. }
  596. HRESULT CICharConverter::UnicodeToInternetEncoding(LPCSTR lpSrcStr, LPINT lpnSrcSize,
  597.     LPSTR lpDstStr, LPINT lpnDstSize, DWORD dwFlag, WCHAR *lpFallBack)
  598. {
  599.     HRESULT hr ;
  600.     hr = UnicodeToMultiByteEncoding(_dwInternetEncoding,lpSrcStr,lpnSrcSize,lpDstStr,lpnDstSize,dwFlag,lpFallBack);
  601.     return hr ;
  602. }
  603. HRESULT CICharConverter::InternetEncodingToUnicode(LPCSTR lpSrcStr, LPINT lpnSrcSize,
  604.     LPSTR lpDstStr, LPINT lpnDstSize)
  605. {
  606.     int cch = 0 ;
  607.     int cb = *lpnSrcSize;
  608.     if ( !_cvt_count )
  609.     {
  610.         // If we have a multibyte character encoding, we are at risk of splitting
  611.         // some characters at the read boundary.  We must Make sure we have a
  612.         // discrete number of characters first.
  613.         UINT uMax = MAX_CHAR_SIZE ;
  614.         cb++; // pre-increment
  615.         do
  616.         {
  617.             cch = MultiByteToWideChar( MAPUSERDEF(_dwInternetEncoding),
  618.                                         MB_ERR_INVALID_CHARS | MB_PRECOMPOSED,
  619.                                         lpSrcStr, --cb,
  620.                                         NULL, 0 );
  621.             --uMax;
  622.         } while (!cch && uMax && cb);
  623.     }
  624.     if ( cb == (*lpnSrcSize - MAX_CHAR_SIZE +1 ))  // if conversion problem isn't at the end of the string
  625.         cb = *lpnSrcSize ; // restore orginal value
  626.     *lpnDstSize = MultiByteToWideChar( MAPUSERDEF(_dwInternetEncoding), 0,
  627.                                lpSrcStr, cb,
  628.                                (LPWSTR)lpDstStr, *lpnDstSize/sizeof(WCHAR) );
  629.     *lpnDstSize = *lpnDstSize * sizeof(WCHAR);
  630.     if ( !_cvt_count ) // save SrcSize if it is the first time conversion
  631.         _nSrcSize = cb ;
  632.     CheckUnicodeDataType(_dwUnicodeEncoding, lpDstStr, *lpnDstSize);
  633.     if (*lpnDstSize==0 && cb)
  634.         return E_FAIL ;
  635.     else
  636.         return S_OK ;
  637. }
  638. HRESULT CICharConverter::WindowsCodePageToUnicode(LPCSTR lpSrcStr, LPINT lpnSrcSize,
  639.     LPSTR lpDstStr, LPINT lpnDstSize)
  640. {
  641.     int cch = 0 ;
  642.     int cb = *lpnSrcSize;
  643.     if ( !_cvt_count )
  644.     {
  645.         UINT uMax = MAX_CHAR_SIZE ;
  646.         cb++; // pre-increment
  647.         do
  648.         {
  649.             cch = MultiByteToWideChar( MAPUSERDEF(_dwWinCodePage),
  650.                                         MB_ERR_INVALID_CHARS | MB_PRECOMPOSED,
  651.                                         lpSrcStr, --cb,
  652.                                         NULL, 0 );
  653.             --uMax;
  654.         } while (!cch && uMax && cb);
  655.     }
  656.     if ( cb == (*lpnSrcSize - MAX_CHAR_SIZE +1 ))  // if conversion problem isn't at the end of the string
  657.         cb = *lpnSrcSize ; // restore orginal value
  658.     *lpnDstSize = MultiByteToWideChar( MAPUSERDEF(_dwWinCodePage), 0,
  659.                                lpSrcStr, cb,
  660.                                (LPWSTR)lpDstStr, *lpnDstSize/sizeof(WCHAR) );
  661.     *lpnDstSize = *lpnDstSize * sizeof(WCHAR);
  662.     if ( !_cvt_count ) // save SrcSize if it is the first time conversion
  663.         _nSrcSize = cb ;
  664.     CheckUnicodeDataType(_dwUnicodeEncoding, lpDstStr, *lpnDstSize);
  665.     if (*lpnDstSize==0 && cb)
  666.         return E_FAIL ;
  667.     else
  668.         return S_OK ;
  669. }
  670. HRESULT CICharConverter::WindowsCodePageToInternetEncoding(LPDWORD lpdwMode, LPCSTR lpSrcStr, LPINT lpnSrcSize,
  671.     LPSTR lpDstStr, LPINT lpnDstSize, DWORD dwFlag, WCHAR *lpFallBack)
  672. {
  673.     HRESULT hr ;
  674.     // check if the conversion should go through Unicode indirectly
  675.     if ( _dwConvertType & 0x10 )
  676.         hr = WindowsCodePageToInternetEncodingWrap(lpSrcStr, lpnSrcSize, lpDstStr, lpnDstSize, dwFlag, lpFallBack);
  677.     else
  678.     {
  679.         hr = DoConvertINetString(lpdwMode, FALSE, _dwWinCodePage, _dwInternetEncoding, lpSrcStr, lpnSrcSize, lpDstStr, *lpnDstSize, lpnDstSize);
  680.         if ( !_cvt_count ) // save SrcSize if it is the first time conversion
  681.             _nSrcSize = *lpnSrcSize ;
  682.     }
  683.     return hr ;
  684. }
  685. HRESULT CICharConverter::InternetEncodingToWindowsCodePage(LPDWORD lpdwMode, LPCSTR lpSrcStr, LPINT lpnSrcSize,
  686.     LPSTR lpDstStr, LPINT lpnDstSize, DWORD dwFlag, WCHAR *lpFallBack)
  687. {
  688.     HRESULT hr ;
  689.     // check if the conversion should go through Unicode indirectly
  690.     if ( _dwConvertType & 0x10 )
  691.         hr = InternetEncodingToWindowsCodePageWrap(lpSrcStr, lpnSrcSize, lpDstStr, lpnDstSize, dwFlag, lpFallBack);
  692.     else
  693.     {
  694.         hr = DoConvertINetString(lpdwMode, TRUE, _dwWinCodePage, _dwInternetEncoding, lpSrcStr, lpnSrcSize, lpDstStr, *lpnDstSize, lpnDstSize);
  695.         if ( !_cvt_count ) // save SrcSize if it is the first time conversion
  696.             _nSrcSize = *lpnSrcSize ;
  697.     }
  698.     return hr ;
  699. }
  700. HRESULT CICharConverter::WindowsCodePageToInternetEncodingWrap(LPCSTR lpSrcStr, LPINT lpnSrcSize,
  701.     LPSTR lpDstStr, LPINT lpnDstSize, DWORD dwFlag, WCHAR *lpFallBack)
  702. {
  703.     int nBuffSize = 0 ;
  704.     int cb = *lpnSrcSize;
  705.     UINT uMax = MAX_CHAR_SIZE ;
  706.     BOOL UseDefChar = FALSE ;
  707.     HRESULT hr = S_OK;
  708.     if ( !_cvt_count )
  709.     {
  710.         cb++; // pre-increment
  711.         do
  712.         {
  713.             nBuffSize = MultiByteToWideChar( MAPUSERDEF(_dwWinCodePage),
  714.                                         MB_ERR_INVALID_CHARS | MB_PRECOMPOSED,
  715.                                         lpSrcStr, --cb,
  716.                                         NULL, 0 );
  717.             --uMax;
  718.         } while (!nBuffSize && uMax && cb);
  719.     }
  720.     if ( cb == (*lpnSrcSize - MAX_CHAR_SIZE +1 ))  // if conversion problem isn't at the end of the string
  721.         cb = *lpnSrcSize ; // restore orginal value
  722.     if (!nBuffSize)  // in case there are illeage characters
  723.         nBuffSize = cb ;
  724.     if ( _lpInterm1Str = (LPSTR) LocalAlloc(LPTR, (nBuffSize * sizeof(WCHAR))))
  725.     {
  726.         nBuffSize = MultiByteToWideChar(MAPUSERDEF(_dwWinCodePage), 0,
  727.                         lpSrcStr, cb, (LPWSTR)_lpInterm1Str, nBuffSize );
  728.         int iSrcSizeTmp = nBuffSize * sizeof(WCHAR);
  729.         hr = UnicodeToMultiByteEncoding(MAPUSERDEF(_dwInternetEncoding), (LPCSTR)_lpInterm1Str, &iSrcSizeTmp,
  730.                                         lpDstStr, lpnDstSize, dwFlag, lpFallBack);
  731. //        *lpnDstSize = WideCharToMultiByte( MAPUSERDEF(_dwInternetEncoding), 0,
  732. //                        (LPCWSTR)_lpInterm1Str, nBuffSize, lpDstStr, *lpnDstSize, NULL, &UseDefChar );
  733.         if ( !_cvt_count ) // save SrcSize if it is the first time conversion
  734.             _nSrcSize = cb ;
  735.     }
  736.     else        
  737.         hr = E_FAIL;
  738.     if (hr == S_OK)
  739.     {
  740.         if (*lpnDstSize==0 && cb)
  741.             hr = E_FAIL ;
  742.         else 
  743.         {
  744.             if ( UseDefChar )
  745.                 return S_FALSE ;
  746.             else
  747.                 return S_OK ;
  748.         }
  749.     }
  750.     return hr;
  751. }
  752. HRESULT CICharConverter::InternetEncodingToWindowsCodePageWrap(LPCSTR lpSrcStr, LPINT lpnSrcSize,
  753.     LPSTR lpDstStr, LPINT lpnDstSize, DWORD dwFlag, WCHAR *lpFallBack)
  754. {
  755.     int nBuffSize = 0 ;
  756.     int cb = *lpnSrcSize;
  757.     UINT uMax = MAX_CHAR_SIZE ;
  758.     BOOL UseDefChar = FALSE ;
  759.     HRESULT hr = S_OK;
  760.     if ( !_cvt_count )
  761.     {
  762.         cb++; // pre-increment
  763.         do
  764.         {
  765.             nBuffSize = MultiByteToWideChar( MAPUSERDEF(_dwInternetEncoding),
  766.                                         MB_ERR_INVALID_CHARS | MB_PRECOMPOSED,
  767.                                         lpSrcStr, --cb,
  768.                                         NULL, 0 );
  769.             --uMax;
  770.         } while (!nBuffSize && uMax && cb);
  771.     }
  772.     if ( cb == (*lpnSrcSize - MAX_CHAR_SIZE +1 ))  // if conversion problem isn't at the end of the string
  773.         cb = *lpnSrcSize ; // restore orginal value
  774.     if (!nBuffSize)  // in case there are illeage characters
  775.         nBuffSize = cb ;
  776.     if ( _lpInterm1Str = (LPSTR) LocalAlloc(LPTR,nBuffSize * sizeof (WCHAR) ))
  777.     {
  778.         nBuffSize = MultiByteToWideChar( MAPUSERDEF(_dwInternetEncoding), 0,
  779.                         lpSrcStr, cb, (LPWSTR)_lpInterm1Str, nBuffSize );
  780.         int iSrcSizeTmp = nBuffSize * sizeof(WCHAR);
  781.         hr = UnicodeToMultiByteEncoding(MAPUSERDEF(_dwWinCodePage), (LPCSTR)_lpInterm1Str, &iSrcSizeTmp,
  782.                                         lpDstStr, lpnDstSize, dwFlag, lpFallBack);
  783. //        *lpnDstSize = WideCharToMultiByte( MAPUSERDEF(_dwWinCodePage), 0,
  784. //                        (LPCWSTR)_lpInterm1Str, nBuffSize, lpDstStr, *lpnDstSize, NULL, &UseDefChar );
  785.         if ( !_cvt_count ) // save SrcSize if it is the first time conversion
  786.             _nSrcSize = cb ;
  787.     }
  788.     else
  789.         hr = E_FAIL;
  790.     if (hr == S_OK)
  791.     {
  792.         if (*lpnDstSize==0 && cb)
  793.             hr = E_FAIL ;
  794.         else 
  795.         {
  796.             if ( UseDefChar )
  797.                 return S_FALSE ;
  798.             else
  799.                 return S_OK ;
  800.         }
  801.     }
  802.     return hr;
  803. }
  804. HRESULT CICharConverter::ConvertIWUU(LPDWORD lpdwMode, LPCSTR lpSrcStr, LPINT lpnSrcSize,
  805.     LPSTR lpDstStr, LPINT lpnDstSize, DWORD dwFlag, WCHAR *lpFallBack)
  806. {
  807.     int nBuffSize = 0 ;
  808.     HRESULT hr = S_OK ;
  809.     HRESULT hrWarnings = S_OK ;
  810.     // InternetEncodingToWindowsCodePage
  811.     if ( _dwConvertType % 2 && _dwConvertType < 21 ) /* start from Internet Encoding */
  812.     {
  813.         if ( _dwConvertType == 5 || _dwConvertType == 9 ) /* use interm buffer */
  814.         {
  815.             hr = InternetEncodingToWindowsCodePage(lpdwMode, lpSrcStr, lpnSrcSize, NULL, &nBuffSize, dwFlag, lpFallBack);
  816.             if ( _lpInterm1Str = (LPSTR) LocalAlloc(LPTR,nBuffSize) )
  817.             {
  818.                 hr = InternetEncodingToWindowsCodePage(lpdwMode, lpSrcStr, lpnSrcSize, _lpInterm1Str, &nBuffSize, dwFlag, lpFallBack);
  819.                 lpSrcStr = _lpInterm1Str ;
  820.                 *lpnSrcSize = nBuffSize ;
  821.             }
  822.             else
  823.                 goto fail ;
  824.         }
  825.         else
  826.             hr = InternetEncodingToWindowsCodePage(lpdwMode, lpSrcStr, lpnSrcSize, lpDstStr, lpnDstSize, dwFlag, lpFallBack);
  827.         _cvt_count ++ ;
  828.     }
  829.     if ( hr != S_OK )
  830.         hrWarnings = hr ;
  831.         
  832.     // WindowsCodePageToUnicode or InternetEncodingToUnicode
  833.     if ( _dwConvertType == 21 || _dwConvertType == 25 )
  834.     {
  835.         if ( _dwConvertType == 21 )
  836.             hr = InternetEncodingToUnicode(lpSrcStr, lpnSrcSize, lpDstStr, lpnDstSize);
  837.         else // _dwConvertType == 25 
  838.         {
  839.             hr = InternetEncodingToUnicode(lpSrcStr, lpnSrcSize, NULL, &nBuffSize);
  840.             if ( _lpInterm1Str= (LPSTR)LocalAlloc(LPTR, nBuffSize) )
  841.             {
  842.                 hr = InternetEncodingToUnicode(lpSrcStr, lpnSrcSize, _lpInterm1Str, &nBuffSize);
  843.                 lpSrcStr = _lpInterm1Str ;
  844.                 *lpnSrcSize = nBuffSize ;
  845.             }
  846.             else
  847.                 goto fail ;
  848.         }
  849.         _cvt_count ++ ;
  850.     }
  851.     else if ( _dwConvertType >= 4 && _dwConvertType <= 10 )
  852.     {
  853.         if ( _dwConvertType > 8 )
  854.         {
  855.             nBuffSize = 0 ;
  856.             hr = WindowsCodePageToUnicode(lpSrcStr, lpnSrcSize, NULL, &nBuffSize);
  857.             if ( _cvt_count )
  858.             {
  859.                 if ( _lpInterm2Str= (LPSTR)LocalAlloc(LPTR, nBuffSize) )
  860.                 {
  861.                     hr = WindowsCodePageToUnicode(lpSrcStr, lpnSrcSize, _lpInterm2Str, &nBuffSize);
  862.                     lpSrcStr = _lpInterm2Str ;
  863.                     *lpnSrcSize = nBuffSize ;
  864.                 }
  865.                 else
  866.                     goto fail ;
  867.             }
  868.             else
  869.             {
  870.                 if ( _lpInterm1Str= (LPSTR)LocalAlloc(LPTR, nBuffSize) )
  871.                 {
  872.                     hr = WindowsCodePageToUnicode(lpSrcStr, lpnSrcSize, _lpInterm1Str, &nBuffSize);
  873.                     lpSrcStr = _lpInterm1Str ;
  874.                     *lpnSrcSize = nBuffSize ;
  875.                 }
  876.                 else
  877.                     goto fail ;
  878.             }
  879.         }
  880.         else
  881.             hr = WindowsCodePageToUnicode(lpSrcStr, lpnSrcSize, lpDstStr, lpnDstSize);
  882.         _cvt_count ++ ;
  883.     }
  884.     if ( hr != S_OK )
  885.         hrWarnings = hr ;
  886.     // UnicodeToUTF78
  887.     if ( _dwConvertType & 0x08 )
  888. #ifndef UNIX
  889.         hr = UnicodeToUTF78(lpdwMode, lpSrcStr, lpnSrcSize, lpDstStr, lpnDstSize);
  890. #else
  891.         {
  892.         /* we now hack the lpSrcStr to be the same as 2 byte Unicode so mlang
  893.          * lowlevel code can work right.
  894.          */
  895.         LPWSTR lpwSrcStr = (LPWSTR)lpSrcStr;
  896.         INT tmpSize = *lpnSrcSize/sizeof(WCHAR);
  897.         UCHAR *pTmp = new UCHAR[(tmpSize+1)*2];
  898.         if(pTmp) {
  899.             for(int i = 0; i < tmpSize; i++) {
  900.                 pTmp[i*2] = *lpwSrcStr++;
  901.                 pTmp[i*2+1] = 0x00;
  902.             }
  903.             pTmp[i*2] = pTmp[i*2+1] = 0x00;
  904.             tmpSize *= 2;
  905.             hr = UnicodeToUTF78(lpdwMode, (LPCSTR)pTmp, &tmpSize, lpDstStr, lpnDstSize);
  906.         }
  907.         else
  908.             hr = E_FAIL;
  909.         delete [] pTmp;
  910.         }
  911. #endif /* UNIX */
  912.     return ( hr == S_OK ? hrWarnings : hr ) ;
  913. fail :
  914.     return E_FAIL ;
  915. }
  916. HRESULT CICharConverter::ConvertUUWI(LPDWORD lpdwMode, LPCSTR lpSrcStr, LPINT lpnSrcSize,
  917.     LPSTR lpDstStr, LPINT lpnDstSize, DWORD dwFlag, WCHAR *lpFallBack)
  918. {
  919.     int nBuffSize = 0 ;
  920.     HRESULT hr = S_OK ;
  921.     HRESULT hrWarnings = S_OK ;
  922.     // UTF78ToUnicode
  923.     if ( _dwConvertType & 0x08 )
  924.     {
  925.         if ( _dwConvertType == 12 ) /* convert UTF78 -> Unicode only */
  926.             hr = UTF78ToUnicode(lpdwMode, lpSrcStr, lpnSrcSize, lpDstStr, lpnDstSize);
  927.         else /* use interm buffer, type = 10 or 9 */
  928.         {
  929.             hr = UTF78ToUnicode(lpdwMode, lpSrcStr, lpnSrcSize, NULL, &nBuffSize);
  930.             if ( _lpInterm1Str= (LPSTR)LocalAlloc(LPTR, nBuffSize) )
  931.             {
  932.                 hr = UTF78ToUnicode(lpdwMode, lpSrcStr, lpnSrcSize, _lpInterm1Str, &nBuffSize);
  933.                 lpSrcStr = _lpInterm1Str ;
  934.                 *lpnSrcSize = nBuffSize ;
  935.             }
  936.             else
  937.                 goto fail ;
  938.         }
  939.         _cvt_count ++ ;
  940.     }
  941.     if ( hr != S_OK )
  942.         hrWarnings = hr ;
  943.     // UnicodeToWindowsCodePage or UnicodeToInternetEncoding
  944.     if ( _dwConvertType == 21 || _dwConvertType == 25 )
  945.     {
  946.         hr = UnicodeToInternetEncoding(lpSrcStr, lpnSrcSize, lpDstStr, lpnDstSize, dwFlag, lpFallBack);
  947.         _cvt_count ++ ;
  948.     }
  949.     else if ( _dwConvertType >= 4 && _dwConvertType <= 10 )
  950.     {
  951.         if ( _dwConvertType % 2 ) /* use interm buffer */
  952.         {
  953.             nBuffSize = 0 ;
  954.             hr = UnicodeToWindowsCodePage(lpSrcStr, lpnSrcSize, NULL, &nBuffSize, dwFlag, lpFallBack);
  955.             if ( _cvt_count )
  956.             {
  957.                 if ( _lpInterm2Str= (LPSTR)LocalAlloc(LPTR, nBuffSize) )
  958.                 {
  959.                     hr = UnicodeToWindowsCodePage(lpSrcStr, lpnSrcSize, _lpInterm2Str, &nBuffSize, dwFlag, lpFallBack);
  960.                     lpSrcStr = _lpInterm2Str ;
  961.                     *lpnSrcSize = nBuffSize ;
  962.                 }
  963.                 else
  964.                     goto fail ;
  965.             }
  966.             else
  967.             {
  968.                 if ( _lpInterm1Str= (LPSTR)LocalAlloc(LPTR, nBuffSize) )
  969.                 {
  970.                     hr = UnicodeToWindowsCodePage(lpSrcStr, lpnSrcSize, _lpInterm1Str, &nBuffSize, dwFlag, lpFallBack);
  971.                     lpSrcStr = _lpInterm1Str ;
  972.                     *lpnSrcSize = nBuffSize ;
  973.                 }
  974.                 else
  975.                     goto fail ;
  976.             }
  977.         }
  978.         else
  979.             hr = UnicodeToWindowsCodePage(lpSrcStr, lpnSrcSize, lpDstStr, lpnDstSize, dwFlag, lpFallBack);
  980.         _cvt_count ++ ;
  981.     }
  982.     if ( hr != S_OK )
  983.         hrWarnings = hr ;
  984.     // WindowsCodePageToInternetEncoding
  985.     if ( _dwConvertType % 2 && _dwConvertType < 21 )
  986.         hr = WindowsCodePageToInternetEncoding(lpdwMode, lpSrcStr, lpnSrcSize, lpDstStr, lpnDstSize, dwFlag, lpFallBack);
  987.     return ( hr == S_OK ? hrWarnings : hr ) ;
  988. fail :
  989.     return E_FAIL ;
  990. }
  991. #if 0
  992. struct CODEPAGEINFO
  993. {
  994.     UINT        uCodePage ;
  995.     CP_STATE    nCP_State ;    // whether this is a valid windows codepage  ?
  996. };
  997. // ValidCodepageInfo is used to cache whether a codepage is a vaild code
  998. // It uses circular-FIFO cache algorithm
  999. #define MAX_CP_CACHE    32
  1000. static int cp_cache_count = 0 ;
  1001. static int cp_cache_ptr = 0 ;
  1002. static struct CODEPAGEINFO ValidCodepageInfo[MAX_CP_CACHE];
  1003. // ValidCodepageInfo is used to cache whether a codepage is a vaild codepage
  1004. // It uses circular-FIFO cache algorithm
  1005. BOOL CheckIsValidCodePage (UINT uCodePage)
  1006. {
  1007.     if ( uCodePage == 50000 ) // User defined
  1008.         return TRUE ;
  1009.     int i ;
  1010.     BOOL bRet ;
  1011.     for ( i = 0 ; i < cp_cache_count ; i++ )
  1012.     {
  1013.         if ( uCodePage == ValidCodepageInfo[i].uCodePage )
  1014.         {
  1015.             if ( ValidCodepageInfo[i].nCP_State == VALID_CP )
  1016.                 return TRUE ;
  1017.             else
  1018.                 return FALSE ;
  1019.         }
  1020.     }
  1021.     // not found, call IsValidCodePage and cache the return value
  1022.     bRet = IsValidCodePage(uCodePage);
  1023.     EnterCriticalSection(&g_cs);
  1024.     ValidCodepageInfo[cp_cache_ptr].uCodePage = uCodePage ;
  1025.     if (bRet)
  1026.         ValidCodepageInfo[cp_cache_ptr].nCP_State = VALID_CP ;
  1027.     else
  1028.         ValidCodepageInfo[cp_cache_ptr].nCP_State = INVALID_CP ;
  1029.     if ( cp_cache_count < MAX_CP_CACHE )
  1030.         cp_cache_count++ ;
  1031.     cp_cache_ptr = ( ++cp_cache_ptr ) % MAX_CP_CACHE ;
  1032.     LeaveCriticalSection(&g_cs);
  1033.     return bRet ;
  1034. }
  1035. #endif
  1036. /*
  1037.     Conversion Flag:
  1038.     Bit 7 - Convert Direction.
  1039.     Bit 4 (16) - Unicode <-> Internet Encoding
  1040.     Bit 3 (8) - UTF8, UTF7
  1041.     Bit 2 (4) - Unicode
  1042.     Bit 1 (2) - Windows CodePage
  1043.     Bit 0 (1) - Internet Encoding
  1044.     12, 6, 3 (19) - one step convert
  1045.     10, 5 (21)  - two steps convert
  1046.     9 (25) - three steps convert
  1047. */
  1048. int GetWindowsEncodingIndex(DWORD dwEncoding)
  1049. {
  1050.     int nr = sizeof (aEncodingInfo) / sizeof(ENCODINGINFO) ;
  1051.     int i, half = nr / 2, index = -1 ;
  1052.     if (aEncodingInfo[half].dwEncoding > dwEncoding )
  1053.     {
  1054.         for ( i = 0 ; i < half ; i++ )
  1055.             if (aEncodingInfo[i].dwEncoding == dwEncoding )
  1056.                 index = i ;
  1057.     }
  1058.     else if (aEncodingInfo[half].dwEncoding < dwEncoding )
  1059.     {
  1060.         for ( i = half + 1 ; i < nr ; i++ )
  1061.             if (aEncodingInfo[i].dwEncoding == dwEncoding )
  1062.                 index = i ;
  1063.     }
  1064.     else
  1065.         index = half ;
  1066.     if (index>=0) // found
  1067.     {
  1068.         if ( aEncodingInfo[index].nCP_State != VALID_CP &&
  1069.                 aEncodingInfo[index].dwCodePage )
  1070.         {
  1071.             if ( aEncodingInfo[index].dwCodePage == 50000 || IsValidCodePage(aEncodingInfo[index].dwCodePage ) ) // 50000 means user defined
  1072.                 aEncodingInfo[index].nCP_State = VALID_CP ;
  1073.             else
  1074.                 aEncodingInfo[index].nCP_State = INVALID_CP ;
  1075.             if ((aEncodingInfo[index].nCP_State == VALID_CP) &&
  1076.                 (aEncodingInfo[index].dwFlags & CONV_CHK_NLS) &&
  1077.                 !IsValidCodePage(aEncodingInfo[index].dwEncoding))
  1078.                 aEncodingInfo[index].nCP_State = INVALID_CP ;
  1079.         }
  1080.     }
  1081.     return index ;
  1082. }
  1083. HRESULT CICharConverter::ConvertSetup(DWORD dwSrcEncoding, DWORD dwDstEncoding)
  1084. {
  1085.     DWORD SrcFlag = 0, DstFlag = 0 ;
  1086.     int index, unknown = 0 ;
  1087.     /* check source & destination encoding type */
  1088.     index = GetWindowsEncodingIndex(dwSrcEncoding);
  1089.     if ( index >=0 )
  1090.     {
  1091.         SrcFlag = (DWORD) aEncodingInfo[index].bTypeUUIW ;
  1092.         if ( aEncodingInfo[index].dwCodePage )
  1093.         {
  1094.             _dwWinCodePage = (DWORD) aEncodingInfo[index].dwCodePage ;
  1095.             if (aEncodingInfo[index].nCP_State == INVALID_CP )
  1096.                 goto fail ;
  1097.         }
  1098.         if ( SrcFlag & 0x08 )
  1099.             _dwUTFEncoding = dwSrcEncoding ;
  1100.         if ( SrcFlag & 0x01 )
  1101.             _dwInternetEncoding = dwSrcEncoding ;
  1102.         if ( SrcFlag & 0x04 )
  1103.             _dwUnicodeEncoding = dwSrcEncoding ;
  1104.     }
  1105.     // assume it is a unknown Window Codepage
  1106.     else
  1107.     {
  1108.         if ( !CONVERT_IS_VALIDCODEPAGE(dwSrcEncoding))
  1109.             goto fail ;
  1110.         SrcFlag = 0x02 ;
  1111.         _dwWinCodePage = dwSrcEncoding ;
  1112.         unknown ++ ;
  1113.     }
  1114.     index = GetWindowsEncodingIndex(dwDstEncoding);
  1115.     if ( index >=0 )
  1116.     {
  1117.         // check if two codepages are compatiable
  1118.         if ( _dwWinCodePage && aEncodingInfo[index].dwCodePage )
  1119.         {
  1120.             if (_dwWinCodePage != (DWORD) aEncodingInfo[index].dwCodePage )
  1121.                 goto fail ;
  1122.         }
  1123.         DstFlag = (DWORD) aEncodingInfo[index].bTypeUUIW ;
  1124.         if ( aEncodingInfo[index].dwCodePage )
  1125.         {
  1126.             _dwWinCodePage = (DWORD) aEncodingInfo[index].dwCodePage ;
  1127.             if (aEncodingInfo[index].nCP_State == INVALID_CP )
  1128.                 goto fail ;
  1129.         }
  1130.         if ( DstFlag & 0x08 )
  1131.             _dwUTFEncoding = dwDstEncoding ;
  1132.         if ( DstFlag & 0x01 )
  1133.             _dwInternetEncoding = dwDstEncoding ;
  1134.         if ( DstFlag & 0x04 )
  1135.             _dwUnicodeEncoding = dwDstEncoding ;
  1136.     }
  1137.     // 1) First time unknown, assume it is a unknown Window Codepage
  1138.     //    the conversion become UTF78 <-> Unicode <-> Window Codepage
  1139.     // 2) Second time unknown, assume it is a unknown Internet Encoding
  1140.     //    the conversion become Windows Codepage <-> Unicode <-> Internet Encoding
  1141.     else
  1142.     {
  1143.         if ( !CONVERT_IS_VALIDCODEPAGE(dwDstEncoding))
  1144.             goto fail ;
  1145.         if ( unknown == 0 )
  1146.         {
  1147.             if ( _dwWinCodePage )
  1148.             {
  1149.                 if (_dwWinCodePage != dwDstEncoding )
  1150.                     goto fail ;
  1151.             }
  1152.             DstFlag = 0x02 ;
  1153.             _dwWinCodePage = dwDstEncoding ;
  1154.         }
  1155.         else
  1156.         {
  1157.             DstFlag = 0x11 ;
  1158.             _dwInternetEncoding = dwDstEncoding ;
  1159.         }
  1160.     }
  1161.     if ( !SrcFlag | !DstFlag )
  1162.         goto fail ;
  1163.     if ( SrcFlag == DstFlag && dwSrcEncoding != dwDstEncoding && ( 4 != SrcFlag ))
  1164.         goto fail ;
  1165.     _dwConvertType = SrcFlag | DstFlag ;
  1166.     _bConvertDirt = ( SrcFlag & 0x0f ) > ( DstFlag & 0x0f )  ;
  1167.     // if code convertor has been allocated, deallocate it
  1168.     if (_hcins)
  1169.     {
  1170.         delete _hcins ;
  1171.         _hcins = NULL ;
  1172.     }
  1173.     return S_OK ;
  1174. fail :
  1175.     return S_FALSE ;
  1176. }
  1177. HRESULT CICharConverter::DoCodeConvert(LPDWORD lpdwMode, LPCSTR lpSrcStr, LPINT lpnSrcSize,
  1178.     LPSTR lpDstStr, LPINT lpnDstSize, DWORD dwFlag, WCHAR *lpFallBack)
  1179. {
  1180.     HRESULT hr = S_OK ;
  1181.     if ( 4 == _dwConvertType ) // CP_UCS_2 <-> CP_UCS_2_BE 
  1182.     {
  1183.         if (!lpDstStr)
  1184.         {   
  1185.             _nSrcSize = *lpnDstSize = *lpnSrcSize ;
  1186.         }
  1187.         else
  1188.         {
  1189.             int nSize = min(*lpnDstSize,*lpnSrcSize);
  1190.             _nSrcSize = *lpnSrcSize ;
  1191.             if ( lpDstStr && nSize > 0 )
  1192.             {
  1193.                 MoveMemory(lpDstStr, lpSrcStr, nSize );
  1194.                 DataByteSwap(lpDstStr, nSize );
  1195.                 _nSrcSize = nSize ;
  1196.                 *lpnDstSize = nSize ;
  1197.             }
  1198.         }
  1199.     }
  1200.     else if ( _bConvertDirt )
  1201.         hr = ConvertUUWI(lpdwMode, lpSrcStr,lpnSrcSize,lpDstStr,lpnDstSize, dwFlag, lpFallBack);
  1202.     else
  1203.         hr = ConvertIWUU(lpdwMode, lpSrcStr,lpnSrcSize,lpDstStr,lpnDstSize, dwFlag, lpFallBack);
  1204.     return hr ;
  1205. }
  1206. BOOL CICharConverter::ConvertCleanUp()
  1207. {
  1208.     if (_lpInterm1Str)
  1209.     {
  1210.          LocalFree(_lpInterm1Str);
  1211.          _lpInterm1Str = NULL ;
  1212.     }
  1213.     if (_lpInterm2Str)
  1214.     {
  1215.          LocalFree(_lpInterm2Str);
  1216.          _lpInterm2Str = NULL ;
  1217.     }
  1218.     if (_lpUnicodeStr)
  1219.     {
  1220.          LocalFree(_lpUnicodeStr);
  1221.          _lpUnicodeStr = NULL ;
  1222.     }
  1223.     _cvt_count = 0 ;
  1224.     _nSrcSize = 0 ;
  1225.     return TRUE ;
  1226. }
  1227. CICharConverter::CICharConverter()
  1228. {
  1229.     _lpInterm1Str = NULL ;
  1230.     _lpInterm2Str = NULL ;
  1231.     _lpUnicodeStr = NULL ;
  1232.     _hcins = NULL ;
  1233.     _cvt_count = 0 ;
  1234.     _dwWinCodePage = 0;
  1235.     _dwInternetEncoding = 0;
  1236.     _dwUTFEncoding = 0;
  1237.     _dwUnicodeEncoding = 0;
  1238.     _dwConvertType = 0;
  1239.     _nSrcSize = 0 ;
  1240.     _hcins_dst = 0 ;
  1241.     return ;
  1242. }
  1243. CICharConverter::CICharConverter(DWORD dwFlag, WCHAR *lpFallBack)
  1244. {
  1245.     _lpInterm1Str = NULL ;
  1246.     _lpInterm2Str = NULL ;
  1247.     _lpUnicodeStr = NULL ;
  1248.     _hcins = NULL ;
  1249.     _cvt_count = 0 ;
  1250.     _dwWinCodePage = 0;
  1251.     _dwInternetEncoding = 0;
  1252.     _dwUTFEncoding = 0;
  1253.     _dwUnicodeEncoding = 0;
  1254.     _dwConvertType = 0;
  1255.     _nSrcSize = 0 ;
  1256.     _hcins_dst = 0 ;
  1257.     _dwFlag = dwFlag;
  1258.     _lpFallBack = lpFallBack;
  1259.     return ;
  1260. }
  1261. CICharConverter::~CICharConverter()
  1262. {
  1263.     if (_lpInterm1Str)
  1264.     {
  1265.          LocalFree(_lpInterm1Str);
  1266.          _lpInterm1Str = NULL ;
  1267.     }
  1268.     if (_lpInterm2Str)
  1269.     {
  1270.          LocalFree(_lpInterm2Str);
  1271.          _lpInterm2Str = NULL ;
  1272.     }
  1273.     if (_lpUnicodeStr)
  1274.     {
  1275.          LocalFree(_lpUnicodeStr);
  1276.          _lpUnicodeStr = NULL ;
  1277.     }
  1278.     if (_hcins)
  1279.     {
  1280.         delete _hcins ;
  1281.         _hcins = NULL ;
  1282.     }
  1283. }
  1284. CICharConverter::CICharConverter(DWORD dwSrcEncoding, DWORD dwDstEncoding)
  1285. {
  1286.     _lpInterm1Str = NULL ;
  1287.     _lpInterm2Str = NULL ;
  1288.     _lpUnicodeStr = NULL ;
  1289.     _hcins = NULL ;
  1290.     _cvt_count = 0 ;
  1291.     _dwWinCodePage = 0;
  1292.     _dwInternetEncoding = 0;
  1293.     _dwUTFEncoding = 0;
  1294.     _dwUnicodeEncoding = 0;
  1295.     _dwConvertType = 0;
  1296.     _nSrcSize = 0 ;
  1297.     _hcins_dst = 0 ;
  1298.     
  1299.     ConvertSetup(dwSrcEncoding,dwDstEncoding);
  1300.     return ;
  1301. }
  1302. HRESULT WINAPI IsConvertINetStringAvailable(DWORD dwSrcEncoding, DWORD dwDstEncoding)
  1303. {
  1304.     HRESULT hr;
  1305.     CICharConverter * INetConvert = new CICharConverter ;
  1306.     if (!INetConvert)
  1307.         return E_OUTOFMEMORY;
  1308.     hr = INetConvert->ConvertSetup(dwSrcEncoding, dwDstEncoding);
  1309.     delete INetConvert;
  1310.     return hr ;
  1311. }
  1312. #define DETECTION_BUFFER_NUM    3
  1313. // BUGBUG (weiwu)
  1314. // In CP_AUTO and detection result is UTF7 case, private converter might use high word of *lpdwMode to store internal data, but we need 
  1315. // to use it to notify Trident the detection result, currently, we're bias to returning correct detection result.
  1316. // After IE5 release, we have to re-prototype conversion object and resovle this issue
  1317. HRESULT WINAPI ConvertINetStringEx(LPDWORD lpdwMode, DWORD dwSrcEncoding, DWORD dwDstEncoding, LPCSTR lpSrcStr, LPINT lpnSrcSize, LPSTR lpDstStr, LPINT lpnDstSize, DWORD dwFlag, WCHAR *lpFallBack)
  1318. {
  1319.     CICharConverter * INetConvert;
  1320.     int nSrcSize;
  1321.     int nDstSize;
  1322.     DWORD   dwMode = 0 ;
  1323.     // dwDetectResult 
  1324.     // CP_UNDEFINED :Fail to detect
  1325.     //      0       :Not a auto-detect scenario
  1326.     // Others       :Detected encoding
  1327.     DWORD   dwDetectResult = CP_UNDEFINED;
  1328.     HRESULT hr ;
  1329.     if(lpnSrcSize)
  1330.     {
  1331.         nSrcSize = *lpnSrcSize;
  1332.     }
  1333.     else
  1334.         nSrcSize = -1;
  1335.     if ( lpSrcStr && nSrcSize == -1 ) // Get length of lpSrcStr if not given, assuming lpSrcStr is a zero terminate string.
  1336.     {
  1337.         if ( dwSrcEncoding == CP_UCS_2 )
  1338.             nSrcSize = (lstrlenW((WCHAR*)lpSrcStr) << 1) ;
  1339.         else
  1340.             nSrcSize = lstrlenA(lpSrcStr) ;
  1341.     }
  1342.     if (!nSrcSize)
  1343.     {
  1344.         if (lpnDstSize)
  1345.            *lpnDstSize = 0;
  1346.         return S_OK;
  1347.     }
  1348.     INetConvert = new CICharConverter(dwFlag, lpFallBack) ;    
  1349.     if (!INetConvert)
  1350.         return E_OUTOFMEMORY;
  1351.     // ASSERT(CP_AUTO != dwDstEncoding);
  1352.     // if null specified at dst buffer we'll get the size of required buffer.
  1353.     if(!lpDstStr)
  1354.         nDstSize = 0;
  1355.     else if (lpnDstSize)
  1356.         nDstSize = *lpnDstSize;
  1357.     else 
  1358.         nDstSize = 0;
  1359.     if (lpdwMode)
  1360.         dwMode = *lpdwMode ;
  1361.     // In real world, clients uses 28591 as 1252, 28599 as 1254, 
  1362.     // To correctly convert those extended characters to Unicode,
  1363.     // We internally replace it with 1252 
  1364.     if (dwDstEncoding == CP_UCS_2 || dwDstEncoding == CP_UCS_2_BE)
  1365.     {
  1366.         if ((dwSrcEncoding == CP_ISO_8859_1) && _IsValidCodePage(CP_1252))
  1367.             dwSrcEncoding = CP_1252;
  1368.         if ((dwSrcEncoding == CP_ISO_8859_9) && _IsValidCodePage(CP_1254))
  1369.             dwSrcEncoding = CP_1254;
  1370.     }
  1371.     if ((dwDstEncoding == CP_1252) && (dwSrcEncoding == CP_ISO_8859_1))
  1372.     {
  1373.         dwSrcEncoding = CP_1252;
  1374.     }
  1375.     if ((dwDstEncoding == CP_1254) && (dwSrcEncoding == CP_ISO_8859_9))
  1376.     {
  1377.         dwSrcEncoding = CP_1254;
  1378.     }
  1379.     if ( dwSrcEncoding == CP_JP_AUTO ) // Auto Detection for Japan
  1380.     {
  1381.         CIncdJapanese DetectJapan;
  1382.         UINT uiCodePage ;
  1383.         uiCodePage = ( dwMode >> 16 ) & 0xffff ;
  1384.         if ( uiCodePage )
  1385.         {
  1386.             dwSrcEncoding = uiCodePage ;
  1387.             dwDetectResult = 0;
  1388.         }
  1389.         else
  1390.         {
  1391.             dwSrcEncoding = DetectJapan.DetectStringA(lpSrcStr, *lpnSrcSize);
  1392.             // if dwSrcEncoding is zero means there is an ambiguity, we don't return
  1393.             // the detected codepage to caller, instead we defaut its codepage internally
  1394.             // to SJIS
  1395.             if (dwSrcEncoding)
  1396.             {
  1397.                 dwDetectResult = dwSrcEncoding << 16 ;
  1398.             }
  1399.             else
  1400.                 dwSrcEncoding = CP_JPN_SJ;
  1401.         }
  1402.     }
  1403.     // BUGBUG: bug #43190, we auto-detect again for euc-kr page because IMN ver 1.0
  1404.     // mislabel an ISO-KR page as a ks_c_5601-1987 page. This is the only way 
  1405.     // we can fix that stupid mistake. 
  1406.     else if ( dwSrcEncoding == CP_KR_AUTO || dwSrcEncoding == CP_KOR_5601 ||
  1407.         dwSrcEncoding == CP_EUC_KR )
  1408.     {
  1409.         CIncdKorean DetectKorean;
  1410.         UINT uiCodePage ;
  1411.         uiCodePage = ( dwMode >> 16 ) & 0xffff ;
  1412.         if ( uiCodePage )
  1413.         {
  1414.             dwSrcEncoding = uiCodePage ;
  1415.             dwDetectResult = 0;
  1416.         }
  1417.         else
  1418.         {
  1419.             dwSrcEncoding = DetectKorean.DetectStringA(lpSrcStr, *lpnSrcSize);
  1420.             if (dwSrcEncoding)
  1421.             {
  1422.                 dwDetectResult = dwSrcEncoding << 16 ;
  1423.             }
  1424.             else
  1425.                 dwSrcEncoding = CP_KOR_5601;
  1426.         }
  1427.     }
  1428.     else if ( dwSrcEncoding == CP_AUTO ) // General Auto Detection for all code pages
  1429.     {
  1430.         nSrcSize = DETECTION_MAX_LEN < *lpnSrcSize ?  DETECTION_MAX_LEN : *lpnSrcSize;
  1431.         int nScores = DETECTION_BUFFER_NUM;
  1432.         DetectEncodingInfo Encoding[DETECTION_BUFFER_NUM];
  1433.         UINT uiCodePage ;
  1434.         uiCodePage = ( dwMode >> 16 ) & 0xffff ;
  1435.         if ( uiCodePage )
  1436.         {
  1437.             dwSrcEncoding = uiCodePage ;
  1438.             dwDetectResult = 0;
  1439.         }
  1440.         else
  1441.         {
  1442.             dwSrcEncoding = GetACP();
  1443.             if ( S_OK == _DetectInputCodepage(MLDETECTCP_HTML, CP_AUTO, (char *)lpSrcStr, &nSrcSize, &Encoding[0], &nScores))
  1444.             {
  1445.                 MIMECPINFO cpInfo;
  1446.                 if (Encoding[0].nCodePage == CP_20127)
  1447.                     Encoding[0].nCodePage = dwSrcEncoding;
  1448.                 if (NULL != g_pMimeDatabase)
  1449.                 {
  1450.                     if (SUCCEEDED(g_pMimeDatabase->GetCodePageInfo(Encoding[0].nCodePage, 0x409, &cpInfo)) && 
  1451.                         (cpInfo.dwFlags & MIMECONTF_VALID))
  1452.                     {
  1453.                         dwSrcEncoding = Encoding[0].nCodePage;     
  1454.                         dwDetectResult = dwSrcEncoding << 16 ;  
  1455.                     }
  1456.                 }
  1457.             }
  1458.             // If we failed in general detection and system locale is Jpn, we try harder 
  1459.             // with our Japanese detection engine
  1460.             if (dwSrcEncoding == CP_JPN_SJ && dwDetectResult == CP_UNDEFINED)
  1461.             {
  1462.                 CIncdJapanese DetectJapan;
  1463.                 DWORD dwSrcEncodingJpn = DetectJapan.DetectStringA(lpSrcStr, *lpnSrcSize);
  1464.                 if (dwSrcEncodingJpn)
  1465.                 {
  1466.                     // We only change conversion encoding without returnning this result to browser 
  1467.                     // if it is in the middle of detection, this is to prevent other encodings been mis-detected as Jpn encodings.
  1468.                     dwSrcEncoding = dwSrcEncodingJpn;   
  1469.                     
  1470.                     // Set search range for end tag as 10 bytes
  1471.                     if (*lpnSrcSize >= 10)
  1472.                     {
  1473.                         char szTmpStr[11] = {0};
  1474.                         char *lpTmpStr = szTmpStr;
  1475.                         MLStrCpyN(szTmpStr, (char *)&lpSrcStr[*lpnSrcSize-10], 10);                        
  1476.                         //ToLower
  1477.                         while(*lpTmpStr)
  1478.                         {
  1479.                             if (*lpTmpStr >= 'A' && *lpTmpStr <= 'W')
  1480.                                 *lpTmpStr += 0x20;
  1481.                             lpTmpStr++;
  1482.                         }
  1483.                         // If end of page, return this result
  1484.                         if (MLStrStr(szTmpStr, "</html>"))
  1485.                             dwDetectResult = dwSrcEncoding << 16 ;  
  1486.                     }
  1487.                 }
  1488.             }
  1489.             //aEncodingInfo[GetWindowsEncodingIndex(CP_AUTO)].dwCodePage = dwSrcEncoding;         
  1490.         }     
  1491.     }
  1492.     else
  1493.     {
  1494.         // Not a auto-detect scenario
  1495.         dwDetectResult = 0;
  1496.     }
  1497.     if ( S_OK == ( hr = INetConvert->ConvertSetup(dwSrcEncoding,dwDstEncoding )))
  1498.     {
  1499.        if ( dwSrcEncoding != dwDstEncoding )
  1500.        {
  1501.             // if high word of dwMode is CP_UTF_7, it must be detection result, don't pass it to UTF7 converter
  1502.             if ( dwSrcEncoding == CP_UTF_7 && (dwMode >> 16) == CP_UTF_7)
  1503.                 dwMode &= 0xFFFF;
  1504.             // ASSERT(!((IS_ENCODED_ENCODING(dwSrcEncoding) || IS_ENCODED_ENCODING(dwDstEncoding)) && (NULL == lpdwMode)));
  1505.             hr = INetConvert->DoCodeConvert(&dwMode, lpSrcStr, &nSrcSize, lpDstStr, &nDstSize, dwFlag, lpFallBack);
  1506.             // return the number of bytes processed for the source. 
  1507.             if (lpnSrcSize)
  1508.                 *lpnSrcSize = INetConvert->_nSrcSize ;
  1509.             INetConvert->ConvertCleanUp();
  1510.        }
  1511.        else
  1512.        {
  1513.             int nSize, i ;
  1514.             hr = S_OK ;
  1515.             BOOL bLeadByte = FALSE ;
  1516.             // only check for windows codepage
  1517.             if ( INetConvert->_dwConvertType == 02 && lpSrcStr )
  1518.             { 
  1519.                 for ( i=0; i<nSrcSize; i++)
  1520.                 {
  1521.                    if (bLeadByte)
  1522.                        bLeadByte = FALSE ;
  1523.                    else if (IsDBCSLeadByteEx(dwSrcEncoding,lpSrcStr[i]))
  1524.                        bLeadByte = TRUE ;
  1525.                 }
  1526.                 if (bLeadByte)
  1527.                     nSrcSize-- ;
  1528.             }
  1529.             // set input size
  1530.             if (lpnSrcSize)
  1531.                 *lpnSrcSize = nSrcSize ;
  1532.             // set output size and copy if we need to
  1533.             if (lpDstStr && *lpnDstSize)
  1534.             {
  1535.                 nSize = min(*lpnDstSize,nSrcSize);
  1536.                 MoveMemory(lpDstStr, lpSrcStr, nSize);
  1537.                 nDstSize = nSize ;
  1538.             }
  1539.             else
  1540.                 nDstSize = nSrcSize ;
  1541.        }
  1542.     }
  1543.     else
  1544.             nDstSize = 0 ;
  1545.     delete INetConvert;
  1546.     // return the number of bytes copied for the destination,
  1547.     if (lpnDstSize)
  1548.         *lpnDstSize = nDstSize;
  1549.     if (lpdwMode && lpDstStr)
  1550.     {        
  1551.         if (dwDetectResult)                     // CP_AUTO conversion
  1552.         {
  1553.             dwMode &= 0xFFFF;                   // Clear HIGHWORD in case private converter set it
  1554.             // If we have detection result, return it in HIGHWORD
  1555.             // BUGBUG: in the case of UTF7 conversion, private converter might use high word to store internal data,
  1556.             // this will conflict with our logic of returning detection result in high word, it is a design flaw, 
  1557.             // currently, we ignore conversion setting and give detection result more priority
  1558.             if (dwDetectResult != CP_UNDEFINED) 
  1559.                 dwMode |= dwDetectResult;
  1560.         }
  1561.         *lpdwMode = dwMode ;
  1562.     }
  1563.     return hr ;
  1564. }
  1565. HRESULT WINAPI ConvertINetReset(void)
  1566. {
  1567.     // BUGBUG: We will remove this API soon.
  1568.     return S_OK ;
  1569. }
  1570. HRESULT WINAPI ConvertINetMultiByteToUnicodeEx(LPDWORD lpdwMode, DWORD dwEncoding, LPCSTR lpSrcStr, LPINT lpnMultiCharCount, LPWSTR lpDstStr, LPINT lpnWideCharCount, DWORD dwFlag, WCHAR *lpFallBack)
  1571. {
  1572.     HRESULT hr ;
  1573.     int nByteCountSize = 0;
  1574.     if (lpnWideCharCount)
  1575.     {
  1576.         nByteCountSize = *lpnWideCharCount * sizeof(WCHAR);
  1577.     }
  1578. #ifdef UNIX
  1579.    int saved_nByteCountSize = nByteCountSize;
  1580. #endif /* UNIX */
  1581.     hr = ConvertINetStringEx(lpdwMode,dwEncoding, CP_UCS_2, lpSrcStr, lpnMultiCharCount, (LPSTR)lpDstStr, &nByteCountSize, dwFlag, lpFallBack) ;
  1582. #ifdef UNIX
  1583.     if(dwEncoding == 1200 || dwEncoding == 65000 || dwEncoding == 65001 ||
  1584.        (dwEncoding == 50001 && !_IsValidCodePage(dwEncoding)) )
  1585.     {
  1586.         /*
  1587.          * On unix we need to convert the little endian mode 2 byte unicode
  1588.          * format to unix mode 4 byte wChars.
  1589.          */
  1590.         if(lpDstStr && (saved_nByteCountSize < (nByteCountSize/2)*sizeof(WCHAR)))
  1591.             hr = E_FAIL;
  1592.         else
  1593.         {
  1594.             /*
  1595.              * Use a temporary array to do the 2byte -> 4byte conversion
  1596.              */
  1597.             LPSTR pTmp = (LPSTR) lpDstStr;
  1598.             LPWSTR pw4 = NULL;
  1599.             if(pTmp) /* allocate only if we have a lpDstStr */
  1600.                 pw4 = new WCHAR[nByteCountSize/2];
  1601.             if(pw4)
  1602.             {
  1603.                 int i = 0;
  1604.                 LPWSTR pw4Tmp = pw4;
  1605.                 for(; i < nByteCountSize/2; i++)
  1606.                     *pw4Tmp++ = (UCHAR)pTmp[i*2];
  1607.                 pw4Tmp = pw4;
  1608.                 for(i = 0; i < nByteCountSize/2; i++)
  1609.                     *lpDstStr++ = *pw4Tmp++;
  1610.             }
  1611.             if(!pw4 && pTmp) /* if lpDstStr and allocate fails bail out */
  1612.                 hr = E_FAIL;
  1613.             delete [] pw4;
  1614.         }
  1615.         nByteCountSize *= 2; // Expand twice as we have 4 byte wchars.
  1616.     }
  1617. #endif
  1618.     *lpnWideCharCount = nByteCountSize / sizeof(WCHAR);
  1619.     return hr ;
  1620. }
  1621. HRESULT WINAPI ConvertINetUnicodeToMultiByteEx(LPDWORD lpdwMode, DWORD dwEncoding, LPCWSTR lpSrcStr, LPINT lpnWideCharCount, LPSTR lpDstStr, LPINT lpnMultiCharCount, DWORD dwFlag, WCHAR *lpFallBack)
  1622. {
  1623.     HRESULT hr ;
  1624.     int nByteCountSize=-1;
  1625.     if(lpnWideCharCount && *lpnWideCharCount != -1) 
  1626.         nByteCountSize = *lpnWideCharCount * sizeof(WCHAR);
  1627.     hr = ConvertINetStringEx(lpdwMode,CP_UCS_2, dwEncoding, (LPCSTR) lpSrcStr, &nByteCountSize, lpDstStr, lpnMultiCharCount, dwFlag, lpFallBack);
  1628. #ifdef UNIX
  1629.     if(dwEncoding == 1200 || dwEncoding == 65000 || dwEncoding == 65001) {
  1630.         nByteCountSize *= 2; // Expand twice as we have 4 byte wchars.
  1631.     }
  1632. #endif /* UNIX */
  1633.     if (lpnWideCharCount)
  1634.         *lpnWideCharCount = nByteCountSize / sizeof(WCHAR);
  1635.     return hr ;
  1636. }
  1637. HRESULT WINAPI ConvertINetString(LPDWORD lpdwMode, DWORD dwSrcEncoding, DWORD dwDstEncoding, LPCSTR lpSrcStr, LPINT lpnSrcSize, LPSTR lpDstStr, LPINT lpnDstSize)
  1638. {
  1639.     HRESULT hr ;
  1640.     hr = ConvertINetStringEx(lpdwMode,dwSrcEncoding,dwDstEncoding,lpSrcStr,lpnSrcSize,lpDstStr,lpnDstSize, 0, NULL);
  1641.     return hr ;
  1642. }
  1643. HRESULT WINAPI ConvertINetUnicodeToMultiByte(LPDWORD lpdwMode, DWORD dwEncoding, LPCWSTR lpSrcStr, LPINT lpnWideCharCount, LPSTR lpDstStr, LPINT lpnMultiCharCount)
  1644. {
  1645.     HRESULT hr ;
  1646.     DWORD dwFlag = 0 ;
  1647.     if ( lpdwMode )
  1648.         dwFlag |= ( *lpdwMode & 0x00008000 ) ? MLCONVCHARF_ENTITIZE : 0 ;
  1649.     hr = ConvertINetUnicodeToMultiByteEx(lpdwMode,dwEncoding,lpSrcStr,lpnWideCharCount,lpDstStr,lpnMultiCharCount,dwFlag,NULL);
  1650.     return hr ;
  1651. }
  1652. HRESULT WINAPI ConvertINetMultiByteToUnicode(LPDWORD lpdwMode, DWORD dwEncoding, LPCSTR lpSrcStr, LPINT lpnMultiCharCount, LPWSTR lpDstStr, LPINT lpnWideCharCount)
  1653. {
  1654.     HRESULT hr ;
  1655.     hr = ConvertINetMultiByteToUnicodeEx(lpdwMode,dwEncoding,lpSrcStr,lpnMultiCharCount,lpDstStr,lpnWideCharCount, 0, NULL);
  1656.     return hr ;
  1657. }
  1658. #define STR_BUFFER_SIZE 2048
  1659. HRESULT _ConvertINetStringInIStream(CICharConverter * INetConvert, LPDWORD lpdwMode, DWORD dwSrcEncoding, DWORD dwDstEncoding, IStream *pstmIn, IStream *pstmOut, DWORD dwFlag, WCHAR *lpFallBack)
  1660. {
  1661.     DWORD   dwMode, dwModeTemp ;
  1662.     HRESULT hr= S_OK, hrWarnings=S_OK;
  1663.     LPSTR lpstrIn = NULL, lpstrOut = NULL; 
  1664.     ULONG nSrcSize, nSrcUsed, nSrcLeft, nDstSize, _nDstSize, nOutBuffSize ;
  1665.     if (lpdwMode)
  1666.         dwMode = *lpdwMode ;
  1667.     // allocate a temp input buffer - 2K in size
  1668.     if ( (lpstrIn = (LPSTR) LocalAlloc(LPTR, STR_BUFFER_SIZE )) == NULL )
  1669.     {
  1670.         hrWarnings = E_OUTOFMEMORY ;
  1671.         goto exit;
  1672.     }
  1673.     if ( (lpstrOut = (LPSTR) LocalAlloc(LPTR, STR_BUFFER_SIZE * 2 )) == NULL )
  1674.     {
  1675.         hrWarnings = E_OUTOFMEMORY ;
  1676.         goto exit;
  1677.     }
  1678.     nOutBuffSize = STR_BUFFER_SIZE * 2 ;
  1679.     nSrcLeft = 0 ;
  1680.     // In real world, clients uses 28591 as 1252, 28599 as 1254, 
  1681.     // To correctly convert those extended characters to Unicode,
  1682.     // We internally replace it with 1252 
  1683.     if (dwDstEncoding == CP_UCS_2 || dwDstEncoding == CP_UCS_2_BE)
  1684.     {
  1685.         if ((dwSrcEncoding == CP_ISO_8859_1) && _IsValidCodePage(CP_1252))
  1686.             dwSrcEncoding = CP_1252;
  1687.         if ((dwSrcEncoding == CP_ISO_8859_9) && _IsValidCodePage(CP_1254))
  1688.             dwSrcEncoding = CP_1254;
  1689.     }
  1690.     if ((dwDstEncoding == CP_1252) && (dwSrcEncoding == CP_ISO_8859_1))
  1691.     {
  1692.         dwSrcEncoding = CP_1252;
  1693.     }
  1694.     if ((dwDstEncoding == CP_1254) && (dwSrcEncoding == CP_ISO_8859_9))
  1695.     {
  1696.         dwSrcEncoding = CP_1254;
  1697.     }
  1698.     if ( dwSrcEncoding == CP_JP_AUTO ) // Auto Detection for Japan
  1699.     {
  1700.         CIncdJapanese DetectJapan;
  1701.         UINT uiCodePage ;
  1702.         LARGE_INTEGER   li;
  1703.         uiCodePage = ( dwMode >> 16 ) & 0xffff ;
  1704.         if ( uiCodePage )
  1705.             dwSrcEncoding = uiCodePage ;
  1706.         else
  1707.         {
  1708.             LISet32(li, 0);
  1709.             hr = pstmIn->Read(lpstrIn, STR_BUFFER_SIZE , &nSrcSize);
  1710.             if (S_OK != hr)
  1711.                 hrWarnings = hr;
  1712.             hr = pstmIn->Seek(li,STREAM_SEEK_SET, NULL);
  1713.             if (S_OK != hr)
  1714.                 hrWarnings = hr;
  1715.             dwSrcEncoding = DetectJapan.DetectStringA(lpstrIn, nSrcSize);
  1716.             // if dwSrcEncoding is zero means there is an ambiguity, we don't return
  1717.             // the detected codepage to caller, instead we defaut its codepage internally
  1718.             // to SJIS
  1719.             if (dwSrcEncoding)
  1720.             {
  1721.                 dwMode &= 0x0000ffff ;
  1722.                 dwMode |= dwSrcEncoding << 16 ; 
  1723.             }
  1724.             else
  1725.                 dwSrcEncoding = CP_JPN_SJ;
  1726.         }
  1727.     }
  1728.     // BUGBUG: bug #43190, we auto-detect again for euc-kr page because IMN ver 1.0
  1729.     // mislabel an ISO-KR page as a ks_c_5601-1987 page. This is the only way 
  1730.     // we can fix that stupid mistake. 
  1731.     else if ( dwSrcEncoding == CP_KR_AUTO || dwSrcEncoding == CP_KOR_5601 ||
  1732.         dwSrcEncoding == CP_EUC_KR )
  1733.     {
  1734.         CIncdKorean DetectKorean;
  1735.         UINT uiCodePage ;
  1736.         LARGE_INTEGER   li;
  1737.         uiCodePage = ( dwMode >> 16 ) & 0xffff ;
  1738.         if ( uiCodePage )
  1739.             dwSrcEncoding = uiCodePage ;
  1740.         else
  1741.         {
  1742.             LISet32(li, 0);
  1743.             
  1744.             hr = pstmIn->Read(lpstrIn, STR_BUFFER_SIZE, &nSrcSize);
  1745.             if (S_OK != hr)
  1746.                 hrWarnings = hr;
  1747.             hr = pstmIn->Seek(li,STREAM_SEEK_SET, NULL);
  1748.             if (S_OK != hr)
  1749.                 hrWarnings = hr;
  1750.             dwSrcEncoding = DetectKorean.DetectStringA(lpstrIn, nSrcSize);
  1751.             if (dwSrcEncoding)
  1752.             {
  1753.                 dwMode &= 0x0000ffff ;
  1754.                 dwMode |= dwSrcEncoding << 16 ; 
  1755.             }
  1756.             else
  1757.                 dwSrcEncoding = CP_KOR_5601;
  1758.         }
  1759.     }
  1760.     else if ( dwSrcEncoding == CP_AUTO ) // General Auto Detection for all code pages
  1761.     {
  1762.         INT nScores = 1;
  1763.         DWORD dwSrcEncoding ;
  1764.         DetectEncodingInfo Encoding;
  1765.         UINT uiCodePage ;
  1766.         LARGE_INTEGER   li;
  1767.         uiCodePage = ( dwMode >> 16 ) & 0xffff ;
  1768.         if ( uiCodePage )
  1769.             dwSrcEncoding = uiCodePage ;
  1770.         else
  1771.         {
  1772.             LISet32(li, 0);
  1773.             hr = pstmIn->Read(lpstrIn, STR_BUFFER_SIZE , &nSrcSize);
  1774.             if (S_OK != hr)
  1775.                 hrWarnings = hr;
  1776.             hr = pstmIn->Seek(li,STREAM_SEEK_SET, NULL);
  1777.             if (S_OK != hr)
  1778.                 hrWarnings = hr;
  1779.             if (DETECTION_MAX_LEN < nSrcSize)
  1780.                 nSrcSize =  DETECTION_MAX_LEN;
  1781.             if ( S_OK == _DetectInputCodepage(MLDETECTCP_HTML, 1252, lpstrIn, (int *)&nSrcSize, &Encoding, &nScores))
  1782.             {
  1783.                 dwSrcEncoding = Encoding.nCodePage;
  1784.                 dwMode &= 0x0000ffff ;
  1785.                 dwMode |= dwSrcEncoding << 16 ; 
  1786.             }
  1787.             else
  1788.             {
  1789.                 dwSrcEncoding = CP_ACP;
  1790.             }
  1791.             aEncodingInfo[GetWindowsEncodingIndex(CP_AUTO)].dwCodePage = dwSrcEncoding;
  1792.         }
  1793.     }
  1794.     if ( S_OK == ( hr = INetConvert->ConvertSetup(dwSrcEncoding,dwDstEncoding )))
  1795.     {
  1796.         // Loop for ever
  1797.         while(1)
  1798.         {
  1799.             // Read a buffer
  1800.             hr = pstmIn->Read(&lpstrIn[nSrcLeft], STR_BUFFER_SIZE-nSrcLeft, &nSrcSize);
  1801.             if (S_OK != hr)
  1802.                 hrWarnings = hr;
  1803.             // Done
  1804.             if (0 == nSrcSize)
  1805.                 break;
  1806.             nSrcSize += nSrcLeft ;
  1807.             nSrcUsed = nSrcSize ;
  1808.             dwModeTemp = dwMode ;
  1809.             nDstSize = 0 ;
  1810.             // get the size of output buffer
  1811.             hr = INetConvert->DoCodeConvert(&dwModeTemp, (LPCSTR)lpstrIn, (LPINT)&nSrcUsed, NULL, (LPINT)&nDstSize, dwFlag, lpFallBack);
  1812.             if (S_OK != hr)
  1813.                 hrWarnings = hr;
  1814.             // Reallocate output buffer if so
  1815.             if ( nDstSize > nOutBuffSize )
  1816.             {
  1817.                 LPSTR psz = (LPSTR) LocalReAlloc(lpstrOut, nDstSize, LMEM_ZEROINIT|LMEM_MOVEABLE);
  1818.                 if (psz == NULL)
  1819.                 {
  1820.                     hrWarnings = E_OUTOFMEMORY ;
  1821.                     goto exit;
  1822.                 }
  1823.                 lpstrOut = psz;
  1824.                 nOutBuffSize = nDstSize ;
  1825.             }
  1826.             _nDstSize = nDstSize;
  1827.             // Due to multi_stage conversion, this is the actual size is used
  1828.             nSrcUsed = INetConvert->_nSrcSize ;
  1829.             nSrcLeft = nSrcSize - nSrcUsed ;
  1830. #if 0
  1831.             // restore Src size
  1832.             nSrcUsed = nSrcSize ;
  1833. #endif
  1834.             // do conversion
  1835.             hr = INetConvert->DoCodeConvert(&dwMode, (LPCSTR)lpstrIn, (LPINT)&nSrcUsed, lpstrOut, (LPINT)&_nDstSize, dwFlag, lpFallBack);
  1836.             if (S_OK != hr)
  1837.                 hrWarnings = hr;
  1838.             // Write It
  1839.             hr = pstmOut->Write(lpstrOut, nDstSize, &nDstSize);
  1840.             if (S_OK != hr)
  1841.                 hrWarnings = hr;
  1842.             if (nSrcLeft )
  1843.                 MoveMemory(lpstrIn, &lpstrIn[nSrcSize-nSrcLeft],nSrcLeft);
  1844.             INetConvert->ConvertCleanUp();
  1845.         }
  1846.     }
  1847.     if (nSrcLeft )
  1848.     {
  1849.         LARGE_INTEGER   li;
  1850.         LISet32(li, -(LONG)nSrcLeft );
  1851.         hr = pstmIn->Seek(li,STREAM_SEEK_CUR, NULL);
  1852.     }
  1853.     if (lpdwMode)
  1854.         *lpdwMode = dwMode ;
  1855. exit :
  1856.     if (lpstrIn)
  1857.         LocalFree(lpstrIn);
  1858.     if (lpstrOut)
  1859.         LocalFree(lpstrOut);
  1860.     // Done
  1861.     return (hr == S_OK) ? hrWarnings : hr;
  1862. }
  1863. HRESULT WINAPI ConvertINetStringInIStream(LPDWORD lpdwMode, DWORD dwSrcEncoding, DWORD dwDstEncoding, IStream *pstmIn, IStream *pstmOut, DWORD dwFlag, WCHAR *lpFallBack)
  1864. {
  1865.     HRESULT hr;
  1866.     CICharConverter * INetConvert = new CICharConverter(dwFlag, lpFallBack) ;
  1867.     if (!INetConvert)
  1868.         return E_OUTOFMEMORY;
  1869.     hr = _ConvertINetStringInIStream(INetConvert,lpdwMode,dwSrcEncoding,dwDstEncoding,pstmIn,pstmOut,dwFlag,lpFallBack);
  1870.     delete INetConvert;
  1871.     return hr ;
  1872. }