Jamoma API  0.6.0.a19
libbase64++.h
1 #ifndef LIBBASE64_CPP_H
2 #define LIBBASE64_CPP_H
3 
4 #include <string>
5 //#define LIBBASE64_THROW_STD_INVALID_ARGUMENT
6 
7 //version info
8 #define __LIBBASE64_MAJOR__ 1
9 #define __LIBBASE64_MINOR__ 1
10 #define __LIBBASE64_PATCH__ 0
11 #define __LIBBASE64_VERSION__ (__LIBBASE64_MAJOR__ * 10000 + __LIBBASE64_MINOR__ * 100 + __LIBBASE64_PATCH__)
12 
13 //code coverage and asserts
14 #ifdef NDEBUG
15  #define LIBBASE64_ASSERT(cond, msg) (void)0
16  #define CREATEBOUNDCHECKER(type, name, ubound, lbound) (void)0
17  #define GETITEM_BOUNDCHECK(loc, name) (*(loc))
18 #else
19  #include <iostream>
20  #define LIBBASE64_ASSERT(cond, msg) if (!(cond)){ std::cerr << msg << std::endl; throw false; }
21 
22  template<typename T>
23  class libbase64_boundChecker {
24  public:
25  libbase64_boundChecker(const T * lbound, const T * ubound) : upperbound(ubound), lowerbound(lbound){};
26  T getLocation(const T * loc){
27  LIBBASE64_ASSERT(loc < upperbound, "Array index above bounds");
28  LIBBASE64_ASSERT(loc >= lowerbound, "Array index below bounds");
29  return *loc;
30  }
31  private:
32  const T * lowerbound;
33  const T * upperbound;
34  };
35  #define CREATEBOUNDCHECKER(type, name, ubound, lbound) libbase64_boundChecker<type> name(ubound, lbound)
36  #define GETITEM_BOUNDCHECK(loc, name) name.getLocation(loc)
37 
38  #ifdef LIBBASE64CODECOVERAGE
39  #define LIBBASE64CODECOVERAGEBRANCH { static bool f_codeCoverage_ = false; if (f_codeCoverage_ == false){ libbase64::getCoverageHits<STRINGTYPE, CHARTYPE, UCHARTYPE, SAFETY>(true); f_codeCoverage_ = true; } }
40  #endif
41 #endif
42 #ifndef LIBBASE64CODECOVERAGE
43  #define LIBBASE64CODECOVERAGEBRANCH (void)0
44 #endif
45 
46 //predictive branching optimizations
47 #ifdef __GNUC__
48  #define LIBBASE64_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100)
49  #if (LIBBASE64_GCC_VERSION >= 29600)
50  #define libbase64_likely(x) __builtin_expect((long)((bool)(x)),1)
51  #define libbase64_unlikely(x) __builtin_expect((long)((bool)(x)),0)
52  #endif
53 #endif
54 #ifndef libbase64_likely
55  #define libbase64_likely(x) x
56  #define libbase64_unlikely(x) x
57 #endif
58 
59 
60 namespace libbase64 {
61  #ifdef LIBBASE64CODECOVERAGE //Gets the number of branches that has been made
62  template<class STRINGTYPE, typename CHARTYPE, typename UCHARTYPE, bool SAFETY>
63  static size_t getCoverageHits(bool inc){
64  static size_t hits = 0;
65  if (inc) ++hits;
66  return hits;
67  }
68  #endif
69 
70  //characters used in convertions
71  namespace libbase64_characters {
72  template<typename T>
73  inline static const T * getChar64(void){
74  static const T char64s[64] = {
75  (T)'A', (T)'B', (T)'C', (T)'D', (T)'E', (T)'F', (T)'G', (T)'H', (T)'I', (T)'J', (T)'K', (T)'L', (T)'M',
76  (T)'N', (T)'O', (T)'P', (T)'Q', (T)'R', (T)'S', (T)'T', (T)'U', (T)'V', (T)'W', (T)'X', (T)'Y', (T)'Z',
77  (T)'a', (T)'b', (T)'c', (T)'d', (T)'e', (T)'f', (T)'g', (T)'h', (T)'i', (T)'j', (T)'k', (T)'l', (T)'m',
78  (T)'n', (T)'o', (T)'p', (T)'q', (T)'r', (T)'s', (T)'t', (T)'u', (T)'v', (T)'w', (T)'x', (T)'y', (T)'z',
79  (T)'0', (T)'1', (T)'2', (T)'3', (T)'4', (T)'5', (T)'6', (T)'7', (T)'8', (T)'9', (T)'+', (T)'/'
80  };
81  return char64s;
82  }
83 
84  template<typename T>
85  inline static T getChar(unsigned char bin){
86  CREATEBOUNDCHECKER(T, char64bounds, getChar64<T>(), getChar64<T>() + 64);
87  return GETITEM_BOUNDCHECK(getChar64<T>() + bin, char64bounds);
88  }
89 
90  template<typename T>
91  inline static T toBinary(T c) {
92  static T binaryConvert[80] = {62,48,49,50,63,52,53,54,55,56,57,58,59,60,61,249,250,251,252,253,254,255,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51};
93  CREATEBOUNDCHECKER(T, binaryConvertsbounds, binaryConvert, binaryConvert + 80);
94  return GETITEM_BOUNDCHECK(binaryConvert + c - 43, binaryConvertsbounds);
95  }
96 
97  template<typename T>
98  static inline T & emptyString(void){
99  static T t;
100  return t;
101  }
102  }
103 
104  namespace libbase64_Calculator {
105  inline static size_t getEncodingSize(size_t bytes){
106  return (bytes + 2 - ((bytes + 2) % 3)) / 3 * 4;
107  }
108  inline static size_t getDecodingSize(size_t res){
109  return res * 3 / 4;
110  }
111  }
112 
113 
114  /**
115  * Encodes data into a base64 string of STRINGTYPE
116  */
117  template<class STRINGTYPE, typename CHARTYPE, typename UCHARTYPE, bool SAFETY>
118  static STRINGTYPE encode(const unsigned char * binary, size_t bytes){
119  CREATEBOUNDCHECKER(unsigned char, binarybounds, binary, binary + bytes);
120 
121  //make sure that there is actually something to encode
122  if (SAFETY){
123  if (libbase64_unlikely(bytes == 0)){
124  LIBBASE64CODECOVERAGEBRANCH;
125  return libbase64_characters::emptyString<STRINGTYPE>();
126  }
127  }
128 
129  //calculate length and how misaligned it is
130  size_t misaligned = bytes % 3;
131  STRINGTYPE result;
132  result.reserve(libbase64_Calculator::getEncodingSize(bytes));
133 
134  //do all of the ones that are 3 byte aligned
135  for (size_t i = 0, aligned((bytes - misaligned) / 3); i < aligned; ++i){
136  LIBBASE64CODECOVERAGEBRANCH;
137  result += libbase64_characters::getChar<CHARTYPE>((GETITEM_BOUNDCHECK(binary, binarybounds) & 0xFC) >> 2);
138  result += libbase64_characters::getChar<CHARTYPE>(((GETITEM_BOUNDCHECK(binary, binarybounds) & 0x03) << 4) + ((GETITEM_BOUNDCHECK(binary + 1, binarybounds) & 0xF0) >> 4));
139  result += libbase64_characters::getChar<CHARTYPE>(((GETITEM_BOUNDCHECK(binary + 1, binarybounds) & 0x0F) << 2) + ((GETITEM_BOUNDCHECK(binary + 2, binarybounds) & 0xC0) >> 6));
140  result += libbase64_characters::getChar<CHARTYPE>(GETITEM_BOUNDCHECK(binary + 2, binarybounds) & 0x3F);
141  binary += 3;
142  }
143 
144  //handle any additional characters at the end of it
145  if (libbase64_likely(misaligned != 0)){
146  LIBBASE64CODECOVERAGEBRANCH;
147  //copy the rest into a temporary buffer, need it for the null terminators
148  unsigned char temp[3] = { '\0', '\0', '\0' };
149  for (unsigned char i = 0; i < (unsigned char)misaligned; ++i){
150  LIBBASE64CODECOVERAGEBRANCH;
151  temp[i] = GETITEM_BOUNDCHECK(binary++, binarybounds);
152  }
153 
154  //now do the final three bytes
155  result += libbase64_characters::getChar<CHARTYPE>((temp[0] & 0xFC) >> 2);
156  result += libbase64_characters::getChar<CHARTYPE>(((temp[0] & 0x03) << 4) + ((temp[1] & 0xF0) >> 4));
157  if (misaligned == 2){
158  LIBBASE64CODECOVERAGEBRANCH;
159  result += libbase64_characters::getChar<CHARTYPE>(((temp[1] & 0x0F) << 2) + ((temp[2] & 0xC0) >> 6));
160  } else {
161  LIBBASE64CODECOVERAGEBRANCH;
162  result += (CHARTYPE)'=';
163  }
164  result += (CHARTYPE)'=';
165  } else {
166  LIBBASE64CODECOVERAGEBRANCH;
167  }
168 
169  LIBBASE64_ASSERT(libbase64_Calculator::getEncodingSize(bytes) == result.length(), "Reserve wasn't the correct guess");
170  return result;
171  }
172 
173  template<class STRINGTYPE, typename CHARTYPE, typename UCHARTYPE, bool SAFETY>
174  static std::string decode(const STRINGTYPE & encoded){
175  //check length to be sure its acceptable for base64
176  const size_t length = encoded.length();
177 
178  if (SAFETY){
179  if (libbase64_unlikely((length % 4) != 0)){
180  LIBBASE64CODECOVERAGEBRANCH;
181  return libbase64_characters::emptyString<std::string>();
182  }
183  if (libbase64_unlikely(length == 0)){
184  LIBBASE64CODECOVERAGEBRANCH;
185  return libbase64_characters::emptyString<std::string>();
186  }
187 
188  //check to be sure there aren't odd characters or characters in the wrong places
189  size_t pos = encoded.find_first_not_of(libbase64_characters::getChar64<CHARTYPE>());
190  if (libbase64_unlikely(pos != STRINGTYPE::npos)){
191  LIBBASE64CODECOVERAGEBRANCH;
192  if (libbase64_unlikely(encoded[pos] != (CHARTYPE)'=')){
193  LIBBASE64CODECOVERAGEBRANCH; //INVALID_CHAR
194  #ifdef LIBBASE64_THROW_STD_INVALID_ARGUMENT
195  throw std::invalid_argument("invalid character in base64");
196  #else
197  return libbase64_characters::emptyString<std::string>();
198  #endif
199  }
200  if (pos != length - 1){
201  LIBBASE64CODECOVERAGEBRANCH;
202  if (libbase64_unlikely(pos != length - 2)){
203  LIBBASE64CODECOVERAGEBRANCH; //EQUAL_WRONG_PLACE
204  #ifdef LIBBASE64_THROW_STD_INVALID_ARGUMENT
205  throw std::invalid_argument("equal sign in wrong place in base64");
206  #else
207  return libbase64_characters::emptyString<std::string>();
208  #endif
209  }
210  if (libbase64_unlikely(encoded[pos + 1] != (CHARTYPE)'=')){
211  LIBBASE64CODECOVERAGEBRANCH; //EQUAL_NOT_LAST
212  #ifdef LIBBASE64_THROW_STD_INVALID_ARGUMENT
213  throw std::invalid_argument("invalid character in base64");
214  #else
215  return libbase64_characters::emptyString<std::string>();
216  #endif
217  }
218  LIBBASE64CODECOVERAGEBRANCH;
219  } else {
220  LIBBASE64CODECOVERAGEBRANCH;
221  }
222  } else {
223  LIBBASE64CODECOVERAGEBRANCH;
224  }
225  }
226 
227  const CHARTYPE * runner = encoded.data();
228  const CHARTYPE * end = runner + encoded.length();
229  CREATEBOUNDCHECKER(CHARTYPE, encodedbounds, runner, end);
230  size_t aligned = length / 4; //don't do the last ones as they might be = padding
231  std::string result;
232  --aligned;
233  result.reserve(libbase64_Calculator::getDecodingSize(length));
234 
235  //first do the ones that can not have any padding
236  for (unsigned int i = 0; i < aligned; ++i){
237  const CHARTYPE second = libbase64_characters::toBinary<UCHARTYPE>(GETITEM_BOUNDCHECK(runner + 1, encodedbounds));
238  const CHARTYPE third = libbase64_characters::toBinary<UCHARTYPE>(GETITEM_BOUNDCHECK(runner + 2, encodedbounds));
239  result += (libbase64_characters::toBinary<UCHARTYPE>(GETITEM_BOUNDCHECK(runner, encodedbounds)) << 2) + ((second & 0x30) >> 4);
240  result += ((second & 0xf) << 4) + ((third & 0x3c) >> 2);
241  result += ((third & 0x3) << 6) + libbase64_characters::toBinary<UCHARTYPE>(GETITEM_BOUNDCHECK(runner + 3, encodedbounds));
242  runner += 4;
243  }
244 
245  //now do the ones that might have padding, the first two characters can not be padding, so do them quickly
246  const CHARTYPE second = libbase64_characters::toBinary<UCHARTYPE>(GETITEM_BOUNDCHECK(runner + 1, encodedbounds));
247  result += (libbase64_characters::toBinary<UCHARTYPE>(GETITEM_BOUNDCHECK(runner + 0, encodedbounds)) << 2) + ((second & 0x30) >> 4);
248  runner += 2;
249  if ((runner != end) && (*runner != (CHARTYPE)'=')){ //not two = pads
250  LIBBASE64CODECOVERAGEBRANCH;
251  const CHARTYPE third = libbase64_characters::toBinary<UCHARTYPE>(GETITEM_BOUNDCHECK(runner, encodedbounds));
252  result += ((second & 0xf) << 4) + ((third & 0x3c) >> 2);
253  ++runner;
254  if ((runner != end) && (*runner != (CHARTYPE)'=')){ //no padding
255  LIBBASE64CODECOVERAGEBRANCH;
256  result += ((third & 0x3) << 6) + libbase64_characters::toBinary<UCHARTYPE>(GETITEM_BOUNDCHECK(runner, encodedbounds));
257  } else {
258  LIBBASE64CODECOVERAGEBRANCH;
259  }
260  } else {
261  LIBBASE64CODECOVERAGEBRANCH;
262  }
263 
264  LIBBASE64_ASSERT(libbase64_Calculator::getDecodingSize(length) >= result.length(), "Reserve wasn't the correct guess, too small");
265  LIBBASE64_ASSERT((result.length() <= 3) || (libbase64_Calculator::getDecodingSize(length) > result.length() - 3), "Reserve wasn't the correct guess, too big");
266  return result;
267  }
268 }
269 
270 #endif