implement wxMBConv_iconv::To/FromWChar() instead of MB2WC/WC2MB: this allows to use wxMBConv conversions with wxTextInputStream and fixes TextStreamTestCase unit test failures

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@53858 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Vadim Zeitlin
2008-05-30 22:49:48 +00:00
parent 05b5a45f96
commit 8f4b0f43f0

View File

@@ -1863,10 +1863,11 @@ public:
wxMBConv_iconv(const char *name);
virtual ~wxMBConv_iconv();
virtual size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const;
virtual size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const;
// classify this encoding as explained in wxMBConv::GetMBNulLen() comment
// implement base class virtual methods
virtual size_t ToWChar(wchar_t *dst, size_t dstLen,
const char *src, size_t srcLen = wxNO_LEN) const;
virtual size_t FromWChar(char *dst, size_t dstLen,
const wchar_t *src, size_t srcLen = wxNO_LEN) const;
virtual size_t GetMBNulLen() const;
#if wxUSE_UNICODE_UTF8
@@ -2052,11 +2053,15 @@ wxMBConv_iconv::~wxMBConv_iconv()
iconv_close(w2m);
}
size_t wxMBConv_iconv::MB2WC(wchar_t *buf, const char *psz, size_t n) const
size_t
wxMBConv_iconv::ToWChar(wchar_t *dst, size_t dstLen,
const char *src, size_t srcLen) const
{
if ( srcLen == wxNO_LEN )
{
// find the string length: notice that must be done differently for
// NUL-terminated strings and UTF-16/32 which are terminated with 2/4 NULs
size_t inbuf;
// NUL-terminated strings and UTF-16/32 which are terminated with 2/4
// consecutive NULs
const size_t nulLen = GetMBNulLen();
switch ( nulLen )
{
@@ -2064,20 +2069,25 @@ size_t wxMBConv_iconv::MB2WC(wchar_t *buf, const char *psz, size_t n) const
return wxCONV_FAILED;
case 1:
inbuf = strlen(psz); // arguably more optimized than our version
srcLen = strlen(src); // arguably more optimized than our version
break;
case 2:
case 4:
// for UTF-16/32 not only we need to have 2/4 consecutive NULs but
// they also have to start at character boundary and not span two
// adjacent characters
// for UTF-16/32 not only we need to have 2/4 consecutive NULs
// but they also have to start at character boundary and not
// span two adjacent characters
const char *p;
for ( p = psz; NotAllNULs(p, nulLen); p += nulLen )
for ( p = src; NotAllNULs(p, nulLen); p += nulLen )
;
inbuf = p - psz;
srcLen = p - src;
break;
}
}
// we express length in the number of (wide) characters but iconv always
// counts buffer sizes it in bytes
dstLen *= SIZEOF_WCHAR_T;
#if wxUSE_THREADS
// NB: iconv() is MT-safe, but each thread must use its own iconv_t handle.
@@ -2089,53 +2099,51 @@ size_t wxMBConv_iconv::MB2WC(wchar_t *buf, const char *psz, size_t n) const
wxMutexLocker lock(wxConstCast(this, wxMBConv_iconv)->m_iconvMutex);
#endif // wxUSE_THREADS
size_t outbuf = n * SIZEOF_WCHAR_T;
size_t res, cres;
const char *pszPtr = psz;
const char *pszPtr = src;
if (buf)
if ( dst )
{
char* bufPtr = (char*)buf;
char* bufPtr = (char*)dst;
// have destination buffer, convert there
cres = iconv(m2w,
ICONV_CHAR_CAST(&pszPtr), &inbuf,
&bufPtr, &outbuf);
res = n - (outbuf / SIZEOF_WCHAR_T);
ICONV_CHAR_CAST(&pszPtr), &srcLen,
&bufPtr, &dstLen);
res = dstLen - (dstLen / SIZEOF_WCHAR_T);
if (ms_wcNeedsSwap)
{
// convert to native endianness
for ( unsigned i = 0; i < res; i++ )
buf[n] = WC_BSWAP(buf[i]);
dst[dstLen] = WC_BSWAP(dst[i]);
}
// NUL-terminate the string if there is any space left
if (res < n)
buf[res] = 0;
if (res < dstLen)
dst[res] = 0;
}
else
else // no destination buffer
{
// no destination buffer... convert using temp buffer
// to calculate destination buffer requirement
// convert using temp buffer to calculate the size of the buffer needed
wchar_t tbuf[8];
res = 0;
do
{
char* bufPtr = (char*)tbuf;
outbuf = 8 * SIZEOF_WCHAR_T;
dstLen = 8 * SIZEOF_WCHAR_T;
cres = iconv(m2w,
ICONV_CHAR_CAST(&pszPtr), &inbuf,
&bufPtr, &outbuf );
ICONV_CHAR_CAST(&pszPtr), &srcLen,
&bufPtr, &dstLen );
res += 8 - (outbuf / SIZEOF_WCHAR_T);
res += 8 - (dstLen / SIZEOF_WCHAR_T);
}
while ((cres == (size_t)-1) && (errno == E2BIG));
}
if (ICONV_FAILED(cres, inbuf))
if (ICONV_FAILED(cres, srcLen))
{
//VS: it is ok if iconv fails, hence trace only
wxLogTrace(TRACE_STRCONV, wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode()));
@@ -2145,16 +2153,19 @@ size_t wxMBConv_iconv::MB2WC(wchar_t *buf, const char *psz, size_t n) const
return res;
}
size_t wxMBConv_iconv::WC2MB(char *buf, const wchar_t *psz, size_t n) const
size_t wxMBConv_iconv::FromWChar(char *dst, size_t dstLen,
const wchar_t *src, size_t srcLen) const
{
#if wxUSE_THREADS
// NB: explained in MB2WC
wxMutexLocker lock(wxConstCast(this, wxMBConv_iconv)->m_iconvMutex);
#endif
size_t inlen = wxWcslen(psz);
size_t inbuflen = inlen * SIZEOF_WCHAR_T;
size_t outbuflen = n;
if ( srcLen == wxNO_LEN )
srcLen = wxWcslen(src);
size_t inbuflen = srcLen * SIZEOF_WCHAR_T;
size_t outbuflen = dstLen;
size_t res, cres;
wchar_t *tmpbuf = 0;
@@ -2165,39 +2176,38 @@ size_t wxMBConv_iconv::WC2MB(char *buf, const wchar_t *psz, size_t n) const
// (doing WC_BSWAP twice on the original buffer won't help, as it
// could be in read-only memory, or be accessed in some other thread)
tmpbuf = (wchar_t *)malloc(inbuflen + SIZEOF_WCHAR_T);
for ( size_t i = 0; i < inlen; i++ )
tmpbuf[n] = WC_BSWAP(psz[i]);
for ( size_t i = 0; i < srcLen; i++ )
tmpbuf[i] = WC_BSWAP(src[i]);
tmpbuf[inlen] = L'\0';
psz = tmpbuf;
tmpbuf[srcLen] = L'\0';
src = tmpbuf;
}
char* inbuf = (char*)psz;
if (buf)
char* inbuf = (char*)src;
if ( dst )
{
// have destination buffer, convert there
cres = iconv(w2m, ICONV_CHAR_CAST(&inbuf), &inbuflen, &buf, &outbuflen);
cres = iconv(w2m, ICONV_CHAR_CAST(&inbuf), &inbuflen, &dst, &outbuflen);
res = n - outbuflen;
res = dstLen - outbuflen;
// NB: iconv was given only wcslen(psz) characters on input, and so
// NB: iconv was given only wcslen(src) characters on input, and so
// it couldn't convert the trailing zero. Let's do it ourselves
// if there's some room left for it in the output buffer.
if (res < n)
buf[0] = 0;
if (res < dstLen)
dst[0] = 0;
}
else
else // no destination buffer
{
// no destination buffer: convert using temp buffer
// to calculate destination buffer requirement
// convert using temp buffer to calculate the size of the buffer needed
char tbuf[16];
res = 0;
do
{
buf = tbuf;
dst = tbuf;
outbuflen = 16;
cres = iconv(w2m, ICONV_CHAR_CAST(&inbuf), &inbuflen, &buf, &outbuflen);
cres = iconv(w2m, ICONV_CHAR_CAST(&inbuf), &inbuflen, &dst, &outbuflen);
res += 16 - outbuflen;
}