1. added encodings handling to XRC, so that it is possible
to load resources that don't use English+wxLocale for i18n 2. expat interface can now read non-utf-8 encodings as well git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@13783 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -300,10 +300,11 @@ wxList *wxXmlDocument::sm_handlers = NULL;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
wxXmlDocument::wxXmlDocument(const wxString& filename, wxXmlIOType io_type)
|
wxXmlDocument::wxXmlDocument(const wxString& filename, wxXmlIOType io_type,
|
||||||
|
const wxString& encoding)
|
||||||
: wxObject(), m_root(NULL)
|
: wxObject(), m_root(NULL)
|
||||||
{
|
{
|
||||||
if (!Load(filename, io_type))
|
if (!Load(filename, io_type, encoding))
|
||||||
{
|
{
|
||||||
wxDELETE(m_root);
|
wxDELETE(m_root);
|
||||||
}
|
}
|
||||||
@@ -311,10 +312,11 @@ wxXmlDocument::wxXmlDocument(const wxString& filename, wxXmlIOType io_type)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
wxXmlDocument::wxXmlDocument(wxInputStream& stream, wxXmlIOType io_type)
|
wxXmlDocument::wxXmlDocument(wxInputStream& stream, wxXmlIOType io_type,
|
||||||
|
const wxString& encoding)
|
||||||
: wxObject(), m_root(NULL)
|
: wxObject(), m_root(NULL)
|
||||||
{
|
{
|
||||||
if (!Load(stream, io_type))
|
if (!Load(stream, io_type, encoding))
|
||||||
{
|
{
|
||||||
wxDELETE(m_root);
|
wxDELETE(m_root);
|
||||||
}
|
}
|
||||||
@@ -341,22 +343,33 @@ wxXmlDocument& wxXmlDocument::operator=(const wxXmlDocument& doc)
|
|||||||
void wxXmlDocument::DoCopy(const wxXmlDocument& doc)
|
void wxXmlDocument::DoCopy(const wxXmlDocument& doc)
|
||||||
{
|
{
|
||||||
m_version = doc.m_version;
|
m_version = doc.m_version;
|
||||||
|
#if !wxUSE_UNICODE
|
||||||
m_encoding = doc.m_encoding;
|
m_encoding = doc.m_encoding;
|
||||||
|
#endif
|
||||||
|
m_fileEncoding = doc.m_fileEncoding;
|
||||||
m_root = new wxXmlNode(*doc.m_root);
|
m_root = new wxXmlNode(*doc.m_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool wxXmlDocument::Load(const wxString& filename, wxXmlIOType io_type)
|
bool wxXmlDocument::Load(const wxString& filename, wxXmlIOType io_type,
|
||||||
|
const wxString& encoding)
|
||||||
{
|
{
|
||||||
wxFileInputStream stream(filename);
|
wxFileInputStream stream(filename);
|
||||||
return Load(stream, io_type);
|
return Load(stream, io_type, encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool wxXmlDocument::Load(wxInputStream& stream, wxXmlIOType io_type)
|
bool wxXmlDocument::Load(wxInputStream& stream, wxXmlIOType io_type,
|
||||||
|
const wxString& encoding)
|
||||||
{
|
{
|
||||||
|
#if wxUSE_UNICODE
|
||||||
|
(void)encoding;
|
||||||
|
#else
|
||||||
|
m_encoding = encoding;
|
||||||
|
#endif
|
||||||
|
|
||||||
wxNode *n = sm_handlers->GetFirst();
|
wxNode *n = sm_handlers->GetFirst();
|
||||||
while (n)
|
while (n)
|
||||||
{
|
{
|
||||||
@@ -365,7 +378,7 @@ bool wxXmlDocument::Load(wxInputStream& stream, wxXmlIOType io_type)
|
|||||||
if ((io_type == wxXML_IO_AUTO || io_type == h->GetType()) &&
|
if ((io_type == wxXML_IO_AUTO || io_type == h->GetType()) &&
|
||||||
h->CanLoad(stream))
|
h->CanLoad(stream))
|
||||||
{
|
{
|
||||||
return h->Load(stream, *this);
|
return h->Load(stream, *this, encoding);
|
||||||
}
|
}
|
||||||
n = n->GetNext();
|
n = n->GetNext();
|
||||||
}
|
}
|
||||||
|
@@ -101,7 +101,12 @@ bool wxXmlIOHandlerBin::Save(wxOutputStream& stream, const wxXmlDocument& doc)
|
|||||||
{
|
{
|
||||||
WriteHeader(stream, "XMLBIN ");
|
WriteHeader(stream, "XMLBIN ");
|
||||||
wxDataOutputStream ds(stream);
|
wxDataOutputStream ds(stream);
|
||||||
ds << doc.GetVersion() << doc.GetEncoding();
|
ds << doc.GetVersion();
|
||||||
|
#if wxUSE_UNICODE
|
||||||
|
ds << wxString(wxT("UTF-8"));
|
||||||
|
#else
|
||||||
|
ds << doc.GetEncoding();
|
||||||
|
#endif
|
||||||
SaveBinNode(ds, doc.GetRoot());
|
SaveBinNode(ds, doc.GetRoot());
|
||||||
return stream.LastError() == wxSTREAM_NOERROR;
|
return stream.LastError() == wxSTREAM_NOERROR;
|
||||||
}
|
}
|
||||||
@@ -142,7 +147,8 @@ static wxXmlNode *LoadBinNode(wxDataInputStream& ds, wxXmlNode *parent)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool wxXmlIOHandlerBin::Load(wxInputStream& stream, wxXmlDocument& doc)
|
bool wxXmlIOHandlerBin::Load(wxInputStream& stream, wxXmlDocument& doc,
|
||||||
|
const wxString& encoding)
|
||||||
{
|
{
|
||||||
ReadHeader(stream);
|
ReadHeader(stream);
|
||||||
wxDataInputStream ds(stream);
|
wxDataInputStream ds(stream);
|
||||||
@@ -151,7 +157,7 @@ bool wxXmlIOHandlerBin::Load(wxInputStream& stream, wxXmlDocument& doc)
|
|||||||
ds >> tmp;
|
ds >> tmp;
|
||||||
doc.SetVersion(tmp);
|
doc.SetVersion(tmp);
|
||||||
ds >> tmp;
|
ds >> tmp;
|
||||||
doc.SetEncoding(tmp);
|
doc.SetFileEncoding(tmp);
|
||||||
|
|
||||||
doc.SetRoot(LoadBinNode(ds, NULL));
|
doc.SetRoot(LoadBinNode(ds, NULL));
|
||||||
|
|
||||||
|
@@ -48,11 +48,12 @@ bool wxXmlIOHandlerBinZ::Save(wxOutputStream& stream, const wxXmlDocument& doc)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool wxXmlIOHandlerBinZ::Load(wxInputStream& stream, wxXmlDocument& doc)
|
bool wxXmlIOHandlerBinZ::Load(wxInputStream& stream, wxXmlDocument& doc,
|
||||||
|
const wxString& encoding)
|
||||||
{
|
{
|
||||||
ReadHeader(stream);
|
ReadHeader(stream);
|
||||||
wxZlibInputStream costr(stream);
|
wxZlibInputStream costr(stream);
|
||||||
return wxXmlIOHandlerBin::Load(costr, doc);
|
return wxXmlIOHandlerBin::Load(costr, doc, encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -30,23 +30,32 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
FIXME:
|
FIXME:
|
||||||
|
|
||||||
- handle unknown encodings
|
|
||||||
- process all elements, including CDATA
|
- process all elements, including CDATA
|
||||||
- XRC resources should automatically select desired encoding based on
|
|
||||||
runtime environment (?) (would need BIN and BINZ formats modification,
|
|
||||||
too)
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
// converts Expat-produced string in UTF-8 into wxString.
|
// converts Expat-produced string in UTF-8 into wxString.
|
||||||
inline static wxString CharToString(const char *s, size_t len = wxSTRING_MAXLEN)
|
inline static wxString CharToString(wxMBConv *conv,
|
||||||
|
const char *s, size_t len = wxSTRING_MAXLEN)
|
||||||
{
|
{
|
||||||
#if wxUSE_UNICODE
|
#if wxUSE_UNICODE
|
||||||
|
(void)conv;
|
||||||
return wxString(s, wxConvUTF8, len);
|
return wxString(s, wxConvUTF8, len);
|
||||||
#else
|
#else
|
||||||
return wxString(s, len);
|
if ( conv )
|
||||||
|
{
|
||||||
|
size_t nLen = (len != wxSTRING_MAXLEN) ? len :
|
||||||
|
nLen = wxConvUTF8.MB2WC((wchar_t*) NULL, s, 0);
|
||||||
|
|
||||||
|
wchar_t *buf = new wchar_t[nLen+1];
|
||||||
|
wxConvUTF8.MB2WC(buf, s, nLen);
|
||||||
|
buf[nLen] = 0;
|
||||||
|
return wxString(buf, *conv, len);
|
||||||
|
delete[] buf;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return wxString(s, len);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,21 +71,23 @@ bool wxXmlIOHandlerExpat::CanLoad(wxInputStream& stream)
|
|||||||
|
|
||||||
struct wxXmlParsingContext
|
struct wxXmlParsingContext
|
||||||
{
|
{
|
||||||
|
wxMBConv *conv;
|
||||||
|
|
||||||
wxXmlNode *root;
|
wxXmlNode *root;
|
||||||
wxXmlNode *node;
|
wxXmlNode *node;
|
||||||
wxXmlNode *lastAsText;
|
wxXmlNode *lastAsText;
|
||||||
wxString encoding;
|
wxString encoding;
|
||||||
wxString version;
|
wxString version;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void StartElementHnd(void *userData, const char *name, const char **atts)
|
static void StartElementHnd(void *userData, const char *name, const char **atts)
|
||||||
{
|
{
|
||||||
wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
|
wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
|
||||||
wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, CharToString(name));
|
wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, CharToString(ctx->conv, name));
|
||||||
const char **a = atts;
|
const char **a = atts;
|
||||||
while (*a)
|
while (*a)
|
||||||
{
|
{
|
||||||
node->AddProperty(CharToString(a[0]), CharToString(a[1]));
|
node->AddProperty(CharToString(ctx->conv, a[0]), CharToString(ctx->conv, a[1]));
|
||||||
a += 2;
|
a += 2;
|
||||||
}
|
}
|
||||||
if (ctx->root == NULL)
|
if (ctx->root == NULL)
|
||||||
@@ -106,7 +117,7 @@ static void TextHnd(void *userData, const char *s, int len)
|
|||||||
if (ctx->lastAsText)
|
if (ctx->lastAsText)
|
||||||
{
|
{
|
||||||
ctx->lastAsText->SetContent(ctx->lastAsText->GetContent() +
|
ctx->lastAsText->SetContent(ctx->lastAsText->GetContent() +
|
||||||
CharToString(buf));
|
CharToString(ctx->conv, buf));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -120,7 +131,7 @@ static void TextHnd(void *userData, const char *s, int len)
|
|||||||
if (!whiteOnly)
|
if (!whiteOnly)
|
||||||
{
|
{
|
||||||
ctx->lastAsText = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"),
|
ctx->lastAsText = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"),
|
||||||
CharToString(buf));
|
CharToString(ctx->conv, buf));
|
||||||
ctx->node->AddChild(ctx->lastAsText);
|
ctx->node->AddChild(ctx->lastAsText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,7 +149,7 @@ static void CommentHnd(void *userData, const char *data)
|
|||||||
// the root element (e.g. wxDesigner's output). We ignore such
|
// the root element (e.g. wxDesigner's output). We ignore such
|
||||||
// comments, no big deal...
|
// comments, no big deal...
|
||||||
ctx->node->AddChild(new wxXmlNode(wxXML_COMMENT_NODE,
|
ctx->node->AddChild(new wxXmlNode(wxXML_COMMENT_NODE,
|
||||||
wxT("comment"), CharToString(data)));
|
wxT("comment"), CharToString(ctx->conv, data)));
|
||||||
}
|
}
|
||||||
ctx->lastAsText = NULL;
|
ctx->lastAsText = NULL;
|
||||||
}
|
}
|
||||||
@@ -150,7 +161,7 @@ static void DefaultHnd(void *userData, const char *s, int len)
|
|||||||
{
|
{
|
||||||
wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
|
wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
|
||||||
|
|
||||||
wxString buf = CharToString(s, (size_t)len);
|
wxString buf = CharToString(ctx->conv, s, (size_t)len);
|
||||||
int pos;
|
int pos;
|
||||||
pos = buf.Find(wxT("encoding="));
|
pos = buf.Find(wxT("encoding="));
|
||||||
if (pos != wxNOT_FOUND)
|
if (pos != wxNOT_FOUND)
|
||||||
@@ -161,7 +172,36 @@ static void DefaultHnd(void *userData, const char *s, int len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxXmlIOHandlerExpat::Load(wxInputStream& stream, wxXmlDocument& doc)
|
static int UnknownEncodingHnd(void * WXUNUSED(encodingHandlerData),
|
||||||
|
const XML_Char *name, XML_Encoding *info)
|
||||||
|
{
|
||||||
|
// We must build conversion table for expat. The easiest way to do so
|
||||||
|
// is to let wxCSConv convert as string containing all characters to
|
||||||
|
// wide character representation:
|
||||||
|
wxCSConv conv(name);
|
||||||
|
char mbBuf[255];
|
||||||
|
wchar_t wcBuf[255];
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < 255; i++)
|
||||||
|
mbBuf[i] = i+1;
|
||||||
|
mbBuf[255] = 0;
|
||||||
|
conv.MB2WC(wcBuf, mbBuf, 255);
|
||||||
|
wcBuf[255] = 0;
|
||||||
|
|
||||||
|
info->map[0] = 0;
|
||||||
|
for (i = 0; i < 255; i++)
|
||||||
|
info->map[i+1] = (int)wcBuf[i];
|
||||||
|
|
||||||
|
info->data = NULL;
|
||||||
|
info->convert = NULL;
|
||||||
|
info->release = NULL;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wxXmlIOHandlerExpat::Load(wxInputStream& stream, wxXmlDocument& doc,
|
||||||
|
const wxString& encoding)
|
||||||
{
|
{
|
||||||
const size_t BUFSIZE = 1024;
|
const size_t BUFSIZE = 1024;
|
||||||
char buf[BUFSIZE];
|
char buf[BUFSIZE];
|
||||||
@@ -170,11 +210,19 @@ bool wxXmlIOHandlerExpat::Load(wxInputStream& stream, wxXmlDocument& doc)
|
|||||||
XML_Parser parser = XML_ParserCreate(NULL);
|
XML_Parser parser = XML_ParserCreate(NULL);
|
||||||
|
|
||||||
ctx.root = ctx.node = NULL;
|
ctx.root = ctx.node = NULL;
|
||||||
|
ctx.encoding = wxT("UTF-8"); // default in absence of encoding=""
|
||||||
|
ctx.conv = NULL;
|
||||||
|
#if !wxUSE_UNICODE
|
||||||
|
if ( encoding != wxT("UTF-8") && encoding != wxT("utf-8") )
|
||||||
|
ctx.conv = new wxCSConv(encoding);
|
||||||
|
#endif
|
||||||
|
|
||||||
XML_SetUserData(parser, (void*)&ctx);
|
XML_SetUserData(parser, (void*)&ctx);
|
||||||
XML_SetElementHandler(parser, StartElementHnd, EndElementHnd);
|
XML_SetElementHandler(parser, StartElementHnd, EndElementHnd);
|
||||||
XML_SetCharacterDataHandler(parser, TextHnd);
|
XML_SetCharacterDataHandler(parser, TextHnd);
|
||||||
XML_SetCommentHandler(parser, CommentHnd);
|
XML_SetCommentHandler(parser, CommentHnd);
|
||||||
XML_SetDefaultHandler(parser, DefaultHnd);
|
XML_SetDefaultHandler(parser, DefaultHnd);
|
||||||
|
XML_SetUnknownEncodingHandler(parser, UnknownEncodingHnd, NULL);
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -190,9 +238,14 @@ bool wxXmlIOHandlerExpat::Load(wxInputStream& stream, wxXmlDocument& doc)
|
|||||||
} while (!done);
|
} while (!done);
|
||||||
|
|
||||||
doc.SetVersion(ctx.version);
|
doc.SetVersion(ctx.version);
|
||||||
doc.SetEncoding(ctx.encoding);
|
doc.SetFileEncoding(ctx.encoding);
|
||||||
doc.SetRoot(ctx.root);
|
doc.SetRoot(ctx.root);
|
||||||
|
|
||||||
XML_ParserFree(parser);
|
XML_ParserFree(parser);
|
||||||
|
#if !wxUSE_UNICODE
|
||||||
|
if ( ctx.conv )
|
||||||
|
delete ctx.conv;
|
||||||
|
#endif
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@@ -100,9 +100,9 @@ bool wxXmlResource::Load(const wxString& filemask)
|
|||||||
{
|
{
|
||||||
#if wxUSE_FILESYSTEM
|
#if wxUSE_FILESYSTEM
|
||||||
if (filemask.Lower().Matches(wxT("*.zip")) ||
|
if (filemask.Lower().Matches(wxT("*.zip")) ||
|
||||||
filemask.Lower().Matches(wxT("*.rsc")))
|
filemask.Lower().Matches(wxT("*.xrs")))
|
||||||
{
|
{
|
||||||
rt = rt && Load(fnd + wxT("#zip:*.xmb"));
|
rt = rt && Load(fnd + wxT("#zip:*.xmlbin"));
|
||||||
rt = rt && Load(fnd + wxT("#zip:*.xrc"));
|
rt = rt && Load(fnd + wxT("#zip:*.xrc"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -286,6 +286,17 @@ void wxXmlResource::UpdateResources()
|
|||||||
wxFileSystem fsys;
|
wxFileSystem fsys;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
wxString encoding(wxT("UTF-8"));
|
||||||
|
#if !wxUSE_UNICODE && wxUSE_INTL
|
||||||
|
if ( (GetFlags() & wxXRC_USE_LOCALE) == 0 )
|
||||||
|
{
|
||||||
|
// In case we are not using wxLocale to translate strings, convert the strings
|
||||||
|
// GUI's charset. This must not be done when wxXRC_USE_LOCALE is on, because
|
||||||
|
// it could break wxGetTranslation lookup.
|
||||||
|
encoding = wxLocale::GetSystemEncodingName();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
for (size_t i = 0; i < m_data.GetCount(); i++)
|
for (size_t i = 0; i < m_data.GetCount(); i++)
|
||||||
{
|
{
|
||||||
modif = (m_data[i].Doc == NULL);
|
modif = (m_data[i].Doc == NULL);
|
||||||
@@ -305,7 +316,7 @@ void wxXmlResource::UpdateResources()
|
|||||||
|
|
||||||
if (modif)
|
if (modif)
|
||||||
{
|
{
|
||||||
wxInputStream *stream = NULL;
|
wxInputStream *stream = NULL;
|
||||||
|
|
||||||
# if wxUSE_FILESYSTEM
|
# if wxUSE_FILESYSTEM
|
||||||
file = fsys.OpenFile(m_data[i].File);
|
file = fsys.OpenFile(m_data[i].File);
|
||||||
@@ -320,9 +331,10 @@ void wxXmlResource::UpdateResources()
|
|||||||
delete m_data[i].Doc;
|
delete m_data[i].Doc;
|
||||||
m_data[i].Doc = new wxXmlDocument;
|
m_data[i].Doc = new wxXmlDocument;
|
||||||
}
|
}
|
||||||
if (!stream || !m_data[i].Doc->Load(*stream))
|
if (!stream || !m_data[i].Doc->Load(*stream, wxXML_IO_AUTO, encoding))
|
||||||
{
|
{
|
||||||
wxLogError(_("Cannot load resources from file '%s'."), m_data[i].File.c_str());
|
wxLogError(_("Cannot load resources from file '%s'."),
|
||||||
|
m_data[i].File.c_str());
|
||||||
wxDELETE(m_data[i].Doc);
|
wxDELETE(m_data[i].Doc);
|
||||||
}
|
}
|
||||||
else if (m_data[i].Doc->GetRoot()->GetName() != wxT("resource"))
|
else if (m_data[i].Doc->GetRoot()->GetName() != wxT("resource"))
|
||||||
|
@@ -44,22 +44,22 @@ static void OutputStringEnt(wxOutputStream& stream, const wxString& str)
|
|||||||
{
|
{
|
||||||
wxString buf;
|
wxString buf;
|
||||||
size_t i, last, len;
|
size_t i, last, len;
|
||||||
char c;
|
wxChar c;
|
||||||
|
|
||||||
len = str.Len();
|
len = str.Len();
|
||||||
last = 0;
|
last = 0;
|
||||||
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
c = str.GetChar(i);
|
c = str.GetChar(i);
|
||||||
if (c == '<' || c == '>' ||
|
if (c == wxT('<') || c == wxT('>') ||
|
||||||
(c == '&' && str.Mid(i+1, 4) != wxT("amp;")))
|
(c == wxT('&') && str.Mid(i+1, 4) != wxT("amp;")))
|
||||||
{
|
{
|
||||||
OutputString(stream, str.Mid(last, i - last));
|
OutputString(stream, str.Mid(last, i - last));
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
case '<': OutputString(stream, wxT("<")); break;
|
case wxT('<'): OutputString(stream, wxT("<")); break;
|
||||||
case '>': OutputString(stream, wxT(">")); break;
|
case wxT('>'): OutputString(stream, wxT(">")); break;
|
||||||
case '&': OutputString(stream, wxT("&")); break;
|
case wxT('&'): OutputString(stream, wxT("&")); break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
last = i + 1;
|
last = i + 1;
|
||||||
|
@@ -300,10 +300,11 @@ wxList *wxXmlDocument::sm_handlers = NULL;
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
wxXmlDocument::wxXmlDocument(const wxString& filename, wxXmlIOType io_type)
|
wxXmlDocument::wxXmlDocument(const wxString& filename, wxXmlIOType io_type,
|
||||||
|
const wxString& encoding)
|
||||||
: wxObject(), m_root(NULL)
|
: wxObject(), m_root(NULL)
|
||||||
{
|
{
|
||||||
if (!Load(filename, io_type))
|
if (!Load(filename, io_type, encoding))
|
||||||
{
|
{
|
||||||
wxDELETE(m_root);
|
wxDELETE(m_root);
|
||||||
}
|
}
|
||||||
@@ -311,10 +312,11 @@ wxXmlDocument::wxXmlDocument(const wxString& filename, wxXmlIOType io_type)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
wxXmlDocument::wxXmlDocument(wxInputStream& stream, wxXmlIOType io_type)
|
wxXmlDocument::wxXmlDocument(wxInputStream& stream, wxXmlIOType io_type,
|
||||||
|
const wxString& encoding)
|
||||||
: wxObject(), m_root(NULL)
|
: wxObject(), m_root(NULL)
|
||||||
{
|
{
|
||||||
if (!Load(stream, io_type))
|
if (!Load(stream, io_type, encoding))
|
||||||
{
|
{
|
||||||
wxDELETE(m_root);
|
wxDELETE(m_root);
|
||||||
}
|
}
|
||||||
@@ -341,22 +343,33 @@ wxXmlDocument& wxXmlDocument::operator=(const wxXmlDocument& doc)
|
|||||||
void wxXmlDocument::DoCopy(const wxXmlDocument& doc)
|
void wxXmlDocument::DoCopy(const wxXmlDocument& doc)
|
||||||
{
|
{
|
||||||
m_version = doc.m_version;
|
m_version = doc.m_version;
|
||||||
|
#if !wxUSE_UNICODE
|
||||||
m_encoding = doc.m_encoding;
|
m_encoding = doc.m_encoding;
|
||||||
|
#endif
|
||||||
|
m_fileEncoding = doc.m_fileEncoding;
|
||||||
m_root = new wxXmlNode(*doc.m_root);
|
m_root = new wxXmlNode(*doc.m_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool wxXmlDocument::Load(const wxString& filename, wxXmlIOType io_type)
|
bool wxXmlDocument::Load(const wxString& filename, wxXmlIOType io_type,
|
||||||
|
const wxString& encoding)
|
||||||
{
|
{
|
||||||
wxFileInputStream stream(filename);
|
wxFileInputStream stream(filename);
|
||||||
return Load(stream, io_type);
|
return Load(stream, io_type, encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool wxXmlDocument::Load(wxInputStream& stream, wxXmlIOType io_type)
|
bool wxXmlDocument::Load(wxInputStream& stream, wxXmlIOType io_type,
|
||||||
|
const wxString& encoding)
|
||||||
{
|
{
|
||||||
|
#if wxUSE_UNICODE
|
||||||
|
(void)encoding;
|
||||||
|
#else
|
||||||
|
m_encoding = encoding;
|
||||||
|
#endif
|
||||||
|
|
||||||
wxNode *n = sm_handlers->GetFirst();
|
wxNode *n = sm_handlers->GetFirst();
|
||||||
while (n)
|
while (n)
|
||||||
{
|
{
|
||||||
@@ -365,7 +378,7 @@ bool wxXmlDocument::Load(wxInputStream& stream, wxXmlIOType io_type)
|
|||||||
if ((io_type == wxXML_IO_AUTO || io_type == h->GetType()) &&
|
if ((io_type == wxXML_IO_AUTO || io_type == h->GetType()) &&
|
||||||
h->CanLoad(stream))
|
h->CanLoad(stream))
|
||||||
{
|
{
|
||||||
return h->Load(stream, *this);
|
return h->Load(stream, *this, encoding);
|
||||||
}
|
}
|
||||||
n = n->GetNext();
|
n = n->GetNext();
|
||||||
}
|
}
|
||||||
|
@@ -101,7 +101,12 @@ bool wxXmlIOHandlerBin::Save(wxOutputStream& stream, const wxXmlDocument& doc)
|
|||||||
{
|
{
|
||||||
WriteHeader(stream, "XMLBIN ");
|
WriteHeader(stream, "XMLBIN ");
|
||||||
wxDataOutputStream ds(stream);
|
wxDataOutputStream ds(stream);
|
||||||
ds << doc.GetVersion() << doc.GetEncoding();
|
ds << doc.GetVersion();
|
||||||
|
#if wxUSE_UNICODE
|
||||||
|
ds << wxString(wxT("UTF-8"));
|
||||||
|
#else
|
||||||
|
ds << doc.GetEncoding();
|
||||||
|
#endif
|
||||||
SaveBinNode(ds, doc.GetRoot());
|
SaveBinNode(ds, doc.GetRoot());
|
||||||
return stream.LastError() == wxSTREAM_NOERROR;
|
return stream.LastError() == wxSTREAM_NOERROR;
|
||||||
}
|
}
|
||||||
@@ -142,7 +147,8 @@ static wxXmlNode *LoadBinNode(wxDataInputStream& ds, wxXmlNode *parent)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool wxXmlIOHandlerBin::Load(wxInputStream& stream, wxXmlDocument& doc)
|
bool wxXmlIOHandlerBin::Load(wxInputStream& stream, wxXmlDocument& doc,
|
||||||
|
const wxString& encoding)
|
||||||
{
|
{
|
||||||
ReadHeader(stream);
|
ReadHeader(stream);
|
||||||
wxDataInputStream ds(stream);
|
wxDataInputStream ds(stream);
|
||||||
@@ -151,7 +157,7 @@ bool wxXmlIOHandlerBin::Load(wxInputStream& stream, wxXmlDocument& doc)
|
|||||||
ds >> tmp;
|
ds >> tmp;
|
||||||
doc.SetVersion(tmp);
|
doc.SetVersion(tmp);
|
||||||
ds >> tmp;
|
ds >> tmp;
|
||||||
doc.SetEncoding(tmp);
|
doc.SetFileEncoding(tmp);
|
||||||
|
|
||||||
doc.SetRoot(LoadBinNode(ds, NULL));
|
doc.SetRoot(LoadBinNode(ds, NULL));
|
||||||
|
|
||||||
|
@@ -48,11 +48,12 @@ bool wxXmlIOHandlerBinZ::Save(wxOutputStream& stream, const wxXmlDocument& doc)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
bool wxXmlIOHandlerBinZ::Load(wxInputStream& stream, wxXmlDocument& doc)
|
bool wxXmlIOHandlerBinZ::Load(wxInputStream& stream, wxXmlDocument& doc,
|
||||||
|
const wxString& encoding)
|
||||||
{
|
{
|
||||||
ReadHeader(stream);
|
ReadHeader(stream);
|
||||||
wxZlibInputStream costr(stream);
|
wxZlibInputStream costr(stream);
|
||||||
return wxXmlIOHandlerBin::Load(costr, doc);
|
return wxXmlIOHandlerBin::Load(costr, doc, encoding);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -30,23 +30,32 @@
|
|||||||
/*
|
/*
|
||||||
|
|
||||||
FIXME:
|
FIXME:
|
||||||
|
|
||||||
- handle unknown encodings
|
|
||||||
- process all elements, including CDATA
|
- process all elements, including CDATA
|
||||||
- XRC resources should automatically select desired encoding based on
|
|
||||||
runtime environment (?) (would need BIN and BINZ formats modification,
|
|
||||||
too)
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
// converts Expat-produced string in UTF-8 into wxString.
|
// converts Expat-produced string in UTF-8 into wxString.
|
||||||
inline static wxString CharToString(const char *s, size_t len = wxSTRING_MAXLEN)
|
inline static wxString CharToString(wxMBConv *conv,
|
||||||
|
const char *s, size_t len = wxSTRING_MAXLEN)
|
||||||
{
|
{
|
||||||
#if wxUSE_UNICODE
|
#if wxUSE_UNICODE
|
||||||
|
(void)conv;
|
||||||
return wxString(s, wxConvUTF8, len);
|
return wxString(s, wxConvUTF8, len);
|
||||||
#else
|
#else
|
||||||
return wxString(s, len);
|
if ( conv )
|
||||||
|
{
|
||||||
|
size_t nLen = (len != wxSTRING_MAXLEN) ? len :
|
||||||
|
nLen = wxConvUTF8.MB2WC((wchar_t*) NULL, s, 0);
|
||||||
|
|
||||||
|
wchar_t *buf = new wchar_t[nLen+1];
|
||||||
|
wxConvUTF8.MB2WC(buf, s, nLen);
|
||||||
|
buf[nLen] = 0;
|
||||||
|
return wxString(buf, *conv, len);
|
||||||
|
delete[] buf;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return wxString(s, len);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -62,21 +71,23 @@ bool wxXmlIOHandlerExpat::CanLoad(wxInputStream& stream)
|
|||||||
|
|
||||||
struct wxXmlParsingContext
|
struct wxXmlParsingContext
|
||||||
{
|
{
|
||||||
|
wxMBConv *conv;
|
||||||
|
|
||||||
wxXmlNode *root;
|
wxXmlNode *root;
|
||||||
wxXmlNode *node;
|
wxXmlNode *node;
|
||||||
wxXmlNode *lastAsText;
|
wxXmlNode *lastAsText;
|
||||||
wxString encoding;
|
wxString encoding;
|
||||||
wxString version;
|
wxString version;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void StartElementHnd(void *userData, const char *name, const char **atts)
|
static void StartElementHnd(void *userData, const char *name, const char **atts)
|
||||||
{
|
{
|
||||||
wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
|
wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
|
||||||
wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, CharToString(name));
|
wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, CharToString(ctx->conv, name));
|
||||||
const char **a = atts;
|
const char **a = atts;
|
||||||
while (*a)
|
while (*a)
|
||||||
{
|
{
|
||||||
node->AddProperty(CharToString(a[0]), CharToString(a[1]));
|
node->AddProperty(CharToString(ctx->conv, a[0]), CharToString(ctx->conv, a[1]));
|
||||||
a += 2;
|
a += 2;
|
||||||
}
|
}
|
||||||
if (ctx->root == NULL)
|
if (ctx->root == NULL)
|
||||||
@@ -106,7 +117,7 @@ static void TextHnd(void *userData, const char *s, int len)
|
|||||||
if (ctx->lastAsText)
|
if (ctx->lastAsText)
|
||||||
{
|
{
|
||||||
ctx->lastAsText->SetContent(ctx->lastAsText->GetContent() +
|
ctx->lastAsText->SetContent(ctx->lastAsText->GetContent() +
|
||||||
CharToString(buf));
|
CharToString(ctx->conv, buf));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -120,7 +131,7 @@ static void TextHnd(void *userData, const char *s, int len)
|
|||||||
if (!whiteOnly)
|
if (!whiteOnly)
|
||||||
{
|
{
|
||||||
ctx->lastAsText = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"),
|
ctx->lastAsText = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"),
|
||||||
CharToString(buf));
|
CharToString(ctx->conv, buf));
|
||||||
ctx->node->AddChild(ctx->lastAsText);
|
ctx->node->AddChild(ctx->lastAsText);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -138,7 +149,7 @@ static void CommentHnd(void *userData, const char *data)
|
|||||||
// the root element (e.g. wxDesigner's output). We ignore such
|
// the root element (e.g. wxDesigner's output). We ignore such
|
||||||
// comments, no big deal...
|
// comments, no big deal...
|
||||||
ctx->node->AddChild(new wxXmlNode(wxXML_COMMENT_NODE,
|
ctx->node->AddChild(new wxXmlNode(wxXML_COMMENT_NODE,
|
||||||
wxT("comment"), CharToString(data)));
|
wxT("comment"), CharToString(ctx->conv, data)));
|
||||||
}
|
}
|
||||||
ctx->lastAsText = NULL;
|
ctx->lastAsText = NULL;
|
||||||
}
|
}
|
||||||
@@ -150,7 +161,7 @@ static void DefaultHnd(void *userData, const char *s, int len)
|
|||||||
{
|
{
|
||||||
wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
|
wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
|
||||||
|
|
||||||
wxString buf = CharToString(s, (size_t)len);
|
wxString buf = CharToString(ctx->conv, s, (size_t)len);
|
||||||
int pos;
|
int pos;
|
||||||
pos = buf.Find(wxT("encoding="));
|
pos = buf.Find(wxT("encoding="));
|
||||||
if (pos != wxNOT_FOUND)
|
if (pos != wxNOT_FOUND)
|
||||||
@@ -161,7 +172,36 @@ static void DefaultHnd(void *userData, const char *s, int len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wxXmlIOHandlerExpat::Load(wxInputStream& stream, wxXmlDocument& doc)
|
static int UnknownEncodingHnd(void * WXUNUSED(encodingHandlerData),
|
||||||
|
const XML_Char *name, XML_Encoding *info)
|
||||||
|
{
|
||||||
|
// We must build conversion table for expat. The easiest way to do so
|
||||||
|
// is to let wxCSConv convert as string containing all characters to
|
||||||
|
// wide character representation:
|
||||||
|
wxCSConv conv(name);
|
||||||
|
char mbBuf[255];
|
||||||
|
wchar_t wcBuf[255];
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < 255; i++)
|
||||||
|
mbBuf[i] = i+1;
|
||||||
|
mbBuf[255] = 0;
|
||||||
|
conv.MB2WC(wcBuf, mbBuf, 255);
|
||||||
|
wcBuf[255] = 0;
|
||||||
|
|
||||||
|
info->map[0] = 0;
|
||||||
|
for (i = 0; i < 255; i++)
|
||||||
|
info->map[i+1] = (int)wcBuf[i];
|
||||||
|
|
||||||
|
info->data = NULL;
|
||||||
|
info->convert = NULL;
|
||||||
|
info->release = NULL;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wxXmlIOHandlerExpat::Load(wxInputStream& stream, wxXmlDocument& doc,
|
||||||
|
const wxString& encoding)
|
||||||
{
|
{
|
||||||
const size_t BUFSIZE = 1024;
|
const size_t BUFSIZE = 1024;
|
||||||
char buf[BUFSIZE];
|
char buf[BUFSIZE];
|
||||||
@@ -170,11 +210,19 @@ bool wxXmlIOHandlerExpat::Load(wxInputStream& stream, wxXmlDocument& doc)
|
|||||||
XML_Parser parser = XML_ParserCreate(NULL);
|
XML_Parser parser = XML_ParserCreate(NULL);
|
||||||
|
|
||||||
ctx.root = ctx.node = NULL;
|
ctx.root = ctx.node = NULL;
|
||||||
|
ctx.encoding = wxT("UTF-8"); // default in absence of encoding=""
|
||||||
|
ctx.conv = NULL;
|
||||||
|
#if !wxUSE_UNICODE
|
||||||
|
if ( encoding != wxT("UTF-8") && encoding != wxT("utf-8") )
|
||||||
|
ctx.conv = new wxCSConv(encoding);
|
||||||
|
#endif
|
||||||
|
|
||||||
XML_SetUserData(parser, (void*)&ctx);
|
XML_SetUserData(parser, (void*)&ctx);
|
||||||
XML_SetElementHandler(parser, StartElementHnd, EndElementHnd);
|
XML_SetElementHandler(parser, StartElementHnd, EndElementHnd);
|
||||||
XML_SetCharacterDataHandler(parser, TextHnd);
|
XML_SetCharacterDataHandler(parser, TextHnd);
|
||||||
XML_SetCommentHandler(parser, CommentHnd);
|
XML_SetCommentHandler(parser, CommentHnd);
|
||||||
XML_SetDefaultHandler(parser, DefaultHnd);
|
XML_SetDefaultHandler(parser, DefaultHnd);
|
||||||
|
XML_SetUnknownEncodingHandler(parser, UnknownEncodingHnd, NULL);
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
@@ -190,9 +238,14 @@ bool wxXmlIOHandlerExpat::Load(wxInputStream& stream, wxXmlDocument& doc)
|
|||||||
} while (!done);
|
} while (!done);
|
||||||
|
|
||||||
doc.SetVersion(ctx.version);
|
doc.SetVersion(ctx.version);
|
||||||
doc.SetEncoding(ctx.encoding);
|
doc.SetFileEncoding(ctx.encoding);
|
||||||
doc.SetRoot(ctx.root);
|
doc.SetRoot(ctx.root);
|
||||||
|
|
||||||
XML_ParserFree(parser);
|
XML_ParserFree(parser);
|
||||||
|
#if !wxUSE_UNICODE
|
||||||
|
if ( ctx.conv )
|
||||||
|
delete ctx.conv;
|
||||||
|
#endif
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
@@ -100,9 +100,9 @@ bool wxXmlResource::Load(const wxString& filemask)
|
|||||||
{
|
{
|
||||||
#if wxUSE_FILESYSTEM
|
#if wxUSE_FILESYSTEM
|
||||||
if (filemask.Lower().Matches(wxT("*.zip")) ||
|
if (filemask.Lower().Matches(wxT("*.zip")) ||
|
||||||
filemask.Lower().Matches(wxT("*.rsc")))
|
filemask.Lower().Matches(wxT("*.xrs")))
|
||||||
{
|
{
|
||||||
rt = rt && Load(fnd + wxT("#zip:*.xmb"));
|
rt = rt && Load(fnd + wxT("#zip:*.xmlbin"));
|
||||||
rt = rt && Load(fnd + wxT("#zip:*.xrc"));
|
rt = rt && Load(fnd + wxT("#zip:*.xrc"));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -286,6 +286,17 @@ void wxXmlResource::UpdateResources()
|
|||||||
wxFileSystem fsys;
|
wxFileSystem fsys;
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
|
wxString encoding(wxT("UTF-8"));
|
||||||
|
#if !wxUSE_UNICODE && wxUSE_INTL
|
||||||
|
if ( (GetFlags() & wxXRC_USE_LOCALE) == 0 )
|
||||||
|
{
|
||||||
|
// In case we are not using wxLocale to translate strings, convert the strings
|
||||||
|
// GUI's charset. This must not be done when wxXRC_USE_LOCALE is on, because
|
||||||
|
// it could break wxGetTranslation lookup.
|
||||||
|
encoding = wxLocale::GetSystemEncodingName();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
for (size_t i = 0; i < m_data.GetCount(); i++)
|
for (size_t i = 0; i < m_data.GetCount(); i++)
|
||||||
{
|
{
|
||||||
modif = (m_data[i].Doc == NULL);
|
modif = (m_data[i].Doc == NULL);
|
||||||
@@ -305,7 +316,7 @@ void wxXmlResource::UpdateResources()
|
|||||||
|
|
||||||
if (modif)
|
if (modif)
|
||||||
{
|
{
|
||||||
wxInputStream *stream = NULL;
|
wxInputStream *stream = NULL;
|
||||||
|
|
||||||
# if wxUSE_FILESYSTEM
|
# if wxUSE_FILESYSTEM
|
||||||
file = fsys.OpenFile(m_data[i].File);
|
file = fsys.OpenFile(m_data[i].File);
|
||||||
@@ -320,9 +331,10 @@ void wxXmlResource::UpdateResources()
|
|||||||
delete m_data[i].Doc;
|
delete m_data[i].Doc;
|
||||||
m_data[i].Doc = new wxXmlDocument;
|
m_data[i].Doc = new wxXmlDocument;
|
||||||
}
|
}
|
||||||
if (!stream || !m_data[i].Doc->Load(*stream))
|
if (!stream || !m_data[i].Doc->Load(*stream, wxXML_IO_AUTO, encoding))
|
||||||
{
|
{
|
||||||
wxLogError(_("Cannot load resources from file '%s'."), m_data[i].File.c_str());
|
wxLogError(_("Cannot load resources from file '%s'."),
|
||||||
|
m_data[i].File.c_str());
|
||||||
wxDELETE(m_data[i].Doc);
|
wxDELETE(m_data[i].Doc);
|
||||||
}
|
}
|
||||||
else if (m_data[i].Doc->GetRoot()->GetName() != wxT("resource"))
|
else if (m_data[i].Doc->GetRoot()->GetName() != wxT("resource"))
|
||||||
|
@@ -44,22 +44,22 @@ static void OutputStringEnt(wxOutputStream& stream, const wxString& str)
|
|||||||
{
|
{
|
||||||
wxString buf;
|
wxString buf;
|
||||||
size_t i, last, len;
|
size_t i, last, len;
|
||||||
char c;
|
wxChar c;
|
||||||
|
|
||||||
len = str.Len();
|
len = str.Len();
|
||||||
last = 0;
|
last = 0;
|
||||||
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
c = str.GetChar(i);
|
c = str.GetChar(i);
|
||||||
if (c == '<' || c == '>' ||
|
if (c == wxT('<') || c == wxT('>') ||
|
||||||
(c == '&' && str.Mid(i+1, 4) != wxT("amp;")))
|
(c == wxT('&') && str.Mid(i+1, 4) != wxT("amp;")))
|
||||||
{
|
{
|
||||||
OutputString(stream, str.Mid(last, i - last));
|
OutputString(stream, str.Mid(last, i - last));
|
||||||
switch (c)
|
switch (c)
|
||||||
{
|
{
|
||||||
case '<': OutputString(stream, wxT("<")); break;
|
case wxT('<'): OutputString(stream, wxT("<")); break;
|
||||||
case '>': OutputString(stream, wxT(">")); break;
|
case wxT('>'): OutputString(stream, wxT(">")); break;
|
||||||
case '&': OutputString(stream, wxT("&")); break;
|
case wxT('&'): OutputString(stream, wxT("&")); break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
last = i + 1;
|
last = i + 1;
|
||||||
|
Reference in New Issue
Block a user