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.
c-utility/src/base64.c@0:f7f1f0d76dd6, 2018-08-23 (annotated)
- Committer:
- XinZhangMS
- Date:
- Thu Aug 23 06:52:14 2018 +0000
- Revision:
- 0:f7f1f0d76dd6
azure-c-sdk for mbed os supporting NUCLEO_F767ZI
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
XinZhangMS | 0:f7f1f0d76dd6 | 1 | // Copyright (c) Microsoft. All rights reserved. |
XinZhangMS | 0:f7f1f0d76dd6 | 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. |
XinZhangMS | 0:f7f1f0d76dd6 | 3 | |
XinZhangMS | 0:f7f1f0d76dd6 | 4 | #include <stdlib.h> |
XinZhangMS | 0:f7f1f0d76dd6 | 5 | #include "azure_c_shared_utility/gballoc.h" |
XinZhangMS | 0:f7f1f0d76dd6 | 6 | #include <stddef.h> |
XinZhangMS | 0:f7f1f0d76dd6 | 7 | #include <stdint.h> |
XinZhangMS | 0:f7f1f0d76dd6 | 8 | #include "azure_c_shared_utility/base64.h" |
XinZhangMS | 0:f7f1f0d76dd6 | 9 | #include "azure_c_shared_utility/xlogging.h" |
XinZhangMS | 0:f7f1f0d76dd6 | 10 | |
XinZhangMS | 0:f7f1f0d76dd6 | 11 | |
XinZhangMS | 0:f7f1f0d76dd6 | 12 | #define splitInt(intVal, bytePos) (char)((intVal >> (bytePos << 3)) & 0xFF) |
XinZhangMS | 0:f7f1f0d76dd6 | 13 | #define joinChars(a, b, c, d) (uint32_t)((uint32_t)a + ((uint32_t)b << 8) + ((uint32_t)c << 16) + ((uint32_t)d << 24)) |
XinZhangMS | 0:f7f1f0d76dd6 | 14 | |
XinZhangMS | 0:f7f1f0d76dd6 | 15 | static char base64char(unsigned char val) |
XinZhangMS | 0:f7f1f0d76dd6 | 16 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 17 | char result; |
XinZhangMS | 0:f7f1f0d76dd6 | 18 | |
XinZhangMS | 0:f7f1f0d76dd6 | 19 | if (val < 26) |
XinZhangMS | 0:f7f1f0d76dd6 | 20 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 21 | result = 'A' + (char)val; |
XinZhangMS | 0:f7f1f0d76dd6 | 22 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 23 | else if (val < 52) |
XinZhangMS | 0:f7f1f0d76dd6 | 24 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 25 | result = 'a' + ((char)val - 26); |
XinZhangMS | 0:f7f1f0d76dd6 | 26 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 27 | else if (val < 62) |
XinZhangMS | 0:f7f1f0d76dd6 | 28 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 29 | result = '0' + ((char)val - 52); |
XinZhangMS | 0:f7f1f0d76dd6 | 30 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 31 | else if (val == 62) |
XinZhangMS | 0:f7f1f0d76dd6 | 32 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 33 | result = '+'; |
XinZhangMS | 0:f7f1f0d76dd6 | 34 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 35 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 36 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 37 | result = '/'; |
XinZhangMS | 0:f7f1f0d76dd6 | 38 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 39 | |
XinZhangMS | 0:f7f1f0d76dd6 | 40 | return result; |
XinZhangMS | 0:f7f1f0d76dd6 | 41 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 42 | |
XinZhangMS | 0:f7f1f0d76dd6 | 43 | static char base64b16(unsigned char val) |
XinZhangMS | 0:f7f1f0d76dd6 | 44 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 45 | const uint32_t base64b16values[4] = { |
XinZhangMS | 0:f7f1f0d76dd6 | 46 | joinChars('A', 'E', 'I', 'M'), |
XinZhangMS | 0:f7f1f0d76dd6 | 47 | joinChars('Q', 'U', 'Y', 'c'), |
XinZhangMS | 0:f7f1f0d76dd6 | 48 | joinChars('g', 'k', 'o', 's'), |
XinZhangMS | 0:f7f1f0d76dd6 | 49 | joinChars('w', '0', '4', '8') |
XinZhangMS | 0:f7f1f0d76dd6 | 50 | }; |
XinZhangMS | 0:f7f1f0d76dd6 | 51 | return splitInt(base64b16values[val >> 2], (val & 0x03)); |
XinZhangMS | 0:f7f1f0d76dd6 | 52 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 53 | |
XinZhangMS | 0:f7f1f0d76dd6 | 54 | static char base64b8(unsigned char val) |
XinZhangMS | 0:f7f1f0d76dd6 | 55 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 56 | const uint32_t base64b8values = joinChars('A', 'Q', 'g', 'w'); |
XinZhangMS | 0:f7f1f0d76dd6 | 57 | return splitInt(base64b8values, val); |
XinZhangMS | 0:f7f1f0d76dd6 | 58 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 59 | |
XinZhangMS | 0:f7f1f0d76dd6 | 60 | static int base64toValue(char base64character, unsigned char* value) |
XinZhangMS | 0:f7f1f0d76dd6 | 61 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 62 | int result = 0; |
XinZhangMS | 0:f7f1f0d76dd6 | 63 | if (('A' <= base64character) && (base64character <= 'Z')) |
XinZhangMS | 0:f7f1f0d76dd6 | 64 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 65 | *value = base64character - 'A'; |
XinZhangMS | 0:f7f1f0d76dd6 | 66 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 67 | else if (('a' <= base64character) && (base64character <= 'z')) |
XinZhangMS | 0:f7f1f0d76dd6 | 68 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 69 | *value = ('Z' - 'A') + 1 + (base64character - 'a'); |
XinZhangMS | 0:f7f1f0d76dd6 | 70 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 71 | else if (('0' <= base64character) && (base64character <= '9')) |
XinZhangMS | 0:f7f1f0d76dd6 | 72 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 73 | *value = ('Z' - 'A') + 1 + ('z' - 'a') + 1 + (base64character - '0'); |
XinZhangMS | 0:f7f1f0d76dd6 | 74 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 75 | else if ('+' == base64character) |
XinZhangMS | 0:f7f1f0d76dd6 | 76 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 77 | *value = 62; |
XinZhangMS | 0:f7f1f0d76dd6 | 78 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 79 | else if ('/' == base64character) |
XinZhangMS | 0:f7f1f0d76dd6 | 80 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 81 | *value = 63; |
XinZhangMS | 0:f7f1f0d76dd6 | 82 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 83 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 84 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 85 | *value = 0; |
XinZhangMS | 0:f7f1f0d76dd6 | 86 | result = -1; |
XinZhangMS | 0:f7f1f0d76dd6 | 87 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 88 | return result; |
XinZhangMS | 0:f7f1f0d76dd6 | 89 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 90 | |
XinZhangMS | 0:f7f1f0d76dd6 | 91 | static size_t numberOfBase64Characters(const char* encodedString) |
XinZhangMS | 0:f7f1f0d76dd6 | 92 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 93 | size_t length = 0; |
XinZhangMS | 0:f7f1f0d76dd6 | 94 | unsigned char junkChar; |
XinZhangMS | 0:f7f1f0d76dd6 | 95 | while (base64toValue(encodedString[length],&junkChar) != -1) |
XinZhangMS | 0:f7f1f0d76dd6 | 96 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 97 | length++; |
XinZhangMS | 0:f7f1f0d76dd6 | 98 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 99 | return length; |
XinZhangMS | 0:f7f1f0d76dd6 | 100 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 101 | |
XinZhangMS | 0:f7f1f0d76dd6 | 102 | /*returns the count of original bytes before being base64 encoded*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 103 | /*notice NO validation of the content of encodedString. Its length is validated to be a multiple of 4.*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 104 | static size_t Base64decode_len(const char *encodedString) |
XinZhangMS | 0:f7f1f0d76dd6 | 105 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 106 | size_t result; |
XinZhangMS | 0:f7f1f0d76dd6 | 107 | size_t sourceLength = strlen(encodedString); |
XinZhangMS | 0:f7f1f0d76dd6 | 108 | |
XinZhangMS | 0:f7f1f0d76dd6 | 109 | if (sourceLength == 0) |
XinZhangMS | 0:f7f1f0d76dd6 | 110 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 111 | result = 0; |
XinZhangMS | 0:f7f1f0d76dd6 | 112 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 113 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 114 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 115 | result = sourceLength / 4 * 3; |
XinZhangMS | 0:f7f1f0d76dd6 | 116 | if (encodedString[sourceLength - 1] == '=') |
XinZhangMS | 0:f7f1f0d76dd6 | 117 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 118 | if (encodedString[sourceLength - 2] == '=') |
XinZhangMS | 0:f7f1f0d76dd6 | 119 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 120 | result --; |
XinZhangMS | 0:f7f1f0d76dd6 | 121 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 122 | result--; |
XinZhangMS | 0:f7f1f0d76dd6 | 123 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 124 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 125 | return result; |
XinZhangMS | 0:f7f1f0d76dd6 | 126 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 127 | |
XinZhangMS | 0:f7f1f0d76dd6 | 128 | static void Base64decode(unsigned char *decodedString, const char *base64String) |
XinZhangMS | 0:f7f1f0d76dd6 | 129 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 130 | |
XinZhangMS | 0:f7f1f0d76dd6 | 131 | size_t numberOfEncodedChars; |
XinZhangMS | 0:f7f1f0d76dd6 | 132 | size_t indexOfFirstEncodedChar; |
XinZhangMS | 0:f7f1f0d76dd6 | 133 | size_t decodedIndex; |
XinZhangMS | 0:f7f1f0d76dd6 | 134 | |
XinZhangMS | 0:f7f1f0d76dd6 | 135 | // |
XinZhangMS | 0:f7f1f0d76dd6 | 136 | // We can only operate on individual bytes. If we attempt to work |
XinZhangMS | 0:f7f1f0d76dd6 | 137 | // on anything larger we could get an alignment fault on some |
XinZhangMS | 0:f7f1f0d76dd6 | 138 | // architectures |
XinZhangMS | 0:f7f1f0d76dd6 | 139 | // |
XinZhangMS | 0:f7f1f0d76dd6 | 140 | |
XinZhangMS | 0:f7f1f0d76dd6 | 141 | numberOfEncodedChars = numberOfBase64Characters(base64String); |
XinZhangMS | 0:f7f1f0d76dd6 | 142 | indexOfFirstEncodedChar = 0; |
XinZhangMS | 0:f7f1f0d76dd6 | 143 | decodedIndex = 0; |
XinZhangMS | 0:f7f1f0d76dd6 | 144 | while (numberOfEncodedChars >= 4) |
XinZhangMS | 0:f7f1f0d76dd6 | 145 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 146 | unsigned char c1; |
XinZhangMS | 0:f7f1f0d76dd6 | 147 | unsigned char c2; |
XinZhangMS | 0:f7f1f0d76dd6 | 148 | unsigned char c3; |
XinZhangMS | 0:f7f1f0d76dd6 | 149 | unsigned char c4; |
XinZhangMS | 0:f7f1f0d76dd6 | 150 | (void)base64toValue(base64String[indexOfFirstEncodedChar], &c1); |
XinZhangMS | 0:f7f1f0d76dd6 | 151 | (void)base64toValue(base64String[indexOfFirstEncodedChar + 1], &c2); |
XinZhangMS | 0:f7f1f0d76dd6 | 152 | (void)base64toValue(base64String[indexOfFirstEncodedChar + 2], &c3); |
XinZhangMS | 0:f7f1f0d76dd6 | 153 | (void)base64toValue(base64String[indexOfFirstEncodedChar + 3], &c4); |
XinZhangMS | 0:f7f1f0d76dd6 | 154 | decodedString[decodedIndex] = (c1 << 2) | (c2 >> 4); |
XinZhangMS | 0:f7f1f0d76dd6 | 155 | decodedIndex++; |
XinZhangMS | 0:f7f1f0d76dd6 | 156 | decodedString[decodedIndex] = ((c2 & 0x0f) << 4) | (c3 >> 2); |
XinZhangMS | 0:f7f1f0d76dd6 | 157 | decodedIndex++; |
XinZhangMS | 0:f7f1f0d76dd6 | 158 | decodedString[decodedIndex] = ((c3 & 0x03) << 6) | c4; |
XinZhangMS | 0:f7f1f0d76dd6 | 159 | decodedIndex++; |
XinZhangMS | 0:f7f1f0d76dd6 | 160 | numberOfEncodedChars -= 4; |
XinZhangMS | 0:f7f1f0d76dd6 | 161 | indexOfFirstEncodedChar += 4; |
XinZhangMS | 0:f7f1f0d76dd6 | 162 | |
XinZhangMS | 0:f7f1f0d76dd6 | 163 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 164 | |
XinZhangMS | 0:f7f1f0d76dd6 | 165 | if (numberOfEncodedChars == 2) |
XinZhangMS | 0:f7f1f0d76dd6 | 166 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 167 | unsigned char c1; |
XinZhangMS | 0:f7f1f0d76dd6 | 168 | unsigned char c2; |
XinZhangMS | 0:f7f1f0d76dd6 | 169 | (void)base64toValue(base64String[indexOfFirstEncodedChar], &c1); |
XinZhangMS | 0:f7f1f0d76dd6 | 170 | (void)base64toValue(base64String[indexOfFirstEncodedChar + 1], &c2); |
XinZhangMS | 0:f7f1f0d76dd6 | 171 | decodedString[decodedIndex] = (c1 << 2) | (c2 >> 4); |
XinZhangMS | 0:f7f1f0d76dd6 | 172 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 173 | else if (numberOfEncodedChars == 3) |
XinZhangMS | 0:f7f1f0d76dd6 | 174 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 175 | unsigned char c1; |
XinZhangMS | 0:f7f1f0d76dd6 | 176 | unsigned char c2; |
XinZhangMS | 0:f7f1f0d76dd6 | 177 | unsigned char c3; |
XinZhangMS | 0:f7f1f0d76dd6 | 178 | (void)base64toValue(base64String[indexOfFirstEncodedChar], &c1); |
XinZhangMS | 0:f7f1f0d76dd6 | 179 | (void)base64toValue(base64String[indexOfFirstEncodedChar + 1], &c2); |
XinZhangMS | 0:f7f1f0d76dd6 | 180 | (void)base64toValue(base64String[indexOfFirstEncodedChar + 2], &c3); |
XinZhangMS | 0:f7f1f0d76dd6 | 181 | decodedString[decodedIndex] = (c1 << 2) | (c2 >> 4); |
XinZhangMS | 0:f7f1f0d76dd6 | 182 | decodedIndex++; |
XinZhangMS | 0:f7f1f0d76dd6 | 183 | decodedString[decodedIndex] = ((c2 & 0x0f) << 4) | (c3 >> 2); |
XinZhangMS | 0:f7f1f0d76dd6 | 184 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 185 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 186 | |
XinZhangMS | 0:f7f1f0d76dd6 | 187 | BUFFER_HANDLE Base64_Decoder(const char* source) |
XinZhangMS | 0:f7f1f0d76dd6 | 188 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 189 | BUFFER_HANDLE result; |
XinZhangMS | 0:f7f1f0d76dd6 | 190 | /*Codes_SRS_BASE64_06_008: [If source is NULL then Base64_Decode shall return NULL.]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 191 | if (source == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 192 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 193 | LogError("invalid parameter const char* source=%p", source); |
XinZhangMS | 0:f7f1f0d76dd6 | 194 | result = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 195 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 196 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 197 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 198 | if ((strlen(source) % 4) != 0) |
XinZhangMS | 0:f7f1f0d76dd6 | 199 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 200 | /*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.]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 201 | LogError("Invalid length Base64 string!"); |
XinZhangMS | 0:f7f1f0d76dd6 | 202 | result = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 203 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 204 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 205 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 206 | if ((result = BUFFER_new()) == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 207 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 208 | /*Codes_SRS_BASE64_06_010: [If there is any memory allocation failure during the decode then Base64_Decode shall return NULL.]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 209 | LogError("Could not create a buffer to decoding."); |
XinZhangMS | 0:f7f1f0d76dd6 | 210 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 211 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 212 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 213 | size_t sizeOfOutputBuffer = Base64decode_len(source); |
XinZhangMS | 0:f7f1f0d76dd6 | 214 | /*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.]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 215 | if (sizeOfOutputBuffer > 0) |
XinZhangMS | 0:f7f1f0d76dd6 | 216 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 217 | if (BUFFER_pre_build(result, sizeOfOutputBuffer) != 0) |
XinZhangMS | 0:f7f1f0d76dd6 | 218 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 219 | /*Codes_SRS_BASE64_06_010: [If there is any memory allocation failure during the decode then Base64_Decode shall return NULL.]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 220 | LogError("Could not prebuild a buffer for base 64 decoding."); |
XinZhangMS | 0:f7f1f0d76dd6 | 221 | BUFFER_delete(result); |
XinZhangMS | 0:f7f1f0d76dd6 | 222 | result = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 223 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 224 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 225 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 226 | Base64decode(BUFFER_u_char(result), source); |
XinZhangMS | 0:f7f1f0d76dd6 | 227 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 228 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 229 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 230 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 231 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 232 | return result; |
XinZhangMS | 0:f7f1f0d76dd6 | 233 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 234 | |
XinZhangMS | 0:f7f1f0d76dd6 | 235 | |
XinZhangMS | 0:f7f1f0d76dd6 | 236 | static STRING_HANDLE Base64_Encode_Internal(const unsigned char* source, size_t size) |
XinZhangMS | 0:f7f1f0d76dd6 | 237 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 238 | STRING_HANDLE result; |
XinZhangMS | 0:f7f1f0d76dd6 | 239 | size_t neededSize = 0; |
XinZhangMS | 0:f7f1f0d76dd6 | 240 | char* encoded; |
XinZhangMS | 0:f7f1f0d76dd6 | 241 | size_t currentPosition = 0; |
XinZhangMS | 0:f7f1f0d76dd6 | 242 | neededSize += (size == 0) ? (0) : ((((size - 1) / 3) + 1) * 4); |
XinZhangMS | 0:f7f1f0d76dd6 | 243 | neededSize += 1; /*+1 because \0 at the end of the string*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 244 | /*Codes_SRS_BASE64_06_006: [If when allocating memory to produce the encoding a failure occurs then Base64_Encoder shall return NULL.]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 245 | encoded = (char*)malloc(neededSize); |
XinZhangMS | 0:f7f1f0d76dd6 | 246 | if (encoded == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 247 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 248 | result = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 249 | LogError("Base64_Encoder:: Allocation failed."); |
XinZhangMS | 0:f7f1f0d76dd6 | 250 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 251 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 252 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 253 | /*b0 b1(+1) b2(+2) |
XinZhangMS | 0:f7f1f0d76dd6 | 254 | 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 |
XinZhangMS | 0:f7f1f0d76dd6 | 255 | |----c1---| |----c2---| |----c3---| |----c4---| |
XinZhangMS | 0:f7f1f0d76dd6 | 256 | */ |
XinZhangMS | 0:f7f1f0d76dd6 | 257 | |
XinZhangMS | 0:f7f1f0d76dd6 | 258 | size_t destinationPosition = 0; |
XinZhangMS | 0:f7f1f0d76dd6 | 259 | while (size - currentPosition >= 3) |
XinZhangMS | 0:f7f1f0d76dd6 | 260 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 261 | char c1 = base64char(source[currentPosition] >> 2); |
XinZhangMS | 0:f7f1f0d76dd6 | 262 | char c2 = base64char( |
XinZhangMS | 0:f7f1f0d76dd6 | 263 | ((source[currentPosition] & 3) << 4) | |
XinZhangMS | 0:f7f1f0d76dd6 | 264 | (source[currentPosition + 1] >> 4) |
XinZhangMS | 0:f7f1f0d76dd6 | 265 | ); |
XinZhangMS | 0:f7f1f0d76dd6 | 266 | char c3 = base64char( |
XinZhangMS | 0:f7f1f0d76dd6 | 267 | ((source[currentPosition + 1] & 0x0F) << 2) | |
XinZhangMS | 0:f7f1f0d76dd6 | 268 | ((source[currentPosition + 2] >> 6) & 3) |
XinZhangMS | 0:f7f1f0d76dd6 | 269 | ); |
XinZhangMS | 0:f7f1f0d76dd6 | 270 | char c4 = base64char( |
XinZhangMS | 0:f7f1f0d76dd6 | 271 | source[currentPosition + 2] & 0x3F |
XinZhangMS | 0:f7f1f0d76dd6 | 272 | ); |
XinZhangMS | 0:f7f1f0d76dd6 | 273 | currentPosition += 3; |
XinZhangMS | 0:f7f1f0d76dd6 | 274 | encoded[destinationPosition++] = c1; |
XinZhangMS | 0:f7f1f0d76dd6 | 275 | encoded[destinationPosition++] = c2; |
XinZhangMS | 0:f7f1f0d76dd6 | 276 | encoded[destinationPosition++] = c3; |
XinZhangMS | 0:f7f1f0d76dd6 | 277 | encoded[destinationPosition++] = c4; |
XinZhangMS | 0:f7f1f0d76dd6 | 278 | |
XinZhangMS | 0:f7f1f0d76dd6 | 279 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 280 | if (size - currentPosition == 2) |
XinZhangMS | 0:f7f1f0d76dd6 | 281 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 282 | char c1 = base64char(source[currentPosition] >> 2); |
XinZhangMS | 0:f7f1f0d76dd6 | 283 | char c2 = base64char( |
XinZhangMS | 0:f7f1f0d76dd6 | 284 | ((source[currentPosition] & 0x03) << 4) | |
XinZhangMS | 0:f7f1f0d76dd6 | 285 | (source[currentPosition + 1] >> 4) |
XinZhangMS | 0:f7f1f0d76dd6 | 286 | ); |
XinZhangMS | 0:f7f1f0d76dd6 | 287 | char c3 = base64b16(source[currentPosition + 1] & 0x0F); |
XinZhangMS | 0:f7f1f0d76dd6 | 288 | encoded[destinationPosition++] = c1; |
XinZhangMS | 0:f7f1f0d76dd6 | 289 | encoded[destinationPosition++] = c2; |
XinZhangMS | 0:f7f1f0d76dd6 | 290 | encoded[destinationPosition++] = c3; |
XinZhangMS | 0:f7f1f0d76dd6 | 291 | encoded[destinationPosition++] = '='; |
XinZhangMS | 0:f7f1f0d76dd6 | 292 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 293 | else if (size - currentPosition == 1) |
XinZhangMS | 0:f7f1f0d76dd6 | 294 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 295 | char c1 = base64char(source[currentPosition] >> 2); |
XinZhangMS | 0:f7f1f0d76dd6 | 296 | char c2 = base64b8(source[currentPosition] & 0x03); |
XinZhangMS | 0:f7f1f0d76dd6 | 297 | encoded[destinationPosition++] = c1; |
XinZhangMS | 0:f7f1f0d76dd6 | 298 | encoded[destinationPosition++] = c2; |
XinZhangMS | 0:f7f1f0d76dd6 | 299 | encoded[destinationPosition++] = '='; |
XinZhangMS | 0:f7f1f0d76dd6 | 300 | encoded[destinationPosition++] = '='; |
XinZhangMS | 0:f7f1f0d76dd6 | 301 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 302 | |
XinZhangMS | 0:f7f1f0d76dd6 | 303 | /*null terminating the string*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 304 | encoded[destinationPosition] = '\0'; |
XinZhangMS | 0:f7f1f0d76dd6 | 305 | /*Codes_SRS_BASE64_06_007: [Otherwise Base64_Encoder shall return a pointer to STRING, that string contains the base 64 encoding of input.]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 306 | result = STRING_new_with_memory(encoded); |
XinZhangMS | 0:f7f1f0d76dd6 | 307 | if (result == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 308 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 309 | free(encoded); |
XinZhangMS | 0:f7f1f0d76dd6 | 310 | LogError("Base64_Encoder:: Allocation failed for return value."); |
XinZhangMS | 0:f7f1f0d76dd6 | 311 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 312 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 313 | return result; |
XinZhangMS | 0:f7f1f0d76dd6 | 314 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 315 | |
XinZhangMS | 0:f7f1f0d76dd6 | 316 | STRING_HANDLE Base64_Encode_Bytes(const unsigned char* source, size_t size) |
XinZhangMS | 0:f7f1f0d76dd6 | 317 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 318 | STRING_HANDLE result; |
XinZhangMS | 0:f7f1f0d76dd6 | 319 | /*Codes_SRS_BASE64_02_001: [If source is NULL then Base64_Encode_Bytes shall return NULL.] */ |
XinZhangMS | 0:f7f1f0d76dd6 | 320 | if (source == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 321 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 322 | result = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 323 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 324 | /*Codes_SRS_BASE64_02_002: [If source is not NULL and size is zero, then Base64_Encode_Bytes shall produce an empty STRING_HANDLE.] */ |
XinZhangMS | 0:f7f1f0d76dd6 | 325 | else if (size == 0) |
XinZhangMS | 0:f7f1f0d76dd6 | 326 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 327 | result = STRING_new(); /*empty string*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 328 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 329 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 330 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 331 | result = Base64_Encode_Internal(source, size); |
XinZhangMS | 0:f7f1f0d76dd6 | 332 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 333 | return result; |
XinZhangMS | 0:f7f1f0d76dd6 | 334 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 335 | |
XinZhangMS | 0:f7f1f0d76dd6 | 336 | STRING_HANDLE Base64_Encoder(BUFFER_HANDLE input) |
XinZhangMS | 0:f7f1f0d76dd6 | 337 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 338 | STRING_HANDLE result; |
XinZhangMS | 0:f7f1f0d76dd6 | 339 | /*the following will happen*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 340 | /*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*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 341 | /*2. the remaining characters (1 or 2) shall be encoded.*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 342 | /*there's a level of assumption that 'a' corresponds to 0b000000 and that '_' corresponds to 0b111111*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 343 | /*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*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 344 | /*these are the bits of the 3 normal bytes to be encoded*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 345 | |
XinZhangMS | 0:f7f1f0d76dd6 | 346 | /*Codes_SRS_BASE64_06_001: [If input is NULL then Base64_Encoder shall return NULL.]*/ |
XinZhangMS | 0:f7f1f0d76dd6 | 347 | if (input == NULL) |
XinZhangMS | 0:f7f1f0d76dd6 | 348 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 349 | result = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 350 | LogError("Base64_Encoder:: NULL input"); |
XinZhangMS | 0:f7f1f0d76dd6 | 351 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 352 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 353 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 354 | size_t inputSize; |
XinZhangMS | 0:f7f1f0d76dd6 | 355 | const unsigned char* inputBinary; |
XinZhangMS | 0:f7f1f0d76dd6 | 356 | if ((BUFFER_content(input, &inputBinary) != 0) || |
XinZhangMS | 0:f7f1f0d76dd6 | 357 | (BUFFER_size(input, &inputSize) != 0)) |
XinZhangMS | 0:f7f1f0d76dd6 | 358 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 359 | result = NULL; |
XinZhangMS | 0:f7f1f0d76dd6 | 360 | LogError("Base64_Encoder:: BUFFER_routines failure."); |
XinZhangMS | 0:f7f1f0d76dd6 | 361 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 362 | else |
XinZhangMS | 0:f7f1f0d76dd6 | 363 | { |
XinZhangMS | 0:f7f1f0d76dd6 | 364 | result = Base64_Encode_Internal(inputBinary, inputSize); |
XinZhangMS | 0:f7f1f0d76dd6 | 365 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 366 | } |
XinZhangMS | 0:f7f1f0d76dd6 | 367 | return result; |
XinZhangMS | 0:f7f1f0d76dd6 | 368 | } |