X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/2c53a80a097697483b10c022febe08f06afe2d3a..b9efe021b554fa3967d1442cf758435c5cd5ae8f:/src/common/strconv.cpp?ds=inline diff --git a/src/common/strconv.cpp b/src/common/strconv.cpp index 011d3280b8..aea1e1a18a 100644 --- a/src/common/strconv.cpp +++ b/src/common/strconv.cpp @@ -1,12 +1,14 @@ ///////////////////////////////////////////////////////////////////////////// // Name: strconv.cpp // Purpose: Unicode conversion classes -// Author: Ove Kaaven, Robert Roebling, Vadim Zeitlin, Vaclav Slavik +// Author: Ove Kaaven, Robert Roebling, Vadim Zeitlin, Vaclav Slavik, +// Ryan Norton, Fredrik Roubert (UTF7) // Modified by: // Created: 29/01/98 // RCS-ID: $Id$ // Copyright: (c) 1999 Ove Kaaven, Robert Roebling, Vaclav Slavik // (c) 2000-2003 Vadim Zeitlin +// (c) 2004 Ryan Norton, Fredrik Roubert // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -68,6 +70,7 @@ #ifdef HAVE_ICONV #include + #include "wx/thread.h" #endif #include "wx/encconv.h" @@ -149,7 +152,7 @@ static size_t decode_utf16(const wxUint16* input, wxUint32& output) output = *input; return 1; } - else if ((input[1]<0xdc00) || (input[1]>=0xdfff)) + else if ((input[1]<0xdc00) || (input[1]>0xdfff)) { output = *input; return (size_t)-1; @@ -215,6 +218,131 @@ const wxCharBuffer wxMBConv::cWC2MB(const wchar_t *pwz) const return buf; } +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 + while(szPos != szEnd) + { + wxASSERT(szPos < szEnd); //something is _really_ screwed up if this rings true + + //Get the length of the current (sub)string + size_t nLen = MB2WC(NULL, szPos, 0); + + //Invalid conversion? + if( nLen == (size_t)-1 ) + { + *pOutSize = 0; + theBuffer.data()[0u] = wxT('\0'); + return theBuffer; + } + + + //Increase the actual length (+1 for current null character) + nActualLength += nLen + 1; + + //if buffer too big, realloc the buffer + if (nActualLength > (nCurrentSize+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 + //Note that we have to use strlen instead of nLen here + //because XX2XX gives us the size of the output buffer, + //which is not necessarily the length of the string + szPos += strlen(szPos) + 1; + } + + //success - return actual length and the buffer + *pOutSize = nActualLength; + return theBuffer; +} + +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 + while(szPos != szEnd) + { + wxASSERT(szPos < szEnd); //something is _really_ screwed up if this rings true + + //Get the length of the current (sub)string + size_t nLen = WC2MB(NULL, szPos, 0); + + //Invalid conversion? + if( nLen == (size_t)-1 ) + { + *pOutSize = 0; + theBuffer.data()[0u] = wxT('\0'); + return theBuffer; + } + + //Increase the actual length (+1 for current null character) + nActualLength += nLen + 1; + + //if buffer too big, realloc the buffer + if (nActualLength > (nCurrentSize+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 + //Note that we have to use wxWcslen instead of nLen here + //because XX2XX gives us the size of the output buffer, + //which is not necessarily the length of the string + szPos += wxWcslen(szPos) + 1; + } + + //success - return actual length and the buffer + *pOutSize = nActualLength; + return theBuffer; +} + // ---------------------------------------------------------------------------- // wxMBConvLibc // ---------------------------------------------------------------------------- @@ -229,33 +357,241 @@ size_t wxMBConvLibc::WC2MB(char *buf, const wchar_t *psz, size_t n) const return wxWC2MB(buf, psz, n); } +#ifdef __UNIX__ + // ---------------------------------------------------------------------------- -// UTF-7 +// wxConvBrokenFileNames // ---------------------------------------------------------------------------- -#if 0 -static char utf7_setD[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789'(),-./:?"; -static char utf7_setO[]="!\"#$%&*;<=>@[]^_`{|}"; -static char utf7_setB[]="ABCDEFGHIJKLMNOPQRSTUVWXYZ" - "abcdefghijklmnopqrstuvwxyz" - "0123456789+/"; +wxConvBrokenFileNames::wxConvBrokenFileNames(const wxChar *charset) +{ + if ( !charset || wxStricmp(charset, _T("UTF-8")) == 0 + || wxStricmp(charset, _T("UTF8")) == 0 ) + m_conv = new wxMBConvUTF8(wxMBConvUTF8::MAP_INVALID_UTF8_TO_OCTAL); + else + m_conv = new wxCSConv(charset); +} + +size_t +wxConvBrokenFileNames::MB2WC(wchar_t *outputBuf, + const char *psz, + size_t outputSize) const +{ + return m_conv->MB2WC( outputBuf, psz, outputSize ); +} + +size_t +wxConvBrokenFileNames::WC2MB(char *outputBuf, + const wchar_t *psz, + size_t outputSize) const +{ + return m_conv->WC2MB( outputBuf, psz, outputSize ); +} + #endif -// TODO: write actual implementations of UTF-7 here -size_t wxMBConvUTF7::MB2WC(wchar_t * WXUNUSED(buf), - const char * WXUNUSED(psz), - size_t WXUNUSED(n)) const +// ---------------------------------------------------------------------------- +// UTF-7 +// ---------------------------------------------------------------------------- + +// Implementation (C) 2004 Fredrik Roubert + +// +// BASE64 decoding table +// +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, 0x3e, 0xff, 0xff, 0xff, 0x3f, + 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, + 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, + 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, + 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, + 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, + 0x31, 0x32, 0x33, 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, 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, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +size_t wxMBConvUTF7::MB2WC(wchar_t *buf, const char *psz, size_t n) const { - return 0; + size_t len = 0; + + while (*psz && ((!buf) || (len < n))) + { + 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 + { + // BASE64 encoded string + bool lsb; + unsigned char c; + unsigned int d, l; + for (lsb = false, d = 0, l = 0; + (cc = utf7unb64[(unsigned char)*psz]) != 0xff; psz++) + { + d <<= 6; + d += cc; + for (l += 6; l >= 8; lsb = !lsb) + { + c = (unsigned char)((d >> (l -= 8)) % 256); + if (lsb) + { + if (buf) + *buf++ |= c; + len ++; + } + else + if (buf) + *buf = (wchar_t)(c << 8); + } + } + if (*psz == '-') + psz++; + } + } + if (buf && (len < n)) + *buf = 0; + return len; } -size_t wxMBConvUTF7::WC2MB(char * WXUNUSED(buf), - const wchar_t * WXUNUSED(psz), - size_t WXUNUSED(n)) const +// +// BASE64 encoding table +// +static const unsigned char utf7enb64[] = { - return 0; + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' +}; + +// +// UTF-7 encoding table +// +// 0 - Set D (directly encoded characters) +// 1 - Set O (optional direct characters) +// 2 - whitespace characters (optional) +// 3 - special characters +// +static const unsigned char utf7encode[128] = +{ + 3, 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, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 1, 1, 1, + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 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 +{ + + + size_t len = 0; + + while (*psz && ((!buf) || (len < n))) + { + wchar_t cc = *psz++; + if (cc < 0x80 && utf7encode[cc] < 1) + { + // plain ASCII char + if (buf) + *buf++ = (char)cc; + len++; + } +#ifndef WC_UTF16 + else if (((wxUint32)cc) > 0xffff) + { + // no surrogate pair generation (yet?) + return (size_t)-1; + } +#endif + else + { + if (buf) + *buf++ = '+'; + len++; + if (cc != '+') + { + // BASE64 encode string + unsigned int lsb, d, l; + for (d = 0, l = 0;; psz++) + { + for (lsb = 0; lsb < 2; lsb ++) + { + d <<= 8; + d += lsb ? cc & 0xff : (cc & 0xff00) >> 8; + + for (l += 8; l >= 6; ) + { + l -= 6; + if (buf) + *buf++ = utf7enb64[(d >> l) % 64]; + len++; + } + } + cc = *psz; + if (!(cc) || (cc < 0x80 && utf7encode[cc] < 1)) + break; + } + if (l != 0) + { + if (buf) + *buf++ = utf7enb64[((d % 16) << (6 - l)) % 64]; + len++; + } + } + if (buf) + *buf++ = '-'; + len++; + } + } + if (buf && (len < n)) + *buf = 0; + return len; } // ---------------------------------------------------------------------------- @@ -265,12 +601,19 @@ size_t wxMBConvUTF7::WC2MB(char * WXUNUSED(buf), static wxUint32 utf8_max[]= { 0x7f, 0x7ff, 0xffff, 0x1fffff, 0x3ffffff, 0x7fffffff, 0xffffffff }; +// boundaries of the private use area we use to (temporarily) remap invalid +// characters invalid in a UTF-8 encoded string +const wxUint32 wxUnicodePUA = 0x100000; +const wxUint32 wxUnicodePUAEnd = wxUnicodePUA + 256; + size_t wxMBConvUTF8::MB2WC(wchar_t *buf, const char *psz, size_t n) const { size_t len = 0; while (*psz && ((!buf) || (len < n))) { + const char *opsz = psz; + bool invalid = false; unsigned char cc = *psz++, fc = cc; unsigned cnt; for (cnt = 0; fc & 0x80; cnt++) @@ -281,6 +624,15 @@ size_t wxMBConvUTF8::MB2WC(wchar_t *buf, const char *psz, size_t n) const if (buf) *buf++ = cc; len++; + + // escape the escape character for octal escapes + if ((m_options & MAP_INVALID_UTF8_TO_OCTAL) + && cc == '\\' && (!buf || len < n)) + { + if (buf) + *buf++ = cc; + len++; + } } else { @@ -288,7 +640,7 @@ size_t wxMBConvUTF8::MB2WC(wchar_t *buf, const char *psz, size_t n) const if (!cnt) { // invalid UTF-8 sequence - return (size_t)-1; + invalid = true; } else { @@ -296,32 +648,93 @@ size_t wxMBConvUTF8::MB2WC(wchar_t *buf, const char *psz, size_t n) const wxUint32 res = cc & (0x3f >> cnt); while (cnt--) { - cc = *psz++; + cc = *psz; if ((cc & 0xC0) != 0x80) { // invalid UTF-8 sequence - return (size_t)-1; + invalid = true; + break; } + psz++; res = (res << 6) | (cc & 0x3f); } - if (res <= utf8_max[ocnt]) + if (invalid || res <= utf8_max[ocnt]) { // illegal UTF-8 encoding - return (size_t)-1; + invalid = true; + } + else if ((m_options & MAP_INVALID_UTF8_TO_PUA) && + res >= wxUnicodePUA && res < wxUnicodePUAEnd) + { + // if one of our PUA characters turns up externally + // it must also be treated as an illegal sequence + // (a bit like you have to escape an escape character) + invalid = true; } + else + { #ifdef WC_UTF16 - // cast is ok because wchar_t == wxUuint16 if WC_UTF16 - size_t pa = encode_utf16(res, (wxUint16 *)buf); - if (pa == (size_t)-1) - return (size_t)-1; - if (buf) - buf += pa; - len += pa; + // cast is ok because wchar_t == wxUuint16 if WC_UTF16 + size_t pa = encode_utf16(res, (wxUint16 *)buf); + if (pa == (size_t)-1) + { + invalid = true; + } + else + { + if (buf) + buf += pa; + len += pa; + } #else // !WC_UTF16 - if (buf) - *buf++ = res; - len++; + if (buf) + *buf++ = res; + len++; #endif // WC_UTF16/!WC_UTF16 + } + } + if (invalid) + { + if (m_options & MAP_INVALID_UTF8_TO_PUA) + { + while (opsz < psz && (!buf || len < n)) + { +#ifdef WC_UTF16 + // cast is ok because wchar_t == wxUuint16 if WC_UTF16 + size_t pa = encode_utf16((unsigned char)*opsz + wxUnicodePUA, (wxUint16 *)buf); + wxASSERT(pa != (size_t)-1); + if (buf) + buf += pa; + opsz++; + len += pa; +#else + if (buf) + *buf++ = wxUnicodePUA + (unsigned char)*opsz; + opsz++; + len++; +#endif + } + } + else if (m_options & MAP_INVALID_UTF8_TO_OCTAL) + { + while (opsz < psz && (!buf || len < n)) + { + if ( buf && len + 3 < n ) + { + unsigned char n = *opsz; + *buf++ = L'\\'; + *buf++ = (wchar_t)( L'0' + n / 0100 ); + *buf++ = (wchar_t)( L'0' + (n % 0100) / 010 ); + *buf++ = (wchar_t)( L'0' + n % 010 ); + } + opsz++; + len += 4; + } + } + else // MAP_INVALID_UTF8_NOT + { + return (size_t)-1; + } } } } @@ -330,6 +743,11 @@ size_t wxMBConvUTF8::MB2WC(wchar_t *buf, const char *psz, size_t n) const return len; } +static inline bool isoctal(wchar_t wch) +{ + return L'0' <= wch && wch <= L'7'; +} + size_t wxMBConvUTF8::WC2MB(char *buf, const wchar_t *psz, size_t n) const { size_t len = 0; @@ -344,36 +762,67 @@ size_t wxMBConvUTF8::WC2MB(char *buf, const wchar_t *psz, size_t n) const #else cc=(*psz++) & 0x7fffffff; #endif - unsigned cnt; - for (cnt = 0; cc > utf8_max[cnt]; cnt++) {} - if (!cnt) + + if ( (m_options & MAP_INVALID_UTF8_TO_PUA) + && cc >= wxUnicodePUA && cc < wxUnicodePUAEnd ) + { + if (buf) + *buf++ = (char)(cc - wxUnicodePUA); + len++; + } + else if ( (m_options & MAP_INVALID_UTF8_TO_OCTAL) + && cc == L'\\' && psz[0] == L'\\' ) { - // plain ASCII char if (buf) - *buf++ = (char) cc; + *buf++ = (char)cc; + psz++; len++; } + else if ( (m_options & MAP_INVALID_UTF8_TO_OCTAL) && + cc == L'\\' && + isoctal(psz[0]) && isoctal(psz[1]) && isoctal(psz[2]) ) + { + if (buf) + { + *buf++ = (char) ((psz[0] - L'0')*0100 + + (psz[1] - L'0')*010 + + (psz[2] - L'0')); + } + psz += 3; + len++; + } else { - len += cnt + 1; - if (buf) + unsigned cnt; + for (cnt = 0; cc > utf8_max[cnt]; cnt++) {} + if (!cnt) { - *buf++ = (char) ((-128 >> cnt) | ((cc >> (cnt * 6)) & (0x3f >> cnt))); - while (cnt--) - *buf++ = (char) (0x80 | ((cc >> (cnt * 6)) & 0x3f)); + // plain ASCII char + if (buf) + *buf++ = (char) cc; + len++; + } + + else + { + len += cnt + 1; + if (buf) + { + *buf++ = (char) ((-128 >> cnt) | ((cc >> (cnt * 6)) & (0x3f >> cnt))); + while (cnt--) + *buf++ = (char) (0x80 | ((cc >> (cnt * 6)) & 0x3f)); + } } } } - if (buf && (lenWC 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; @@ -1050,6 +1514,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; @@ -1153,10 +1622,20 @@ public: // and break the library itself, e.g. wxTextInputStream::NextChar() // wouldn't work if reading an incomplete MB char didn't result in an // error + // + // note however that using MB_ERR_INVALID_CHARS with CP_UTF7 results in + // an error (tested under Windows Server 2003) and apparently it is + // done on purpose, i.e. the function accepts any input in this case + // and although I'd prefer to return error on ill-formed output, our + // own wxMBConvUTF7 doesn't detect errors (e.g. lone "+" which is + // explicitly ill-formed according to RFC 2152) neither so we don't + // even have any fallback here... + int flags = m_CodePage == CP_UTF7 ? 0 : MB_ERR_INVALID_CHARS; + const size_t len = ::MultiByteToWideChar ( m_CodePage, // code page - MB_ERR_INVALID_CHARS, // flags: fall on error + flags, // flags: fall on error psz, // input string -1, // its length (NUL-terminated) buf, // output string @@ -1301,14 +1780,10 @@ private: CFStringEncoding wxCFStringEncFromFontEnc(wxFontEncoding encoding) { - CFStringEncoding enc = 0 ; + CFStringEncoding enc = kCFStringEncodingInvalidId ; if ( encoding == wxFONTENCODING_DEFAULT ) { -#if wxUSE_GUI - encoding = wxFont::GetDefaultEncoding() ; -#else - encoding = wxLocale::GetSystemEncoding() ; -#endif + enc = CFStringGetSystemEncoding(); } else switch( encoding) { @@ -1396,7 +1871,6 @@ CFStringEncoding wxCFStringEncFromFontEnc(wxFontEncoding encoding) case wxFONTENCODING_CP950 : enc = kCFStringEncodingDOSChineseTrad; break ; - case wxFONTENCODING_CP1250 : enc = kCFStringEncodingWindowsLatin2; break ; @@ -1421,9 +1895,10 @@ CFStringEncoding wxCFStringEncFromFontEnc(wxFontEncoding encoding) case wxFONTENCODING_CP1257 : enc = kCFStringEncodingWindowsBalticRim; break ; - case wxFONTENCODING_UTF7 : - enc = kCFStringEncodingNonLossyASCII ; - break ; +// This only really encodes to UTF7 (if that) evidently +// case wxFONTENCODING_UTF7 : +// enc = kCFStringEncodingNonLossyASCII ; +// break ; case wxFONTENCODING_UTF8 : enc = kCFStringEncodingUTF8 ; break ; @@ -1560,245 +2035,6 @@ CFStringEncoding wxCFStringEncFromFontEnc(wxFontEncoding encoding) return enc ; } -wxFontEncoding wxFontEncFromCFStringEnc(CFStringEncoding encoding) -{ - wxFontEncoding enc = wxFONTENCODING_DEFAULT ; - - switch( encoding) - { - case kCFStringEncodingISOLatin1 : - enc = wxFONTENCODING_ISO8859_1 ; - break ; - case kCFStringEncodingISOLatin2 : - enc = wxFONTENCODING_ISO8859_2; - break ; - case kCFStringEncodingISOLatin3 : - enc = wxFONTENCODING_ISO8859_3 ; - break ; - case kCFStringEncodingISOLatin4 : - enc = wxFONTENCODING_ISO8859_4; - break ; - case kCFStringEncodingISOLatinCyrillic : - enc = wxFONTENCODING_ISO8859_5; - break ; - case kCFStringEncodingISOLatinArabic : - enc = wxFONTENCODING_ISO8859_6; - break ; - case kCFStringEncodingISOLatinGreek : - enc = wxFONTENCODING_ISO8859_7; - break ; - case kCFStringEncodingISOLatinHebrew : - enc = wxFONTENCODING_ISO8859_8; - break ; - case kCFStringEncodingISOLatin5 : - enc = wxFONTENCODING_ISO8859_9; - break ; - case kCFStringEncodingISOLatin6 : - enc = wxFONTENCODING_ISO8859_10; - break ; - case kCFStringEncodingISOLatin7 : - enc = wxFONTENCODING_ISO8859_13; - break ; - case kCFStringEncodingISOLatin8 : - enc = wxFONTENCODING_ISO8859_14; - break ; - case kCFStringEncodingISOLatin9 : - enc =wxFONTENCODING_ISO8859_15 ; - break ; - - case kCFStringEncodingKOI8_R : - enc = wxFONTENCODING_KOI8; - break ; - -// case : -// enc = wxFONTENCODING_BULGARIAN; -// break ; - - case kCFStringEncodingDOSLatinUS : - enc = wxFONTENCODING_CP437; - break ; - case kCFStringEncodingDOSLatin1 : - enc = wxFONTENCODING_CP850; - break ; - case kCFStringEncodingDOSLatin2 : - enc =wxFONTENCODING_CP852 ; - break ; - case kCFStringEncodingDOSCyrillic : - enc = wxFONTENCODING_CP855; - break ; - case kCFStringEncodingDOSRussian : - enc = wxFONTENCODING_CP866; - break ; - case kCFStringEncodingDOSThai : - enc =wxFONTENCODING_CP874 ; - break ; - case kCFStringEncodingDOSJapanese : - enc = wxFONTENCODING_CP932; - break ; - case kCFStringEncodingDOSChineseSimplif : - enc = wxFONTENCODING_CP936; - break ; - case kCFStringEncodingDOSKorean : - enc = wxFONTENCODING_CP949; - break ; - case kCFStringEncodingDOSChineseTrad : - enc = wxFONTENCODING_CP950; - break ; - - case kCFStringEncodingWindowsLatin2 : - enc = wxFONTENCODING_CP1250; - break ; - case kCFStringEncodingWindowsCyrillic : - enc = wxFONTENCODING_CP1251; - break ; - case kCFStringEncodingWindowsLatin1 : - enc = wxFONTENCODING_CP1252; - break ; - case kCFStringEncodingWindowsGreek : - enc = wxFONTENCODING_CP1253; - break ; - case kCFStringEncodingWindowsLatin5 : - enc = wxFONTENCODING_CP1254; - break ; - case kCFStringEncodingWindowsHebrew : - enc = wxFONTENCODING_CP1255; - break ; - case kCFStringEncodingWindowsArabic : - enc = wxFONTENCODING_CP1256; - break ; - case kCFStringEncodingWindowsBalticRim : - enc =wxFONTENCODING_CP1257 ; - break ; - case kCFStringEncodingEUC_JP : - enc = wxFONTENCODING_EUC_JP; - break ; - case kCFStringEncodingUnicode : - enc = wxFONTENCODING_UTF16; - break; - case kCFStringEncodingMacRoman : - enc = wxFONTENCODING_MACROMAN ; - break ; - case kCFStringEncodingMacJapanese : - enc = wxFONTENCODING_MACJAPANESE ; - break ; - case kCFStringEncodingMacChineseTrad : - enc = wxFONTENCODING_MACCHINESETRAD ; - break ; - case kCFStringEncodingMacKorean : - enc = wxFONTENCODING_MACKOREAN ; - break ; - case kCFStringEncodingMacArabic : - enc =wxFONTENCODING_MACARABIC ; - break ; - case kCFStringEncodingMacHebrew : - enc = wxFONTENCODING_MACHEBREW ; - break ; - case kCFStringEncodingMacGreek : - enc = wxFONTENCODING_MACGREEK ; - break ; - case kCFStringEncodingMacCyrillic : - enc = wxFONTENCODING_MACCYRILLIC ; - break ; - case kCFStringEncodingMacDevanagari : - enc = wxFONTENCODING_MACDEVANAGARI ; - break ; - case kCFStringEncodingMacGurmukhi : - enc = wxFONTENCODING_MACGURMUKHI ; - break ; - case kCFStringEncodingMacGujarati : - enc = wxFONTENCODING_MACGUJARATI ; - break ; - case kCFStringEncodingMacOriya : - enc =wxFONTENCODING_MACORIYA ; - break ; - case kCFStringEncodingMacBengali : - enc =wxFONTENCODING_MACBENGALI ; - break ; - case kCFStringEncodingMacTamil : - enc = wxFONTENCODING_MACTAMIL ; - break ; - case kCFStringEncodingMacTelugu : - enc = wxFONTENCODING_MACTELUGU ; - break ; - case kCFStringEncodingMacKannada : - enc = wxFONTENCODING_MACKANNADA ; - break ; - case kCFStringEncodingMacMalayalam : - enc = wxFONTENCODING_MACMALAJALAM ; - break ; - case kCFStringEncodingMacSinhalese : - enc = wxFONTENCODING_MACSINHALESE ; - break ; - case kCFStringEncodingMacBurmese : - enc = wxFONTENCODING_MACBURMESE ; - break ; - case kCFStringEncodingMacKhmer : - enc = wxFONTENCODING_MACKHMER ; - break ; - case kCFStringEncodingMacThai : - enc = wxFONTENCODING_MACTHAI ; - break ; - case kCFStringEncodingMacLaotian : - enc = wxFONTENCODING_MACLAOTIAN ; - break ; - case kCFStringEncodingMacGeorgian : - enc = wxFONTENCODING_MACGEORGIAN ; - break ; - case kCFStringEncodingMacArmenian : - enc = wxFONTENCODING_MACARMENIAN ; - break ; - case kCFStringEncodingMacChineseSimp : - enc = wxFONTENCODING_MACCHINESESIMP ; - break ; - case kCFStringEncodingMacTibetan : - enc = wxFONTENCODING_MACTIBETAN ; - break ; - case kCFStringEncodingMacMongolian : - enc = wxFONTENCODING_MACMONGOLIAN ; - break ; - case kCFStringEncodingMacEthiopic : - enc = wxFONTENCODING_MACETHIOPIC ; - break ; - case kCFStringEncodingMacCentralEurRoman: - enc = wxFONTENCODING_MACCENTRALEUR ; - break ; - case kCFStringEncodingMacVietnamese: - enc = wxFONTENCODING_MACVIATNAMESE ; - break ; - case kCFStringEncodingMacExtArabic : - enc = wxFONTENCODING_MACARABICEXT ; - break ; - case kCFStringEncodingMacSymbol : - enc = wxFONTENCODING_MACSYMBOL ; - break ; - case kCFStringEncodingMacDingbats : - enc = wxFONTENCODING_MACDINGBATS ; - break ; - case kCFStringEncodingMacTurkish : - enc = wxFONTENCODING_MACTURKISH ; - break ; - case kCFStringEncodingMacCroatian : - enc = wxFONTENCODING_MACCROATIAN ; - break ; - case kCFStringEncodingMacIcelandic : - enc = wxFONTENCODING_MACICELANDIC ; - break ; - case kCFStringEncodingMacRomanian : - enc = wxFONTENCODING_MACROMANIAN ; - break ; - case kCFStringEncodingMacCeltic : - enc = wxFONTENCODING_MACCELTIC ; - break ; - case kCFStringEncodingMacGaelic : - enc = wxFONTENCODING_MACGAELIC ; - break ; -// case kCFStringEncodingMacKeyboardGlyphs : -// enc = wxFONTENCODING_MACKEYBOARD ; -// break ; - } ; - return enc ; -} - class wxMBConv_cocoa : public wxMBConv { public: @@ -1807,10 +2043,12 @@ public: Init(CFStringGetSystemEncoding()) ; } +#if wxUSE_FONTMAP wxMBConv_cocoa(const wxChar* name) { - Init( wxCFStringEncFromFontEnc(wxFontMapper::Get()->CharsetToEncoding(name, false) ) ) ; + Init( wxCFStringEncFromFontEnc(wxFontMapperBase::Get()->CharsetToEncoding(name, false) ) ) ; } +#endif wxMBConv_cocoa(wxFontEncoding encoding) { @@ -1823,160 +2061,118 @@ public: void Init( CFStringEncoding encoding) { - m_char_encoding = encoding ; - m_unicode_encoding = kCFStringEncodingUnicode; + m_encoding = encoding ; } size_t MB2WC(wchar_t * szOut, const char * szUnConv, size_t nOutSize) const { wxASSERT(szUnConv); - size_t nBufSize = strlen(szUnConv) + 1; - size_t nRealOutSize; - - UniChar* szUniCharBuffer = (UniChar*) szOut; - wchar_t* szConvBuffer = szOut; - - if (szConvBuffer == NULL && nOutSize != 0) - { - szConvBuffer = new wchar_t[nOutSize] ; - } - -#if SIZEOF_WCHAR_T == 4 - szUniCharBuffer = new UniChar[nOutSize]; -#endif - - CFDataRef theData = CFDataCreateWithBytesNoCopy ( - NULL, //allocator - (const UInt8*)szUnConv, - nBufSize - 1, - NULL //deallocator - ); - - wxASSERT(theData); - - CFStringRef theString = CFStringCreateFromExternalRepresentation ( - NULL, - theData, - m_char_encoding + CFStringRef theString = CFStringCreateWithBytes ( + NULL, //the allocator + (const UInt8*)szUnConv, + strlen(szUnConv), + m_encoding, + false //no BOM/external representation ); wxASSERT(theString); - if (nOutSize == 0) + size_t nOutLength = CFStringGetLength(theString); + + if (szOut == NULL) { - nRealOutSize = CFStringGetLength(theString) + 1; CFRelease(theString); - return nRealOutSize - 1; + return nOutLength; } - CFRange theRange = { 0, CFStringGetLength(theString) }; - - CFStringGetCharacters(theString, theRange, szUniCharBuffer); + CFRange theRange = { 0, nOutSize }; +#if SIZEOF_WCHAR_T == 4 + UniChar* szUniCharBuffer = new UniChar[nOutSize]; +#endif - nRealOutSize = (CFStringGetLength(theString) + 1); + CFStringGetCharacters(theString, theRange, szUniCharBuffer); CFRelease(theString); - szUniCharBuffer[nRealOutSize-1] = '\0' ; + szUniCharBuffer[nOutLength] = '\0' ; #if SIZEOF_WCHAR_T == 4 wxMBConvUTF16 converter ; - converter.MB2WC(szConvBuffer , (const char*)szUniCharBuffer , nRealOutSize ) ; + converter.MB2WC(szOut, (const char*)szUniCharBuffer , nOutSize ) ; delete[] szUniCharBuffer; #endif - if ( szOut == NULL ) - delete [] szConvBuffer; - return nRealOutSize ; + return nOutLength; } size_t WC2MB(char *szOut, const wchar_t *szUnConv, size_t nOutSize) const { - size_t nBufSize = wxWcslen(szUnConv) + 1; + wxASSERT(szUnConv); + size_t nRealOutSize; - char* szBuffer = szOut; + size_t nBufSize = wxWcslen(szUnConv); UniChar* szUniBuffer = (UniChar*) szUnConv; - if (szOut == NULL) - { - // worst case - nRealOutSize = ((nBufSize - 1) << 1)+1 ; - szBuffer = new char[ nRealOutSize ] ; - } - else - nRealOutSize = nOutSize; - #if SIZEOF_WCHAR_T == 4 - wxMBConvUTF16BE converter ; + wxMBConvUTF16 converter ; nBufSize = converter.WC2MB( NULL , szUnConv , 0 ); szUniBuffer = new UniChar[ (nBufSize / sizeof(UniChar)) + 1] ; converter.WC2MB( (char*) szUniBuffer , szUnConv, nBufSize + sizeof(UniChar)) ; nBufSize /= sizeof(UniChar); - ++nBufSize; #endif CFStringRef theString = CFStringCreateWithCharactersNoCopy( NULL, //allocator szUniBuffer, nBufSize, - NULL //deallocator + kCFAllocatorNull //deallocator - we want to deallocate it ourselves ); wxASSERT(theString); //Note that CER puts a BOM when converting to unicode - //so we may want to check and use getchars instead in that case - CFDataRef theData = CFStringCreateExternalRepresentation( - NULL, //allocator - theString, - m_char_encoding, - 0 //what to put in characters that can't be converted - - //0 tells CFString to return NULL if it meets such a character - ); - - if(!theData) - return (size_t)-1; - - CFRelease(theString); - - nRealOutSize = CFDataGetLength(theData); - - if ( szOut == NULL ) - delete[] szBuffer; + //so we check and use getchars instead in that case + if (m_encoding == kCFStringEncodingUnicode) + { + if (szOut != NULL) + CFStringGetCharacters(theString, CFRangeMake(0, nOutSize - 1), (UniChar*) szOut); - if(nOutSize == 0) + nRealOutSize = CFStringGetLength(theString) + 1; + } + else { -//TODO: This gets flagged as a non-malloced address by the debugger... -//#if SIZEOF_WCHAR_T == 4 -// delete[] szUniBuffer; -//#endif - CFRelease(theData); - return nRealOutSize - 1; + CFStringGetBytes( + theString, + CFRangeMake(0, CFStringGetLength(theString)), + m_encoding, + 0, //what to put in characters that can't be converted - + //0 tells CFString to return NULL if it meets such a character + false, //not an external representation + (UInt8*) szOut, + nOutSize, + (CFIndex*) &nRealOutSize + ); } - CFRange theRange = {0, CFDataGetLength(theData) }; - CFDataGetBytes(theData, theRange, (UInt8*) szBuffer); + CFRelease(theString); - CFRelease(theData); +#if SIZEOF_WCHAR_T == 4 + delete[] szUniBuffer; +#endif -//TODO: This gets flagged as a non-malloced address by the debugger... -//#if SIZEOF_WCHAR_T == 4 -// delete[] szUniBuffer; -//#endif return nRealOutSize - 1; } bool IsOk() const { - //TODO: check for invalid en/de/coding - return true; + return m_encoding != kCFStringEncodingInvalidId && + CFStringIsEncodingAvailable(m_encoding); } private: - CFStringEncoding m_char_encoding ; - CFStringEncoding m_unicode_encoding ; + CFStringEncoding m_encoding ; }; #endif // defined(__WXCOCOA__) @@ -1995,10 +2191,12 @@ public: Init(CFStringGetSystemEncoding()) ; } +#if wxUSE_FONTMAP wxMBConv_mac(const wxChar* name) { - Init( wxMacGetSystemEncFromFontEnc(wxFontMapper::Get()->CharsetToEncoding(name, false) ) ) ; + Init( wxMacGetSystemEncFromFontEnc(wxFontMapperBase::Get()->CharsetToEncoding(name, false) ) ) ; } +#endif wxMBConv_mac(wxFontEncoding encoding) { @@ -2038,7 +2236,8 @@ public: if (buf == NULL) { - n = byteInLen ; + //apple specs say at least 32 + n = wxMax( 32 , byteInLen ) ; tbuf = (wchar_t*) malloc( n * SIZEOF_WCHAR_T) ; } ByteCount byteBufferLen = n * sizeof( UniChar ) ; @@ -2053,7 +2252,7 @@ public: // we have to terminate here, because n might be larger for the trailing zero, and if UniChar // is not properly terminated we get random characters at the end ubuf[byteOutLen / sizeof( UniChar ) ] = 0 ; - wxMBConvUTF16BE converter ; + wxMBConvUTF16 converter ; res = converter.MB2WC( (buf ? buf : tbuf) , (const char*)ubuf , n ) ; free( ubuf ) ; #else @@ -2078,15 +2277,15 @@ public: if (buf == NULL) { - // worst case - n = byteInLen * 2 ; + //apple specs say at least 32 + n = wxMax( 32 , ((byteInLen / SIZEOF_WCHAR_T) * 8) + SIZEOF_WCHAR_T ); tbuf = (char*) malloc( n ) ; } ByteCount byteBufferLen = n ; UniChar* ubuf = NULL ; #if SIZEOF_WCHAR_T == 4 - wxMBConvUTF16BE converter ; + wxMBConvUTF16 converter ; size_t unicharlen = converter.WC2MB( NULL , psz , 0 ) ; byteInLen = unicharlen ; ubuf = (UniChar*) malloc( byteInLen + 2 ) ; @@ -2104,8 +2303,23 @@ public: size_t res = byteOutLen ; if ( buf && res < n) + { buf[res] = 0; + //we need to double-trip to verify it didn't insert any ? in place + //of bogus characters + wxWCharBuffer wcBuf(n); + size_t pszlen = wxWcslen(psz); + if ( MB2WC(wcBuf.data(), buf, n) == (size_t)-1 || + wxWcslen(wcBuf) != pszlen || + memcmp(wcBuf, psz, pszlen * sizeof(wchar_t)) != 0 ) + { + // we didn't obtain the same thing we started from, hence + // the conversion was lossy and we consider that it failed + return (size_t)-1; + } + } + return res ; } @@ -2143,7 +2357,7 @@ public: wxMBConv_wxwin(const wxChar* name) { if (name) - m_enc = wxFontMapper::Get()->CharsetToEncoding(name, false); + m_enc = wxFontMapperBase::Get()->CharsetToEncoding(name, false); else m_enc = wxFONTENCODING_SYSTEM; @@ -2161,7 +2375,10 @@ public: { size_t inbuf = strlen(psz); if (buf) - m2w.Convert(psz,buf); + { + if (!m2w.Convert(psz,buf)) + return (size_t)-1; + } return inbuf; } @@ -2169,7 +2386,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; } @@ -2296,7 +2516,7 @@ wxMBConv *wxCSConv::DoCreate() const #if wxUSE_FONTMAP if ( name.empty() ) - name = wxFontMapper::Get()->GetEncodingName(m_encoding); + name = wxFontMapperBase::Get()->GetEncodingName(m_encoding); #endif // wxUSE_FONTMAP wxMBConv_iconv *conv = new wxMBConv_iconv(name); @@ -2323,11 +2543,17 @@ wxMBConv *wxCSConv::DoCreate() const #endif // wxHAVE_WIN32_MB2WC #if defined(__WXMAC__) { - if ( m_name || ( m_encoding < wxFONTENCODING_UTF16BE ) ) + // leave UTF16 and UTF32 to the built-ins of wx + if ( m_name || ( m_encoding < wxFONTENCODING_UTF16BE || + ( m_encoding >= wxFONTENCODING_MACMIN && m_encoding <= wxFONTENCODING_MACMAX ) ) ) { +#if wxUSE_FONTMAP wxMBConv_mac *conv = m_name ? new wxMBConv_mac(m_name) : new wxMBConv_mac(m_encoding); +#else + wxMBConv_mac *conv = new wxMBConv_mac(m_encoding); +#endif if ( conv->IsOk() ) return conv; @@ -2340,8 +2566,12 @@ wxMBConv *wxCSConv::DoCreate() const if ( m_name || ( m_encoding <= wxFONTENCODING_UTF16 ) ) { +#if wxUSE_FONTMAP wxMBConv_cocoa *conv = m_name ? new wxMBConv_cocoa(m_name) : new wxMBConv_cocoa(m_encoding); +#else + wxMBConv_cocoa *conv = new wxMBConv_cocoa(m_encoding); +#endif if ( conv->IsOk() ) return conv; @@ -2357,7 +2587,7 @@ wxMBConv *wxCSConv::DoCreate() const // use "false" to suppress interactive dialogs -- we can be called from // anywhere and popping up a dialog from here is the last thing we want to // do - enc = wxFontMapper::Get()->CharsetToEncoding(m_name, false); + enc = wxFontMapperBase::Get()->CharsetToEncoding(m_name, false); } #endif // wxUSE_FONTMAP @@ -2413,7 +2643,7 @@ wxMBConv *wxCSConv::DoCreate() const m_name ? m_name : #if wxUSE_FONTMAP - wxFontMapper::GetEncodingDescription(m_encoding).c_str() + wxFontMapperBase::GetEncodingDescription(m_encoding).c_str() #else // !wxUSE_FONTMAP wxString::Format(_("encoding %s"), m_encoding).c_str() #endif // wxUSE_FONTMAP/!wxUSE_FONTMAP @@ -2510,13 +2740,19 @@ static wxCSConv wxConvISO8859_1Obj(wxFONTENCODING_ISO8859_1); static wxMBConvUTF7 wxConvUTF7Obj; static wxMBConvUTF8 wxConvUTF8Obj; - WXDLLIMPEXP_DATA_BASE(wxMBConv&) wxConvLibc = wxConvLibcObj; WXDLLIMPEXP_DATA_BASE(wxCSConv&) wxConvLocal = wxConvLocalObj; WXDLLIMPEXP_DATA_BASE(wxCSConv&) wxConvISO8859_1 = wxConvISO8859_1Obj; WXDLLIMPEXP_DATA_BASE(wxMBConvUTF7&) wxConvUTF7 = wxConvUTF7Obj; WXDLLIMPEXP_DATA_BASE(wxMBConvUTF8&) wxConvUTF8 = wxConvUTF8Obj; WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvCurrent = &wxConvLibcObj; +WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvFileName = & +#ifdef __WXOSX__ + wxConvUTF8Obj; +#else + wxConvLibcObj; +#endif + #else // !wxUSE_WCHAR_T