Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ AR = ar
RANLIB = ranlib

# Default libraries to link if configure is not used
htslib_default_libs = -lz -lm -lbz2 -llzma -lcurl
htslib_default_libs = -lz -lm -lbz2 -llzma -lcurl -lisal

CPPFLAGS =
# TODO: make the 64-bit support for VCF optional via configure, for now add -DVCF_ALLOW_INT64
Expand Down
117 changes: 112 additions & 5 deletions bgzf.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,13 @@
#include <libdeflate.h>
#endif

/* Should be fixed in the build system later */
#define HAVE_ISAL 1
#ifdef HAVE_ISAL
#include <isa-l.h>
#include <isa-l/crc.h>
#endif

#include "htslib/hts.h"
#include "htslib/bgzf.h"
#include "htslib/hfile.h"
Expand Down Expand Up @@ -547,11 +554,70 @@ BGZF *bgzf_hopen(hFILE *hfp, const char *mode)
return fp;
}

#ifdef HAVE_LIBDEFLATE
#if HAVE_ISAL
uint32_t hts_crc32(uint32_t crc, const void *buf, size_t len) {
return crc32_gzip_refl(crc, buf, len);
}
#elif HAVE_LIBDEFLATE
uint32_t hts_crc32(uint32_t crc, const void *buf, size_t len) {
return libdeflate_crc32(crc, buf, len);
}
#else
uint32_t hts_crc32(uint32_t crc, const void *buf, size_t len) {
return crc32(crc, buf, len);
}
#endif

#if HAVE_ISAL
static int _bgzf_compress_isal(uint8_t *dst, size_t *dlen, const void *src, size_t slen, int level)
{
if (level < 0 || level > 3) {
return -1;
}
struct isal_zstream *z = malloc(sizeof(struct isal_zstream));
if (z == NULL) {
return -1;
}
static int level_buf_sizes[] = {
ISAL_DEF_LVL0_DEFAULT,
ISAL_DEF_LVL1_DEFAULT,
ISAL_DEF_LVL2_DEFAULT,
ISAL_DEF_LVL3_DEFAULT
};
size_t level_buf_size = level_buf_sizes[level];
uint8_t *level_buf = malloc(level_buf_size);
if (level_buf == NULL) {
free(z);
}
isal_deflate_init(z);
z->level = level;
z->level_buf = level_buf;
z->level_buf_size = level_buf_size;
z->gzip_flag = IGZIP_GZIP_NO_HDR; // Also calculates length and CRC
z->next_in = (uint8_t *)src;
z->avail_in = slen;
z->next_out = dst + BLOCK_HEADER_LENGTH;
z->avail_out = *dlen - BLOCK_HEADER_LENGTH;
z->flush = FULL_FLUSH;
z->end_of_stream = 1;

int ret = isal_deflate(z);
if (ret != COMP_OK) {
hts_log_error("Call to _bgzf_compress_isal failed");
free(level_buf);
free(z);
return -1;
}
*dlen = z->next_out - (uint8_t *)dst;
free(level_buf);
free(z);
memcpy(dst, g_magic, BLOCK_HEADER_LENGTH); // the last two bytes are a place holder for the length of the block
packInt16(&dst[16], *dlen - 1); // write the compressed length; -1 to fit 2 bytes
return 0;
}
#endif

#if HAVE_LIBDEFLATE
int bgzf_compress(void *_dst, size_t *dlen, const void *src, size_t slen, int level)
{
if (slen == 0) {
Expand All @@ -575,6 +641,13 @@ int bgzf_compress(void *_dst, size_t *dlen, const void *src, size_t slen, int le

} else {
level = level > 0 ? level : 6; // libdeflate doesn't honour -1 as default

#if HAVE_ISAL
if (level == 1 || level == 2) {
return _bgzf_compress_isal(dst, dlen, src, slen, level);
}
#endif

// NB levels go up to 12 here.
int lvl_map[] = {0,1,2,3,5,6,7,8,10,12};
level = lvl_map[level>9 ?9 :level];
Expand Down Expand Up @@ -611,9 +684,6 @@ int bgzf_compress(void *_dst, size_t *dlen, const void *src, size_t slen, int le

#else

uint32_t hts_crc32(uint32_t crc, const void *buf, size_t len) {
return crc32(crc, buf, len);
}

int bgzf_compress(void *_dst, size_t *dlen, const void *src, size_t slen, int level)
{
Expand Down Expand Up @@ -719,7 +789,44 @@ static int deflate_block(BGZF *fp, int block_length)
return comp_size;
}

#ifdef HAVE_LIBDEFLATE
#ifdef HAVE_ISAL
static int bgzf_uncompress(uint8_t *dst, size_t *dlen,
const uint8_t *src, size_t slen,
uint32_t expected_crc) {
struct inflate_state *z = malloc(sizeof(struct inflate_state));
if (z == NULL) {
hts_log_error("Allocating isal inflate state failed");
return -1;
}
isal_inflate_init(z);
z->next_in = (uint8_t *)src;
z->avail_in = slen;
z->next_out = dst;
z->avail_out = *dlen;
z->crc_flag = ISAL_GZIP_NO_HDR;

int ret = isal_inflate(z);
if (ret != ISAL_DECOMP_OK) {
hts_log_error("Inflate operation failed: %d", ret);
free(z);
return -1;

}
*dlen = z->next_out - dst;
uint32_t crc = z->crc;
free(z);
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
// Pretend the CRC was OK so the fuzzer doesn't have to get it right
crc = expected_crc;
#endif
if (crc != expected_crc) {
hts_log_error("CRC32 checksum mismatch");
return -2;
}
return 0;
}

#elif HAVE_LIBDEFLATE

static int bgzf_uncompress(uint8_t *dst, size_t *dlen,
const uint8_t *src, size_t slen,
Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ AS_IF([test "x$with_libdeflate" != "xno"],
AC_CHECK_LIB([deflate], [libdeflate_deflate_compress],[:],[libdeflate='missing library'])
AS_IF([test "$libdeflate" = "ok"],
[AC_DEFINE([HAVE_LIBDEFLATE], 1, [Define if libdeflate is available.])
LIBS="-ldeflate $LIBS"
LIBS="-ldeflate -lisal $LIBS"
private_LIBS="$private_LIBS -ldeflate"
static_LIBS="$static_LIBS -ldeflate"],
[AS_IF([test "x$with_libdeflate" != "xcheck"],
Expand Down
Loading