X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/6e394fc6236b98a0c4303fca9a306dc823cc36c8..11ca2edf95b3b99733224001138d1dc7d57d2e31:/src/common/strconv.cpp?ds=sidebyside diff --git a/src/common/strconv.cpp b/src/common/strconv.cpp index 88c3c6ca79..ca7031528b 100644 --- a/src/common/strconv.cpp +++ b/src/common/strconv.cpp @@ -70,6 +70,7 @@ #ifdef HAVE_ICONV #include + #include "wx/thread.h" #endif #include "wx/encconv.h" @@ -217,14 +218,18 @@ const wxCharBuffer wxMBConv::cWC2MB(const wchar_t *pwz) const return buf; } -size_t wxMBConv::MB2WC(wchar_t* szBuffer, const char* szString, - size_t outsize, size_t nStringLen) const +const wxWCharBuffer wxMBConv::cMB2WC(const char *szString, size_t nStringLen, size_t* pOutSize) const { + wxASSERT(pOutSize != NULL); + const char* szEnd = szString + nStringLen + 1; const char* szPos = szString; const char* szStart = szPos; size_t nActualLength = 0; + size_t nCurrentSize = nStringLen; //try normal size first (should never resize?) + + wxWCharBuffer theBuffer(nCurrentSize); //Convert the string until the length() is reached, continuing the //loop every time a null character is reached @@ -237,18 +242,31 @@ size_t wxMBConv::MB2WC(wchar_t* szBuffer, const char* szString, //Invalid conversion? if( nLen == (size_t)-1 ) - return nLen; + { + *pOutSize = 0; + theBuffer.data()[0u] = wxT('\0'); + return theBuffer; + } + //Increase the actual length (+1 for current null character) nActualLength += nLen + 1; - //Only copy data in if buffer size is big enough - if (szBuffer != NULL && - nActualLength <= outsize) + //if buffer too big, realloc the buffer + if (nActualLength > (nCurrentSize+1)) { - //Convert the current (sub)string - if ( MB2WC(&szBuffer[szPos - szStart], szPos, nLen + 1) == (size_t)-1 ) - return (size_t)-1; + wxWCharBuffer theNewBuffer(nCurrentSize << 1); + memcpy(theNewBuffer.data(), theBuffer.data(), nCurrentSize * sizeof(wchar_t)); + theBuffer = theNewBuffer; + nCurrentSize <<= 1; + } + + //Convert the current (sub)string + if ( MB2WC(&theBuffer.data()[szPos - szStart], szPos, nLen + 1) == (size_t)-1 ) + { + *pOutSize = 0; + theBuffer.data()[0u] = wxT('\0'); + return theBuffer; } //Increment to next (sub)string @@ -258,17 +276,23 @@ size_t wxMBConv::MB2WC(wchar_t* szBuffer, const char* szString, szPos += strlen(szPos) + 1; } - return nActualLength - 1; //success - return actual length + //success - return actual length and the buffer + *pOutSize = nActualLength; + return theBuffer; } -size_t wxMBConv::WC2MB(char* szBuffer, const wchar_t* szString, - size_t outsize, size_t nStringLen) const +const wxCharBuffer wxMBConv::cWC2MB(const wchar_t *szString, size_t nStringLen, size_t* pOutSize) const { + wxASSERT(pOutSize != NULL); + const wchar_t* szEnd = szString + nStringLen + 1; const wchar_t* szPos = szString; const wchar_t* szStart = szPos; size_t nActualLength = 0; + size_t nCurrentSize = nStringLen << 2; //try * 4 first + + wxCharBuffer theBuffer(nCurrentSize); //Convert the string until the length() is reached, continuing the //loop every time a null character is reached @@ -281,18 +305,30 @@ size_t wxMBConv::WC2MB(char* szBuffer, const wchar_t* szString, //Invalid conversion? if( nLen == (size_t)-1 ) - return nLen; + { + *pOutSize = 0; + theBuffer.data()[0u] = wxT('\0'); + return theBuffer; + } //Increase the actual length (+1 for current null character) nActualLength += nLen + 1; - //Only copy data in if buffer size is big enough - if (szBuffer != NULL && - nActualLength <= outsize) + //if buffer too big, realloc the buffer + if (nActualLength > (nCurrentSize+1)) { - //Convert the current (sub)string - if(WC2MB(&szBuffer[szPos - szStart], szPos, nLen + 1) == (size_t)-1 ) - return (size_t)-1; + wxCharBuffer theNewBuffer(nCurrentSize << 1); + memcpy(theNewBuffer.data(), theBuffer.data(), nCurrentSize); + theBuffer = theNewBuffer; + nCurrentSize <<= 1; + } + + //Convert the current (sub)string + if(WC2MB(&theBuffer.data()[szPos - szStart], szPos, nLen + 1) == (size_t)-1 ) + { + *pOutSize = 0; + theBuffer.data()[0u] = wxT('\0'); + return theBuffer; } //Increment to next (sub)string @@ -302,7 +338,9 @@ size_t wxMBConv::WC2MB(char* szBuffer, const wchar_t* szString, szPos += wxWcslen(szPos) + 1; } - return nActualLength - 1; //success - return actual length + //success - return actual length and the buffer + *pOutSize = nActualLength; + return theBuffer; } // ---------------------------------------------------------------------------- @@ -399,7 +437,7 @@ size_t wxMBConvUTF7::MB2WC(wchar_t *buf, const char *psz, size_t n) const d += cc; for (l += 6; l >= 8; lsb = !lsb) { - c = (d >> (l -= 8)) % 256; + c = (unsigned char)((d >> (l -= 8)) % 256); if (lsb) { if (buf) @@ -408,7 +446,7 @@ size_t wxMBConvUTF7::MB2WC(wchar_t *buf, const char *psz, size_t n) const } else if (buf) - *buf = c << 8; + *buf = (wchar_t)(c << 8); } } if (*psz == '-') @@ -473,7 +511,7 @@ size_t wxMBConvUTF7::WC2MB(char *buf, const wchar_t len++; } #ifndef WC_UTF16 - else if (((wxUint16)cc) > 0xffff) + else if (((wxUint32)cc) > 0xffff) { // no surrogate pair generation (yet?) return (size_t)-1; @@ -1111,12 +1149,13 @@ size_t wxMBConvUTF32swap::WC2MB(char *buf, const wchar_t *psz, size_t n) const #ifdef HAVE_ICONV -// VS: glibc 2.1.3 is broken in that iconv() conversion to/from UCS4 fails with E2BIG -// if output buffer is _exactly_ as big as needed. Such case is (unless there's -// yet another bug in glibc) the only case when iconv() returns with (size_t)-1 -// (which means error) and says there are 0 bytes left in the input buffer -- -// when _real_ error occurs, bytes-left-in-input buffer is non-zero. Hence, -// this alternative test for iconv() failure. +// VS: glibc 2.1.3 is broken in that iconv() conversion to/from UCS4 fails with +// E2BIG if output buffer is _exactly_ as big as needed. Such case is +// (unless there's yet another bug in glibc) the only case when iconv() +// returns with (size_t)-1 (which means error) and says there are 0 bytes +// left in the input buffer -- when _real_ error occurs, +// bytes-left-in-input buffer is non-zero. Hence, this alternative test for +// iconv() failure. // [This bug does not appear in glibc 2.2.] #if defined(__GLIBC__) && __GLIBC__ == 2 && __GLIBC_MINOR__ <= 1 #define ICONV_FAILED(cres, bufLeft) ((cres == (size_t)-1) && \ @@ -1148,6 +1187,10 @@ protected: // the other direction iconv_t m2w, w2m; +#if wxUSE_THREADS + // guards access to m2w and w2m objects + wxMutex m_iconvMutex; +#endif private: // the name (for iconv_open()) of a wide char charset -- if none is @@ -1259,6 +1302,16 @@ wxMBConv_iconv::~wxMBConv_iconv() size_t wxMBConv_iconv::MB2WC(wchar_t *buf, const char *psz, size_t n) const { +#if wxUSE_THREADS + // NB: iconv() is MT-safe, but each thread must use it's own iconv_t handle. + // Unfortunately there is a couple of global wxCSConv objects such as + // wxConvLocal that are used all over wx code, so we have to make sure + // the handle is used by at most one thread at the time. Otherwise + // only a few wx classes would be safe to use from non-main threads + // as MB<->WC conversion would fail "randomly". + wxMutexLocker lock(wxConstCast(this, wxMBConv_iconv)->m_iconvMutex); +#endif + size_t inbuf = strlen(psz); size_t outbuf = n * SIZEOF_WCHAR_T; size_t res, cres; @@ -1316,6 +1369,11 @@ size_t wxMBConv_iconv::MB2WC(wchar_t *buf, const char *psz, size_t n) const size_t wxMBConv_iconv::WC2MB(char *buf, const wchar_t *psz, size_t n) const { +#if wxUSE_THREADS + // NB: explained in MB2WC + wxMutexLocker lock(wxConstCast(this, wxMBConv_iconv)->m_iconvMutex); +#endif + size_t inbuf = wxWcslen(psz) * SIZEOF_WCHAR_T; size_t outbuf = n; size_t res, cres; @@ -2158,7 +2216,10 @@ public: { size_t inbuf = strlen(psz); if (buf) - m2w.Convert(psz,buf); + { + if (!m2w.Convert(psz,buf)) + return (size_t)-1; + } return inbuf; } @@ -2166,7 +2227,10 @@ public: { const size_t inbuf = wxWcslen(psz); if (buf) - w2m.Convert(psz,buf); + { + if (!w2m.Convert(psz,buf)) + return (size_t)-1; + } return inbuf; }