bes  Updated for version 3.20.8
Base64.h
1 // -*- mode: c++; c-basic-offset:4 -*-
2 
3 // This file is part of the BES
4 
5 // Copyright (c) 2020 OPeNDAP, Inc.
6 // Author: Dan Holloway <dholloway@opendap.org>
7 //
8 // This library is free software; you can redistribute it and/or
9 // modify it under the terms of the GNU Lesser General Public
10 // License as published by the Free Software Foundation; either
11 // version 2.1 of the License, or (at your option) any later version.
12 //
13 // This library is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Lesser General Public License for more details.
17 //
18 // You should have received a copy of the GNU Lesser General Public
19 // License along with this library; if not, write to the Free Software
20 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 //
22 // You can contact OPeNDAP, Inc. at PO Box 112, Saunderstown, RI. 02874-0112.
23 
24 // This class based on implementation described at http://vorbrodt.blog/2019/03/23/base64-encoding
25 // and http://en.wikibooks.org/wiki/Algorithm_Implementation/Miscellaneous/Base64.
26 
27 #include <stdexcept>
28 #include <string>
29 #include <vector>
30 
31 #define BASE64_ENCODE_LOOKUP "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
32 #define BASE64_PAD_CHARACTER '='
33 
34 namespace base64 {
35 
36  class Base64 {
37 
38  // Lookup table for encoding, if you want to use an alternate alphabet, change the characters here
39  //constexpr static char encodeLookup[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
40  //constexpr static char padCharacter = '=';
41 
42  public:
43  static std::string encode(const u_int8_t *cursor, int32_t size) {
44  char encodeLookup[] = BASE64_ENCODE_LOOKUP;
45  char padCharacter = BASE64_PAD_CHARACTER;
46  std::string encodedString;
47  encodedString.reserve(((size / 3) + (size % 3 > 0)) * 4);
48  u_int64_t temp;
49 
50  for (int32_t idx = 0; idx < size / 3; idx++) {
51  temp = (*cursor++) << 16;
52  temp += (*cursor++) << 8;
53  temp += (*cursor++);
54  encodedString.append(1, encodeLookup[(temp & 0x00FC0000) >> 18]);
55  encodedString.append(1, encodeLookup[(temp & 0x0003F000) >> 12]);
56  encodedString.append(1, encodeLookup[(temp & 0x00000FC0) >> 6]);
57  encodedString.append(1, encodeLookup[(temp & 0x0000003F)]);
58  }
59 
60  switch (size % 3) {
61  case 1:
62  temp = (*cursor++) << 16;
63  encodedString.append(1, encodeLookup[(temp & 0x00FC0000) >> 18]);
64  encodedString.append(1, encodeLookup[(temp & 0x0003F000) >> 12]);
65  encodedString.append(2, padCharacter);
66  break;
67  case 2:
68  temp = (*cursor++) << 16;
69  temp += (*cursor++) << 8;
70  encodedString.append(1, encodeLookup[(temp & 0x00FC0000) >> 18]);
71  encodedString.append(1, encodeLookup[(temp & 0x0003F000) >> 12]);
72  encodedString.append(1, encodeLookup[(temp & 0x00000FC0) >> 6]);
73  encodedString.append(1, padCharacter);
74  break;
75  }
76  return encodedString;
77  }
78 
79  static std::vector <u_int8_t> decode(const std::string &input) {
80  char padCharacter = BASE64_PAD_CHARACTER;
81 
82  if (input.length() % 4) //Sanity check
83  throw std::runtime_error("Non-Valid base64!");
84 
85  size_t padding = 0;
86  if (input.length()) {
87  if (input[input.length() - 1] == padCharacter)
88  padding++;
89  if (input[input.length() - 2] == padCharacter)
90  padding++;
91  }
92 
93  std::vector <u_int8_t> decodedBytes;
94  decodedBytes.reserve(((input.length() / 4) * 3) - padding);
95 
96  u_int32_t temp = 0;
97 
98  std::string::const_iterator cursor = input.begin();
99  while (cursor < input.end()) {
100  for (size_t quantumPosition = 0; quantumPosition < 4; quantumPosition++) {
101  temp <<= 6;
102  if (*cursor >= 0x41 && *cursor <= 0x5A) // This area will need tweaking if
103  temp |= *cursor - 0x41; // you are using an alternate alphabet
104  else if (*cursor >= 0x61 && *cursor <= 0x7A)
105  temp |= *cursor - 0x47;
106  else if (*cursor >= 0x30 && *cursor <= 0x39)
107  temp |= *cursor + 0x04;
108  else if (*cursor == 0x2B)
109  temp |= 0x3E; //change to 0x2D for URL alphabet
110  else if (*cursor == 0x2F)
111  temp |= 0x3F; //change to 0x5F for URL alphabet
112  else if (*cursor == padCharacter) //pad
113  {
114  switch (input.end() - cursor) {
115  case 1: //One pad character
116  decodedBytes.push_back((temp >> 16) & 0x000000FF);
117  decodedBytes.push_back((temp >> 8) & 0x000000FF);
118  return decodedBytes;
119  case 2: //Two pad characters
120  decodedBytes.push_back((temp >> 10) & 0x000000FF);
121  return decodedBytes;
122  default:
123  throw std::runtime_error("Invalid Padding in Base 64!");
124  }
125  } else
126  throw std::runtime_error("Non-Valid Character in Base 64!");
127 
128  cursor++;
129  }
130  decodedBytes.push_back((temp >> 16) & 0x000000FF);
131  decodedBytes.push_back((temp >> 8) & 0x000000FF);
132  decodedBytes.push_back((temp) & 0x000000FF);
133  }
134 
135  return decodedBytes;
136  }
137  };
138 
139 } // namespace base64