| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include <assert.h> |
| |
|
| | #include "sqlite3ext.h" |
| |
|
| | #ifndef deliberate_fall_through |
| | |
| | # if GCC_VERSION>=7000000 |
| | # define deliberate_fall_through __attribute__((fallthrough)); |
| | # else |
| | # define deliberate_fall_through |
| | # endif |
| | #endif |
| |
|
| | SQLITE_EXTENSION_INIT1; |
| |
|
| | #define PC 0x80 |
| | #define WS 0x81 |
| | #define ND 0x82 |
| | #define PAD_CHAR '=' |
| |
|
| | #ifndef U8_TYPEDEF |
| | typedef unsigned char u8; |
| | #define U8_TYPEDEF |
| | #endif |
| |
|
| | |
| | static const u8 b64DigitValues[128] = { |
| | |
| | ND,ND,ND,ND, ND,ND,ND,ND, ND,WS,WS,WS, WS,WS,ND,ND, |
| | |
| | ND,ND,ND,ND, ND,ND,ND,ND, ND,ND,ND,ND, ND,ND,ND,ND, |
| | |
| | WS,ND,ND,ND, ND,ND,ND,ND, ND,ND,ND,62, ND,ND,ND,63, |
| | |
| | 52,53,54,55, 56,57,58,59, 60,61,ND,ND, ND,PC,ND,ND, |
| | |
| | ND, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, |
| | |
| | 15,16,17,18, 19,20,21,22, 23,24,25,ND, ND,ND,ND,ND, |
| | |
| | ND,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, |
| | |
| | 41,42,43,44, 45,46,47,48, 49,50,51,ND, ND,ND,ND,ND |
| | }; |
| |
|
| | static const char b64Numerals[64+1] |
| | = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; |
| |
|
| | #define BX_DV_PROTO(c) \ |
| | ((((u8)(c))<0x80)? (u8)(b64DigitValues[(u8)(c)]) : 0x80) |
| | #define IS_BX_DIGIT(bdp) (((u8)(bdp))<0x80) |
| | #define IS_BX_WS(bdp) ((bdp)==WS) |
| | #define IS_BX_PAD(bdp) ((bdp)==PC) |
| | #define BX_NUMERAL(dv) (b64Numerals[(u8)(dv)]) |
| | |
| | #define B64_DARK_MAX 72 |
| |
|
| | |
| | |
| | |
| | static char* toBase64( u8 *pIn, int nbIn, char *pOut ){ |
| | int nCol = 0; |
| | while( nbIn >= 3 ){ |
| | |
| | pOut[0] = BX_NUMERAL(pIn[0]>>2); |
| | pOut[1] = BX_NUMERAL(((pIn[0]<<4)|(pIn[1]>>4))&0x3f); |
| | pOut[2] = BX_NUMERAL(((pIn[1]&0xf)<<2)|(pIn[2]>>6)); |
| | pOut[3] = BX_NUMERAL(pIn[2]&0x3f); |
| | pOut += 4; |
| | nbIn -= 3; |
| | pIn += 3; |
| | if( (nCol += 4)>=B64_DARK_MAX || nbIn<=0 ){ |
| | *pOut++ = '\n'; |
| | nCol = 0; |
| | } |
| | } |
| | if( nbIn > 0 ){ |
| | signed char nco = nbIn+1; |
| | int nbe; |
| | unsigned long qv = *pIn++; |
| | for( nbe=1; nbe<3; ++nbe ){ |
| | qv <<= 8; |
| | if( nbe<nbIn ) qv |= *pIn++; |
| | } |
| | for( nbe=3; nbe>=0; --nbe ){ |
| | char ce = (nbe<nco)? BX_NUMERAL((u8)(qv & 0x3f)) : PAD_CHAR; |
| | qv >>= 6; |
| | pOut[nbe] = ce; |
| | } |
| | pOut += 4; |
| | *pOut++ = '\n'; |
| | } |
| | *pOut = 0; |
| | return pOut; |
| | } |
| |
|
| | |
| | static char * skipNonB64( char *s, int nc ){ |
| | char c; |
| | while( nc-- > 0 && (c = *s) && !IS_BX_DIGIT(BX_DV_PROTO(c)) ) ++s; |
| | return s; |
| | } |
| |
|
| | |
| | static u8* fromBase64( char *pIn, int ncIn, u8 *pOut ){ |
| | if( ncIn>0 && pIn[ncIn-1]=='\n' ) --ncIn; |
| | while( ncIn>0 && *pIn!=PAD_CHAR ){ |
| | static signed char nboi[] = { 0, 0, 1, 2, 3 }; |
| | char *pUse = skipNonB64(pIn, ncIn); |
| | unsigned long qv = 0L; |
| | int nti, nbo, nac; |
| | ncIn -= (pUse - pIn); |
| | pIn = pUse; |
| | nti = (ncIn>4)? 4 : ncIn; |
| | ncIn -= nti; |
| | nbo = nboi[nti]; |
| | if( nbo==0 ) break; |
| | for( nac=0; nac<4; ++nac ){ |
| | char c = (nac<nti)? *pIn++ : b64Numerals[0]; |
| | u8 bdp = BX_DV_PROTO(c); |
| | switch( bdp ){ |
| | case ND: |
| | |
| | ncIn = 0; |
| | deliberate_fall_through; |
| | case WS: |
| | |
| | nti = nac; |
| | deliberate_fall_through; |
| | case PC: |
| | bdp = 0; |
| | --nbo; |
| | deliberate_fall_through; |
| | default: |
| | qv = qv<<6 | bdp; |
| | break; |
| | } |
| | } |
| | switch( nbo ){ |
| | case 3: |
| | pOut[2] = (qv) & 0xff; |
| | deliberate_fall_through; |
| | case 2: |
| | pOut[1] = (qv>>8) & 0xff; |
| | deliberate_fall_through; |
| | case 1: |
| | pOut[0] = (qv>>16) & 0xff; |
| | break; |
| | } |
| | pOut += nbo; |
| | } |
| | return pOut; |
| | } |
| |
|
| | |
| | static void base64(sqlite3_context *context, int na, sqlite3_value *av[]){ |
| | sqlite3_int64 nb; |
| | sqlite3_int64 nv = sqlite3_value_bytes(av[0]); |
| | sqlite3_int64 nc; |
| | int nvMax = sqlite3_limit(sqlite3_context_db_handle(context), |
| | SQLITE_LIMIT_LENGTH, -1); |
| | char *cBuf; |
| | u8 *bBuf; |
| | assert(na==1); |
| | switch( sqlite3_value_type(av[0]) ){ |
| | case SQLITE_BLOB: |
| | nb = nv; |
| | nc = 4*((nv+2)/3); |
| | nc += (nc+(B64_DARK_MAX-1))/B64_DARK_MAX + 1; |
| | if( nvMax < nc ){ |
| | sqlite3_result_error(context, "blob expanded to base64 too big", -1); |
| | return; |
| | } |
| | bBuf = (u8*)sqlite3_value_blob(av[0]); |
| | if( !bBuf ){ |
| | if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){ |
| | goto memFail; |
| | } |
| | sqlite3_result_text(context,"",-1,SQLITE_STATIC); |
| | break; |
| | } |
| | cBuf = sqlite3_malloc(nc); |
| | if( !cBuf ) goto memFail; |
| | nc = (int)(toBase64(bBuf, nb, cBuf) - cBuf); |
| | sqlite3_result_text(context, cBuf, nc, sqlite3_free); |
| | break; |
| | case SQLITE_TEXT: |
| | nc = nv; |
| | nb = 3*((nv+3)/4); |
| | if( nvMax < nb ){ |
| | sqlite3_result_error(context, "blob from base64 may be too big", -1); |
| | return; |
| | }else if( nb<1 ){ |
| | nb = 1; |
| | } |
| | cBuf = (char *)sqlite3_value_text(av[0]); |
| | if( !cBuf ){ |
| | if( SQLITE_NOMEM==sqlite3_errcode(sqlite3_context_db_handle(context)) ){ |
| | goto memFail; |
| | } |
| | sqlite3_result_zeroblob(context, 0); |
| | break; |
| | } |
| | bBuf = sqlite3_malloc(nb); |
| | if( !bBuf ) goto memFail; |
| | nb = (int)(fromBase64(cBuf, nc, bBuf) - bBuf); |
| | sqlite3_result_blob(context, bBuf, nb, sqlite3_free); |
| | break; |
| | default: |
| | sqlite3_result_error(context, "base64 accepts only blob or text", -1); |
| | return; |
| | } |
| | return; |
| | memFail: |
| | sqlite3_result_error(context, "base64 OOM", -1); |
| | } |
| |
|
| | |
| | |
| | |
| | #ifndef SQLITE_SHELL_EXTFUNCS |
| | #ifdef _WIN32 |
| | __declspec(dllexport) |
| | #endif |
| | int sqlite3_base_init |
| | #else |
| | static int sqlite3_base64_init |
| | #endif |
| | (sqlite3 *db, char **pzErr, const sqlite3_api_routines *pApi){ |
| | SQLITE_EXTENSION_INIT2(pApi); |
| | (void)pzErr; |
| | return sqlite3_create_function |
| | (db, "base64", 1, |
| | SQLITE_DETERMINISTIC|SQLITE_INNOCUOUS|SQLITE_DIRECTONLY|SQLITE_UTF8, |
| | 0, base64, 0, 0); |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | #define BASE64_INIT(db) sqlite3_base64_init(db, 0, 0) |
| | #define BASE64_EXPOSE(db, pzErr) |
| |
|