Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

char* (Array) cast to unsigned long + 1?

I'm trying to port some C code to Java, however I've been struggling to figure out what these lines of code do.

Note: rawEntry is of type char* and appears to be a 12 bytes long allocated as such

char *rawEntry = (char*)malloc(0x000c);

unsigned long *l;
unsigned long offset;

// ...

l = (unsigned long*) rawEntry + 1;
offset = ntohl(*l);

As far as I can tell, it takes the first four items of the array, and puts them together to form a long, however my attempts in java have been less than successful.

offset = (rawEntry[0] << 24) +
         (rawEntry[1] << 16) +
         (rawEntry[2] << 8) +
         (rawEntry[3]) +
         1;

When presented with the following array,

1 0 0 0 0 0 0 0 0 0 11 -38

The C code outputs 3034 as the offset
My Java code outputs 16777217, or 1 if I flip the endian

like image 415
CraftedCart Avatar asked Mar 10 '23 14:03

CraftedCart


2 Answers

This expression

l = (unsigned long*) rawEntry + 1;

casts rawEntry to pointer to a type that has size of 8 bytes on your system. After that, adding 1 means adding 8 bytes, so the actual conversion looks like this:

offset = (Byte.toUnsignedInt(rawEntry[ 8]) << 24) +
         (Byte.toUnsignedInt(rawEntry[ 9]) << 16) +
         (Byte.toUnsignedInt(rawEntry[10]) <<  8) +
         (Byte.toUnsignedInt(rawEntry[11]) <<  0);

The following four bytes are interpreted as 3034:

0 0 11 -38

You should be able to simplify this further by using ByteBuffer:

int offset = ByteBuffer.wrap(rawEntry, 8, 4).getInt();
like image 199
Sergey Kalinichenko Avatar answered Mar 14 '23 21:03

Sergey Kalinichenko


Before going further it is important to note that this code depends on the actual magnitude of a long on your platform. On 64 bits platforms longs are 64 bits, that is a long takes up 8 bytes. On the other hand ntohl converts a “network long” that is 32 bits long (4 bytes).

Assuming rawEntry is {1,0,0,0,0,0,0,0,0,0,0xB,0xDA,…} (0xB is the base 16 equivalent of 11, 0xDA is the base 16 (hexadecimal) unsigned value that corresponds to -38)

l = (unsigned long*) rawEntry + 1;

really means that l refers to the second unsigned long. That is skip the first 8 bytes from rawEntry and l then points to the {0,0,0xB,0xDA,…} part. Now *l is the unsigned long represented by the {0,0,0xB,0xDA,…} bytes sequence and it is dependent on your architecture. If you are on a little endian machine that will be 0x…DA0B0000 (ellipsis because the end of the array is unkown, that is undefined behaviour). And now ntohl will just keep the last 32 bits and invert the bytes order resulting in 0x00000BDA or 3034 in base 10.

The easy way to write this in Java would be

offset = (rawEntry[8] << 24) +
         (rawEntry[9] << 16) +
         (rawEntry[10] << 8) +
         (rawEntry[11]);
like image 25
kmkaplan Avatar answered Mar 14 '23 22:03

kmkaplan