1
0
forked from 0ad/0ad

wchar: only raise warning dialog if caller doesn't ask for a return code

update test_wchar accordingly.
app_hooks: update documentation

This was SVN commit r7190.
This commit is contained in:
janwas 2009-11-10 21:07:18 +00:00
parent 7a6109f474
commit 345395375a
4 changed files with 54 additions and 37 deletions

View File

@ -105,13 +105,10 @@ extern void ah_override_gl_upload_caps();
/**
* return path to directory into which crash dumps should be written.
*
* if implementing via static storage, be sure to guarantee reentrancy
* (e.g. by only filling the string once).
* must be callable at any time - in particular, before VFS init.
* this means path_MakeAbsolute cannot be used; it is best
* to specify a path relative to sys_get_executable_name.
* paths are typically relative to sys_get_executable_name.
*
* @return full path ending with directory separator (e.g. '/').
* @return path ending with directory separator (e.g. '/').
**/
extern const fs::wpath& ah_get_log_dir();

View File

@ -65,16 +65,16 @@ public:
{ "c\xef\xbf\x01", L"c\xfffd\xfffd\x0001" },
{ "d\xffX\x80Y\x80" , L"d\xfffdX\xfffdY\xfffd" }
};
debug_SkipErrors(ERR::WCHAR_INVALID_UTF8);
for (size_t i = 0; i < ARRAY_SIZE(tests); ++i)
{
const std::string str_utf8(tests[i].utf8);
const std::wstring str_utf16(tests[i].utf16);
const std::wstring str_utf8to16 = wstring_from_utf8(str_utf8);
LibError err;
const std::wstring str_utf8to16 = wstring_from_utf8(str_utf8, &err);
TS_ASSERT_EQUALS(err, ERR::WCHAR_INVALID_UTF8);
TS_ASSERT_EQUALS(str_utf16.length(), str_utf8to16.length());
TS_ASSERT_SAME_DATA(str_utf8to16.data(), str_utf16.data(), str_utf16.length()*sizeof(wchar_t));
}
TS_ASSERT_EQUALS(debug_StopSkippingErrors(), 8);
}
};

View File

@ -63,30 +63,33 @@ ERROR_ASSOCIATE(ERR::WCHAR_INVALID_UTF8, L"Invalid UTF-8 sequence", -1);
typedef u8 UTF8;
typedef u32 UTF32;
// referenced by ReplaceIfInvalid and UTF8::Decode; use DEBUG_WARN_ERR
// to ensure the problem is seen by users.
static const UTF32 replacementCharacter = 0xFFFDul;
static UTF32 ReplaceIfInvalid(UTF32 u)
// called from ReplaceIfInvalid and UTF8Codec::Decode
static UTF32 RaiseError(LibError err, LibError* perr)
{
if(perr) // caller wants return code, not warning dialog
{
if(*perr == INFO::OK) // only return the first error (see header)
*perr = err;
}
else
DEBUG_WARN_ERR(err);
return 0xFFFDul; // replacement character
}
static UTF32 ReplaceIfInvalid(UTF32 u, LibError* err)
{
// disallow surrogates
if(0xD800ul <= u && u <= 0xDFFFul)
{
DEBUG_WARN_ERR(ERR::WCHAR_SURROGATE);
return replacementCharacter;
}
return RaiseError(ERR::WCHAR_SURROGATE, err);
// outside BMP (UTF-16 representation would require surrogates)
if(u > 0xFFFFul)
{
DEBUG_WARN_ERR(ERR::WCHAR_OUTSIDE_BMP);
return replacementCharacter;
}
return RaiseError(ERR::WCHAR_OUTSIDE_BMP, err);
// noncharacter (note: WEOF (0xFFFF) causes VC's swprintf to fail)
if(u == 0xFFFEul || u == 0xFFFFul || (0xFDD0ul <= u && u <= 0xFDEFul))
{
DEBUG_WARN_ERR(ERR::WCHAR_NONCHARACTER);
return replacementCharacter;
}
return RaiseError(ERR::WCHAR_NONCHARACTER, err);
return u;
}
@ -108,14 +111,13 @@ public:
}
// @return decoded scalar, or replacementCharacter on error
static UTF32 Decode(const UTF8*& srcPos, const UTF8* const srcEnd)
static UTF32 Decode(const UTF8*& srcPos, const UTF8* const srcEnd, LibError* err)
{
const size_t size = SizeFromFirstByte(*srcPos);
if(!IsValid(srcPos, size, srcEnd))
{
srcPos += 1; // only skip the offending byte (increases chances of resynchronization)
DEBUG_WARN_ERR(ERR::WCHAR_INVALID_UTF8);
return replacementCharacter;
return RaiseError(ERR::WCHAR_INVALID_UTF8, err);
}
UTF32 u = 0;
@ -189,13 +191,16 @@ private:
//-----------------------------------------------------------------------------
std::string utf8_from_wstring(const std::wstring& src)
std::string utf8_from_wstring(const std::wstring& src, LibError* err)
{
if(err)
*err = INFO::OK;
std::string dst(src.size()*3+1, ' '); // see UTF8Codec::Size; +1 ensures &dst[0] is valid
UTF8* dstPos = (UTF8*)&dst[0];
for(size_t i = 0; i < src.size(); i++)
{
const UTF32 u = ReplaceIfInvalid(UTF32(src[i]));
const UTF32 u = ReplaceIfInvalid(UTF32(src[i]), err);
UTF8Codec::Encode(u, dstPos);
}
dst.resize(dstPos - (UTF8*)&dst[0]);
@ -203,16 +208,19 @@ std::string utf8_from_wstring(const std::wstring& src)
}
std::wstring wstring_from_utf8(const std::string& src)
std::wstring wstring_from_utf8(const std::string& src, LibError* err)
{
if(err)
*err = INFO::OK;
std::wstring dst;
dst.reserve(src.size());
const UTF8* srcPos = (const UTF8*)src.data();
const UTF8* const srcEnd = srcPos + src.size();
while(srcPos < srcEnd)
{
const UTF32 u = UTF8Codec::Decode(srcPos, srcEnd);
dst.push_back((wchar_t)ReplaceIfInvalid(u));
const UTF32 u = UTF8Codec::Decode(srcPos, srcEnd, err);
dst.push_back((wchar_t)ReplaceIfInvalid(u, err));
}
return dst;
}

View File

@ -18,9 +18,7 @@
#ifndef INCLUDED_WCHAR
#define INCLUDED_WCHAR
// note: returning LibError below would be inconvenient; we only use
// these to raise warnings. (codes instead of strings allow suppressing
// the error dialog when running the self-test)
// note: error codes are returned via optional output parameter.
namespace ERR
{
const LibError WCHAR_SURROGATE = -100700;
@ -29,7 +27,21 @@ namespace ERR
const LibError WCHAR_INVALID_UTF8 = -100703;
}
LIB_API std::wstring wstring_from_utf8(const std::string& s);
LIB_API std::string utf8_from_wstring(const std::wstring& s);
/**
* convert UTF-8 to a wide string (UTF-16 or UCS-4, depending on the
* platform's wchar_t).
*
* @param s input string (UTF-8)
* @param err if nonzero, this receives the first error encountered
* (the rest may be subsequent faults) or INFO::OK if all went well.
* otherwise, the function raises a warning dialog for every
* error/warning.
**/
LIB_API std::wstring wstring_from_utf8(const std::string& s, LibError* err = 0);
/**
* opposite of wstring_from_utf8
**/
LIB_API std::string utf8_from_wstring(const std::wstring& s, LibError* err = 0);
#endif // #ifndef INCLUDED_WCHAR