cleanup of code for Base64 encoding and decoding
[rocksndiamonds.git] / src / libgame / base64.c
index 46267fd591014e33c2ce482395791404499efb35..485f81bc9e1ce64b4a4f74a566807f605487a2d4 100644 (file)
 
 */
 
+// ----------------------------------------------------------------------------
+// Base64 encoder/decoder code was altered for integration in Rocks'n'Diamonds
+// ----------------------------------------------------------------------------
+
 #include <stdio.h>
 #include <stdlib.h>
 
 #include "base64.h"
 
 
-const static char* b64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ;
-
-// maps A=>0,B=>1..
-const static unsigned char unb64[]={
-  0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //10
-  0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //20
-  0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //30
-  0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //40
-  0,   0,   0,  62,   0,   0,   0,  63,  52,  53, //50
- 54,  55,  56,  57,  58,  59,  60,  61,   0,   0, //60
-  0,   0,   0,   0,   0,   0,   1,   2,   3,   4, //70
-  5,   6,   7,   8,   9,  10,  11,  12,  13,  14, //80
- 15,  16,  17,  18,  19,  20,  21,  22,  23,  24, //90
- 25,   0,   0,   0,   0,   0,   0,  26,  27,  28, //100
- 29,  30,  31,  32,  33,  34,  35,  36,  37,  38, //110
- 39,  40,  41,  42,  43,  44,  45,  46,  47,  48, //120
- 49,  50,  51,   0,   0,   0,   0,   0,   0,   0, //130
-  0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //140
-  0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //150
-  0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //160
-  0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //170
-  0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //180
-  0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //190
-  0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //200
-  0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //210
-  0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //220
-  0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //230
-  0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //240
-  0,   0,   0,   0,   0,   0,   0,   0,   0,   0, //250
-  0,   0,   0,   0,   0,   0,
-}; // This array has 256 elements
-
-// Converts binary data of length=len to base64 characters.
-// Length of the resultant string is stored in flen
-// (you must pass pointer flen).
-char* base64( const void* binaryData, int len, int *flen )
+const static char *b64encode =
+  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+int base64_encoded_size(int unencoded_size)
 {
-  const unsigned char* bin = (const unsigned char*) binaryData ;
-  char* res ;
+  int mod = unencoded_size % 3;
+  int pad = (mod > 0 ? 3 - mod : 0);
 
-  int rc = 0 ; // result counter
-  int byteNo ; // I need this after the loop
+  return 4 * (unencoded_size + pad) / 3 + 1;
+}
 
-  int modulusLen = len % 3 ;
-  int pad = ((modulusLen&1)<<1) + ((modulusLen&2)>>1) ; // 2 gives 1 and 1 gives 2, but 0 gives 0.
+void base64_encode(char *encoded_data,
+                  const void *unencoded_ptr, int unencoded_size)
+{
+  const byte *unencoded_data = (const byte *)unencoded_ptr;
+  char *ptr = encoded_data;
+  int i;
 
-  *flen = 4*(len + pad)/3 ;
-  res = (char*) malloc( *flen + 1 ) ; // and one for the null
-  if( !res )
-  {
-    puts( "ERROR: base64 could not allocate enough memory." ) ;
-    puts( "I must stop because I could not get enough" ) ;
-    return 0;
-  }
+  int mod = unencoded_size % 3;
+  int pad = (mod > 0 ? 3 - mod : 0);
 
-  for( byteNo = 0 ; byteNo <= len-3 ; byteNo+=3 )
+  for (i = 0; i <= unencoded_size - 3; i += 3)
   {
-    unsigned char BYTE0=bin[byteNo];
-    unsigned char BYTE1=bin[byteNo+1];
-    unsigned char BYTE2=bin[byteNo+2];
-    res[rc++]  = b64[ BYTE0 >> 2 ] ;
-    res[rc++]  = b64[ ((0x3&BYTE0)<<4) + (BYTE1 >> 4) ] ;
-    res[rc++]  = b64[ ((0x0f&BYTE1)<<2) + (BYTE2>>6) ] ;
-    res[rc++]  = b64[ 0x3f&BYTE2 ] ;
+    byte byte0 = unencoded_data[i];
+    byte byte1 = unencoded_data[i + 1];
+    byte byte2 = unencoded_data[i + 2];
+
+    *ptr++ = b64encode[byte0 >> 2];
+    *ptr++ = b64encode[((byte0 & 0x03) << 4) + (byte1 >> 4)];
+    *ptr++ = b64encode[((byte1 & 0x0f) << 2) + (byte2 >> 6)];
+    *ptr++ = b64encode[byte2 & 0x3f];
   }
 
-  if( pad==2 )
+  if (pad == 1)
   {
-    res[rc++] = b64[ bin[byteNo] >> 2 ] ;
-    res[rc++] = b64[ (0x3&bin[byteNo])<<4 ] ;
-    res[rc++] = '=';
-    res[rc++] = '=';
+    byte byte0 = unencoded_data[i];
+    byte byte1 = unencoded_data[i + 1];
+
+    *ptr++ = b64encode[byte0 >> 2];
+    *ptr++ = b64encode[((byte0 & 0x03) << 4) + (byte1 >> 4)];
+    *ptr++ = b64encode[((byte1 & 0x0f) << 2)];
+    *ptr++ = '=';
   }
-  else if( pad==1 )
+  else if (pad == 2)
   {
-    res[rc++]  = b64[ bin[byteNo] >> 2 ] ;
-    res[rc++]  = b64[ ((0x3&bin[byteNo])<<4)   +   (bin[byteNo+1] >> 4) ] ;
-    res[rc++]  = b64[ (0x0f&bin[byteNo+1])<<2 ] ;
-    res[rc++] = '=';
+    byte byte0 = unencoded_data[i];
+
+    *ptr++ = b64encode[byte0 >> 2];
+    *ptr++ = b64encode[(byte0 & 0x03) << 4];
+    *ptr++ = '=';
+    *ptr++ = '=';
   }
 
-  res[rc]=0; // NULL TERMINATOR! ;)
-  return res ;
+  *ptr++= '\0';
 }
 
-unsigned char* unbase64( const char* ascii, int len, int *flen )
+const static byte b64decode[] =
 {
-  const unsigned char *safeAsciiPtr = (const unsigned char*)ascii ;
-  unsigned char *bin ;
-  int cb=0;
-  int charNo;
-  int pad = 0 ;
-
-  if( len < 2 ) { // 2 accesses below would be OOB.
-    // catch empty string, return NULL as result.
-    puts( "ERROR: You passed an invalid base64 string (too short). You get NULL back." ) ;
-    *flen=0;
-    return 0 ;
-  }
-  if( safeAsciiPtr[ len-1 ]=='=' )  ++pad ;
-  if( safeAsciiPtr[ len-2 ]=='=' )  ++pad ;
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,      //   0
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,      //  16
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 62,  0,  0,  0, 63,      //  32
+  52, 53, 54, 55, 56, 57, 58, 59, 60, 61,  0,  0,  0,  0,  0,  0,      //  48
+
+   0,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,      //  64
+  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,  0,  0,  0,  0,  0,      //  80
+   0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,      //  96
+  41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,  0,  0,  0,  0,  0,      // 112
+
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,      // 128
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,      // 144
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,      // 160
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,      // 176
+
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,      // 192
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,      // 208
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,      // 224
+   0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,      // 240
+};
+
+int base64_decoded_size(const char *encoded_data)
+{
+  int encoded_size = strlen(encoded_data);
 
-  *flen = 3*len/4 - pad ;
-  bin = (unsigned char*)malloc( *flen ) ;
-  if( !bin )
-  {
-    puts( "ERROR: unbase64 could not allocate enough memory." ) ;
-    puts( "I must stop because I could not get enough" ) ;
+  if (encoded_size < 2)
     return 0;
-  }
 
-  for( charNo=0; charNo <= len - 4 - pad ; charNo+=4 )
+  int pad = 0;
+
+  if (encoded_data[encoded_size - 1] == '=')
+    pad++;
+  if (encoded_data[encoded_size - 2] == '=')
+    pad++;
+
+  return 3 * encoded_size / 4 - pad;
+}
+
+void base64_decode(byte *decoded_data, const char *encoded_ptr)
+{
+  const byte *encoded_data = (const byte *)encoded_ptr;
+  byte *ptr = decoded_data;
+  int encoded_size = strlen(encoded_ptr);
+  int i;
+
+  if (encoded_size < 2)
+    return;
+
+  int pad = 0;
+
+  if (encoded_data[encoded_size - 1] == '=')
+    pad++;
+  if (encoded_data[encoded_size - 2] == '=')
+    pad++;
+
+  for (i = 0; i <= encoded_size - 4 - pad; i += 4)
   {
-    int A=unb64[safeAsciiPtr[charNo]];
-    int B=unb64[safeAsciiPtr[charNo+1]];
-    int C=unb64[safeAsciiPtr[charNo+2]];
-    int D=unb64[safeAsciiPtr[charNo+3]];
-
-    bin[cb++] = (A<<2) | (B>>4) ;
-    bin[cb++] = (B<<4) | (C>>2) ;
-    bin[cb++] = (C<<6) | (D) ;
+    byte byte0 = b64decode[encoded_data[i]];
+    byte byte1 = b64decode[encoded_data[i + 1]];
+    byte byte2 = b64decode[encoded_data[i + 2]];
+    byte byte3 = b64decode[encoded_data[i + 3]];
+
+    *ptr++ = (byte0 << 2) | (byte1 >> 4);
+    *ptr++ = (byte1 << 4) | (byte2 >> 2);
+    *ptr++ = (byte2 << 6) | (byte3);
   }
 
-  if( pad==1 )
+  if (pad == 1)
   {
-    int A=unb64[safeAsciiPtr[charNo]];
-    int B=unb64[safeAsciiPtr[charNo+1]];
-    int C=unb64[safeAsciiPtr[charNo+2]];
+    byte byte0 = b64decode[encoded_data[i]];
+    byte byte1 = b64decode[encoded_data[i + 1]];
+    byte byte2 = b64decode[encoded_data[i + 2]];
 
-    bin[cb++] = (A<<2) | (B>>4) ;
-    bin[cb++] = (B<<4) | (C>>2) ;
+    *ptr++ = (byte0 << 2) | (byte1 >> 4);
+    *ptr++ = (byte1 << 4) | (byte2 >> 2);
   }
-  else if( pad==2 )
+  else if (pad == 2)
   {
-    int A=unb64[safeAsciiPtr[charNo]];
-    int B=unb64[safeAsciiPtr[charNo+1]];
+    byte byte0 = b64decode[encoded_data[i]];
+    byte byte1 = b64decode[encoded_data[i + 1]];
 
-    bin[cb++] = (A<<2) | (B>>4) ;
+    *ptr++ = (byte0 << 2) | (byte1 >> 4);
   }
-
-  return bin ;
 }