fail WC2MB conversion in wxCSConv if we can't be sure that we don't lose information
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@25821 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -40,6 +40,7 @@
|
|||||||
|
|
||||||
#ifdef __WXMSW__
|
#ifdef __WXMSW__
|
||||||
#include "wx/msw/private.h"
|
#include "wx/msw/private.h"
|
||||||
|
#include "wx/msw/missing.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef __WXWINCE__
|
#ifndef __WXWINCE__
|
||||||
@@ -1151,28 +1152,118 @@ public:
|
|||||||
return len ? len - 1 : (size_t)-1;
|
return len ? len - 1 : (size_t)-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t WC2MB(char *buf, const wchar_t *psz, size_t n) const
|
size_t WC2MB(char *buf, const wchar_t *pwz, size_t n) const
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
we have a problem here: by default, WideCharToMultiByte() may
|
||||||
|
replace characters unrepresentable in the target code page with bad
|
||||||
|
quality approximations such as turning "1/2" symbol (U+00BD) into
|
||||||
|
"1" for the code pages which don't have it and we, obviously, want
|
||||||
|
to avoid this at any price
|
||||||
|
|
||||||
|
the trouble is that this function does it _silently_, i.e. it won't
|
||||||
|
even tell us whether it did or not... Win98/2000 and higher provide
|
||||||
|
WC_NO_BEST_FIT_CHARS but it doesn't work for the older systems and
|
||||||
|
we have to resort to a round trip, i.e. check that converting back
|
||||||
|
results in the same string -- this is, of course, expensive but
|
||||||
|
otherwise we simply can't be sure to not garble the data.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// determine if we can rely on WC_NO_BEST_FIT_CHARS: according to MSDN
|
||||||
|
// it doesn't work with CJK encodings (which we test for rather roughly
|
||||||
|
// here...) nor with UTF-7/8 nor, of course, with Windows versions not
|
||||||
|
// supporting it
|
||||||
|
BOOL usedDef wxDUMMY_INITIALIZE(false),
|
||||||
|
*pUsedDef;
|
||||||
|
int flags;
|
||||||
|
if ( CanUseNoBestFit() && m_CodePage < 50000 )
|
||||||
|
{
|
||||||
|
// it's our lucky day
|
||||||
|
flags = WC_NO_BEST_FIT_CHARS;
|
||||||
|
pUsedDef = &usedDef;
|
||||||
|
}
|
||||||
|
else // old system or unsupported encoding
|
||||||
|
{
|
||||||
|
flags = 0;
|
||||||
|
pUsedDef = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
const size_t len = ::WideCharToMultiByte
|
const size_t len = ::WideCharToMultiByte
|
||||||
(
|
(
|
||||||
m_CodePage, // code page
|
m_CodePage, // code page
|
||||||
0, // flags (none)
|
flags, // either none or no best fit
|
||||||
psz, // input string
|
pwz, // input string
|
||||||
-1, // it is (wide) NUL-terminated
|
-1, // it is (wide) NUL-terminated
|
||||||
buf, // output buffer
|
buf, // output buffer
|
||||||
buf ? n : 0, // and its size
|
buf ? n : 0, // and its size
|
||||||
NULL, // default "replacement" char
|
NULL, // default "replacement" char
|
||||||
NULL // [out] was it used?
|
pUsedDef // [out] was it used?
|
||||||
);
|
);
|
||||||
|
|
||||||
// see the comment above for the reason of "len - 1"
|
if ( !len )
|
||||||
return len ? len - 1 : (size_t)-1;
|
{
|
||||||
|
// function totally failed
|
||||||
|
return (size_t)-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsOk() const
|
// if we were really converting, check if we succeeded
|
||||||
{ return m_CodePage != -1; }
|
if ( buf )
|
||||||
|
{
|
||||||
|
if ( flags )
|
||||||
|
{
|
||||||
|
// check if the conversion failed, i.e. if any replacements
|
||||||
|
// were done
|
||||||
|
if ( usedDef )
|
||||||
|
return (size_t)-1;
|
||||||
|
}
|
||||||
|
else // we must resort to double tripping...
|
||||||
|
{
|
||||||
|
wxWCharBuffer wcBuf(n);
|
||||||
|
if ( MB2WC(wcBuf.data(), buf, n) == (size_t)-1 ||
|
||||||
|
wcscmp(wcBuf, pwz) != 0 )
|
||||||
|
{
|
||||||
|
// we didn't obtain the same thing we started from, hence
|
||||||
|
// the conversion was lossy and we consider that it failed
|
||||||
|
return (size_t)-1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// see the comment above for the reason of "len - 1"
|
||||||
|
return len - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsOk() const { return m_CodePage != -1; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
static bool CanUseNoBestFit()
|
||||||
|
{
|
||||||
|
static int s_isWin98Or2k = -1;
|
||||||
|
|
||||||
|
if ( s_isWin98Or2k == -1 )
|
||||||
|
{
|
||||||
|
int verMaj, verMin;
|
||||||
|
switch ( wxGetOsVersion(&verMaj, &verMin) )
|
||||||
|
{
|
||||||
|
case wxWIN95:
|
||||||
|
s_isWin98Or2k = verMaj >= 4 && verMin >= 10;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case wxWINDOWS_NT:
|
||||||
|
s_isWin98Or2k = verMaj >= 5;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// unknown, be conseravtive by default
|
||||||
|
s_isWin98Or2k = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
wxASSERT_MSG( s_isWin98Or2k != -1, _T("should be set above") );
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_isWin98Or2k == 1;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
long m_CodePage;
|
long m_CodePage;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user