PDA

View Full Version : Breaking QByteArray::toBase64() results into 64 character lines



philw
28th October 2013, 04:22
It would be nice if QByteArray::toBase64() had an option to split the results into multiple fixed-length lines.

Currently its results are just in a single line (i.e. with no line breaks). (We actually have a requirement for this, my group's model serialization can't have arbitrarily long lines). The documentation states that this function conforms to RFC 2045 which seems to require lines of no more that 76 characters, but there may be a technical reason why this isn't always required. But still, it would be nice. (Apparently some other Base64 encodings require line lengths of 64 characters, so that's a good general length).

Could QByteArray::toBase64() be enhanced with an optional integer parameter of the maximum line length, with 0 as the default for the current single-line behavior?

Here is a function we are now using to do this line breaking:


QByteArray UserImageData::wrapAt64Chars (const QByteArray& inArray)
{
// This function takes a QByteArray lacking line breaks and returns
// that QByteArray value with line breaks inserted after every
// 64 bytes. It is intended for use with Base64-encoded QByteArrays
// created with QByteArray::toBase64() which generates a Base64 string
// without line breaks [as of Qt 4.8.5].
//
// Note that the QByteArray::fromBase64() static method ignores all
// characters which are not part of the encoding, including CR and LF.
// This is a provision of the "RFC 2045" Base64 standard supported by
// these methods. RFC 2045 specficies a maximum line length of 76
// characters. See: http://en.wikipedia.org/wiki/Base64
//
// The code below was adapted from this method in Qt 4.8:
// ByteArray QSslCertificatePrivate::QByteArray_from_X509();

const int inSize = inArray.size();
const int outEst = inSize + (inSize/32) + 4;
QByteArray outArray;
outArray.reserve (outEst);

const char* inPtr = inArray.data();
for (int inCrs = 0; inCrs <= inSize - 64; inCrs += 64)
{
outArray += QByteArray::fromRawData (inPtr + inCrs, 64);
outArray += "\n";
}

const int rem = inSize % 64;
if (rem > 0)
{
outArray += QByteArray::fromRawData (inPtr + inSize - rem, rem);
outArray += "\n";
}

return (outArray);
}

ChrisW67
28th October 2013, 05:18
You would need to take this to the Qt developers' mailing list, discuss it, and submit a relevant patch for approval if there was interest. Since you are asking to change the API and binary compatibility it is unlikely to be accepted during the Qt5 cycle... but stranger things have happened.

I can also see an issue with exactly what you use to separate the lines of base64 characters: the native line ending, or the CR LF pair that would be expected in RFC822 mail. Base64 encoding can be used for purposes other than email and the native line may be more appropriate at times.

If 4n character lines are desired out you can encode your input 3n bytes at a time rather than post-process the full result.


const int bytesPerLine = 54; // 72 chars per line out
QByteArray output;
for(int i = 0; i < input.size(); i += bytesPerLine) {
output += input.mid(i, bytesPerLine).toBase64();
output += "\r\n";
}

May not be the most efficient for large input.

anda_skoa
28th October 2013, 08:53
You would need to take this to the Qt developers' mailing list, discuss it, and submit a relevant patch for approval if there was interest. Since you are asking to change the API and binary compatibility it is unlikely to be accepted during the Qt5 cycle... but stranger things have happened.


An overload should be OK to add.

I am wondering though if it would not be most effecient to handle it at serialization time, i.e. serialize the data in lines of the length required by the serialization format.

Cheers,
_