LCOV - code coverage report
Current view: top level - ballet/base64 - fd_base64.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 68 68 100.0 %
Date: 2025-08-05 05:04:49 Functions: 2 2 100.0 %

          Line data    Source code
       1             : #include "fd_base64.h"
       2             : 
       3             : static const char base64_alphabet[] =
       4             :     "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
       5             : 
       6             : /* Inverse lookup table of ASCII byte => Base64 code point.
       7             : 
       8             :    Simple Base64 decode. Could do better here, but it's good
       9             :    enough for now.  One obvious optimization is to provide
      10             :    multiple LUTs for each limb of the encoded word, then AND
      11             :    them together. */
      12             : 
      13             : static uchar const invlut[ 0x100 ] = {
      14             :   /* 0x00 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      15             :   /* 0x08 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      16             :   /* 0x10 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      17             :   /* 0x18 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      18             :   /* 0x20 */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      19             :   /* 0x28 */ 0xff, 0xff, 0xff, 0x3e, 0xff, 0xff, 0xff, 0x3f,
      20             :   /* 0x30 */ 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
      21             :   /* 0x38 */ 0x3c, 0x3d, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      22             :   /* 0x40 */ 0xff, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
      23             :   /* 0x48 */ 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
      24             :   /* 0x50 */ 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16,
      25             :   /* 0x58 */ 0x17, 0x18, 0x19, 0xff, 0xff, 0xff, 0xff, 0xff,
      26             :   /* 0x60 */ 0xff, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20,
      27             :   /* 0x68 */ 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
      28             :   /* 0x70 */ 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
      29             :   /* 0x78 */ 0x31, 0x32, 0x33, 0xff, 0xff, 0xff, 0xff, 0xff,
      30             :              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      31             :              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      32             :              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      33             :              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      34             :              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      35             :              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      36             :              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      37             :              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      38             :              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      39             :              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      40             :              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      41             :              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      42             :              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      43             :              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      44             :              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
      45             :              0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
      46             : };
      47             : 
      48             : long
      49             : fd_base64_decode( uchar *      out,
      50             :                   char const * in,
      51      630090 :                   ulong        in_len ) {
      52             : 
      53      630090 :   uchar * const out_orig = out;
      54             : 
      55      630090 :   if( in_len==0UL ) return 0UL;
      56             : 
      57      629580 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( in_len, 4UL ) ) ) return -1L;
      58             : 
      59      629550 :   ulong pad_cnt = 0UL;
      60      629550 :   if( in[ in_len-2UL ]=='=' ) pad_cnt++;
      61      629550 :   if( in[ in_len-1UL ]=='=' ) pad_cnt++;
      62      629550 :   in_len -= pad_cnt;
      63             : 
      64             :   /* 3 char padding is invalid */
      65      629550 :   if( FD_UNLIKELY( (in_len%4UL)==1UL ) ) return -1L;
      66             : 
      67             :   /* "Fast" decode */
      68             : 
      69  2729429931 :   while( in_len>=4UL ) {
      70  2728800393 :     int a = (schar)invlut[ (ulong)(uchar)in[ 0 ] ];
      71  2728800393 :     int b = (schar)invlut[ (ulong)(uchar)in[ 1 ] ];
      72  2728800393 :     int c = (schar)invlut[ (ulong)(uchar)in[ 2 ] ];
      73  2728800393 :     int d = (schar)invlut[ (ulong)(uchar)in[ 3 ] ];
      74             : 
      75  2728800393 :     int err = (a<0) | (b<0) | (c<0) | (d<0);
      76  2728800393 :     if( FD_UNLIKELY( err ) ) return -1L;
      77             : 
      78  2728800381 :     ulong triple = ((ulong)a<<18UL) | ((ulong)b<<12UL) | ((ulong)c<<6UL) | ((ulong)d);
      79             : 
      80  2728800381 :     out[ 0 ] = (uchar)(triple>>16UL);
      81  2728800381 :     out[ 1 ] = (uchar)(triple>> 8UL);
      82  2728800381 :     out[ 2 ] = (uchar)(triple>> 0UL);
      83             : 
      84  2728800381 :     in     += 4L;
      85  2728800381 :     in_len -= 4L;
      86  2728800381 :     out    += 3L;
      87  2728800381 :   }
      88             : 
      89             :   /* Decode last chunk */
      90             : 
      91      629538 :   if( in_len>0UL ) {
      92             : 
      93      200028 :     int a = (schar)invlut[ (ulong)(uchar)in[ 0 ] ];
      94      200028 :     int b = (schar)invlut[ (ulong)(uchar)in[ 1 ] ];
      95      200028 :     int c = 0;
      96      200028 :     if( in_len==3 )
      97       99846 :         c = (schar)invlut[ (ulong)(uchar)in[ 2 ] ];
      98             : 
      99      200028 :     int err = (a<0) | (b<0) | (c<0);
     100      200028 :     if( FD_UNLIKELY( err ) ) return -1L;
     101             : 
     102      200019 :     ulong triple   = ((ulong)a<<18UL) | ((ulong)b<<12UL) | ((ulong)c<<6UL);
     103      200019 :           triple   = fd_ulong_bswap( triple );
     104      200019 :           triple >>= 40UL;
     105             : 
     106      200019 :     switch( in_len ) {
     107       99843 :     case 3: *out = (uchar)triple;
     108       99843 :              out++;
     109       99843 :             triple>>=8UL;
     110       99843 :             __attribute__((fallthrough));
     111      200019 :     case 2: *out = (uchar)triple;
     112      200019 :              out++;
     113      200019 :     }
     114             : 
     115      629529 :   } while(0);
     116             : 
     117      629529 :   return out - out_orig;
     118      629538 : }
     119             : 
     120             : ulong
     121             : fd_base64_encode( char *       encoded,
     122             :                   void const * _data,
     123      300054 :                   ulong        data_len ) {
     124             : 
     125      300054 :   uchar const * data = fd_type_pun_const( _data );
     126             : 
     127      300054 :   uint encoded_len = 0;
     128      300054 :   uint accumulator = 0;
     129      300054 :   int bits_collected = 0;
     130             : 
     131    76849650 :   while( data_len-- ) {
     132    76549596 :     accumulator = ( accumulator << 8 ) | *data++;
     133    76549596 :     bits_collected += 8;
     134             : 
     135   178515759 :     while( bits_collected >= 6 ) {
     136   101966163 :       encoded[ encoded_len++ ] = base64_alphabet[ ( accumulator >> ( bits_collected - 6) ) & 0x3F ];
     137   101966163 :       bits_collected -= 6;
     138   101966163 :     }
     139    76549596 :   }
     140             : 
     141      300054 :   if( bits_collected > 0 ) {
     142             :     // If there are remaining bits, pad the last Base64 character with zeroes
     143      200037 :     accumulator <<= 6 - bits_collected;
     144      200037 :     encoded[ encoded_len++ ] = base64_alphabet[accumulator & 0x3F ];
     145      200037 :   }
     146             : 
     147             :   // Add padding characters if necessary
     148      600270 :   while( encoded_len % 4 != 0 ) {
     149      300216 :     encoded[ encoded_len++ ] = '=';
     150      300216 :   }
     151             : 
     152      300054 :   return encoded_len;
     153      300054 : }

Generated by: LCOV version 1.14