I'm using protobuf to send/receive binary data from Cpp to Js and vice-versa and I'm using QWebChannel to communicate with the HTML client.
Question: How to deserialize binary data in cpp which is serialized and sent from Js?
Following I tried:
//Serialization: Cpp to JS - WORKING
tutorial::PhoneNumber* ph = new tutorial::PhoneNumber();
ph->set_number("555-515-135");
ph->set_type(500);
QByteArray bytes = QByteArray::fromStdString(ph->SerializeAsString());
QString args = "\"" + bytes.toBase64(QByteArray::Base64Encoding) + "\"";
QString JsFunctionCall = QString("DeserializePhoneNumber(%1);").arg(args);
m_pWebView->page()->runJavaScript(JsFunctionCall);
//Deserialization In JS - Js Code - WORKING
var obj = phone_msg.PhoneNumber.deserializeBinary(data);
console.log("PhoneNumber: " + obj.getNumber());
console.log("Type: " + obj.getType());
//Serialization in Js - WORKING
var phNum = new phone_msg.PhoneNumber;
phNum.setNumber("555-515-135");
phNum.setId(500);
var base64Str = btoa(phNum.serializeBinary());
console.log("base64Str: " + base64Str);
//Call Cpp function from Js
MainChannel.SendMsgToCpp(base64Str);
Deserialization in Cpp - NOT WORKING
bool WebRelay::ReceiveMsgFromJs(QVariant data)
{
QString str = data.toString();
QByteArray bytedata = str.toLatin1();
QByteArray base64data = QByteArray::fromBase64(bytedata);
std::string stdstr = base64data.toStdString();
tutorial::PhoneNumber cppPhNum;
//THIS IS NOT WORKING. Text and id are invalid
cppPhNum.ParseFromArray(base64data.constData(), base64data.size());
qDebug() << "Text:" << itemData.number();
qDebug() << "id:" << cppPhNum.id();
}
Found the problem.
I was getting comma-separated bytes from Js like:
10,7,74,115,73,116,101,109,49,16,45
I split the strings by ',' and created a QByteArray
QStringList strList = str.split(',');
QByteArray bytedata;
foreach(const QString & str, strList)
{
bytedata+= (str.toUInt());
}
std::string stdstr = bytedata.toStdString();
itemData.ParseFromString(stdstr);
It works.
Also in JS, I removed convertion of the binary string to base64:
var base64Str = phNum.serializeBinary();
Related
I want to send text from a current TextView editor buffer to PDF through export function, but I don't see any text when I open the exported PDF.
Here's my attempt in C++ code:
void MainWindow::export_note() {
auto op = Gtk::PrintOperation::create();
string file_path = work_dir + "/" + curr_path;
string file_name = curr_path.substr(curr_path.rfind("/")+1);
string file_content = editor.get_buffer()->get_text();
op->set_export_filename(file_name);
ofstream out(file_path);
out << file_content;
out.close();
auto res = op->run(Gtk::PrintOperation::Action::EXPORT);
return;
}
The only thing that works is the file_name being updated.
I am trying to convert QNetworkCookie to QString but I can't find a way how to do this.
For example, I've tried to do something like this
QString cookie = QVariant(cookies_[i]).toString();
and this
QString cookie = (QString*)cookies_[i];
Nothing worked.
As #Aditya told, QNetworkCookie::value() works as QByteArray.
So, problem solvetion for me is:
auto cookie = reply->manager()->cookieJar()->cookiesForUrl(webReportsUrl);//).value(0);
cookies = cookie[0].name() + "=" + cookie[0].value() + "; domain=" + cookie[0].domain() + "; path=" + cookie[0].path();
qDebug() << "Cookie: " << cookies;
But presented returns only cookies' value without a name, domain, and others.
I'm trying download comments from YouTube through private api but for some reason request to api does not work in curl. It should return JSON with information about comments under video but to me it return nothing. Literally nothing. In postman with same parameters and headers all work perfectly. I think that i'm not correctly use curl but i does not know where i wrong.
My downloader code:
QMap<QString, QString> commentsChunk = {
{"Accept", "*/*"},
{"Host", "www.youtube.com"},
{"Content-Type", "application/x-www-form-urlencoded"},
{"Origin", "https://www.youtube.com"},
{"DNT", "1"},
{"Pragma", "no-cache"},
{"Cache-control", "no-cache"},
{"TE", "Trailers"},
};
QString dir = KTools::Options::configPath + "/tmp";
cc->setErrFile(dir, "errfile.txt");
cc->currHeaderMode = KTools::Enums::Curl::HeaderMode::None;
cc->currCookieMode = KTools::Enums::Curl::CookieMode::GetAllTimes;
cc->cookieFileName = "cookieYoutube.txt";
cc->cookiePath = KTools::Options::configPath;
cc->setOptions();
QByteArray data = cc->request(params.value("url").toString() + "/videos");
KTools::HtmlAst::Object htmlObj = KTools::HtmlAst::Object();
htmlObj.makeAst(data);
QString xsrfToken = QUrl::toPercentEncoding(htmlObj.arrsAndObjs.objects[0].value("XSRF_TOKEN").toString());;
commentsChunk["X-YouTube-Client-Version"] = htmlObj.arrsAndObjs.objects[0].value("INNERTUBE_CONTEXT_CLIENT_VERSION").toString();
commentsChunk["X-YouTube-Client-Name"] = htmlObj.arrsAndObjs.objects[0].value("INNERTUBE_CONTEXT_CLIENT_NAME").toVariant().toString();
QJsonArray videosInfo = htmlObj.arrsAndObjs.objects[3].value("contents").toObject().value("twoColumnBrowseResultsRenderer").toObject().value("tabs").toArray()[1].toObject().value("tabRenderer").toObject().value("content").toObject().value("sectionListRenderer").toObject().value("contents").toArray()[0].toObject().value("itemSectionRenderer").toObject().value("contents").toArray()[0].toObject().value("gridRenderer").toObject().value("items").toArray(); // line 45 "items":[...]
QVector<QString> videosId;
for (int i = 0; i < videosInfo.size(); i++)
{
videosId.append(videosInfo[i].toObject().value("gridVideoRenderer").toObject().value("videoId").toString());
}
data = cc->request("https://www.youtube.com/watch?v=" + videosId[1]);
htmlObj = KTools::HtmlAst::Object();
htmlObj.makeAst(data);
QJsonArray continuations = htmlObj.arrsAndObjs.objects[5].value("contents").toObject().value("twoColumnWatchNextResults").toObject().value("secondaryResults").toObject().value("secondaryResults").toObject().value("continuations").toArray();
QVector<QJsonObject> commentsJsons;
cc->restartSession();
cc->setRequestType(KTools::Enums::Curl::RequestType::Post);
cc->currHeaderMode = KTools::Enums::Curl::HeaderMode::Custom;
QVector<QVector<QVector<QString>>> regexResult;
KTools::ExForString::executeRegex(data, {{"([^\"]+___________[^\"]+)\",\"[^\"]+\":\"([^\"]+)"}}, regexResult);
cc->setHeader(commentsChunk);
cc->setOptions();
QString tmp = QUrl::toPercentEncoding(regexResult[0][0][1]);
QString tmp2 = QUrl::toPercentEncoding(regexResult[0][0][2]);
cc->currPostParam = "session_token=" + xsrfToken;
data = cc->request("https://www.youtube.com/comment_service_ajax?action_get_comments=1&pbj=1&ctoken=" + tmp + "&continuation=" + tmp + "&itct=" + tmp2);
KTools::File::writeFile((tmp + "\n" + tmp2 + "\n" + cc->currPostParam).toUtf8(), dir, "requestParams.txt");
cc->unsetErrFile();
QString nope;
My curl wrapper code:
Header file: https://pastebin.com/beg1MYgG
Implementation file: https://pastebin.com/Dv4i823P
Curl log: https://pastebin.com/xXnsQEqY
Update: Thanks to suggestion in comment i locate my problem. For some reason function std::string::c_str() work incorrectly, in other words gives random characters. How can i fix it?
In the end it's just been UB.
if (currRequestType == KTools::Enums::Curl::RequestType::Post)
{
curl_easy_setopt(gCurlHandle, CURLOPT_POSTFIELDS, currPostParam.toStdString().c_str());
curl_easy_setopt(gCurlHandle, CURLOPT_POSTFIELDSIZE, currPostParam.size());
}
Curl store not string but reference to string. But temporary string returned bu c_str() destroys in the end of if statement.
I have this C++ code, and am having trouble json serializing it.
string uInput;
string const& retInput;
while(!std::cin.eof()) {
getline(cin, uInput);
JSONExample source; //JSON enabled class from jsonserialize.h
source.text = uInput;
//create JSON from producer
std::string json = JSON::producer<JSONExample>::convert(source); //string -> returns {"JSONExample":{"text":"hi"}}
//then create new instance from a consumer...
JSONExample sink = JSON::consumer<JSONExample>::convert(json);
//retInput = serialize(sink);
// Json::FastWriter fastWriter;
// retInput = fastWriter.write(uInput);
retInput = static_cast<string const&>(uInput);
pubnub::futres fr_2 = pb_2.publish(chan, retInput);
cout << "user input as json which should be published is " << retInput<< std::endl;
while(!cin.eof()) {
getline(cin, uInput);
newInput = "\"\\\"";
newInput += uInput;
newInput += "\\\"\"";
Instead of typing in the message like "\"hi\"", this code takes "hi" and does it.
If the change you described made the "Invalid JSON" disappear, then a "more correct" solution would be, AFAICT, to change the publish() line to:
pubnub::futres fr_2 = pb_2.publish(chan, json);
Because json already has JSON serialized data. Of course, if that JSON is what you want to publish.
Hei , I have this text in a JSON :
( without the returns all in one line)
[
{
"ERROR":false,
"USERNAME":"Benutzer",
"FORMAT":"HUMAN",
"LATITUDE_MIN":84,
"LATITUDE_MAX":36,
"LONGITUDE_MIN":5,
"LONGITUDE_MAX":20,
"RECORDS":203
},
[
{
"MMSI":233434540,
"TIME":"2014-10-09 06:19:06 GMT",
"LONGITUDE":8.86037,
"LATITUDE":54.12666,
"COG":347,
"SOG":0,
"HEADING":236,
"NAVSTAT":0,
"IMO":0,
"NAME":"HELGOLAND",
"CALLSIGN":"DK6068",
"TYPE":90,
"A":20,
"B":15,
"C":4,
"D":4,
"DRAUGHT":2,
"DEST":"BREMERHAVEN",
"ETA":"00-00 00:00"
},
{
"MMSI":319072300,
"TIME":"2014-10-09 06:08:53 GMT",
"LONGITUDE":9.71578,
"LATITUDE":54.31949,
"COG":343.6,
"SOG":0,
"HEADING":197,
"NAVSTAT":5,
"IMO":1012189,
"NAME":"M.Y. ESTER III",
"CALLSIGN":"ZGED3",
"TYPE":37,
"A":31,
"B":35,
"C":7,
"D":6,
"DRAUGHT":3.5,
"DEST":"SCHACT AUDORF",
"ETA":"09-16 08:00"
}
// many more lines but the Json IS VALID.
]
]
I would parse it and put that in a MYSQL table.
Not all, only name and MMSI first.
But this don't view anything in my consle because its dont jump in the foreach:
bool ok = true;
// my json data is in reply & ok is a boolean
QVariantList result = parser.parse(reply, &ok).toList();
foreach(QVariant record, result) {
QVariantMap map = record.toMap();
qDebug() << map.value("NAME");
}
What's wrong ?
When i debug, i only see that it doesn't jump in the foreach.
I use the QJson libary : QJson::Parser parser; But please anyone can tell me what i do wrong?
Your code looks like you are iterating over top level array, while the data you are looking for is in the nested array, which is effectively the second item of the top level array. So, you need to iterate over items in the inner array.
The following code works for me with your sample JSON:
QVariantList result = parser.parse(reply, &ok).toList().at(1).toList();
foreach (const QVariant &item, result) {
QVariantMap map = item.toMap();
qDebug() << map["NAME"].toString();
qDebug() << map["MMSI"].toLongLong();
}
If you are using Qt5 or above, you can make use of the awesome features provided by QJsonDocument, QJsonObject and QJsonArray.
I have copied your json into a file named test.txt in my D-drive and the code below works fine.
QJsonDocument jsonDoc;
QByteArray temp;
QFile file("D://test.txt");
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
temp = file.readAll();
}
jsonDoc = QJsonDocument::fromJson(temp);
QJsonArray jsonArray = jsonDoc.array().at(1).toArray(); //Since you are interested in the json array which is the second item and not the first json object with error
for(int i =0; i < jsonArray.size(); ++i)
{
QJsonObject jsonObj = jsonArray.at(i).toObject();
int mmsi = jsonObj.find("MMSI").value().toInt();
QString name = jsonObj.find("NAME").value().toString();
qDebug() << mmsi;
qDebug() << name;
}
If you have to stick to Qt4, you can try using the qjson4 library which tries to mimic the behavior of the 'QJsonDocument' which is part of Qt5.