3535#include <sys/types.h>
3636#include <inttypes.h>
3737
38+ #ifdef HAVE_LIBDEFLATE
39+ #include <libdeflate.h>
40+ #endif
41+
3842#include "htslib/hts.h"
3943#include "htslib/bgzf.h"
4044#include "htslib/hfile.h"
@@ -359,6 +363,64 @@ BGZF *bgzf_hopen(hFILE *hfp, const char *mode)
359363 return fp ;
360364}
361365
366+ #ifdef HAVE_LIBDEFLATE
367+ int bgzf_compress (void * _dst , size_t * dlen , const void * src , size_t slen , int level )
368+ {
369+ if (slen == 0 ) {
370+ // EOF block
371+ if (* dlen < 28 ) return -1 ;
372+ memcpy (_dst , "\037\213\010\4\0\0\0\0\0\377\6\0\102\103\2\0\033\0\3\0\0\0\0\0\0\0\0\0" , 28 );
373+ * dlen = 28 ;
374+ return 0 ;
375+ }
376+
377+ uint8_t * dst = (uint8_t * )_dst ;
378+
379+ if (level == 0 ) {
380+ // Uncompressed data
381+ if (* dlen < slen + 5 + BLOCK_HEADER_LENGTH + BLOCK_FOOTER_LENGTH ) return -1 ;
382+ dst [BLOCK_HEADER_LENGTH ] = 1 ; // BFINAL=1, BTYPE=00; see RFC1951
383+ u16_to_le (slen , & dst [BLOCK_HEADER_LENGTH + 1 ]); // length
384+ u16_to_le (~slen , & dst [BLOCK_HEADER_LENGTH + 3 ]); // ones-complement length
385+ memcpy (dst + BLOCK_HEADER_LENGTH + 5 , src , slen );
386+ * dlen = slen + 5 + BLOCK_HEADER_LENGTH + BLOCK_FOOTER_LENGTH ;
387+
388+ } else {
389+ level = level > 0 ? level : 6 ; // libdeflate doesn't honour -1 as default
390+ // NB levels go up to 12 here.
391+ struct libdeflate_compressor * z = libdeflate_alloc_compressor (level );
392+ if (!z ) return -1 ;
393+
394+ // Raw deflate
395+ size_t clen =
396+ libdeflate_deflate_compress (z , src , slen ,
397+ dst + BLOCK_HEADER_LENGTH ,
398+ * dlen - BLOCK_HEADER_LENGTH - BLOCK_FOOTER_LENGTH );
399+
400+ if (clen <= 0 ) {
401+ hts_log_error ("Call to libdeflate_deflate_compress failed" );
402+ libdeflate_free_compressor (z );
403+ return -1 ;
404+ }
405+
406+ * dlen = clen + BLOCK_HEADER_LENGTH + BLOCK_FOOTER_LENGTH ;
407+
408+ libdeflate_free_compressor (z );
409+ }
410+
411+ // write the header
412+ memcpy (dst , g_magic , BLOCK_HEADER_LENGTH ); // the last two bytes are a place holder for the length of the block
413+ packInt16 (& dst [16 ], * dlen - 1 ); // write the compressed length; -1 to fit 2 bytes
414+
415+ // write the footer
416+ uint32_t crc = libdeflate_crc32 (0 , src , slen );
417+ packInt32 ((uint8_t * )& dst [* dlen - 8 ], crc );
418+ packInt32 ((uint8_t * )& dst [* dlen - 4 ], slen );
419+ return 0 ;
420+ }
421+
422+ #else
423+
362424int bgzf_compress (void * _dst , size_t * dlen , const void * src , size_t slen , int level )
363425{
364426 uint32_t crc ;
@@ -395,6 +457,7 @@ int bgzf_compress(void *_dst, size_t *dlen, const void *src, size_t slen, int le
395457 packInt32 ((uint8_t * )& dst [* dlen - 4 ], slen );
396458 return 0 ;
397459}
460+ #endif // HAVE_LIBDEFLATE
398461
399462static int bgzf_gzip_compress (BGZF * fp , void * _dst , size_t * dlen , const void * src , size_t slen , int level )
400463{
@@ -438,6 +501,28 @@ static int deflate_block(BGZF *fp, int block_length)
438501 return comp_size ;
439502}
440503
504+ #ifdef HAVE_LIBDEFLATE
505+
506+ static int bgzf_uncompress (uint8_t * dst , size_t * dlen , const uint8_t * src , size_t slen ) {
507+ struct libdeflate_decompressor * z = libdeflate_alloc_decompressor ();
508+ if (!z ) {
509+ hts_log_error ("Call to libdeflate_alloc_decompressor failed" );
510+ return -1 ;
511+ }
512+
513+ int ret = libdeflate_deflate_decompress (z , src , slen , dst , * dlen , dlen );
514+ libdeflate_free_decompressor (z );
515+
516+ if (ret != LIBDEFLATE_SUCCESS ) {
517+ hts_log_error ("Inflate operation failed: %d" , ret );
518+ return -1 ;
519+ }
520+
521+ return 0 ;
522+ }
523+
524+ #else
525+
441526static int bgzf_uncompress (uint8_t * dst , size_t * dlen , const uint8_t * src , size_t slen ) {
442527 z_stream zs ;
443528 zs .zalloc = NULL ;
@@ -467,6 +552,7 @@ static int bgzf_uncompress(uint8_t *dst, size_t *dlen, const uint8_t *src, size_
467552 * dlen = * dlen - zs .avail_out ;
468553 return 0 ;
469554}
555+ #endif // HAVE_LIBDEFLATE
470556
471557// Inflate the block in fp->compressed_block into fp->uncompressed_block
472558static int inflate_block (BGZF * fp , int block_length )
@@ -482,7 +568,11 @@ static int inflate_block(BGZF* fp, int block_length)
482568 // Check CRC of uncompressed block matches the gzip header.
483569 // NB: we may wish to switch out the zlib crc32 for something more performant.
484570 // See PR#361 and issue#467
571+ #ifdef HAVE_LIBDEFLATE
572+ uint32_t c1 = libdeflate_crc32 (0L , (unsigned char * )fp -> uncompressed_block , dlen );
573+ #else
485574 uint32_t c1 = crc32 (0L , (unsigned char * )fp -> uncompressed_block , dlen );
575+ #endif
486576 uint32_t c2 = le_to_u32 ((uint8_t * )fp -> compressed_block + block_length - 8 );
487577 if (c1 != c2 ) {
488578 fp -> errcode |= BGZF_ERR_CRC ;
@@ -1160,7 +1250,7 @@ static void *bgzf_mt_reader(void *vp) {
11601250 pthread_cond_signal (& mt -> command_c );
11611251 pthread_mutex_unlock (& mt -> command_m );
11621252 hts_tpool_process_destroy (mt -> out_queue );
1163- pthread_exit ( NULL ) ;
1253+ return NULL ;
11641254
11651255 default :
11661256 break ;
@@ -1182,7 +1272,7 @@ static void *bgzf_mt_reader(void *vp) {
11821272 // We tear down the multi-threaded decoder and revert to the old code.
11831273 hts_tpool_dispatch (mt -> pool , mt -> out_queue , bgzf_nul_func , j );
11841274 hts_tpool_process_ref_decr (mt -> out_queue );
1185- pthread_exit ( & j -> errcode ) ;
1275+ return & j -> errcode ;
11861276 }
11871277
11881278 // Dispatch an empty block so EOF is spotted.
@@ -1193,7 +1283,7 @@ static void *bgzf_mt_reader(void *vp) {
11931283 hts_tpool_dispatch (mt -> pool , mt -> out_queue , bgzf_nul_func , j );
11941284 if (j -> errcode != 0 ) {
11951285 hts_tpool_process_destroy (mt -> out_queue );
1196- pthread_exit ( & j -> errcode ) ;
1286+ return & j -> errcode ;
11971287 }
11981288
11991289 // We hit EOF so can stop reading, but we may get a subsequent
@@ -1224,10 +1314,9 @@ static void *bgzf_mt_reader(void *vp) {
12241314 pthread_cond_signal (& mt -> command_c );
12251315 pthread_mutex_unlock (& mt -> command_m );
12261316 hts_tpool_process_destroy (mt -> out_queue );
1227- pthread_exit ( NULL ) ;
1317+ return NULL ;
12281318 }
12291319 }
1230- return NULL ;
12311320}
12321321
12331322int bgzf_thread_pool (BGZF * fp , hts_tpool * pool , int qsize ) {
@@ -1452,7 +1541,7 @@ ssize_t bgzf_block_write(BGZF *fp, const void *data, size_t length)
14521541 uint64_t ublock_size ; // amount of uncompressed data to be fed into next block
14531542 while (remaining > 0 ) {
14541543 current_block = fp -> idx -> moffs - fp -> idx -> noffs ;
1455- ublock_size = fp -> idx -> offs [current_block + 1 ].uaddr - fp -> idx -> offs [current_block ].uaddr ;
1544+ ublock_size = current_block + 1 < fp -> idx -> moffs ? fp -> idx -> offs [current_block + 1 ].uaddr - fp -> idx -> offs [current_block ].uaddr : BGZF_MAX_BLOCK_SIZE ;
14561545 uint8_t * buffer = (uint8_t * )fp -> uncompressed_block ;
14571546 int copy_length = ublock_size - fp -> block_offset ;
14581547 if (copy_length > remaining ) copy_length = remaining ;
@@ -1462,7 +1551,8 @@ ssize_t bgzf_block_write(BGZF *fp, const void *data, size_t length)
14621551 remaining -= copy_length ;
14631552 if (fp -> block_offset == ublock_size ) {
14641553 if (lazy_flush (fp ) != 0 ) return -1 ;
1465- fp -> idx -> noffs -- ; // decrement noffs to track the blocks
1554+ if (fp -> idx -> noffs > 0 )
1555+ fp -> idx -> noffs -- ; // decrement noffs to track the blocks
14661556 }
14671557 }
14681558 return length - remaining ;
0 commit comments