#include "wx/strconv.h"
-#if wxUSE_WCHAR_T
-
#ifndef __WXWINCE__
#include <errno.h>
#endif
// 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
+ // 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
if ( !srcEnd )
{
// we convert just one chunk in this case as this is the entire
- // string anyhow
+ // string anyhow (and we don't count the trailing NUL in this case)
break;
}
- // advance the input pointer past the end of this chunk
+ // advance the input pointer past the end of this chunk: notice that we
+ // will always stop before srcEnd because we know that the chunk is
+ // always properly NUL-terminated
while ( NotAllNULs(src, nulLen) )
{
// notice that we must skip over multiple bytes here as we suppose
src += nulLen;
}
- src += nulLen; // skipping over its terminator as well
+ // if the buffer ends before this NUL, we shouldn't count it in our
+ // output so skip the code below
+ if ( src == srcEnd )
+ break;
+
+ // do count this terminator as it's inside the buffer we convert
+ dstWritten++;
+ if ( dst )
+ dst++;
+
+ src += nulLen; // skip the terminator itself
- // 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 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;
const size_t lenNul = GetMBNulLen();
for ( const wchar_t * const srcEnd = src + srcLen;
src < srcEnd;
- src += wxWcslen(src) + 1 /* skip L'\0' too */ )
+ src++ /* skip L'\0' too */ )
{
// try to convert the current chunk
size_t lenChunk = WC2MB(NULL, src, 0);
-
if ( lenChunk == wxCONV_FAILED )
return wxCONV_FAILED;
dstWritten += lenChunk;
- if ( src+lenChunk < srcEnd || isNulTerminated )
+
+ const wchar_t * const
+ chunkEnd = isNulTerminated ? srcEnd - 1 : src + wxWcslen(src);
+
+ // our return value accounts for the trailing NUL(s), unlike that of
+ // WC2MB(), however don't do it for the last NUL we artificially added
+ // ourselves above
+ if ( chunkEnd < srcEnd )
dstWritten += lenNul;
if ( dst )
if ( dstWritten > dstLen )
return wxCONV_FAILED;
- if ( WC2MB(dst, src, lenChunk + lenNul) == wxCONV_FAILED )
+ // if we know that there is enough space in the destination buffer
+ // (because we accounted for lenNul in dstWritten above), we can
+ // convert directly in place -- but otherwise we need another
+ // temporary buffer to ensure that we don't overwrite the output
+ wxCharBuffer dstBuf;
+ char *dstTmp;
+ if ( chunkEnd == srcEnd )
+ {
+ dstBuf = wxCharBuffer(lenChunk + lenNul - 1);
+ dstTmp = dstBuf.data();
+ }
+ else
+ {
+ dstTmp = dst;
+ }
+
+ if ( WC2MB(dstTmp, src, lenChunk + lenNul) == wxCONV_FAILED )
return wxCONV_FAILED;
+ if ( dstTmp != dst )
+ {
+ // copy everything up to but excluding the terminating NUL(s)
+ // into the real output buffer
+ memcpy(dst, dstTmp, lenChunk);
+
+ // micro-optimization: if dstTmp != dst it means that chunkEnd
+ // == srcEnd and so we're done, no need to update anything below
+ break;
+ }
+
dst += lenChunk;
- if ( src+lenChunk < srcEnd || isNulTerminated )
+ if ( chunkEnd < srcEnd )
dst += lenNul;
}
+
+ src = chunkEnd;
}
return dstWritten;
return wxCharBuffer();
}
+const wxWCharBuffer wxMBConv::cMB2WC(const wxScopedCharBuffer& buf) const
+{
+ const size_t srcLen = buf.length();
+ if ( srcLen )
+ {
+ const size_t dstLen = ToWChar(NULL, 0, buf, srcLen);
+ if ( dstLen != wxCONV_FAILED )
+ {
+ wxWCharBuffer wbuf(dstLen);
+ wbuf.data()[dstLen] = L'\0';
+ if ( ToWChar(wbuf.data(), dstLen, buf, srcLen) != wxCONV_FAILED )
+ return wbuf;
+ }
+ }
+
+ return wxScopedWCharBuffer::CreateNonOwned(L"", 0);
+}
+
+const wxCharBuffer wxMBConv::cWC2MB(const wxScopedWCharBuffer& wbuf) const
+{
+ const size_t srcLen = wbuf.length();
+ if ( srcLen )
+ {
+ const size_t dstLen = FromWChar(NULL, 0, wbuf, srcLen);
+ if ( dstLen != wxCONV_FAILED )
+ {
+ wxCharBuffer buf(dstLen);
+ buf.data()[dstLen] = '\0';
+ if ( FromWChar(buf.data(), dstLen, wbuf, srcLen) != wxCONV_FAILED )
+ return buf;
+ }
+ }
+
+ return wxScopedCharBuffer::CreateNonOwned("", 0);
+}
+
// ----------------------------------------------------------------------------
// wxMBConvLibc
// ----------------------------------------------------------------------------
for ( const char *p = src; ; p++ )
{
- if ( !(srcLen == wxNO_LEN ? *p : srcLen) )
+ if ( (srcLen == wxNO_LEN ? !*p : !srcLen) )
{
// all done successfully, just add the trailing NULL if we are not
// using explicit length
for ( const wchar_t *wp = src; ; wp++ )
{
- if ( !(srcLen == wxNO_LEN ? *wp : srcLen) )
+ if ( (srcLen == wxNO_LEN ? !*wp : !srcLen) )
{
// all done successfully, just add the trailing NULL if we are not
// using explicit length
virtual wxMBConv *Clone() const
{
- wxMBConv_iconv *p = new wxMBConv_iconv(m_name.ToAscii());
+ wxMBConv_iconv *p = new wxMBConv_iconv(m_name);
p->m_minMBCharWidth = m_minMBCharWidth;
return p;
}
// name of the encoding handled by this conversion
- wxString m_name;
+ const char *m_name;
// cached result of GetMBNulLen(); set to 0 meaning "unknown"
// initially
bool wxMBConv_iconv::ms_wcNeedsSwap = false;
wxMBConv_iconv::wxMBConv_iconv(const char *name)
- : m_name(name)
+ : m_name(wxStrdup(name))
{
m_minMBCharWidth = 0;
wxLogTrace(TRACE_STRCONV, wxT("Looking for wide char codeset:"));
#if wxUSE_FONTMAP
- const wxChar **names = wxFontMapperBase::GetAllEncodingNames(WC_ENC);
+ const wxChar *const *names = wxFontMapperBase::GetAllEncodingNames(WC_ENC);
#else // !wxUSE_FONTMAP
- static const wxChar *names_static[] =
+ static const wxChar *const names_static[] =
{
#if SIZEOF_WCHAR_T == 4
wxT("UCS-4"),
-#elif SIZEOF_WCHAR_T = 2
+#elif SIZEOF_WCHAR_T == 2
wxT("UCS-2"),
#endif
NULL
};
- const wxChar **names = names_static;
+ const wxChar *const *names = names_static;
#endif // wxUSE_FONTMAP/!wxUSE_FONTMAP
for ( ; *names && ms_wcCharsetName.empty(); ++names )
wxMBConv_iconv::~wxMBConv_iconv()
{
+ free(const_cast<char *>(m_name));
+
if ( m2w != ICONV_T_INVALID )
iconv_close(m2w);
if ( w2m != ICONV_T_INVALID )
{
m_name = NULL;
m_convReal = NULL;
- m_deferred = true;
+}
+
+void wxCSConv::SetEncoding(wxFontEncoding encoding)
+{
+ switch ( encoding )
+ {
+ case wxFONTENCODING_MAX:
+ case wxFONTENCODING_SYSTEM:
+ if ( m_name )
+ {
+ // It's ok to not have encoding value if we have a name for it.
+ m_encoding = wxFONTENCODING_SYSTEM;
+ }
+ else // No name neither.
+ {
+ // Fall back to the system default encoding in this case (not
+ // sure how much sense does this make but this is how the old
+ // code used to behave).
+#if wxUSE_INTL
+ m_encoding = wxLocale::GetSystemEncoding();
+ if ( m_encoding == wxFONTENCODING_SYSTEM )
+#endif // wxUSE_INTL
+ m_encoding = wxFONTENCODING_ISO8859_1;
+ }
+ break;
+
+ case wxFONTENCODING_DEFAULT:
+ // wxFONTENCODING_DEFAULT is same as US-ASCII in this context
+ m_encoding = wxFONTENCODING_ISO8859_1;
+ break;
+
+ default:
+ // Just use the provided encoding.
+ m_encoding = encoding;
+ }
}
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;
- }
+ SetEncoding(wxFontMapperBase::GetEncodingFromName(charset));
#else
- m_encoding = wxFONTENCODING_SYSTEM;
+ SetEncoding(wxFONTENCODING_SYSTEM);
#endif
+
+ m_convReal = DoCreate();
}
wxCSConv::wxCSConv(wxFontEncoding encoding)
Init();
- m_encoding = encoding;
+ SetEncoding(encoding);
+
+ m_convReal = DoCreate();
}
wxCSConv::~wxCSConv()
Init();
SetName(conv.m_name);
- m_encoding = conv.m_encoding;
+ SetEncoding(conv.m_encoding);
+
+ m_convReal = DoCreate();
}
wxCSConv& wxCSConv::operator=(const wxCSConv& conv)
Clear();
SetName(conv.m_name);
- m_encoding = conv.m_encoding;
+ SetEncoding(conv.m_encoding);
+
+ m_convReal = DoCreate();
return *this;
}
void wxCSConv::Clear()
{
free(m_name);
- delete m_convReal;
-
m_name = NULL;
- m_convReal = NULL;
+
+ wxDELETE(m_convReal);
}
void wxCSConv::SetName(const char *charset)
{
- if (charset)
- {
+ if ( charset )
m_name = wxStrdup(charset);
- m_deferred = true;
- }
}
#if wxUSE_FONTMAP
// check for the special case of ASCII or ISO8859-1 charset: as we have
// special knowledge of it anyhow, we don't need to create a special
// conversion object
- if ( m_encoding == wxFONTENCODING_ISO8859_1 ||
- m_encoding == wxFONTENCODING_DEFAULT )
+ if ( m_encoding == wxFONTENCODING_ISO8859_1 )
{
// don't convert at all
return NULL;
delete conv;
}
- const wxChar** names = wxFontMapperBase::GetAllEncodingNames(encoding);
+ const wxChar* const* names = wxFontMapperBase::GetAllEncodingNames(encoding);
// CS : in case this does not return valid names (eg for MacRoman)
// encoding got a 'failure' entry in the cache all the same,
// although it just has to be created using a different method, so
return NULL;
}
-void wxCSConv::CreateConvIfNeeded() const
-{
- if ( m_deferred )
- {
- wxCSConv *self = (wxCSConv *)this; // const_cast
-
- // if we don't have neither the name nor the encoding, use the default
- // encoding for this system
- if ( !m_name && m_encoding == wxFONTENCODING_SYSTEM )
- {
-#if wxUSE_INTL
- self->m_encoding = wxLocale::GetSystemEncoding();
-#else
- // fallback to some reasonable default:
- self->m_encoding = wxFONTENCODING_ISO8859_1;
-#endif // wxUSE_INTL
- }
-
- self->m_convReal = DoCreate();
- self->m_deferred = false;
- }
-}
-
bool wxCSConv::IsOk() const
{
- CreateConvIfNeeded();
-
// special case: no convReal created for wxFONTENCODING_ISO8859_1
if ( m_encoding == wxFONTENCODING_ISO8859_1 )
return true; // always ok as we do it ourselves
size_t wxCSConv::ToWChar(wchar_t *dst, size_t dstLen,
const char *src, size_t srcLen) const
{
- CreateConvIfNeeded();
-
if (m_convReal)
return m_convReal->ToWChar(dst, dstLen, src, srcLen);
size_t wxCSConv::FromWChar(char *dst, size_t dstLen,
const wchar_t *src, size_t srcLen) const
{
- CreateConvIfNeeded();
-
if (m_convReal)
return m_convReal->FromWChar(dst, dstLen, src, srcLen);
size_t wxCSConv::GetMBNulLen() const
{
- CreateConvIfNeeded();
-
if ( m_convReal )
- {
return m_convReal->GetMBNulLen();
- }
// otherwise, we are ISO-8859-1
return 1;
#if wxUSE_UNICODE_UTF8
bool wxCSConv::IsUTF8() const
{
- CreateConvIfNeeded();
-
if ( m_convReal )
- {
return m_convReal->IsUTF8();
- }
// otherwise, we are ISO-8859-1
return false;
WXDLLIMPEXP_DATA_BASE(wxMBConv *) wxConvUI = wxGet_wxConvLocalPtr();
#ifdef __DARWIN__
-// The xnu kernel always communicates file paths in decomposed UTF-8.
-// WARNING: Are we sure that CFString's conversion will cause decomposition?
+// It is important to use this conversion object under Darwin as it ensures
+// that Unicode strings are (re)composed correctly even though xnu kernel uses
+// decomposed form internally (at least for the file names).
static wxMBConv_cf wxConvMacUTF8DObj(wxFONTENCODING_UTF8);
#endif
#else // !__DARWIN__
wxGet_wxConvLibcPtr();
#endif // __DARWIN__/!__DARWIN__
-
-#else // !wxUSE_WCHAR_T
-
-// FIXME-UTF8: remove this, wxUSE_WCHAR_T is required now
-// stand-ins in absence of wchar_t
-WXDLLIMPEXP_DATA_BASE(wxMBConv) wxConvLibc,
- wxConvISO8859_1,
- wxConvLocal,
- wxConvUTF8;
-
-#endif // wxUSE_WCHAR_T/!wxUSE_WCHAR_T