PDA

View Full Version : Saving and reading text to and from Base64



Chase
18th April 2011, 12:45
I need to save some information (text) into a file. However, I need to obfuscate the contents to prevent tampering, or at least make it harder. The easiest solution that came to mind was to convert the QString data to CString, stream it to QByteArray, convert it to Base64 using QByteArray::toBase64(), then save it to a file using QDataStream. I don't have problem with saving.

Reading the information from the file, however, hasn't been successful. Upon reading the information, only a single word is retrieved, not the whole text. I need some advice on this one. Here's a simplified version of my code:



QString strTest = "This is a string.$";
QString strTest2 = "Another string.$";

QFile testFile( "./Test.ini" );
if( testFile.exists() ) {
testFile.open( QIODevice::Append );
QByteArray byteStrTest2( strTest2.toStdString().c_str() );
qDebug() << "strTest2.toStdString().c_str() : "
<< strTest2.toStdString().c_str();

QDataStream writer( &testFile );
writer << byteStrTest2.toBase64();
testFile.close();
}
if( !testFile.exists() ) {
testFile.open( QIODevice::WriteOnly );
QByteArray byteStrTest( strTest.toStdString().c_str() );
qDebug() << "strTest.toStdString().c_str() : "
<< strTest.toStdString().c_str();

QDataStream writer( &testFile );
writer << byteStrTest.toBase64();
testFile.close();
}

readFromByte( &testFile );
}

void readFromByte(QFile *file) {
file->open( QIODevice::ReadOnly );
QDataStream reader( file );
QByteArray byteFileContents;
reader >> byteFileContents;

qDebug() << "byteFileContents : " << byteFileContents;
qDebug() << "byteFileContents.fromBase64( byteFileContents ) : "
<< byteFileContents.fromBase64( byteFileContents );

byteFileContents = byteFileContents.fromBase64( byteFileContents );
qDebug() << "byteFileContents.size() : " << byteFileContents.size();

char *chrFileContents = new char[ byteFileContents.size() + 1 ];
strcpy( chrFileContents, byteFileContents.data() );
QString strFileContents = QString::fromAscii( chrFileContents, byteFileContents.size() );
QStringList strings = strFileContents.split( '$', QString::KeepEmptyParts, Qt::CaseSensitive );

QString strDisplay;
foreach(strDisplay, strings) {
qDebug() << "Value : " << strDisplay; // Output is always "Value : This is a string."
}
file->close();

qDebug() << "sizeof( chrFileContents ) : " << sizeof( chrFileContents );
qDebug() << "sizeof( char ) : " << sizeof( char );
}
Thanks in advance.

ChrisW67
19th April 2011, 01:07
I think you have over-complicated the exercise. Something like:


#include <QtCore>
#include <QDebug>

int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);

QString strToSave("Some test data");
QFile output("output.txt");
if (output.open(QIODevice::WriteOnly)) {
output.write(strToSave.toUtf8().toBase64());
output.close();
}

QFile input("output.txt");
if (input.open(QIODevice::ReadOnly)) {
QByteArray asSaved = input.readAll();
QString strRestored(QByteArray::fromBase64(asSaved));

qDebug() << "Saved:" << strToSave;
qDebug() << "As:" << asSaved;
qDebug() << "Restored:" << strRestored;
}
}

Chase
19th April 2011, 08:18
That's what my first code looked like, with the only difference being the QIODevice flag -- I used QIODevice::Append if the file already exists. It corrupts the file after several writes.

Thanks anyway.

ChrisW67
19th April 2011, 09:33
It corrupts the file after several writes.
What does this mean?

If you concatenate a series of QDataStreams, each containing a QByteArray, then what your file contains is a series of QDataStreams not one combined QDataStream. Your read code is expecting to read the entire file but it getting the first QByteArray in the file.

Is there a reason you are using QDataStream for text-only data?

A revised version


#include <QtCore>
#include <QDebug>

int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);

QString strToSave("Some test data");
QFile output("output.txt");
if (output.open(QIODevice::Append)) {
QDataStream out(&output);
out << strToSave.toUtf8().toBase64();
output.close();
}

QFile input("output.txt");
if (input.open(QIODevice::ReadOnly)) {
QDataStream in(&input);
QByteArray asSaved;

while (!input.atEnd()) {
in >> asSaved;

QString strRestored(QByteArray::fromBase64(asSaved));

qDebug() << "Saved:" << strToSave;
qDebug() << "As:" << asSaved;
qDebug() << "Restored:" << strRestored;
}
}

Chase
19th April 2011, 09:51
If I use QFile::readAll() to read strings from the file, I get lots of garbage in the final string after performing write operations on it several times. In other words, the approach that you pointed out only gives expected result on first and second write and read operations. After that, the file will be filled with garbage.

This is the output that I'm getting using your code, which is very similar to my first implementation:


"This is a string.$Another string.$♦▬µ≈F?W"7G&?µrΓ@Another string.$♦▬µ≈F?W"7G&?µrΓ@"That's why I decided to try QDataStream to do the job instead.

Edit: This post was made before I saw your edited post. "QFile::open()" should be "QFile::readAll()".