LCOV - code coverage report
Current view: top level - util/textstream - fd_textstream.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 0 270 0.0 %
Date: 2024-11-13 11:58:15 Functions: 0 14 0.0 %

          Line data    Source code
       1             : #include <stdio.h>
       2             : #include <stdlib.h>
       3             : #include <stdarg.h>
       4             : #include "../fd_util.h"
       5             : #include "fd_textstream.h"
       6             : 
       7             : struct fd_textstream_blk {
       8             :     struct fd_textstream_blk * next;
       9             :     ulong used;
      10             : };
      11             : typedef struct fd_textstream_blk fd_textstream_blk_t;
      12             : 
      13             : fd_textstream_t * fd_textstream_new( fd_textstream_t * strm,
      14             :                                      fd_valloc_t       valloc,
      15           0 :                                      ulong             alloc_sz) {
      16           0 :   strm->valloc = valloc;
      17           0 :   strm->alloc_sz = alloc_sz;
      18           0 :   fd_textstream_blk_t * blk = (fd_textstream_blk_t *)
      19           0 :     fd_valloc_malloc(valloc, alignof(fd_textstream_blk_t), sizeof(fd_textstream_blk_t) + alloc_sz);
      20           0 :   if ( blk == NULL )
      21           0 :     return NULL;
      22           0 :   blk->next = NULL;
      23           0 :   blk->used = 0;
      24           0 :   strm->first_blk = strm->last_blk = blk;
      25           0 :   return strm;
      26           0 : }
      27             : 
      28           0 : void fd_textstream_destroy( fd_textstream_t * strm ) {
      29           0 :   for ( fd_textstream_blk_t * blk = strm->first_blk; blk; ) {
      30           0 :     fd_textstream_blk_t * next = blk->next;
      31           0 :     fd_valloc_free(strm->valloc, blk);
      32           0 :     blk = next;
      33           0 :   }
      34           0 : }
      35             : 
      36           0 : void fd_textstream_clear( fd_textstream_t * strm ) {
      37           0 :   for ( fd_textstream_blk_t * blk = strm->first_blk->next; blk; ) {
      38           0 :     fd_textstream_blk_t * next = blk->next;
      39           0 :     fd_valloc_free(strm->valloc, blk);
      40           0 :     blk = next;
      41           0 :   }
      42           0 :   fd_textstream_blk_t * blk = strm->first_blk;
      43           0 :   blk->next = NULL;
      44           0 :   blk->used = 0;
      45           0 :   strm->last_blk = blk;
      46           0 : }
      47             : 
      48           0 : fd_textstream_blk_t * fd_textstream_new_blk( fd_textstream_t * strm ) {
      49           0 :   fd_textstream_blk_t * blk = (fd_textstream_blk_t *)
      50           0 :     fd_valloc_malloc(strm->valloc, alignof(fd_textstream_blk_t), sizeof(fd_textstream_blk_t) + strm->alloc_sz);
      51           0 :   if ( blk == NULL )
      52           0 :     return NULL;
      53           0 :   blk->next = NULL;
      54           0 :   blk->used = 0;
      55           0 :   strm->last_blk->next = blk;
      56           0 :   strm->last_blk = blk;
      57           0 :   return blk;
      58           0 : }
      59             : 
      60             : int fd_textstream_append( fd_textstream_t * strm,
      61             :                           const char *      text,
      62           0 :                           ulong             text_sz ) {
      63           0 :   fd_textstream_blk_t * blk = strm->last_blk;
      64           0 :   if ( FD_LIKELY( blk->used + text_sz <= strm->alloc_sz ) ) {
      65             :     /* pass */
      66           0 :   } else if ( text_sz > strm->alloc_sz ) {
      67           0 :     return -1;
      68           0 :   } else {
      69           0 :     blk = fd_textstream_new_blk( strm );
      70           0 :     if ( blk == NULL )
      71           0 :       return -1;
      72           0 :   }
      73           0 :   char* buf = (char*)(blk + 1);
      74           0 :   fd_memcpy(buf + blk->used, text, text_sz);
      75           0 :   blk->used += text_sz;
      76           0 :   return 0;
      77           0 : }
      78             : 
      79           0 : ulong fd_textstream_total_size( fd_textstream_t * strm ) {
      80           0 :   ulong tot = 0;
      81           0 :   for ( fd_textstream_blk_t * blk = strm->first_blk; blk; blk = blk->next )
      82           0 :     tot += blk->used;
      83           0 :   return tot;
      84           0 : }
      85             : 
      86             : int fd_textstream_get_output( fd_textstream_t * strm,
      87           0 :                               char * outbuf) {
      88           0 :   ulong tot = 0;
      89           0 :   for ( fd_textstream_blk_t * blk = strm->first_blk; blk; blk = blk->next ) {
      90           0 :     fd_memcpy(outbuf + tot, blk+1, blk->used);
      91           0 :     tot += blk->used;
      92           0 :   }
      93           0 :   return 0;
      94           0 : }
      95             : 
      96           0 : ulong fd_textstream_get_iov_count( fd_textstream_t * strm ) {
      97           0 :   ulong tot = 0;
      98           0 :   for ( fd_textstream_blk_t * blk = strm->first_blk; blk; blk = blk->next )
      99           0 :     tot++;
     100           0 :   return tot;
     101           0 : }
     102             : 
     103             : int fd_textstream_get_iov( fd_textstream_t * strm,
     104           0 :                            struct fd_iovec * iov) {
     105           0 :   ulong tot = 0;
     106           0 :   for ( fd_textstream_blk_t * blk = strm->first_blk; blk; blk = blk->next ) {
     107           0 :     iov[tot].iov_base = blk+1;
     108           0 :     iov[tot].iov_len = blk->used;
     109           0 :     tot++;
     110           0 :   }
     111           0 :   return 0;
     112           0 : }
     113             : 
     114             : int fd_textstream_encode_utf8( fd_textstream_t * strm,
     115             :                                const uint *      chars,
     116           0 :                                ulong             chars_sz ) {
     117           0 :   ulong out_sz = 0;
     118           0 :   for ( ulong i = 0; i < chars_sz; ++i ) {
     119           0 :     uint ch = chars[i];
     120           0 :     if (ch < 0x80)
     121           0 :       out_sz += 1;
     122           0 :     else if (ch < 0x800)
     123           0 :       out_sz += 2;
     124           0 :     else if (ch < 0x10000)
     125           0 :       out_sz += 3;
     126           0 :     else if (ch < 0x110000)
     127           0 :       out_sz += 4;
     128           0 :     else
     129           0 :       return -1;
     130           0 :   }
     131             : 
     132           0 :   fd_textstream_blk_t * blk = strm->last_blk;
     133           0 :   if ( FD_LIKELY( blk->used + out_sz <= strm->alloc_sz ) ) {
     134             :     /* pass */
     135           0 :   } else if ( out_sz > strm->alloc_sz ) {
     136           0 :     return -1;
     137           0 :   } else {
     138           0 :     blk = fd_textstream_new_blk( strm );
     139           0 :     if ( blk == NULL )
     140           0 :       return -1;
     141           0 :   }
     142           0 :   char* dest = (char*)(blk + 1) + blk->used;
     143             : 
     144           0 :   ulong j = 0;
     145           0 :   for ( ulong i = 0; i < chars_sz; ++i ) {
     146           0 :     uint ch = chars[i];
     147           0 :     if (ch < 0x80) {
     148           0 :       dest[j++] = (char)ch;
     149           0 :     } else if (ch < 0x800) {
     150           0 :       dest[j++] = (char)((ch>>6) | 0xC0);
     151           0 :       dest[j++] = (char)((ch & 0x3F) | 0x80);
     152           0 :     } else if (ch < 0x10000) {
     153           0 :       dest[j++] = (char)((ch>>12) | 0xE0);
     154           0 :       dest[j++] = (char)(((ch>>6) & 0x3F) | 0x80);
     155           0 :       dest[j++] = (char)((ch & 0x3F) | 0x80);
     156           0 :     } else if (ch < 0x110000) {
     157           0 :       dest[j++] = (char)((ch>>18) | 0xF0);
     158           0 :       dest[j++] = (char)(((ch>>12) & 0x3F) | 0x80);
     159           0 :       dest[j++] = (char)(((ch>>6) & 0x3F) | 0x80);
     160           0 :       dest[j++] = (char)((ch & 0x3F) | 0x80);
     161           0 :     }
     162           0 :   }
     163             : 
     164           0 :   blk->used += j;
     165           0 :   return 0;
     166           0 : }
     167             : 
     168             : static const char b58digits_ordered[] = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
     169             : 
     170             : int fd_textstream_encode_base58( fd_textstream_t * strm,
     171             :                                  const void *      data,
     172           0 :                                  ulong             data_sz ) {
     173             :   /* Prevent explosive growth in computation */
     174           0 :   if (data_sz > 400U)
     175           0 :     return -1;
     176             : 
     177           0 :   const uchar* bin = (const uchar*)data;
     178           0 :   ulong carry;
     179           0 :   ulong i, j, high, zcount = 0;
     180           0 :   ulong size;
     181             : 
     182           0 :   while (zcount < data_sz && !bin[zcount])
     183           0 :     ++zcount;
     184             : 
     185             :   /* Temporary buffer size */
     186           0 :   size = (data_sz - zcount) * 138 / 100 + 1;
     187           0 :   uchar buf[size];
     188           0 :   fd_memset(buf, 0, size);
     189             : 
     190           0 :   for (i = zcount, high = size - 1; i < data_sz; ++i, high = j) {
     191           0 :     for (carry = bin[i], j = size - 1; (j > high) || carry; --j) {
     192           0 :       carry += 256UL * (ulong)buf[j];
     193           0 :       buf[j] = (uchar)(carry % 58);
     194           0 :       carry /= 58UL;
     195           0 :       if (!j) {
     196             :         // Otherwise j wraps to maxint which is > high
     197           0 :         break;
     198           0 :       }
     199           0 :     }
     200           0 :   }
     201             : 
     202           0 :   for (j = 0; j < size && !buf[j]; ++j) ;
     203             : 
     204           0 :   ulong out_sz = zcount + size - j;
     205           0 :   fd_textstream_blk_t * blk = strm->last_blk;
     206           0 :   if ( FD_LIKELY( blk->used + out_sz <= strm->alloc_sz ) ) {
     207             :     /* pass */
     208           0 :   } else if ( out_sz > strm->alloc_sz ) {
     209           0 :     return -1;
     210           0 :   } else {
     211           0 :     blk = fd_textstream_new_blk( strm );
     212           0 :     if ( blk == NULL )
     213           0 :       return -1;
     214           0 :   }
     215           0 :   char* b58 = (char*)(blk + 1) + blk->used;
     216             : 
     217           0 :   if (zcount)
     218           0 :     fd_memset(b58, '1', zcount);
     219           0 :   for (i = zcount; j < size; ++i, ++j)
     220           0 :     b58[i] = b58digits_ordered[buf[j]];
     221             : 
     222           0 :   blk->used += i;
     223             : 
     224           0 :   return 0;
     225           0 : }
     226             : 
     227             : static char base64_encoding_table[] = {
     228             :   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
     229             :   'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
     230             :   'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
     231             :   'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
     232             :   'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
     233             :   'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
     234             :   'w', 'x', 'y', 'z', '0', '1', '2', '3',
     235             :   '4', '5', '6', '7', '8', '9', '+', '/'
     236             : };
     237             : 
     238             : int fd_textstream_encode_base64( fd_textstream_t * strm,
     239             :                                  const void *      data,
     240           0 :                                  ulong             data_sz ) {
     241           0 :   ulong out_sz = 4 * ((data_sz + 2) / 3);
     242           0 :   fd_textstream_blk_t * blk = strm->last_blk;
     243           0 :   if ( FD_LIKELY( blk->used + out_sz <= strm->alloc_sz ) ) {
     244             :     /* pass */
     245           0 :   } else if ( out_sz > strm->alloc_sz ) {
     246           0 :     return -1;
     247           0 :   } else {
     248           0 :     blk = fd_textstream_new_blk( strm );
     249           0 :     if ( blk == NULL )
     250           0 :       return -1;
     251           0 :   }
     252           0 :   char* out_data = (char*)(blk + 1) + blk->used;
     253             : 
     254           0 :   ulong j = 0;
     255           0 :   for (ulong i = 0; i < data_sz; ) {
     256           0 :     switch (data_sz - i) {
     257           0 :     default: { /* 3 and above */
     258           0 :       uint octet_a = ((uchar*)data)[i++];
     259           0 :       uint octet_b = ((uchar*)data)[i++];
     260           0 :       uint octet_c = ((uchar*)data)[i++];
     261           0 :       uint triple = (octet_a << 0x10) + (octet_b << 0x08) + octet_c;
     262           0 :       out_data[j++] = base64_encoding_table[(triple >> 3 * 6) & 0x3F];
     263           0 :       out_data[j++] = base64_encoding_table[(triple >> 2 * 6) & 0x3F];
     264           0 :       out_data[j++] = base64_encoding_table[(triple >> 1 * 6) & 0x3F];
     265           0 :       out_data[j++] = base64_encoding_table[(triple >> 0 * 6) & 0x3F];
     266           0 :       break;
     267           0 :     }
     268           0 :     case 2: {
     269           0 :       uint octet_a = ((uchar*)data)[i++];
     270           0 :       uint octet_b = ((uchar*)data)[i++];
     271           0 :       uint triple = (octet_a << 0x10) + (octet_b << 0x08);
     272           0 :       out_data[j++] = base64_encoding_table[(triple >> 3 * 6) & 0x3F];
     273           0 :       out_data[j++] = base64_encoding_table[(triple >> 2 * 6) & 0x3F];
     274           0 :       out_data[j++] = base64_encoding_table[(triple >> 1 * 6) & 0x3F];
     275           0 :       out_data[j++] = '=';
     276           0 :       break;
     277           0 :     }
     278           0 :     case 1: {
     279           0 :       uint octet_a = ((uchar*)data)[i++];
     280           0 :       uint triple = (octet_a << 0x10);
     281           0 :       out_data[j++] = base64_encoding_table[(triple >> 3 * 6) & 0x3F];
     282           0 :       out_data[j++] = base64_encoding_table[(triple >> 2 * 6) & 0x3F];
     283           0 :       out_data[j++] = '=';
     284           0 :       out_data[j++] = '=';
     285           0 :       break;
     286           0 :     }
     287           0 :     }
     288           0 :   }
     289             : 
     290           0 :   blk->used += j;
     291           0 :   return 0;
     292           0 : }
     293             : 
     294             : static const char hex_encoding_table[] = "0123456789ABCDEF";
     295             : 
     296             : int fd_textstream_encode_hex( fd_textstream_t * strm,
     297             :                               const void *      data,
     298           0 :                               ulong             data_sz ) {
     299           0 :   ulong out_sz = 2 * data_sz;
     300           0 :   fd_textstream_blk_t * blk = strm->last_blk;
     301           0 :   if ( FD_LIKELY( blk->used + out_sz <= strm->alloc_sz ) ) {
     302             :     /* pass */
     303           0 :   } else if ( out_sz > strm->alloc_sz ) {
     304           0 :     return -1;
     305           0 :   } else {
     306           0 :     blk = fd_textstream_new_blk( strm );
     307           0 :     if ( blk == NULL )
     308           0 :       return -1;
     309           0 :   }
     310           0 :   char* out_data = (char*)(blk + 1) + blk->used;
     311             : 
     312           0 :   ulong j = 0;
     313           0 :   for (ulong i = 0; i < data_sz; ) {
     314           0 :     uint octet = ((uchar*)data)[i++];
     315           0 :     out_data[j++] = hex_encoding_table[(octet >> 4) & 0xF];
     316           0 :     out_data[j++] = hex_encoding_table[octet & 0xF];
     317           0 :   }
     318             : 
     319           0 :   blk->used += j;
     320           0 :   return 0;
     321           0 : }
     322             : 
     323           0 : int fd_textstream_sprintf( fd_textstream_t * strm, const char* format, ... ) {
     324           0 :   fd_textstream_blk_t * blk = strm->last_blk;
     325           0 :   ulong remain = strm->alloc_sz - blk->used;
     326           0 :   char* buf = (char*)(blk + 1) + blk->used;
     327           0 :   va_list ap;
     328           0 :   va_start(ap, format);
     329           0 :   int r = vsnprintf(buf, remain, format, ap);
     330           0 :   va_end(ap);
     331           0 :   if (r >= 0 && (uint)r < remain) {
     332           0 :     blk->used += (uint)r;
     333           0 :     return 0;
     334           0 :   }
     335             : 
     336           0 :   blk = fd_textstream_new_blk( strm );
     337           0 :   if ( blk == NULL )
     338           0 :     return -1;
     339             : 
     340           0 :   remain = strm->alloc_sz;
     341           0 :   buf = (char*)(blk + 1);
     342           0 :   va_start(ap, format);
     343           0 :   r = vsnprintf(buf, remain, format, ap);
     344           0 :   va_end(ap);
     345           0 :   if (r >= 0 && (uint)r < remain) {
     346           0 :     blk->used = (uint)r;
     347           0 :     return 0;
     348           0 :   }
     349             : 
     350           0 :   return -1;
     351           0 : }

Generated by: LCOV version 1.14