X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1e1c5d6276dadefa53deebbd7fe5b766bad74cde..69659fd770f615210efac4b4fa741b3ad6223616:/src/common/strconv.cpp?ds=sidebyside diff --git a/src/common/strconv.cpp b/src/common/strconv.cpp index 49e78f40dd..59ea721b71 100644 --- a/src/common/strconv.cpp +++ b/src/common/strconv.cpp @@ -15,21 +15,21 @@ // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" +#ifdef __BORLANDC__ + #pragma hdrstop +#endif //__BORLANDC__ + #ifndef WX_PRECOMP #include "wx/intl.h" #include "wx/log.h" #include "wx/utils.h" + #include "wx/hashmap.h" #endif #include "wx/strconv.h" #if wxUSE_WCHAR_T -#ifdef __WINDOWS__ - #include "wx/msw/private.h" - #include "wx/msw/missing.h" -#endif - #ifndef __WXWINCE__ #include #endif @@ -39,6 +39,8 @@ #include #if defined(__WIN32__) && !defined(__WXMICROWIN__) + #include "wx/msw/private.h" + #include "wx/msw/missing.h" #define wxHAVE_WIN32_MB2WC #endif @@ -54,16 +56,9 @@ #include "wx/encconv.h" #include "wx/fontmap.h" -#ifdef __WXMAC__ -#ifndef __DARWIN__ -#include -#include -#include -#endif - -// includes Mac headers -#include "wx/mac/private.h" -#endif +#ifdef __DARWIN__ +#include "wx/mac/corefoundation/private/strconv_cf.h" +#endif //def __DARWIN__ #define TRACE_STRCONV _T("strconv") @@ -474,11 +469,11 @@ size_t wxMBConvLibc::WC2MB(char *buf, const wchar_t *psz, size_t n) const #ifdef __UNIX__ -wxConvBrokenFileNames::wxConvBrokenFileNames(const wxChar *charset) +wxConvBrokenFileNames::wxConvBrokenFileNames(const wxString& charset) { - if ( !charset || wxStricmp(charset, _T("UTF-8")) == 0 - || wxStricmp(charset, _T("UTF8")) == 0 ) - m_conv = new wxMBConvUTF8(wxMBConvUTF8::MAP_INVALID_UTF8_TO_OCTAL); + if ( wxStricmp(charset, _T("UTF-8")) == 0 || + wxStricmp(charset, _T("UTF8")) == 0 ) + m_conv = new wxMBConvUTF8(wxMBConvUTF8::MAP_INVALID_UTF8_TO_PUA); else m_conv = new wxCSConv(charset); } @@ -1586,7 +1581,7 @@ wxMBConvUTF32swap::FromWChar(char *dst, size_t dstLen, class wxMBConv_iconv : public wxMBConv { public: - wxMBConv_iconv(const wxChar *name); + wxMBConv_iconv(const char *name); virtual ~wxMBConv_iconv(); virtual size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const; @@ -1595,9 +1590,13 @@ public: // classify this encoding as explained in wxMBConv::GetMBNulLen() comment virtual size_t GetMBNulLen() const; +#if wxUSE_UNICODE_UTF8 + virtual bool IsUTF8() const; +#endif + virtual wxMBConv *Clone() const { - wxMBConv_iconv *p = new wxMBConv_iconv(m_name); + wxMBConv_iconv *p = new wxMBConv_iconv(m_name.ToAscii()); p->m_minMBCharWidth = m_minMBCharWidth; return p; } @@ -1635,7 +1634,7 @@ private: }; // make the constructor available for unit testing -WXDLLIMPEXP_BASE wxMBConv* new_wxMBConv_iconv( const wxChar* name ) +WXDLLIMPEXP_BASE wxMBConv* new_wxMBConv_iconv( const char* name ) { wxMBConv_iconv* result = new wxMBConv_iconv( name ); if ( !result->IsOk() ) @@ -1650,15 +1649,11 @@ WXDLLIMPEXP_BASE wxMBConv* new_wxMBConv_iconv( const wxChar* name ) wxString wxMBConv_iconv::ms_wcCharsetName; bool wxMBConv_iconv::ms_wcNeedsSwap = false; -wxMBConv_iconv::wxMBConv_iconv(const wxChar *name) +wxMBConv_iconv::wxMBConv_iconv(const char *name) : m_name(name) { m_minMBCharWidth = 0; - // iconv operates with chars, not wxChars, but luckily it uses only ASCII - // names for the charsets - const wxCharBuffer cname(wxString(name).ToAscii()); - // check for charset that represents wchar_t: if ( ms_wcCharsetName.empty() ) { @@ -1667,7 +1662,7 @@ wxMBConv_iconv::wxMBConv_iconv(const wxChar *name) #if wxUSE_FONTMAP const wxChar **names = wxFontMapperBase::GetAllEncodingNames(WC_ENC); #else // !wxUSE_FONTMAP - static const wxChar *names[] = + static const wxChar *names_static[] = { #if SIZEOF_WCHAR_T == 4 _T("UCS-4"), @@ -1676,6 +1671,7 @@ wxMBConv_iconv::wxMBConv_iconv(const wxChar *name) #endif NULL }; + const wxChar **names = names_static; #endif // wxUSE_FONTMAP/!wxUSE_FONTMAP for ( ; *names && ms_wcCharsetName.empty(); ++names ) @@ -1694,13 +1690,13 @@ wxMBConv_iconv::wxMBConv_iconv(const wxChar *name) wxLogTrace(TRACE_STRCONV, _T(" trying charset \"%s\""), nameXE.c_str()); - m2w = iconv_open(nameXE.ToAscii(), cname); + m2w = iconv_open(nameXE.ToAscii(), name); if ( m2w == ICONV_T_INVALID ) { // try charset w/o bytesex info (e.g. "UCS4") wxLogTrace(TRACE_STRCONV, _T(" trying charset \"%s\""), nameCS.c_str()); - m2w = iconv_open(nameCS.ToAscii(), cname); + m2w = iconv_open(nameCS.ToAscii(), name); // and check for bytesex ourselves: if ( m2w != ICONV_T_INVALID ) @@ -1743,14 +1739,14 @@ wxMBConv_iconv::wxMBConv_iconv(const wxChar *name) wxLogTrace(TRACE_STRCONV, wxT("iconv wchar_t charset is \"%s\"%s"), - ms_wcCharsetName.empty() ? _T("") - : ms_wcCharsetName.c_str(), + ms_wcCharsetName.empty() ? wxString("") + : ms_wcCharsetName, ms_wcNeedsSwap ? _T(" (needs swap)") : _T("")); } else // we already have ms_wcCharsetName { - m2w = iconv_open(ms_wcCharsetName.ToAscii(), cname); + m2w = iconv_open(ms_wcCharsetName.ToAscii(), name); } if ( ms_wcCharsetName.empty() ) @@ -1759,12 +1755,12 @@ wxMBConv_iconv::wxMBConv_iconv(const wxChar *name) } else { - w2m = iconv_open(cname, ms_wcCharsetName.ToAscii()); + w2m = iconv_open(name, ms_wcCharsetName.ToAscii()); if ( w2m == ICONV_T_INVALID ) { wxLogTrace(TRACE_STRCONV, wxT("\"%s\" -> \"%s\" works but not the converse!?"), - ms_wcCharsetName.c_str(), cname.data()); + ms_wcCharsetName.c_str(), name); } } } @@ -1805,8 +1801,8 @@ 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 + // 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 // 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 @@ -1953,7 +1949,7 @@ size_t wxMBConv_iconv::GetMBNulLen() const wxMutexLocker lock(self->m_iconvMutex); #endif - wchar_t *wnul = L""; + const wchar_t *wnul = L""; char buf[8]; // should be enough for NUL in any encoding size_t inLen = sizeof(wchar_t), outLen = WXSIZEOF(buf); @@ -1972,6 +1968,14 @@ size_t wxMBConv_iconv::GetMBNulLen() const return m_minMBCharWidth; } +#if wxUSE_UNICODE_UTF8 +bool wxMBConv_iconv::IsUTF8() const +{ + return wxStricmp(m_name, "UTF-8") == 0 || + wxStricmp(m_name, "UTF8") == 0; +} +#endif + #endif // HAVE_ICONV @@ -1983,7 +1987,7 @@ size_t wxMBConv_iconv::GetMBNulLen() const // from utils.cpp #if wxUSE_FONTMAP -extern WXDLLIMPEXP_BASE long wxCharsetToCodepage(const wxChar *charset); +extern WXDLLIMPEXP_BASE long wxCharsetToCodepage(const char *charset); extern WXDLLIMPEXP_BASE long wxEncodingToCodepage(wxFontEncoding encoding); #endif @@ -2004,7 +2008,7 @@ public: } #if wxUSE_FONTMAP - wxMBConv_win32(const wxChar* name) + wxMBConv_win32(const char* name) { m_CodePage = wxCharsetToCodepage(name); m_minMBCharWidth = 0; @@ -2032,12 +2036,12 @@ public: // http://msdn.microsoft.com/library/en-us/intl/unicode_17si.asp if ( m_CodePage == CP_UTF8 ) { - return wxConvUTF8.MB2WC(buf, psz, n); + return wxMBConvUTF8().MB2WC(buf, psz, n); } if ( m_CodePage == CP_UTF7 ) { - return wxConvUTF7.MB2WC(buf, psz, n); + return wxMBConvUTF7().MB2WC(buf, psz, n); } int flags = 0; @@ -2227,11 +2231,11 @@ private: int verMaj, verMin; switch ( wxGetOsVersion(&verMaj, &verMin) ) { - case wxWIN95: + case wxOS_WINDOWS_9X: s_isWin98Or2k = verMaj >= 4 && verMin >= 10; break; - case wxWINDOWS_NT: + case wxOS_WINDOWS_NT: s_isWin98Or2k = verMaj >= 5; break; @@ -2285,604 +2289,6 @@ private: #endif // wxHAVE_WIN32_MB2WC -// ============================================================================ -// Cocoa conversion classes -// ============================================================================ - -#if defined(__WXCOCOA__) - -// RN: There is no UTF-32 support in either Core Foundation or Cocoa. -// Strangely enough, internally Core Foundation uses -// UTF-32 internally quite a bit - its just not public (yet). - -#include -#include - -CFStringEncoding wxCFStringEncFromFontEnc(wxFontEncoding encoding) -{ - CFStringEncoding enc = kCFStringEncodingInvalidId ; - - switch (encoding) - { - case wxFONTENCODING_DEFAULT : - enc = CFStringGetSystemEncoding(); - break ; - - case wxFONTENCODING_ISO8859_1 : - enc = kCFStringEncodingISOLatin1 ; - break ; - case wxFONTENCODING_ISO8859_2 : - enc = kCFStringEncodingISOLatin2; - break ; - case wxFONTENCODING_ISO8859_3 : - enc = kCFStringEncodingISOLatin3 ; - break ; - case wxFONTENCODING_ISO8859_4 : - enc = kCFStringEncodingISOLatin4; - break ; - case wxFONTENCODING_ISO8859_5 : - enc = kCFStringEncodingISOLatinCyrillic; - break ; - case wxFONTENCODING_ISO8859_6 : - enc = kCFStringEncodingISOLatinArabic; - break ; - case wxFONTENCODING_ISO8859_7 : - enc = kCFStringEncodingISOLatinGreek; - break ; - case wxFONTENCODING_ISO8859_8 : - enc = kCFStringEncodingISOLatinHebrew; - break ; - case wxFONTENCODING_ISO8859_9 : - enc = kCFStringEncodingISOLatin5; - break ; - case wxFONTENCODING_ISO8859_10 : - enc = kCFStringEncodingISOLatin6; - break ; - case wxFONTENCODING_ISO8859_11 : - enc = kCFStringEncodingISOLatinThai; - break ; - case wxFONTENCODING_ISO8859_13 : - enc = kCFStringEncodingISOLatin7; - break ; - case wxFONTENCODING_ISO8859_14 : - enc = kCFStringEncodingISOLatin8; - break ; - case wxFONTENCODING_ISO8859_15 : - enc = kCFStringEncodingISOLatin9; - break ; - - case wxFONTENCODING_KOI8 : - enc = kCFStringEncodingKOI8_R; - break ; - case wxFONTENCODING_ALTERNATIVE : // MS-DOS CP866 - enc = kCFStringEncodingDOSRussian; - break ; - -// case wxFONTENCODING_BULGARIAN : -// enc = ; -// break ; - - case wxFONTENCODING_CP437 : - enc = kCFStringEncodingDOSLatinUS ; - break ; - case wxFONTENCODING_CP850 : - enc = kCFStringEncodingDOSLatin1; - break ; - case wxFONTENCODING_CP852 : - enc = kCFStringEncodingDOSLatin2; - break ; - case wxFONTENCODING_CP855 : - enc = kCFStringEncodingDOSCyrillic; - break ; - case wxFONTENCODING_CP866 : - enc = kCFStringEncodingDOSRussian ; - break ; - case wxFONTENCODING_CP874 : - enc = kCFStringEncodingDOSThai; - break ; - case wxFONTENCODING_CP932 : - enc = kCFStringEncodingDOSJapanese; - break ; - case wxFONTENCODING_CP936 : - enc = kCFStringEncodingDOSChineseSimplif ; - break ; - case wxFONTENCODING_CP949 : - enc = kCFStringEncodingDOSKorean; - break ; - case wxFONTENCODING_CP950 : - enc = kCFStringEncodingDOSChineseTrad; - break ; - case wxFONTENCODING_CP1250 : - enc = kCFStringEncodingWindowsLatin2; - break ; - case wxFONTENCODING_CP1251 : - enc = kCFStringEncodingWindowsCyrillic ; - break ; - case wxFONTENCODING_CP1252 : - enc = kCFStringEncodingWindowsLatin1 ; - break ; - case wxFONTENCODING_CP1253 : - enc = kCFStringEncodingWindowsGreek; - break ; - case wxFONTENCODING_CP1254 : - enc = kCFStringEncodingWindowsLatin5; - break ; - case wxFONTENCODING_CP1255 : - enc = kCFStringEncodingWindowsHebrew ; - break ; - case wxFONTENCODING_CP1256 : - enc = kCFStringEncodingWindowsArabic ; - break ; - case wxFONTENCODING_CP1257 : - enc = kCFStringEncodingWindowsBalticRim; - break ; -// This only really encodes to UTF7 (if that) evidently -// case wxFONTENCODING_UTF7 : -// enc = kCFStringEncodingNonLossyASCII ; -// break ; - case wxFONTENCODING_UTF8 : - enc = kCFStringEncodingUTF8 ; - break ; - case wxFONTENCODING_EUC_JP : - enc = kCFStringEncodingEUC_JP; - break ; - case wxFONTENCODING_UTF16 : - enc = kCFStringEncodingUnicode ; - break ; - case wxFONTENCODING_MACROMAN : - enc = kCFStringEncodingMacRoman ; - break ; - case wxFONTENCODING_MACJAPANESE : - enc = kCFStringEncodingMacJapanese ; - break ; - case wxFONTENCODING_MACCHINESETRAD : - enc = kCFStringEncodingMacChineseTrad ; - break ; - case wxFONTENCODING_MACKOREAN : - enc = kCFStringEncodingMacKorean ; - break ; - case wxFONTENCODING_MACARABIC : - enc = kCFStringEncodingMacArabic ; - break ; - case wxFONTENCODING_MACHEBREW : - enc = kCFStringEncodingMacHebrew ; - break ; - case wxFONTENCODING_MACGREEK : - enc = kCFStringEncodingMacGreek ; - break ; - case wxFONTENCODING_MACCYRILLIC : - enc = kCFStringEncodingMacCyrillic ; - break ; - case wxFONTENCODING_MACDEVANAGARI : - enc = kCFStringEncodingMacDevanagari ; - break ; - case wxFONTENCODING_MACGURMUKHI : - enc = kCFStringEncodingMacGurmukhi ; - break ; - case wxFONTENCODING_MACGUJARATI : - enc = kCFStringEncodingMacGujarati ; - break ; - case wxFONTENCODING_MACORIYA : - enc = kCFStringEncodingMacOriya ; - break ; - case wxFONTENCODING_MACBENGALI : - enc = kCFStringEncodingMacBengali ; - break ; - case wxFONTENCODING_MACTAMIL : - enc = kCFStringEncodingMacTamil ; - break ; - case wxFONTENCODING_MACTELUGU : - enc = kCFStringEncodingMacTelugu ; - break ; - case wxFONTENCODING_MACKANNADA : - enc = kCFStringEncodingMacKannada ; - break ; - case wxFONTENCODING_MACMALAJALAM : - enc = kCFStringEncodingMacMalayalam ; - break ; - case wxFONTENCODING_MACSINHALESE : - enc = kCFStringEncodingMacSinhalese ; - break ; - case wxFONTENCODING_MACBURMESE : - enc = kCFStringEncodingMacBurmese ; - break ; - case wxFONTENCODING_MACKHMER : - enc = kCFStringEncodingMacKhmer ; - break ; - case wxFONTENCODING_MACTHAI : - enc = kCFStringEncodingMacThai ; - break ; - case wxFONTENCODING_MACLAOTIAN : - enc = kCFStringEncodingMacLaotian ; - break ; - case wxFONTENCODING_MACGEORGIAN : - enc = kCFStringEncodingMacGeorgian ; - break ; - case wxFONTENCODING_MACARMENIAN : - enc = kCFStringEncodingMacArmenian ; - break ; - case wxFONTENCODING_MACCHINESESIMP : - enc = kCFStringEncodingMacChineseSimp ; - break ; - case wxFONTENCODING_MACTIBETAN : - enc = kCFStringEncodingMacTibetan ; - break ; - case wxFONTENCODING_MACMONGOLIAN : - enc = kCFStringEncodingMacMongolian ; - break ; - case wxFONTENCODING_MACETHIOPIC : - enc = kCFStringEncodingMacEthiopic ; - break ; - case wxFONTENCODING_MACCENTRALEUR : - enc = kCFStringEncodingMacCentralEurRoman ; - break ; - case wxFONTENCODING_MACVIATNAMESE : - enc = kCFStringEncodingMacVietnamese ; - break ; - case wxFONTENCODING_MACARABICEXT : - enc = kCFStringEncodingMacExtArabic ; - break ; - case wxFONTENCODING_MACSYMBOL : - enc = kCFStringEncodingMacSymbol ; - break ; - case wxFONTENCODING_MACDINGBATS : - enc = kCFStringEncodingMacDingbats ; - break ; - case wxFONTENCODING_MACTURKISH : - enc = kCFStringEncodingMacTurkish ; - break ; - case wxFONTENCODING_MACCROATIAN : - enc = kCFStringEncodingMacCroatian ; - break ; - case wxFONTENCODING_MACICELANDIC : - enc = kCFStringEncodingMacIcelandic ; - break ; - case wxFONTENCODING_MACROMANIAN : - enc = kCFStringEncodingMacRomanian ; - break ; - case wxFONTENCODING_MACCELTIC : - enc = kCFStringEncodingMacCeltic ; - break ; - case wxFONTENCODING_MACGAELIC : - enc = kCFStringEncodingMacGaelic ; - break ; -// case wxFONTENCODING_MACKEYBOARD : -// enc = kCFStringEncodingMacKeyboardGlyphs ; -// break ; - - default : - // because gcc is picky - break ; - } - - return enc ; -} - -class wxMBConv_cocoa : public wxMBConv -{ -public: - wxMBConv_cocoa() - { - Init(CFStringGetSystemEncoding()) ; - } - - wxMBConv_cocoa(const wxMBConv_cocoa& conv) - { - m_encoding = conv.m_encoding; - } - -#if wxUSE_FONTMAP - wxMBConv_cocoa(const wxChar* name) - { - Init( wxCFStringEncFromFontEnc(wxFontMapperBase::Get()->CharsetToEncoding(name, false) ) ) ; - } -#endif - - wxMBConv_cocoa(wxFontEncoding encoding) - { - Init( wxCFStringEncFromFontEnc(encoding) ); - } - - ~wxMBConv_cocoa() - { - } - - void Init( CFStringEncoding encoding) - { - m_encoding = encoding ; - } - - size_t MB2WC(wchar_t * szOut, const char * szUnConv, size_t nOutSize) const - { - wxASSERT(szUnConv); - - CFStringRef theString = CFStringCreateWithBytes ( - NULL, //the allocator - (const UInt8*)szUnConv, - strlen(szUnConv), - m_encoding, - false //no BOM/external representation - ); - - wxASSERT(theString); - - size_t nOutLength = CFStringGetLength(theString); - - if (szOut == NULL) - { - CFRelease(theString); - return nOutLength; - } - - CFRange theRange = { 0, nOutSize }; - -#if SIZEOF_WCHAR_T == 4 - UniChar* szUniCharBuffer = new UniChar[nOutSize]; -#endif - - CFStringGetCharacters(theString, theRange, szUniCharBuffer); - - CFRelease(theString); - - szUniCharBuffer[nOutLength] = '\0'; - -#if SIZEOF_WCHAR_T == 4 - wxMBConvUTF16 converter; - converter.MB2WC( szOut, (const char*)szUniCharBuffer, nOutSize ); - delete [] szUniCharBuffer; -#endif - - return nOutLength; - } - - size_t WC2MB(char *szOut, const wchar_t *szUnConv, size_t nOutSize) const - { - wxASSERT(szUnConv); - - size_t nRealOutSize; - size_t nBufSize = wxWcslen(szUnConv); - UniChar* szUniBuffer = (UniChar*) szUnConv; - -#if SIZEOF_WCHAR_T == 4 - 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); -#endif - - CFStringRef theString = CFStringCreateWithCharactersNoCopy( - NULL, //allocator - szUniBuffer, - nBufSize, - kCFAllocatorNull //deallocator - we want to deallocate it ourselves - ); - - wxASSERT(theString); - - //Note that CER puts a BOM when converting to unicode - //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); - - 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 - ); - } - - CFRelease(theString); - -#if SIZEOF_WCHAR_T == 4 - delete[] szUniBuffer; -#endif - - return nRealOutSize - 1; - } - - virtual wxMBConv *Clone() const { return new wxMBConv_cocoa(*this); } - - bool IsOk() const - { - return m_encoding != kCFStringEncodingInvalidId && - CFStringIsEncodingAvailable(m_encoding); - } - -private: - CFStringEncoding m_encoding ; -}; - -#endif // defined(__WXCOCOA__) - -// ============================================================================ -// Mac conversion classes -// ============================================================================ - -#if defined(__WXMAC__) && defined(TARGET_CARBON) - -class wxMBConv_mac : public wxMBConv -{ -public: - wxMBConv_mac() - { - Init(CFStringGetSystemEncoding()) ; - } - - wxMBConv_mac(const wxMBConv_mac& conv) - { - Init(conv.m_char_encoding); - } - -#if wxUSE_FONTMAP - wxMBConv_mac(const wxChar* name) - { - Init( wxMacGetSystemEncFromFontEnc( wxFontMapperBase::Get()->CharsetToEncoding(name, false) ) ); - } -#endif - - wxMBConv_mac(wxFontEncoding encoding) - { - Init( wxMacGetSystemEncFromFontEnc(encoding) ); - } - - ~wxMBConv_mac() - { - OSStatus status = noErr ; - status = TECDisposeConverter(m_MB2WC_converter); - status = TECDisposeConverter(m_WC2MB_converter); - } - - - void Init( TextEncodingBase encoding) - { - OSStatus status = noErr ; - m_char_encoding = encoding ; - m_unicode_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault, 0, kUnicode16BitFormat) ; - - status = TECCreateConverter(&m_MB2WC_converter, - m_char_encoding, - m_unicode_encoding); - status = TECCreateConverter(&m_WC2MB_converter, - m_unicode_encoding, - m_char_encoding); - } - - size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const - { - OSStatus status = noErr ; - ByteCount byteOutLen ; - ByteCount byteInLen = strlen(psz) + 1; - wchar_t *tbuf = NULL ; - UniChar* ubuf = NULL ; - size_t res = 0 ; - - if (buf == NULL) - { - // Apple specs say at least 32 - n = wxMax( 32, byteInLen ) ; - tbuf = (wchar_t*) malloc( n * SIZEOF_WCHAR_T ) ; - } - - ByteCount byteBufferLen = n * sizeof( UniChar ) ; - -#if SIZEOF_WCHAR_T == 4 - ubuf = (UniChar*) malloc( byteBufferLen + 2 ) ; -#else - ubuf = (UniChar*) (buf ? buf : tbuf) ; -#endif - - status = TECConvertText( - m_MB2WC_converter, (ConstTextPtr) psz, byteInLen, &byteInLen, - (TextPtr) ubuf, byteBufferLen, &byteOutLen); - -#if SIZEOF_WCHAR_T == 4 - // 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 ; - wxMBConvUTF16 converter ; - res = converter.MB2WC( (buf ? buf : tbuf), (const char*)ubuf, n ) ; - free( ubuf ) ; -#else - res = byteOutLen / sizeof( UniChar ) ; -#endif - - if ( buf == NULL ) - free(tbuf) ; - - if ( buf && res < n) - buf[res] = 0; - - return res ; - } - - size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const - { - OSStatus status = noErr ; - ByteCount byteOutLen ; - ByteCount byteInLen = wxWcslen(psz) * SIZEOF_WCHAR_T ; - - char *tbuf = NULL ; - - if (buf == NULL) - { - // 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 - wxMBConvUTF16 converter ; - size_t unicharlen = converter.WC2MB( NULL, psz, 0 ) ; - byteInLen = unicharlen ; - ubuf = (UniChar*) malloc( byteInLen + 2 ) ; - converter.WC2MB( (char*) ubuf, psz, unicharlen + 2 ) ; -#else - ubuf = (UniChar*) psz ; -#endif - - status = TECConvertText( - m_WC2MB_converter, (ConstTextPtr) ubuf, byteInLen, &byteInLen, - (TextPtr) (buf ? buf : tbuf), byteBufferLen, &byteOutLen); - -#if SIZEOF_WCHAR_T == 4 - free( ubuf ) ; -#endif - - if ( buf == NULL ) - free(tbuf) ; - - 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) == wxCONV_FAILED || - 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 wxCONV_FAILED; - } - } - - return res ; - } - - virtual wxMBConv *Clone() const { return new wxMBConv_mac(*this); } - - bool IsOk() const - { return m_MB2WC_converter != NULL && m_WC2MB_converter != NULL; } - -private: - TECObjectRef m_MB2WC_converter; - TECObjectRef m_WC2MB_converter; - - TextEncodingBase m_char_encoding; - TextEncodingBase m_unicode_encoding; -}; - -#endif // defined(__WXMAC__) && defined(TARGET_CARBON) // ============================================================================ // wxEncodingConverter based conversion classes @@ -2895,14 +2301,17 @@ class wxMBConv_wxwin : public wxMBConv private: void Init() { - m_ok = m2w.Init(m_enc, wxFONTENCODING_UNICODE) && + // Refuse to use broken wxEncodingConverter code for Mac-specific encodings. + // The wxMBConv_cf class does a better job. + m_ok = (m_enc < wxFONTENCODING_MACMIN || m_enc > wxFONTENCODING_MACMAX) && + m2w.Init(m_enc, wxFONTENCODING_UNICODE) && w2m.Init(wxFONTENCODING_UNICODE, m_enc); } public: // temporarily just use wxEncodingConverter stuff, // so that it works while a better implementation is built - wxMBConv_wxwin(const wxChar* name) + wxMBConv_wxwin(const char* name) { if (name) m_enc = wxFontMapperBase::Get()->CharsetToEncoding(name, false); @@ -2975,7 +2384,7 @@ private: }; // make the constructors available for unit testing -WXDLLIMPEXP_BASE wxMBConv* new_wxMBConv_wxwin( const wxChar* name ) +WXDLLIMPEXP_BASE wxMBConv* new_wxMBConv_wxwin( const char* name ) { wxMBConv_wxwin* result = new wxMBConv_wxwin( name ); if ( !result->IsOk() ) @@ -3000,13 +2409,13 @@ void wxCSConv::Init() m_deferred = true; } -wxCSConv::wxCSConv(const wxChar *charset) +wxCSConv::wxCSConv(const wxString& charset) { Init(); - if ( charset ) + if ( !charset.empty() ) { - SetName(charset); + SetName(charset.ToAscii()); } #if wxUSE_FONTMAP @@ -3063,17 +2472,16 @@ void wxCSConv::Clear() m_convReal = NULL; } -void wxCSConv::SetName(const wxChar *charset) +void wxCSConv::SetName(const char *charset) { if (charset) { - m_name = wxStrdup(charset); + m_name = strdup(charset); m_deferred = true; } } #if wxUSE_FONTMAP -#include "wx/hashmap.h" WX_DECLARE_HASH_MAP( wxFontEncoding, wxString, wxIntegerHash, wxIntegerEqual, wxEncodingNameCache ); @@ -3087,7 +2495,7 @@ wxMBConv *wxCSConv::DoCreate() const wxLogTrace(TRACE_STRCONV, wxT("creating conversion for %s"), (m_name ? m_name - : wxFontMapperBase::GetEncodingName(m_encoding).c_str())); + : (const char*)wxFontMapperBase::GetEncodingName(m_encoding).mb_str())); #endif // wxUSE_FONTMAP // check for the special case of ASCII or ISO8859-1 charset: as we have @@ -3114,12 +2522,13 @@ wxMBConv *wxCSConv::DoCreate() const if ( m_name ) #endif // !wxUSE_FONTMAP { - wxString name(m_name); +#if wxUSE_FONTMAP wxFontEncoding encoding(m_encoding); +#endif - if ( !name.empty() ) + if ( m_name ) { - wxMBConv_iconv *conv = new wxMBConv_iconv(name); + wxMBConv_iconv *conv = new wxMBConv_iconv(m_name); if ( conv->IsOk() ) return conv; @@ -3127,7 +2536,7 @@ wxMBConv *wxCSConv::DoCreate() const #if wxUSE_FONTMAP encoding = - wxFontMapperBase::Get()->CharsetToEncoding(name, false); + wxFontMapperBase::Get()->CharsetToEncoding(m_name, false); #endif // wxUSE_FONTMAP } #if wxUSE_FONTMAP @@ -3138,7 +2547,7 @@ wxMBConv *wxCSConv::DoCreate() const if ( it->second.empty() ) return NULL; - wxMBConv_iconv *conv = new wxMBConv_iconv(it->second); + wxMBConv_iconv *conv = new wxMBConv_iconv(it->second.ToAscii()); if ( conv->IsOk() ) return conv; @@ -3146,20 +2555,30 @@ wxMBConv *wxCSConv::DoCreate() const } const wxChar** names = wxFontMapperBase::GetAllEncodingNames(encoding); - - for ( ; *names; ++names ) + // CS : in case this does not return valid names (eg for MacRoman) + // encoding got a 'failure' entry in the cache all the same, + // although it just has to be created using a different method, so + // only store failed iconv creation attempts (or perhaps we + // shoulnd't do this at all ?) + if ( names[0] != NULL ) { - wxMBConv_iconv *conv = new wxMBConv_iconv(*names); - if ( conv->IsOk() ) + for ( ; *names; ++names ) { - gs_nameCache[encoding] = *names; - return conv; + // FIXME-UTF8: wxFontMapperBase::GetAllEncodingNames() + // will need changes that will obsolete this + wxString name(*names); + wxMBConv_iconv *conv = new wxMBConv_iconv(name.ToAscii()); + if ( conv->IsOk() ) + { + gs_nameCache[encoding] = *names; + return conv; + } + + delete conv; } - delete conv; + gs_nameCache[encoding] = _T(""); // cache the failure } - - gs_nameCache[encoding] = _T(""); // cache the failure } #endif // wxUSE_FONTMAP } @@ -3180,35 +2599,17 @@ wxMBConv *wxCSConv::DoCreate() const } #endif // wxHAVE_WIN32_MB2WC -#if defined(__WXMAC__) +#ifdef __DARWIN__ { // 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); + wxMBConv_cf *conv = m_name ? new wxMBConv_cf(m_name) + : new wxMBConv_cf(m_encoding); #else - wxMBConv_mac *conv = new wxMBConv_mac(m_encoding); -#endif - if ( conv->IsOk() ) - return conv; - - delete conv; - } - } -#endif - -#if defined(__WXCOCOA__) - { - 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); + wxMBConv_cf *conv = new wxMBConv_cf(m_encoding); #endif if ( conv->IsOk() ) @@ -3217,7 +2618,8 @@ wxMBConv *wxCSConv::DoCreate() const delete conv; } } -#endif +#endif // __DARWIN__ + // step (2) wxFontEncoding enc = m_encoding; #if wxUSE_FONTMAP @@ -3270,10 +2672,10 @@ wxMBConv *wxCSConv::DoCreate() const // NB: This is a hack to prevent deadlock. What could otherwise happen // in Unicode build: wxConvLocal creation ends up being here // because of some failure and logs the error. But wxLog will try to - // attach timestamp, for which it will need wxConvLocal (to convert - // time to char* and then wchar_t*), but that fails, tries to log - // error, but wxLog has a (already locked) critical section that - // guards static buffer. + // attach a timestamp, for which it will need wxConvLocal (to convert + // time to char* and then wchar_t*), but that fails, tries to log the + // error, but wxLog has an (already locked) critical section that + // guards the static buffer. static bool alreadyLoggingError = false; if (!alreadyLoggingError) { @@ -3282,9 +2684,9 @@ wxMBConv *wxCSConv::DoCreate() const m_name ? m_name : #if wxUSE_FONTMAP - wxFontMapperBase::GetEncodingDescription(m_encoding).c_str() + (const char*)wxFontMapperBase::GetEncodingDescription(m_encoding).ToAscii() #else // !wxUSE_FONTMAP - wxString::Format(_("encoding %s"), m_encoding).c_str() + (const char*)wxString::Format(_("encoding %i"), m_encoding).ToAscii() #endif // wxUSE_FONTMAP/!wxUSE_FONTMAP ); @@ -3300,20 +2702,60 @@ void wxCSConv::CreateConvIfNeeded() const { wxCSConv *self = (wxCSConv *)this; // const_cast -#if wxUSE_INTL // if we don't have neither the name nor the encoding, use the default // encoding for this system if ( !m_name && m_encoding == wxFONTENCODING_SYSTEM ) { - self->m_name = wxStrdup(wxLocale::GetSystemEncodingName()); - } +#if wxUSE_INTL + self->m_encoding = wxLocale::GetSystemEncoding(); +#else + // fallback to some reasonable default: + self->m_encoding = wxFONTENCODING_ISO8859_1; #endif // wxUSE_INTL + } self->m_convReal = DoCreate(); self->m_deferred = false; } } +bool wxCSConv::IsOk() const +{ + CreateConvIfNeeded(); + + // special case: no convReal created for wxFONTENCODING_ISO8859_1 + if ( m_encoding == wxFONTENCODING_ISO8859_1 ) + return true; // always ok as we do it ourselves + + // m_convReal->IsOk() is called at its own creation, so we know it must + // be ok if m_convReal is non-NULL + return m_convReal != NULL; +} + +size_t wxCSConv::ToWChar(wchar_t *dst, size_t dstLen, + const char *src, size_t srcLen) const +{ + CreateConvIfNeeded(); + + if (m_convReal) + return m_convReal->ToWChar(dst, dstLen, src, srcLen); + + // latin-1 (direct) + return wxMBConv::ToWChar(dst, dstLen, src, srcLen); +} + +size_t wxCSConv::FromWChar(char *dst, size_t dstLen, + const wchar_t *src, size_t srcLen) const +{ + CreateConvIfNeeded(); + + if (m_convReal) + return m_convReal->FromWChar(dst, dstLen, src, srcLen); + + // latin-1 (direct) + return wxMBConv::FromWChar(dst, dstLen, src, srcLen); +} + size_t wxCSConv::MB2WC(wchar_t *buf, const char *psz, size_t n) const { CreateConvIfNeeded(); @@ -3373,42 +2815,119 @@ size_t wxCSConv::GetMBNulLen() const return m_convReal->GetMBNulLen(); } + // otherwise, we are ISO-8859-1 return 1; } +#if wxUSE_UNICODE_UTF8 +bool wxCSConv::IsUTF8() const +{ + CreateConvIfNeeded(); + + if ( m_convReal ) + { + return m_convReal->IsUTF8(); + } + + // otherwise, we are ISO-8859-1 + return false; +} +#endif + + +#if wxUSE_UNICODE + +wxWCharBuffer wxSafeConvertMB2WX(const char *s) +{ + if ( !s ) + return wxWCharBuffer(); + + wxWCharBuffer wbuf(wxConvLibc.cMB2WX(s)); + if ( !wbuf ) + wbuf = wxMBConvUTF8().cMB2WX(s); + if ( !wbuf ) + wbuf = wxConvISO8859_1.cMB2WX(s); + + return wbuf; +} + +wxCharBuffer wxSafeConvertWX2MB(const wchar_t *ws) +{ + if ( !ws ) + return wxCharBuffer(); + + wxCharBuffer buf(wxConvLibc.cWX2MB(ws)); + if ( !buf ) + buf = wxMBConvUTF8(wxMBConvUTF8::MAP_INVALID_UTF8_TO_OCTAL).cWX2MB(ws); + + return buf; +} + +#endif // wxUSE_UNICODE + // ---------------------------------------------------------------------------- // globals // ---------------------------------------------------------------------------- +// NB: The reason why we create converted objects in this convoluted way, +// using a factory function instead of global variable, is that they +// may be used at static initialization time (some of them are used by +// wxString ctors and there may be a global wxString object). In other +// words, possibly _before_ the converter global object would be +// initialized. + +#undef wxConvLibc +#undef wxConvUTF8 +#undef wxConvUTF7 +#undef wxConvLocal +#undef wxConvISO8859_1 + +#define WX_DEFINE_GLOBAL_CONV2(klass, impl_klass, name, ctor_args) \ + WXDLLIMPEXP_DATA_BASE(klass*) name##Ptr = NULL; \ + WXDLLIMPEXP_BASE klass* wxGet_##name##Ptr() \ + { \ + static impl_klass name##Obj ctor_args; \ + return &name##Obj; \ + } \ + /* this ensures that all global converter objects are created */ \ + /* by the time static initialization is done, i.e. before any */ \ + /* thread is launched: */ \ + static klass* gs_##name##instance = wxGet_##name##Ptr() + +#define WX_DEFINE_GLOBAL_CONV(klass, name, ctor_args) \ + WX_DEFINE_GLOBAL_CONV2(klass, klass, name, ctor_args) + #ifdef __WINDOWS__ - static wxMBConv_win32 wxConvLibcObj; -#elif defined(__WXMAC__) && !defined(__MACH__) - static wxMBConv_mac wxConvLibcObj ; + WX_DEFINE_GLOBAL_CONV2(wxMBConv, wxMBConv_win32, wxConvLibc, wxEMPTY_PARAMETER_VALUE); #else - static wxMBConvLibc wxConvLibcObj; + WX_DEFINE_GLOBAL_CONV2(wxMBConv, wxMBConvLibc, wxConvLibc, wxEMPTY_PARAMETER_VALUE); #endif -static wxCSConv wxConvLocalObj(wxFONTENCODING_SYSTEM); -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 *) wxConvUI = &wxConvLocal; -WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvFileName = & -#ifdef __WXOSX__ - wxConvUTF8Obj; -#else - wxConvLibcObj; +WX_DEFINE_GLOBAL_CONV(wxMBConvUTF8, wxConvUTF8, wxEMPTY_PARAMETER_VALUE); +WX_DEFINE_GLOBAL_CONV(wxMBConvUTF7, wxConvUTF7, wxEMPTY_PARAMETER_VALUE); + +WX_DEFINE_GLOBAL_CONV(wxCSConv, wxConvLocal, (wxFONTENCODING_SYSTEM)); +WX_DEFINE_GLOBAL_CONV(wxCSConv, wxConvISO8859_1, (wxFONTENCODING_ISO8859_1)); + +WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvCurrent = wxGet_wxConvLibcPtr(); +WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvUI = wxGet_wxConvLocalPtr(); + +#ifdef __DARWIN__ +// The xnu kernel always communicates file paths in decomposed UTF-8. +// WARNING: Are we sure that CFString's conversion will cause decomposition? +static wxMBConv_cf wxConvMacUTF8DObj(wxFONTENCODING_UTF8); #endif +WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvFileName = +#ifdef __DARWIN__ + &wxConvMacUTF8DObj; +#else // !__DARWIN__ + wxGet_wxConvLibcPtr(); +#endif // __DARWIN__/!__DARWIN__ + #else // !wxUSE_WCHAR_T +// FIXME-UTF8: remove this, wxUSE_WCHAR_T is required now // stand-ins in absence of wchar_t WXDLLIMPEXP_DATA_BASE(wxMBConv) wxConvLibc, wxConvISO8859_1,