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

Generated by: LCOV version 1.14