LCOV - code coverage report
Current view: top level - ballet/base64 - fd_base64.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 22 68 32.4 %
Date: 2024-11-13 11:58:15 Functions: 1 2 50.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           0 :                   ulong        in_len ) {
      52             : 
      53           0 :   uchar * const out_orig = out;
      54             : 
      55           0 :   if( in_len==0UL ) return 0UL;
      56             : 
      57           0 :   if( FD_UNLIKELY( !fd_ulong_is_aligned( in_len, 4UL ) ) ) return -1L;
      58             : 
      59           0 :   ulong pad_cnt = 0UL;
      60           0 :   if( in[ in_len-2UL ]=='=' ) pad_cnt++;
      61           0 :   if( in[ in_len-1UL ]=='=' ) pad_cnt++;
      62           0 :   in_len -= pad_cnt;
      63             : 
      64             :   /* 3 char padding is invalid */
      65           0 :   if( FD_UNLIKELY( (in_len%4UL)==1UL ) ) return -1L;
      66             : 
      67             :   /* "Fast" decode */
      68             : 
      69           0 :   while( in_len>=4UL ) {
      70           0 :     int a = (schar)invlut[ (ulong)(uchar)in[ 0 ] ];
      71           0 :     int b = (schar)invlut[ (ulong)(uchar)in[ 1 ] ];
      72           0 :     int c = (schar)invlut[ (ulong)(uchar)in[ 2 ] ];
      73           0 :     int d = (schar)invlut[ (ulong)(uchar)in[ 3 ] ];
      74             : 
      75           0 :     int err = (a<0) | (b<0) | (c<0) | (d<0);
      76           0 :     if( FD_UNLIKELY( err ) ) return -1L;
      77             : 
      78           0 :     ulong triple = ((ulong)a<<18UL) | ((ulong)b<<12UL) | ((ulong)c<<6UL) | ((ulong)d);
      79             : 
      80           0 :     out[ 0 ] = (uchar)(triple>>16UL);
      81           0 :     out[ 1 ] = (uchar)(triple>> 8UL);
      82           0 :     out[ 2 ] = (uchar)(triple>> 0UL);
      83             : 
      84           0 :     in     += 4L;
      85           0 :     in_len -= 4L;
      86           0 :     out    += 3L;
      87           0 :   }
      88             : 
      89             :   /* Decode last chunk */
      90             : 
      91           0 :   if( in_len>0UL ) {
      92             : 
      93           0 :     int a = (schar)invlut[ (ulong)(uchar)in[ 0 ] ];
      94           0 :     int b = (schar)invlut[ (ulong)(uchar)in[ 1 ] ];
      95           0 :     int c = 0;
      96           0 :     if( in_len==3 )
      97           0 :         c = (schar)invlut[ (ulong)(uchar)in[ 2 ] ];
      98             : 
      99           0 :     int err = (a<0) | (b<0) | (c<0);
     100           0 :     if( FD_UNLIKELY( err ) ) return -1L;
     101             : 
     102           0 :     ulong triple   = ((ulong)a<<18UL) | ((ulong)b<<12UL) | ((ulong)c<<6UL);
     103           0 :           triple   = fd_ulong_bswap( triple );
     104           0 :           triple >>= 40UL;
     105             : 
     106           0 :     switch( in_len ) {
     107           0 :     case 3: *out = (uchar)triple;
     108           0 :              out++;
     109           0 :             triple>>=8UL;
     110           0 :             __attribute__((fallthrough));
     111           0 :     case 2: *out = (uchar)triple;
     112           0 :              out++;
     113           0 :     }
     114             : 
     115           0 :   } while(0);
     116             : 
     117           0 :   return out - out_orig;
     118           0 : }
     119             : 
     120             : ulong
     121             : fd_base64_encode( char *       encoded,
     122             :                   void const * _data,
     123        3084 :                   ulong        data_len ) {
     124             : 
     125        3084 :   uchar const * data = fd_type_pun_const( _data );
     126             : 
     127        3084 :   uint encoded_len = 0;
     128        3084 :   uint accumulator = 0;
     129        3084 :   int bits_collected = 0;
     130             : 
     131       69684 :   while( data_len-- ) {
     132       66600 :     accumulator = ( accumulator << 8 ) | *data++;
     133       66600 :     bits_collected += 8;
     134             : 
     135      153369 :     while( bits_collected >= 6 ) {
     136       86769 :       encoded[ encoded_len++ ] = base64_alphabet[ ( accumulator >> ( bits_collected - 6) ) & 0x3F ];
     137       86769 :       bits_collected -= 6;
     138       86769 :     }
     139       66600 :   }
     140             : 
     141        3084 :   if( bits_collected > 0 ) {
     142             :     // If there are remaining bits, pad the last Base64 character with zeroes
     143        3057 :     accumulator <<= 6 - bits_collected;
     144        3057 :     encoded[ encoded_len++ ] = base64_alphabet[accumulator & 0x3F ];
     145        3057 :   }
     146             : 
     147             :   // Add padding characters if necessary
     148        6162 :   while( encoded_len % 4 != 0 ) {
     149        3078 :     encoded[ encoded_len++ ] = '=';
     150        3078 :   }
     151             : 
     152        3084 :   return encoded_len;
     153        3084 : }

Generated by: LCOV version 1.14