]> git.saurik.com Git - wxWidgets.git/blobdiff - src/common/strconv.cpp
fixing file paths after renaming
[wxWidgets.git] / src / common / strconv.cpp
index 91186b40c69db828d9b9d909546ed28bb6653b15..507bf1307b042ea439a3e7afc6a8eefe23e392b8 100644 (file)
     #define wxHAVE_WIN32_MB2WC
 #endif
 
     #define wxHAVE_WIN32_MB2WC
 #endif
 
-#ifdef __SALFORDC__
-    #include <clib.h>
-#endif
-
 #ifdef HAVE_ICONV
     #include <iconv.h>
     #include "wx/thread.h"
 #ifdef HAVE_ICONV
     #include <iconv.h>
     #include "wx/thread.h"
@@ -57,7 +53,7 @@
 #include "wx/fontmap.h"
 
 #ifdef __DARWIN__
 #include "wx/fontmap.h"
 
 #ifdef __DARWIN__
-#include "wx/mac/corefoundation/private/strconv_cf.h"
+#include "wx/osx/core/private/strconv_cf.h"
 #endif //def __DARWIN__
 
 
 #endif //def __DARWIN__
 
 
@@ -391,7 +387,11 @@ wxMBConv::cMB2WC(const char *inBuff, size_t inLen, size_t *outLen) const
     const size_t dstLen = ToWChar(NULL, 0, inBuff, inLen);
     if ( dstLen != wxCONV_FAILED )
     {
     const size_t dstLen = ToWChar(NULL, 0, inBuff, inLen);
     if ( dstLen != wxCONV_FAILED )
     {
-        wxWCharBuffer wbuf(dstLen - 1);
+        // notice that we allocate space for dstLen+1 wide characters here
+        // because we want the buffer to always be NUL-terminated, even if the
+        // input isn't (as otherwise the caller has no way to know its length)
+        wxWCharBuffer wbuf(dstLen);
+        wbuf.data()[dstLen - 1] = L'\0';
         if ( ToWChar(wbuf.data(), dstLen, inBuff, inLen) != wxCONV_FAILED )
         {
             if ( outLen )
         if ( ToWChar(wbuf.data(), dstLen, inBuff, inLen) != wxCONV_FAILED )
         {
             if ( outLen )
@@ -417,16 +417,18 @@ wxMBConv::cWC2MB(const wchar_t *inBuff, size_t inLen, size_t *outLen) const
     size_t dstLen = FromWChar(NULL, 0, inBuff, inLen);
     if ( dstLen != wxCONV_FAILED )
     {
     size_t dstLen = FromWChar(NULL, 0, inBuff, inLen);
     if ( dstLen != wxCONV_FAILED )
     {
-        // special case of empty input: can't allocate 0 size buffer below as
-        // wxCharBuffer insists on NUL-terminating it
-        wxCharBuffer buf(dstLen ? dstLen - 1 : 1);
+        const size_t nulLen = GetMBNulLen();
+
+        // as above, ensure that the buffer is always NUL-terminated, even if
+        // the input is not
+        wxCharBuffer buf(dstLen + nulLen - 1);
+        memset(buf.data() + dstLen, 0, nulLen);
         if ( FromWChar(buf.data(), dstLen, inBuff, inLen) != wxCONV_FAILED )
         {
             if ( outLen )
             {
                 *outLen = dstLen;
 
         if ( FromWChar(buf.data(), dstLen, inBuff, inLen) != wxCONV_FAILED )
         {
             if ( outLen )
             {
                 *outLen = dstLen;
 
-                const size_t nulLen = GetMBNulLen();
                 if ( dstLen >= nulLen &&
                         !NotAllNULs(buf.data() + dstLen - nulLen, nulLen) )
                 {
                 if ( dstLen >= nulLen &&
                         !NotAllNULs(buf.data() + dstLen - nulLen, nulLen) )
                 {
@@ -482,6 +484,8 @@ wxConvBrokenFileNames::wxConvBrokenFileNames(const wxString& charset)
 // ----------------------------------------------------------------------------
 
 // Implementation (C) 2004 Fredrik Roubert
 // ----------------------------------------------------------------------------
 
 // Implementation (C) 2004 Fredrik Roubert
+//
+// Changes to work in streaming mode (C) 2008 Vadim Zeitlin
 
 //
 // BASE64 decoding table
 
 //
 // BASE64 decoding table
@@ -519,73 +523,134 @@ static const unsigned char utf7unb64[] =
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
-    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+    0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 
 };
 
 };
 
-size_t wxMBConvUTF7::MB2WC(wchar_t *buf, const char *psz, size_t n) const
+size_t wxMBConvUTF7::ToWChar(wchar_t *dst, size_t dstLen,
+                             const char *src, size_t srcLen) const
 {
 {
+    DecoderState stateOrig,
+         *statePtr;
+    if ( srcLen == wxNO_LEN )
+    {
+        // convert the entire string, up to and including the trailing NUL
+        srcLen = strlen(src) + 1;
+
+        // when working on the entire strings we don't update nor use the shift
+        // state from the previous call
+        statePtr = &stateOrig;
+    }
+    else // when working with partial strings we do use the shift state
+    {
+        statePtr = wx_const_cast(DecoderState *, &m_stateDecoder);
+
+        // also save the old state to be able to rollback to it on error
+        stateOrig = m_stateDecoder;
+    }
+
+    // but to simplify the code below we use this variable in both cases
+    DecoderState& state = *statePtr;
+
+
+    // number of characters [which would have been] written to dst [if it were
+    // not NULL]
     size_t len = 0;
 
     size_t len = 0;
 
-    while ( *psz && (!buf || (len < n)) )
+    const char * const srcEnd = src + srcLen;
+
+    while ( (src < srcEnd) && (!dst || (len < dstLen)) )
     {
     {
-        unsigned char cc = *psz++;
-        if (cc != '+')
-        {
-            // plain ASCII char
-            if (buf)
-                *buf++ = cc;
-            len++;
-        }
-        else if (*psz == '-')
-        {
-            // encoded plus sign
-            if (buf)
-                *buf++ = cc;
-            len++;
-            psz++;
-        }
-        else // start of BASE64 encoded string
+        const unsigned char cc = *src++;
+
+        if ( state.IsShifted() )
         {
         {
-            bool lsb, ok;
-            unsigned int d, l;
-            for ( ok = lsb = false, d = 0, l = 0;
-                  (cc = utf7unb64[(unsigned char)*psz]) != 0xff;
-                  psz++ )
+            const unsigned char dc = utf7unb64[cc];
+            if ( dc == 0xff )
+            {
+                // end of encoded part
+                state.ToDirect();
+
+                // re-parse this character normally below unless it's '-' which
+                // is consumed by the decoder
+                if ( cc == '-' )
+                    continue;
+            }
+            else // valid encoded character
             {
             {
-                d <<= 6;
-                d += cc;
-                for (l += 6; l >= 8; lsb = !lsb)
+                // mini base64 decoder: each character is 6 bits
+                state.bit += 6;
+                state.accum <<= 6;
+                state.accum += dc;
+
+                if ( state.bit >= 8 )
                 {
                 {
-                    unsigned char c = (unsigned char)((d >> (l -= 8)) % 256);
-                    if (lsb)
+                    // got the full byte, consume it
+                    state.bit -= 8;
+                    unsigned char b = (state.accum >> state.bit) & 0x00ff;
+
+                    if ( state.isLSB )
                     {
                     {
-                        if (buf)
-                            *buf++ |= c;
-                        len ++;
+                        // we've got the full word, output it
+                        if ( dst )
+                            *dst++ = (state.msb << 8) | b;
+                        len++;
+                        state.isLSB = false;
                     }
                     }
-                    else
+                    else // MSB
                     {
                     {
-                        if (buf)
-                            *buf = (wchar_t)(c << 8);
+                        // just store it while we wait for LSB
+                        state.msb = b;
+                        state.isLSB = true;
                     }
                     }
-
-                    ok = true;
                 }
             }
                 }
             }
+        }
 
 
-            if ( !ok )
+        if ( state.IsDirect() )
+        {
+            // start of an encoded segment?
+            if ( cc == '+' )
             {
             {
-                // in valid UTF7 we should have valid characters after '+'
-                return wxCONV_FAILED;
+                if ( src == srcEnd )
+                    return wxCONV_FAILED; // can't have '+' at the end
+
+                if ( *src == '-' )
+                {
+                    // just the encoded plus sign, don't switch to shifted mode
+                    if ( dst )
+                        *dst++ = '+';
+                    len++;
+                    src++;
+                }
+                else
+                {
+                    state.ToShifted();
+                }
             }
             }
+            else // not '+'
+            {
+                // only printable 7 bit ASCII characters (with the exception of
+                // NUL, TAB, CR and LF) can be used directly
+                if ( cc >= 0x7f || (cc < ' ' &&
+                      !(cc == '\0' || cc == '\t' || cc == '\r' || cc == '\n')) )
+                    return wxCONV_FAILED;
 
 
-            if (*psz == '-')
-                psz++;
+                if ( dst )
+                    *dst++ = cc;
+                len++;
+            }
         }
     }
 
         }
     }
 
-    if ( buf && (len < n) )
-        *buf = '\0';
+    if ( !len )
+    {
+        // as we didn't read any characters we should be called with the same
+        // data (followed by some more new data) again later so don't save our
+        // state
+        state = stateOrig;
+
+        return wxCONV_FAILED;
+    }
 
     return len;
 }
 
     return len;
 }
@@ -615,7 +680,7 @@ static const unsigned char utf7enb64[] =
 //
 static const unsigned char utf7encode[128] =
 {
 //
 static const unsigned char utf7encode[128] =
 {
-    3, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3,
+    0, 3, 3, 3, 3, 3, 3, 3, 3, 2, 2, 3, 3, 2, 3, 3,
     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
     2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 3, 0, 0, 0, 3,
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
     3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
     2, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 3, 0, 0, 0, 3,
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0,
@@ -625,21 +690,72 @@ static const unsigned char utf7encode[128] =
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 3, 3
 };
 
     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 3, 3
 };
 
-size_t wxMBConvUTF7::WC2MB(char *buf, const wchar_t *psz, size_t n) const
+static inline bool wxIsUTF7Direct(wchar_t wc)
 {
 {
+    return wc < 0x80 && utf7encode[wc] < 1;
+}
+
+size_t wxMBConvUTF7::FromWChar(char *dst, size_t dstLen,
+                               const wchar_t *src, size_t srcLen) const
+{
+    EncoderState stateOrig,
+                *statePtr;
+    if ( srcLen == wxNO_LEN )
+    {
+        // we don't apply the stored state when operating on entire strings at
+        // once
+        statePtr = &stateOrig;
+
+        srcLen = wxWcslen(src) + 1;
+    }
+    else // do use the mode we left the output in previously
+    {
+        stateOrig = m_stateEncoder;
+        statePtr = wx_const_cast(EncoderState *, &m_stateEncoder);
+    }
+
+    EncoderState& state = *statePtr;
+
+
     size_t len = 0;
 
     size_t len = 0;
 
-    while (*psz && ((!buf) || (len < n)))
+    const wchar_t * const srcEnd = src + srcLen;
+    while ( src < srcEnd && (!dst || len < dstLen) )
     {
     {
-        wchar_t cc = *psz++;
-        if (cc < 0x80 && utf7encode[cc] < 1)
+        wchar_t cc = *src++;
+        if ( wxIsUTF7Direct(cc) )
         {
         {
-            // plain ASCII char
-            if (buf)
-                *buf++ = (char)cc;
+            if ( state.IsShifted() )
+            {
+                // pad with zeros the last encoded block if necessary
+                if ( state.bit )
+                {
+                    if ( dst )
+                        *dst++ = utf7enb64[((state.accum % 16) << (6 - state.bit)) % 64];
+                    len++;
+                }
+
+                state.ToDirect();
+
+                if ( dst )
+                    *dst++ = '-';
+                len++;
+            }
 
 
+            if ( dst )
+                *dst++ = (char)cc;
             len++;
         }
             len++;
         }
+        else if ( cc == '+' && state.IsDirect() )
+        {
+            if ( dst )
+            {
+                *dst++ = '+';
+                *dst++ = '-';
+            }
+
+            len += 2;
+        }
 #ifndef WC_UTF16
         else if (((wxUint32)cc) > 0xffff)
         {
 #ifndef WC_UTF16
         else if (((wxUint32)cc) > 0xffff)
         {
@@ -649,52 +765,45 @@ size_t wxMBConvUTF7::WC2MB(char *buf, const wchar_t *psz, size_t n) const
 #endif
         else
         {
 #endif
         else
         {
-            if (buf)
-                *buf++ = '+';
+            if ( state.IsDirect() )
+            {
+                state.ToShifted();
 
 
-            len++;
-            if (cc != '+')
+                if ( dst )
+                    *dst++ = '+';
+                len++;
+            }
+
+            // BASE64 encode string
+            for ( ;; )
             {
             {
-                // BASE64 encode string
-                unsigned int lsb, d, l;
-                for (d = 0, l = 0; /*nothing*/; psz++)
+                for ( unsigned lsb = 0; lsb < 2; lsb++ )
                 {
                 {
-                    for (lsb = 0; lsb < 2; lsb ++)
-                    {
-                        d <<= 8;
-                        d += lsb ? cc & 0xff : (cc & 0xff00) >> 8;
+                    state.accum <<= 8;
+                    state.accum += lsb ? cc & 0xff : (cc & 0xff00) >> 8;
 
 
-                        for (l += 8; l >= 6; )
-                        {
-                            l -= 6;
-                            if (buf)
-                                *buf++ = utf7enb64[(d >> l) % 64];
-                            len++;
-                        }
+                    for (state.bit += 8; state.bit >= 6; )
+                    {
+                        state.bit -= 6;
+                        if ( dst )
+                            *dst++ = utf7enb64[(state.accum >> state.bit) % 64];
+                        len++;
                     }
                     }
-
-                    cc = *psz;
-                    if (!(cc) || (cc < 0x80 && utf7encode[cc] < 1))
-                        break;
                 }
 
                 }
 
-                if (l != 0)
-                {
-                    if (buf)
-                        *buf++ = utf7enb64[((d % 16) << (6 - l)) % 64];
+                if ( src == srcEnd || wxIsUTF7Direct(cc = *src) )
+                    break;
 
 
-                    len++;
-                }
+                src++;
             }
             }
-
-            if (buf)
-                *buf++ = '-';
-            len++;
         }
     }
 
         }
     }
 
-    if (buf && (len < n))
-        *buf = 0;
+    // we need to restore the original encoder state if we were called just to
+    // calculate the amount of space needed as we will presumably be called
+    // again to really convert the data now
+    if ( !dst )
+        state = stateOrig;
 
     return len;
 }
 
     return len;
 }
@@ -878,7 +987,7 @@ wxMBConvStrictUTF8::FromWChar(char *dst, size_t dstLen,
 
     for ( const wchar_t *wp = src; ; wp++ )
     {
 
     for ( const wchar_t *wp = src; ; wp++ )
     {
-        if ( !(srcLen == wxNO_LEN ? *wp : srcLen--) )
+        if ( !(srcLen == wxNO_LEN ? *wp : srcLen) )
         {
             // all done successfully, just add the trailing NULL if we are not
             // using explicit length
         {
             // all done successfully, just add the trailing NULL if we are not
             // using explicit length
@@ -898,6 +1007,8 @@ wxMBConvStrictUTF8::FromWChar(char *dst, size_t dstLen,
             return written;
         }
 
             return written;
         }
 
+        if ( srcLen != wxNO_LEN )
+            srcLen--;
 
         wxUint32 code;
 #ifdef WC_UTF16
 
         wxUint32 code;
 #ifdef WC_UTF16
@@ -983,14 +1094,15 @@ wxMBConvStrictUTF8::FromWChar(char *dst, size_t dstLen,
     return wxCONV_FAILED;
 }
 
     return wxCONV_FAILED;
 }
 
-size_t wxMBConvUTF8::MB2WC(wchar_t *buf, const char *psz, size_t n) const
+size_t wxMBConvUTF8::ToWChar(wchar_t *buf, size_t n,
+                             const char *psz, size_t srcLen) const
 {
     if ( m_options == MAP_INVALID_UTF8_NOT )
 {
     if ( m_options == MAP_INVALID_UTF8_NOT )
-        return wxMBConvStrictUTF8::MB2WC(buf, psz, n);
+        return wxMBConvStrictUTF8::ToWChar(buf, n, psz, srcLen);
 
     size_t len = 0;
 
 
     size_t len = 0;
 
-    while (*psz && ((!buf) || (len < n)))
+    while ((srcLen == wxNO_LEN ? *psz : srcLen--) && ((!buf) || (len < n)))
     {
         const char *opsz = psz;
         bool invalid = false;
     {
         const char *opsz = psz;
         bool invalid = false;
@@ -1124,10 +1236,10 @@ size_t wxMBConvUTF8::MB2WC(wchar_t *buf, const char *psz, size_t n) const
         }
     }
 
         }
     }
 
-    if (buf && (len < n))
+    if (srcLen == wxNO_LEN && buf && (len < n))
         *buf = 0;
 
         *buf = 0;
 
-    return len;
+    return len + 1;
 }
 
 static inline bool isoctal(wchar_t wch)
 }
 
 static inline bool isoctal(wchar_t wch)
@@ -1135,14 +1247,15 @@ static inline bool isoctal(wchar_t wch)
     return L'0' <= wch && wch <= L'7';
 }
 
     return L'0' <= wch && wch <= L'7';
 }
 
-size_t wxMBConvUTF8::WC2MB(char *buf, const wchar_t *psz, size_t n) const
+size_t wxMBConvUTF8::FromWChar(char *buf, size_t n,
+                               const wchar_t *psz, size_t srcLen) const
 {
     if ( m_options == MAP_INVALID_UTF8_NOT )
 {
     if ( m_options == MAP_INVALID_UTF8_NOT )
-        return wxMBConvStrictUTF8::WC2MB(buf, psz, n);
+        return wxMBConvStrictUTF8::FromWChar(buf, n, psz, srcLen);
 
     size_t len = 0;
 
 
     size_t len = 0;
 
-    while (*psz && ((!buf) || (len < n)))
+    while ((srcLen == wxNO_LEN ? *psz : srcLen--) && ((!buf) || (len < n)))
     {
         wxUint32 cc;
 
     {
         wxUint32 cc;
 
@@ -1210,10 +1323,10 @@ size_t wxMBConvUTF8::WC2MB(char *buf, const wchar_t *psz, size_t n) const
         }
     }
 
         }
     }
 
-    if (buf && (len < n))
+    if (srcLen == wxNO_LEN && buf && (len < n))
         *buf = 0;
 
         *buf = 0;
 
-    return len;
+    return len + 1;
 }
 
 // ============================================================================
 }
 
 // ============================================================================
@@ -1859,10 +1972,11 @@ public:
     wxMBConv_iconv(const char *name);
     virtual ~wxMBConv_iconv();
 
     wxMBConv_iconv(const char *name);
     virtual ~wxMBConv_iconv();
 
-    virtual size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const;
-    virtual size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const;
-
-    // classify this encoding as explained in wxMBConv::GetMBNulLen() comment
+    // implement base class virtual methods
+    virtual size_t ToWChar(wchar_t *dst, size_t dstLen,
+                           const char *src, size_t srcLen = wxNO_LEN) const;
+    virtual size_t FromWChar(char *dst, size_t dstLen,
+                             const wchar_t *src, size_t srcLen = wxNO_LEN) const;
     virtual size_t GetMBNulLen() const;
 
 #if wxUSE_UNICODE_UTF8
     virtual size_t GetMBNulLen() const;
 
 #if wxUSE_UNICODE_UTF8
@@ -1977,7 +2091,7 @@ wxMBConv_iconv::wxMBConv_iconv(const char *name)
                 if ( m2w != ICONV_T_INVALID )
                 {
                     char    buf[2], *bufPtr;
                 if ( m2w != ICONV_T_INVALID )
                 {
                     char    buf[2], *bufPtr;
-                    wchar_t wbuf[2], *wbufPtr;
+                    wchar_t wbuf[2];
                     size_t  insz, outsz;
                     size_t  res;
 
                     size_t  insz, outsz;
                     size_t  res;
 
@@ -1986,12 +2100,12 @@ wxMBConv_iconv::wxMBConv_iconv(const char *name)
                     wbuf[0] = 0;
                     insz = 2;
                     outsz = SIZEOF_WCHAR_T * 2;
                     wbuf[0] = 0;
                     insz = 2;
                     outsz = SIZEOF_WCHAR_T * 2;
-                    wbufPtr = wbuf;
+                    char* wbufPtr = (char*)wbuf;
                     bufPtr = buf;
 
                     res = iconv(
                         m2w, ICONV_CHAR_CAST(&bufPtr), &insz,
                     bufPtr = buf;
 
                     res = iconv(
                         m2w, ICONV_CHAR_CAST(&bufPtr), &insz,
-                        (char**)&wbufPtr, &outsz);
+                        &wbufPtr, &outsz);
 
                     if (ICONV_FAILED(res, insz))
                     {
 
                     if (ICONV_FAILED(res, insz))
                     {
@@ -2048,33 +2162,47 @@ wxMBConv_iconv::~wxMBConv_iconv()
         iconv_close(w2m);
 }
 
         iconv_close(w2m);
 }
 
-size_t wxMBConv_iconv::MB2WC(wchar_t *buf, const char *psz, size_t n) const
+size_t
+wxMBConv_iconv::ToWChar(wchar_t *dst, size_t dstLen,
+                        const char *src, size_t srcLen) const
 {
 {
-    // find the string length: notice that must be done differently for
-    // NUL-terminated strings and UTF-16/32 which are terminated with 2/4 NULs
-    size_t inbuf;
-    const size_t nulLen = GetMBNulLen();
-    switch ( nulLen )
+    if ( srcLen == wxNO_LEN )
     {
     {
-        default:
-            return wxCONV_FAILED;
+        // find the string length: notice that must be done differently for
+        // NUL-terminated strings and UTF-16/32 which are terminated with 2/4
+        // consecutive NULs
+        const size_t nulLen = GetMBNulLen();
+        switch ( nulLen )
+        {
+            default:
+                return wxCONV_FAILED;
 
 
-        case 1:
-            inbuf = strlen(psz); // arguably more optimized than our version
-            break;
+            case 1:
+                srcLen = strlen(src); // arguably more optimized than our version
+                break;
 
 
-        case 2:
-        case 4:
-            // for UTF-16/32 not only we need to have 2/4 consecutive NULs but
-            // they also have to start at character boundary and not span two
-            // adjacent characters
-            const char *p;
-            for ( p = psz; NotAllNULs(p, nulLen); p += nulLen )
-                ;
-            inbuf = p - psz;
-            break;
+            case 2:
+            case 4:
+                // for UTF-16/32 not only we need to have 2/4 consecutive NULs
+                // but they also have to start at character boundary and not
+                // span two adjacent characters
+                const char *p;
+                for ( p = src; NotAllNULs(p, nulLen); p += nulLen )
+                    ;
+                srcLen = p - src;
+                break;
+        }
+
+        // when we're determining the length of the string ourselves we count
+        // the terminating NUL(s) as part of it and always NUL-terminate the
+        // output
+        srcLen += nulLen;
     }
 
     }
 
+    // we express length in the number of (wide) characters but iconv always
+    // counts buffer sizes it in bytes
+    dstLen *= SIZEOF_WCHAR_T;
+
 #if wxUSE_THREADS
     // NB: iconv() is MT-safe, but each thread must use its own iconv_t handle.
     //     Unfortunately there are a couple of global wxCSConv objects such as
 #if wxUSE_THREADS
     // NB: iconv() is MT-safe, but each thread must use its own iconv_t handle.
     //     Unfortunately there are a couple of global wxCSConv objects such as
@@ -2085,53 +2213,51 @@ size_t wxMBConv_iconv::MB2WC(wchar_t *buf, const char *psz, size_t n) const
     wxMutexLocker lock(wxConstCast(this, wxMBConv_iconv)->m_iconvMutex);
 #endif // wxUSE_THREADS
 
     wxMutexLocker lock(wxConstCast(this, wxMBConv_iconv)->m_iconvMutex);
 #endif // wxUSE_THREADS
 
-    size_t outbuf = n * SIZEOF_WCHAR_T;
     size_t res, cres;
     size_t res, cres;
-    // VS: Use these instead of psz, buf because iconv() modifies its arguments:
-    wchar_t *bufPtr = buf;
-    const char *pszPtr = psz;
+    const char *pszPtr = src;
 
 
-    if (buf)
+    if ( dst )
     {
     {
+        char* bufPtr = (char*)dst;
+
         // have destination buffer, convert there
         // have destination buffer, convert there
+        size_t dstLenOrig = dstLen;
         cres = iconv(m2w,
         cres = iconv(m2w,
-                     ICONV_CHAR_CAST(&pszPtr), &inbuf,
-                     (char**)&bufPtr, &outbuf);
-        res = n - (outbuf / SIZEOF_WCHAR_T);
+                     ICONV_CHAR_CAST(&pszPtr), &srcLen,
+                     &bufPtr, &dstLen);
+
+        // convert the number of bytes converted as returned by iconv to the
+        // number of (wide) characters converted that we need
+        res = (dstLenOrig - dstLen) / SIZEOF_WCHAR_T;
 
         if (ms_wcNeedsSwap)
         {
             // convert to native endianness
             for ( unsigned i = 0; i < res; i++ )
 
         if (ms_wcNeedsSwap)
         {
             // convert to native endianness
             for ( unsigned i = 0; i < res; i++ )
-                buf[n] = WC_BSWAP(buf[i]);
+                dst[i] = WC_BSWAP(dst[i]);
         }
         }
-
-        // NUL-terminate the string if there is any space left
-        if (res < n)
-            buf[res] = 0;
     }
     }
-    else
+    else // no destination buffer
     {
     {
-        // no destination buffer... convert using temp buffer
-        // to calculate destination buffer requirement
+        // convert using temp buffer to calculate the size of the buffer needed
         wchar_t tbuf[8];
         res = 0;
 
         do
         {
         wchar_t tbuf[8];
         res = 0;
 
         do
         {
-            bufPtr = tbuf;
-            outbuf = 8 * SIZEOF_WCHAR_T;
+            char* bufPtr = (char*)tbuf;
+            dstLen = 8 * SIZEOF_WCHAR_T;
 
             cres = iconv(m2w,
 
             cres = iconv(m2w,
-                         ICONV_CHAR_CAST(&pszPtr), &inbuf,
-                         (char**)&bufPtr, &outbuf );
+                         ICONV_CHAR_CAST(&pszPtr), &srcLen,
+                         &bufPtr, &dstLen );
 
 
-            res += 8 - (outbuf / SIZEOF_WCHAR_T);
+            res += 8 - (dstLen / SIZEOF_WCHAR_T);
         }
         while ((cres == (size_t)-1) && (errno == E2BIG));
     }
 
         }
         while ((cres == (size_t)-1) && (errno == E2BIG));
     }
 
-    if (ICONV_FAILED(cres, inbuf))
+    if (ICONV_FAILED(cres, srcLen))
     {
         //VS: it is ok if iconv fails, hence trace only
         wxLogTrace(TRACE_STRCONV, wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode()));
     {
         //VS: it is ok if iconv fails, hence trace only
         wxLogTrace(TRACE_STRCONV, wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode()));
@@ -2141,16 +2267,19 @@ size_t wxMBConv_iconv::MB2WC(wchar_t *buf, const char *psz, size_t n) const
     return res;
 }
 
     return res;
 }
 
-size_t wxMBConv_iconv::WC2MB(char *buf, const wchar_t *psz, size_t n) const
+size_t wxMBConv_iconv::FromWChar(char *dst, size_t dstLen,
+                                 const wchar_t *src, size_t srcLen) const
 {
 #if wxUSE_THREADS
     // NB: explained in MB2WC
     wxMutexLocker lock(wxConstCast(this, wxMBConv_iconv)->m_iconvMutex);
 #endif
 
 {
 #if wxUSE_THREADS
     // NB: explained in MB2WC
     wxMutexLocker lock(wxConstCast(this, wxMBConv_iconv)->m_iconvMutex);
 #endif
 
-    size_t inlen = wxWcslen(psz);
-    size_t inbuf = inlen * SIZEOF_WCHAR_T;
-    size_t outbuf = n;
+    if ( srcLen == wxNO_LEN )
+        srcLen = wxWcslen(src) + 1;
+
+    size_t inbuflen = srcLen * SIZEOF_WCHAR_T;
+    size_t outbuflen = dstLen;
     size_t res, cres;
 
     wchar_t *tmpbuf = 0;
     size_t res, cres;
 
     wchar_t *tmpbuf = 0;
@@ -2160,41 +2289,35 @@ size_t wxMBConv_iconv::WC2MB(char *buf, const wchar_t *psz, size_t n) const
         // need to copy to temp buffer to switch endianness
         // (doing WC_BSWAP twice on the original buffer won't help, as it
         //  could be in read-only memory, or be accessed in some other thread)
         // need to copy to temp buffer to switch endianness
         // (doing WC_BSWAP twice on the original buffer won't help, as it
         //  could be in read-only memory, or be accessed in some other thread)
-        tmpbuf = (wchar_t *)malloc(inbuf + SIZEOF_WCHAR_T);
-        for ( size_t i = 0; i < inlen; i++ )
-            tmpbuf[n] = WC_BSWAP(psz[i]);
+        tmpbuf = (wchar_t *)malloc(inbuflen + SIZEOF_WCHAR_T);
+        for ( size_t i = 0; i < srcLen; i++ )
+            tmpbuf[i] = WC_BSWAP(src[i]);
 
 
-        tmpbuf[inlen] = L'\0';
-        psz = tmpbuf;
+        tmpbuf[srcLen] = L'\0';
+        src = tmpbuf;
     }
 
     }
 
-    if (buf)
+    char* inbuf = (char*)src;
+    if ( dst )
     {
         // have destination buffer, convert there
     {
         // have destination buffer, convert there
-        cres = iconv( w2m, ICONV_CHAR_CAST(&psz), &inbuf, &buf, &outbuf );
+        cres = iconv(w2m, ICONV_CHAR_CAST(&inbuf), &inbuflen, &dst, &outbuflen);
 
 
-        res = n - outbuf;
-
-        // NB: iconv was given only wcslen(psz) characters on input, and so
-        //     it couldn't convert the trailing zero. Let's do it ourselves
-        //     if there's some room left for it in the output buffer.
-        if (res < n)
-            buf[0] = 0;
+        res = dstLen - outbuflen;
     }
     }
-    else
+    else // no destination buffer
     {
     {
-        // no destination buffer: convert using temp buffer
-        // to calculate destination buffer requirement
+        // convert using temp buffer to calculate the size of the buffer needed
         char tbuf[16];
         res = 0;
         do
         {
         char tbuf[16];
         res = 0;
         do
         {
-            buf = tbuf;
-            outbuf = 16;
+            dst = tbuf;
+            outbuflen = 16;
 
 
-            cres = iconv( w2m, ICONV_CHAR_CAST(&psz), &inbuf, &buf, &outbuf );
+            cres = iconv(w2m, ICONV_CHAR_CAST(&inbuf), &inbuflen, &dst, &outbuflen);
 
 
-            res += 16 - outbuf;
+            res += 16 - outbuflen;
         }
         while ((cres == (size_t)-1) && (errno == E2BIG));
     }
         }
         while ((cres == (size_t)-1) && (errno == E2BIG));
     }
@@ -2204,7 +2327,7 @@ size_t wxMBConv_iconv::WC2MB(char *buf, const wchar_t *psz, size_t n) const
         free(tmpbuf);
     }
 
         free(tmpbuf);
     }
 
-    if (ICONV_FAILED(cres, inbuf))
+    if (ICONV_FAILED(cres, inbuflen))
     {
         wxLogTrace(TRACE_STRCONV, wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode()));
         return wxCONV_FAILED;
     {
         wxLogTrace(TRACE_STRCONV, wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode()));
         return wxCONV_FAILED;
@@ -2449,8 +2572,10 @@ public:
                     return wxCONV_FAILED;
             }
 
                     return wxCONV_FAILED;
             }
 
+            if ( !n )
+                n = wcslen(pwz);
             wxWCharBuffer wcBuf(n);
             wxWCharBuffer wcBuf(n);
-            if ( MB2WC(wcBuf.data(), buf, n) == wxCONV_FAILED ||
+            if ( MB2WC(wcBuf.data(), buf, n + 1) == wxCONV_FAILED ||
                     wcscmp(wcBuf, pwz) != 0 )
             {
                 // we didn't obtain the same thing we started from, hence
                     wcscmp(wcBuf, pwz) != 0 )
             {
                 // we didn't obtain the same thing we started from, hence
@@ -3188,8 +3313,14 @@ wxCharBuffer wxSafeConvertWX2MB(const wchar_t *ws)
     WX_DEFINE_GLOBAL_CONV2(wxMBConv, wxMBConvLibc, wxConvLibc, wxEMPTY_PARAMETER_VALUE);
 #endif
 
     WX_DEFINE_GLOBAL_CONV2(wxMBConv, wxMBConvLibc, wxConvLibc, wxEMPTY_PARAMETER_VALUE);
 #endif
 
-WX_DEFINE_GLOBAL_CONV(wxMBConvStrictUTF8, wxConvUTF8, wxEMPTY_PARAMETER_VALUE);
-WX_DEFINE_GLOBAL_CONV(wxMBConvUTF7, wxConvUTF7, wxEMPTY_PARAMETER_VALUE);
+// NB: we can't use wxEMPTY_PARAMETER_VALUE as final argument here because it's
+//     passed to WX_DEFINE_GLOBAL_CONV2 after a macro expansion and so still
+//     provokes an error message about "not enough macro parameters"; and we
+//     can't use "()" here as the name##Obj declaration would be parsed as a
+//     function declaration then, so use a semicolon and live with an extra
+//     empty statement (and hope that no compilers warns about this)
+WX_DEFINE_GLOBAL_CONV(wxMBConvStrictUTF8, wxConvUTF8, ;);
+WX_DEFINE_GLOBAL_CONV(wxMBConvUTF7, wxConvUTF7, ;);
 
 WX_DEFINE_GLOBAL_CONV(wxCSConv, wxConvLocal, (wxFONTENCODING_SYSTEM));
 WX_DEFINE_GLOBAL_CONV(wxCSConv, wxConvISO8859_1, (wxFONTENCODING_ISO8859_1));
 
 WX_DEFINE_GLOBAL_CONV(wxCSConv, wxConvLocal, (wxFONTENCODING_SYSTEM));
 WX_DEFINE_GLOBAL_CONV(wxCSConv, wxConvISO8859_1, (wxFONTENCODING_ISO8859_1));