-wxXmlDocument::wxXmlDocument(const wxString& filename, wxXmlIOType io_type)
+wxXmlDocument::wxXmlDocument(const wxString& filename, wxXmlIOType io_type,
+ const wxString& encoding)
: wxObject(), m_root(NULL)
{
- if (!Load(filename, io_type))
+ if (!Load(filename, io_type, encoding))
{
wxDELETE(m_root);
}
-wxXmlDocument::wxXmlDocument(wxInputStream& stream, wxXmlIOType io_type)
+wxXmlDocument::wxXmlDocument(wxInputStream& stream, wxXmlIOType io_type,
+ const wxString& encoding)
: wxObject(), m_root(NULL)
{
- if (!Load(stream, io_type))
+ if (!Load(stream, io_type, encoding))
{
wxDELETE(m_root);
}
void wxXmlDocument::DoCopy(const wxXmlDocument& doc)
{
m_version = doc.m_version;
+#if !wxUSE_UNICODE
m_encoding = doc.m_encoding;
+#endif
+ m_fileEncoding = doc.m_fileEncoding;
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);
- 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();
while (n)
{
if ((io_type == wxXML_IO_AUTO || io_type == h->GetType()) &&
h->CanLoad(stream))
{
- return h->Load(stream, *this);
+ return h->Load(stream, *this, encoding);
}
n = n->GetNext();
}
{
WriteHeader(stream, "XMLBIN ");
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());
return stream.LastError() == wxSTREAM_NOERROR;
}
-bool wxXmlIOHandlerBin::Load(wxInputStream& stream, wxXmlDocument& doc)
+bool wxXmlIOHandlerBin::Load(wxInputStream& stream, wxXmlDocument& doc,
+ const wxString& encoding)
{
ReadHeader(stream);
wxDataInputStream ds(stream);
ds >> tmp;
doc.SetVersion(tmp);
ds >> tmp;
- doc.SetEncoding(tmp);
+ doc.SetFileEncoding(tmp);
doc.SetRoot(LoadBinNode(ds, NULL));
-bool wxXmlIOHandlerBinZ::Load(wxInputStream& stream, wxXmlDocument& doc)
+bool wxXmlIOHandlerBinZ::Load(wxInputStream& stream, wxXmlDocument& doc,
+ const wxString& encoding)
{
ReadHeader(stream);
wxZlibInputStream costr(stream);
- return wxXmlIOHandlerBin::Load(costr, doc);
+ return wxXmlIOHandlerBin::Load(costr, doc, encoding);
}
/*
FIXME:
-
- - handle unknown encodings
- 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.
-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
+ (void)conv;
return wxString(s, wxConvUTF8, len);
#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
}
struct wxXmlParsingContext
{
+ wxMBConv *conv;
+
wxXmlNode *root;
wxXmlNode *node;
wxXmlNode *lastAsText;
- wxString encoding;
- wxString version;
+ wxString encoding;
+ wxString version;
};
static void StartElementHnd(void *userData, const char *name, const char **atts)
{
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;
while (*a)
{
- node->AddProperty(CharToString(a[0]), CharToString(a[1]));
+ node->AddProperty(CharToString(ctx->conv, a[0]), CharToString(ctx->conv, a[1]));
a += 2;
}
if (ctx->root == NULL)
if (ctx->lastAsText)
{
ctx->lastAsText->SetContent(ctx->lastAsText->GetContent() +
- CharToString(buf));
+ CharToString(ctx->conv, buf));
}
else
{
if (!whiteOnly)
{
ctx->lastAsText = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"),
- CharToString(buf));
+ CharToString(ctx->conv, buf));
ctx->node->AddChild(ctx->lastAsText);
}
}
// the root element (e.g. wxDesigner's output). We ignore such
// comments, no big deal...
ctx->node->AddChild(new wxXmlNode(wxXML_COMMENT_NODE,
- wxT("comment"), CharToString(data)));
+ wxT("comment"), CharToString(ctx->conv, data)));
}
ctx->lastAsText = NULL;
}
{
wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
- wxString buf = CharToString(s, (size_t)len);
+ wxString buf = CharToString(ctx->conv, s, (size_t)len);
int pos;
pos = buf.Find(wxT("encoding="));
if (pos != wxNOT_FOUND)
}
}
-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;
char buf[BUFSIZE];
XML_Parser parser = XML_ParserCreate(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_SetElementHandler(parser, StartElementHnd, EndElementHnd);
XML_SetCharacterDataHandler(parser, TextHnd);
XML_SetCommentHandler(parser, CommentHnd);
XML_SetDefaultHandler(parser, DefaultHnd);
+ XML_SetUnknownEncodingHandler(parser, UnknownEncodingHnd, NULL);
do
{
} while (!done);
doc.SetVersion(ctx.version);
- doc.SetEncoding(ctx.encoding);
+ doc.SetFileEncoding(ctx.encoding);
doc.SetRoot(ctx.root);
XML_ParserFree(parser);
+#if !wxUSE_UNICODE
+ if ( ctx.conv )
+ delete ctx.conv;
+#endif
+
return TRUE;
}
{
#if wxUSE_FILESYSTEM
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"));
}
else
wxFileSystem fsys;
# 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++)
{
modif = (m_data[i].Doc == NULL);
if (modif)
{
- wxInputStream *stream = NULL;
+ wxInputStream *stream = NULL;
# if wxUSE_FILESYSTEM
file = fsys.OpenFile(m_data[i].File);
delete m_data[i].Doc;
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);
}
else if (m_data[i].Doc->GetRoot()->GetName() != wxT("resource"))
{
wxString buf;
size_t i, last, len;
- char c;
+ wxChar c;
len = str.Len();
last = 0;
for (i = 0; i < len; i++)
{
c = str.GetChar(i);
- if (c == '<' || c == '>' ||
- (c == '&' && str.Mid(i+1, 4) != wxT("amp;")))
+ if (c == wxT('<') || c == wxT('>') ||
+ (c == wxT('&') && str.Mid(i+1, 4) != wxT("amp;")))
{
OutputString(stream, str.Mid(last, i - last));
switch (c)
{
- case '<': OutputString(stream, wxT("<")); break;
- case '>': OutputString(stream, wxT(">")); break;
- case '&': OutputString(stream, wxT("&")); break;
+ case wxT('<'): OutputString(stream, wxT("<")); break;
+ case wxT('>'): OutputString(stream, wxT(">")); break;
+ case wxT('&'): OutputString(stream, wxT("&")); break;
default: break;
}
last = i + 1;
-wxXmlDocument::wxXmlDocument(const wxString& filename, wxXmlIOType io_type)
+wxXmlDocument::wxXmlDocument(const wxString& filename, wxXmlIOType io_type,
+ const wxString& encoding)
: wxObject(), m_root(NULL)
{
- if (!Load(filename, io_type))
+ if (!Load(filename, io_type, encoding))
{
wxDELETE(m_root);
}
-wxXmlDocument::wxXmlDocument(wxInputStream& stream, wxXmlIOType io_type)
+wxXmlDocument::wxXmlDocument(wxInputStream& stream, wxXmlIOType io_type,
+ const wxString& encoding)
: wxObject(), m_root(NULL)
{
- if (!Load(stream, io_type))
+ if (!Load(stream, io_type, encoding))
{
wxDELETE(m_root);
}
void wxXmlDocument::DoCopy(const wxXmlDocument& doc)
{
m_version = doc.m_version;
+#if !wxUSE_UNICODE
m_encoding = doc.m_encoding;
+#endif
+ m_fileEncoding = doc.m_fileEncoding;
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);
- 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();
while (n)
{
if ((io_type == wxXML_IO_AUTO || io_type == h->GetType()) &&
h->CanLoad(stream))
{
- return h->Load(stream, *this);
+ return h->Load(stream, *this, encoding);
}
n = n->GetNext();
}
{
WriteHeader(stream, "XMLBIN ");
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());
return stream.LastError() == wxSTREAM_NOERROR;
}
-bool wxXmlIOHandlerBin::Load(wxInputStream& stream, wxXmlDocument& doc)
+bool wxXmlIOHandlerBin::Load(wxInputStream& stream, wxXmlDocument& doc,
+ const wxString& encoding)
{
ReadHeader(stream);
wxDataInputStream ds(stream);
ds >> tmp;
doc.SetVersion(tmp);
ds >> tmp;
- doc.SetEncoding(tmp);
+ doc.SetFileEncoding(tmp);
doc.SetRoot(LoadBinNode(ds, NULL));
-bool wxXmlIOHandlerBinZ::Load(wxInputStream& stream, wxXmlDocument& doc)
+bool wxXmlIOHandlerBinZ::Load(wxInputStream& stream, wxXmlDocument& doc,
+ const wxString& encoding)
{
ReadHeader(stream);
wxZlibInputStream costr(stream);
- return wxXmlIOHandlerBin::Load(costr, doc);
+ return wxXmlIOHandlerBin::Load(costr, doc, encoding);
}
/*
FIXME:
-
- - handle unknown encodings
- 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.
-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
+ (void)conv;
return wxString(s, wxConvUTF8, len);
#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
}
struct wxXmlParsingContext
{
+ wxMBConv *conv;
+
wxXmlNode *root;
wxXmlNode *node;
wxXmlNode *lastAsText;
- wxString encoding;
- wxString version;
+ wxString encoding;
+ wxString version;
};
static void StartElementHnd(void *userData, const char *name, const char **atts)
{
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;
while (*a)
{
- node->AddProperty(CharToString(a[0]), CharToString(a[1]));
+ node->AddProperty(CharToString(ctx->conv, a[0]), CharToString(ctx->conv, a[1]));
a += 2;
}
if (ctx->root == NULL)
if (ctx->lastAsText)
{
ctx->lastAsText->SetContent(ctx->lastAsText->GetContent() +
- CharToString(buf));
+ CharToString(ctx->conv, buf));
}
else
{
if (!whiteOnly)
{
ctx->lastAsText = new wxXmlNode(wxXML_TEXT_NODE, wxT("text"),
- CharToString(buf));
+ CharToString(ctx->conv, buf));
ctx->node->AddChild(ctx->lastAsText);
}
}
// the root element (e.g. wxDesigner's output). We ignore such
// comments, no big deal...
ctx->node->AddChild(new wxXmlNode(wxXML_COMMENT_NODE,
- wxT("comment"), CharToString(data)));
+ wxT("comment"), CharToString(ctx->conv, data)));
}
ctx->lastAsText = NULL;
}
{
wxXmlParsingContext *ctx = (wxXmlParsingContext*)userData;
- wxString buf = CharToString(s, (size_t)len);
+ wxString buf = CharToString(ctx->conv, s, (size_t)len);
int pos;
pos = buf.Find(wxT("encoding="));
if (pos != wxNOT_FOUND)
}
}
-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;
char buf[BUFSIZE];
XML_Parser parser = XML_ParserCreate(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_SetElementHandler(parser, StartElementHnd, EndElementHnd);
XML_SetCharacterDataHandler(parser, TextHnd);
XML_SetCommentHandler(parser, CommentHnd);
XML_SetDefaultHandler(parser, DefaultHnd);
+ XML_SetUnknownEncodingHandler(parser, UnknownEncodingHnd, NULL);
do
{
} while (!done);
doc.SetVersion(ctx.version);
- doc.SetEncoding(ctx.encoding);
+ doc.SetFileEncoding(ctx.encoding);
doc.SetRoot(ctx.root);
XML_ParserFree(parser);
+#if !wxUSE_UNICODE
+ if ( ctx.conv )
+ delete ctx.conv;
+#endif
+
return TRUE;
}
{
#if wxUSE_FILESYSTEM
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"));
}
else
wxFileSystem fsys;
# 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++)
{
modif = (m_data[i].Doc == NULL);
if (modif)
{
- wxInputStream *stream = NULL;
+ wxInputStream *stream = NULL;
# if wxUSE_FILESYSTEM
file = fsys.OpenFile(m_data[i].File);
delete m_data[i].Doc;
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);
}
else if (m_data[i].Doc->GetRoot()->GetName() != wxT("resource"))
{
wxString buf;
size_t i, last, len;
- char c;
+ wxChar c;
len = str.Len();
last = 0;
for (i = 0; i < len; i++)
{
c = str.GetChar(i);
- if (c == '<' || c == '>' ||
- (c == '&' && str.Mid(i+1, 4) != wxT("amp;")))
+ if (c == wxT('<') || c == wxT('>') ||
+ (c == wxT('&') && str.Mid(i+1, 4) != wxT("amp;")))
{
OutputString(stream, str.Mid(last, i - last));
switch (c)
{
- case '<': OutputString(stream, wxT("<")); break;
- case '>': OutputString(stream, wxT(">")); break;
- case '&': OutputString(stream, wxT("&")); break;
+ case wxT('<'): OutputString(stream, wxT("<")); break;
+ case wxT('>'): OutputString(stream, wxT(">")); break;
+ case wxT('&'): OutputString(stream, wxT("&")); break;
default: break;
}
last = i + 1;