Line data Source code
1 : #define _GNU_SOURCE 2 : #define _FILE_OFFSET_BITS 64 3 : #include <stdio.h> 4 : #include <stdlib.h> 5 : #include <zstd.h> 6 : #include "../../util/log/fd_log.h" 7 : #include "fd_libc_zstd.h" 8 : 9 : struct fd_zstd_rstream { 10 : FILE * file; 11 : ZSTD_DStream * dstream; 12 : ulong in_rd; 13 : uchar * in_buf; 14 : ulong in_buf_max; 15 : ZSTD_inBuffer input; 16 : uint eof : 1; 17 : }; 18 : 19 : typedef struct fd_zstd_rstream fd_zstd_rstream_t; 20 : 21 : static ssize_t 22 : rstream_read( void * cookie, 23 : char * buf, 24 0 : size_t size ) { 25 0 : fd_zstd_rstream_t * zs = cookie; 26 0 : if( zs->eof ) return 0; 27 : 28 0 : ZSTD_outBuffer output = { buf, size, 0 }; 29 0 : while( output.pos < output.size ) { 30 0 : if( zs->input.pos >= zs->input.size ) { 31 0 : size_t read_sz = fread( zs->in_buf, 1, zs->in_buf_max, zs->file ); 32 0 : if( read_sz==0 ) { 33 0 : if( feof( zs->file ) ) break; 34 0 : return -1; 35 0 : } 36 0 : zs->input.src = zs->in_buf; 37 0 : zs->input.size = read_sz; 38 0 : zs->input.pos = 0; 39 0 : } 40 : 41 0 : size_t const ret = ZSTD_decompressStream( zs->dstream, &output, &zs->input ); 42 0 : if( FD_UNLIKELY( ZSTD_isError( ret ) ) ) { 43 0 : FD_LOG_WARNING(( "ZSTD_decompressStream failed (%u-%s)", ZSTD_getErrorCode( ret ), ZSTD_getErrorName( ret ) )); 44 0 : return -1; 45 0 : } 46 : 47 0 : if( output.pos>0 && ret==0 ) break; 48 0 : } 49 : 50 0 : zs->eof = (!!feof( zs->file )) && (zs->input.pos >= zs->input.size); 51 0 : zs->in_rd += output.pos; 52 0 : return (ssize_t)output.pos; 53 0 : } 54 : 55 : static int 56 : rstream_seek( void * cookie, 57 : long * pos, 58 0 : int w ) { 59 0 : fd_zstd_rstream_t * zs = cookie; 60 0 : if( FD_UNLIKELY( *pos ) ) { 61 0 : FD_LOG_WARNING(( "Invalid seek(%ld,%i) on fd_libc_zstd_rstream handle", *pos, w )); 62 0 : return -1; 63 0 : } 64 0 : if( w==SEEK_SET ) { 65 0 : if( FD_UNLIKELY( 0!=fseek( zs->file, 0L, SEEK_SET ) ) ) { 66 0 : return -1; 67 0 : } 68 0 : zs->input.src = zs->in_buf; 69 0 : zs->input.size = 0; 70 0 : zs->input.pos = 0; 71 0 : zs->in_rd = 0UL; 72 0 : zs->eof = 0; 73 0 : size_t const reset_ret = ZSTD_DCtx_reset( zs->dstream, ZSTD_reset_session_only ); 74 0 : if( FD_UNLIKELY( ZSTD_isError( reset_ret ) ) ) return -1; 75 0 : *pos = 0L; 76 0 : } else if( w==SEEK_CUR ) { 77 0 : *pos = (long)zs->in_rd; 78 0 : } else { 79 0 : FD_LOG_CRIT(( "unsupported seek mode" )); 80 0 : } 81 0 : return 0; 82 0 : } 83 : 84 : static int 85 0 : rstream_close( void * cookie ) { 86 0 : fd_zstd_rstream_t * zs = cookie; 87 0 : int close_ret = fclose( zs->file ); 88 0 : free( zs->in_buf ); 89 0 : free( zs ); 90 0 : return close_ret; 91 0 : } 92 : 93 : FILE * 94 : fd_zstd_rstream_open( FILE * file, 95 : ZSTD_DStream * dstream, 96 0 : ulong buf_sz ) { 97 0 : if( FD_UNLIKELY( !buf_sz ) ) return NULL; 98 : 99 0 : fd_zstd_rstream_t * zs = malloc( sizeof(fd_zstd_rstream_t) ); 100 0 : if( FD_UNLIKELY( !zs ) ) return NULL; 101 : 102 0 : uchar * buf = malloc( buf_sz ); 103 0 : if( FD_UNLIKELY( !buf ) ) { 104 0 : free( zs ); 105 0 : return NULL; 106 0 : } 107 : 108 0 : zs->file = file; 109 0 : zs->dstream = dstream; 110 : 111 0 : size_t const init_ret = ZSTD_DCtx_reset( dstream, ZSTD_reset_session_only ); 112 0 : if( FD_UNLIKELY( ZSTD_isError( init_ret ) ) ) { 113 0 : FD_LOG_WARNING(( "ZSTD_DCtx_reset failed: %s", ZSTD_getErrorName( init_ret ) )); 114 0 : free( zs ); 115 0 : free( buf ); 116 0 : return NULL; 117 0 : } 118 : 119 0 : zs->in_rd = 0UL; 120 0 : zs->in_buf = buf; 121 0 : zs->in_buf_max = buf_sz; 122 0 : zs->input.src = zs->in_buf; 123 0 : zs->input.size = 0; 124 0 : zs->input.pos = 0; 125 0 : zs->eof = 0; 126 : 127 0 : static cookie_io_functions_t const io_funcs = { 128 0 : .read = rstream_read, 129 0 : .write = NULL, 130 0 : .seek = rstream_seek, 131 0 : .close = rstream_close 132 0 : }; 133 0 : FILE * ret = fopencookie( zs, "rb", io_funcs ); 134 0 : if( FD_UNLIKELY( !ret ) ) { 135 0 : free( buf ); 136 0 : free( zs ); 137 0 : } 138 0 : return ret; 139 0 : }