130 lines
4.6 KiB
C++
130 lines
4.6 KiB
C++
|
|
#include "sam_io.h"
|
|||
|
|
|
|||
|
|
#include <htslib/sam.h>
|
|||
|
|
#include <libdeflate.h>
|
|||
|
|
#include <stdint.h>
|
|||
|
|
#include <stdio.h>
|
|||
|
|
#include <zlib.h>
|
|||
|
|
#include <spdlog/spdlog.h>
|
|||
|
|
|
|||
|
|
|
|||
|
|
namespace nsgv {
|
|||
|
|
extern bool gIsBigEndian;
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
int bgzfUncompress(uint8_t *dst, size_t *dlen, const uint8_t *src, size_t slen, uint32_t expected_crc) {
|
|||
|
|
struct libdeflate_decompressor *z = libdeflate_alloc_decompressor();
|
|||
|
|
if (!z) {
|
|||
|
|
hts_log_error("Call to libdeflate_alloc_decompressor failed");
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
int ret = libdeflate_deflate_decompress(z, src, slen, dst, *dlen, dlen);
|
|||
|
|
libdeflate_free_decompressor(z);
|
|||
|
|
|
|||
|
|
if (ret != LIBDEFLATE_SUCCESS) {
|
|||
|
|
hts_log_error("Inflate operation failed: %d", ret);
|
|||
|
|
return -1;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
uint32_t crc = libdeflate_crc32(0, (unsigned char *)dst, *dlen);
|
|||
|
|
#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;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void parseSamHeader(FILE *fp, HeaderBuf &hdrBuf) {
|
|||
|
|
const int kMaxBlockSize = 65535;
|
|||
|
|
sam_hdr_t *header = NULL;
|
|||
|
|
uint8_t *fBuf = (uint8_t*)malloc(kMaxBlockSize);
|
|||
|
|
DataBuffer uData;
|
|||
|
|
size_t readState = 0;
|
|||
|
|
int blockLen = 0;
|
|||
|
|
size_t dlen = 0x10000; // 65535
|
|||
|
|
int magicLen;
|
|||
|
|
int32_t i, nameLen, numNames = 0;
|
|||
|
|
size_t bufsize;
|
|||
|
|
ssize_t bytes;
|
|||
|
|
|
|||
|
|
uData.allocMem(kMaxBlockSize);
|
|||
|
|
|
|||
|
|
readState = fread(fBuf, 1, BLOCK_HEADER_LENGTH, fp);
|
|||
|
|
blockLen = unpackInt16(&fBuf[16]) + 1;
|
|||
|
|
readState = fread(&fBuf[BLOCK_HEADER_LENGTH], 1, blockLen - BLOCK_HEADER_LENGTH, fp);
|
|||
|
|
header = sam_hdr_init();
|
|||
|
|
|
|||
|
|
|
|||
|
|
uint32_t crc = le_to_u32(fBuf + blockLen - 8);
|
|||
|
|
int ret = bgzfUncompress(uData.data, &dlen, (Bytef *)fBuf + 18, blockLen - 18, crc);
|
|||
|
|
uData.curLen = dlen;
|
|||
|
|
// 解析header
|
|||
|
|
magicLen = 4;
|
|||
|
|
if (memcmp(uData.data, "BAM\1", magicLen)) {
|
|||
|
|
spdlog::error("Invalid BAM binary header");
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
uData.readPos += magicLen;
|
|||
|
|
header->l_text = le_to_u32(uData.data + uData.readPos); uData.readPos += 4;
|
|||
|
|
header->text = (char *)malloc(header->l_text + 1);
|
|||
|
|
header->text[header->l_text] = 0;
|
|||
|
|
// while (uData.readPos + header->l_text > uData.curLen) { // header内容超过了一个block,继续读
|
|||
|
|
// readState = fread(fBuf, 1, BLOCK_HEADER_LENGTH, fp); // 读压缩块头
|
|||
|
|
// blockLen = unpackInt16(&fBuf[16]) + 1; // 压缩块大小
|
|||
|
|
// readState = fread(&fBuf[BLOCK_HEADER_LENGTH], 1, blockLen - BLOCK_HEADER_LENGTH, fp); // 读压缩块剩下的部分
|
|||
|
|
// size_t newDataSize = uData.maxLen;
|
|||
|
|
// while (uData.curLen + kMaxBlockSize > uData.maxLen) newDataSize *= 2;
|
|||
|
|
// uData.reAllocMem(newDataSize);
|
|||
|
|
// ret = bgzfUncompress(&uData.data[uData.curLen], &dlen, (Bytef *)fBuf + 18, blockLen - 18, crc);
|
|||
|
|
// uData.curLen += dlen;
|
|||
|
|
// }
|
|||
|
|
memcpy(header->text, &uData.data[uData.readPos], header->l_text);
|
|||
|
|
uData.readPos += header->l_text;
|
|||
|
|
|
|||
|
|
memcpy(&header->n_targets, &uData.data[uData.readPos], 4); // n_targets
|
|||
|
|
uData.readPos += 4;
|
|||
|
|
spdlog::info("num target: {}", header->n_targets);
|
|||
|
|
if (nsgv::gIsBigEndian) ed_swap_4p(&header->n_targets);
|
|||
|
|
if (header->n_targets > 0) {
|
|||
|
|
header->target_name = (char **)calloc(header->n_targets, sizeof(char *));
|
|||
|
|
header->target_len = (uint32_t *)calloc(header->n_targets, sizeof(uint32_t));
|
|||
|
|
} else {
|
|||
|
|
header->target_name = NULL;
|
|||
|
|
header->target_len = NULL;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
for (int i = 0; i != header->n_targets; ++i) {
|
|||
|
|
memcpy(&nameLen, &uData.data[uData.readPos], 4);
|
|||
|
|
uData.readPos += 4;
|
|||
|
|
if (nsgv::gIsBigEndian) ed_swap_4p(&nameLen);
|
|||
|
|
header->target_name[i] = (char *)malloc(nameLen);
|
|||
|
|
++numNames;
|
|||
|
|
memcpy(header->target_name[i], &uData.data[uData.readPos], nameLen);
|
|||
|
|
uData.readPos += nameLen;
|
|||
|
|
if (header->target_name[i][nameLen - 1] != '\0') {
|
|||
|
|
/* Fix missing NUL-termination. Is this being too nice?
|
|||
|
|
We could alternatively bail out with an error. */
|
|||
|
|
char *newName = (char*)realloc(header->target_name[i], nameLen + 1);
|
|||
|
|
header->target_name[i] = newName;
|
|||
|
|
header->target_name[i][nameLen] = '\0';
|
|||
|
|
}
|
|||
|
|
memcpy(&header->target_len[i], &uData.data[uData.readPos], 4);
|
|||
|
|
uData.readPos += 4;
|
|||
|
|
if (nsgv::gIsBigEndian) ed_swap_4p(&header->target_len[i]);
|
|||
|
|
|
|||
|
|
// spdlog::info("nameLen {}, {}, {}", nameLen, header->target_len[i], header->target_name[i]);
|
|||
|
|
}
|
|||
|
|
// spdlog::info("test res: {} {} {} {}", header->l_text, dlen, header->n_targets, header->text);
|
|||
|
|
|
|||
|
|
|
|||
|
|
hdrBuf.header = header;
|
|||
|
|
free(fBuf);
|
|||
|
|
|
|||
|
|
// exit(0);
|
|||
|
|
}
|