home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / wxos2233.zip / wxOS2-2_3_3.zip / wxWindows-2.3.3 / src / common / strconv.cpp < prev    next >
C/C++ Source or Header  |  2002-09-05  |  30KB  |  1,055 lines

  1. /////////////////////////////////////////////////////////////////////////////
  2. // Name:        strconv.cpp
  3. // Purpose:     Unicode conversion classes
  4. // Author:      Ove Kaaven, Robert Roebling, Vadim Zeitlin, Vaclav Slavik
  5. // Modified by:
  6. // Created:     29/01/98
  7. // RCS-ID:      $Id: strconv.cpp,v 1.65 2002/09/04 22:07:12 VS Exp $
  8. // Copyright:   (c) 1999 Ove Kaaven, Robert Roebling, Vadim Zeitlin, Vaclav Slavik
  9. // Licence:     wxWindows license
  10. /////////////////////////////////////////////////////////////////////////////
  11.  
  12. // ============================================================================
  13. // declarations
  14. // ============================================================================
  15.  
  16. // ----------------------------------------------------------------------------
  17. // headers
  18. // ----------------------------------------------------------------------------
  19.  
  20. #ifdef __GNUG__
  21.   #pragma implementation "strconv.h"
  22. #endif
  23.  
  24. // For compilers that support precompilation, includes "wx.h".
  25. #include "wx/wxprec.h"
  26.  
  27. #ifdef __BORLANDC__
  28.   #pragma hdrstop
  29. #endif
  30.  
  31. #ifndef WX_PRECOMP
  32.     #include "wx/intl.h"
  33.     #include "wx/log.h"
  34. #endif // WX_PRECOMP
  35.  
  36. #ifdef __WXMSW__
  37.     #include "wx/msw/private.h"
  38. #endif
  39.  
  40. #include <errno.h>
  41. #include <ctype.h>
  42. #include <string.h>
  43. #include <stdlib.h>
  44.  
  45. #include "wx/module.h"
  46. #include "wx/strconv.h"
  47.  
  48. // ----------------------------------------------------------------------------
  49. // globals
  50. // ----------------------------------------------------------------------------
  51.  
  52. #if wxUSE_WCHAR_T
  53.     WXDLLEXPORT_DATA(wxMBConv) wxConvLibc;
  54.     WXDLLEXPORT_DATA(wxCSConv) wxConvLocal((const wxChar *)NULL);
  55. #else
  56.     // stand-ins in absence of wchar_t
  57.     WXDLLEXPORT_DATA(wxMBConv) wxConvLibc, wxConvFile, wxConvLocal;
  58. #endif // wxUSE_WCHAR_T
  59.  
  60. WXDLLEXPORT_DATA(wxMBConv *) wxConvCurrent = &wxConvLibc;
  61.  
  62. class wxStrConvModule: public wxModule
  63. {
  64. public:
  65.     wxStrConvModule() : wxModule() { }
  66.     virtual bool OnInit() { return TRUE; }
  67.     virtual void OnExit()
  68.     {
  69. #if wxUSE_WCHAR_T
  70.          wxConvLocal.Clear();
  71. #endif
  72.     }
  73.  
  74.     DECLARE_DYNAMIC_CLASS(wxStrConvModule)
  75. };
  76.  
  77. IMPLEMENT_DYNAMIC_CLASS(wxStrConvModule, wxModule)
  78.  
  79.  
  80. // ----------------------------------------------------------------------------
  81. // headers
  82. // ----------------------------------------------------------------------------
  83.  
  84. #if wxUSE_WCHAR_T
  85.  
  86. #ifdef __SALFORDC__
  87.     #include <clib.h>
  88. #endif
  89.  
  90. #ifdef HAVE_ICONV
  91.     #include <iconv.h>
  92. #endif
  93.  
  94. #include "wx/encconv.h"
  95. #include "wx/fontmap.h"
  96.  
  97. // ----------------------------------------------------------------------------
  98. // macros
  99. // ----------------------------------------------------------------------------
  100.  
  101. #define BSWAP_UCS4(str, len) { unsigned _c; for (_c=0; _c<len; _c++) str[_c]=wxUINT32_SWAP_ALWAYS(str[_c]); }
  102. #define BSWAP_UTF16(str, len) { unsigned _c; for (_c=0; _c<len; _c++) str[_c]=wxUINT16_SWAP_ALWAYS(str[_c]); }
  103.  
  104. // under Unix SIZEOF_WCHAR_T is defined by configure, but under other platforms
  105. // it might be not defined - assume the most common value
  106. #ifndef SIZEOF_WCHAR_T
  107.     #define SIZEOF_WCHAR_T 2
  108. #endif // !defined(SIZEOF_WCHAR_T)
  109.  
  110. #if SIZEOF_WCHAR_T == 4
  111.     #define WC_NAME         "UCS4"
  112.     #define WC_BSWAP         BSWAP_UCS4
  113.     #ifdef WORDS_BIGENDIAN
  114.       #define WC_NAME_BEST  "UCS-4BE"
  115.     #else
  116.       #define WC_NAME_BEST  "UCS-4LE"
  117.     #endif
  118. #elif SIZEOF_WCHAR_T == 2
  119.     #define WC_NAME         "UTF16"
  120.     #define WC_BSWAP         BSWAP_UTF16
  121.     #define WC_UTF16
  122.     #ifdef WORDS_BIGENDIAN
  123.       #define WC_NAME_BEST  "UTF-16BE"
  124.     #else
  125.       #define WC_NAME_BEST  "UTF-16LE"
  126.     #endif
  127. #else // sizeof(wchar_t) != 2 nor 4
  128.     // I don't know what to do about this
  129.     #error "Weird sizeof(wchar_t): please report your platform details to wx-users mailing list"
  130. #endif
  131.  
  132. // ============================================================================
  133. // implementation
  134. // ============================================================================
  135.  
  136. // ----------------------------------------------------------------------------
  137. // UTF-16 en/decoding
  138. // ----------------------------------------------------------------------------
  139.  
  140. #ifdef WC_UTF16
  141.  
  142. static size_t encode_utf16(wxUint32 input, wchar_t *output)
  143. {
  144.     if (input<=0xffff)
  145.     {
  146.         if (output) *output++ = (wchar_t) input;
  147.         return 1;
  148.     }
  149.     else if (input>=0x110000)
  150.     {
  151.         return (size_t)-1;
  152.     }
  153.     else
  154.     {
  155.         if (output)
  156.         {
  157.             *output++ = (wchar_t) ((input >> 10)+0xd7c0);
  158.             *output++ = (wchar_t) ((input&0x3ff)+0xdc00);
  159.         }
  160.         return 2;
  161.     }
  162. }
  163.  
  164. static size_t decode_utf16(const wchar_t* input, wxUint32& output)
  165. {
  166.     if ((*input<0xd800) || (*input>0xdfff))
  167.     {
  168.         output = *input;
  169.         return 1;
  170.     }
  171.     else if ((input[1]<0xdc00) || (input[1]>=0xdfff))
  172.     {
  173.         output = *input;
  174.         return (size_t)-1;
  175.     }
  176.     else
  177.     {
  178.         output = ((input[0] - 0xd7c0) << 10) + (input[1] - 0xdc00);
  179.         return 2;
  180.     }
  181. }
  182.  
  183. #endif // WC_UTF16
  184.  
  185. // ----------------------------------------------------------------------------
  186. // wxMBConv
  187. // ----------------------------------------------------------------------------
  188.  
  189. #define IGNORE_LIBC 0
  190.  
  191. size_t wxMBConv::MB2WC(wchar_t *buf, const char *psz, size_t n) const
  192. {
  193. #if IGNORE_LIBC
  194.     if (buf)
  195.     {
  196.         for (size_t i = 0; i < strlen( psz )+1; i++)
  197.             buf[i] = (wchar_t) psz[i];
  198.         return strlen( psz );
  199.     }
  200.     else
  201.     {
  202.         return strlen( psz );
  203.     }
  204. #else
  205.     return wxMB2WC(buf, psz, n);
  206. #endif
  207. }
  208.  
  209. size_t wxMBConv::WC2MB(char *buf, const wchar_t *psz, size_t n) const
  210. {
  211. #if IGNORE_LIBC
  212.     if (buf)
  213.     {
  214.         for (size_t i = 0; i < wxStrlen( psz )+1; i++)
  215.             buf[i] = (char) psz[i];
  216.         return wxStrlen( psz );
  217.     }
  218.     else
  219.     {
  220.         return wxStrlen( psz );
  221.     }
  222. #else
  223.     return wxWC2MB(buf, psz, n);
  224. #endif
  225. }
  226.  
  227. const wxWCharBuffer wxMBConv::cMB2WC(const char *psz) const
  228. {
  229.     if (psz)
  230.     {
  231.         size_t nLen = MB2WC((wchar_t *) NULL, psz, 0);  // return value excludes /0
  232.         if (nLen == (size_t)-1)
  233.             return wxWCharBuffer((wchar_t *) NULL);
  234.         wxWCharBuffer buf(nLen);                        // this allocates nLen1+
  235.         MB2WC((wchar_t *)(const wchar_t *) buf, psz, nLen+1);
  236.         return buf;
  237.     }
  238.     else
  239.         return wxWCharBuffer((wchar_t *) NULL);
  240. }
  241.  
  242. const wxCharBuffer wxMBConv::cWC2MB(const wchar_t *pwz) const
  243. {
  244.     // return value excludes NUL
  245.     size_t nLen = pwz ? WC2MB((char *) NULL, pwz, 0) : (size_t)-1;
  246.     if (nLen == (size_t)-1)
  247.         return wxCharBuffer((const char *)NULL);
  248.  
  249.     wxCharBuffer buf(nLen);                      // this allocates nLen+1
  250.     WC2MB((char *)(const char *) buf, pwz, nLen+1);
  251.     return buf;
  252. }
  253.  
  254. // ----------------------------------------------------------------------------
  255. // standard gdk conversion
  256. // ----------------------------------------------------------------------------
  257.  
  258. #ifdef __WXGTK12__
  259.  
  260. WXDLLEXPORT_DATA(wxMBConvGdk) wxConvGdk;
  261.  
  262. #include <gdk/gdk.h>
  263.  
  264. size_t wxMBConvGdk::MB2WC(wchar_t *buf, const char *psz, size_t n) const
  265. {
  266.     if (buf)
  267.     {
  268.         return gdk_mbstowcs((GdkWChar *)buf, psz, n);
  269.     }
  270.     else
  271.     {
  272.         GdkWChar *nbuf = new GdkWChar[n=strlen(psz)];
  273.         size_t len = gdk_mbstowcs(nbuf, psz, n);
  274.         delete[] nbuf;
  275.         return len;
  276.     }
  277. }
  278.  
  279. size_t wxMBConvGdk::WC2MB(char *buf, const wchar_t *psz, size_t n) const
  280. {
  281.     char *mbstr = gdk_wcstombs((GdkWChar *)psz);
  282.     size_t len = mbstr ? strlen(mbstr) : 0;
  283.     if (buf)
  284.     {
  285.         if (len > n)
  286.             len = n;
  287.         memcpy(buf, psz, len);
  288.         if (len < n)
  289.             buf[len] = 0;
  290.     }
  291.     return len;
  292. }
  293.  
  294. #endif // GTK > 1.0
  295.  
  296. // ----------------------------------------------------------------------------
  297. // UTF-7
  298. // ----------------------------------------------------------------------------
  299.  
  300. WXDLLEXPORT_DATA(wxMBConvUTF7) wxConvUTF7;
  301.  
  302. #if 0
  303. static char utf7_setD[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  304.                         "abcdefghijklmnopqrstuvwxyz"
  305.                         "0123456789'(),-./:?";
  306. static char utf7_setO[]="!\"#$%&*;<=>@[]^_`{|}";
  307. static char utf7_setB[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  308.                         "abcdefghijklmnopqrstuvwxyz"
  309.                         "0123456789+/";
  310. #endif
  311.  
  312. // TODO: write actual implementations of UTF-7 here
  313. size_t wxMBConvUTF7::MB2WC(wchar_t * WXUNUSED(buf),
  314.                            const char * WXUNUSED(psz),
  315.                            size_t WXUNUSED(n)) const
  316. {
  317.   return 0;
  318. }
  319.  
  320. size_t wxMBConvUTF7::WC2MB(char * WXUNUSED(buf),
  321.                            const wchar_t * WXUNUSED(psz),
  322.                            size_t WXUNUSED(n)) const
  323. {
  324.   return 0;
  325. }
  326.  
  327. // ----------------------------------------------------------------------------
  328. // UTF-8
  329. // ----------------------------------------------------------------------------
  330.  
  331. WXDLLEXPORT_DATA(wxMBConvUTF8) wxConvUTF8;
  332.  
  333. static wxUint32 utf8_max[]=
  334.     { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff, 0xffffffff };
  335.  
  336. size_t wxMBConvUTF8::MB2WC(wchar_t *buf, const char *psz, size_t n) const
  337. {
  338.     size_t len = 0;
  339.  
  340.     while (*psz && ((!buf) || (len < n)))
  341.     {
  342.         unsigned char cc = *psz++, fc = cc;
  343.         unsigned cnt;
  344.         for (cnt = 0; fc & 0x80; cnt++)
  345.             fc <<= 1;
  346.         if (!cnt)
  347.         {
  348.             // plain ASCII char
  349.             if (buf)
  350.                 *buf++ = cc;
  351.             len++;
  352.         }
  353.         else
  354.         {
  355.             cnt--;
  356.             if (!cnt)
  357.             {
  358.                 // invalid UTF-8 sequence
  359.                 return (size_t)-1;
  360.             }
  361.             else
  362.             {
  363.                 unsigned ocnt = cnt - 1;
  364.                 wxUint32 res = cc & (0x3f >> cnt);
  365.                 while (cnt--)
  366.                 {
  367.                     cc = *psz++;
  368.                     if ((cc & 0xC0) != 0x80)
  369.                     {
  370.                         // invalid UTF-8 sequence
  371.                         return (size_t)-1;
  372.                     }
  373.                     res = (res << 6) | (cc & 0x3f);
  374.                 }
  375.                 if (res <= utf8_max[ocnt])
  376.                 {
  377.                     // illegal UTF-8 encoding
  378.                     return (size_t)-1;
  379.                 }
  380. #ifdef WC_UTF16
  381.                 size_t pa = encode_utf16(res, buf);
  382.                 if (pa == (size_t)-1)
  383.                   return (size_t)-1;
  384.                 if (buf)
  385.                     buf += pa;
  386.                 len += pa;
  387. #else // !WC_UTF16
  388.                 if (buf)
  389.                     *buf++ = res;
  390.                 len++;
  391. #endif // WC_UTF16/!WC_UTF16
  392.             }
  393.         }
  394.     }
  395.     if (buf && (len < n))
  396.         *buf = 0;
  397.     return len;
  398. }
  399.  
  400. size_t wxMBConvUTF8::WC2MB(char *buf, const wchar_t *psz, size_t n) const
  401. {
  402.     size_t len = 0;
  403.  
  404.     while (*psz && ((!buf) || (len < n)))
  405.     {
  406.         wxUint32 cc;
  407. #ifdef WC_UTF16
  408.         size_t pa = decode_utf16(psz, cc);
  409.         psz += (pa == (size_t)-1) ? 1 : pa;
  410. #else
  411.         cc=(*psz++) & 0x7fffffff;
  412. #endif
  413.         unsigned cnt;
  414.         for (cnt = 0; cc > utf8_max[cnt]; cnt++) {}
  415.         if (!cnt)
  416.         {
  417.             // plain ASCII char
  418.             if (buf)
  419.                 *buf++ = (char) cc;
  420.             len++;
  421.         }
  422.  
  423.         else
  424.         {
  425.             len += cnt + 1;
  426.             if (buf)
  427.             {
  428.                 *buf++ = (char) ((-128 >> cnt) | ((cc >> (cnt * 6)) & (0x3f >> cnt)));
  429.                 while (cnt--)
  430.                     *buf++ = (char) (0x80 | ((cc >> (cnt * 6)) & 0x3f));
  431.             }
  432.         }
  433.     }
  434.  
  435.     if (buf && (len<n)) *buf = 0;
  436.     
  437.     return len;
  438. }
  439.  
  440. // ============================================================================
  441. // wxCharacterSet and derived classes
  442. // ============================================================================
  443.  
  444. // ----------------------------------------------------------------------------
  445. // wxCharacterSet is the ABC for the classes below
  446. // ----------------------------------------------------------------------------
  447.  
  448. class wxCharacterSet
  449. {
  450. public:
  451.     wxCharacterSet(const wxChar*name) : cname(name) {}
  452.     virtual ~wxCharacterSet() {}
  453.     virtual size_t MB2WC(wchar_t *buf, const char *psz, size_t n) = 0;
  454.     virtual size_t WC2MB(char *buf, const wchar_t *psz, size_t n) = 0;
  455.     virtual bool usable() const = 0;
  456. public:
  457.     const wxChar*cname;
  458. };
  459.  
  460. // ----------------------------------------------------------------------------
  461. // ID_CharSet: implementation of wxCharacterSet using an existing wxMBConv
  462. // ----------------------------------------------------------------------------
  463.  
  464. class ID_CharSet : public wxCharacterSet
  465. {
  466. public:
  467.     ID_CharSet(const wxChar *name, wxMBConv *cnv)
  468.         : wxCharacterSet(name), work(cnv) {}
  469.  
  470.     size_t MB2WC(wchar_t *buf, const char *psz, size_t n)
  471.         { return work ? work->MB2WC(buf,psz,n) : (size_t)-1; }
  472.  
  473.     size_t WC2MB(char *buf, const wchar_t *psz, size_t n)
  474.         { return work ? work->WC2MB(buf,psz,n) : (size_t)-1; }
  475.  
  476.     bool usable() const
  477.         { return work!=NULL; }
  478. public:
  479.     wxMBConv*work;
  480. };
  481.  
  482.  
  483. // ============================================================================
  484. // The classes doing conversion using the iconv_xxx() functions
  485. // ============================================================================
  486.  
  487. #ifdef HAVE_ICONV
  488.  
  489. // VS: glibc 2.1.3 is broken in that iconv() conversion to/from UCS4 fails with E2BIG
  490. //     if output buffer is _exactly_ as big as needed. Such case is (unless there's
  491. //     yet another bug in glibc) the only case when iconv() returns with (size_t)-1
  492. //     (which means error) and says there are 0 bytes left in the input buffer --
  493. //     when _real_ error occurs, bytes-left-in-input buffer is non-zero. Hence,
  494. //     this alternative test for iconv() failure.
  495. //     [This bug does not appear in glibc 2.2.]
  496. #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ <= 1
  497. #define ICONV_FAILED(cres, bufLeft) ((cres == (size_t)-1) && \
  498.                                      (errno != E2BIG || bufLeft != 0))
  499. #else
  500. #define ICONV_FAILED(cres, bufLeft)  (cres == (size_t)-1)
  501. #endif
  502.  
  503. #define ICONV_CHAR_CAST(x)  ((ICONV_CONST char **)(x))
  504.  
  505. // ----------------------------------------------------------------------------
  506. // IC_CharSet: encapsulates an iconv character set
  507. // ----------------------------------------------------------------------------
  508.  
  509. class IC_CharSet : public wxCharacterSet
  510. {
  511. public:
  512.     IC_CharSet(const wxChar *name);
  513.     virtual ~IC_CharSet();
  514.  
  515.     virtual size_t MB2WC(wchar_t *buf, const char *psz, size_t n);
  516.     virtual size_t WC2MB(char *buf, const wchar_t *psz, size_t n);
  517.  
  518.     bool usable() const
  519.         { return (m2w != (iconv_t)-1) && (w2m != (iconv_t)-1); }
  520.  
  521. protected:
  522.     // the iconv handlers used to translate from multibyte to wide char and in
  523.     // the other direction
  524.     iconv_t m2w,
  525.             w2m;
  526.  
  527. private:
  528.     // the name (for iconv_open()) of a wide char charset - if none is
  529.     // available on this machine, it will remain NULL
  530.     static const char *ms_wcCharsetName;
  531.  
  532.     // true if the wide char encoding we use (i.e. ms_wcCharsetName) has
  533.     // different endian-ness than the native one
  534.     static bool ms_wcNeedsSwap;
  535. };
  536.  
  537. const char *IC_CharSet::ms_wcCharsetName = NULL;
  538. bool IC_CharSet::ms_wcNeedsSwap = FALSE;
  539.  
  540. IC_CharSet::IC_CharSet(const wxChar *name)
  541.           : wxCharacterSet(name)
  542. {
  543.     // Do it the hard way
  544.     char cname[100];
  545.     for (size_t i = 0; i < wxStrlen(name)+1; i++)
  546.         cname[i] = (char) name[i];
  547.  
  548.     // check for charset that represents wchar_t:
  549.     if (ms_wcCharsetName == NULL)
  550.     {
  551.         ms_wcNeedsSwap = FALSE;
  552.  
  553.         // try charset with explicit bytesex info (e.g. "UCS-4LE"):
  554.         ms_wcCharsetName = WC_NAME_BEST;
  555.         m2w = iconv_open(ms_wcCharsetName, cname);
  556.  
  557.         if (m2w == (iconv_t)-1)
  558.         {
  559.             // try charset w/o bytesex info (e.g. "UCS4")
  560.             // and check for bytesex ourselves:
  561.             ms_wcCharsetName = WC_NAME;
  562.             m2w = iconv_open(ms_wcCharsetName, cname);
  563.  
  564.             // last bet, try if it knows WCHAR_T pseudo-charset
  565.             if (m2w == (iconv_t)-1)
  566.             {
  567.                 ms_wcCharsetName = "WCHAR_T";
  568.                 m2w = iconv_open(ms_wcCharsetName, cname);
  569.             }
  570.  
  571.             if (m2w != (iconv_t)-1)
  572.             {
  573.                 char    buf[2], *bufPtr;
  574.                 wchar_t wbuf[2], *wbufPtr;
  575.                 size_t  insz, outsz;
  576.                 size_t  res;
  577.  
  578.                 buf[0] = 'A';
  579.                 buf[1] = 0;
  580.                 wbuf[0] = 0;
  581.                 insz = 2;
  582.                 outsz = SIZEOF_WCHAR_T * 2;
  583.                 wbufPtr = wbuf;
  584.                 bufPtr = buf;
  585.  
  586.                 res = iconv(m2w, ICONV_CHAR_CAST(&bufPtr), &insz,
  587.                             (char**)&wbufPtr, &outsz);
  588.  
  589.                 if (ICONV_FAILED(res, insz))
  590.                 {
  591.                     ms_wcCharsetName = NULL;
  592.                     wxLogLastError(wxT("iconv"));
  593.                     wxLogError(_("Convertion to charset '%s' doesn't work."), name);
  594.                 }
  595.                 else
  596.                 {
  597.                     ms_wcNeedsSwap = wbuf[0] != (wchar_t)buf[0];
  598.                 }
  599.             }
  600.             else
  601.             {
  602.                 ms_wcCharsetName = NULL;
  603.  
  604.                 // VS: we must not output an error here, since wxWindows will safely
  605.                 //     fall back to using wxEncodingConverter.
  606.                 wxLogTrace(wxT("strconv"), wxT("Impossible to convert to/from charset '%s' with iconv, falling back to wxEncodingConverter."), name);
  607.                 //wxLogError(
  608.             }
  609.         }
  610.         wxLogTrace(wxT("strconv"), wxT("wchar_t charset is '%s', needs swap: %i"), ms_wcCharsetName, ms_wcNeedsSwap);
  611.     }
  612.     else // we already have ms_wcCharsetName
  613.     {
  614.         m2w = iconv_open(ms_wcCharsetName, cname);
  615.     }
  616.  
  617.     // NB: don't ever pass NULL to iconv_open(), it may crash!
  618.     if ( ms_wcCharsetName )
  619.     {
  620.         w2m = iconv_open( cname, ms_wcCharsetName);
  621.     }
  622.     else
  623.     {
  624.         w2m = (iconv_t)-1;
  625.     }
  626. }
  627.  
  628. IC_CharSet::~IC_CharSet()
  629. {
  630.     if ( m2w != (iconv_t)-1 )
  631.         iconv_close(m2w);
  632.     if ( w2m != (iconv_t)-1 )
  633.         iconv_close(w2m);
  634. }
  635.  
  636. size_t IC_CharSet::MB2WC(wchar_t *buf, const char *psz, size_t n)
  637. {
  638.     size_t inbuf = strlen(psz);
  639.     size_t outbuf = n * SIZEOF_WCHAR_T;
  640.     size_t res, cres;
  641.     // VS: Use these instead of psz, buf because iconv() modifies its arguments:
  642.     wchar_t *bufPtr = buf;
  643.     const char *pszPtr = psz;
  644.  
  645.     if (buf)
  646.     {
  647.         // have destination buffer, convert there
  648.         cres = iconv(m2w,
  649.                      ICONV_CHAR_CAST(&pszPtr), &inbuf,
  650.                      (char**)&bufPtr, &outbuf);
  651.         res = n - (outbuf / SIZEOF_WCHAR_T);
  652.  
  653.         if (ms_wcNeedsSwap)
  654.         {
  655.             // convert to native endianness
  656.             WC_BSWAP(buf /* _not_ bufPtr */, res)
  657.         }
  658.         
  659.         // NB: iconv was given only strlen(psz) characters on input, and so
  660.         //     it couldn't convert the trailing zero. Let's do it ourselves
  661.         //     if there's some room left for it in the output buffer.
  662.         if (res < n)
  663.             buf[res] = 0;
  664.     }
  665.     else
  666.     {
  667.         // no destination buffer... convert using temp buffer
  668.         // to calculate destination buffer requirement
  669.         wchar_t tbuf[8];
  670.         res = 0;
  671.         do {
  672.             bufPtr = tbuf;
  673.             outbuf = 8*SIZEOF_WCHAR_T;
  674.  
  675.             cres = iconv(m2w,
  676.                          ICONV_CHAR_CAST(&pszPtr), &inbuf,
  677.                          (char**)&bufPtr, &outbuf );
  678.  
  679.             res += 8-(outbuf/SIZEOF_WCHAR_T);
  680.         } while ((cres==(size_t)-1) && (errno==E2BIG));
  681.     }
  682.  
  683.     if (ICONV_FAILED(cres, inbuf))
  684.     {
  685.         //VS: it is ok if iconv fails, hence trace only
  686.         wxLogTrace(wxT("strconv"), wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode()));
  687.         return (size_t)-1;
  688.     }
  689.  
  690.     return res;
  691. }
  692.  
  693. size_t IC_CharSet::WC2MB(char *buf, const wchar_t *psz, size_t n)
  694. {
  695. #if defined(__BORLANDC__) && (__BORLANDC__ > 0x530)
  696.     size_t inbuf = std::wcslen(psz) * SIZEOF_WCHAR_T;
  697. #else
  698.     size_t inbuf = ::wcslen(psz) * SIZEOF_WCHAR_T;
  699. #endif
  700.     size_t outbuf = n;
  701.     size_t res, cres;
  702.  
  703.     wchar_t *tmpbuf = 0;
  704.  
  705.     if (ms_wcNeedsSwap)
  706.     {
  707.         // need to copy to temp buffer to switch endianness
  708.         // this absolutely doesn't rock!
  709.         // (no, doing WC_BSWAP twice on the original buffer won't help, as it
  710.         //  could be in read-only memory, or be accessed in some other thread)
  711.         tmpbuf=(wchar_t*)malloc((inbuf+1)*SIZEOF_WCHAR_T);
  712.         memcpy(tmpbuf,psz,(inbuf+1)*SIZEOF_WCHAR_T);
  713.         WC_BSWAP(tmpbuf, inbuf)
  714.         psz=tmpbuf;
  715.     }
  716.  
  717.     if (buf)
  718.     {
  719.         // have destination buffer, convert there
  720.         cres = iconv( w2m, ICONV_CHAR_CAST(&psz), &inbuf, &buf, &outbuf );
  721.  
  722.         res = n-outbuf;
  723.         
  724.         // NB: iconv was given only wcslen(psz) characters on input, and so
  725.         //     it couldn't convert the trailing zero. Let's do it ourselves
  726.         //     if there's some room left for it in the output buffer.
  727.         if (res < n)
  728.             buf[0] = 0;
  729.     }
  730.     else
  731.     {
  732.         // no destination buffer... convert using temp buffer
  733.         // to calculate destination buffer requirement
  734.         char tbuf[16];
  735.         res = 0;
  736.         do {
  737.             buf = tbuf; outbuf = 16;
  738.  
  739.             cres = iconv( w2m, ICONV_CHAR_CAST(&psz), &inbuf, &buf, &outbuf );
  740.  
  741.             res += 16 - outbuf;
  742.         } while ((cres==(size_t)-1) && (errno==E2BIG));
  743.     }
  744.  
  745.     if (ms_wcNeedsSwap)
  746.     {
  747.         free(tmpbuf);
  748.     }
  749.  
  750.     if (ICONV_FAILED(cres, inbuf))
  751.     {
  752.         //VS: it is ok if iconv fails, hence trace only
  753.         wxLogTrace(wxT("strconv"), wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode()));
  754.         return (size_t)-1;
  755.     }
  756.  
  757.     return res;
  758. }
  759.  
  760. #endif // HAVE_ICONV
  761.  
  762. // ============================================================================
  763. // Win32 conversion classes
  764. // ============================================================================
  765.  
  766. #if defined(__WIN32__) && !defined(__WXMICROWIN__)
  767.  
  768. extern long wxCharsetToCodepage(const wxChar *charset); // from utils.cpp
  769.  
  770. class CP_CharSet : public wxCharacterSet
  771. {
  772. public:
  773.     CP_CharSet(const wxChar* name)
  774.         : wxCharacterSet(name)
  775.         {
  776.             m_CodePage = wxCharsetToCodepage(name);
  777.         }
  778.  
  779.     size_t MB2WC(wchar_t *buf, const char *psz, size_t n)
  780.     {
  781.         size_t len =
  782. #ifdef __WXWINE__
  783.             MultiByteToWideChar(m_CodePage, 0, psz, -1, (WCHAR*) buf, buf ? n : 0);
  784. #else
  785.             MultiByteToWideChar(m_CodePage, 0, psz, -1, buf, buf ? n : 0);
  786. #endif
  787.         //VS: returns # of written chars for buf!=NULL and *size*
  788.         //    needed buffer for buf==NULL
  789.         return len ? (buf ? len : len-1) : (size_t)-1;
  790.     }
  791.  
  792.     size_t WC2MB(char *buf, const wchar_t *psz, size_t n)
  793.     {
  794. #ifdef __WXWINE__
  795.         size_t len = WideCharToMultiByte(m_CodePage, 0, (const WCHAR*) psz, -1, buf,
  796.                                          buf ? n : 0, NULL, NULL);
  797. #else
  798.         size_t len = WideCharToMultiByte(m_CodePage, 0, psz, -1, buf,
  799.                                          buf ? n : 0, NULL, NULL);
  800. #endif
  801.         //VS: returns # of written chars for buf!=NULL and *size*
  802.         //    needed buffer for buf==NULL
  803.         return len ? (buf ? len : len-1) : (size_t)-1;
  804.     }
  805.  
  806.     bool usable() const
  807.         { return m_CodePage != -1; }
  808.  
  809. public:
  810.     long m_CodePage;
  811. };
  812. #endif // __WIN32__
  813.  
  814. // ============================================================================
  815. // wxEncodingConverter based conversion classes
  816. // ============================================================================
  817.  
  818. #if wxUSE_FONTMAP
  819.  
  820. class EC_CharSet : public wxCharacterSet
  821. {
  822. public:
  823.     // temporarily just use wxEncodingConverter stuff,
  824.     // so that it works while a better implementation is built
  825.     EC_CharSet(const wxChar* name) : wxCharacterSet(name),
  826.                                      enc(wxFONTENCODING_SYSTEM)
  827.     {
  828.         if (name)
  829.             enc = wxFontMapper::Get()->CharsetToEncoding(name, FALSE);
  830.  
  831.         m_ok = m2w.Init(enc, wxFONTENCODING_UNICODE) &&
  832.                w2m.Init(wxFONTENCODING_UNICODE, enc);
  833.     }
  834.  
  835.     size_t MB2WC(wchar_t *buf, const char *psz, size_t WXUNUSED(n))
  836.     {
  837.         size_t inbuf = strlen(psz);
  838.         if (buf)
  839.             m2w.Convert(psz,buf);
  840.         return inbuf;
  841.     }
  842.  
  843.     size_t WC2MB(char *buf, const wchar_t *psz, size_t WXUNUSED(n))
  844.     {
  845. #if ( defined(__BORLANDC__) && (__BORLANDC__ > 0x530) ) \
  846.     || ( defined(__MWERKS__) && defined(__WXMSW__) )
  847.         size_t inbuf = std::wcslen(psz);
  848. #else
  849.         size_t inbuf = ::wcslen(psz);
  850. #endif
  851.         if (buf)
  852.             w2m.Convert(psz,buf);
  853.  
  854.         return inbuf;
  855.     }
  856.  
  857.     bool usable() const { return m_ok; }
  858.  
  859. public:
  860.     wxFontEncoding enc;
  861.     wxEncodingConverter m2w, w2m;
  862.  
  863.     // were we initialized successfully?
  864.     bool m_ok;
  865. };
  866.  
  867. #endif // wxUSE_FONTMAP
  868.  
  869. // ----------------------------------------------------------------------------
  870. // the function creating the wxCharacterSet for the specified charset on the
  871. // current system, trying all possibilities
  872. // ----------------------------------------------------------------------------
  873.  
  874. static wxCharacterSet *wxGetCharacterSet(const wxChar *name)
  875. {
  876.     // check for the special case of ASCII charset
  877. #if wxUSE_FONTMAP
  878.     if ( wxFontMapper::Get()->CharsetToEncoding(name) == wxFONTENCODING_DEFAULT )
  879. #else // wxUSE_FONTMAP
  880.     if ( !name )
  881. #endif // wxUSE_FONTMAP/!wxUSE_FONTMAP
  882.     {
  883.         // don't convert at all
  884.         return NULL;
  885.     }
  886.  
  887.     // the test above must have taken care of this case
  888.     wxCHECK_MSG( name, NULL, _T("NULL name must be wxFONTENCODING_DEFAULT") );
  889.  
  890.     wxCharacterSet *cset;
  891.  
  892.     if ( wxStricmp(name, wxT("UTF8")) == 0 || wxStricmp(name, wxT("UTF-8")) == 0)
  893.     {
  894.         cset = new ID_CharSet(name, &wxConvUTF8);
  895.     }
  896.     else
  897.     {
  898. #ifdef HAVE_ICONV
  899.         cset = new IC_CharSet(name);
  900. #else // !HAVE_ICONV
  901.         cset = NULL;
  902. #endif // HAVE_ICONV/!HAVE_ICONV
  903.     }
  904.  
  905.     // it can only be NULL in this case
  906. #ifndef HAVE_ICONV
  907.     if ( cset )
  908. #endif // !HAVE_ICONV
  909.     {
  910.         if ( cset->usable() )
  911.             return cset;
  912.  
  913.         delete cset;
  914.         cset = NULL;
  915.     }
  916.  
  917. #if defined(__WIN32__) && !defined(__WXMICROWIN__)
  918.     cset = new CP_CharSet(name);
  919.     if ( cset->usable() )
  920.         return cset;
  921.  
  922.     delete cset;
  923.     cset = NULL;
  924. #endif // __WIN32__
  925.  
  926. #if wxUSE_FONTMAP
  927.     cset = new EC_CharSet(name);
  928.     if ( cset->usable() )
  929.         return cset;
  930.  
  931.     delete cset;
  932.     cset = NULL;
  933. #endif // wxUSE_FONTMAP
  934.  
  935.     wxLogError(_("Cannot convert from encoding '%s'!"), name);
  936.  
  937.     return NULL;
  938. }
  939.  
  940. // ============================================================================
  941. // wxCSConv implementation
  942. // ============================================================================
  943.  
  944. wxCSConv::wxCSConv(const wxChar *charset)
  945. {
  946.     m_name = (wxChar *)NULL;
  947.     m_cset = (wxCharacterSet *) NULL;
  948.     m_deferred = TRUE;
  949.  
  950.     SetName(charset);
  951. }
  952.  
  953. wxCSConv::~wxCSConv()
  954. {
  955.     Clear();
  956. }
  957.  
  958. wxCSConv::wxCSConv(const wxCSConv& conv)
  959.     : wxMBConv()
  960. {
  961.     Clear();
  962.     SetName(conv.m_name);
  963. }
  964.  
  965. wxCSConv& wxCSConv::operator=(const wxCSConv& conv)
  966. {
  967.     Clear();
  968.     SetName(conv.m_name);
  969.     return *this;
  970. }
  971.  
  972. void wxCSConv::Clear()
  973. {
  974.     if (m_name)
  975.         free(m_name);
  976.     if (m_cset)
  977.         delete m_cset;
  978.     m_name = NULL;
  979.     m_cset = NULL;
  980. }
  981.  
  982. void wxCSConv::SetName(const wxChar *charset)
  983. {
  984.     if (charset)
  985.     {
  986.         m_name = wxStrdup(charset);
  987.         m_deferred = TRUE;
  988.     }
  989. }
  990.  
  991. void wxCSConv::LoadNow()
  992. {
  993.     if (m_deferred)
  994.     {
  995.         if ( !m_name )
  996.         {
  997.             wxString name = wxLocale::GetSystemEncodingName();
  998.             if ( !name.empty() )
  999.             {
  1000.                 SetName(name);
  1001.             }
  1002.         }
  1003.  
  1004.         // wxGetCharacterSet() complains about NULL name
  1005.         m_cset = m_name ? wxGetCharacterSet(m_name) : NULL;
  1006.         m_deferred = FALSE;
  1007.     }
  1008. }
  1009.  
  1010. size_t wxCSConv::MB2WC(wchar_t *buf, const char *psz, size_t n) const
  1011. {
  1012.     ((wxCSConv *)this)->LoadNow(); // discard constness
  1013.  
  1014.     if (m_cset)
  1015.         return m_cset->MB2WC(buf, psz, n);
  1016.  
  1017.     // latin-1 (direct)
  1018.     size_t len = strlen(psz);
  1019.  
  1020.     if (buf)
  1021.     {
  1022.         for (size_t c = 0; c <= len; c++)
  1023.             buf[c] = (unsigned char)(psz[c]);
  1024.     }
  1025.  
  1026.     return len;
  1027. }
  1028.  
  1029. size_t wxCSConv::WC2MB(char *buf, const wchar_t *psz, size_t n) const
  1030. {
  1031.     ((wxCSConv *)this)->LoadNow(); // discard constness
  1032.  
  1033.     if (m_cset)
  1034.         return m_cset->WC2MB(buf, psz, n);
  1035.  
  1036.     // latin-1 (direct)
  1037. #if ( defined(__BORLANDC__) && (__BORLANDC__ > 0x530) ) \
  1038.     || ( defined(__MWERKS__) && defined(__WXMSW__) )
  1039.     size_t len=std::wcslen(psz);
  1040. #else
  1041.     size_t len=::wcslen(psz);
  1042. #endif
  1043.     if (buf)
  1044.     {
  1045.         for (size_t c = 0; c <= len; c++)
  1046.             buf[c] = (psz[c] > 0xff) ? '?' : psz[c];
  1047.     }
  1048.  
  1049.     return len;
  1050. }
  1051.  
  1052. #endif // wxUSE_WCHAR_T
  1053.  
  1054.  
  1055.