LCOV - code coverage report
Current view: top level - flamenco/types - fd_bincode.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 124 357 34.7 %
Date: 2025-11-29 04:46:19 Functions: 20 17199 0.1 %

          Line data    Source code
       1             : #ifndef HEADER_fd_src_flamenco_types_fd_bincode_h
       2             : #define HEADER_fd_src_flamenco_types_fd_bincode_h
       3             : 
       4             : #include "../../util/fd_util.h"
       5             : 
       6             : typedef void
       7             : (* fd_types_walk_fn_t)( void *       self,
       8             :                         void const * arg,
       9             :                         char const * name,
      10             :                         int          type,
      11             :                         char const * type_name,
      12             :                         uint         level,
      13             :                         uint         varint );
      14             : 
      15             : typedef void
      16             : (* fd_types_walk_fn_t)( void *       self,
      17             :                         void const * arg,
      18             :                         char const * name,
      19             :                         int          type,
      20             :                         char const * type_name,
      21             :                         uint         level,
      22             :                         uint         varint );
      23             : 
      24             : /* Context argument used for encoding */
      25             : struct fd_bincode_encode_ctx {
      26             :   /* Current position in data buffer */
      27             :   void * data;
      28             :   /* End of buffer */
      29             :   void * dataend;
      30             : };
      31             : typedef struct fd_bincode_encode_ctx fd_bincode_encode_ctx_t;
      32             : 
      33             : /* Context argument used for decoding */
      34             : struct fd_bincode_decode_ctx {
      35             :   /* Current position in data buffer */
      36             :   void const * data;
      37             :   /* End of buffer */
      38             :   void const * dataend;
      39             : };
      40             : typedef struct fd_bincode_decode_ctx fd_bincode_decode_ctx_t;
      41             : 
      42       56181 : #define FD_BINCODE_SUCCESS         (    0)
      43           0 : #define FD_BINCODE_ERR_UNDERFLOW   (-1001) /* Attempted to read past end of buffer */
      44           6 : #define FD_BINCODE_ERR_OVERFLOW    (-1002) /* Attempted to write past end of buffer */
      45           0 : #define FD_BINCODE_ERR_ENCODING    (-1003) /* Invalid encoding */
      46             : 
      47             : #define FD_BINCODE_PRIMITIVE_STUBS( name, type ) \
      48             :   static inline int \
      49             :   fd_bincode_##name##_decode( type *                    self, \
      50         540 :                               fd_bincode_decode_ctx_t * ctx ) { \
      51         540 :     uchar const * ptr = (uchar const *) ctx->data; \
      52         540 :     if ( FD_UNLIKELY((void const *)(ptr + sizeof(type)) > ctx->dataend ) ) \
      53         540 :       return FD_BINCODE_ERR_UNDERFLOW; \
      54         540 :     memcpy( self, ptr, sizeof(type) );  /* unaligned */ \
      55         540 :     ctx->data = ptr + sizeof(type); \
      56         540 :     return FD_BINCODE_SUCCESS; \
      57         540 :   } \
      58             :   static inline int \
      59       49227 :   fd_bincode_##name##_decode_footprint( fd_bincode_decode_ctx_t * ctx ) { \
      60       49227 :     uchar const * ptr = (uchar const *) ctx->data; \
      61       49227 :     if ( FD_UNLIKELY((void const *)(ptr + sizeof(type)) > ctx->dataend ) ) \
      62       49227 :       return FD_BINCODE_ERR_UNDERFLOW; \
      63       49227 :     ctx->data = ptr + sizeof(type); \
      64       49227 :     return FD_BINCODE_SUCCESS; \
      65       49227 :   } \
      66             :   static inline void \
      67             :   fd_bincode_##name##_decode_unsafe( type *                    self, \
      68       37407 :                                      fd_bincode_decode_ctx_t * ctx ) { \
      69       37407 :     uchar const * ptr = (uchar const *) ctx->data; \
      70       37407 :     memcpy( self, ptr, sizeof(type) );  /* unaligned */ \
      71       37407 :     ctx->data = ptr + sizeof(type); \
      72       37407 :   } \
      73             :   static inline int \
      74             :   fd_bincode_##name##_encode( type                      self, \
      75        3069 :                               fd_bincode_encode_ctx_t * ctx ) { \
      76        3069 :     uchar * ptr = (uchar *)ctx->data; \
      77        3069 :     if ( FD_UNLIKELY((void *)(ptr + sizeof(type)) > ctx->dataend ) ) \
      78        3069 :       return FD_BINCODE_ERR_OVERFLOW; \
      79        3069 :     memcpy( ptr, &self, sizeof(type) );  /* unaligned */ \
      80        3066 :     ctx->data = ptr + sizeof(type); \
      81        3066 :     return FD_BINCODE_SUCCESS; \
      82        3069 :   }
      83             : 
      84             : /* fd_w_u128 is a wrapped "uint128" type providing basic 128-bit
      85             :    unsigned int functionality to fd_types, even if the compile target
      86             :    does not natively support uint128. */
      87             : 
      88             : union __attribute__((aligned(16))) fd_w_u128 {
      89             :   uchar   uc[16];
      90             :   ulong   ul[2];
      91             : # if FD_HAS_INT128
      92             :   uint128 ud;
      93             : # endif
      94             : };
      95             : 
      96             : typedef union fd_w_u128 fd_w_u128_t;
      97             : 
      98             : FD_BINCODE_PRIMITIVE_STUBS( uint8,   uchar       )
      99             : FD_BINCODE_PRIMITIVE_STUBS( uint16,  ushort      )
     100             : FD_BINCODE_PRIMITIVE_STUBS( uint32,  uint        )
     101             : FD_BINCODE_PRIMITIVE_STUBS( uint64,  ulong       )
     102             : FD_BINCODE_PRIMITIVE_STUBS( int64,   long        )
     103             : FD_BINCODE_PRIMITIVE_STUBS( uint128, fd_w_u128_t )
     104             : FD_BINCODE_PRIMITIVE_STUBS( double,  double      )
     105             : 
     106             : static inline int
     107             : fd_bincode_bool_decode( uchar *                   self,
     108          18 :                         fd_bincode_decode_ctx_t * ctx ) {
     109             : 
     110          18 :   uchar const * ptr = (uchar const *)ctx->data;
     111          18 :   if( FD_UNLIKELY( ptr+1 > (uchar const *)ctx->dataend ) )
     112           0 :     return FD_BINCODE_ERR_UNDERFLOW;
     113             : 
     114          18 :   if( FD_UNLIKELY( *ptr & (~1U) ) )
     115           0 :     return FD_BINCODE_ERR_ENCODING;
     116             : 
     117          18 :   *self = *ptr;
     118          18 :   ctx->data = ptr + 1;
     119             : 
     120          18 :   return FD_BINCODE_SUCCESS;
     121          18 : }
     122             : 
     123             : static inline int
     124          21 : fd_bincode_bool_decode_footprint( fd_bincode_decode_ctx_t * ctx ) {
     125             : 
     126          21 :   uchar const * ptr = (uchar const *)ctx->data;
     127          21 :   if( FD_UNLIKELY( ptr+1 > (uchar const *)ctx->dataend ) )
     128           0 :     return FD_BINCODE_ERR_UNDERFLOW;
     129             : 
     130          21 :   if( FD_UNLIKELY( *ptr & (~1U) ) )
     131           0 :     return FD_BINCODE_ERR_ENCODING;
     132             : 
     133          21 :   ctx->data = ptr + 1;
     134             : 
     135          21 :   return FD_BINCODE_SUCCESS;
     136          21 : }
     137             : 
     138             : static inline void
     139             : fd_bincode_bool_decode_unsafe( uchar *                   self,
     140          30 :                                fd_bincode_decode_ctx_t * ctx ) {
     141          30 :   fd_bincode_uint8_decode_unsafe( self, ctx );
     142          30 : }
     143             : 
     144             : static inline int
     145             : fd_bincode_bool_encode( uchar                     self,
     146         207 :                         fd_bincode_encode_ctx_t * ctx ) {
     147             : 
     148         207 :   uchar * ptr = (uchar *)ctx->data;
     149         207 :   if ( FD_UNLIKELY( (void *)(ptr + 1) > ctx->dataend ) )
     150           0 :     return FD_BINCODE_ERR_OVERFLOW;
     151             : 
     152         207 :   *ptr = !!self;
     153         207 :   ctx->data = ptr + 1;
     154             : 
     155         207 :   return FD_BINCODE_SUCCESS;
     156         207 : }
     157             : 
     158             : static inline int
     159             : fd_bincode_bytes_decode( uchar *                   self,
     160             :                          ulong                     len,
     161           0 :                          fd_bincode_decode_ctx_t * ctx ) {
     162           0 :   uchar * ptr = (uchar *) ctx->data;
     163           0 :   if ( FD_UNLIKELY((ulong)( (uchar *) ctx->dataend - ptr) < len ) ) // Get wrap-around case right
     164           0 :     return FD_BINCODE_ERR_UNDERFLOW;
     165           0 : 
     166           0 :   fd_memcpy(self, ptr, len);
     167           0 :   ctx->data = ptr + len;
     168           0 : 
     169           0 :   return FD_BINCODE_SUCCESS;
     170           0 : }
     171             : 
     172             : static inline int
     173             : fd_bincode_bytes_decode_footprint( ulong                     len,
     174         522 :                                    fd_bincode_decode_ctx_t * ctx ) {
     175         522 :   uchar * ptr = (uchar *) ctx->data;
     176         522 :   if ( FD_UNLIKELY((ulong)( (uchar *) ctx->dataend - ptr) < len ) ) { // Get wrap-around case right
     177           0 :     return FD_BINCODE_ERR_UNDERFLOW;
     178           0 :   }
     179             : 
     180         522 :   ctx->data = ptr + len;
     181             : 
     182         522 :   return FD_BINCODE_SUCCESS;
     183         522 : }
     184             : 
     185             : static inline void
     186             : fd_bincode_bytes_decode_unsafe( uchar *                   self,
     187             :                                 ulong                     len,
     188       34500 :                                 fd_bincode_decode_ctx_t * ctx ) {
     189       34500 :   uchar * ptr = (uchar *) ctx->data;
     190       34500 :   fd_memcpy(self, ptr, len);
     191       34500 :   ctx->data = ptr + len;
     192       34500 : }
     193             : 
     194             : static inline int
     195             : fd_bincode_bytes_encode( uchar const *             self,
     196             :                          ulong                     len,
     197         996 :                          fd_bincode_encode_ctx_t * ctx ) {
     198         996 :   fd_msan_check( self, len );
     199             : 
     200         996 :   uchar * ptr = (uchar *)ctx->data;
     201         996 :   if( FD_UNLIKELY( (void *)( ptr+len ) > ctx->dataend ) )
     202           0 :     return FD_BINCODE_ERR_OVERFLOW;
     203             : 
     204         996 :   fd_memcpy( ptr, self, len );
     205         996 :   ctx->data = ptr + len;
     206             : 
     207         996 :   return FD_BINCODE_SUCCESS;
     208         996 : }
     209             : 
     210             : /* Alternate versions of fd_cu16_dec to make the function signature more consistent with the
     211             :    other fd_bincode_decode functions.  */
     212             : static inline int
     213             : fd_bincode_compact_u16_decode( ushort *                  self,
     214           0 :                                fd_bincode_decode_ctx_t * ctx ) {
     215           0 :   const uchar * ptr = (const uchar*) ctx->data;
     216           0 :   if( FD_UNLIKELY( ptr==NULL ) ) {
     217           0 :     return FD_BINCODE_ERR_UNDERFLOW;
     218           0 :   }
     219             : 
     220           0 :   if( FD_LIKELY( (void *) (ptr + 1) <= ctx->dataend && !(0x80U & ptr[0]) ) ) {
     221           0 :     *self = (ushort)ptr[0];
     222           0 :     ctx->data = ptr + 1;
     223           0 :     return FD_BINCODE_SUCCESS;
     224           0 :   }
     225             : 
     226           0 :   if( FD_LIKELY( (void *) (ptr + 2) <= ctx->dataend && !(0x80U & ptr[1]) ) ) {
     227           0 :     if( FD_UNLIKELY( !ptr[1] ) ) /* Detect non-minimal encoding */
     228           0 :       return FD_BINCODE_ERR_ENCODING;
     229           0 :     *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)ptr[1])<<7));
     230           0 :     ctx->data = ptr + 2;
     231           0 :     return FD_BINCODE_SUCCESS;
     232           0 :   }
     233             : 
     234           0 :   if( FD_LIKELY( (void *) (ptr + 3) <= ctx->dataend && !(0xFCU & ptr[2]) ) ) {
     235           0 :     if( FD_UNLIKELY( !ptr[2] ) ) /* Detect non-minimal encoding */
     236           0 :       return FD_BINCODE_ERR_ENCODING;
     237           0 :     *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)(ptr[1]&0x7FUL))<<7) + (((ulong)ptr[2])<<14));
     238           0 :     ctx->data = ptr + 3;
     239           0 :     return FD_BINCODE_SUCCESS;
     240           0 :   }
     241             : 
     242           0 :   return FD_BINCODE_ERR_UNDERFLOW;
     243           0 : }
     244             : 
     245             : static inline void
     246             : fd_bincode_compact_u16_decode_unsafe( ushort *                  self,
     247           0 :                                       fd_bincode_decode_ctx_t * ctx ) {
     248           0 :   const uchar * ptr = (const uchar*) ctx->data;
     249             : 
     250           0 :   if( !(0x80U & ptr[0]) ) {
     251           0 :     *self = (ushort)ptr[0];
     252           0 :     ctx->data = ptr + 1;
     253           0 :     return;
     254           0 :   }
     255             : 
     256           0 :   if( !(0x80U & ptr[1]) ) {
     257           0 :     *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)ptr[1])<<7));
     258           0 :     ctx->data = ptr + 2;
     259           0 :     return;
     260           0 :   }
     261             : 
     262           0 :   *self = (ushort)((ulong)(ptr[0]&0x7FUL) + (((ulong)(ptr[1]&0x7FUL))<<7) + (((ulong)ptr[2])<<14));
     263           0 :   ctx->data = ptr + 3;
     264           0 : }
     265             : 
     266             : static inline int
     267             : fd_bincode_compact_u16_encode( ushort const *            self,
     268          12 :                                fd_bincode_encode_ctx_t * ctx ) {
     269          12 :   uchar * ptr = (uchar*) ctx->data;
     270          12 :   ulong val = *self;
     271             : 
     272          12 :   if ( val < 0x80UL ) {
     273          12 :     if ( FD_UNLIKELY((void *) (ptr + 1) > ctx->dataend ) )
     274           0 :       return FD_BINCODE_ERR_OVERFLOW;
     275          12 :     *ptr = (uchar)val;
     276          12 :     ctx->data = ptr + 1;
     277          12 :     return FD_BINCODE_SUCCESS;
     278          12 :   }
     279             : 
     280           0 :   else if ( val < 0x4000UL ) {
     281           0 :     if ( FD_UNLIKELY((void *) (ptr + 2) > ctx->dataend ) )
     282           0 :       return FD_BINCODE_ERR_OVERFLOW;
     283           0 :     ptr[0] = (uchar)((val&0x7FUL)|0x80UL);
     284           0 :     ptr[1] = (uchar)(val>>7);
     285           0 :     ctx->data = ptr + 2;
     286           0 :     return FD_BINCODE_SUCCESS;
     287           0 :   }
     288             : 
     289           0 :   else {
     290           0 :     if ( FD_UNLIKELY((void *) (ptr + 3) > ctx->dataend ) )
     291           0 :       return FD_BINCODE_ERR_OVERFLOW;
     292           0 :     ptr[0] = (uchar)((val&0x7FUL)|0x80UL);
     293           0 :     ptr[1] = (uchar)(((val>>7)&0x7FUL)|0x80UL);
     294           0 :     ptr[2] = (uchar)(val>>14);
     295           0 :     ctx->data = ptr + 3;
     296           0 :     return FD_BINCODE_SUCCESS;
     297           0 :   }
     298          12 : }
     299             : 
     300             : static inline ulong
     301           0 : fd_bincode_compact_u16_size( ushort const * self ) {
     302           0 :   ulong val = *self;
     303             : 
     304           0 :   if ( val < 0x80UL ) {
     305           0 :     return 1;
     306           0 :   }
     307           0 :   else if ( val < 0x4000UL ) {
     308           0 :     return 2;
     309           0 :   }
     310           0 :   else {
     311           0 :     return 3;
     312           0 :   }
     313           0 : }
     314             : 
     315             : /* Decodes an integer encoded using the serde_varint algorithm:
     316             :    https://github.com/solana-labs/solana/blob/master/sdk/program/src/serde_varint.rs
     317             : 
     318             :    A variable number of bytes could have been used to encode the integer.
     319             :    The most significant bit of each byte indicates if more bytes have been used, so we keep consuming until
     320             :    we reach a byte where the most significant bit is 0.
     321             : */
     322             : static inline int
     323             : fd_bincode_varint_decode( ulong *                   self,
     324           0 :                           fd_bincode_decode_ctx_t * ctx ) {
     325           0 :   ulong out   = 0UL;
     326           0 :   uint  shift = 0U;
     327           0 : 
     328           0 :   while( FD_LIKELY( shift < 64U ) ) {
     329           0 : 
     330           0 :     if( FD_UNLIKELY( ctx->data >= ctx->dataend ) )
     331           0 :       return FD_BINCODE_ERR_UNDERFLOW;
     332           0 : 
     333           0 :     uint byte = *(uchar const *)ctx->data;
     334           0 :     ctx->data = (uchar const *)ctx->data + 1;
     335           0 :     out |= (byte & 0x7FUL) << shift;
     336           0 : 
     337           0 :     if( (byte & 0x80U) == 0U ) {
     338           0 :       if( (out>>shift) != byte )
     339           0 :         return FD_BINCODE_ERR_ENCODING;
     340           0 :       if( byte==0U && (shift!=0U || out!=0UL) )
     341           0 :         return FD_BINCODE_ERR_ENCODING;
     342           0 :       *self = out;
     343           0 :       return FD_BINCODE_SUCCESS;
     344           0 :     }
     345           0 : 
     346           0 :     shift += 7U;
     347           0 : 
     348           0 :   }
     349           0 : 
     350           0 :   return FD_BINCODE_ERR_ENCODING;
     351           0 : }
     352             : 
     353             : static inline int
     354           0 : fd_bincode_varint_decode_footprint( fd_bincode_decode_ctx_t * ctx ) {
     355           0 :   ulong out   = 0UL;
     356           0 :   uint  shift = 0U;
     357             : 
     358           0 :   while( FD_LIKELY( shift < 64U ) ) {
     359             : 
     360           0 :     if( FD_UNLIKELY( ctx->data >= ctx->dataend ) )
     361           0 :       return FD_BINCODE_ERR_UNDERFLOW;
     362             : 
     363           0 :     uint byte = *(uchar const *)ctx->data;
     364           0 :     ctx->data = (uchar const *)ctx->data + 1;
     365           0 :     out |= (byte & 0x7FUL) << shift;
     366             : 
     367           0 :     if( (byte & 0x80U) == 0U ) {
     368           0 :       if( (out>>shift) != byte )
     369           0 :         return FD_BINCODE_ERR_ENCODING;
     370           0 :       if( byte==0U && (shift!=0U || out!=0UL) )
     371           0 :         return FD_BINCODE_ERR_ENCODING;
     372           0 :       return FD_BINCODE_SUCCESS;
     373           0 :     }
     374             : 
     375           0 :     shift += 7U;
     376             : 
     377           0 :   }
     378             : 
     379           0 :   return FD_BINCODE_ERR_ENCODING;
     380           0 : }
     381             : 
     382             : static inline void
     383             : fd_bincode_varint_decode_unsafe( ulong *                   self,
     384           0 :                                  fd_bincode_decode_ctx_t * ctx ) {
     385           0 :   ulong out   = 0UL;
     386           0 :   uint  shift = 0U;
     387             : 
     388           0 :   for(;;) {
     389           0 :     uint byte = *(uchar const *)ctx->data;
     390           0 :     ctx->data = (uchar const *)ctx->data + 1;
     391           0 :     out |= (byte & 0x7FUL) << shift;
     392             : 
     393           0 :     if( (byte & 0x80U) == 0U ) {
     394           0 :       *self = out;
     395           0 :       return;
     396           0 :     }
     397             : 
     398           0 :     shift += 7U;
     399           0 :   }
     400           0 : }
     401             : 
     402             : static inline int
     403             : fd_bincode_varint_encode( ulong                     val,
     404           0 :                           fd_bincode_encode_ctx_t * ctx ) {
     405           0 :   uchar * ptr = (uchar *) ctx->data;
     406           0 :   while (1) {
     407           0 :     if ( FD_UNLIKELY((void *) (ptr + 1) > ctx->dataend ) )
     408           0 :       return FD_BINCODE_ERR_OVERFLOW;
     409           0 :     if ( val < 0x80UL ) {
     410           0 :       *(ptr++) = (uchar)val;
     411           0 :       ctx->data = ptr;
     412           0 :       return FD_BINCODE_SUCCESS;
     413           0 :     }
     414           0 :     *(ptr++) = (uchar)((val&0x7FUL)|0x80UL);
     415           0 :     val >>= 7;
     416           0 :   }
     417           0 : }
     418             : 
     419             : static inline ulong
     420           0 : fd_bincode_varint_size( ulong val ) {
     421           0 :   ulong sz = 0;
     422           0 :   while (1) {
     423           0 :     if ( val < 0x80UL ) {
     424           0 :       return sz+1;
     425           0 :     }
     426           0 :     sz++;
     427           0 :     val >>= 7;
     428           0 :   }
     429           0 : }
     430             : 
     431             : enum {
     432             :   /* All meta tags must fit in 6 bits */
     433             : 
     434             :   /* Primitive types with an implicit encoding length */
     435             :   FD_ARCHIVE_META_CHAR = 0x1,
     436             :   FD_ARCHIVE_META_STRING = 0x2,
     437             :   FD_ARCHIVE_META_CHAR32 = 0x3,
     438             :   FD_ARCHIVE_META_DOUBLE = 0x4,
     439             :   FD_ARCHIVE_META_LONG = 0x5,
     440             :   FD_ARCHIVE_META_UINT = 0x6,
     441             :   FD_ARCHIVE_META_UINT128 = 0x7,
     442             :   FD_ARCHIVE_META_BOOL = 0x8,
     443             :   FD_ARCHIVE_META_UCHAR = 0x9,
     444             :   FD_ARCHIVE_META_UCHAR32 = 0xa,
     445             :   FD_ARCHIVE_META_UCHAR128 = 0xb,
     446             :   FD_ARCHIVE_META_UCHAR2048 = 0xc,
     447             :   FD_ARCHIVE_META_ULONG = 0xd,
     448             :   FD_ARCHIVE_META_USHORT = 0xe,
     449             : 
     450             :   /* Meta types which have an encoding length after the short tag */
     451             :   FD_ARCHIVE_META_STRUCT = 0x21,
     452             :   FD_ARCHIVE_META_VECTOR = 0x22,
     453             :   FD_ARCHIVE_META_DEQUE = 0x23,
     454             :   FD_ARCHIVE_META_MAP = 0x24,
     455             :   FD_ARCHIVE_META_TREAP = 0x25,
     456             :   FD_ARCHIVE_META_OPTION = 0x26,
     457             :   FD_ARCHIVE_META_ARRAY = 0x27,
     458             :   FD_ARCHIVE_META_STATIC_VECTOR = 0x28,
     459             : };
     460             : 
     461             : #define FD_ARCHIVE_META_SENTINAL (ushort)0 /* End of structure */
     462             : 
     463           0 : static inline int fd_archive_encode_setup_length( fd_bincode_encode_ctx_t * ctx, void ** offset_out ) {
     464           0 :   uchar * ptr = (uchar *)ctx->data;
     465           0 :   if ( FD_UNLIKELY((void *)(ptr + sizeof(uint)) > ctx->dataend ) )
     466           0 :     return FD_BINCODE_ERR_OVERFLOW;
     467           0 :   /* Skip over length for now but make space for it */
     468           0 :   *offset_out = ptr;
     469           0 :   ctx->data = ptr + sizeof(uint);
     470           0 :   return FD_BINCODE_SUCCESS;
     471           0 : }
     472             : 
     473           0 : static inline int fd_archive_encode_set_length( fd_bincode_encode_ctx_t * ctx, void * offset ) {
     474           0 :   *(uint *)offset = (uint)((uchar *)ctx->data - ((uchar *)offset + sizeof(uint)));
     475           0 :   return FD_BINCODE_SUCCESS;
     476           0 : }
     477             : 
     478           0 : static inline int fd_archive_decode_setup_length( fd_bincode_decode_ctx_t * ctx, void ** offset_out ) {
     479           0 :   uchar * ptr = (uchar *)ctx->data;
     480           0 :   if ( FD_UNLIKELY((void *)(ptr + sizeof(uint)) > ctx->dataend ) )
     481           0 :     return FD_BINCODE_ERR_UNDERFLOW;
     482           0 :   /* Skip over length for now and verify it later */
     483           0 :   *offset_out = ptr;
     484           0 :   ctx->data = ptr + sizeof(uint);
     485           0 :   return FD_BINCODE_SUCCESS;
     486           0 : }
     487             : 
     488           0 : static inline int fd_archive_decode_check_length( fd_bincode_decode_ctx_t * ctx, void * offset ) {
     489           0 :   if( *(uint *)offset != (uint)((uchar *)ctx->data - ((uchar *)offset + sizeof(uint))) )
     490           0 :     return FD_BINCODE_ERR_ENCODING;
     491           0 :   return FD_BINCODE_SUCCESS;
     492           0 : }
     493             : 
     494             : /* Convenience API for deserializing with common allocators */
     495             : 
     496             : /* fd_bincode_decode_spad decodes a bincode type.  The result is
     497             :    allocated into a spad on success.  On failure, no spad allocations
     498             :    are made.
     499             : 
     500             :    fd_bincode_decode1_spad optionally outputs the number of bytes read
     501             :    to *psz. */
     502             : 
     503             : #define fd_bincode_decode1_spad( type, spad, buf, buf_sz, perr, psz )  \
     504           0 :   __extension__({                                                      \
     505           0 :     fd_spad_t *  const spad_   = (spad);                               \
     506           0 :     void const * const buf_    = (buf);                                \
     507           0 :     ulong        const buf_sz_ = (buf_sz);                             \
     508           0 :     int *              perr_   = (perr);                               \
     509           0 :     ulong *            psz_    = (psz);                                \
     510           0 :     fd_bincode_decode_ctx_t ctx = {0};                                 \
     511           0 :     if( perr_ ) *perr_ = -1;                                           \
     512           0 :     ctx.data    = (void const *)( buf_ );                              \
     513           0 :     ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ );         \
     514           0 :     ulong total_sz = 0UL;                                              \
     515           0 :     int err = fd_##type##_decode_footprint( &ctx, &total_sz );         \
     516           0 :     fd_##type##_t * out = NULL;                                        \
     517           0 :     if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) {                       \
     518           0 :       ulong align = fd_##type##_align();                               \
     519           0 :       void * mem = fd_spad_alloc( spad_, align, total_sz );            \
     520           0 :       if( FD_UNLIKELY( !mem ) ) {                                      \
     521           0 :         FD_LOG_ERR(( "fd_bincode_" #type "_decode failed: out of memory (decode requires %lu+%lu bytes, but only %lu bytes free in spad)", align-1UL, total_sz, fd_spad_mem_free( spad_ ) )); \
     522           0 :       }                                                                \
     523           0 :       out = fd_##type##_decode( mem, &ctx );                           \
     524           0 :       if( psz_ ) *psz_ = (ulong)ctx.data - (ulong)buf_;                \
     525           0 :     }                                                                  \
     526           0 :     if( perr_ ) *perr_ = err;                                          \
     527           0 :     out;                                                               \
     528           0 :   })
     529             : 
     530             : #define fd_bincode_decode1_spad_global( type, spad, buf, buf_sz, perr, psz )  \
     531             :   __extension__({                                                             \
     532             :     fd_spad_t *  const spad_   = (spad);                                      \
     533             :     void const * const buf_    = (buf);                                       \
     534             :     ulong        const buf_sz_ = (buf_sz);                                    \
     535             :     int *              perr_   = (perr);                                      \
     536             :     ulong *            psz_    = (psz);                                       \
     537             :     fd_bincode_decode_ctx_t ctx = {0};                                        \
     538             :     if( perr_ ) *perr_ = -1;                                                  \
     539             :     ctx.data    = (void const *)( buf_ );                                     \
     540             :     ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ );                \
     541             :     ulong total_sz = 0UL;                                                     \
     542             :     int err = fd_##type##_decode_footprint( &ctx, &total_sz );                \
     543             :     fd_##type##_global_t * out = NULL;                                        \
     544             :     if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) {                              \
     545             :       ulong align = fd_##type##_align();                                      \
     546             :       void * mem = fd_spad_alloc( spad_, align, total_sz );                   \
     547             :       if( FD_UNLIKELY( !mem ) ) {                                             \
     548             :         FD_LOG_ERR(( "fd_bincode_" #type "_decode failed: out of memory (decode requires %lu+%lu bytes, but only %lu bytes free in spad)", align-1UL, total_sz, fd_spad_mem_free( spad_ ) )); \
     549             :       }                                                                       \
     550             :       out = fd_##type##_decode_global( mem, &ctx );                           \
     551             :       if( psz_ ) *psz_ = (ulong)ctx.data - (ulong)buf_;                       \
     552             :     }                                                                         \
     553             :     if( perr_ ) *perr_ = err;                                                 \
     554             :     out;                                                                      \
     555             :   })
     556             : 
     557             : #define fd_bincode_decode_spad( type, spad, buf, buf_sz, perr ) \
     558           0 :   fd_bincode_decode1_spad( type, spad, buf, buf_sz, perr, NULL )
     559             : 
     560             : #define fd_bincode_decode_spad_global( type, spad, buf, buf_sz, perr ) \
     561             :   fd_bincode_decode1_spad_global( type, spad, buf, buf_sz, perr, NULL )
     562             : 
     563             : /* fd_bincode_decode_scratch decodes a bincode type.  The result is
     564             :    allocated into the thread's scratch region on success.  On failure,
     565             :    no allocations are made. */
     566             : 
     567             : #define fd_bincode_decode1_scratch( type, buf, buf_sz, perr, psz )     \
     568           3 :   __extension__({                                                      \
     569           3 :     void const * const buf_    = (buf);                                \
     570           3 :     ulong        const buf_sz_ = (buf_sz);                             \
     571           3 :     int *              perr_   = (perr);                               \
     572           3 :     ulong *            psz_    = (psz);                                \
     573           3 :     fd_bincode_decode_ctx_t ctx = {0};                                 \
     574           3 :     if( perr_ ) *perr_ = -1;                                           \
     575           3 :     ctx.data    = (void const *)( buf_ );                              \
     576           3 :     ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ );         \
     577           3 :     ulong total_sz = 0UL;                                              \
     578           3 :     int err = fd_##type##_decode_footprint( &ctx, &total_sz );         \
     579           3 :     fd_##type##_t * out = NULL;                                        \
     580           3 :     if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) {                       \
     581           3 :       ulong align = fd_##type##_align();                               \
     582           3 :       if( FD_UNLIKELY( !fd_scratch_alloc_is_safe( align, total_sz ) ) ) { \
     583           0 :         FD_LOG_ERR(( "fd_bincode_" #type "_decode failed: out of memory (decode requires %lu+%lu bytes, but only %lu bytes free in scratch region)", align-1UL, total_sz, fd_scratch_free() )); \
     584           0 :       }                                                                \
     585           3 :       void * mem = fd_scratch_alloc( align, total_sz );                \
     586           3 :       out = fd_##type##_decode( mem, &ctx );                           \
     587           3 :       if( psz_ ) *psz_ = (ulong)ctx.data - (ulong)buf_;                \
     588           3 :     }                                                                  \
     589           3 :     if( perr_ ) *perr_ = err;                                          \
     590           3 :     out;                                                               \
     591           3 :   })
     592             : 
     593             : #define fd_bincode_decode_scratch( type, buf, buf_sz, perr ) \
     594           3 :   fd_bincode_decode1_scratch( type, buf, buf_sz, perr, NULL )
     595             : 
     596             : /* fd_bincode_decode_static decodes a statically-sized bincode type.
     597             : 
     598             :    Example usage:
     599             : 
     600             :    fd_epoch_schedule_t es[1]; int err;
     601             :    if( FD_UNLIKELY( fd_bincode_decode_static( epoch_schedule, es, buf, bufsz, &err ) ) ) {
     602             :      ... parse fail ...
     603             :      return;
     604             :    }
     605             :    ... parse success ... */
     606             : 
     607             : #define fd_bincode_decode_static1( type, suffix, out, buf, buf_sz, perr ) \
     608           6 :   __extension__({                                                      \
     609           6 :     void const * const buf_    = (buf);                                \
     610           6 :     ulong        const buf_sz_ = (buf_sz);                             \
     611           6 :     int *              perr_   = (perr);                               \
     612           6 :     fd_##type##suffix##_t *    res     = NULL;                         \
     613           6 :     fd_bincode_decode_ctx_t ctx = {0};                                 \
     614           6 :     ctx.data    = (void const *)( buf_ );                              \
     615           6 :     ctx.dataend = (void const *)( (ulong)ctx.data + buf_sz_ );         \
     616           6 :     ulong total_sz = 0UL;                                              \
     617           6 :     int err = fd_##type##_decode_footprint( &ctx, &total_sz );         \
     618           6 :     if( FD_LIKELY( err==FD_BINCODE_SUCCESS ) ) {                       \
     619           6 :       res = fd_##type##_decode##suffix( (out), &ctx );                 \
     620           6 :     }                                                                  \
     621           6 :     if( perr_ ) *perr_ = err;                                          \
     622           6 :     res;                                                               \
     623           6 :   })
     624             : 
     625             : #define fd_bincode_decode_static( t,o,b,s,p ) \
     626           6 :   fd_bincode_decode_static1( t, , o, b, s, p )
     627             : 
     628             : #define fd_bincode_decode_static_global( t,o,b,s,p ) \
     629             :   fd_bincode_decode_static1( t, _global, o, b, s, p )
     630             : 
     631             : #define fd_bincode_decode_static_limited_deserialize( type, out, buf, buf_sz, limit, perr ) \
     632           0 :   fd_bincode_decode_static( type, out, buf, buf_sz>limit ? limit : buf_sz, perr )
     633             : 
     634             : #endif /* HEADER_fd_src_flamenco_types_fd_bincode_h */

Generated by: LCOV version 1.14