Subversion Repositories Games.Chess Giants

Rev

Rev 178 | Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
154 pmbaty 1
// base64.cpp
2
 
3
#include <stdio.h> // for size_t
4
 
5
 
6
// function prototypes
7
size_t base64_encode (char *dest, const char *source, size_t source_len);
8
size_t base64_decode (unsigned char *dest, const unsigned char *source, size_t source_len);
9
 
10
 
11
size_t base64_encode (char *dest, const char *source, size_t source_len)
12
{
13
   // encode a string in its base64 equivalent. It is up to the caller to ensure
14
   // that dest is large enough to contain the base64 representation of source.
15
   // Typically, a 4/3 size ratio is needed (i.e. when source is 30 bytes long,
16
   // dest should be large enough to contain 40 bytes).
17
   // When finished, return the length of the decoded data.
18
 
19
   static const char char_values[64 + 1] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
20
 
21
   unsigned char bytes[3];
22
   char *ptr;
23
 
24
   ptr = dest; // save where the destination buffer starts
25
 
26
   // as long as there are more than 3 characters left...
27
   while (source_len >= 3)
28
   {
29
      // get 3 bytes from source string
30
      bytes[0] = *(source++);
31
      bytes[1] = *(source++);
32
      bytes[2] = *(source++);
33
 
34
      // split these 3 bytes in 4 chunks of 6 bit each and replace each of them
35
      // with the corresponding character
36
      *(ptr++) = char_values[bytes[0] >> 2];
37
      *(ptr++) = char_values[((bytes[0] & 0x03) << 4) | (bytes[1] >> 4)];
38
      *(ptr++) = char_values[((bytes[1] & 0x0F) << 2) | (bytes[2] >> 6)];
39
      *(ptr++) = char_values[bytes[2] & 0x3F];
40
 
41
      source_len -= 3; // 3 characters less to process
42
   }
43
 
44
   // are there any characters left ?
45
   if (source_len > 0)
46
   {
47
      // encode the 6 most significant bits of the first character
48
      bytes[0] = *(source++);
49
      *(ptr++) = char_values[bytes[0] >> 2];
50
 
51
      // is there a second character to encode ?
52
      if (source_len > 1)
53
      {
54
         // encode the 2 least significant bytes of the first character
55
         // and the 8 bytes of the second character over 2 characters
56
         bytes[1] = *source;
57
         *(ptr++) = char_values [((bytes[0] & 0x03) << 4) | (bytes[1] >> 4)];
58
         *(ptr++) = char_values [(bytes[1] & 0x0F) << 2];
59
      }
60
 
61
      // else it was the only character left
62
      else
63
      {
64
         // encode the 2 least significant bytes of that character
65
         *(ptr++) = char_values[(bytes[0] & 0x03) << 4];
66
         *(ptr++) = '='; // padding (no character left)
67
      }
68
 
69
      *(ptr++) = '='; // padding (no character left)
70
   }
71
 
72
   *ptr = 0; // terminate the string
73
   return (ptr - dest); // finished, source has been base64-encoded in dest
74
}
75
 
76
 
77
size_t base64_decode (unsigned char *dest, const unsigned char *source, size_t source_len)
78
{
79
   // decodes a base64 string into its 8-bit equivalent. It is up to the caller
80
   // to ensure that dest is large enough to contain the decoded representation
81
   // of source. Typically, a 3/4 size ratio is needed (i.e. when source is 40
82
   // bytes long, dest should be large enough to contain 30 bytes).
83
   // When finished, return the length of the decoded data.
84
 
85
   #define __ 0xFF
86
   static const unsigned char dtable[256] =
87
   {
88
      __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
89
      __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
90
      __, __, __, __, __, __, __, __, __, __, __, 62, __, __, __, 63, // _ _ _ _ _ _ _ _ _ _ _ + _ _ _ /
91
      52, 53, 54, 55, 56, 57, 58, 59, 60, 61, __, __, __,  0, __, __, // 0 1 2 3 4 5 6 7 8 9 _ _ _ = _ _
92
      __,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, // _ A B C D E F G H I J K L M N O
93
      15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, __, __, __, __, __, // P Q R S T U V W X Y Z _ _ _ _ _
94
      __, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, // _ a b c d e f g h i j k l m n o
95
      41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, __, __, __, __, __, // p q r s t u v w x y z _ _ _ _ _
96
      __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
97
      __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
98
      __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
99
      __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
100
      __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
101
      __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
102
      __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
103
      __, __, __, __, __, __, __, __, __, __, __, __, __, __, __, __  // _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
104
   };
105
   #undef __
106
   unsigned char rawin[4];
107
   unsigned char block[4];
108
   unsigned char *pos;
109
   unsigned char tmp;
110
   size_t char_index;
111
   size_t count;
112
 
113
   pos = dest; // initialize output stream writer at the beginning of the stream
114
   count = 0; // reset the block character counter
115
 
116
   // for each base64 character in source...
117
   for (char_index = 0; char_index < source_len; char_index++)
118
   {
119
      tmp = dtable[source[char_index]]; // peek at the translation of this character in the table
120
      if (tmp == 0xFF)
121
         continue; // skip (ignore) all non-base64 characters
122
 
123
      rawin[count] = source[char_index]; // keep track of the character we're translating
124
      block[count] = tmp; // store the translation in the current block
125
      count++; // there's one character more in the current 4-character block
126
 
127
      // each time we've filled a 4-character block, decode it in 3 bytes in the output stream
128
      if (count == 4)
129
      {
130
         *pos++ = (block[0] << 2) | (block[1] >> 4);
131
         *pos++ = (block[1] << 4) | (block[2] >> 2);
132
         *pos++ = (block[2] << 6) | (block[3] >> 0);
133
         count = 0; // and reset the character counter for the next block
134
      }
135
   }
136
 
137
   // handle stream end: have we decoded anything ?
138
   if (pos > dest)
139
   {
140
      if (rawin[2] == '=')
141
         pos -= 2;
142
      else if (rawin[3] == '=')
143
         pos--;
144
   }
145
 
146
   *pos = 0; // drop a string terminator where the decoded stream ends (but don't take it in account in the length)
147
   return (pos - dest); // source has been base64-decoded in dest, return decoded length
148
}