Showing posts with label source. Show all posts
Showing posts with label source. Show all posts

Sunday, February 2, 2014

Very Simple Base64 Reader

I've written this very simple Base64 reader. I wrote this as part of my loader for Tiled Map Editor files (see mapeditor.org). The code is very simple, but it works. The out_binary_data parameter is unsigned char * for simplicity as the code works in 8 bit chunks. Tiled actually uses 32 bit int variables so the pointer will need to be cast to int *. If you have anymore questions about the code, just leave a comment.


// converts a 6 bit value into the Base64 ASCII equivalent
unsigned char ASCIITo_6BitVal(char ch)
{
 if((ch >= 'A') && (ch <= 'Z')) return ch - 'A';
 else if((ch >= 'a') && (ch <= 'z')) return (ch - 'a') + 26;
 else if((ch >= '0') && (ch <= '9')) return (ch - '0') + 52;
 else if(ch == '+') return 62;
 else if(ch == '/') return 63;
 else if(ch == '=') return 64;
 else return 65;
}

// converts binary data to Base64, If the data will be used on a platform with a different endianness, the
// data 32 bit integers or the decoder will not be able to switch the endianness automatically
int Base64Binary(const char *in_base64_data, unsigned int in_base64_data_length,
                 unsigned char *out_binary_data, unsigned int in_binary_buffer_length, unsigned int &out_binary_data_length)
{
 out_binary_data_length = 0;

 for(unsigned int i = 0; i < in_base64_data_length; i += 4)
 {
  bool end_found = false;
  unsigned char b64_byte1 = ASCIITo_6BitVal(in_base64_data[i]);
  if(b64_byte1 > 63) return 1; // stop processing
  unsigned char b64_byte2 = ASCIITo_6BitVal(in_base64_data[i+1]);
  if(b64_byte2 > 63) return -1;
  unsigned char b64_byte3 = ASCIITo_6BitVal(in_base64_data[i+2]);
  if(b64_byte3 > 64) return -1; // this could be the end of the stream so it could also be '='
  unsigned char b64_byte4 = ASCIITo_6BitVal(in_base64_data[i+3]);
  if(b64_byte4 > 64) return -1; // this could be the end of the stream so it could also be '='

  int size = 3;
  // check for the end
  if(b64_byte4 == 64)
  {
   size = 2;
   end_found = true;
   b64_byte4 = 0;
  }
  if(b64_byte3 == 64)
  {
   size = 1;
   end_found = true;
   b64_byte3 = 0;
  }

  if(in_binary_buffer_length < (out_binary_data_length + size))
  {
   // the buffer is too small
   return -2;
  }

  out_binary_data[out_binary_data_length + 0] = (b64_byte1 << 2) | ((0x30 & b64_byte2) >> 4);
  if(size > 1)out_binary_data[out_binary_data_length + 1] = ((0xF & b64_byte2) << 4) | ((0x3C & b64_byte3) >> 2);
  if(size > 2)out_binary_data[out_binary_data_length + 2] = ((0x3 & b64_byte3) << 6) | b64_byte4;

  out_binary_data_length += size;

  if(end_found) break;
 }

 return 0;
}