source: azure_iot_hub/trunk/azure_iohub/c-utility/src/azure_base64.c@ 388

Last change on this file since 388 was 388, checked in by coas-nagasima, 5 years ago

Azure IoT Hub Device C SDK を使ったサンプルの追加

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