UTF-8 and TinyXML - c++

For some reason I can not read data from a xml file properly.
For example instead of "Schrüder" I get something like "Schrüder".
My code:
tinyxml2::XMLDocument doc;
bool open(string path) {
if(doc.LoadFile(path.c_str()) == XML_SUCCESS)
return true;
return false;
}
int main() {
if(open("C:\\Users\\Admin\\Desktop\\Test.xml"))
cout << "Success" << endl;
XMLNode * node = doc.RootElement();
string test = node->FirstChild()->GetText();
cout << test << endl;
return 0;
}
Part of XML:
<?xml version="1.0" encoding="UTF-8"?>
<myXML>
<my:TXT_UTF8Test>Schrüder</my:TXT_UTF8Test>
</myXML>
Notice that if I convert it to ANSI and change the encoding type to "ISO-8859-15" it works fine.
I read that something like "LoadFile( filename, TIXML_ENCODING_UTF8 )" should help. However that's not the case (error: Invalid arguments, it just expects a const char). I have the latest version of TinyXML2 (I guess?). I downloaded it just a couple minutes ago from https://github.com/leethomason/tinyxml2.
Any ideas?
Edit: When I write the string to a .xml or .txt file it works fine. There might be some problem with the eclipse ide console. Anyway, when I try to send the string via E-Mail, I also get the same problems. Here's the MailSend script:
bool sendMail(std::string params) {
if( (int) ShellExecute(NULL, "open", "H:\\MailSend\\MailSend_anhang.exe", params.c_str(), NULL, SW_HIDE) <= 32 )
return false;
return true;
}
I call it in the main method like this:
sendMail("-f:d.nitschmann#example.com -t:person2#example.com -s:Subject -b:Body " + test);

I think the problem is with your terminal; can you try run your test code in a different terminal ? one with known good UTF-8 support ?
Output with terminal in UTF-8 mode:
$ ./a.out
Success
Schrüder
Output with terminal in ISO-8859-15 mode:
$ ./a.out
Success
SchrÃŒder
Also - please try and follow http://sscce.org/ - for posterity sake here is your code with everything needed to compile (17676169.cpp):
#include <tinyxml2.h>
#include <string>
#include <iostream>
using namespace std;
using namespace tinyxml2;
tinyxml2::XMLDocument doc;
bool open(string path) {
if(doc.LoadFile(path.c_str()) == XML_SUCCESS)
return true;
return false;
}
int main() {
if(open("Test.xml"))
cout << "Success" << endl;
XMLNode * node = doc.RootElement();
string test = node->FirstChildElement()->GetText();
cout << test << endl;
return 0;
}
compiled with:
g++ -o 17676169 17676169.cpp -ltinyxml2
and uuencoded Test.xml - to ensure exact same data is used
begin 660 Test.xml
M/#]X;6P#=F5R<VEO;CTB,2XP(B!E;F-O9&EN9STB551&+3#B/SX*/&UY6$U,
M/#H#("`#/&UY.E185%]55$8X5&5S=#Y38VARP[QD97(\+VUY.E185%]55$8X
/5&5S=#X*/"]M>5A-3#X*
`
end
Edit 1:
If you want to confirm this theory - run this in eclipse:
#include <iostream>
#include <string>
#include <fstream>
int main()
{
std::ifstream ifs("Test.xml");
std::string xml_data((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
std::cout << xml_data;
}
Output with terminal in UTF-8 mode:
$ ./17676169.cat
<?xml version="1.0" encoding="UTF-8"?>
<myXML>
<my:TXT_UTF8Test>Schrüder</my:TXT_UTF8Test>
</myXML>
Output with terminal in ISO-8859-15 mode:
$ ./17676169.cat
<?xml version="1.0" encoding="UTF-8"?>
<myXML>
<my:TXT_UTF8Test>SchrÃŒder</my:TXT_UTF8Test>
</myXML>

Related

QDomElement::namespaceURI returns empty string

I'm trying to get to the root of a problem in some library, and it seems like I don't understand how QDomElement::namespaceURI work, or don't understand how xmlns works.
Here is my minimal isolated code fragment:
#include <iostream>
#include <QString>
#include <QDomDocument>
int main() {
QString request = "<iq from='user2#example.org' id='disco1' to='user1#example.org' type='get'>";
request += "<query node='someAddress' xmlns='http://jabber.org/protocol/disco#info'/>";
request += "</iq>";
QDomDocument doc;
doc.setContent(request);
QDomElement iq = doc.documentElement();
QDomElement query = iq.firstChildElement();
std::cout << query.tagName().toStdString() << " " << query.namespaceURI().toStdString() << std::endl;
return 0;
}
I compile it this way
g++ -o xmlTest xmlTest.cpp -lQt5Core -lQt5Xml -I /usr/include/qt -I /usr/include/qt/QtCore -I /usr/include/qt/QtXml
I expect it to print query http://jabber.org/protocol/disco#info
Instead it prints query and I do not understand why.
What am I doing wrong?
By default QtXml does not do namespace processing. There is an optional bool namespaceProcessing flag you can pass to setContent() to enable it.
Modifying that line like so, produces the expected behaviour:
doc.setContent(request, true);
$ ./xmlTest
query http://jabber.org/protocol/disco#info

Qt utf-16 output shows question marks in Windows cmd and powershell -- with minimum reproducible example in C++

Previously, I have asked Qt translations in C++ project are rendered as question marks in cmd and powershell question. The point of the question was that the help message of .\app -h, translated to Cyrillic, is rendered as ?????????.
Since then, I discovered that in https://github.com/RSATom/Qt/blob/master/qtbase/src/corelib/tools/qcommandlineparser.cpp, the Qt messages are printed with qInfo("%ls", qUtf16Printable(message)) on Windows.
In cmd.exe or poweshell.exe I get question marks ?????????, when trying to output a Cyrillic message this way.
I tried to change the font of cmd.exe and powershell.exe to Lucida Console and to execute chcp 10000 (as proposed here UTF-16 on cmd.exe), but this does not help.
Here is the minimum reproducible example:
// > cl main.cpp /I C:\Qt\5.12.12\msvc2017_64\include
// > link main.obj /LIBPATH C:\Qt\5.12.12\msvc2017_64\lib\Qt5Core.lib
#include "QtCore/QtGlobal"
#include "QtCore/QString"
int main()
{
qInfo("%ls", qUtf16Printable("Привет"));
return 0;
}
// > main.exe
// ??????
I would really appreciate any help. There are two problems here. The first: how can I use QCommandLineParser under Windows. The second: if QCommandLineParser (using qInfo("%ls", qUtf16Printable(message))) is okay and not a bug, then how can I make cmd show it all right.
I don't pretend on the answer, but on Windows for Unicode console output you should do something similar to:
#include <QDebug>
#include <iostream>
#include <string>
#include <fcntl.h>
#include <io.h>
#include <stdio.h>
void myMessageOutput( QtMsgType type, const QMessageLogContext & context, const QString & msg )
{
Q_UNUSED( context );
std::wcout << msg.toStdWString() << std::endl;
if( type == QtFatalMsg )
abort();
}
int main()
{
_setmode( _fileno( stdout ), _O_U16TEXT );
qInstallMessageHandler( myMessageOutput );
const std::wstring rs = L"Привет";
const auto s = QString::fromStdWString( rs );
std::wcout << s.toStdWString() << std::endl;
qDebug() << s;
qInfo() << s;
return 0;
}
Accidentally I found the solution. You should create following manifest file for your executable:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<application>
<windowsSettings>
<activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage>
</windowsSettings>
</application>
</assembly>
Let it will be named as app.manifest. In CMake project just add app.manifest into sources of your executable.
In the main() function add two lines of code:
#include <Windows.h>
int main( int argc, char ** argv )
{
SetConsoleCP( GetACP() );
SetConsoleOutputCP( GetACP() );
}
And voila...
Printing should be done using UTF-8, so:
// 1 - works.
QTextStream s( stdout );
s << QString( "Вот оно!!!\n" ) << Qt::flush;
// 2 - works.
fputs( qPrintable( QString( "Опа-на...\n" ) ), stdout );
// 3 - works.
std::cout << u8"std::cout работает!!!\n";
// 4 - DOES NOT work.
std::wcout << L"wcout НЕ работает!!!\n";

Program with SPI_SETDESKWALLPAPER Function Only Changes the Desktop Background to the Color Black when Trying to Change it to an Image using C++

I am trying to change the desktop background/wallpaper to a different image with a .png file. Although when I run the program, the background turns to solid black instead.
I am certain that I typed the file name, "ksa.png", correctly in my code to be the image I want to be on my background. I used an if condition to write out the last error on a file when the error occurred and used an else condition to write out "Success" if no errors occurred; but when I run the program, it writes "Success" to the file. I have thought about using a .jpg file instead, thinking that maybe .png files just don't work. I'll give an update when I tried using that.
#include <windows.h>
#include <fstream>
int main () {
const wchar_t *filenm = L"ksa.png";
std::ofstream log;
if (SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (void*)filenm, SPIF_UPDATEINIFILE) == FALSE) {
log.open("log.txt");
log << "Error: " << GetLastError();
log.close();
}
else {
log.open("log.txt");
log << "Success";
log.close();
}
return 0;
}
When I run this program, the desktop background is suppose to be set as the image "ksa.png". Instead it's solid black. Any help is appreciated for making this work, thank you.
UPDATE
Okay so I updated the code to where it would run a .jpg file and I'm still getting the same result. Also I moved the line log.open("log.txt") command before the SystemParametersInfo() function like Remy Lebeau suggested and it still writes out "Success" to the file. I'm still having the same problem.
Here is my updated code:
#include <windows.h>
#include <fstream>
int main () {
const wchar_t *filenm = L"3.jpg";
std::ofstream log;
log.open("log.txt");
if (SystemParametersInfo(SPI_SETDESKWALLPAPER, 0, (void*)filenm, SPIF_UPDATEINIFILE) == FALSE) {
log << "Error: " << GetLastError();
log.close();
}
else {
log.open("log.txt");
log << "Success";
log.close();
}
return 0;
}
Emmmm,there is a problem with your picture path. I've tried your code. You can't get pictures under relative paths unless you use absolute paths.
Like Cody Gray♦'s judgment .
const wchar_t *filenm = L"C:\\Users\\strives\\Desktop\\timg.bmp";

Why does gSOAP set stdin mode to binary if reads data from a file stream?

I've been playing with gSOAP XML data binding by loading XML document into C++ class, modifying data and serializing it back into XML.
Here's the snippet of the XML - library.xml:
<?xml version="1.0" encoding="UTF-8"?>
<gt:Library xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:gt="http://www.bk.com/gSOAP/test">
<gt:Books>
<gt:Book isbn="0132350882" author="Robert C. Martin" title="Clean Code">
<gt:CopiesAvailable>2</gt:CopiesAvailable>
</gt:Book>
<gt:Book isbn="020161622X" author="Andrew Hunt" title="The Pragmatic Programmer">
<gt:CopiesAvailable>0</gt:CopiesAvailable>
</gt:Book>
<gt:Book isbn="0201633612" author="Erich Gamma" title="Design patterns">
<gt:CopiesAvailable>1</gt:CopiesAvailable>
</gt:Book>
</gt:Books>
...
</gt:Library>
The following code loads XML into object, modifies object and serializes it back into XML.
Note that XML is loaded from a file, via file stream and that data to be added is obtained from a user, via stdin (cin).
main.cpp:
#include "soapH.h"
#include "gt.nsmap"
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
using std::cin;
using std::cout;
using std::endl;
using std::ifstream;
using std::ofstream;
using std::fstream;
using std::string;
using std::stringstream;
void DisplayAllBooks(const _gt__Library& library)
{
cout << "\n\nDisplaying all books in the library:" << endl;
std::vector<_gt__Library_Books_Book>::const_iterator it = library.Books.Book.begin();
for(;it != library.Books.Book.end(); it++)
{
cout << "\nBook:\n" << "\tTitle:" << (*it).title << "\n\tAuthor:" << (*it).author <<"\n\tISBN: " << (*it).isbn << "\n\tCopies available: " << static_cast<int>((*it).CopiesAvailable) << endl;
}
}
void AddBook(_gt__Library& library)
{
cout << "\n\nAdding a new book:" << endl;
_gt__Library_Books_Book book;
cout << "\tTitle: " << std::flush;
getline(cin, book.title);
cout << "\tAuthor: " << std::flush;
getline(cin, book.author);
cout << "\tISBN:" << std::flush;
getline(cin, book.isbn);
cout << "\tCopies available: " << std::flush;
string strCopiesAvailable;
getline(cin, strCopiesAvailable);
stringstream ss(strCopiesAvailable);
ss >> book.CopiesAvailable;
library.Books.Book.push_back(book);
}
// Terminate and destroy soap
void DestroySoap(struct soap* pSoap)
{
// remove deserialized class instances (C++ objects)
soap_destroy(pSoap);
// clean up and remove deserialized data
soap_end(pSoap);
// detach context (last use and no longer in scope)
soap_done(pSoap);
}
int main()
{
//
// Create and intialize soap
//
// gSOAP runtime context
struct soap soap;
// initialize runtime context
soap_init(&soap);
// Set input mode
soap_imode(&soap, SOAP_ENC_XML);
// reset deserializers; start new (de)serialization phase
soap_begin(&soap);
//
// Load XML (Deserialize)
//
_gt__Library library;
string strXML = "library.xml";
ifstream fstreamIN(strXML);
soap.is = &fstreamIN;
// calls soap_begin_recv, soap_get__gt__Library and soap_end_recv
if(soap_read__gt__Library(&soap, &library) != SOAP_OK)
{
std::cout << "soap_read__gt__Library() failed" << std::endl;
DestroySoap(&soap);
return 1;
}
fstreamIN.close();
//
// Display books before and after adding a new book
//
DisplayAllBooks(library);
AddBook(library);
DisplayAllBooks(library);
//
// Serialize
//
soap_set_omode(&soap, SOAP_XML_INDENT);
ofstream fstreamOUT("library.xml");
soap.os = &fstreamOUT;
// calls soap_begin_send, soap_serialize, soap_put and soap_end_send
if(soap_write__gt__Library(&soap, &library) != SOAP_OK)
{
std::cout << "soap_write__gt__Library() failed" << std::endl;
DestroySoap(&soap);
return 1;
}
fstreamOUT.close();
DestroySoap(&soap);
return 0;
}
After running this test application, everything is fine apart from all newly added elements have strings that terminate with a Carriage Return character (CR - 
):
Modified XML looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<gt:Library xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENC="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:gt="http://www.bk.com/gSOAP/test">
<gt:Books>
<gt:Book isbn="0132350882" author="Robert C. Martin" title="Clean Code">
<gt:CopiesAvailable>2</gt:CopiesAvailable>
</gt:Book>
<gt:Book isbn="020161622X" author="Andrew Hunt" title="The Pragmatic Programmer">
<gt:CopiesAvailable>0</gt:CopiesAvailable>
</gt:Book>
<gt:Book isbn="0201633612" author="Erich Gamma" title="Design patterns">
<gt:CopiesAvailable>1</gt:CopiesAvailable>
</gt:Book>
<gt:Book isbn="12345678
" author="Scott Meyers
" title="Effective C++
">
<gt:CopiesAvailable>123</gt:CopiesAvailable>
</gt:Book>
</gt:Books>
...
</gt:Library>
I traced the source of the bug and found the following:
soap_read__gt__Library() calls soap_begin_send() which executes the following line:
_setmode(soap->recvfd, _O_BINARY);
soap->recvfd is set to 0 in soap_init() and 0 is a value of file descriptor of stdin.
Once stdin's mode is changed to a binary, STL library does not parse \r\n to a single \n for read operations and getline(cin, str), as usual, reads everything up to \n, copying \r into output string. And that is exactly Carriage Return character which appears in new strings in the final XML.
My question is: Why does gSOAP modify stdin mode if the data source is a file stream? Is this a bug in gSOAP?
NOTE:
As expected, if stdio's mode is reverted back to _O_TEXT after soap_begin_send() but before reading data from std::cin, getline() works fine. Here is the patch:
_setmode(_fileno(stdin), _O_TEXT)
This is to avoid encoding problems when reading and writing Unicode and UTF-8 encoded XML.
Also this cause unwanted side effects! By using
_setmode(soap->recvfd, _O_BINARY); // found in stdsoap2.cpp
you always assume to read from a file or stdin, however if you set soap->is to a std::istringstream this isn't true.
Just assume you are using getchar() in your main routine, but on a thread you try to deserialize a xml from a std:istringstream (using gsoap xml binding). As result your program will hang. the only way around is to set soap->recvfd = -1;
Regards Ralph

Requesting complete, compilable libxml2 sax example

I'm having a heck of a time figuring out how to use the sax parser for libxml2. Can someone post an example that parses this XML ( yes, without the <xml...> header and footer tags, if that can be parsed by the libxml2 sax parser):
<hello foo="bar">world</hello>
The parser should print out the data enclosed in element hello and also grab the value of attribute foo.
I'm working on this example, but hoping that someone else beats me to the punch since I'm not making much progress. The Google hasn't yielded any complete, working examples for libxml2 sax parser.
Adapted from http://julp.developpez.com/c/libxml2/?page=sax
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/parserInternals.h>
void start_element_callback(void *user_data, const xmlChar *name, const xmlChar **attrs) {
printf("Beginning of element : %s \n", name);
while (NULL != attrs && NULL != attrs[0]) {
printf("attribute: %s=%s\n",attrs[0],attrs[1]);
attrs = &attrs[2];
}
}
int main() {
const char* xml_path = "hello_world.xml";
FILE *xml_fh = fopen(xml_path,"w+");
fputs("<hello foo=\"bar\" baz=\"baa\">world</hello>",xml_fh);
fclose(xml_fh);
// Initialize all fields to zero
xmlSAXHandler sh = { 0 };
// register callback
sh.startElement = start_element_callback;
xmlParserCtxtPtr ctxt;
// create the context
if ((ctxt = xmlCreateFileParserCtxt(xml_path)) == NULL) {
fprintf(stderr, "Erreur lors de la création du contexte\n");
return EXIT_FAILURE;
}
// register sax handler with the context
ctxt->sax = &sh;
// parse the doc
xmlParseDocument(ctxt);
// well-formed document?
if (ctxt->wellFormed) {
printf("XML Document is well formed\n");
} else {
fprintf(stderr, "XML Document isn't well formed\n");
//xmlFreeParserCtxt(ctxt);
return EXIT_FAILURE;
}
// free the memory
// xmlFreeParserCtxt(ctxt);
return EXIT_SUCCESS;
}
This produces output:
Beginning of element : hello
attribute: foo=bar
attribute: baz=baa
XML Document is well formed
Compiled with the following command on Ubuntu 10.04.1:
g++ -I/usr/include/libxml2 libxml2_hello_world.cpp /usr/lib/libxml2.a -lz\
-o libxml2_hello_world
Can I suggest rapidxml?