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;
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
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;
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 )
// 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;
// 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;
}
if ( lenChunk == wxCONV_FAILED )
return wxCONV_FAILED;
- lenChunk += lenNul;
dstWritten += lenChunk;
+ if ( 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 ( isNulTerminated )
+ dst += lenNul;
}
}
// 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)--;
}
{
*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;
}
}
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
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
// 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
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();
}
#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