Unsolved Application exits with exit code 0, when toBase64 is used
-
Good evening!
Currently i'm working on a file upload and got stuck. Maybe someone with more experience in Qt 5 and C++ can help me out.
The Application exits with exit code 0 before the Image is uploaded when toBase64 is used. This behavior does not occur when readAll is used.
fileio.h
#ifndef FILEIO_H #define FILEIO_H #include <QObject> class FileIO : public QObject { Q_OBJECT public: explicit FileIO(QObject *parent = nullptr); Q_INVOKABLE QString read(const QString& Url); Q_INVOKABLE QString readBinaryAsBase64(const QString& Url); Q_INVOKABLE bool write(const QString& Url, QString data); public slots: signals: void error(const QString& msg); private: QString mSource; }; #endif // FILEIO_H
fileio.cpp
#include "fileio.h" #include <QFile> #include <QTextStream> FileIO::FileIO(QObject *parent) : QObject(parent) { } QString FileIO::readBinaryAsBase64(const QString& Url) { mSource = Url; if (mSource.isEmpty()){ emit error("source is empty"); return QString(); } QFile file(mSource); QString fileContent; if ( file.open(QIODevice::ReadOnly) ) { fileContent = QString::fromUtf8(file.readAll().toBase64(QByteArray::Base64UrlEncoding)); } else { emit error("Unable to open the file"); return QString(); } return fileContent; } QString FileIO::read(const QString& Url) { mSource = Url; if (mSource.isEmpty()){ emit error("source is empty"); return QString(); } QFile file(mSource); QString fileContent; if ( file.open(QIODevice::ReadOnly) ) { QString line; QTextStream t( &file ); t.setCodec("UTF-8"); do { line = t.readLine(); fileContent += line; } while (!line.isNull()); file.close(); } else { emit error("Unable to open the file"); return QString(); } return fileContent; } bool FileIO::write(const QString& Url, QString data) { mSource = Url; if (mSource.isEmpty()){ emit error("source is empty"); return false;} QFile file(mSource); if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)){ emit error("Error"); return false;} QTextStream out(&file); out << data; file.close(); return true; }
main.cpp
#include "fileio.h" #include <QGuiApplication> #include <QtWidgets/QApplication> #include <QQmlApplicationEngine> int main(int argc, char *argv[]) { qmlRegisterType<FileIO, 1>("FileIO", 1, 0, "FileIO"); QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); //QGuiApplication QApplication app(argc, argv); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); if (engine.rootObjects().isEmpty()) return -1; return app.exec(); }
main.qml
ApplicationWindow { visible: true width: 740 height: 880 title: qsTr("Test") Rectangle { property string oid: "123" id: rectPhoto anchors.fill: parent FileDialog { id: fileDialog title: "Please choose a file" folder: shortcuts.home onAccepted: { console.log("You chose: " + fileDialog.fileUrls) msgUpload.visible = true } onRejected: { console.log("Canceled") } } MessageDialog { id: msgUpload title: "Upload?" icon: StandardIcon.Question text: "Do you really want to upload " + fileDialog.fileUrls + "?" standardButtons: StandardButton.Yes | StandardButton.No onYes: { // removes "file://" var path = fileDialog.fileUrls[0].slice(7) var image = fileUpload.readBinaryAsBase64(path); // works as expected console.log("type", typeof image, "base64 data", image) Employee.uploadPhoto(rectPhoto.oid, image, Utils.basename(path), function(http) { if (http.readyState === 4) { if (http.status === 200) { console.log("ok"); } else { console.log("error: " + http.status); } } }); } } FileIO { id: fileUpload } RowLayout { Layout.alignment: Qt.AlignLeft | Qt.AlignBottom Button { text: "Upload!" id: btnUpload Layout.fillWidth: true onClicked: { fileDialog.visible = true } } Button { text: Abort id: btnAbort Layout.fillWidth: true } } }
employee.js
function uploadPhoto(oid, image, image_name, callback) { var http = new XMLHttpRequest(); var url = "http://localhost:8081/upload_photo"; var params = "&image=" + image + "&image_name=" + encodeURIComponent(image_name) + "&oid=" + encodeURIComponent(oid); http.open("POST", url, true); // Send the proper header information along with the request http.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); http.setRequestHeader("Content-length", params.length); http.setRequestHeader("Connection", "close"); http.onreadystatechange = function() { // Call a function when the state changes. callback(http); } http.send(params); }
utils.js
function basename(str, sep) { return str.substr(str.lastIndexOf(sep) + 1); }
Kind Regards,
GrrArgh
-
I'm assuming that you are just uploading the image. It should be just uploaded without any encoding. Any idea why r u encoding to base64 with URLEncoding ?
As added noted, It can done with backend C++ code itself rather than doing this in QML and moving around the image between C++ and QML.
-
Hi,
First thing to do: stop using QString when dealing with binary content, use QByteArray. Base64 encoded data can be stored in a QString because the binary data is encoded in a string representation. However loading the content of a non-text file in a QString will definitely get you in trouble since the data will "stop" at the first termination character it crosses.
-
@SGaist said in Application exits with exit code 0, when toBase64 is used:
Hi,
First thing to do: stop using QString when dealing with binary content, use QByteArray. Base64 encoded data can be stored in a QString because the binary data is encoded in a string representation. However loading the content of a non-text file in a QString will definitely get you in trouble since the data will "stop" at the first termination character it crosses.
Thanks, I know that. I only posted the solution depending on Base64 encoding and not the whole. I just wanna figure out why this implementation is behaving like explained.
The same sample, modified to transfer binary an image does work.