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 3 : if( FD_UNLIKELY( dstream->magic != FD_ZSTD_DSTREAM_MAGIC ) ) 74 0 : FD_LOG_CRIT(( "fd_zstd_dstream_t at %p has invalid magic (memory corruption?)", (void *)dstream )); 75 : 76 : /* No need to inform libzstd */ 77 : 78 3 : FD_COMPILER_MFENCE(); 79 3 : dstream->magic = 0UL; 80 3 : dstream->mem_sz = 0UL; 81 3 : FD_COMPILER_MFENCE(); 82 : 83 3 : return (void *)dstream; 84 3 : } 85 : 86 : void 87 3 : fd_zstd_dstream_reset( fd_zstd_dstream_t * dstream ) { 88 3 : ZSTD_DCtx_reset( fd_zstd_dstream_ctx( dstream ), ZSTD_reset_session_only ); 89 3 : } 90 : 91 : int 92 : fd_zstd_dstream_read( fd_zstd_dstream_t * dstream, 93 : uchar const ** restrict in_p, 94 : uchar const * in_end, 95 : uchar ** restrict out_p, 96 : uchar * out_end, 97 228 : ulong * opt_errcode ) { 98 : 99 228 : ulong _opt_errcode[1]; 100 228 : opt_errcode = opt_errcode ? opt_errcode : _opt_errcode; 101 : 102 228 : uchar const * in_start = *in_p; 103 228 : uchar * out_start = *out_p; 104 : 105 228 : if( FD_UNLIKELY( ( in_start > in_end ) | 106 228 : ( out_start > out_end ) ) ) 107 0 : return EINVAL; 108 : 109 228 : ZSTD_inBuffer in_buf = 110 228 : { .src = in_start, 111 228 : .size = (ulong)in_end - (ulong)in_start, 112 228 : .pos = 0UL }; 113 228 : ZSTD_outBuffer out_buf = 114 228 : { .dst = out_start, 115 228 : .size = (ulong)out_end - (ulong)out_start, 116 228 : .pos = 0UL }; 117 : 118 228 : ZSTD_DCtx * ctx = fd_zstd_dstream_ctx( dstream ); 119 228 : ulong const rc = ZSTD_decompressStream( ctx, &out_buf, &in_buf ); 120 228 : if( FD_UNLIKELY( ZSTD_isError( rc ) ) ) { 121 0 : FD_LOG_WARNING(( "err: %s", ZSTD_getErrorName( rc ) )); 122 0 : *opt_errcode = rc; 123 0 : return EPROTO; 124 0 : } 125 : 126 228 : if( FD_UNLIKELY( (in_buf.size ) & (!in_buf.pos ) & 127 228 : (out_buf.size) & (!out_buf.pos) ) ) { 128 : /* should not happen */ 129 0 : FD_LOG_WARNING(( "libzstd returned success but failed to do any progress" )); 130 0 : *opt_errcode = 0UL; 131 0 : return EPIPE; 132 0 : } 133 : 134 228 : *in_p = (void const *)((ulong)in_start + in_buf.pos ); 135 228 : *out_p = (void * )((ulong)out_start + out_buf.pos); 136 228 : return rc==0UL ? -1 /* frame complete */ : 0 /* still working */; 137 228 : }