Line data Source code
1 : #include "fd_zstd.h" 2 : #include "fd_zstd_private.h" 3 : #include "../../util/fd_util.h" 4 : 5 : #if !FD_HAS_ZSTD 6 : #error "fd_zstd requires libzstd" 7 : #endif 8 : 9 : #define ZSTD_STATIC_LINKING_ONLY 10 : #include <zstd.h> 11 : #include <errno.h> 12 : 13 : fd_zstd_peek_t * 14 : fd_zstd_peek( fd_zstd_peek_t * peek, 15 : void const * buf, 16 57 : ulong bufsz ) { 17 57 : ZSTD_frameHeader hdr[1]; 18 57 : ulong const err = ZSTD_getFrameHeader( hdr, buf, bufsz ); 19 57 : if( FD_UNLIKELY( ZSTD_isError( err ) ) ) return NULL; 20 57 : if( FD_UNLIKELY( err>0 ) ) return NULL; 21 36 : fd_msan_unpoison( hdr, sizeof(ZSTD_frameHeader) ); 22 36 : if( FD_UNLIKELY( hdr->windowSize > (1U<<ZSTD_WINDOWLOG_MAX) ) ) return NULL; 23 36 : peek->window_sz = hdr->windowSize; 24 36 : peek->frame_content_sz = hdr->frameContentSize; 25 36 : peek->frame_is_skippable = hdr->frameType == ZSTD_skippableFrame; 26 36 : return peek; 27 36 : } 28 : 29 : ulong 30 3 : fd_zstd_dstream_align( void ) { 31 3 : return FD_ZSTD_DSTREAM_ALIGN; 32 3 : } 33 : 34 : ulong 35 3 : fd_zstd_dstream_footprint( ulong max_window_sz ) { 36 3 : return offsetof(fd_zstd_dstream_t, mem) + ZSTD_estimateDStreamSize( max_window_sz ); 37 3 : } 38 : 39 : fd_zstd_dstream_t * 40 : fd_zstd_dstream_new( void * mem, 41 3 : ulong max_window_sz ) { 42 3 : fd_zstd_dstream_t * dstream = mem; 43 3 : dstream->mem_sz = ZSTD_estimateDStreamSize( max_window_sz ); 44 : 45 3 : ZSTD_DCtx * ctx = ZSTD_initStaticDStream( dstream->mem, ZSTD_estimateDStreamSize( max_window_sz ) ); 46 3 : if( FD_UNLIKELY( !ctx ) ) { 47 : /* should never happen */ 48 0 : FD_LOG_WARNING(( "ZSTD_initStaticDStream failed (max_window_sz=%lu)", max_window_sz )); 49 0 : return NULL; 50 0 : } 51 3 : if( FD_UNLIKELY( (ulong)ctx != (ulong)dstream->mem ) ) 52 0 : FD_LOG_CRIT(( "ZSTD_initStaticDStream returned unexpected pointer (ctx=%p, mem=%p)", 53 3 : (void *)ctx, (void *)dstream->mem )); 54 : 55 3 : FD_COMPILER_MFENCE(); 56 3 : dstream->magic = FD_ZSTD_DSTREAM_MAGIC; 57 3 : FD_COMPILER_MFENCE(); 58 3 : return dstream; 59 3 : } 60 : 61 : static ZSTD_DCtx * 62 231 : fd_zstd_dstream_ctx( fd_zstd_dstream_t * dstream ) { 63 231 : if( FD_UNLIKELY( dstream->magic != FD_ZSTD_DSTREAM_MAGIC ) ) 64 0 : FD_LOG_CRIT(( "fd_zstd_dstream_t at %p has invalid magic (memory corruption?)", (void *)dstream )); 65 231 : return (ZSTD_DCtx *)fd_type_pun( dstream->mem ); 66 231 : } 67 : 68 : void * 69 3 : fd_zstd_dstream_delete( fd_zstd_dstream_t * dstream ) { 70 : 71 3 : if( FD_UNLIKELY( !dstream ) ) return NULL; 72 : 73 : /* No need to inform libzstd */ 74 : 75 3 : FD_COMPILER_MFENCE(); 76 3 : dstream->magic = 0UL; 77 3 : dstream->mem_sz = 0UL; 78 3 : FD_COMPILER_MFENCE(); 79 : 80 3 : return (void *)dstream; 81 3 : } 82 : 83 : void 84 3 : fd_zstd_dstream_reset( fd_zstd_dstream_t * dstream ) { 85 3 : ZSTD_DCtx_reset( fd_zstd_dstream_ctx( dstream ), ZSTD_reset_session_only ); 86 3 : } 87 : 88 : int 89 : fd_zstd_dstream_read( fd_zstd_dstream_t * dstream, 90 : uchar const ** restrict in_p, 91 : uchar const * in_end, 92 : uchar ** restrict out_p, 93 : uchar * out_end, 94 228 : ulong * opt_errcode ) { 95 : 96 228 : ulong _opt_errcode[1]; 97 228 : opt_errcode = opt_errcode ? opt_errcode : _opt_errcode; 98 : 99 228 : uchar const * in_start = *in_p; 100 228 : uchar * out_start = *out_p; 101 : 102 228 : if( FD_UNLIKELY( ( in_start > in_end ) | 103 228 : ( out_start > out_end ) ) ) 104 0 : return EINVAL; 105 : 106 228 : ZSTD_inBuffer in_buf = 107 228 : { .src = in_start, 108 228 : .size = (ulong)in_end - (ulong)in_start, 109 228 : .pos = 0UL }; 110 228 : ZSTD_outBuffer out_buf = 111 228 : { .dst = out_start, 112 228 : .size = (ulong)out_end - (ulong)out_start, 113 228 : .pos = 0UL }; 114 : 115 228 : ZSTD_DCtx * ctx = fd_zstd_dstream_ctx( dstream ); 116 228 : ulong const rc = ZSTD_decompressStream( ctx, &out_buf, &in_buf ); 117 228 : if( FD_UNLIKELY( ZSTD_isError( rc ) ) ) { 118 0 : FD_LOG_WARNING(( "err: %s", ZSTD_getErrorName( rc ) )); 119 0 : *opt_errcode = rc; 120 0 : return EPROTO; 121 0 : } 122 : 123 228 : if( FD_UNLIKELY( (in_buf.size ) & (!in_buf.pos ) & 124 228 : (out_buf.size) & (!out_buf.pos) ) ) { 125 : /* should not happen */ 126 0 : FD_LOG_WARNING(( "libzstd returned success but failed to do any progress" )); 127 0 : *opt_errcode = 0UL; 128 0 : return EPIPE; 129 0 : } 130 : 131 228 : *in_p = (void const *)((ulong)in_start + in_buf.pos ); 132 228 : *out_p = (void * )((ulong)out_start + out_buf.pos); 133 228 : return rc==0UL ? -1 /* frame complete */ : 0 /* still working */; 134 228 : }