PDA

View Full Version : Problem with QHttp's data encoding.



Diath
3rd July 2011, 04:01
Hello QtCentre members. I'm experiencing problems with data encoding. Let me describe my problem. I have done launcher for some game with Qt that has few simple QWebView elements to lookup news, servers status etc. and .dll injector for custom stuff for client. And now I wanted to implement auto updater feature. It works like parse ./data/version and http://url/version files then cast both buffers into integer values and compare them. If version on server is higher than version of client then it automatically hides launcher and downloads new package with QHttp object and after download is complete it calls function which saves buffer into file and calls 7z.exe to extract archive. Everything works here as I wanted to except for retrevied object's encoding. First both archives had same size (exact to byte) but after opening both in Notepad++ some of characters look different, I tried to change data stream's encoding to UTF8 with setCodec, but after that retrieved file is about 4 Mb larger than the file on server. Have you guys any suggestion how do I solve this problem?

Here's my code:


#include "updater.h"

Updater::Updater(QWidget *parent) : QDialog(parent), ui(new Ui::Updater)
{
_parent = parent;
params << "-y" << "x" << "*******.Launcher.tmp";

ui->setupUi(this);
ui->pBar->setRange(0, 3);

QTimer::singleShot(0, this, SLOT( versionCheck() ));
}

Updater::~Updater()
{
if( http )
delete http;

delete this;
}

int Updater::getCurrentVersion()
{
int ret = 0;
QFile *file = new QFile("./data/version");
if( file->exists() && file->open(QIODevice::ReadOnly | QIODevice::Text) ) {
QTextStream stream(file);
ret = atoi(stream.readLine().toLatin1().data());
file->close();
}

return ret;
}

void Updater::updateCurrentVersion()
{
//gotta fix this one later
QFile *file = new QFile("./data/version");
if( file->exists() && file->open(QIODevice::WriteOnly | QIODevice::Text) ) {
QTextStream s(file);
s << (int) getCurrentVersion() + 1;
file->close();
}
}

void Updater::versionCheck()
{
ui->pBar->setValue(1);
ui->pLabel->setText("Checking for updates...");

http = new QHttp();
http->setHost("launcher.*******.pl", 80);
http->get("/version");
connect(http, SIGNAL( done(bool) ), this, SLOT( finishVersionCheck() ));

ui->pBar->setValue(2);
ui->pLabel->setText("Retrieving data from server...");
}

void Updater::finishVersionCheck()
{
ui->pBar->setValue(3);
ui->pLabel->setText("Checking version...");

if( atoi(http->readAll().data()) > getCurrentVersion() ) {
if( QMessageBox::question(this, "Updater", "There is an update available.\nWould you like to download it now?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes ) {
ui->pBar->setValue(0);
ui->pLabel->setText("Downloading...");

http = new QHttp();
http->setHost("launcher.*******.pl", 80);
http->get("/test.7z");
connect(http, SIGNAL( done(bool) ), this, SLOT( finishDownload() ));
connect(http, SIGNAL( dataReadProgress(int, int) ), this, SLOT( updateProgress(int, int) ));
}
else {
_parent->close();
}
}
else {
_parent->show();
close();
}
}

void Updater::finishDownload()
{
QFile *file = new QFile("*******.Launcher.tmp");
if( file->exists() )
file->remove();

if( !file->open(QIODevice::WriteOnly | QIODevice::Text) ) {
QMessageBox::critical(this, "Updater", "Failed to open file.");
return;
}

QTextStream data(file);
data.setCodec("UTf-8");
data << http->readAll();
file->close();

QProcess *proc = new QProcess();
proc->start("7z.exe", params);
delete proc;

//file->remove();
updateCurrentVersion();
QMessageBox::information(this, "Updater", "New version has been downloaded.");

_parent->show();
close();
delete file;
}

void Updater::updateProgress(int done, int total)
{
ui->pBar->setRange(0, total);
ui->pBar->setValue(done);

QString text;
text.sprintf("Downloading: %d/%d kb (%3.2f%%)", done / 1024, total / 1024, (done / (double) total) * 100.0);
ui->pLabel->setText(text);
}



Regards, Diath.

ChrisW67
3rd July 2011, 09:39
QHttp is obsolete and should not be used in new code

You are requesting a binary file and then telling Qt that it is a text file (line 92) in UTF-8 encoding (line 97-98). At the very least the CR and LF characters may be mangled. The QTextStream may also remove or substitute bytes sequences that are not valid UTF-8. Just open the output file and use QIODevice::write() to output the QByteArray you get from readAll(). No need for a QTextStream.

BTW: Lines 25, 38 and 88 are memory leaks. There's no need to allocate QFile objects on the heap.

Diath
3rd July 2011, 21:59
So I have changed QTextStream to file.write(http->readAll()) but still after download is compile I'm not able to open the archive (Archive is corrupt~.).
Here's my current code:
void Updater::finishDownload()
{
QFile file("Launcher.tmp");
if( file.exists() )
file.remove();

if( !file.open(QIODevice::WriteOnly | QIODevice::Text) ) {
QMessageBox::critical(this, "Updater", "Failed to open file.");
return;
}

file.write(http->readAll());
file.close();

QProcess proc;
proc.start("7z.exe", params);

//file->remove();
updateCurrentVersion();
QMessageBox::information(this, "Updater", "New version has been downloaded.");

_parent->show();
close();
}

Any other tips?

@Edit:
Oh, dumb me. QIODevice::Text as you said, of course. Problem solved, thanks Chris.