0

I am tring to read couple of bytes from byteData as mentioned below in my C++ code. The actual value within byteData is a binary blob byte array in BIG-ENDIAN byte order format. So I cannot simply just "cast" the byte array into a String..

byteData byte array is composed of these three things -

First is `schemaId` which is of two bytes (short datatype in Java)
Second is `lastModifiedDate` which is of eight bytes (long datatype in Java)
Third is the length of actual `byteArray` within `byteData` which we need from `byteData`.
Fourth is the actual value of that `byteArray` in `byteData`.

Now I am trying to extract the above particular information from the byteData in C++... Somehow I am able to extract schemaId and the value which I am getting is also correct.. Now I am not sure how to extract other things from it...

uint16_t schemaId;
uint64_t lastModifiedDate;
uint16_t attributeLength; // or it should be uint32_t?
const char* actual_binary_value;

while (result.next()) {
    for (size_t i = 0; i < result.column_count(); ++i) {
        cql::cql_byte_t* byteData = NULL;
        cql::cql_int_t size = 0;
        result.get_data(i, &byteData, size);

        // I cannot just "cast" the byte array into a String
        // value = reinterpret_cast<char*>(byteData);

        // this works fine
        schemaId = ntohs(*reinterpret_cast<uint16_t*>(byteData));

        // now how to retrieve lastModifiedDate, length of binary value and actual_binary_value from byteData?
        // the below doesn't works..
           lastModifiedDate = be64toh(*reinterpret_cast<uint64_t*>(data));

        // And how to extract other things as well?

    }

    // this prints out `9223090561897746107`  but it should print out `1289811105109`
    cout<< lastModifiedDate <<endl;

    // And print out other things..
}

If somebody needs to see my java code then this is my java code -

    byte[] avroBinaryValue = text.getBytes();

    long lastModifiedDate = 1289811105109L;
    short schemaId = 32767;

    int size = 2 + 8 + 4 + avroBinaryValue.length; // short is 2 bytes, long 8 and int 4

    ByteBuffer bbuf = ByteBuffer.allocate(size); 
    bbuf.order(ByteOrder.BIG_ENDIAN);

    bbuf.putShort(schemaId);
    bbuf.putLong(lastModifiedDate);
    bbuf.putInt(avroBinaryValue.length);
    bbuf.put(avroBinaryValue);

    // merge everything into one bytearray.
    byte[] bytesToStore = bbuf.array();

    Hex.encodeHexString(bytesToStore)

Can anybody help me what wrong I am doing in my C++ code and why I am not able to extract lastModifiedDate properly from it and other fields as well? As I understand lastModifiedDate is 64 bit integer, so is there any way to swap out 64 bit integer here? Or some other better way to do the conversion?

In short, I am trying to extract schemaId, lastModifiedDate, avroBinaryValue.length and avroBinaryValue from that byte array in C++..

I am able to extract schemaId but I am stuck on other things now...

AKIWEB
  • 16,538
  • 58
  • 164
  • 276
  • possible duplicate of [How to extract individual fields from byte array (which is in BIG-ENDIAN) in C++](http://stackoverflow.com/questions/19392004/how-to-extract-individual-fields-from-byte-array-which-is-in-big-endian-in-c) – Jonathan Potter Oct 16 '13 at 02:01
  • @JonathanPotter: In that question I was asking about schemaId and other stuff I agree but some guy suggested me to look for how to swap 64 bit integer to extract lastModifiedDate from it and I did some research and I was not able to figure out... So that's why posted as a new question here.. – AKIWEB Oct 16 '13 at 02:18

1 Answers1

1

Your method looks fine, there are just two possible issues I see.

  1. Your code as shown is simply casting an undefined variable data as a uint64_t. Make sure that you are actually advancing through the data buffer and converting the correct data.

  2. Platform dependency. From what I've seen, the 64-bit byte swapping functions (be64toh, betoh64, ntohll, etc), are not universally supported on all platforms. You may need to use a different function on your platform, and/or automatically detect what works if you want the code to be platform independent. See similar questions here and here, for example.

As to how to get the data, something like this should work:

int index=0;
schemaId = ntohs(*reinterpret_cast<uint16_t*>(&byteData[index]));
index += 2;
lastModifiedDate = be64toh(*reinterpret_cast<uint64_t*>(&byteData[index]));
index += 8;
attributeLength = ntohl(*reinterpret_cast<uint32_t*>(&byteData[index]));
index += 4;
actual_binary_data = (const char *)&byteData[index];
Community
  • 1
  • 1
Chris Olsen
  • 2,494
  • 19
  • 35
  • Thanks for suggestion... In corresponding to your first point, am I doing something wrong? And we cannot swap the bits manually instead of using some predefined functions? – AKIWEB Oct 16 '13 at 04:30
  • Updated answer with example code. Re: manual swapping, you should probably avoid it and use a library function when possible. The code will be more portable. – Chris Olsen Oct 16 '13 at 05:28
  • Thanks for suggestion.. I am stuck on this problem since two days.. As my background is in Java so finding it little bit hard time to figure out all these things.. Thanks for the help.. But after compiling the above code, this is what I am getting in an exception - `error: invalid static_cast from type cql::cql_byte_t* {aka unsigned char*} to type uint16_t* {aka short unsigned int*} ` Any idea what's wrong? – AKIWEB Oct 16 '13 at 05:35
  • Sorry, wrong cast type. You can use reinterpret_cast, or just implicit cast. – Chris Olsen Oct 16 '13 at 05:54
  • Thanks a lot Chris for the help.. Appreciated your help on this.. It works fine now.. One last thing I wanted to know here is- In `attributeLength` you are using `uint32_t*`, I am not sure whether we should be using `uint32_t*` or `uint16_t*`.. Meaning why you decided to go with `uint32_t*`.. Sorry for asking dumb question... Any thoughts? – AKIWEB Oct 16 '13 at 19:07
  • Glad you got it working. To avoid corrupted data, you need to make sure to read the data fields back in using the same sizes as they were written. `attributeLength` was written as a 32-bit java int, so you need to read it back as a 32-bit value. – Chris Olsen Oct 16 '13 at 21:39