DSL
base64.cpp
1 #include <drift/dslcore.h>
2 #include <drift/base64.h>
3 
4 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 4 -*- */
5 /* vi: set expandtab shiftwidth=4 tabstop=4: */
47 #if defined(BIG_ENDIAN)
48 #define WORDS_BIGENDIAN 1
49 #else
50 #undef WORDS_BIGENDIAN
51 #endif
52 
53 #include <drift/base64_data.h>
54 
55 #define BADCHAR 0x01FFFFFF
56 
63 #define DOPAD 1
64 
65 /*
66  * if we aren't doing padding
67  * set the pad character to NULL
68  */
69 #ifndef DOPAD
70 #undef CHARPAD
71 #define CHARPAD '\0'
72 #endif
73 
74 int DSL_CC base64_encode(const void * str, size_t len, char * dest) {
75  size_t i;
76  const uint8* s = (const uint8*) str;
77  uint8* p = (uint8*) dest;
78 
79  /* unsigned here is important! */
80  /* uint8 is fastest on G4, amd */
81  /* uint32 is fastest on Intel */
82  uint32 t1, t2, t3;
83 
84  for (i = 0; i < len - 2; i += 3) {
85  t1 = s[i]; t2 = s[i+1]; t3 = s[i+2];
86  *p++ = e0[t1];
87  *p++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)];
88  *p++ = e1[((t2 & 0x0F) << 2) | ((t3 >> 6) & 0x03)];
89  *p++ = e2[t3];
90  }
91 
92  switch (len - i) {
93  case 0:
94  break;
95  case 1:
96  t1 = s[i];
97  *p++ = e0[t1];
98  *p++ = e1[(t1 & 0x03) << 4];
99  *p++ = CHARPAD;
100  *p++ = CHARPAD;
101  break;
102  default: /* case 2 */
103  t1 = s[i]; t2 = s[i+1];
104  *p++ = e0[t1];
105  *p++ = e1[((t1 & 0x03) << 4) | ((t2 >> 4) & 0x0F)];
106  *p++ = e2[(t2 & 0x0F) << 2];
107  *p++ = CHARPAD;
108  }
109 
110  *p = '\0';
111  return (int)(p - (uint8*)dest);
112 }
113 
114 #ifdef WORDS_BIGENDIAN /* BIG ENDIAN -- SUN / IBM / MOTOROLA */
115 int DSL_CC base64_decode(const char* src, size_t len, void * dest) {
116  if (len == 0) return 0;
117 
118 #ifdef DOPAD
119  /* if padding is used, then the message must be at least
120  4 chars and be a multiple of 4.
121  there can be at most 2 pad chars at the end */
122  if (len < 4 || (len % 4 != 0)) return -1;
123  if (src[len-1] == CHARPAD) {
124  len--;
125  if (src[len -1] == CHARPAD) {
126  len--;
127  }
128  }
129 #endif /* DOPAD */
130 
131  int i;
132  int leftover = len % 4;
133  int chunks = (leftover == 0) ? len / 4 - 1 : len /4;
134 
135  uint8* p = (uint8*) dest;
136  uint32 x = 0;
137  uint32* destInt = (uint32*) p;
138  uint32* srcInt = (uint32*) src;
139  uint32 y = *srcInt++;
140  for (i = 0; i < chunks; ++i) {
141  x = d0[y >> 24 & 0xff] | d1[y >> 16 & 0xff] |
142  d2[y >> 8 & 0xff] | d3[y & 0xff];
143 
144  if (x >= BADCHAR) return -1;
145  *destInt = x << 8;
146  p += 3;
147  destInt = (uint32*)p;
148  y = *srcInt++;
149  }
150 
151  switch (leftover) {
152  case 0:
153  x = d0[y >> 24 & 0xff] | d1[y >> 16 & 0xff] |
154  d2[y >> 8 & 0xff] | d3[y & 0xff];
155  if (x >= BADCHAR) return -1;
156  *p++ = ((uint8*)&x)[1];
157  *p++ = ((uint8*)&x)[2];
158  *p = ((uint8*)&x)[3];
159  return (chunks+1)*3;
160 #ifndef DOPAD
161  case 1: /* with padding this is an impossible case */
162  x = d3[y >> 24];
163  *p = (uint8)x;
164  break;
165 #endif
166  case 2:
167  x = d3[y >> 24] *64 + d3[(y >> 16) & 0xff];
168  *p = (uint8)(x >> 4);
169  break;
170  default: /* case 3 */
171  x = (d3[y >> 24] *64 + d3[(y >> 16) & 0xff])*64 +
172  d3[(y >> 8) & 0xff];
173  *p++ = (uint8) (x >> 10);
174  *p = (uint8) (x >> 2);
175  break;
176  }
177 
178  if (x >= BADCHAR) return -1;
179  return 3*chunks + (6*leftover)/8;
180 }
181 
182 #else /* LITTLE ENDIAN -- INTEL AND FRIENDS */
183 int DSL_CC base64_decode(const char* src, size_t len, void * dest) {
184  if (len == 0) return 0;
185 
186 #ifdef DOPAD
187  /*
188  * if padding is used, then the message must be at least
189  * 4 chars and be a multiple of 4
190  */
191  if (len < 4 || (len % 4 != 0)) return -1; /* error */
192  /* there can be at most 2 pad chars at the end */
193  if (src[len-1] == CHARPAD) {
194  len--;
195  if (src[len -1] == CHARPAD) {
196  len--;
197  }
198  }
199 #endif
200 
201  int i;
202  int leftover = len % 4;
203  int chunks = (leftover == 0) ? len / 4 - 1 : len /4;
204 
205  uint8* p = (uint8*) dest;
206  uint32 x = 0;
207  uint32* destInt = (uint32*) p;
208  uint32* srcInt = (uint32*) src;
209  uint32 y = *srcInt++;
210  for (i = 0; i < chunks; ++i) {
211  x = d0[y & 0xff] |
212  d1[(y >> 8) & 0xff] |
213  d2[(y >> 16) & 0xff] |
214  d3[(y >> 24) & 0xff];
215 
216  if (x >= BADCHAR) return -1;
217  *destInt = x ;
218  p += 3;
219  destInt = (uint32*)p;
220  y = *srcInt++;}
221 
222 
223  switch (leftover) {
224  case 0:
225  x = d0[y & 0xff] |
226  d1[(y >> 8) & 0xff] |
227  d2[(y >> 16) & 0xff] |
228  d3[(y >> 24) & 0xff];
229 
230  if (x >= BADCHAR) return -1;
231  *p++ = ((uint8*)(&x))[0];
232  *p++ = ((uint8*)(&x))[1];
233  *p = ((uint8*)(&x))[2];
234  return (chunks+1)*3;
235  break;
236 #ifndef DOPAD
237  case 1: /* with padding this is an impossible case */
238  x = d0[y & 0xff];
239  *p = *((uint8*)(&x)); // i.e. first char/byte in int
240  break;
241 #endif
242  case 2: // * case 2, 1 output byte */
243  x = d0[y & 0xff] | d1[y >> 8 & 0xff];
244  *p = *((uint8*)(&x)); // i.e. first char
245  break;
246  default: /* case 3, 2 output bytes */
247  x = d0[y & 0xff] |
248  d1[y >> 8 & 0xff ] |
249  d2[y >> 16 & 0xff]; /* 0x3c */
250  *p++ = ((uint8*)(&x))[0];
251  *p = ((uint8*)(&x))[1];
252  break;
253  }
254 
255  if (x >= BADCHAR) return -1;
256 
257  return 3*chunks + (6*leftover)/8;
258 }
259 
260 #endif /* if bigendian / else / endif */
int DSL_CC base64_decode(const char *src, size_t len, void *dest)
Definition: base64.cpp:183
int DSL_CC base64_encode(const void *str, size_t len, char *dest)
Definition: base64.cpp:74