+size_t
+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
+ // 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
+
+ // the number of chars [which would be] written to dst [if it were not NULL]
+ size_t dstWritten = 0;
+
+ // the number of NULs terminating this string
+ size_t nulLen = 0; // not really needed, but just to avoid warnings
+
+ // if we were not given the input size we just have to assume that the
+ // string is properly terminated as we have no way of knowing how long it
+ // is anyhow, but if we do have the size check whether there are enough
+ // NULs at the end
+ wxCharBuffer bufTmp;
+ const char *srcEnd;
+ if ( srcLen != wxNO_LEN )
+ {
+ // we need to know how to find the end of this string
+ nulLen = GetMBNulLen();
+ if ( nulLen == wxCONV_FAILED )
+ return wxCONV_FAILED;
+
+ // if there are enough NULs we can avoid the copy
+ if ( srcLen < nulLen || NotAllNULs(src + srcLen - nulLen, nulLen) )
+ {
+ // make a copy in order to properly NUL-terminate the string
+ bufTmp = wxCharBuffer(srcLen + nulLen - 1 /* 1 will be added */);
+ char * const p = bufTmp.data();
+ memcpy(p, src, srcLen);
+ for ( char *s = p + srcLen; s < p + srcLen + nulLen; s++ )
+ *s = '\0';
+
+ src = bufTmp;
+ }
+
+ srcEnd = src + srcLen;
+ }
+ else // quit after the first loop iteration
+ {
+ srcEnd = NULL;
+ }
+
+ for ( ;; )
+ {
+ // try to convert the current chunk
+ size_t lenChunk = MB2WC(NULL, src, 0);
+ if ( lenChunk == wxCONV_FAILED )
+ return wxCONV_FAILED;
+
+ lenChunk++; // for the L'\0' at the end of this chunk
+
+ dstWritten += lenChunk;
+
+ if ( lenChunk == 1 )
+ {
+ // nothing left in the input string, conversion succeeded
+ break;
+ }
+
+ if ( dst )
+ {
+ if ( dstWritten > dstLen )
+ return wxCONV_FAILED;
+
+ if ( MB2WC(dst, src, lenChunk) == wxCONV_FAILED )
+ return wxCONV_FAILED;
+
+ dst += lenChunk;
+ }
+
+ if ( !srcEnd )
+ {
+ // we convert just one chunk in this case as this is the entire
+ // string anyhow
+ break;
+ }
+
+ // advance the input pointer past the end of this chunk
+ while ( NotAllNULs(src, nulLen) )
+ {
+ // notice that we must skip over multiple bytes here as we suppose
+ // that if NUL takes 2 or 4 bytes, then all the other characters do
+ // too and so if advanced by a single byte we might erroneously
+ // detect sequences of NUL bytes in the middle of the input
+ src += nulLen;
+ }
+
+ src += nulLen; // skipping over its terminator as well
+
+ // 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
+ if ( src >= srcEnd )
+ break;
+ }
+
+ return dstWritten;
+}
+
+size_t
+wxMBConv::FromWChar(char *dst, size_t dstLen,
+ const wchar_t *src, size_t srcLen) const
+{
+ // the number of chars [which would be] written to dst [if it were not NULL]
+ size_t dstWritten = 0;
+
+ // 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 )
+ {
+ srcLen = wxWcslen(src) + 1;
+ }
+ else if ( srcLen != 0 && src[srcLen - 1] != L'\0' )
+ {
+ // make a copy in order to properly NUL-terminate the string
+ bufTmp = wxWCharBuffer(srcLen);
+ memcpy(bufTmp.data(), src, srcLen * sizeof(wchar_t));
+ src = bufTmp;
+ }
+
+ const size_t lenNul = GetMBNulLen();
+ for ( const wchar_t * const srcEnd = src + srcLen;
+ src < srcEnd;
+ src += wxWcslen(src) + 1 /* skip L'\0' too */ )
+ {
+ // try to convert the current chunk
+ size_t lenChunk = WC2MB(NULL, src, 0);
+
+ if ( lenChunk == wxCONV_FAILED )
+ return wxCONV_FAILED;
+
+ lenChunk += lenNul;
+ dstWritten += lenChunk;
+
+ if ( dst )
+ {
+ if ( dstWritten > dstLen )
+ return wxCONV_FAILED;
+
+ if ( WC2MB(dst, src, lenChunk) == wxCONV_FAILED )
+ return wxCONV_FAILED;
+
+ dst += lenChunk;
+ }
+ }
+
+ return dstWritten;
+}
+
+size_t wxMBConv::MB2WC(wchar_t *outBuff, const char *inBuff, size_t outLen) const
+{
+ size_t rc = ToWChar(outBuff, outLen, inBuff);
+ if ( rc != wxCONV_FAILED )
+ {
+ // ToWChar() returns the buffer length, i.e. including the trailing
+ // NUL, while this method doesn't take it into account
+ rc--;
+ }
+
+ return rc;
+}
+
+size_t wxMBConv::WC2MB(char *outBuff, const wchar_t *inBuff, size_t outLen) const
+{
+ size_t rc = FromWChar(outBuff, outLen, inBuff);
+ if ( rc != wxCONV_FAILED )
+ {
+ rc -= GetMBNulLen();
+ }
+
+ return rc;
+}
+