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); wxMBConv_iconv(const char *name);
virtual ~wxMBConv_iconv(); virtual ~wxMBConv_iconv();
virtual size_t MB2WC(wchar_t *buf, const char *psz, size_t n) const; // implement base class virtual methods
virtual size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const; virtual size_t ToWChar(wchar_t *dst, size_t dstLen,
const char *src, size_t srcLen = wxNO_LEN) const;
// classify this encoding as explained in wxMBConv::GetMBNulLen() comment virtual size_t FromWChar(char *dst, size_t dstLen,
const wchar_t *src, size_t srcLen = wxNO_LEN) const;
virtual size_t GetMBNulLen() const; virtual size_t GetMBNulLen() const;
#if wxUSE_UNICODE_UTF8 #if wxUSE_UNICODE_UTF8
@@ -2052,11 +2053,15 @@ wxMBConv_iconv::~wxMBConv_iconv()
iconv_close(w2m); 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 // 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 // NUL-terminated strings and UTF-16/32 which are terminated with 2/4
size_t inbuf; // consecutive NULs
const size_t nulLen = GetMBNulLen(); const size_t nulLen = GetMBNulLen();
switch ( nulLen ) switch ( nulLen )
{ {
@@ -2064,20 +2069,25 @@ size_t wxMBConv_iconv::MB2WC(wchar_t *buf, const char *psz, size_t n) const
return wxCONV_FAILED; return wxCONV_FAILED;
case 1: case 1:
inbuf = strlen(psz); // arguably more optimized than our version srcLen = strlen(src); // arguably more optimized than our version
break; break;
case 2: case 2:
case 4: case 4:
// for UTF-16/32 not only we need to have 2/4 consecutive NULs but // for UTF-16/32 not only we need to have 2/4 consecutive NULs
// they also have to start at character boundary and not span two // but they also have to start at character boundary and not
// adjacent characters // span two adjacent characters
const char *p; 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; 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 #if wxUSE_THREADS
// NB: iconv() is MT-safe, but each thread must use its own iconv_t handle. // 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); wxMutexLocker lock(wxConstCast(this, wxMBConv_iconv)->m_iconvMutex);
#endif // wxUSE_THREADS #endif // wxUSE_THREADS
size_t outbuf = n * SIZEOF_WCHAR_T;
size_t res, cres; 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 // have destination buffer, convert there
cres = iconv(m2w, cres = iconv(m2w,
ICONV_CHAR_CAST(&pszPtr), &inbuf, ICONV_CHAR_CAST(&pszPtr), &srcLen,
&bufPtr, &outbuf); &bufPtr, &dstLen);
res = n - (outbuf / SIZEOF_WCHAR_T); res = dstLen - (dstLen / SIZEOF_WCHAR_T);
if (ms_wcNeedsSwap) if (ms_wcNeedsSwap)
{ {
// convert to native endianness // convert to native endianness
for ( unsigned i = 0; i < res; i++ ) 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 // NUL-terminate the string if there is any space left
if (res < n) if (res < dstLen)
buf[res] = 0; dst[res] = 0;
} }
else else // no destination buffer
{ {
// no destination buffer... convert using temp buffer // convert using temp buffer to calculate the size of the buffer needed
// to calculate destination buffer requirement
wchar_t tbuf[8]; wchar_t tbuf[8];
res = 0; res = 0;
do do
{ {
char* bufPtr = (char*)tbuf; char* bufPtr = (char*)tbuf;
outbuf = 8 * SIZEOF_WCHAR_T; dstLen = 8 * SIZEOF_WCHAR_T;
cres = iconv(m2w, cres = iconv(m2w,
ICONV_CHAR_CAST(&pszPtr), &inbuf, ICONV_CHAR_CAST(&pszPtr), &srcLen,
&bufPtr, &outbuf ); &bufPtr, &dstLen );
res += 8 - (outbuf / SIZEOF_WCHAR_T); res += 8 - (dstLen / SIZEOF_WCHAR_T);
} }
while ((cres == (size_t)-1) && (errno == E2BIG)); 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 //VS: it is ok if iconv fails, hence trace only
wxLogTrace(TRACE_STRCONV, wxT("iconv failed: %s"), wxSysErrorMsg(wxSysErrorCode())); 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; 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 #if wxUSE_THREADS
// NB: explained in MB2WC // NB: explained in MB2WC
wxMutexLocker lock(wxConstCast(this, wxMBConv_iconv)->m_iconvMutex); wxMutexLocker lock(wxConstCast(this, wxMBConv_iconv)->m_iconvMutex);
#endif #endif
size_t inlen = wxWcslen(psz); if ( srcLen == wxNO_LEN )
size_t inbuflen = inlen * SIZEOF_WCHAR_T; srcLen = wxWcslen(src);
size_t outbuflen = n;
size_t inbuflen = srcLen * SIZEOF_WCHAR_T;
size_t outbuflen = dstLen;
size_t res, cres; size_t res, cres;
wchar_t *tmpbuf = 0; 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 // (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) // 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 + SIZEOF_WCHAR_T);
for ( size_t i = 0; i < inlen; i++ ) for ( size_t i = 0; i < srcLen; i++ )
tmpbuf[n] = WC_BSWAP(psz[i]); tmpbuf[i] = WC_BSWAP(src[i]);
tmpbuf[inlen] = L'\0'; tmpbuf[srcLen] = L'\0';
psz = tmpbuf; src = tmpbuf;
} }
char* inbuf = (char*)psz; char* inbuf = (char*)src;
if (buf) if ( dst )
{ {
// have destination buffer, convert there // 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 // 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 there's some room left for it in the output buffer.
if (res < n) if (res < dstLen)
buf[0] = 0; dst[0] = 0;
} }
else else // no destination buffer
{ {
// no destination buffer: convert using temp buffer // convert using temp buffer to calculate the size of the buffer needed
// to calculate destination buffer requirement
char tbuf[16]; char tbuf[16];
res = 0; res = 0;
do do
{ {
buf = tbuf; dst = tbuf;
outbuflen = 16; 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; res += 16 - outbuflen;
} }