Fixes default log output to console for macOS
[sqlcipher.git] / ext / misc / base64.c
blobbc7a976abcf905b555fee14a73ae1b738a140bdb
1 /*
2 ** 2022-11-18
3 **
4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
6 **
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 *************************************************************************
13 ** This is a SQLite extension for converting in either direction
14 ** between a (binary) blob and base64 text. Base64 can transit a
15 ** sane USASCII channel unmolested. It also plays nicely in CSV or
16 ** written as TCL brace-enclosed literals or SQL string literals,
17 ** and can be used unmodified in XML-like documents.
19 ** This is an independent implementation of conversions specified in
20 ** RFC 4648, done on the above date by the author (Larry Brasfield)
21 ** who thereby has the right to put this into the public domain.
23 ** The conversions meet RFC 4648 requirements, provided that this
24 ** C source specifies that line-feeds are included in the encoded
25 ** data to limit visible line lengths to 72 characters and to
26 ** terminate any encoded blob having non-zero length.
28 ** Length limitations are not imposed except that the runtime
29 ** SQLite string or blob length limits are respected. Otherwise,
30 ** any length binary sequence can be represented and recovered.
31 ** Generated base64 sequences, with their line-feeds included,
32 ** can be concatenated; the result converted back to binary will
33 ** be the concatenation of the represented binary sequences.
35 ** This SQLite3 extension creates a function, base64(x), which
36 ** either: converts text x containing base64 to a returned blob;
37 ** or converts a blob x to returned text containing base64. An
38 ** error will be thrown for other input argument types.
40 ** This code relies on UTF-8 encoding only with respect to the
41 ** meaning of the first 128 (7-bit) codes matching that of USASCII.
42 ** It will fail miserably if somehow made to try to convert EBCDIC.
43 ** Because it is table-driven, it could be enhanced to handle that,
44 ** but the world and SQLite have moved on from that anachronism.
46 ** To build the extension:
47 ** Set shell variable SQDIR=<your favorite SQLite checkout directory>
48 ** *Nix: gcc -O2 -shared -I$SQDIR -fPIC -o base64.so base64.c
49 ** OSX: gcc -O2 -dynamiclib -fPIC -I$SQDIR -o base64.dylib base64.c
50 ** Win32: gcc -O2 -shared -I%SQDIR% -o base64.dll base64.c
51 ** Win32: cl /Os -I%SQDIR% base64.c -link -dll -out:base64.dll
54 #include <assert.h>
56 #include "sqlite3ext.h"
58 #ifndef deliberate_fall_through
59 /* Quiet some compilers about some of our intentional code. */
60 # if GCC_VERSION>=7000000
61 # define deliberate_fall_through __attribute__((fallthrough));
62 # else
63 # define deliberate_fall_through
64 # endif
65 #endif
67 SQLITE_EXTENSION_INIT1;
69 #define PC 0x80 /* pad character */
70 #define WS 0x81 /* whitespace */
71 #define ND 0x82 /* Not above or digit-value */
72 #define PAD_CHAR '='
74 #ifndef U8_TYPEDEF
75 typedef unsigned char u8;
76 #define U8_TYPEDEF
77 #endif
79 /* Decoding table, ASCII (7-bit) value to base 64 digit value or other */
80 static const u8 b64DigitValues[128] = {
81 /* HT LF VT FF CR */
82 ND,ND,ND,ND, ND,ND,ND,ND, ND,WS,WS,WS, WS,WS,ND,ND,
83 /* US */
84 ND,ND,ND,ND, ND,ND,ND,ND, ND,ND,ND,ND, ND,ND,ND,ND,
85 /*sp + / */
86 WS,ND,ND,ND, ND,ND,ND,ND, ND,ND,ND,62, ND,ND,ND,63,
87 /* 0 1 5 9 = */
88 52,53,54,55, 56,57,58,59, 60,61,ND,ND, ND,PC,ND,ND,
89 /* A O */
90 ND, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14,
91 /* P Z */
92 15,16,17,18, 19,20,21,22, 23,24,25,ND, ND,ND,ND,ND,
93 /* a o */
94 ND,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
95 /* p z */
96 41,42,43,44, 45,46,47,48, 49,50,51,ND, ND,ND,ND,ND
99 static const char b64Numerals[64+1]
100 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
102 #define BX_DV_PROTO(c) \
103 ((((u8)(c))<0x80)? (u8)(b64DigitValues[(u8)(c)]) : 0x80)
104 #define IS_BX_DIGIT(bdp) (((u8)(bdp))<0x80)
105 #define IS_BX_WS(bdp) ((bdp)==WS)
106 #define IS_BX_PAD(bdp) ((bdp)==PC)
107 #define BX_NUMERAL(dv) (b64Numerals[(u8)(dv)])
108 /* Width of base64 lines. Should be an integer multiple of 4. */
109 #define B64_DARK_MAX 72
111 /* Encode a byte buffer into base64 text with linefeeds appended to limit
112 ** encoded group lengths to B64_DARK_MAX or to terminate the last group.
114 static char* toBase64( u8 *pIn, int nbIn, char *pOut ){
115 int nCol = 0;
116 while( nbIn >= 3 ){
117 /* Do the bit-shuffle, exploiting unsigned input to avoid masking. */
118 pOut[0] = BX_NUMERAL(pIn[0]>>2);
119 pOut[1] = BX_NUMERAL(((pIn[0]<<4)|(pIn[1]>>4))&0x3f);
120 pOut[2] = BX_NUMERAL(((pIn[1]&0xf)<<2)|(pIn[2]>>6));
121 pOut[3] = BX_NUMERAL(pIn[2]&0x3f);
122 pOut += 4;
123 nbIn -= 3;
124 pIn += 3;
125 if( (nCol += 4)>=B64_DARK_MAX || nbIn<=0 ){
126 *pOut++ = '\n';
127 nCol = 0;
130 if( nbIn > 0 ){
131 signed char nco = nbIn+1;
132 int nbe;
133 unsigned long qv = *pIn++;
134 for( nbe=1; nbe<3; ++nbe ){
135 qv <<= 8;
136 if( nbe<nbIn ) qv |= *pIn++;
138 for( nbe=3; nbe>=0; --nbe ){
139 char ce = (nbe<nco)? BX_NUMERAL((u8)(qv & 0x3f)) : PAD_CHAR;
140 qv >>= 6;
141 pOut[nbe] = ce;
143 pOut += 4;
144 *pOut++ = '\n';
146 *pOut = 0;
147 return pOut;
150 /* Skip over text which is not base64 numeral(s). */
151 static char * skipNonB64( char *s, int nc ){
152 char c;
153 while( nc-- > 0 && (c = *s) && !IS_BX_DIGIT(BX_DV_PROTO(c)) ) ++s;
154 return s;
157 /* Decode base64 text into a byte buffer. */
158 static u8* fromBase64( char *pIn, int ncIn, u8 *pOut ){
159 if( ncIn>0 && pIn[ncIn-1]=='\n' ) --ncIn;
160 while( ncIn>0 && *pIn!=PAD_CHAR ){
161 static signed char nboi[] = { 0, 0, 1, 2, 3 };
162 char *pUse = skipNonB64(pIn, ncIn);
163 unsigned long qv = 0L;
164 int nti, nbo, nac;
165 ncIn -= (pUse - pIn);
166 pIn = pUse;
167 nti = (ncIn>4)? 4 : ncIn;
168 ncIn -= nti;
169 nbo = nboi[nti];
170 if( nbo==0 ) break;
171 for( nac=0; nac<4; ++nac ){
172 char c = (nac<nti)? *pIn++ : b64Numerals[0];
173 u8 bdp = BX_DV_PROTO(c);
174 switch( bdp ){
175 case ND:
176 /* Treat dark non-digits as pad, but they terminate decode too. */
177 ncIn = 0;
178 deliberate_fall_through;
179 case WS:
180 /* Treat whitespace as pad and terminate this group.*/
181 nti = nac;
182 deliberate_fall_through;
183 case PC:
184 bdp = 0;
185 --nbo;
186 deliberate_fall_through;
187 default: /* bdp is the digit value. */
188 qv = qv<<6 | bdp;
189 break;
192 switch( nbo ){
193 case 3:
194 pOut[2] = (qv) & 0xff;
195 case 2:
196 pOut[1] = (qv>>8) & 0xff;
197 case 1:
198 pOut[0] = (qv>>16) & 0xff;
200 pOut += nbo;
202 return pOut;
205 /* This function does the work for the SQLite base64(x) UDF. */
206 static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){
207 int nb, nc, nv = sqlite3_value_bytes(av[0]);
208 int nvMax = sqlite3_limit(sqlite3_context_db_handle(context),
209 SQLITE_LIMIT_LENGTH, -1);
210 char *cBuf;
211 u8 *bBuf;
212 assert(na==1);
213 switch( sqlite3_value_type(av[0]) ){
214 case SQLITE_BLOB:
215 nb = nv;
216 nc = 4*(nv+2/3); /* quads needed */
217 nc += (nc+(B64_DARK_MAX-1))/B64_DARK_MAX + 1; /* LFs and a 0-terminator */
218 if( nvMax < nc ){
219 sqlite3_result_error(context, "blob expanded to base64 too big", -1);
220 return;
222 bBuf = (u8*)sqlite3_value_blob(av[0]);
223 if( !bBuf ){
224 if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){
225 goto memFail;
227 sqlite3_result_text(context,"",-1,SQLITE_STATIC);
228 break;
230 cBuf = sqlite3_malloc(nc);
231 if( !cBuf ) goto memFail;
232 nc = (int)(toBase64(bBuf, nb, cBuf) - cBuf);
233 sqlite3_result_text(context, cBuf, nc, sqlite3_free);
234 break;
235 case SQLITE_TEXT:
236 nc = nv;
237 nb = 3*((nv+3)/4); /* may overestimate due to LF and padding */
238 if( nvMax < nb ){
239 sqlite3_result_error(context, "blob from base64 may be too big", -1);
240 return;
241 }else if( nb<1 ){
242 nb = 1;
244 cBuf = (char *)sqlite3_value_text(av[0]);
245 if( !cBuf ){
246 if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){
247 goto memFail;
249 sqlite3_result_zeroblob(context, 0);
250 break;
252 bBuf = sqlite3_malloc(nb);
253 if( !bBuf ) goto memFail;
254 nb = (int)(fromBase64(cBuf, nc, bBuf) - bBuf);
255 sqlite3_result_blob(context, bBuf, nb, sqlite3_free);
256 break;
257 default:
258 sqlite3_result_error(context, "base64 accepts only blob or text", -1);
259 return;
261 return;
262 memFail:
263 sqlite3_result_error(context, "base64 OOM", -1);
267 ** Establish linkage to running SQLite library.
269 #ifndef SQLITE_SHELL_EXTFUNCS
270 #ifdef _WIN32
271 __declspec(dllexport)
272 #endif
273 int sqlite3_base_init
274 #else
275 static int sqlite3_base64_init
276 #endif
277 (sqlite3 *db, char **pzErr, const sqlite3_api_routines *pApi){
278 SQLITE_EXTENSION_INIT2(pApi);
279 (void)pzErr;
280 return sqlite3_create_function
281 (db, "base64", 1,
282 SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS|SQLITE_DIRECTONLY|SQLITE_UTF8,
283 0, base64, 0, 0);
287 ** Define some macros to allow this extension to be built into the shell
288 ** conveniently, in conjunction with use of SQLITE_SHELL_EXTFUNCS. This
289 ** allows shell.c, as distributed, to have this extension built in.
291 #define BASE64_INIT(db) sqlite3_base64_init(db, 0, 0)
292 #define BASE64_EXPOSE(db, pzErr) /* Not needed, ..._init() does this. */