GBK与Utf-8编码在rapidjson的转换。
字符串为GBK编码的程序与utf-8编码的程序通过json交互时,由于rapidjson使用Utf-8编码,GBK和utf-8对某些中文字符的编码不同导致rapidjson解析时出错。例如“玕”在utf-8编码第一位对应多字节的转义符'\',导致后面解析为其它符号意义全乱套,rapidjson解析json串时就会失败。
解决方案
通过修改rapidjson接口,自动处理GBK与Utf8互转,调用方不需要考虑编码问题。调用方通过CJsonHelper接口实现json生成与解析。
rapidjson源代码修改:
document.h 修改前
template <unsigned parseFlags>
GenericDocument& Parse(const Ch* str) {
return Parse<parseFlags, Encoding>(str);
}
修改后
#include <stringapiset.h>
template <unsigned parseFlags>
GenericDocument& Parse(const Ch* str) {
CString s(str);
jsonConvertGBKToUtf8(s);
return Parse<parseFlags, Encoding>(s);
}
void jsonConvertGBKToUtf8(CString& strGBK)
{
int len = MultiByteToWideChar(CP_ACP, 0, (LPCTSTR)strGBK, -1, NULL, 0);
wchar_t* wszUtf8 = new wchar_t[len];
memset(wszUtf8, 0, len);
MultiByteToWideChar(CP_ACP, 0, (LPCTSTR)strGBK, -1, wszUtf8, len);
len = WideCharToMultiByte(CP_UTF8, 0, wszUtf8, -1, NULL, 0, NULL, NULL);
char* szUtf8 = new char[len + 1];
memset(szUtf8, 0, len + 1);
WideCharToMultiByte(CP_UTF8, 0, wszUtf8, -1, szUtf8, len, NULL, NULL);
strGBK = szUtf8;
delete[] szUtf8;
delete[] wszUtf8;
}
stringbuffer.h 修改前:
const Ch* GetString() const {
// Push and pop a null terminator. This is safe.
*stack_.template Push<Ch>() = '\0';
stack_.template Pop<Ch>(1);
return stack_.template Bottom<Ch>();
}
修改后:
#include <afxstr.h>
CString GetString() const {
// Push and pop a null terminator. This is safe.
*stack_.template Push<Ch>() = '\0';
stack_.template Pop<Ch>(1);
CString sRet(stack_.template Bottom<Ch>());
ConvertUtf8ToGBK(sRet);
return sRet;
}
void ConvertUtf8ToGBK(CString& strUtf8) const
{
int len = MultiByteToWideChar(CP_UTF8, 0, (LPCTSTR)strUtf8, -1, NULL, 0);
wchar_t* wszGBK = new wchar_t[len];
memset(wszGBK, 0, len);
MultiByteToWideChar(CP_UTF8, 0, (LPCTSTR)strUtf8, -1, wszGBK, len);
len = WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, NULL, 0, NULL, NULL);
char* szGBK = new char[len + 1];
memset(szGBK, 0, len + 1);
WideCharToMultiByte(CP_ACP, 0, wszGBK, -1, szGBK, len, NULL, NULL);
strUtf8 = szGBK;
delete[] szGBK;
delete[] wszGBK;
}
接口封装类的修改:
对rapidJson调用做了封装,调用时原则上通过CJsonHelper实现。为了防止调用GenericValue类AddMember方法将其删除:(document.h)——GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator)。