LCOV - code coverage report
Current view: top level - flamenco/types - fd_bincode.h (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 164 353 46.5 %
Date: 2025-08-05 05:04:49 Functions: 27 10388 0.3 %

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

Generated by: LCOV version 1.14