LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Byte array conversion (https://www.linuxquestions.org/questions/programming-9/byte-array-conversion-756887/)

yaplej 09-21-2009 07:32 PM

Byte array conversion
 
Hello,

I am trying to convert a variable array of bytes to an unsigned long int. The number of bytes is passed into the function as tcpoptlen. Manually converting the first type bytes in the array works fine, but trying to convert n bytes crashes.

This worked to convert the first two bytes into a unsigned long integer.
Code:

tcpoptdata = (opt[i+2] << 8) | opt[i+3];

Code:

u_int64_t tcpoptdata;
u_int8_t bytefield;
u_int8_t count;

 /* if the option exists, but data length is 2  */
    if (tcpoptlen == 2)
          return 1;       
    else
                                       
    tcpoptdata = 0;
    count = tcpoptlen - 2;
    bytefield = 2;
                                       
    while (count > 0) {
                                               
          tcpoptdata |= opt[i + bytefield];
          if (((tcpoptlen - bytefield) - 1) != 0)
              tcpoptdata <<= (8 * ((tcpoptlen - bytefield) - 1));
                                               
          count =- 1;
          bytefield =+ 1;
 
}
                                       
return tcpoptdata;


smeezekitty 09-21-2009 09:35 PM

how big is a unsigned long?
if its 64 bits:
Code:

tcpoptdata =
(opt[i+2]<<56) + (opt[i+3]<<48) + (opt[i+4]<<40) + (opt[i+5]<<32)+
(opt[i+6]<<24) + (opt[i+7]<<16) + (opt[i+8]<<8) | (opt[i+9]&0xFE);

that should do it
i just reread your post
replace j with the number you want to convert
Code:

tcpoptdata = ((j > 0)*
(opt[i+2]<<56)) + ((j > 1)*(opt[i+3]<<48)) + ((j > 2)*(opt[i+4]<<40)) + ((j>3)*(opt[i+5]<<32))+
((j>4)*(opt[i+6]<<24)) + ((j>5)*(opt[i+7]<<16)) + ((j>6)*(opt[i+8]<<8)) | ((j>7)*(opt[i+9]&0xFE));


pixellany 09-22-2009 08:41 AM

Moved: This thread is more suitable in <Programming> and has been moved accordingly to help your thread/question get the exposure it deserves.

carbonfiber 09-22-2009 09:31 AM

Hello. What exactly does each byte represent? What is the type of opt? Why are you not using uint64_t, uint8_t (stdint.h)?

yaplej 09-22-2009 11:57 AM

opt is an unsigned char(edit actually it looks like an array of chars). tcpopelen defines how many bytes are storing bitwise data. I need to take each byte as a field, and contantonate them together so the bits remain the same in integer form.

tcpoptlen = 2 so its two bytes or 16-bit the value is 65000 or byte[1] = 11111101, byte[2] = 11101000. I need to convert them back into an integer = 1111110111101000

At least I think thats how it work. I thought it would be easier to start with reading the into before I started trying to write to opt[].

carbonfiber 09-22-2009 12:39 PM

I'm (still) guessing you're looking for something along these lines:

Code:

/* warning: the following convert function makes many gross assumptions. */

#include <stdio.h>

unsigned long convert(const unsigned char *s, size_t sz)
{     
        unsigned long data = s[0];
        for (size_t i = 1; i < sz; ++i)
                data = (data << 8) | s[i];

        return data;
}

int main()
{     
        unsigned char s[] = { 0x07, 0xF8, 0x94, 0x09 };
        printf("%lu\n", convert(s, sizeof(s)));
        return 0;
}


yaplej 09-22-2009 04:50 PM

Well I am finally getting there. My test data is tcpoplen = 4, and opt[i+2] + opt[i+3] = the 16-bit binary value of 1460.

It works(meaning not crashing the system), but the data I get is 1461 not 1460 like it should be. So the problem is with my routine that converts the bytes into a single integer value.


Code:

   
u_int64_t tcpoptdata;
u_int8_t bytefield;
u_int8_t count;

/* if the option exists, but data length is 2  */
    if (tcpoptlen == 2)
          return 1;       
    else
                                       
    count = opt[i+1] - 2; // get option length from header,
                          // and ignore header fields.
    bytefield = 2;  // the first data byte is always at i+2.
    tcpoptdata = 0; // initialize tcpoptdata.
                                       
                                       
                       
    while (count > 0) {
          count--;
          if ((count) != 0) {
              tcpoptdata += (opt[i+bytefield] << 8 * count);
          }
          else {
              tcpoptdata += opt[i+bytefield];
          }       
                                       
          bytefield++;
    }
                                       
    tcpoptdata |= opt[i+bytefield];       
                                       

return tcpoptdata;


yaplej 09-22-2009 05:42 PM

Fixed it! Had to add "& 0xFE" to this line. Not sure what that does, but it is now returning the correct result for any byte length tcp option.

Code:

tcpoptdata |= opt[i+bytefield];
Code:



u_int64_t tcpoptdata;
u_int8_t bytefield;
u_int8_t count;

/* if the option exists, but data length is 2  */
    if (tcpoptlen == 2)
          return 1;       
    else
                                       
    count = opt[i+1] - 2; // get option length from header,
                          // and ignore header fields.
    bytefield = 2;  // the first data byte is always at i+2.
    tcpoptdata = 0; // initialize tcpoptdata.
                                       
                                       
                       
    while (count > 0) {
          count--;
          if ((count) != 0) {
              tcpoptdata += (opt[i+bytefield] << 8 * count);
          }
          else {
              tcpoptdata += opt[i+bytefield];
          }       
                                       
          bytefield++;
    }
                                       
    tcpoptdata |= opt[i+bytefield] & 0xFE;       
                                       

return tcpoptdata;


yaplej 09-23-2009 01:38 PM

Quote:

Originally Posted by carbonfiber (Post 3692939)
Hello. What exactly does each byte represent? What is the type of opt? Why are you not using uint64_t, uint8_t (stdint.h)?

This is done in kernel space so using <stdint.h> is not allowed from what I understand.

smeezekitty 09-23-2009 01:44 PM

Quote:

Originally Posted by yaplej (Post 3694567)
This is done in kernel space so using <stdint.h> is not allowed from what I understand.

stdint sholuld be just a seires of typedefs or #defines
so there is no reason it would not work
but my sugjestion is if it works to fool with it


All times are GMT -5. The time now is 09:22 AM.