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.
Dependents: STM32F746_iothub_client_sample_mqtt f767zi_mqtt iothub_client_sample_amqp iothub_client_sample_http ... more
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 Wed Jul 13 2022 23:38:02 by
1.7.2