1 /******************************************************************************
2 *
3 * Project: Common Portability Library
4 * Purpose: Encoding/Decoding Base64 strings
5 * Author: Paul Ramsey <pramsey@cleverelephant.ca>
6 * Dave Blasby <dblasby@gmail.com>
7 * René Nyffenegger
8 *
9 ******************************************************************************
10 * Copyright (c) 2008 Paul Ramsey
11 * Copyright (c) 2002 Refractions Research
12 * Copyright (C) 2004-2008 René Nyffenegger
13 * Copyright (c) 2010-2013, Even Rouault <even dot rouault at spatialys.com>
14 *
15 * (see also part way down the file for license terms for René's code)
16 *
17 * Permission is hereby granted, free of charge, to any person obtaining a
18 * copy of this software and associated documentation files (the "Software"),
19 * to deal in the Software without restriction, including without limitation
20 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
21 * and/or sell copies of the Software, and to permit persons to whom the
22 * Software is furnished to do so, subject to the following conditions:
23 *
24 * The above copyright notice and this permission notice shall be included in
25 * all copies of this Software or works derived from this Software.
26 *
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
28 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
33 * DEALINGS IN THE SOFTWARE.
34 ****************************************************************************/
35
36 #include "cpl_port.h"
37 #include "cpl_string.h"
38
39 #include <string>
40
41 #include "cpl_conv.h"
42
43 CPL_CVSID("$Id: cpl_base64.cpp b1c9c12ad373e40b955162b45d704070d4ebf7b0 2019-06-19 16:50:15 +0200 Even Rouault $")
44
45 // Derived from MapServer's mappostgis.c.
46
47 /*
48 ** Decode a base64 character.
49 */
50 constexpr unsigned char CPLBase64DecodeChar[256] = {
51 // Not Base64 characters.
52 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
53 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
54 64,64,64,64,64,64,64,64,64,64,64,
55 // +
56 62,
57 // Not Base64 characters.
58 64,64,64,
59 // /
60 63,
61 // 0-9
62 52,53,54,55,56,57,58,59,60,61,
63 // Not Base64 characters.
64 64,64,64,64,64,64,64,
65 // A-Z
66 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,
67 // Not Base64 characters.
68 64,64,64,64,64,64,
69 // a-z
70 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,
71 51,
72 // Not Base64 characters.
73 64,64,64,64,64,
74 // Not Base64 characters (upper 128 characters).
75 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
76 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
77 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
78 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
79 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
80 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
81 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
82 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64
83 };
84
85 /************************************************************************/
86 /* CPLBase64DecodeInPlace() */
87 /************************************************************************/
88
89 /** Decode base64 string "pszBase64" (null terminated) in place.
90 *
91 * Returns length of decoded array or 0 on failure.
92 */
CPLBase64DecodeInPlace(GByte * pszBase64)93 int CPLBase64DecodeInPlace( GByte* pszBase64 )
94 {
95 if( pszBase64 && *pszBase64 )
96 {
97 unsigned char *p = pszBase64;
98 int offset_1 = 0;
99 int offset_2 = 0;
100
101 // Drop illegal chars first.
102 for( ; pszBase64[offset_1]; ++offset_1 )
103 {
104 unsigned char c = pszBase64[offset_1];
105 if( (CPLBase64DecodeChar[c] != 64) || (c == '=') )
106 {
107 pszBase64[offset_2++] = c;
108 }
109 }
110
111 for( int idx = 0; idx < offset_2; idx += 4 )
112 {
113 unsigned char b1 = CPLBase64DecodeChar[pszBase64[idx]];
114 unsigned char b2 = 0;
115 unsigned char c3 = 'A';
116 unsigned char c4 = 'A';
117
118 if( idx + 3 < offset_2 )
119 {
120 b2 = CPLBase64DecodeChar[pszBase64[idx+1]];
121 c3 = pszBase64[idx+2];
122 c4 = pszBase64[idx+3];
123 }
124 else if( idx + 2 < offset_2 )
125 {
126 b2 = CPLBase64DecodeChar[pszBase64[idx+1]];
127 c3 = pszBase64[idx+2];
128 }
129 else if( idx + 1 < offset_2 )
130 {
131 b2 = CPLBase64DecodeChar[pszBase64[idx+1]];
132 // c3 = 'A';
133 } // Else: Use the default values.
134
135 const unsigned char b3 = CPLBase64DecodeChar[c3];
136 const unsigned char b4 = CPLBase64DecodeChar[c4];
137
138 *p++ = ( (b1 << 2) | (b2 >> 4) );
139 if( p - pszBase64 == offset_1 )
140 break;
141 if( c3 != '=' )
142 {
143 *p++ = ( ((b2 & 0xf) << 4) | (b3 >> 2) );
144 if( p - pszBase64 == offset_1 )
145 break;
146 }
147 if( c4 != '=' )
148 {
149 *p++ = ( ((b3 & 0x3) << 6) | b4);
150 if( p - pszBase64 == offset_1 )
151 break;
152 }
153 }
154 return static_cast<int>(p-pszBase64);
155 }
156 return 0;
157 }
158
159 /*
160 * This function was extracted from the base64 cpp utility published by
161 * René Nyffenegger. The code was modified into a form suitable for use in
162 * CPL. The original code can be found at:
163 *
164 * http://www.adp-gmbh.ch/cpp/common/base64.html.
165 *
166 * The following is the original notice of this function.
167 *
168 * base64.cpp and base64.h
169 *
170 * Copyright (C) 2004-2008 René Nyffenegger
171 *
172 * This source code is provided 'as-is', without any express or implied
173 * warranty. In no event will the author be held liable for any damages
174 * arising from the use of this software.
175 *
176 * Permission is granted to anyone to use this software for any purpose,
177 * including commercial applications, and to alter it and redistribute it
178 * freely, subject to the following restrictions:
179 *
180 * 1. The origin of this source code must not be misrepresented; you must not
181 * claim that you wrote the original source code. If you use this source
182 * code in a product, an acknowledgment in the product documentation would
183 * be appreciated but is not required.
184 *
185 * 2. Altered source versions must be plainly marked as such, and must not be
186 * misrepresented as being the original source code.
187 *
188 * 3. This notice may not be removed or altered from any source distribution.
189 *
190 * René Nyffenegger rene.nyffenegger@adp-gmbh.ch
191 */
192
193 /************************************************************************/
194 /* CPLBase64Encode() */
195 /************************************************************************/
196
197 /** Base64 encode a buffer. */
198
CPLBase64Encode(int nDataLen,const GByte * pabyBytesToEncode)199 char *CPLBase64Encode(int nDataLen, const GByte *pabyBytesToEncode)
200 {
201 constexpr char base64Chars[] =
202 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
203
204 const int kCharArray3Size = 3;
205 const int kCharArray4Size = 4;
206 unsigned char charArray3[kCharArray3Size] = {};
207
208 std::string result("");
209 int array3_idx = 0;
210 while( nDataLen-- )
211 {
212 charArray3[array3_idx++] = *(pabyBytesToEncode++);
213
214 if( array3_idx == kCharArray3Size )
215 {
216 const unsigned char charArray4[kCharArray4Size] = {
217 static_cast<unsigned char>( (charArray3[0] & 0xfc) >> 2),
218 static_cast<unsigned char>(((charArray3[0] & 0x03) << 4) +
219 ((charArray3[1] & 0xf0) >> 4)),
220 static_cast<unsigned char>(((charArray3[1] & 0x0f) << 2) +
221 ((charArray3[2] & 0xc0) >> 6)),
222 static_cast<unsigned char>( charArray3[2] & 0x3f)
223 };
224
225 for( int idx = 0; idx < kCharArray4Size; ++idx )
226 {
227 result += base64Chars[charArray4[idx]];
228 }
229
230 array3_idx = 0;
231 }
232 }
233
234 if( array3_idx )
235 {
236 for( int idx = array3_idx; idx < kCharArray3Size; ++idx )
237 {
238 charArray3[idx] = '\0';
239 }
240
241 const unsigned char charArray4[kCharArray4Size] = {
242 static_cast<unsigned char>( (charArray3[0] & 0xfc) >> 2),
243 static_cast<unsigned char>(((charArray3[0] & 0x03) << 4) +
244 ((charArray3[1] & 0xf0) >> 4)),
245 static_cast<unsigned char>(((charArray3[1] & 0x0f) << 2) +
246 ((charArray3[2] & 0xc0) >> 6)),
247 static_cast<unsigned char>( charArray3[2] & 0x3f)
248 };
249
250 for( int idx = 0; idx < (array3_idx + 1); ++idx )
251 {
252 result += base64Chars[charArray4[idx]];
253 }
254
255 while( array3_idx++ < kCharArray3Size )
256 result += '=';
257 }
258
259 return CPLStrdup(result.c_str());
260 }
261