Load and display QString with proper encoding - c++

I am trying to load a name from file that has several special characters and if it is in file (looks like meno: Marek Ružička/) display it. Code here:
QFile File("info/"+meno+".txt");
File.open(QIODevice::ReadOnly);
QVariant Data(File.readAll());
QString in = Data.toString(), pom;
if(in.contains("meno:")){
pom = in.split("meno:").at(1);
pom=pom.split("/").at(0);
ui->label_meno->setText(trUtf8("Celé meno: ")+pom);}
the part trUtf8("Celé meno: ") displays well but I cant find how to display string in pom, it alone looks like Marek RužiÄka, using toUtf8() function makes it Marek RuþiÃÂka, I've tried to convert it to stdString too but doesn't work either. I am not sure if the conversion from QFile to QVariant and to QString is right, if this causes problem how to read data properly?

Try this:
QTextCodec* utf = QTextCodec::codecForName("UTF-8");
QByteArray data = <<INPUT QBYTEARRAY>>.toUtf8();
QString utfString = utf->toUnicode(data);
qDebug() << utfString;

One of the right ways is to use QTextStream for the reading, and then you can specify the codec for utf 8 as follow:
in.setCodec("UTF-8");
See the documentation for further details:
void QTextStream::setCodec(const char * codecName)
Sets the codec for this stream to the QTextCodec for the encoding specified by codecName. Common values for codecName include "ISO 8859-1", "UTF-8", and "UTF-16". If the encoding isn't recognized, nothing happens.
Example:
QTextStream out(&file);
out.setCodec("UTF-8");
Another right way would be to fix your current code without using QTextStream by using the dedicated QString method as follows:
QString in = QString::fromUtf8(File.readAll()), pom;
Please note that though you may wish to add more error handling into your code than available now.

Related

Convert QByteArray to QString

I want to encrypt the data of a database and to do this, I used AES_128 in this link for encryption.
The result of encryption is a QByteArray and the QByteArray is saved on the text file in the correct shape and I could decode it correctly, but and I need to convert it to the QString and reverse to QByteArray to store and read it on the Sqlite DB. I tried some options like
QByteArray encodedText; QString DataAsString = QString(encodedText);
and
string DataAsString1 = encodedText.toStdString();
and
QString DataAsString = QTextCodec::codecForName("UTF-8") >toUnicode(encodedText);
and other solutions like this link, but the outputs of these options aren't in the correct way. Because after casting, I couldn't convert the encoded text to decoded correctly.
This is the input string of encoded text:
"\x14r\xF7""6#\xFE\xDB\xF0""D\x1B\xB5\x10\xEDx\xE1""F"
and these are the outputs for the different options:
\024r�6#���D\033�\020�x�F
and
\024r�6#���D\033�\020�x�F
Does anybody suggestion about the right conversion?
try to use this:
QString QString::fromUtf8(const QByteArray &str)

How to solve the error FODC0002 when using QXmlFormatter?

I'm trying to use QXmlQuery to get some elements from a XML file. Everything works fine (I'm able to validate the source XML file and etc) until I get to the part in which I try to use QXmlFormatter, in order to write the results to another XML file. When I get to this part, the following error is shown: Error FODC0002 in tag:trolltech.com,2007:QtXmlPatterns:QIODeviceVariable:inputDocument, at line 1, column 0: Premature end of document.
The code is based on the "Recipes" project available as an example in Qt. The only difference here is that I made a simpler version of the "cookbook" XML file. I've tried to use QBuffer(the approach implemented in the example) instead of a file, but as expected, got the same result.
Here is the source XML, called temp2_xml.xml
<?xml version="1.0" encoding="UTF-8"?>
<cookbook>
<recipe>
<title>Quick and Easy Mushroom Soup</title>
<title>Cheese on Toast</title>
</recipe>
</cookbook>
Here is the Xquery file, called allRecipes.xq:
(: Select all recipes. :)
declare variable $inputDocument external;
doc($inputDocument)/cookbook/recipe/<p>{string(title)}</p>
And here's the code:
QFile aqr_xq("C:/test_xml/allRecipes.xq");
aqr_xq.open(QIODevice::ReadOnly);
QFile file("C:/test_xml/temp_xml.xml");
file.open(QIODevice::ReadWrite);
QFile aqr_r;
aqr_r.setFileName("C:/test_xml/temp2_xml.xml");
aqr_r.open(QIODevice::ReadOnly);
QTextStream in(&aqr_r);
QString inputDocument = in.readAll();
const QString str_query(QString::fromLatin1(aqr_xq.readAll()));
QXmlQuery query;
query.bindVariable("inputDocument",&aqr_r);
query.setQuery(str_query);
bool debug_xml = false;
debug_xml = query.isValid();
QXmlFormatter ser(query, &file);
query.evaluateTo(&ser);
Any ideas about what's causing the problem and how to solve it?
I think the problem is indeed the use of the text stream to consume the opened file, if I don't use that and simply use the code
QFile aqr_xq(queryFile);
aqr_xq.open(QIODevice::ReadOnly);
QFile file(outputFile);
file.open(QIODevice::ReadWrite);
QFile aqr_r;
aqr_r.setFileName(inputFile);
aqr_r.open(QIODevice::ReadOnly);
const QString str_query(QString::fromLatin1(aqr_xq.readAll()));
QXmlQuery query;
query.bindVariable("inputDocument",&aqr_r);
query.setQuery(str_query);
bool debug_xml = false;
debug_xml = query.isValid();
QXmlFormatter ser(query, &file);
query.evaluateTo(&ser);
then indeed the error is in the XQuery and is raised as
Error XPTY0004: Required cardinality is zero or one("?"); got cardinality one or more("+").
You haven't said which output you want to create but if you I change the XQuery to e.g.
declare variable $inputDocument external;
doc($inputDocument)/cookbook/recipe/title/<p>{string()}</p>
then the C++ code runs fine.
Note also that you can load the XQuery directly from a file by using
query.setQuery(QUrl(queryFile));

QString& QString::operator=(const QByteArray&)' is private

I am trying to read standard output from QProcess as QString where the passed argument is a linux command. The linux command gives me the linux username. When I pass the argument to QProcess I expect the output to be my linux username. In doing so I have to read the standard output and get the result as QString but I get the error:
QString& QString::operator=(const QByteArray&)' is private.
My code:
QProcess process;
process.start(QString::fromStdString("whoami"));
process.waitForFinished(-1); // will wait forever until finished
QByteArray name = process.readAllStandardOutput();
QString username = name; //Error here saying
QProcess process;
process.start(QString::fromStdString("whoami"));
process.waitForFinished(-1); // this could be omitted
QTextStream txtStream(&process);
QString username = txtStream.readLine();
Note QTextStream by default is using default locale string encoding what is preferred. You can use QTextStream::setCodec to change string encoding (UTF-8, Windows-1250, UCS or whatever you need, default codec from system locale is usually best choice).
It also allows you to process data in streamed manner and this is always good.
Simply do this:
QByteArray name = process.readAllStandardOutput();
QString username = QString::fromRawData(name.data(), name.size());

Detect text file encoding

In my program I load plain text files supplied by the user:
QFile file(fileName);
file.open(QIODevice::ReadOnly);
QTextStream stream(&file);
const QString &text = stream.readAll();
This works fine when the files are UTF-8 encoded, but some users try to import Windows-1252 encoded files, and if they have words with special characters (for example "è" in "boutonnière"), those will show incorrectly.
Is there a way to detect the encoding, or at least distinguish between UTF-8 (possibly without BOM), and Windows-1252, without asking the user to tell me the encoding?
Turns out that auto-detecting the encoding is impossible for the general case.
However, there is a workaround to at least fall back to the system locale if the text is not valid UTF-8/UTF-16/UTF-32 text. It uses QTextCodec::codecForUtfText(), which tries to decode a byte array using UTF-8, UTF-16 and UTF-32, and returns the supplied default codec if it fails.
Code to do it:
QTextCodec *codec = QTextCodec::codecForUtfText(byteArray, QTextCodec::codecForName("System"));
const QString &text = codec->toUnicode(byteArray);
Update
The above code will not detect UTF-8 without BOM, however, as codecForUtfText() relies on the BOM markers. To detect UTF-8 without BOM, see https://stackoverflow.com/a/18228382/492336.
This trick works for me, at least so far. This method does not require BOM to work:
QTextCodec::ConverterState state;
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
const QByteArray data(readSource());
const QString text = codec->toUnicode(data.constData(), data.size(), &state);
if (state.invalidChars > 0)
{
// Not a UTF-8 text - using system default locale
QTextCodec * codec = QTextCodec::codecForLocale();
if (!codec)
return;
ui->textBrowser->setPlainText(codec->toUnicode(readSource()));
}
else
{
ui->textBrowser->setPlainText(text);
}

QXmlStreamWriter and cyrillic

I have a problem with encoding when writing XML files via QXmlStreamWriter in windows, how can I resolve it? Using stream.setCodec("UTF-8") or "windows-1251" is not helped.
QFile *file = new QFile(filename);
if (file->open(QIODevice::WriteOnly | QIODevice::Text))
{
QXmlStreamWriter stream(file);
stream.setAutoFormatting(true);
stream.writeStartDocument();
stream.writeStartElement("СЕКЦИЯ"); // start root section
stream.writeStartElement("FIELD");
stream.writeAttribute("name", "Имя");
stream.writeAttribute("value", "Иван");
stream.writeEndElement();
stream.writeEndElement(); // END СЕКЦИЯ
file->close();
}
Most likely the interpretation of the string literals in your source file is the problem, not the configuration of the stream writer.
Make sure your source file is encoded in UTF-8 and use QString::fromUtf8("Imja") etc. (Imja in cyrillic of course) instead of the implicit literal to QString conversion.