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 1599 : #define FD_ZSTD_FRAME_STATE_HEADER (0U) 11 2577 : #define FD_ZSTD_FRAME_STATE_BLOCK_HEADER (1U) 12 6072 : #define FD_ZSTD_FRAME_STATE_PAYLOAD (2U) 13 2601 : #define FD_ZSTD_FRAME_STATE_SKIPPABLE (3U) 14 1209 : #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 1185 : #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 5517 : #define FAIL_IF( c, frame, consumed, off ) do { \ 25 5517 : 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 5517 : } while( 0 ) 31 : 32 : int 33 : fd_zstd_frame_advance( fd_zstd_frame_t * frame, 34 : void const * data, 35 : ulong data_sz, 36 3042 : ulong * consumed ) { 37 3042 : uchar const * bytes = (uchar const *)data; 38 3042 : ulong off = 0UL; 39 : 40 5505 : for(;;) { 41 5505 : switch( frame->state ) { 42 1599 : case FD_ZSTD_FRAME_STATE_HEADER: { 43 1599 : ZSTD_frameHeader header[1]; 44 : 45 4323 : for(;;) { 46 4323 : ulong rc = ZSTD_getFrameHeader( header, frame->header, frame->header_sz ); 47 4323 : FAIL_IF( ZSTD_isError( rc ), frame, consumed, off ); 48 : 49 4308 : if( !rc ) break; 50 : 51 : /* Library invariants for rc > 0 */ 52 3090 : FD_TEST( rc<=FD_ZSTD_FRAME_HEADER_MAX ); 53 3090 : FD_TEST( frame->header_sz<rc ); 54 : 55 3090 : if( off==data_sz ) { 56 366 : *consumed = off; 57 366 : return FD_ZSTD_FRAME_MORE; 58 366 : } 59 : 60 2724 : ulong need = rc-frame->header_sz; 61 2724 : ulong copy_sz = fd_ulong_min( need, data_sz-off ); 62 : 63 2724 : fd_memcpy( frame->header+frame->header_sz, bytes+off, copy_sz ); 64 2724 : frame->header_sz += (uchar)copy_sz; 65 2724 : off += copy_sz; 66 2724 : } 67 : 68 1218 : if( header->frameType==ZSTD_skippableFrame ) { 69 84 : frame->bytes_remaining = (ulong)header->frameContentSize; 70 84 : frame->state = FD_ZSTD_FRAME_STATE_SKIPPABLE; 71 1134 : } else { 72 1134 : frame->block_sz_max = header->blockSizeMax; 73 1134 : frame->checksum_sz = header->checksumFlag ? 4U : 0U; 74 1134 : frame->state = FD_ZSTD_FRAME_STATE_BLOCK_HEADER; 75 1134 : } 76 1218 : continue; 77 1599 : } 78 : 79 1383 : case FD_ZSTD_FRAME_STATE_BLOCK_HEADER: { 80 1383 : ulong need = FD_ZSTD_FRAME_BLOCK_HEADER_SZ-frame->block_header_sz; 81 1383 : ulong copy_sz = fd_ulong_min( need, data_sz-off ); 82 : 83 1383 : fd_memcpy( frame->block_header+frame->block_header_sz, bytes+off, copy_sz ); 84 1383 : frame->block_header_sz += (uchar)copy_sz; 85 1383 : off += copy_sz; 86 : 87 1383 : if( FD_UNLIKELY( copy_sz<need ) ) { 88 189 : *consumed = data_sz; 89 189 : return FD_ZSTD_FRAME_MORE; 90 189 : } 91 : 92 1194 : uint block_header = fd_uint_load_3( frame->block_header ); 93 1194 : uint last_block = block_header & 1U; /* bit 0 */ 94 1194 : uint block_type = (block_header>>1) & 3U; /* bits 1-2 */ 95 1194 : uint block_sz = block_header>>3; /* bits 3-23 */ 96 : 97 1194 : FAIL_IF( block_type==FD_ZSTD_FRAME_BLOCK_TYPE_RESERVED || block_sz>frame->block_sz_max, frame, consumed, off ); 98 : 99 1185 : frame->block_header_sz = 0U; 100 1185 : frame->last_block = (uchar)last_block; 101 1185 : frame->bytes_remaining = block_type==FD_ZSTD_FRAME_BLOCK_TYPE_RLE ? 1UL : (ulong)block_sz; 102 1185 : frame->state = FD_ZSTD_FRAME_STATE_PAYLOAD; 103 : 104 1185 : if( last_block ) frame->bytes_remaining += frame->checksum_sz; 105 : 106 1185 : continue; 107 1194 : } 108 : 109 2355 : case FD_ZSTD_FRAME_STATE_PAYLOAD: 110 2517 : case FD_ZSTD_FRAME_STATE_SKIPPABLE: { 111 2517 : ulong skip = fd_ulong_min( frame->bytes_remaining, data_sz-off ); 112 2517 : frame->bytes_remaining -= skip; 113 2517 : off += skip; 114 : 115 2517 : if( frame->bytes_remaining ) { 116 1251 : *consumed = data_sz; 117 1251 : return FD_ZSTD_FRAME_MORE; 118 1251 : } 119 : 120 1266 : 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 1206 : frame->state = FD_ZSTD_FRAME_STATE_END; 126 1206 : *consumed = off; 127 1206 : return FD_ZSTD_FRAME_END; 128 1266 : } 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 5505 : } 138 5505 : } 139 3042 : }