|
1 | 1 | /* |
2 | | -
|
3 | | - https://github.com/superwills/NibbleAndAHalf |
4 | | - base64.h -- Fast base64 encoding and decoding. |
5 | | - version 1.0.0, April 17, 2013 143a |
6 | | -
|
7 | | - Copyright (C) 2013 William Sherif |
8 | | -
|
9 | | - This software is provided 'as-is', without any express or implied |
10 | | - warranty. In no event will the authors be held liable for any damages |
11 | | - arising from the use of this software. |
12 | | -
|
13 | | - Permission is granted to anyone to use this software for any purpose, |
14 | | - including commercial applications, and to alter it and redistribute it |
15 | | - freely, subject to the following restrictions: |
16 | | -
|
17 | | - 1. The origin of this software must not be misrepresented; you must not |
18 | | - claim that you wrote the original software. If you use this software |
19 | | - in a product, an acknowledgment in the product documentation would be |
20 | | - appreciated but is not required. |
21 | | - 2. Altered source versions must be plainly marked as such, and must not be |
22 | | - misrepresented as being the original software. |
23 | | - 3. This notice may not be removed or altered from any source distribution. |
24 | | -
|
25 | | - William Sherif |
26 | | - will.sherif@gmail.com |
27 | | -
|
28 | | - YWxsIHlvdXIgYmFzZSBhcmUgYmVsb25nIHRvIHVz |
29 | | -
|
30 | | -*/ |
| 2 | + * Base64 encoding: Copyright (c) 2005-2011, Jouni Malinen <j@w1.fi> |
| 3 | + * This software may be distributed under the terms of the BSD license. |
| 4 | + * |
| 5 | + * Base64 decoding: Copyright (c) 2016, polfosol |
| 6 | + * Posted at https://stackoverflow.com/a/37109258 under the CC-BY-SA Creative |
| 7 | + * Commons license. |
| 8 | + */ |
31 | 9 |
|
32 | 10 | #include "base64.h" |
| 11 | +#include <open62541/types.h> |
33 | 12 |
|
34 | | -#include <stdio.h> |
35 | | -#include <stdlib.h> |
36 | | - |
37 | | -static const char* b64="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" ; |
38 | | - |
39 | | -// maps A=>0,B=>1.. |
40 | | -static const unsigned char unb64[]={ |
41 | | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //10 |
42 | | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //20 |
43 | | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //30 |
44 | | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //40 |
45 | | - 0, 0, 0, 62, 0, 0, 0, 63, 52, 53, //50 |
46 | | - 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, //60 |
47 | | - 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, //70 |
48 | | - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, //80 |
49 | | - 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, //90 |
50 | | - 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, //100 |
51 | | - 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, //110 |
52 | | - 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, //120 |
53 | | - 49, 50, 51, 0, 0, 0, 0, 0, 0, 0, //130 |
54 | | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //140 |
55 | | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //150 |
56 | | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //160 |
57 | | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //170 |
58 | | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //180 |
59 | | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //190 |
60 | | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //200 |
61 | | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //210 |
62 | | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //220 |
63 | | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //230 |
64 | | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //240 |
65 | | - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //250 |
66 | | - 0, 0, 0, 0, 0, 0, |
67 | | -}; // This array has 256 elements |
68 | | - |
69 | | -// Converts binary data of length=len to base64 characters. |
70 | | -// Length of the resultant string is stored in flen |
71 | | -// (you must pass pointer flen). |
72 | | -char* UA_base64( const void* binaryData, int len, int *flen ) |
73 | | -{ |
74 | | - const unsigned char* bin = (const unsigned char*) binaryData ; |
75 | | - char* res ; |
76 | | - |
77 | | - int rc = 0 ; // result counter |
78 | | - int byteNo ; // I need this after the loop |
79 | | - |
80 | | - int modulusLen = len % 3 ; |
81 | | - int pad = ((modulusLen&1)<<1) + ((modulusLen&2)>>1) ; // 2 gives 1 and 1 gives 2, but 0 gives 0. |
| 13 | +static const unsigned char base64_table[65] = |
| 14 | + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
82 | 15 |
|
83 | | - *flen = 4*(len + pad)/3 ; |
84 | | - res = (char*) malloc( (size_t)(*flen + 1) ) ; // and one for the null |
85 | | - if( !res ) |
86 | | - { |
87 | | - puts( "ERROR: base64 could not allocate enough memory." ) ; |
88 | | - puts( "I must stop because I could not get enough" ) ; |
89 | | - return 0; |
| 16 | +unsigned char * |
| 17 | +UA_base64(const unsigned char *src, size_t len, size_t *out_len) { |
| 18 | + if(len == 0) { |
| 19 | + *out_len = 0; |
| 20 | + return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL; |
90 | 21 | } |
91 | 22 |
|
92 | | - for( byteNo = 0 ; byteNo <= len-3 ; byteNo+=3 ) |
93 | | - { |
94 | | - unsigned char BYTE0=bin[byteNo]; |
95 | | - unsigned char BYTE1=bin[byteNo+1]; |
96 | | - unsigned char BYTE2=bin[byteNo+2]; |
97 | | - res[rc++] = b64[ BYTE0 >> 2 ] ; |
98 | | - res[rc++] = b64[ ((0x3&BYTE0)<<4) + (BYTE1 >> 4) ] ; |
99 | | - res[rc++] = b64[ ((0x0f&BYTE1)<<2) + (BYTE2>>6) ] ; |
100 | | - res[rc++] = b64[ 0x3f&BYTE2 ] ; |
101 | | - } |
102 | | - |
103 | | - if( pad==2 ) |
104 | | - { |
105 | | - res[rc++] = b64[ bin[byteNo] >> 2 ] ; |
106 | | - res[rc++] = b64[ (0x3&bin[byteNo])<<4 ] ; |
107 | | - res[rc++] = '='; |
108 | | - res[rc++] = '='; |
109 | | - } |
110 | | - else if( pad==1 ) |
111 | | - { |
112 | | - res[rc++] = b64[ bin[byteNo] >> 2 ] ; |
113 | | - res[rc++] = b64[ ((0x3&bin[byteNo])<<4) + (bin[byteNo+1] >> 4) ] ; |
114 | | - res[rc++] = b64[ (0x0f&bin[byteNo+1])<<2 ] ; |
115 | | - res[rc++] = '='; |
116 | | - } |
117 | | - |
118 | | - res[rc]=0; // NULL TERMINATOR! ;) |
119 | | - return res ; |
| 23 | + size_t olen = 4*((len + 2) / 3); /* 3-byte blocks to 4-byte */ |
| 24 | + if(olen < len) |
| 25 | + return NULL; /* integer overflow */ |
| 26 | + |
| 27 | + unsigned char *out = (unsigned char*)UA_malloc(olen); |
| 28 | + if(!out) |
| 29 | + return NULL; |
| 30 | + |
| 31 | + const unsigned char *end = src + len; |
| 32 | + const unsigned char *in = src; |
| 33 | + unsigned char *pos = out; |
| 34 | + while(end - in >= 3) { |
| 35 | + *pos++ = base64_table[in[0] >> 2]; |
| 36 | + *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; |
| 37 | + *pos++ = base64_table[((in[1] & 0x0f) << 2) | (in[2] >> 6)]; |
| 38 | + *pos++ = base64_table[in[2] & 0x3f]; |
| 39 | + in += 3; |
| 40 | + } |
| 41 | + |
| 42 | + if(end - in) { |
| 43 | + *pos++ = base64_table[in[0] >> 2]; |
| 44 | + if(end - in == 1) { |
| 45 | + *pos++ = base64_table[(in[0] & 0x03) << 4]; |
| 46 | + *pos++ = '='; |
| 47 | + } else { |
| 48 | + *pos++ = base64_table[((in[0] & 0x03) << 4) | (in[1] >> 4)]; |
| 49 | + *pos++ = base64_table[(in[1] & 0x0f) << 2]; |
| 50 | + } |
| 51 | + *pos++ = '='; |
| 52 | + } |
| 53 | + |
| 54 | + *out_len = (size_t)(pos - out); |
| 55 | + return out; |
120 | 56 | } |
121 | 57 |
|
122 | | -unsigned char* UA_unbase64( const char* ascii, int len, int *flen ) |
123 | | -{ |
124 | | - const unsigned char *safeAsciiPtr = (const unsigned char*)ascii ; |
125 | | - unsigned char *bin ; |
126 | | - int cb=0; |
127 | | - int charNo; |
128 | | - int pad = 0 ; |
129 | | - |
130 | | - if( len < 2 ) { // 2 accesses below would be OOB. |
131 | | - // catch empty string, return NULL as result. |
132 | | - puts( "ERROR: You passed an invalid base64 string (too short). You get NULL back." ) ; |
133 | | - *flen=0; |
134 | | - return 0 ; |
| 58 | +static const uint32_t from_b64[256] = { |
| 59 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 60 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, |
| 61 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 63, 62, 62, 63, |
| 62 | + 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, |
| 63 | + 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, |
| 64 | + 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 63, |
| 65 | + 0, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, |
| 66 | + 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51}; |
| 67 | + |
| 68 | +unsigned char * |
| 69 | +UA_unbase64(const unsigned char *src, size_t len, size_t *out_len) { |
| 70 | + if(len == 0) { |
| 71 | + *out_len = 0; |
| 72 | + return (unsigned char*)UA_EMPTY_ARRAY_SENTINEL; |
135 | 73 | } |
136 | | - if( safeAsciiPtr[ len-1 ]=='=' ) ++pad ; |
137 | | - if( safeAsciiPtr[ len-2 ]=='=' ) ++pad ; |
138 | 74 |
|
139 | | - *flen = 3*len/4 - pad ; |
140 | | - bin = (unsigned char*)malloc( (size_t) (*flen) ) ; |
141 | | - if( !bin ) |
142 | | - { |
143 | | - puts( "ERROR: unbase64 could not allocate enough memory." ) ; |
144 | | - puts( "I must stop because I could not get enough" ) ; |
145 | | - return 0; |
| 75 | + const unsigned char *p = src; |
| 76 | + size_t pad1 = len % 4 || p[len - 1] == '='; |
| 77 | + size_t pad2 = pad1 && (len % 4 > 2 || p[len - 2] != '='); |
| 78 | + const size_t last = (len - pad1) / 4 << 2; |
| 79 | + |
| 80 | + unsigned char *str = (unsigned char*)UA_malloc(last / 4 * 3 + pad1 + pad2); |
| 81 | + if(!str) |
| 82 | + return NULL; |
| 83 | + |
| 84 | + unsigned char *pos = str; |
| 85 | + for(size_t i = 0; i < last; i += 4) { |
| 86 | + uint32_t n = from_b64[p[i]] << 18 | from_b64[p[i + 1]] << 12 | |
| 87 | + from_b64[p[i + 2]] << 6 | from_b64[p[i + 3]]; |
| 88 | + *pos++ = (unsigned char)(n >> 16); |
| 89 | + *pos++ = (unsigned char)(n >> 8 & 0xFF); |
| 90 | + *pos++ = (unsigned char)(n & 0xFF); |
146 | 91 | } |
147 | 92 |
|
148 | | - for( charNo=0; charNo <= len - 4 - pad ; charNo+=4 ) |
149 | | - { |
150 | | - int A=unb64[safeAsciiPtr[charNo]]; |
151 | | - int B=unb64[safeAsciiPtr[charNo+1]]; |
152 | | - int C=unb64[safeAsciiPtr[charNo+2]]; |
153 | | - int D=unb64[safeAsciiPtr[charNo+3]]; |
154 | | - |
155 | | - bin[cb++] = (unsigned char)((A<<2) | (B>>4)) ; |
156 | | - bin[cb++] = (unsigned char)((B<<4) | (C>>2)) ; |
157 | | - bin[cb++] = (unsigned char)((C<<6) | (D)) ; |
| 93 | + if(pad1) { |
| 94 | + uint32_t n = from_b64[p[last]] << 18 | from_b64[p[last + 1]] << 12; |
| 95 | + *pos++ = (unsigned char)(n >> 16); |
| 96 | + if(pad2) { |
| 97 | + n |= from_b64[p[last + 2]] << 6; |
| 98 | + *pos++ = (unsigned char)(n >> 8 & 0xFF); |
| 99 | + } |
158 | 100 | } |
159 | 101 |
|
160 | | - if( pad==1 ) |
161 | | - { |
162 | | - int A=unb64[safeAsciiPtr[charNo]]; |
163 | | - int B=unb64[safeAsciiPtr[charNo+1]]; |
164 | | - int C=unb64[safeAsciiPtr[charNo+2]]; |
165 | | - |
166 | | - bin[cb++] = (unsigned char)((A<<2) | (B>>4)) ; |
167 | | - bin[cb++] = (unsigned char)((B<<4) | (C>>2)) ; |
168 | | - } |
169 | | - else if( pad==2 ) |
170 | | - { |
171 | | - int A=unb64[safeAsciiPtr[charNo]]; |
172 | | - int B=unb64[safeAsciiPtr[charNo+1]]; |
173 | | - |
174 | | - bin[cb++] = (unsigned char)((A<<2) | (B>>4)) ; |
175 | | - } |
176 | | - |
177 | | - return bin ; |
| 102 | + *out_len = (uintptr_t)(pos - str); |
| 103 | + return str; |
178 | 104 | } |
179 | | - |
0 commit comments