PDA

View Full Version : Read ByteArray



kewlcode
4th April 2009, 10:13
I have a ByteArray . I want to read the content and know its equivalent no. e.g.

if bytearray has 255 as its first member then i want to read the first member and the value (i.e. 255) assigned to an integer.

aamer4yu
4th April 2009, 10:20
Have a look at QByteArray::toInt

kewlcode
4th April 2009, 14:33
Thanks Aamer for replying.

I am confused by QByteArray::toInt . Does it return one integer or an array of integers? The bytearray consists of many bytes. How do i convert all of them to integers?

Boron
4th April 2009, 16:07
I don't see your problem :confused:.
If you access an element of the QByteArray by at() or with operator [] you get a "char". And a char is a signed 8 bit value.

So it is not necessary to convert the QByteArray to an array of integers as the elements can simply be used as if they were integers

Example:
QByteArray ba("Hello");
int sum = 0;

// Sum up the ascii values of "Hello"
for( int i = 0; i < ba.size(); i++ )
{
sum += ba[i];
}If the example makes sense is another story, but I am simply interpreting whatever ba[i] returns as an integer.

Concerning the toInt() method:
This method tries to return an integer value represented by the bytes in the QByteArray.
As the example in the Qt docs shows if the QByteArray is "FF" and you call array.toInt(&ok, 16); You want the array to be considered as hexadecimal value. So toInt() returns the integer value 255.
If the array is "FZ" and you call array.toInt(&ok, 16); the method tells you with ok == false that "FZ" is not a hex value.

So with toInt() you can "make" an integer out of an array of bytes. Just like QString::toInt() would make it. Difference is that QString uses unicode characters an QByteArray holds bytes (chars).

Confused enough ;)?

kewlcode
4th April 2009, 16:51
Boron,
thanks for your reply.

Had checked out the "FF" example in the docs. It is fine if it is just one byte i.e. FF.
My byte array suppose contains bytes like -> FF 2 3 25 10 etc. How do I check if the value is FF or 10 etc. ?
An example which failed ->


for( int i = 0; i < ba.size(); i++ )
{
if (ba[i] == 255){
//pte1->appendPlainText (".......OK....");
}
}


This gives the error

C:/Users/vinay/Prog/telnetpro/telnetpro/telnetpro.cpp:61: error: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:

for the line if (ba[i] == 255){

:confused:

tia

aamer4yu
4th April 2009, 17:43
You cauld convert the element to int first.

something like -

int value = ba.at(i);
if(value == 255)
...

hope you get the idea

kewlcode
4th April 2009, 18:39
Aamer,

Thx .

What you suggested works for smaller values but not for higher values in the byte array. I have a suspicion it fails for values above 127 in the byte array.

Still :confused:

talk2amulya
4th April 2009, 19:00
it wont fail for those values..would u care to show us some of ur relevant code snippet?

kewlcode
4th April 2009, 19:17
I am trying to connect to a telnet host. I have a simple form with 'pte1' plaintextedit box and a 'pb1' pushbutton. When I click pb1 pushbutton it establishes connection to host 10.10.1.10 and read the data that arrives on the TcpSocket telcli. The telnet protocol sends some data which includes byte '255' etc.
In the below code it never prints OK on the plaintextedit box.
I am using
pte1->appendPlainText (QString::number(value));

to examine the value of the integer and it prints -1 , -5 etc for (I beleive) values higher than 127.


#include "telnetpro.h"
#include "ui_telnetpro.h"


#include <QtGui>


telnetpro::telnetpro(QWidget *parent)
: QWidget(parent), ui(new Ui::telnetproClass)
{
setupUi(this);
connect( pb1, SIGNAL( clicked()),this, SLOT(starttel() ) );
connect( &telcli, SIGNAL( readyRead() ),this, SLOT(readtel() ) );
}

void telnetpro::starttel()
{

telcli.connectToHost("10.10.1.10",23);

}

void telnetpro::readtel()
{

QByteArray ba;
int i ;
int value;
ba = telcli.readAll();

pte1->appendPlainText ("BEGIN");


for( int i = 0; i < ba.size(); i++ )
{
value = ba.at(i);
if (value > 200){
pte1->appendPlainText (".......OK....");
}
pte1->appendPlainText (QString::number(value));
}

pte1->appendPlainText (".......OVER....");

}

telnetpro::~telnetpro()
{
telcli.close();
delete ui;
}

kewlcode
4th April 2009, 19:20
Sorry the above post is a bit messed up. Posting again the same thing.




I am trying to connect to a telnet host. I have a simple form with 'pte1' plaintextedit box and a 'pb1' pushbutton. When I click pb1 pushbutton it establishes connection to host 10.10.1.10 and read the data that arrives on the TcpSocket telcli. The telnet protocol sends some data which includes byte '255' etc.
In the below code it never prints OK on the plaintextedit box.
I am using
pte1->appendPlainText (QString::number(value));

to examine the value of the integer and it prints -1 , -5 etc for (I beleive) values higher than 127.


#include "telnetpro.h"
#include "ui_telnetpro.h"

#include <QtGui>

telnetpro::telnetpro(QWidget *parent)
: QWidget(parent), ui(new Ui::telnetproClass)
{
setupUi(this);
connect( pb1, SIGNAL( clicked()),this, SLOT(starttel() ) );
connect( &telcli, SIGNAL( readyRead() ),this, SLOT(readtel() ) );
}

void telnetpro::starttel()
{

faldzip
4th April 2009, 19:52
If you want just to print the telnet output just append QString made of QByteArray.

If you want to get integers from QByteArray then its more complicated. For example when you get some data as QByteArray from Q*Socket, and that data contains some ints, then you need to know some additional info. The length of a integer is usual 32-bit which gives 4 bytes. Then that int can be stored as little-endian or big-endian - which describes the order of that 4 bytes:

Hex int can be :


someInt = 0xAABBCCDD;

and you can get data:


AA BB CC DD

or


DD CC BB AA

now you need to construct the integer from it. For example something like this:


qint32 result = 0;
for (int i = 0; i < 4; ++i)
result |= ((qint32)data[i] & 0x000000ff) << (i * 8);

I dont know if its the best way but it's a code snippet from one of my old projects and it was working :]

P.S. And use CODE tags ([#] button) for pasting code.

kewlcode
4th April 2009, 20:20
Finally it worked. I think I was getting -ve numbers for values more than 127 e.g. I would get -1 for 255. When I added 256 to any -ve values it is ok .

Thanks to all of you.


void telnetpro::readtel()
{

QByteArray ba;
int i ;
int value , val1;
ba = telcli.readAll();
pte1->appendPlainText ("BEGIN");

for( int i = 0; i < ba.size(); i++ )
{
value = ba.at(i);
if (value < 0) {
val1 = value + 256;
}
else {
val1=value;
}
if (val1 > 200){
pte1->appendPlainText (".......OK....");
}
pte1->appendPlainText (QString::number(val1));
}

pte1->appendPlainText (".......OVER....");

}

talk2amulya
4th April 2009, 20:30
so were u trying to read characters or integers?cuz the right way to read integers over internet or through a bytearray is how faldżip explained...

aamer4yu
4th April 2009, 21:08
May be you can try the following too-
1.QByteArray::toUInt

QByteArray b = ba.at(i);
int value = b.toUint();

or
2.

quint32 value = ba.at(i);

talk2amulya
4th April 2009, 21:31
May be you can try the following too-
1.QByteArray::toUInt

QByteArray b = ba.at(i);
int value = b.toUint();

or
2.

quint32 value = ba.at(i);


i dont think those methods are gonna be useful if u r trying to find an int..for the first method, at() returns a char..u cant convert a char into QByteArray..no such constructor for QByteArray..for the second method, again its just converting one char to whole int..which is wrong when one knows the whole value of an integer is in 4/8 bytes depending on the architecture, not just one byte!..method that faldzip posted is correct one for reading integers..but in this case, i guess kewlcode is reading characters and interpreting them as integers

aamer4yu
5th April 2009, 06:27
i dont think those methods are gonna be useful if u r trying to find an int..for the first method, at() returns a char..u cant convert a char into QByteArray..no such constructor for QByteArray
I was a bit confused by QByteArray::QByteArray ( const char * str )

for the second method, again its just converting one char to whole int..which is wrong when one knows the whole value of an integer is in 4/8 bytes depending on the architecture, not just one byte!..
Havent you ever come across a assignment like

char ch;
switch(ch)
{ case 'a' : // case is evaluated in terms of int, right ? So dont you think an internal conversion from char to int is being done ? Is it wrong way ?
}
or int a = 'a';
You are right int is 4/8 bytes and char is 1 byte. However how you convert and use, depends on you.

method that faldzip posted is correct one for reading integers.
Lets do a walkthrough...

qint32 result = 0;
for (int i = 0; i < 4; ++i)
result |= ((qint32)data[i] & 0x000000ff) << (i * 8);

he too is converting data[i] to qint32 , ie., integer !!. The success of above code lies in the mask. It will just cut off the negative signature.
Lets say we '01' in data[i]. After typecast, it gets converted to '0000 0001'. Pay heed to the shift number (i*8). What happens if you shift '0000 0001' eight times ? You get the same number !! Even say '0000 0012' you will get '0000 0012'. And since you are doing it in multiples of eight, it wont matter how many times you do it. !!
So why is it working ? (qint32)data[i] & 0x000000ff is the answer. I guess the whole loop sums down to

result = ((qint32)data[i] & 0x000000ff)


.but in this case, i guess kewlcode is reading characters and interpreting them as integers
Ofcourse, thats why I had given the conversion quint32 value = ba.at(i);
By the way, for telnet purposes, it will be better to use unsigned values. If you have Qt Solutions, you might find qttelnet example. Even there they have used uchar :)
Heres the line
const uchar c = uchar(data[currpos]);. You can guess data was QByteArray data = buffer.readAll();

talk2amulya
5th April 2009, 07:32
hey :) all i was trying to say is when one end, i.e. telnet here, is sending an integer, it is sending 4 bytes to represent a particular value..so its just a bit weird to just read one byte and say we read integer..either the other end is sending bytes which are to be interpreted as integers or chars..here u r interpreting it as integer but still reading them as char and converting them to integers..thats all my point..nothing to aggravate u :) cheers!

faldzip
5th April 2009, 08:21
Lets do a walkthrough...

qint32 result = 0;
for (int i = 0; i < 4; ++i)
result |= ((qint32)data[i] & 0x000000ff) << (i * 8);

he too is converting data[i] to qint32 , ie., integer !!. The success of above code lies in the mask. It will just cut off the negative signature.
Lets say we '01' in data[i]. After typecast, it gets converted to '0000 0001'. Pay heed to the shift number (i*8). What happens if you shift '0000 0001' eight times ? You get the same number !! Even say '0000 0012' you will get '0000 0012'. And since you are doing it in multiples of eight, it wont matter how many times you do it. !!
So why is it working ? (qint32)data[i] & 0x000000ff is the answer. I guess the whole loop sums down to

result = ((qint32)data[i] & 0x000000ff)

Are '0000 0001' and '0000 0012' in HEX? It looks like hex cause then it gives 4 bytes. So if it's in hex then what is a result of shifting '0000 0012' eight times? The answer is '0000 1200' so it's not the same number, it's multiplied by 2^8 = 256. So do the walkthrough again. Here is what we get in data (bytes written with HEX):

AA BB CC DD
now we have a result = 0; which is in hex = 00 00 00 00;
then we have a for loop (4 rounds):
1. we take AA and convert it to the qint32:

AA => 00 00 00 AA
then we cut the first byte with 00 00 00 FF to cut out the negative FFs (for byte negative values converted to int), then shifting it 0*8 = no shift :]
We have now:

result == 00 00 00 AA;
2. almost the same but before logical sum (|=) we shift the '00 00 00 BB' by 8 so we get '00 00 BB 00', after logical sum with '00 00 00 AA' we get:

result == 00 00 BB AA;
and so on...
at the end we get:

result == DD CC BB AA;
so we constructed one 4 byte integer from 4 bytes (normally interpreted as chars) sotred in QByteArray. :]

aamer4yu
5th April 2009, 10:12
My Mistake !!
You know I was sleeping before and after that post I had made. Now when I woke up, I realised I was writing in terms of hex, and still using only a byte !! thats why the confusion :D

By the way, few questions..
I guess you are assuming an int will take 4 indexes in bytearray ?
And if the original number was 0xAABBCCDD, the result is 0xDDCCBBAA, isnt it ? What endian or protocol are u assuming while sending and receiving data ?

talk2amulya
5th April 2009, 10:41
Through the network, data is always in network byte order,I.e. Big endian