3
votes

I've searched and searched stackoverflow for the answer, but have not found what I needed.

I have a routine that takes an unsigned char array as a parameter in order to encode it as Base64. I would like to encode an STL float vector (vector) in Base64, and therefore would need to reinterpret the bytes in the float vector as an array of unsigned characters in order to pass it to the encode routine. I have tried a number of things from reinterpret and static casts, to mem copies, etc, but none of them seem to work (at least not the way I implemented them).

Likewise, I'll need to do the exact opposite when decoding the encoded data back to a float array. The decode routine will provide the decoded data as an unsigned char array, and I will need to reinterpret that array of bytes, converting it to a float vector again.

Here is a stripped down version of my C++ code to do the encoding:

std::string
EncodeBase64FloatVector( const vector<float>& p_vector )
{
  unsigned char* sourceArray;

  // SOMEHOW FILL THE sourceArray WITH THE FLOAT VECTOR DATA BITS!!

  char* target;
  size_t targetSize = p_vector.size() * sizeof(float);
  target = new char[ targetSize ];

  int result = EncodeBase64( sourceArray, floatArraySizeInUChars, target, targetSize );

  string returnResult;
  if( result != -1 )
  {
    returnResult = target;
  }
  delete target;
  delete sourceArray;
  return returnResult;
}

Any help would be greatly appreciated. Thanks.

Raymond.

3
Are you making an assumption about big-endian vs. little-endian?Michael Myers
@mmyers: Of course he is, but he might not realize it yet. Also an assumption about floating point format (IEEE, presumably). Hopefully it is for data that is passed around to similar machines, because it would be a pain in a mixed environment.Mark Ransom
Yes, for now I'm assuming the same endian and fp format.Raymond

3 Answers

8
votes

std::vector guarantees the data will be contiguous, and you can get a pointer to the first element in the vector by taking the address of the first element (assuming it's not empty).

typedef unsigned char byte;
std::vector<float> original_data;
...
if (!original_data.empty()) {
  const float *p_floats = &(original_data[0]);  // parens for clarity

Now, to treat that as an array of unsigned char, you use a reinterpret_cast:

  const byte *p_bytes = reinterpret_cast<const byte *>(p_floats);
  // pass p_bytes to your base-64 encoder
}

You might want to encode the length of the vector before the rest of the data, in order to make it easier to decode them.

CAUTION: You still have to worry about endianness and representation details. This will only work if you read back on the same platform (or a compatible one) that you wrote with.

5
votes
sourceArray = reinterpret_cast<const unsigned char *>(&(p_vector[0]))
0
votes

I would highly recommend checking out Google's protobuf to solve your problem. Floats and doubles can vary in size and layout between platforms and that package has solved all those problems for you. Additionally, it can easily handle your data structure should it ever become more complicated than a simple array of floats.

If you do use that, you will have to do your own base64 encoding still as protobuf encodes data assuming you have an 8-bit clean channel to work with. But that's fairly trivial.