X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/05392dc8c6a8b027f36985e6a91a358c7634f187..53cda845db64db0d358f69443cf7edeb2360a048:/src/common/strconv.cpp diff --git a/src/common/strconv.cpp b/src/common/strconv.cpp index b6c3ca3545..41ca712cdf 100644 --- a/src/common/strconv.cpp +++ b/src/common/strconv.cpp @@ -142,7 +142,7 @@ static wxUint32 wxDecodeSurrogate(const wxDecodeSurrogate_t **pSrc) { wxUint32 out; const size_t - n = decode_utf16(wx_reinterpret_cast(const wxUint16 *, *pSrc), out); + n = decode_utf16(reinterpret_cast(*pSrc), out); if ( n == wxCONV_FAILED ) *pSrc = NULL; else @@ -160,11 +160,15 @@ wxMBConv::ToWChar(wchar_t *dst, size_t dstLen, const char *src, size_t srcLen) const { // although new conversion classes are supposed to implement this function - // directly, the existins ones only implement the old MB2WC() and so, to + // directly, the existing ones only implement the old MB2WC() and so, to // avoid to have to rewrite all conversion classes at once, we provide a // default (but not efficient) implementation of this one in terms of the // old function by copying the input to ensure that it's NUL-terminated and // then using MB2WC() to convert it + // + // moreover, some conversion classes simply can't implement ToWChar() + // directly, the primary example is wxConvLibc: mbstowcs() only handles + // NUL-terminated strings // the number of chars [which would be] written to dst [if it were not NULL] size_t dstWritten = 0; @@ -205,6 +209,21 @@ wxMBConv::ToWChar(wchar_t *dst, size_t dstLen, srcEnd = NULL; } + // the idea of this code is straightforward: it converts a NUL-terminated + // chunk of the string during each iteration and updates the output buffer + // with the result + // + // all the complication come from the fact that this function, for + // historical reasons, must behave in 2 subtly different ways when it's + // called with a fixed number of characters and when it's called for the + // entire NUL-terminated string: in the former case (srcEnd == NULL) we + // must count all characters we convert, NUL or not; but in the latter we + // do not count the trailing NUL -- but still count all the NULs inside the + // string + // + // so for the (simple) former case we just always count the trailing NUL, + // but for the latter we need to wait until we see if there is going to be + // another loop iteration and only count it then for ( ;; ) { // try to convert the current chunk @@ -212,11 +231,11 @@ wxMBConv::ToWChar(wchar_t *dst, size_t dstLen, if ( lenChunk == wxCONV_FAILED ) return wxCONV_FAILED; - lenChunk++; // for the L'\0' at the end of this chunk - dstWritten += lenChunk; + if ( !srcEnd ) + dstWritten++; - if ( lenChunk == 1 ) + if ( !lenChunk ) { // nothing left in the input string, conversion succeeded break; @@ -227,10 +246,13 @@ wxMBConv::ToWChar(wchar_t *dst, size_t dstLen, if ( dstWritten > dstLen ) return wxCONV_FAILED; - if ( MB2WC(dst, src, lenChunk) == wxCONV_FAILED ) + // +1 is for trailing NUL + if ( MB2WC(dst, src, lenChunk + 1) == wxCONV_FAILED ) return wxCONV_FAILED; dst += lenChunk; + if ( !srcEnd ) + dst++; } if ( !srcEnd ) @@ -254,9 +276,19 @@ wxMBConv::ToWChar(wchar_t *dst, size_t dstLen, // note that ">=" (and not just "==") is needed here as the terminator // we skipped just above could be inside or just after the buffer - // delimited by inEnd + // delimited by srcEnd if ( src >= srcEnd ) break; + + // if we got here then this wasn't the last chunk in this string and + // hence we must count an extra char for L'\0' even when converting a + // fixed number of characters + if ( srcEnd ) + { + dstWritten++; + if ( dst ) + dst++; + } } return dstWritten; @@ -269,13 +301,15 @@ wxMBConv::FromWChar(char *dst, size_t dstLen, // the number of chars [which would be] written to dst [if it were not NULL] size_t dstWritten = 0; + // if we don't know its length we have no choice but to assume that it is + // NUL-terminated (notice that it can still be NUL-terminated even if + // explicit length is given but it doesn't change our return value) + const bool isNulTerminated = srcLen == wxNO_LEN; + // make a copy of the input string unless it is already properly // NUL-terminated - // - // if we don't know its length we have no choice but to assume that it is, - // indeed, properly terminated wxWCharBuffer bufTmp; - if ( srcLen == wxNO_LEN ) + if ( isNulTerminated ) { srcLen = wxWcslen(src) + 1; } @@ -298,18 +332,21 @@ wxMBConv::FromWChar(char *dst, size_t dstLen, if ( lenChunk == wxCONV_FAILED ) return wxCONV_FAILED; - lenChunk += lenNul; dstWritten += lenChunk; + if ( src+lenChunk < srcEnd || isNulTerminated ) + dstWritten += lenNul; if ( dst ) { if ( dstWritten > dstLen ) return wxCONV_FAILED; - if ( WC2MB(dst, src, lenChunk) == wxCONV_FAILED ) + if ( WC2MB(dst, src, lenChunk + lenNul) == wxCONV_FAILED ) return wxCONV_FAILED; dst += lenChunk; + if ( src+lenChunk < srcEnd || isNulTerminated ) + dst += lenNul; } } @@ -391,13 +428,19 @@ wxMBConv::cMB2WC(const char *inBuff, size_t inLen, size_t *outLen) const // because we want the buffer to always be NUL-terminated, even if the // input isn't (as otherwise the caller has no way to know its length) wxWCharBuffer wbuf(dstLen); - wbuf.data()[dstLen - 1] = L'\0'; + wbuf.data()[dstLen] = L'\0'; if ( ToWChar(wbuf.data(), dstLen, inBuff, inLen) != wxCONV_FAILED ) { if ( outLen ) { *outLen = dstLen; - if ( wbuf[dstLen - 1] == L'\0' ) + + // we also need to handle NUL-terminated input strings + // specially: for them the output is the length of the string + // excluding the trailing NUL, however if we're asked to + // convert a specific number of characters we return the length + // of the resulting output even if it's NUL-terminated + if ( inLen == wxNO_LEN ) (*outLen)--; } @@ -429,11 +472,10 @@ wxMBConv::cWC2MB(const wchar_t *inBuff, size_t inLen, size_t *outLen) const { *outLen = dstLen; - if ( dstLen >= nulLen && - !NotAllNULs(buf.data() + dstLen - nulLen, nulLen) ) + if ( inLen == wxNO_LEN ) { - // in this case the output is NUL-terminated and we're not - // supposed to count NUL + // in this case both input and output are NUL-terminated + // and we're not supposed to count NUL *outLen -= nulLen; } } @@ -523,14 +565,14 @@ 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 }; size_t wxMBConvUTF7::ToWChar(wchar_t *dst, size_t dstLen, const char *src, size_t srcLen) const { DecoderState stateOrig, - *statePtr; + *statePtr; if ( srcLen == wxNO_LEN ) { // convert the entire string, up to and including the trailing NUL @@ -542,7 +584,7 @@ size_t wxMBConvUTF7::ToWChar(wchar_t *dst, size_t dstLen, } else // when working with partial strings we do use the shift state { - statePtr = wx_const_cast(DecoderState *, &m_stateDecoder); + statePtr = const_cast(&m_stateDecoder); // also save the old state to be able to rollback to it on error stateOrig = m_stateDecoder; @@ -567,7 +609,20 @@ size_t wxMBConvUTF7::ToWChar(wchar_t *dst, size_t dstLen, const unsigned char dc = utf7unb64[cc]; if ( dc == 0xff ) { - // end of encoded part + // end of encoded part, check that nothing was left: there can + // be up to 4 bits of 0 padding but nothing else (we also need + // to check isLSB as we count bits modulo 8 while a valid UTF-7 + // encoded sequence must contain an integral number of UTF-16 + // characters) + if ( state.isLSB || state.bit > 4 || + (state.accum & ((1 << state.bit) - 1)) ) + { + if ( !len ) + state = stateOrig; + + return wxCONV_FAILED; + } + state.ToDirect(); // re-parse this character normally below unless it's '-' which @@ -611,9 +666,6 @@ size_t wxMBConvUTF7::ToWChar(wchar_t *dst, size_t dstLen, // start of an encoded segment? if ( cc == '+' ) { - if ( src == srcEnd ) - return wxCONV_FAILED; // can't have '+' at the end - if ( *src == '-' ) { // just the encoded plus sign, don't switch to shifted mode @@ -622,7 +674,15 @@ size_t wxMBConvUTF7::ToWChar(wchar_t *dst, size_t dstLen, len++; src++; } - else + else if ( utf7unb64[(unsigned)*src] == 0xff ) + { + // empty encoded chunks are not allowed + if ( !len ) + state = stateOrig; + + return wxCONV_FAILED; + } + else // base-64 encoded chunk follows { state.ToShifted(); } @@ -711,7 +771,7 @@ size_t wxMBConvUTF7::FromWChar(char *dst, size_t dstLen, else // do use the mode we left the output in previously { stateOrig = m_stateEncoder; - statePtr = wx_const_cast(EncoderState *, &m_stateEncoder); + statePtr = const_cast(&m_stateEncoder); } EncoderState& state = *statePtr; @@ -1347,7 +1407,7 @@ size_t wxMBConvUTF16Base::GetLength(const char *src, size_t srcLen) if ( srcLen == wxNO_LEN ) { // count the number of bytes in input, including the trailing NULs - const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); + const wxUint16 *inBuff = reinterpret_cast(src); for ( srcLen = 1; *inBuff++; srcLen++ ) ; @@ -1431,7 +1491,7 @@ wxMBConvUTF16swap::ToWChar(wchar_t *dst, size_t dstLen, if ( dstLen < srcLen ) return wxCONV_FAILED; - const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); + const wxUint16 *inBuff = reinterpret_cast(src); for ( size_t n = 0; n < srcLen; n++, inBuff++ ) { *dst++ = wxUINT16_SWAP_ALWAYS(*inBuff); @@ -1455,7 +1515,7 @@ wxMBConvUTF16swap::FromWChar(char *dst, size_t dstLen, if ( dstLen < srcLen ) return wxCONV_FAILED; - wxUint16 *outBuff = wx_reinterpret_cast(wxUint16 *, dst); + wxUint16 *outBuff = reinterpret_cast(dst); for ( size_t n = 0; n < srcLen; n += BYTES_PER_CHAR, src++ ) { *outBuff++ = wxUINT16_SWAP_ALWAYS(*src); @@ -1489,7 +1549,7 @@ wxMBConvUTF16straight::ToWChar(wchar_t *dst, size_t dstLen, } size_t outLen = 0; - const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); + const wxUint16 *inBuff = reinterpret_cast(src); for ( const wxUint16 * const inEnd = inBuff + inLen; inBuff < inEnd; ) { const wxUint32 ch = wxDecodeSurrogate(&inBuff); @@ -1514,7 +1574,7 @@ wxMBConvUTF16straight::FromWChar(char *dst, size_t dstLen, srcLen = wxWcslen(src) + 1; size_t outLen = 0; - wxUint16 *outBuff = wx_reinterpret_cast(wxUint16 *, dst); + wxUint16 *outBuff = reinterpret_cast(dst); for ( size_t n = 0; n < srcLen; n++ ) { wxUint16 cc[2]; @@ -1562,7 +1622,7 @@ wxMBConvUTF16swap::ToWChar(wchar_t *dst, size_t dstLen, } size_t outLen = 0; - const wxUint16 *inBuff = wx_reinterpret_cast(const wxUint16 *, src); + const wxUint16 *inBuff = reinterpret_cast(src); for ( const wxUint16 * const inEnd = inBuff + inLen; inBuff < inEnd; ) { wxUint32 ch; @@ -1597,7 +1657,7 @@ wxMBConvUTF16swap::FromWChar(char *dst, size_t dstLen, srcLen = wxWcslen(src) + 1; size_t outLen = 0; - wxUint16 *outBuff = wx_reinterpret_cast(wxUint16 *, dst); + wxUint16 *outBuff = reinterpret_cast(dst); for ( const wchar_t *srcEnd = src + srcLen; src < srcEnd; src++ ) { wxUint16 cc[2]; @@ -1648,7 +1708,7 @@ size_t wxMBConvUTF32Base::GetLength(const char *src, size_t srcLen) if ( srcLen == wxNO_LEN ) { // count the number of bytes in input, including the trailing NULs - const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); + const wxUint32 *inBuff = reinterpret_cast(src); for ( srcLen = 1; *inBuff++; srcLen++ ) ; @@ -1679,7 +1739,7 @@ wxMBConvUTF32straight::ToWChar(wchar_t *dst, size_t dstLen, if ( srcLen == wxNO_LEN ) return wxCONV_FAILED; - const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); + const wxUint32 *inBuff = reinterpret_cast(src); const size_t inLen = srcLen / BYTES_PER_CHAR; size_t outLen = 0; for ( size_t n = 0; n < inLen; n++ ) @@ -1726,7 +1786,7 @@ wxMBConvUTF32straight::FromWChar(char *dst, size_t dstLen, return srcLen * BYTES_PER_CHAR; } - wxUint32 *outBuff = wx_reinterpret_cast(wxUint32 *, dst); + wxUint32 *outBuff = reinterpret_cast(dst); size_t outLen = 0; for ( const wchar_t * const srcEnd = src + srcLen; src < srcEnd; ) { @@ -1757,7 +1817,7 @@ wxMBConvUTF32swap::ToWChar(wchar_t *dst, size_t dstLen, if ( srcLen == wxNO_LEN ) return wxCONV_FAILED; - const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); + const wxUint32 *inBuff = reinterpret_cast(src); const size_t inLen = srcLen / BYTES_PER_CHAR; size_t outLen = 0; for ( size_t n = 0; n < inLen; n++, inBuff++ ) @@ -1804,7 +1864,7 @@ wxMBConvUTF32swap::FromWChar(char *dst, size_t dstLen, return srcLen*BYTES_PER_CHAR; } - wxUint32 *outBuff = wx_reinterpret_cast(wxUint32 *, dst); + wxUint32 *outBuff = reinterpret_cast(dst); size_t outLen = 0; for ( const wchar_t * const srcEnd = src + srcLen; src < srcEnd; ) { @@ -1889,7 +1949,7 @@ wxMBConvUTF32swap::ToWChar(wchar_t *dst, size_t dstLen, if ( dstLen < srcLen ) return wxCONV_FAILED; - const wxUint32 *inBuff = wx_reinterpret_cast(const wxUint32 *, src); + const wxUint32 *inBuff = reinterpret_cast(src); for ( size_t n = 0; n < srcLen; n++, inBuff++ ) { *dst++ = wxUINT32_SWAP_ALWAYS(*inBuff); @@ -1913,7 +1973,7 @@ wxMBConvUTF32swap::FromWChar(char *dst, size_t dstLen, if ( dstLen < srcLen ) return wxCONV_FAILED; - wxUint32 *outBuff = wx_reinterpret_cast(wxUint32 *, dst); + wxUint32 *outBuff = reinterpret_cast(dst); for ( size_t n = 0; n < srcLen; n += BYTES_PER_CHAR, src++ ) { *outBuff++ = wxUINT32_SWAP_ALWAYS(*src); @@ -2240,7 +2300,7 @@ wxMBConv_iconv::ToWChar(wchar_t *dst, size_t dstLen, else // no destination buffer { // convert using temp buffer to calculate the size of the buffer needed - wchar_t tbuf[8]; + wchar_t tbuf[256]; res = 0; do @@ -2287,13 +2347,12 @@ size_t wxMBConv_iconv::FromWChar(char *dst, size_t dstLen, if (ms_wcNeedsSwap) { // need to copy to temp buffer to switch endianness - // (doing WC_BSWAP twice on the original buffer won't help, as it + // (doing WC_BSWAP twice on the original buffer won't work, as it // could be in read-only memory, or be accessed in some other thread) - tmpbuf = (wchar_t *)malloc(inbuflen + SIZEOF_WCHAR_T); + tmpbuf = (wchar_t *)malloc(inbuflen); for ( size_t i = 0; i < srcLen; i++ ) tmpbuf[i] = WC_BSWAP(src[i]); - tmpbuf[srcLen] = L'\0'; src = tmpbuf; } @@ -2308,16 +2367,16 @@ size_t wxMBConv_iconv::FromWChar(char *dst, size_t dstLen, else // no destination buffer { // convert using temp buffer to calculate the size of the buffer needed - char tbuf[16]; + char tbuf[256]; res = 0; do { dst = tbuf; - outbuflen = 16; + outbuflen = WXSIZEOF(tbuf); cres = iconv(w2m, ICONV_CHAR_CAST(&inbuf), &inbuflen, &dst, &outbuflen); - res += 16 - outbuflen; + res += WXSIZEOF(tbuf) - outbuflen; } while ((cres == (size_t)-1) && (errno == E2BIG)); } @@ -2790,7 +2849,7 @@ private: // were we initialized successfully? bool m_ok; - DECLARE_NO_COPY_CLASS(wxMBConv_wxwin) + wxDECLARE_NO_COPY_CLASS(wxMBConv_wxwin); }; // make the constructors available for unit testing @@ -2830,6 +2889,16 @@ 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; + } #else m_encoding = wxFONTENCODING_SYSTEM; #endif @@ -3077,31 +3146,12 @@ wxMBConv *wxCSConv::DoCreate() const delete conv; } -#endif // wxUSE_FONTMAP - - // 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 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) - { - alreadyLoggingError = true; - wxLogError(_("Cannot convert from the charset '%s'!"), - m_name ? m_name - : -#if wxUSE_FONTMAP - (const char*)wxFontMapperBase::GetEncodingDescription(m_encoding).ToAscii() -#else // !wxUSE_FONTMAP - (const char*)wxString::Format(_("encoding %i"), m_encoding).ToAscii() -#endif // wxUSE_FONTMAP/!wxUSE_FONTMAP - ); - alreadyLoggingError = false; - } + wxLogTrace(TRACE_STRCONV, + wxT("encoding \"%s\" is not supported by this system"), + (m_name ? wxString(m_name) + : wxFontMapperBase::GetEncodingName(m_encoding))); +#endif // wxUSE_FONTMAP return NULL; } @@ -3295,8 +3345,15 @@ wxCharBuffer wxSafeConvertWX2MB(const wchar_t *ws) #define WX_DEFINE_GLOBAL_CONV(klass, name, ctor_args) \ WX_DEFINE_GLOBAL_CONV2(klass, klass, name, ctor_args) +#ifdef __INTELC__ + // disable warning "variable 'xxx' was declared but never referenced" + #pragma warning(disable: 177) +#endif // Intel C++ + #ifdef __WINDOWS__ WX_DEFINE_GLOBAL_CONV2(wxMBConv, wxMBConv_win32, wxConvLibc, wxEMPTY_PARAMETER_VALUE); +#elif 0 // defined(__WXOSX__) + WX_DEFINE_GLOBAL_CONV2(wxMBConv, wxMBConv_cf, wxConvLibc, (wxFONTENCODING_UTF8)); #else WX_DEFINE_GLOBAL_CONV2(wxMBConv, wxMBConvLibc, wxConvLibc, wxEMPTY_PARAMETER_VALUE); #endif