bes Updated for version 3.21.1
The Backend Server (BES) is the lower two tiers of the Hyrax data server
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
34namespace 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.size() % 4) //Sanity check
83 throw std::runtime_error("Non-Valid base64!");
84
85 size_t padding = 0;
86 if (input.size()) {
87 if (input[input.size() - 1] == padCharacter)
88 padding++;
89 if (input[input.size() - 2] == padCharacter)
90 padding++;
91 }
92
93 std::vector <u_int8_t> decodedBytes;
94 decodedBytes.reserve(((input.size() / 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