Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of azure_c_shared_utility by
base64.c
00001 // Copyright (c) Microsoft. All rights reserved. 00002 // Licensed under the MIT license. See LICENSE file in the project root for full license information. 00003 00004 #include <stdlib.h> 00005 #include "azure_c_shared_utility/gballoc.h" 00006 #include <stddef.h> 00007 #include <stdint.h> 00008 #include "azure_c_shared_utility/base64.h" 00009 #include "azure_c_shared_utility/xlogging.h" 00010 00011 00012 #define splitInt(intVal, bytePos) (char)((intVal >> (bytePos << 3)) & 0xFF) 00013 #define joinChars(a, b, c, d) (uint32_t)((uint32_t)a + ((uint32_t)b << 8) + ((uint32_t)c << 16) + ((uint32_t)d << 24)) 00014 00015 static char base64char(unsigned char val) 00016 { 00017 char result; 00018 00019 if (val < 26) 00020 { 00021 result = 'A' + (char)val; 00022 } 00023 else if (val < 52) 00024 { 00025 result = 'a' + ((char)val - 26); 00026 } 00027 else if (val < 62) 00028 { 00029 result = '0' + ((char)val - 52); 00030 } 00031 else if (val == 62) 00032 { 00033 result = '+'; 00034 } 00035 else 00036 { 00037 result = '/'; 00038 } 00039 00040 return result; 00041 } 00042 00043 static char base64b16(unsigned char val) 00044 { 00045 const uint32_t base64b16values[4] = { 00046 joinChars('A', 'E', 'I', 'M'), 00047 joinChars('Q', 'U', 'Y', 'c'), 00048 joinChars('g', 'k', 'o', 's'), 00049 joinChars('w', '0', '4', '8') 00050 }; 00051 return splitInt(base64b16values[val >> 2], (val & 0x03)); 00052 } 00053 00054 static char base64b8(unsigned char val) 00055 { 00056 const uint32_t base64b8values = joinChars('A', 'Q', 'g', 'w'); 00057 return splitInt(base64b8values, val); 00058 } 00059 00060 static int base64toValue(char base64character, unsigned char* value) 00061 { 00062 int result = 0; 00063 if (('A' <= base64character) && (base64character <= 'Z')) 00064 { 00065 *value = base64character - 'A'; 00066 } 00067 else if (('a' <= base64character) && (base64character <= 'z')) 00068 { 00069 *value = ('Z' - 'A') + 1 + (base64character - 'a'); 00070 } 00071 else if (('0' <= base64character) && (base64character <= '9')) 00072 { 00073 *value = ('Z' - 'A') + 1 + ('z' - 'a') + 1 + (base64character - '0'); 00074 } 00075 else if ('+' == base64character) 00076 { 00077 *value = 62; 00078 } 00079 else if ('/' == base64character) 00080 { 00081 *value = 63; 00082 } 00083 else 00084 { 00085 *value = 0; 00086 result = -1; 00087 } 00088 return result; 00089 } 00090 00091 static size_t numberOfBase64Characters(const char* encodedString) 00092 { 00093 size_t length = 0; 00094 unsigned char junkChar; 00095 while (base64toValue(encodedString[length],&junkChar) != -1) 00096 { 00097 length++; 00098 } 00099 return length; 00100 } 00101 00102 /*returns the count of original bytes before being base64 encoded*/ 00103 /*notice NO validation of the content of encodedString. Its length is validated to be a multiple of 4.*/ 00104 static size_t Base64decode_len(const char *encodedString) 00105 { 00106 size_t result; 00107 size_t sourceLength = strlen(encodedString); 00108 00109 if (sourceLength == 0) 00110 { 00111 result = 0; 00112 } 00113 else 00114 { 00115 result = sourceLength / 4 * 3; 00116 if (encodedString[sourceLength - 1] == '=') 00117 { 00118 if (encodedString[sourceLength - 2] == '=') 00119 { 00120 result --; 00121 } 00122 result--; 00123 } 00124 } 00125 return result; 00126 } 00127 00128 static void Base64decode(unsigned char *decodedString, const char *base64String) 00129 { 00130 00131 size_t numberOfEncodedChars; 00132 size_t indexOfFirstEncodedChar; 00133 size_t decodedIndex; 00134 00135 // 00136 // We can only operate on individual bytes. If we attempt to work 00137 // on anything larger we could get an alignment fault on some 00138 // architectures 00139 // 00140 00141 numberOfEncodedChars = numberOfBase64Characters(base64String); 00142 indexOfFirstEncodedChar = 0; 00143 decodedIndex = 0; 00144 while (numberOfEncodedChars >= 4) 00145 { 00146 unsigned char c1; 00147 unsigned char c2; 00148 unsigned char c3; 00149 unsigned char c4; 00150 (void)base64toValue(base64String[indexOfFirstEncodedChar], &c1); 00151 (void)base64toValue(base64String[indexOfFirstEncodedChar + 1], &c2); 00152 (void)base64toValue(base64String[indexOfFirstEncodedChar + 2], &c3); 00153 (void)base64toValue(base64String[indexOfFirstEncodedChar + 3], &c4); 00154 decodedString[decodedIndex] = (c1 << 2) | (c2 >> 4); 00155 decodedIndex++; 00156 decodedString[decodedIndex] = ((c2 & 0x0f) << 4) | (c3 >> 2); 00157 decodedIndex++; 00158 decodedString[decodedIndex] = ((c3 & 0x03) << 6) | c4; 00159 decodedIndex++; 00160 numberOfEncodedChars -= 4; 00161 indexOfFirstEncodedChar += 4; 00162 00163 } 00164 00165 if (numberOfEncodedChars == 2) 00166 { 00167 unsigned char c1; 00168 unsigned char c2; 00169 (void)base64toValue(base64String[indexOfFirstEncodedChar], &c1); 00170 (void)base64toValue(base64String[indexOfFirstEncodedChar + 1], &c2); 00171 decodedString[decodedIndex] = (c1 << 2) | (c2 >> 4); 00172 } 00173 else if (numberOfEncodedChars == 3) 00174 { 00175 unsigned char c1; 00176 unsigned char c2; 00177 unsigned char c3; 00178 (void)base64toValue(base64String[indexOfFirstEncodedChar], &c1); 00179 (void)base64toValue(base64String[indexOfFirstEncodedChar + 1], &c2); 00180 (void)base64toValue(base64String[indexOfFirstEncodedChar + 2], &c3); 00181 decodedString[decodedIndex] = (c1 << 2) | (c2 >> 4); 00182 decodedIndex++; 00183 decodedString[decodedIndex] = ((c2 & 0x0f) << 4) | (c3 >> 2); 00184 } 00185 } 00186 00187 BUFFER_HANDLE Base64_Decoder(const char* source) 00188 { 00189 BUFFER_HANDLE result; 00190 /*Codes_SRS_BASE64_06_008: [If source is NULL then Base64_Decode shall return NULL.]*/ 00191 if (source == NULL) 00192 { 00193 LogError("invalid parameter const char* source=%p", source); 00194 result = NULL; 00195 } 00196 else 00197 { 00198 if ((strlen(source) % 4) != 0) 00199 { 00200 /*Codes_SRS_BASE64_06_011: [If the source string has an invalid length for a base 64 encoded string then Base64_Decode shall return NULL.]*/ 00201 LogError("Invalid length Base64 string!"); 00202 result = NULL; 00203 } 00204 else 00205 { 00206 if ((result = BUFFER_new()) == NULL) 00207 { 00208 /*Codes_SRS_BASE64_06_010: [If there is any memory allocation failure during the decode then Base64_Decode shall return NULL.]*/ 00209 LogError("Could not create a buffer to decoding."); 00210 } 00211 else 00212 { 00213 size_t sizeOfOutputBuffer = Base64decode_len(source); 00214 /*Codes_SRS_BASE64_06_009: [If the string pointed to by source is zero length then the handle returned shall refer to a zero length buffer.]*/ 00215 if (sizeOfOutputBuffer > 0) 00216 { 00217 if (BUFFER_pre_build(result, sizeOfOutputBuffer) != 0) 00218 { 00219 /*Codes_SRS_BASE64_06_010: [If there is any memory allocation failure during the decode then Base64_Decode shall return NULL.]*/ 00220 LogError("Could not prebuild a buffer for base 64 decoding."); 00221 BUFFER_delete(result); 00222 result = NULL; 00223 } 00224 else 00225 { 00226 Base64decode(BUFFER_u_char(result), source); 00227 } 00228 } 00229 } 00230 } 00231 } 00232 return result; 00233 } 00234 00235 00236 static STRING_HANDLE Base64_Encode_Internal(const unsigned char* source, size_t size) 00237 { 00238 STRING_HANDLE result; 00239 size_t neededSize = 0; 00240 char* encoded; 00241 size_t currentPosition = 0; 00242 neededSize += (size == 0) ? (0) : ((((size - 1) / 3) + 1) * 4); 00243 neededSize += 1; /*+1 because \0 at the end of the string*/ 00244 /*Codes_SRS_BASE64_06_006: [If when allocating memory to produce the encoding a failure occurs then Base64_Encoder shall return NULL.]*/ 00245 encoded = (char*)malloc(neededSize); 00246 if (encoded == NULL) 00247 { 00248 result = NULL; 00249 LogError("Base64_Encoder:: Allocation failed."); 00250 } 00251 else 00252 { 00253 /*b0 b1(+1) b2(+2) 00254 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 00255 |----c1---| |----c2---| |----c3---| |----c4---| 00256 */ 00257 00258 size_t destinationPosition = 0; 00259 while (size - currentPosition >= 3) 00260 { 00261 char c1 = base64char(source[currentPosition] >> 2); 00262 char c2 = base64char( 00263 ((source[currentPosition] & 3) << 4) | 00264 (source[currentPosition + 1] >> 4) 00265 ); 00266 char c3 = base64char( 00267 ((source[currentPosition + 1] & 0x0F) << 2) | 00268 ((source[currentPosition + 2] >> 6) & 3) 00269 ); 00270 char c4 = base64char( 00271 source[currentPosition + 2] & 0x3F 00272 ); 00273 currentPosition += 3; 00274 encoded[destinationPosition++] = c1; 00275 encoded[destinationPosition++] = c2; 00276 encoded[destinationPosition++] = c3; 00277 encoded[destinationPosition++] = c4; 00278 00279 } 00280 if (size - currentPosition == 2) 00281 { 00282 char c1 = base64char(source[currentPosition] >> 2); 00283 char c2 = base64char( 00284 ((source[currentPosition] & 0x03) << 4) | 00285 (source[currentPosition + 1] >> 4) 00286 ); 00287 char c3 = base64b16(source[currentPosition + 1] & 0x0F); 00288 encoded[destinationPosition++] = c1; 00289 encoded[destinationPosition++] = c2; 00290 encoded[destinationPosition++] = c3; 00291 encoded[destinationPosition++] = '='; 00292 } 00293 else if (size - currentPosition == 1) 00294 { 00295 char c1 = base64char(source[currentPosition] >> 2); 00296 char c2 = base64b8(source[currentPosition] & 0x03); 00297 encoded[destinationPosition++] = c1; 00298 encoded[destinationPosition++] = c2; 00299 encoded[destinationPosition++] = '='; 00300 encoded[destinationPosition++] = '='; 00301 } 00302 00303 /*null terminating the string*/ 00304 encoded[destinationPosition] = '\0'; 00305 /*Codes_SRS_BASE64_06_007: [Otherwise Base64_Encoder shall return a pointer to STRING, that string contains the base 64 encoding of input.]*/ 00306 result = STRING_new_with_memory(encoded); 00307 if (result == NULL) 00308 { 00309 free(encoded); 00310 LogError("Base64_Encoder:: Allocation failed for return value."); 00311 } 00312 } 00313 return result; 00314 } 00315 00316 STRING_HANDLE Base64_Encode_Bytes(const unsigned char* source, size_t size) 00317 { 00318 STRING_HANDLE result; 00319 /*Codes_SRS_BASE64_02_001: [If source is NULL then Base64_Encode_Bytes shall return NULL.] */ 00320 if (source == NULL) 00321 { 00322 result = NULL; 00323 } 00324 /*Codes_SRS_BASE64_02_002: [If source is not NULL and size is zero, then Base64_Encode_Bytes shall produce an empty STRING_HANDLE.] */ 00325 else if (size == 0) 00326 { 00327 result = STRING_new(); /*empty string*/ 00328 } 00329 else 00330 { 00331 result = Base64_Encode_Internal(source, size); 00332 } 00333 return result; 00334 } 00335 00336 STRING_HANDLE Base64_Encoder(BUFFER_HANDLE input) 00337 { 00338 STRING_HANDLE result; 00339 /*the following will happen*/ 00340 /*1. the "data" of the binary shall be "eaten" 3 characters at a time and produce 4 base64 encoded characters for as long as there are more than 3 characters still to process*/ 00341 /*2. the remaining characters (1 or 2) shall be encoded.*/ 00342 /*there's a level of assumption that 'a' corresponds to 0b000000 and that '_' corresponds to 0b111111*/ 00343 /*the encoding will use the optional [=] or [==] at the end of the encoded string, so that other less standard aware libraries can do their work*/ 00344 /*these are the bits of the 3 normal bytes to be encoded*/ 00345 00346 /*Codes_SRS_BASE64_06_001: [If input is NULL then Base64_Encoder shall return NULL.]*/ 00347 if (input == NULL) 00348 { 00349 result = NULL; 00350 LogError("Base64_Encoder:: NULL input"); 00351 } 00352 else 00353 { 00354 size_t inputSize; 00355 const unsigned char* inputBinary; 00356 if ((BUFFER_content(input, &inputBinary) != 0) || 00357 (BUFFER_size(input, &inputSize) != 0)) 00358 { 00359 result = NULL; 00360 LogError("Base64_Encoder:: BUFFER_routines failure."); 00361 } 00362 else 00363 { 00364 result = Base64_Encode_Internal(inputBinary, inputSize); 00365 } 00366 } 00367 return result; 00368 }
Generated on Tue Jul 12 2022 19:14:38 by
