Converting JSON array to QByteArray - c++

I have an array: [0xa,0x0b,0x0c]
This is stored in QJsonArray, I want to cover this to a QByteArray. I've been searching around for a solution and have come across several methods, this is what I have tried but its not right:
QJsonObject::iterator itrBinary = objJSON.find(clsFileThread::mscszBinary);
if ( itrBinary != objJSON.end() ) {
QJsonArray aryBinary(itrBinary->toArray());
//At this point aryBinary contains:
//10,11,12 which is correct
QJsonDocument doc(aryBinary);
QByteArray aryBytes(doc.toBinaryData());
//Now aryBytes contains:
//'q','b','j' why, how?
qDebug() << aryBinary << aryBytes;
}
After the qDebug I get:
QJsonArray([10,11,12]) "qbjs\x01\x00\x00\x00\x18\x00\x00\x00\x06\x00\x00\x00\f\x00\x00\x00J\x01\x00\x00j\x01\x00\x00\x8A\x01\x00\x00"
What I want in QBytesArray is exactly what was put into the QJsonArray, 10, 11, 12.

Thank you to "eyllanesc" for input, I would have thought there would be a built in function to do this, but here is the solution:
QJsonArray aryBinary(itrBinary->toArray());
QJsonArray::iterator itrArray = aryBinary.begin();
QByteArray aryBytes;
while( itrArray != aryBinary.end() ) {
aryBytes.append(static_cast<char>(itrArray->toInt()));
itrArray++;
}
qDebug() << aryBinary << aryBytes;

Related

How to parse QJsonArray?

In my QT application, there is a need to store the value of structures of the same type in a JSON dictionary.
I know about the [JSON Save Game Example article][1], I tried to figure it out for a long time, I didn’t come to anything, I also surfed the forums with the same result.
The main problem is this:
I have a JSON document:
{
"devices": [
{
"name": "some name",
"price": 2000,
"year": 2022
}
]
}
I use the following code to read the information:
//open my JSON
QFile file("path/to/myfile.json");
file.open(QIODevice::ReadOnly);
QByteArray jsonData = file.readAll();
//finding array
QJsonDocument document = QJsonDocument::fromJson(jsonData);
QJsonObject object = document.object();
QJsonArray temp_array = object["devices"].toArray();
//reading
qDebug() << temp_array[0].toObject().value("name").toString(); //returned ""
qDebug() << temp_array.size(); //returned 0
qDebug() << temp_array.empty(); //returned true
qDebug() << object.keys(); //returned QList("devices")
As I previously pointed out in a comment, trying to read the values of the "name" key returned me an empty string, the size and empty functions indicate that I'm looking at an empty array. However, the keys function indicates that my json object still contains the "devices" key.
What could be the problem?
[1]: https://doc.qt.io/qt-5/qtcore-serialization-savegame-example.html
Your code seems to be doing correct things in correct order but something goes wrong. Either your file is not found or it doesn't get opened, or it is found but parsing fails.
You would find out if you did some checks instead of just assuming things work.
Below you will find example of robust programming. The example code checks
if file exists
if file opening fails
if file parsing to JSON fails
if file is actually JSON object (and not e.g. JSON array)
if size of the JSON array named "devices" is bigger than zero
if object in JSON array contains "name" property
if "name" property type is string
(I didn't try to compile the code, but I'm sure you get the idea and figure out what went wrong. If you made this kind of code to a function you would either return or throw exception when things go wrong...)
QFile file("path/to/myfile.json");
if (!file.exists()) {
qWarning() << "File doesn't exist";
}
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "Couldn't open file";
}
QByteArray jsonData = file.readAll();
QJsonParseError parseError;
QJsonDocument document(QJsonDocument::fromJson(jsonData, &parseError));
if (parseError.error != QJsonParseError::NoError) {
qWarning() << "Invalid json file. Parsing failed:" << parseError.error << parseError.errorString();
}
if (!document.isObject()) {
qWarning() << "File is not JSON object!";
}
const QJsonObject &object = document.object();
QJsonArray temp_array = object["devices"].toArray();
if (temp_array.size() < 1) {
qWarning() << "JSON array object count:" << temp_array.size();
}
QJsonObject jsonObj = temp_array[0].toObject();
if (jsonObj.contains("name")) {
if (jsonObj["name"].isString()) {
qDebug() << jsonObj["name"].toString();
} else {
qWarning() << "name" << "is not string!";
}
} else {
qWarning() << "Object in JSON array did not have" << "name";
}

How do you delete a sub-string in a string(qstring) in Qt

Is there a function in Qt similar to delete() and copy() in Delphi.
I am reading data from a device connected to my computer via USB and storing it as a QString. Every line that is read is not the same (or is cut short, even while using readyRead). I created a buffer sting to add these "half sting" (eg. string = "This" instead of "This is a string#") to and now I want to copy the string up until the '#' and then delete the string so if new "half stings" get added I can do the same with them. The code below is what I tried
void MainWindow::readSerial()
{
QByteArray serialData = port->readAll();
serialBuffer += serialData;
QByteArray serialString = serialBuffer.
qDebug() << serialString;
ui -> textEdit ->append(serialString);
//serialBuffer.replace(serialString,"");
}
The above code only returns an empty string.
void MainWindow::readSerial()
{
QByteArray serialData = port->readAll();
serialBuffer += serialData;
QString serialString = serialBuffer.mid(serialBuffer.indexOf("$"),serialBuffer.indexOf("\r\n"));
qDebug()<< "index of \r\n" << serialBuffer.indexOf("\r\n");
qDebug() << "SerialString" <<serialString;
ui -> textEdit ->append(serialString);
qDebug() << "SerialBuffer: " << serialBuffer;
serialBuffer.replace(serialString + "\r\n","");
}
the above code works. Thanks all.
regards

QstringList to Qstring conversion issues

I am working on VS2015 with qt framework. In my source code, I have a function for printing in the GUI screen.
This function is called each time something needs to be printed.
It goes like this.
void Trial::Print_MessageBox(QString string)
{
ui.MessagesScreen->appendPlainText(string);
Cursor_Messagebox.movePosition(QTextCursor::End);
ui.MessagesScreen->setTextCursor(Cursor_Messagebox);
ui.MessagesScreen->ensureCursorVisible();
}
// Output in MessageBox
void Trial::Print_MessageBox(QFlags<QNetworkInterface::InterfaceFlag> flags)
{
QString str = QString("Flag %1").arg(flags);
ui.MessagesScreen->appendPlainText(str);
}
The above function has no problems and running well.
Now I am trying to read a text file. This has set of values in no order or size. An example for this:
231, 54, 4 \n
47777, 2211, 676, 9790, 34236, 7898\n
1, 3\n
Objective is to convert these into integers (line by line) and print them in the GUI and also send them (line by line) to other system. So I tried to do it with the following.
void Trial::ReadFile_Data()
{
QFile file("input.txt");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
{
Print_MessageBox("Error in reading File");
return;
}
QTextStream in(&file);
while (!in.atEnd())
{
QString line = in.readLine();
Print_MessageBox(line);
int conv = line.toInt();
QString str = QString("%1 %2").arg("Values are: ").arg(conv);
Print_MessageBox(str);
QStringList fields = line.split(",");
}
file.close();
}
When I print the "line", it is just printing the same values as in the file. When I do the conversion and printing, I get an error (which is expected) Now I try to remove "," with the help of split then I get QstringList which I cannot use as I have the Qstring function to print(this cant be changed)
I am not getting any pointers from here. Please help me out as this is bugging me since long time.
Just simple...
QStringList::const_iterator constIterator;
for (constIterator = fonts.constBegin(); constIterator != fonts.constEnd();
++constIterator) {
cout << (*constIterator).toLocal8Bit().constData() << endl;
}
where fonts is your QStringlist
Your question reduces to "How do I iterate over a QStringList".
Like this:
// C++11
for (auto field : fields) Print_messageBox(field);
// C++98
foreach (QString field, fields) Print_messageBox(field);
See here for information about how foreach a.k.a Q_FOREACH was implemented.

Creating a QVariantMap in Qt with strings

Apologies for asking something this trivial but I just can't seem to get it right so I guess I've completely misunderstood everything I thought I knew about memory management.
I have a function that parses a network reply for some data and it looks like this:
// Call from another function
QVariantMap *mappedResult = handleReply(reply);
...
// Function
QVariantMap *handleReply(QNetworkReply *reply) {
QVariantMap *result = new QVariantMap;
QVariant testvalue = new QVariant("testvalue");
result->insert("testkey", testvalue);
if (reply->error() > 0) {
qDebug() << "Error number = " + reply->errorString();
QVariant variant = QVariant.fromValue(reply->errorString());
result->insert("error", variant);
} else {
QJsonDocument jsonResponse = QJsonDocument::fromJson(jsonString.toUtf8());
QJsonObject jsonResponseObject = jsonResponse.object();
*result = jsonResponseObject.toVariantMap();
}
return result;
}
If there is no error, the result is parsed fine by the built in toVariantMap function. When there is an error however, I would like to create an entry in the result that is sent back from the function. As you can see in the function, I'm trying to create QVariants from Strings in two different ways.
The first approach gives an error like this:
C:\Qt\5.2.0\mingw48_32\include\QtCore\qvariant.h:466: error: 'QVariant::QVariant(void*)' is private inline QVariant(void *) Q_DECL_EQ_DELETE;
^
The second approach like this:
[PATH] error: expected primary-expression before '.' token QVariant variant = QVariant.fromValue(reply->errorString());
I've also tried setting the values like this:
result->insert("testkey", "testvalue");
result->insert("error", reply->errorString());
The last approach doesn't give compile errors but the result variable in the return statement cannot be inspected in the debugger and as soon as the return statement is executed the application crashes with memory problems indicating I'm not using "new" properly.
"Error accessing memory address 0x...".
If someone with at least a little knowledge could help me sort out how to perform this simple task, I would be very greatful. How can I return a QVariantMap from my function with custom strings as key/value pairs?
Cheers.
I would write your function in the following way (with fixes):
QVariantMap *handleReply(QNetworkReply *reply) {
QVariantMap *result = new QVariantMap;
QVariant testvalue("testvalue"); // <- fixed here
result->insert("testkey", testvalue);
if (reply->error() > 0) {
qDebug() << "Error number = " + reply->errorString();
QVariant variant(reply->errorString()); // <- fixed here
result->insert("error", variant);
} else {
QJsonDocument jsonResponse = QJsonDocument::fromJson(jsonString.toUtf8());
QJsonObject jsonResponseObject = jsonResponse.object();
*result = jsonResponseObject.toVariantMap();
}
return result;
}
However it is still unclear, why do you need to work with a pointer to the variant map instread of passing it by value?

Save QNetworkReply

I would like to be able to save the QNetworkReply to a QString/QByteArray. In the examples I've seen they always saves the stream to another file.
At the moment my code looks something like this, where I get a string from the host and all I want to do is to parse it to look for the specified error code.
if(_reply->error() == QNetworkReply::UnknownContentError) {
qDebug() << _reply->readAll(); // prints out the xml message
QString test = QString(_reply->readAll());
qDebug() << test; // ""
QByteArray test2 = QByteArray(_reply->readAll());
qDebug() << test2; // ""
QRegExp rxlen("(<code>)(.*(?=</code>))");
rxlen.setMinimal(true);
int pos = rxlen.indexIn(test); // pos == -1
if(pos > -1) {
qDebug() << rxlen.cap(2); // never hit
}
}
The message is pretty small and looks something like this:
<?xml version="1.0" encoding="utf-8"?>
<error>
<code>string-value</code>
<message>string-value</message>
</error>
So how can I load this small stream into memory, or just look for the error code?
QNetworkReply inherits from QIODevice which is a stream. After you have read something from a stream it's not there anymore. After your debug line (one with // prints out the xml message comment) there's nothing to read anymore.