I have a method that returns an unsigned char * array and I am trying to encode this as base64 and decode it later. So what I am doing is as follows:
unsigned char * val = myMethod();
char * encodedMsg = reinterpret_cast<char *>(val);
std::cout << "Returned message: " << val << std::endl;
QByteArray raw = QByteArray(encodedMsg).toBase64(QByteArray::Base64Encoding | QByteArray::OmitTrailingEquals);
The output from the method is \u0001z\ri!i, and the encoded value is XHUwMDAxelxyaSFpLA.
Now, I decode it as follows:
QByteArray decoded = QByteArray::fromBase64(raw,
QByteArray::Base64Encoding | QByteArray::OmitTrailingEquals);
qDebug() << decoded;
Now this returns \\u0001z\\ri!i,. Notice that the slashes have been escaped.
I know I can replace this as a post processing step but is there a way to avoid this. Perhaps I am using the encoding/decoding incorrectly?
Try like below,
Base 64 Encode :
unsigned char* Ciphertext = Encypt();
QByteArray qByteArray((char*)(Ciphertext),(int)strlen((char *)Ciphertext));
qDebug()<<"Ciphertext : "<< qByteArray.toBase64();
Output :
Ciphertext : "WLdC+ri94z940BiAven6qXQH6rPbE64nQXt5aFByLGPFh1n//tOGLG02zBSoZ79qMA"
Base 64 Decode :
QString data = QString::fromLatin1(QByteArray::fromBase64(Base64QByteArray.toBase64()).data());
in my case i used this base64 conversion for AES encyption, make it shoultable for yours.
Related
I have a WAV file that I decode with the QAudioDecoder. As a result I have a QAudioBuffer object. I want to store the data stored in QAudioBuffer in a QByteArray for my QIODevice derived class. I want to use this data in the ReadData method of my derived class for audio output. I now have 2 questions:
How to get a QByteArray from a QAuddioBuffer?
I used the following code, but unfortunately this is not correct. The data in QAudioBuffer is coded to 2Bytes, but each element in a QByteArray is coded to 1Byte (right?). Don't we have a loss of information there? To test if QByteArray contains the original data from the WAV file, I save it to a TXT file.
is this approach appropriate? I actually want to apply some operations on the data stored in QAudioBuffer (e.g. filters) and listen to the result in real time.
Thanks in advance.
Here is the code
QAudioFormat *format_decoder;
format_decoder = new QAudioFormat;
format_decoder->setSampleRate(44100);
format_decoder->setChannelCount(1);
format_decoder->setSampleFormat(QAudioFormat::Int16);
QAudioDecoder decoder;
decoder.setSource(filenameSource);
decoder.setAudioFormat(*format_decoder);
decoder.start();
QObject::connect(&decoder, &QAudioDecoder::bufferReady, this, &MainWindow::slot_bufReady);
and the slot
void MainWindow::slot_bufReady(){
QAudioBuffer buffer = m_audioDecoder->read();
QByteArray buffer_ByteArray(buffer.constData<char>(), buffer.byteCount());
QFile file(filenameTest1);
if(!file.open(QIODevice::WriteOnly|QIODevice::Append)) {
qDebug() << "ERRO "; }
QTextStream strem(&file);
for(auto const dat: buffer_ByteArray) {
strem<< qreal(dat)/128.0<< "\r\n";
}
file.cloe();
This looks suspicious:
for(auto const dat: buffer_ByteArray) {
strem<< qreal(dat)/128.0<< "\r\n";
}
Your audio format is 16-bit mono. Reading it byte by byte is a non-starter. Read it sample by sample. That is, read two bytes at a time and convert. More likely this:
int16_t* data = (int16_t*)(buffer.data());
int samples = buffer.sampleCount();
for (int i = 0; i < samples; i++)
{
strem << data[i] << "\r\n";
}
The above will save your samples into a text file. You could plot it with Excel. But as others have said, that's not as useful as saving in as binary. You could prepend a WAV file header such that it can be played and analyzed with other tools.
Update
If your intent is to transcode from 16-bit to 8-bit, this is how you would likely do it:
int16_t* data = (int16_t*)(buffer.data());
QByteArray buffer_ByteArray(buffer.sampleCount(), '\0');
for (size_t i = 0; i < samples; i++) {
buffer_ByteArray[i] = (char)(data[i] / 256); // 16-bit to 8-bit
}
Note: some audio platforms use unsigned integers for 8-bit audio. That is the zero amplitude sample is 0x80. This is the case for 8-bit WAV files. If that's in play, then change this line:
buffer_ByteArray[i] = (char)(data[i] / 256); // 16-bit to 8-bit
To this:
char c = (char)(data[i] / 256); // 16-bit to 8-bit signed
const unsigned char mask = 0x80;
buffer_ByteArray[i] = (char)(mask ^ c);
QString samp_buff[100];
QByteArray data;
uint8_t speed;
samp_buff[3] = data.toHex(); //I converted the QByteArray into a string
qDebug() << "read_every_data_"<< samp_buff[3];
speed = samp_buff[3].toUInt(); //Trying to convert the string to uint8_t
qDebug() << "Converted to UINT8" << speed;
Hi! I successfully got the Qbytearray value (data) stored in as a QString in the samp_buff array of strings, and also during the conversion of QString to uint8_t in the form of hex.
Data: "\x07" //QByteArray
read_every_data_ "07" //QString
Converted to UINT8 7 //Uint8_t
Its working fine for this but the problem arises when this happens.
Data: "\x0B" //QByteArray
read_every_data_ "0b" //QString
Converted to UINT8 0 //Uint8_t
Whenever the hex string has alphabets in it, the result of the conversion becomes zero.
As the documentation of QString::toUint suggests, the signature of the function looks like this.
uint QString::toUInt(bool *ok = nullptr, int base = 10) const
The second argument base is for specifying the base. To convert from hex strings, supply 16 to it.
speed = samp_buff[3].toUInt(nullptr, 16);
I have a QByteArray, inside the QByteArray are multiple values of diferent datatypes which I want to extract. The difficulty by that is, that the values are in an defined length of x-bits, and they have a defined start position (also in bits).
eg: an int8 is stored inside the QByteArray from bit nr. 4 (of the first byte) to bit nr. 12 (inside the second byte).
On the Qt-wiki side i found a method to disassemble a byteArray into a bit array: https://wiki.qt.io/Working_with_Raw_Data
So i'm cutting my bits out of the byte array like that:
QByteArray MyCutter::cutMessage(qint32 bitStart, qint32 bitLength)
{
qDebug() << mBuffer;
QBitArray bits(mBufferLen * 8);
for(quint32 i=0; i<mBufferLen; ++i)
{
for(quint32 b=0; b<8; b++)
{
bits.setBit(i*8 +b, mBuffer.at(i) & (1<<(7-b)));
}
}
qDebug() << bits;
QByteArray bytes;
//round up to the next n*8 length of a byte: (length + y) = x*8
qint32 bitLengthWithZeros = (bitLength + (8 - 1)) & ~(8 - 1);
bytes.resize(bitLengthWithZeros/8);
bytes.fill(0);
for(qint32 b=bitStart ,c=0; b<(bitStart + bitLength); b++, c++)
{
bytes[c/8] = (bytes.at(c/8) | ((bits.testBit(b)?1:0)<<(7-b%8)));
}
qDebug() << bytes;
return bytes.data();
}
This is working fine so far - I can cut my ByteArray into any other.
The Problem is to convert the values into int/float/doubles, and to be more specific into signed values.
To convert i've tried two things:
QByteArray::toHex().toLong(nullptr, 16) ... toLong/toLongLong etc. This is working, but only returns me the UNSIGNED value of the QByteArray. If I'm cutting the mBuffer with the function MyCutter::cutMessage, like the excample above, from the 4. bit to the 12. (which is also 0xFF) im getting 255 as signed int! And that's wrong?
On the other side I've tried to convert it with QStremData:
QDataStream stream(mBuffer);
stream.setByteOrder(QDataStream::LittleEndian);
qint64 result;
stream >> result;
qDebug() << QString::number(result,16);
qDebug() << QString::number(result);
mBuffer are the raw data. If im putting "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF" insde mBuffer, the printed value is -1 which is correct.
QByteArray h = cutMessage(0,8);
qDebug() << h.toHex().toLongLong(nullptr, 16);
QDataStream stream2(h);
stream2.setByteOrder(QDataStream::LittleEndian);
qint64 result2;
stream2 >> result2;
qDebug() << QString::number(result2,16);
qDebug() << QString::number(result2);
Converting the cut-Message with the code block above is always returning me "0".
So without cutting, the interpretation of the whole QByteArray is correct, but if I'am cutting something off it's returning me always the unsigned value, or "0".
Somehow I'am loosing some information while the transformation into QBitArray and vice versa.
Hopefully my explanations are understandable ;)
Recently, I made an attempt to integrate loss less data compression to my game engine for loading assets; but this simple compression example does not seem to work correctly. Any suggestions ? Here is my code :
const char *srcData = "Hi ! This is a really really really long test string !";
const int dstBufferSize = LZ4_compressBound(sizeof(srcData));
char *dstData = new char[dstBufferSize];
int bytesPassed = LZ4_compress_default(srcData, dstData,
sizeof(srcData),
dstBufferSize); // compress data
BOOST_LOG_TRIVIAL(info) << dstData << std::endl; // print compressed data
delete[] dstData;
This is the output. Obviously, you can see it's wrong (part of the string is missing) :
[2016-02-24 15:56:47.986366] [0x00000b0c] [info] #Hi !═══════════════²²²²À▀WÏÇ0
EDIT
When decompressing data, only the 'Hi' part is appearing : the rest are random characters/ no characters
EDIT 2 After Simon's suggestion, I changed the code; but after decompressing the code; i only get Hi ! (nothing after it); Here is the updated code :
const char *srcData = "Hi ! This is a really really really long test string !";
const int dstBufferSize = LZ4_compressBound(strlen(srcData) + 1);
char *dstData = new char[dstBufferSize];
int bytesPassed = LZ4_compress_default(srcData, dstData,
sizeof(srcData),
dstBufferSize);
BOOST_LOG_TRIVIAL(info) << dstData << std::endl;
std::ofstream fWriter("test.bin", std::ofstream::binary);
fWriter << dstData;
fWriter.close();
char* decStr = new char[strlen(srcData) + 1];
LZ4_decompress_fast(dstData, decStr, strlen(srcData) + 1);
std::cout << decStr << std::endl; // only Hi appearing
delete[] dstData;
You are using sizeof(srcData) which will give you the size of the pointer and not of the data it points to.
You should use strlen(srcData)+1 instead (+1 for the \0).
Or use std::string and std::string::size() (Also with +1 for the null terminator).
I have an ugly code for this stuff (create a c char pointer and copy the QString in it) but maybe ... exist in QT an elegant way ...
actual code :
QString maquina is a method parameter.
char *c_maquina = new char[maquina.length() + 1];
strcpy(c_maquina, maquina.toStdString().c_str());
just for information I need a REAL char* not a simple const char* so this code not work :
idMaquina.toLatin1().data();
I can't use http://developer.qt.nokia.com/faq/answer/how_can_i_convert_a_qstring_to_char_and_vice_versa
This is simple:
QByteArray array = string.toLocal8Bit();
char* buffer = array.data();
You can also use toLatin1 or toUtf8 instead of toLocal8Bit. Note that neither of them can be queued with data call. And toStdString().c_str() is also invalid. This is because any QByteArray or std::string produced in such a way is temporary and will be destroyed immediately destroying char buffer with it. You need to store QByteArray in a local variable while you're using the buffer.
Also note that Qt provides QByteArray class to deal with char arrays. Generally there is no need to use char*, you can do almost anything with QByteArray.
I think the solution depends on the type of the characters to be converted, and whether a C-style function with "char *" type arguments needs to be integrated/called.
If a C-style function needs to be integrated/called, do not use toStdString() followed by c_str(), as the return value type is "const char *" which is not suitable for a C-style function.
Use toLatin1() followed by data() for ASCII characters.
Use toLocal8Bit() or toUtf8() followed by data() for other UTF8 characters than ASCII ones.
If several solutions can be used for your specific case, their efficiency levels may be slightly different, which I have not tested.
The following test program shows how to use these solutions:
#include <QCoreApplication>
#include <QDebug>
// This is a C-style test function which needs an argument of type "char *":
void my_c_func(char * my_c_str)
{
printf(" my_c_str[%s]\n", my_c_str);
}
// This is a program which tests the conversion from "QString" to "char *":
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
// Case 1: ASCII characters
// ========================
QString qString1 = "French";
qDebug().nospace().noquote() << "qString1[" << qString1 << "]"; // qString1[French]
// Solution 1.1: to Latin1 QByteArray, followed by data() in 2 steps:
QByteArray latin1BAString1 = qString1.toLatin1();
char * latin1_c_str1 = latin1BAString1.data();
qDebug().nospace().noquote() << "latin1_c_str1[" << latin1_c_str1 << "]"; // latin1_c_str1[French]
my_c_func(latin1_c_str1);
// Solution 1.2: to local 8-bit QByteArray, followed by data() in 2 steps:
QByteArray local8bitBAString1 = qString1.toLocal8Bit();
char * local8bit_c_str1 = local8bitBAString1.data();
qDebug().nospace().noquote() << "local8bit_c_str1[" << local8bit_c_str1 << "]"; // local8bit_c_str1[French]
my_c_func(local8bit_c_str1);
// Solution 1.3: to UTF8 QByteArray, followed by data() in 2 steps:
QByteArray utf8BAString1 = qString1.toUtf8();
char * utf8_c_str1 = utf8BAString1.data();
qDebug().nospace().noquote() << "utf8_c_str1[" << utf8_c_str1 << "]"; // utf8_c_str1[French]
my_c_func(utf8_c_str1);
// !!! Try: Solution 1.4: to std::string , followed by c_str() in 2 steps:
std::string stdString1 = qString1.toStdString();
const char * stdstring_c_str1 = stdString1.c_str(); // "const" must be used !
qDebug().nospace().noquote() << "stdstring_c_str1[" << stdstring_c_str1 << "]"; // stdstring_c_str1[French]
// invalid conversion from 'const char*' to 'char*': ---> NOT GOOD for use by a C-style function !!!
// my_c_func(stdstring_c_str1);
qDebug() << "";
// Case 2: Non-ASCII characters
// ============================
QString qString2 = "français";
qDebug().nospace().noquote() << "qString2[" << qString2 << "]"; // qString2[français]
// !!! Try: Solution 2.1: to Latin1 QByteArray, followed by data() in 2 steps:
QByteArray latin1BAString2 = qString2.toLatin1();
char * latin1_c_str2 = latin1BAString2.data();
qDebug().nospace().noquote() << "latin1_c_str2[" << latin1_c_str2 << "]"; // latin1_c_str2[fran?ais] ---> NOT GOOD for non-ASCII characters !!!
my_c_func(latin1_c_str2);
// Solution 2.2: to Local 8-bit QByteArray, followed by data() in 2 steps:
QByteArray local8bitBAString2 = qString2.toLocal8Bit();
char * local8bit_c_str2 = local8bitBAString2.data();
qDebug().nospace().noquote() << "local8bit_c_str2[" << local8bit_c_str2 << "]"; // local8bit_c_str2[français]
my_c_func(local8bit_c_str2);
// Solution 2.3: to UTF8 QByteArray, followed by data() in 2 steps:
QByteArray utf8BAString2 = qString2.toUtf8();
char * utf8_c_str2 = utf8BAString2.data();
qDebug().nospace().noquote() << "utf8_c_str2[" << utf8_c_str2 << "]"; // utf8_c_str2[français]
my_c_func(utf8_c_str2);
// !!! Try: Solution 2.4: to std::string, followed by c_str() in 2 steps:
std::string stdString2 = qString2.toStdString();
const char * stdstring_c_str2 = stdString2.c_str(); // "const" must be used !
qDebug().nospace().noquote() << "stdstring_c_str2[" << stdstring_c_str2 << "]"; // stdstring_c_str2[français]
// invalid conversion from 'const char*' to 'char*': ---> NOT GOOD for use by a C-style function !!!
// my_c_func(stdstring_c_str2);
return a.exec();
}
The above code has been tested using Qt 5.4 for Linux.
A second subject involved in this question is whether we can chain functions together during this 2-step conversion process:
<myQString>.to<AnotherClass>().<getCPointer>(); // OK or not?
I think this depends on "AnotherClass" and on the type of characters to be converted. Based on some documentation on QString, QByteArray and std::string, it appears that it is safe to write:
<myQString>.toStdString().c_str(); // OK.
<myQString>.toUtf8().data(); // Should be OK as QString is Unicode string.
But the following lines should be avoided:
<myQString>.toLocal8Bit().data(); // May crash if the converted QByteArray object is undefined !
<myQString>.toLatin1().data(); // May crash if the converted QByteArray object is undefined !
I use this in my code all the time
char * toCharP(QString in)
{
QByteArray a; a.append(in);
return a.data();
}
QString::toLatin1().data() gives you a const char* because it gives you its internal buffer. The reason it's const is because you're not supposed to modify it.
So if you want to modify it, you have to copy that data to some other buffer... such as that one you just allocated using new().
std::vector<char> result;
result.reserve( qstr.length()+1 ); // +1 might not be needed, not sure how QString counts
result.insert( result.end(), qstr.begin(), qstr.end() );
char* ptr = result.data(); // while retval exists, retval.data() is a char* pointing to a buffer
QByteArray contains a non const version of data(). See:
http://qt-project.org/doc/qt-5.0/qtcore/qbytearray.html#data
Sometimes, there's just no way to keep your code at top beauty. Deal with it. You might wrap it in a little helper function, taking QString in parameter and returning char*, if you really want.