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 : }