X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/fd5e476dbb9245a9ec755eeaa5b0e4b4556d2f8c..2cdd63c6b1d473ffd7726f619085997b0737952e:/src/common/strconv.cpp diff --git a/src/common/strconv.cpp b/src/common/strconv.cpp index dfd5295d29..76282821db 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; } // ---------------------------------------------------------------------------- @@ -365,7 +403,6 @@ static const unsigned char utf7unb64[] = size_t wxMBConvUTF7::MB2WC(wchar_t *buf, const char *psz, size_t n) const { - size_t len = 0; while (*psz && ((!buf) || (len < n))) @@ -399,7 +436,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 +445,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 == '-') @@ -455,8 +492,7 @@ static const unsigned char utf7encode[128] = 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 wxMBConvUTF7::WC2MB(char *buf, const wchar_t *psz, size_t n) const { @@ -473,8 +509,8 @@ size_t wxMBConvUTF7::WC2MB(char *buf, const wchar_t len++; } #ifndef WC_UTF16 - else if (cc > ((const wchar_t)0xffff)) - { + else if (((wxUint32)cc) > 0xffff) + { // no surrogate pair generation (yet?) return (size_t)-1; } @@ -1111,12 +1147,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 +1185,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 +1300,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 +1367,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; @@ -1419,10 +1475,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 @@ -1567,14 +1633,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) { @@ -1662,7 +1724,6 @@ CFStringEncoding wxCFStringEncFromFontEnc(wxFontEncoding encoding) case wxFONTENCODING_CP950 : enc = kCFStringEncodingDOSChineseTrad; break ; - case wxFONTENCODING_CP1250 : enc = kCFStringEncodingWindowsLatin2; break ; @@ -1687,9 +1748,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 ; @@ -1826,245 +1888,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: @@ -2073,10 +1896,12 @@ public: Init(CFStringGetSystemEncoding()) ; } +#if wxUSE_FONTMAP wxMBConv_cocoa(const wxChar* name) { Init( wxCFStringEncFromFontEnc(wxFontMapper::Get()->CharsetToEncoding(name, false) ) ) ; } +#endif wxMBConv_cocoa(wxFontEncoding encoding) { @@ -2089,160 +1914,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) }; + CFRange theRange = { 0, nOutSize }; +#if SIZEOF_WCHAR_T == 4 + UniChar* szUniCharBuffer = new UniChar[nOutSize]; +#endif + CFStringGetCharacters(theString, theRange, szUniCharBuffer); - - - nRealOutSize = (CFStringGetLength(theString) + 1); - + 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) * 8) +1 ; - szBuffer = new char[ nRealOutSize ] ; - } - else - nRealOutSize = nOutSize; - #if SIZEOF_WCHAR_T == 4 wxMBConvUTF16BE 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; - - if(nOutSize == 0) + //so we check and use getchars instead in that case + if (m_encoding == kCFStringEncodingUnicode) { -//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; + if (szOut != NULL) + CFStringGetCharacters(theString, CFRangeMake(0, nOutSize - 1), (UniChar*) szOut); + + nRealOutSize = CFStringGetLength(theString) + 1; + } + else + { + 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__) @@ -2261,10 +2044,12 @@ public: Init(CFStringGetSystemEncoding()) ; } +#if wxUSE_FONTMAP wxMBConv_mac(const wxChar* name) { Init( wxMacGetSystemEncFromFontEnc(wxFontMapper::Get()->CharsetToEncoding(name, false) ) ) ; } +#endif wxMBConv_mac(wxFontEncoding encoding) { @@ -2304,7 +2089,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 ) ; @@ -2334,13 +2120,6 @@ public: return res ; } - //NB: This is _broken_ - in invalid conversions, instead of returning -1 - //like it should, it (sometimes?) converts invalid characters of the encoding to a question - //mark character '?'. - // - //We need to do the msw double-pass check for the question marks as Vadim - //lines out above (RN: I don't recall this happening in the core foundation version, - //but it might do it there also, ick) size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const { OSStatus status = noErr ; @@ -2351,8 +2130,8 @@ public: if (buf == NULL) { - // worst case - n = ((byteInLen / SIZEOF_WCHAR_T) * 8) + SIZEOF_WCHAR_T; + //apple specs say at least 32 + n = wxMax( 32 , ((byteInLen / SIZEOF_WCHAR_T) * 8) + SIZEOF_WCHAR_T ); tbuf = (char*) malloc( n ) ; } @@ -2377,7 +2156,22 @@ 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 ; } @@ -2434,7 +2228,10 @@ public: { size_t inbuf = strlen(psz); if (buf) - m2w.Convert(psz,buf); + { + if (!m2w.Convert(psz,buf)) + return (size_t)-1; + } return inbuf; } @@ -2442,7 +2239,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; } @@ -2599,8 +2399,12 @@ wxMBConv *wxCSConv::DoCreate() const if ( m_name || ( m_encoding < wxFONTENCODING_UTF16BE ) ) { +#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; @@ -2613,8 +2417,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;