X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a243da29c8135be476e47a035a81e695bbb21e26..abd474ea63667f727940a009cc3e0b23ba9f418f:/src/common/strconv.cpp?ds=sidebyside diff --git a/src/common/strconv.cpp b/src/common/strconv.cpp index db51e2c41b..170ad719bd 100644 --- a/src/common/strconv.cpp +++ b/src/common/strconv.cpp @@ -28,8 +28,6 @@ #include "wx/strconv.h" -#if wxUSE_WCHAR_T - #ifndef __WXWINCE__ #include #endif @@ -323,16 +321,22 @@ wxMBConv::FromWChar(char *dst, size_t dstLen, const size_t lenNul = GetMBNulLen(); for ( const wchar_t * const srcEnd = src + srcLen; src < srcEnd; - src += wxWcslen(src) + 1 /* skip L'\0' too */ ) + src++ /* skip L'\0' too */ ) { // try to convert the current chunk size_t lenChunk = WC2MB(NULL, src, 0); - if ( lenChunk == wxCONV_FAILED ) return wxCONV_FAILED; dstWritten += lenChunk; - if ( src + lenChunk < srcEnd || isNulTerminated ) + + const wchar_t * const + chunkEnd = isNulTerminated ? srcEnd - 1 : src + wxWcslen(src); + + // our return value accounts for the trailing NUL(s), unlike that of + // WC2MB(), however don't do it for the last NUL we artificially added + // ourselves above + if ( chunkEnd < srcEnd ) dstWritten += lenNul; if ( dst ) @@ -340,13 +344,42 @@ wxMBConv::FromWChar(char *dst, size_t dstLen, if ( dstWritten > dstLen ) return wxCONV_FAILED; - if ( WC2MB(dst, src, lenChunk + lenNul) == wxCONV_FAILED ) + // if we know that there is enough space in the destination buffer + // (because we accounted for lenNul in dstWritten above), we can + // convert directly in place -- but otherwise we need another + // temporary buffer to ensure that we don't overwrite the output + wxCharBuffer dstBuf; + char *dstTmp; + if ( chunkEnd == srcEnd ) + { + dstBuf = wxCharBuffer(lenChunk + lenNul - 1); + dstTmp = dstBuf.data(); + } + else + { + dstTmp = dst; + } + + if ( WC2MB(dstTmp, src, lenChunk + lenNul) == wxCONV_FAILED ) return wxCONV_FAILED; + if ( dstTmp != dst ) + { + // copy everything up to but excluding the terminating NUL(s) + // into the real output buffer + memcpy(dst, dstTmp, lenChunk); + + // micro-optimization: if dstTmp != dst it means that chunkEnd + // == srcEnd and so we're done, no need to update anything below + break; + } + dst += lenChunk; - if ( src + lenChunk < srcEnd || isNulTerminated ) + if ( chunkEnd < srcEnd ) dst += lenNul; } + + src = chunkEnd; } return dstWritten; @@ -504,7 +537,7 @@ const wxWCharBuffer wxMBConv::cMB2WC(const wxScopedCharBuffer& buf) const } } - return wxWCharBuffer(); + return wxScopedWCharBuffer::CreateNonOwned(L"", 0); } const wxCharBuffer wxMBConv::cWC2MB(const wxScopedWCharBuffer& wbuf) const @@ -522,7 +555,7 @@ const wxCharBuffer wxMBConv::cWC2MB(const wxScopedWCharBuffer& wbuf) const } } - return wxCharBuffer(); + return wxScopedCharBuffer::CreateNonOwned("", 0); } // ---------------------------------------------------------------------------- @@ -962,7 +995,7 @@ wxMBConvStrictUTF8::ToWChar(wchar_t *dst, size_t dstLen, for ( const char *p = src; ; p++ ) { - if ( !(srcLen == wxNO_LEN ? *p : srcLen) ) + if ( (srcLen == wxNO_LEN ? !*p : !srcLen) ) { // all done successfully, just add the trailing NULL if we are not // using explicit length @@ -1082,7 +1115,7 @@ wxMBConvStrictUTF8::FromWChar(char *dst, size_t dstLen, for ( const wchar_t *wp = src; ; wp++ ) { - if ( !(srcLen == wxNO_LEN ? *wp : srcLen) ) + if ( (srcLen == wxNO_LEN ? !*wp : !srcLen) ) { // all done successfully, just add the trailing NULL if we are not // using explicit length @@ -1612,7 +1645,7 @@ wxMBConvUTF16straight::FromWChar(char *dst, size_t dstLen, wxUint16 *outBuff = reinterpret_cast(dst); for ( size_t n = 0; n < srcLen; n++ ) { - wxUint16 cc[2]; + wxUint16 cc[2] = { 0 }; const size_t numChars = encode_utf16(*src++, cc); if ( numChars == wxCONV_FAILED ) return wxCONV_FAILED; @@ -1695,7 +1728,7 @@ wxMBConvUTF16swap::FromWChar(char *dst, size_t dstLen, wxUint16 *outBuff = reinterpret_cast(dst); for ( const wchar_t *srcEnd = src + srcLen; src < srcEnd; src++ ) { - wxUint16 cc[2]; + wxUint16 cc[2] = { 0 }; const size_t numChars = encode_utf16(*src, cc); if ( numChars == wxCONV_FAILED ) return wxCONV_FAILED; @@ -1779,7 +1812,7 @@ wxMBConvUTF32straight::ToWChar(wchar_t *dst, size_t dstLen, size_t outLen = 0; for ( size_t n = 0; n < inLen; n++ ) { - wxUint16 cc[2]; + wxUint16 cc[2] = { 0 }; const size_t numChars = encode_utf16(*inBuff++, cc); if ( numChars == wxCONV_FAILED ) return wxCONV_FAILED; @@ -1857,7 +1890,7 @@ wxMBConvUTF32swap::ToWChar(wchar_t *dst, size_t dstLen, size_t outLen = 0; for ( size_t n = 0; n < inLen; n++, inBuff++ ) { - wxUint16 cc[2]; + wxUint16 cc[2] = { 0 }; const size_t numChars = encode_utf16(wxUINT32_SWAP_ALWAYS(*inBuff), cc); if ( numChars == wxCONV_FAILED ) return wxCONV_FAILED; @@ -2080,7 +2113,7 @@ public: virtual wxMBConv *Clone() const { - wxMBConv_iconv *p = new wxMBConv_iconv(m_name.ToAscii()); + wxMBConv_iconv *p = new wxMBConv_iconv(m_name); p->m_minMBCharWidth = m_minMBCharWidth; return p; } @@ -2110,7 +2143,7 @@ private: // name of the encoding handled by this conversion - wxString m_name; + const char *m_name; // cached result of GetMBNulLen(); set to 0 meaning "unknown" // initially @@ -2134,7 +2167,7 @@ wxString wxMBConv_iconv::ms_wcCharsetName; bool wxMBConv_iconv::ms_wcNeedsSwap = false; wxMBConv_iconv::wxMBConv_iconv(const char *name) - : m_name(name) + : m_name(wxStrdup(name)) { m_minMBCharWidth = 0; @@ -2150,7 +2183,7 @@ wxMBConv_iconv::wxMBConv_iconv(const char *name) { #if SIZEOF_WCHAR_T == 4 wxT("UCS-4"), -#elif SIZEOF_WCHAR_T = 2 +#elif SIZEOF_WCHAR_T == 2 wxT("UCS-2"), #endif NULL @@ -2251,6 +2284,8 @@ wxMBConv_iconv::wxMBConv_iconv(const char *name) wxMBConv_iconv::~wxMBConv_iconv() { + free(const_cast(m_name)); + if ( m2w != ICONV_T_INVALID ) iconv_close(m2w); if ( w2m != ICONV_T_INVALID ) @@ -2910,7 +2945,41 @@ void wxCSConv::Init() { m_name = NULL; m_convReal = NULL; - m_deferred = true; +} + +void wxCSConv::SetEncoding(wxFontEncoding encoding) +{ + switch ( encoding ) + { + case wxFONTENCODING_MAX: + case wxFONTENCODING_SYSTEM: + if ( m_name ) + { + // It's ok to not have encoding value if we have a name for it. + m_encoding = wxFONTENCODING_SYSTEM; + } + else // No name neither. + { + // Fall back to the system default encoding in this case (not + // sure how much sense does this make but this is how the old + // code used to behave). +#if wxUSE_INTL + m_encoding = wxLocale::GetSystemEncoding(); + if ( m_encoding == wxFONTENCODING_SYSTEM ) +#endif // wxUSE_INTL + m_encoding = wxFONTENCODING_ISO8859_1; + } + break; + + case wxFONTENCODING_DEFAULT: + // wxFONTENCODING_DEFAULT is same as US-ASCII in this context + m_encoding = wxFONTENCODING_ISO8859_1; + break; + + default: + // Just use the provided encoding. + m_encoding = encoding; + } } wxCSConv::wxCSConv(const wxString& charset) @@ -2923,20 +2992,12 @@ wxCSConv::wxCSConv(const wxString& charset) } #if wxUSE_FONTMAP - m_encoding = wxFontMapperBase::GetEncodingFromName(charset); - if ( m_encoding == wxFONTENCODING_MAX ) - { - // set to unknown/invalid value - m_encoding = wxFONTENCODING_SYSTEM; - } - else if ( m_encoding == wxFONTENCODING_DEFAULT ) - { - // wxFONTENCODING_DEFAULT is same as US-ASCII in this context - m_encoding = wxFONTENCODING_ISO8859_1; - } + SetEncoding(wxFontMapperBase::GetEncodingFromName(charset)); #else - m_encoding = wxFONTENCODING_SYSTEM; + SetEncoding(wxFONTENCODING_SYSTEM); #endif + + m_convReal = DoCreate(); } wxCSConv::wxCSConv(wxFontEncoding encoding) @@ -2950,7 +3011,9 @@ wxCSConv::wxCSConv(wxFontEncoding encoding) Init(); - m_encoding = encoding; + SetEncoding(encoding); + + m_convReal = DoCreate(); } wxCSConv::~wxCSConv() @@ -2964,7 +3027,9 @@ wxCSConv::wxCSConv(const wxCSConv& conv) Init(); SetName(conv.m_name); - m_encoding = conv.m_encoding; + SetEncoding(conv.m_encoding); + + m_convReal = DoCreate(); } wxCSConv& wxCSConv::operator=(const wxCSConv& conv) @@ -2972,7 +3037,9 @@ wxCSConv& wxCSConv::operator=(const wxCSConv& conv) Clear(); SetName(conv.m_name); - m_encoding = conv.m_encoding; + SetEncoding(conv.m_encoding); + + m_convReal = DoCreate(); return *this; } @@ -2980,19 +3047,15 @@ wxCSConv& wxCSConv::operator=(const wxCSConv& conv) void wxCSConv::Clear() { free(m_name); - delete m_convReal; - m_name = NULL; - m_convReal = NULL; + + wxDELETE(m_convReal); } void wxCSConv::SetName(const char *charset) { - if (charset) - { + if ( charset ) m_name = wxStrdup(charset); - m_deferred = true; - } } #if wxUSE_FONTMAP @@ -3015,8 +3078,7 @@ wxMBConv *wxCSConv::DoCreate() const // check for the special case of ASCII or ISO8859-1 charset: as we have // special knowledge of it anyhow, we don't need to create a special // conversion object - if ( m_encoding == wxFONTENCODING_ISO8859_1 || - m_encoding == wxFONTENCODING_DEFAULT ) + if ( m_encoding == wxFONTENCODING_ISO8859_1 ) { // don't convert at all return NULL; @@ -3191,33 +3253,8 @@ wxMBConv *wxCSConv::DoCreate() const return NULL; } -void wxCSConv::CreateConvIfNeeded() const -{ - if ( m_deferred ) - { - wxCSConv *self = (wxCSConv *)this; // const_cast - - // 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 ) - { -#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 @@ -3230,8 +3267,6 @@ bool wxCSConv::IsOk() const 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); @@ -3254,8 +3289,6 @@ size_t wxCSConv::ToWChar(wchar_t *dst, size_t dstLen, 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); @@ -3291,12 +3324,8 @@ size_t wxCSConv::FromWChar(char *dst, size_t dstLen, size_t wxCSConv::GetMBNulLen() const { - CreateConvIfNeeded(); - if ( m_convReal ) - { return m_convReal->GetMBNulLen(); - } // otherwise, we are ISO-8859-1 return 1; @@ -3305,12 +3334,8 @@ size_t wxCSConv::GetMBNulLen() const #if wxUSE_UNICODE_UTF8 bool wxCSConv::IsUTF8() const { - CreateConvIfNeeded(); - if ( m_convReal ) - { return m_convReal->IsUTF8(); - } // otherwise, we are ISO-8859-1 return false; @@ -3409,8 +3434,9 @@ 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? +// It is important to use this conversion object under Darwin as it ensures +// that Unicode strings are (re)composed correctly even though xnu kernel uses +// decomposed form internally (at least for the file names). static wxMBConv_cf wxConvMacUTF8DObj(wxFONTENCODING_UTF8); #endif @@ -3420,14 +3446,3 @@ WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvFileName = #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, - wxConvLocal, - wxConvUTF8; - -#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T