LCOV - code coverage report
Current view: top level - discof/restore/utils - fd_zstd_frame.c (source / functions) Hit Total Coverage
Test: cov.lcov Lines: 95 95 100.0 %
Date: 2026-09-17 04:28:31 Functions: 1 1 100.0 %

          Line data    Source code
       1             : #include "fd_zstd_frame.h"
       2             : 
       3             : #include "../../../util/bits/fd_bits.h"
       4             : #include "../../../util/log/fd_log.h"
       5             : 
       6             : #define ZSTD_STATIC_LINKING_ONLY
       7             : #include <zstd.h>
       8             : 
       9             : /* Different states of the ZSTD frame parser state machine */
      10        1509 : #define FD_ZSTD_FRAME_STATE_HEADER       (0U)
      11        2397 : #define FD_ZSTD_FRAME_STATE_BLOCK_HEADER (1U)
      12        5712 : #define FD_ZSTD_FRAME_STATE_PAYLOAD      (2U)
      13        2511 : #define FD_ZSTD_FRAME_STATE_SKIPPABLE    (3U)
      14        1119 : #define FD_ZSTD_FRAME_STATE_END          (4U)
      15          24 : #define FD_ZSTD_FRAME_STATE_ERR          (5U)
      16             : 
      17             : /* Different block types
      18             :    https://github.com/facebook/zstd/blob/dev/doc/zstd_compression_format.md#blocks */
      19             : #define FD_ZSTD_FRAME_BLOCK_TYPE_RAW        (0U)
      20        1095 : #define FD_ZSTD_FRAME_BLOCK_TYPE_RLE        (1U)
      21             : #define FD_ZSTD_FRAME_BLOCK_TYPE_COMPRESSED (2U)
      22             : #define FD_ZSTD_FRAME_BLOCK_TYPE_RESERVED   (3U)
      23             : 
      24        5157 : #define FAIL_IF( c, frame, consumed, off ) do { \
      25        5157 :   if( FD_UNLIKELY( c ) ) {                      \
      26          24 :     (frame)->state = FD_ZSTD_FRAME_STATE_ERR;   \
      27          24 :     *(consumed)    = (off);                     \
      28          24 :     return FD_ZSTD_FRAME_ERR;                   \
      29          24 :   }                                             \
      30        5157 : } while( 0 )
      31             : 
      32             : int
      33             : fd_zstd_frame_advance( fd_zstd_frame_t * frame,
      34             :                        void const *      data,
      35             :                        ulong             data_sz,
      36        2952 :                        ulong *           consumed ) {
      37        2952 :   uchar const * bytes = (uchar const *)data;
      38        2952 :   ulong off = 0UL;
      39             : 
      40        5235 :   for(;;) {
      41        5235 :     switch( frame->state ) {
      42        1509 :       case FD_ZSTD_FRAME_STATE_HEADER: {
      43        1509 :         ZSTD_frameHeader header[1];
      44             : 
      45        4053 :         for(;;) {
      46        4053 :           ulong rc = ZSTD_getFrameHeader( header, frame->header, frame->header_sz );
      47        4053 :           FAIL_IF( ZSTD_isError( rc ), frame, consumed, off );
      48             : 
      49        4038 :           if( !rc ) break;
      50             : 
      51             :           /* Library invariants for rc > 0 */
      52        2910 :           FD_TEST( rc<=FD_ZSTD_FRAME_HEADER_MAX );
      53        2910 :           FD_TEST( frame->header_sz<rc );
      54             : 
      55        2910 :           if( off==data_sz ) {
      56         366 :             *consumed = off;
      57         366 :             return FD_ZSTD_FRAME_MORE;
      58         366 :           }
      59             : 
      60        2544 :           ulong need    = rc-frame->header_sz;
      61        2544 :           ulong copy_sz = fd_ulong_min( need, data_sz-off );
      62             : 
      63        2544 :           fd_memcpy( frame->header+frame->header_sz, bytes+off, copy_sz );
      64        2544 :           frame->header_sz += (uchar)copy_sz;
      65        2544 :           off              += copy_sz;
      66        2544 :         }
      67             : 
      68        1128 :         if( header->frameType==ZSTD_skippableFrame ) {
      69          84 :           frame->bytes_remaining = (ulong)header->frameContentSize;
      70          84 :           frame->state           = FD_ZSTD_FRAME_STATE_SKIPPABLE;
      71        1044 :         } else {
      72        1044 :           frame->block_sz_max = header->blockSizeMax;
      73        1044 :           frame->checksum_sz  = header->checksumFlag ? 4U : 0U;
      74        1044 :           frame->state        = FD_ZSTD_FRAME_STATE_BLOCK_HEADER;
      75        1044 :         }
      76        1128 :         continue;
      77        1509 :       }
      78             : 
      79        1293 :       case FD_ZSTD_FRAME_STATE_BLOCK_HEADER: {
      80        1293 :         ulong need    = FD_ZSTD_FRAME_BLOCK_HEADER_SZ-frame->block_header_sz;
      81        1293 :         ulong copy_sz = fd_ulong_min( need, data_sz-off );
      82             : 
      83        1293 :         fd_memcpy( frame->block_header+frame->block_header_sz, bytes+off, copy_sz );
      84        1293 :         frame->block_header_sz += (uchar)copy_sz;
      85        1293 :         off                    += copy_sz;
      86             : 
      87        1293 :         if( FD_UNLIKELY( copy_sz<need ) ) {
      88         189 :           *consumed = data_sz;
      89         189 :           return FD_ZSTD_FRAME_MORE;
      90         189 :         }
      91             : 
      92        1104 :         uint block_header = fd_uint_load_3( frame->block_header );
      93        1104 :         uint last_block   = block_header & 1U;      /* bit 0 */
      94        1104 :         uint block_type   = (block_header>>1) & 3U; /* bits 1-2 */
      95        1104 :         uint block_sz     = block_header>>3;        /* bits 3-23 */
      96             : 
      97        1104 :         FAIL_IF( block_type==FD_ZSTD_FRAME_BLOCK_TYPE_RESERVED || block_sz>frame->block_sz_max, frame, consumed, off );
      98             : 
      99        1095 :         frame->block_header_sz = 0U;
     100        1095 :         frame->last_block      = (uchar)last_block;
     101        1095 :         frame->bytes_remaining = block_type==FD_ZSTD_FRAME_BLOCK_TYPE_RLE ? 1UL : (ulong)block_sz;
     102        1095 :         frame->state           = FD_ZSTD_FRAME_STATE_PAYLOAD;
     103             : 
     104        1095 :         if( last_block ) frame->bytes_remaining += frame->checksum_sz;
     105             : 
     106        1095 :         continue;
     107        1104 :       }
     108             : 
     109        2265 :       case FD_ZSTD_FRAME_STATE_PAYLOAD:
     110        2427 :       case FD_ZSTD_FRAME_STATE_SKIPPABLE: {
     111        2427 :         ulong skip = fd_ulong_min( frame->bytes_remaining, data_sz-off );
     112        2427 :         frame->bytes_remaining -= skip;
     113        2427 :         off                    += skip;
     114             : 
     115        2427 :         if( frame->bytes_remaining ) {
     116        1251 :           *consumed = data_sz;
     117        1251 :           return FD_ZSTD_FRAME_MORE;
     118        1251 :         }
     119             : 
     120        1176 :         if( frame->state==FD_ZSTD_FRAME_STATE_PAYLOAD && !frame->last_block ) {
     121          60 :           frame->state = FD_ZSTD_FRAME_STATE_BLOCK_HEADER;
     122          60 :           continue;
     123          60 :         }
     124             : 
     125        1116 :         frame->state = FD_ZSTD_FRAME_STATE_END;
     126        1116 :         *consumed    = off;
     127        1116 :         return FD_ZSTD_FRAME_END;
     128        1176 :       }
     129             : 
     130           3 :       case FD_ZSTD_FRAME_STATE_END:
     131           3 :         *consumed = 0UL;
     132           3 :         return FD_ZSTD_FRAME_END;
     133             : 
     134           3 :       default:
     135           3 :         *consumed = 0UL;
     136           3 :         return FD_ZSTD_FRAME_ERR;
     137        5235 :     }
     138        5235 :   }
     139        2952 : }

Generated by: LCOV version 1.14