X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1e1c5d6276dadefa53deebbd7fe5b766bad74cde..507abc7b3af8d73e7caf05261d1f40b51775ae7a:/src/common/strconv.cpp diff --git a/src/common/strconv.cpp b/src/common/strconv.cpp index 49e78f40dd..a603d02f18 100644 --- a/src/common/strconv.cpp +++ b/src/common/strconv.cpp @@ -19,6 +19,7 @@ #include "wx/intl.h" #include "wx/log.h" #include "wx/utils.h" + #include "wx/hashmap.h" #endif #include "wx/strconv.h" @@ -1805,8 +1806,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 @@ -2741,27 +2742,40 @@ public: ~wxMBConv_mac() { OSStatus status = noErr ; - status = TECDisposeConverter(m_MB2WC_converter); - status = TECDisposeConverter(m_WC2MB_converter); + if (m_MB2WC_converter) + status = TECDisposeConverter(m_MB2WC_converter); + if (m_WC2MB_converter) + status = TECDisposeConverter(m_WC2MB_converter); } - - void Init( TextEncodingBase encoding) + void Init( TextEncodingBase encoding,TextEncodingVariant encodingVariant = kTextEncodingDefaultVariant , + TextEncodingFormat encodingFormat = kTextEncodingDefaultFormat) { - OSStatus status = noErr ; - m_char_encoding = encoding ; + m_MB2WC_converter = NULL ; + m_WC2MB_converter = NULL ; + m_char_encoding = CreateTextEncoding(encoding, encodingVariant, encodingFormat) ; m_unicode_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault, 0, kUnicode16BitFormat) ; + } - status = TECCreateConverter(&m_MB2WC_converter, + virtual void CreateIfNeeded() const + { + if ( m_MB2WC_converter == NULL && m_WC2MB_converter == NULL ) + { + OSStatus status = noErr ; + status = TECCreateConverter(&m_MB2WC_converter, m_char_encoding, m_unicode_encoding); - status = TECCreateConverter(&m_WC2MB_converter, + wxASSERT_MSG( status == noErr , _("Unable to create TextEncodingConverter")) ; + status = TECCreateConverter(&m_WC2MB_converter, m_unicode_encoding, m_char_encoding); + wxASSERT_MSG( status == noErr , _("Unable to create TextEncodingConverter")) ; + } } - + size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const { + CreateIfNeeded() ; OSStatus status = noErr ; ByteCount byteOutLen ; ByteCount byteInLen = strlen(psz) + 1; @@ -2810,6 +2824,7 @@ public: size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const { + CreateIfNeeded() ; OSStatus status = noErr ; ByteCount byteOutLen ; ByteCount byteInLen = wxWcslen(psz) * SIZEOF_WCHAR_T ; @@ -2872,16 +2887,192 @@ public: virtual wxMBConv *Clone() const { return new wxMBConv_mac(*this); } bool IsOk() const - { return m_MB2WC_converter != NULL && m_WC2MB_converter != NULL; } + { + CreateIfNeeded() ; + return m_MB2WC_converter != NULL && m_WC2MB_converter != NULL; + } -private: - TECObjectRef m_MB2WC_converter; - TECObjectRef m_WC2MB_converter; +protected : + mutable TECObjectRef m_MB2WC_converter; + mutable TECObjectRef m_WC2MB_converter; TextEncodingBase m_char_encoding; TextEncodingBase m_unicode_encoding; }; +// MB is decomposed (D) normalized UTF8 + +class wxMBConv_macUTF8D : public wxMBConv_mac +{ +public : + wxMBConv_macUTF8D() + { + Init( kTextEncodingUnicodeDefault , kUnicodeNoSubset , kUnicodeUTF8Format ) ; + m_uni = NULL; + m_uniBack = NULL ; + } + + ~wxMBConv_macUTF8D() + { + if (m_uni!=NULL) + DisposeUnicodeToTextInfo(&m_uni); + if (m_uniBack!=NULL) + DisposeUnicodeToTextInfo(&m_uniBack); + } + + size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const + { + CreateIfNeeded() ; + 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 + + // ubuf is a non-decomposed UniChar buffer + + ByteCount dcubuflen = byteInLen * 2 + 2 ; + ByteCount dcubufread , dcubufwritten ; + UniChar *dcubuf = (UniChar*) malloc( dcubuflen ) ; + + ConvertFromUnicodeToText( m_uni , byteInLen , ubuf , + kUnicodeDefaultDirectionMask, 0, NULL, NULL, NULL, dcubuflen , &dcubufread , &dcubufwritten , dcubuf ) ; + + // we now convert that decomposed buffer into UTF8 + + status = TECConvertText( + m_WC2MB_converter, (ConstTextPtr) dcubuf, dcubufwritten, &dcubufread, + (TextPtr) (buf ? buf : tbuf), byteBufferLen, &byteOutLen); + + free( dcubuf ); + +#if SIZEOF_WCHAR_T == 4 + free( ubuf ) ; +#endif + + if ( buf == NULL ) + free(tbuf) ; + + size_t res = byteOutLen ; + if ( buf && res < n) + { + buf[res] = 0; + // don't test for round-trip fidelity yet, we cannot guarantee it yet + } + + return res ; + } + + size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const + { + CreateIfNeeded() ; + 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 + + ByteCount dcubuflen = byteBufferLen * 2 + 2 ; + ByteCount dcubufread , dcubufwritten ; + UniChar *dcubuf = (UniChar*) malloc( dcubuflen ) ; + + status = TECConvertText( + m_MB2WC_converter, (ConstTextPtr) psz, byteInLen, &byteInLen, + (TextPtr) dcubuf, dcubuflen, &byteOutLen); + // 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 + dcubuf[byteOutLen / sizeof( UniChar ) ] = 0 ; + + // now from the decomposed UniChar to properly composed uniChar + ConvertFromUnicodeToText( m_uniBack , byteOutLen , dcubuf , + kUnicodeDefaultDirectionMask, 0, NULL, NULL, NULL, dcubuflen , &dcubufread , &dcubufwritten , ubuf ) ; + + free( dcubuf ); + byteOutLen = dcubufwritten ; + ubuf[byteOutLen / sizeof( UniChar ) ] = 0 ; + + +#if SIZEOF_WCHAR_T == 4 + 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 ; + } + + virtual void CreateIfNeeded() const + { + wxMBConv_mac::CreateIfNeeded() ; + if ( m_uni == NULL ) + { + m_map.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, + kUnicodeNoSubset, kTextEncodingDefaultFormat); + m_map.otherEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, + kUnicodeCanonicalDecompVariant, kTextEncodingDefaultFormat); + m_map.mappingVersion = kUnicodeUseLatestMapping; + + OSStatus err = CreateUnicodeToTextInfo(&m_map, &m_uni); + wxASSERT_MSG( err == noErr , _(" Couldn't create the UnicodeConverter")) ; + + m_map.unicodeEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, + kUnicodeNoSubset, kTextEncodingDefaultFormat); + m_map.otherEncoding = CreateTextEncoding(kTextEncodingUnicodeDefault, + kUnicodeCanonicalCompVariant, kTextEncodingDefaultFormat); + m_map.mappingVersion = kUnicodeUseLatestMapping; + err = CreateUnicodeToTextInfo(&m_map, &m_uniBack); + wxASSERT_MSG( err == noErr , _(" Couldn't create the UnicodeConverter")) ; + } + } +protected : + mutable UnicodeToTextInfo m_uni; + mutable UnicodeToTextInfo m_uniBack; + mutable UnicodeMapping m_map; +}; #endif // defined(__WXMAC__) && defined(TARGET_CARBON) // ============================================================================ @@ -3073,7 +3264,6 @@ void wxCSConv::SetName(const wxChar *charset) } #if wxUSE_FONTMAP -#include "wx/hashmap.h" WX_DECLARE_HASH_MAP( wxFontEncoding, wxString, wxIntegerHash, wxIntegerEqual, wxEncodingNameCache ); @@ -3270,10 +3460,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) { @@ -3392,7 +3582,9 @@ static wxCSConv wxConvLocalObj(wxFONTENCODING_SYSTEM); static wxCSConv wxConvISO8859_1Obj(wxFONTENCODING_ISO8859_1); static wxMBConvUTF7 wxConvUTF7Obj; static wxMBConvUTF8 wxConvUTF8Obj; - +#if defined(__WXMAC__) && defined(TARGET_CARBON) +static wxMBConv_macUTF8D wxConvMacUTF8DObj; +#endif WXDLLIMPEXP_DATA_BASE(wxMBConv&) wxConvLibc = wxConvLibcObj; WXDLLIMPEXP_DATA_BASE(wxCSConv&) wxConvLocal = wxConvLocalObj; WXDLLIMPEXP_DATA_BASE(wxCSConv&) wxConvISO8859_1 = wxConvISO8859_1Obj; @@ -3402,7 +3594,11 @@ WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvCurrent = &wxConvLibcObj; WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvUI = &wxConvLocal; WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvFileName = & #ifdef __WXOSX__ +#if defined(__WXMAC__) && defined(TARGET_CARBON) + wxConvMacUTF8DObj; +#else wxConvUTF8Obj; +#endif #else wxConvLibcObj; #endif