#include "sam_io.h" #include #include #include #include #include #include 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(); spdlog::info("Header file size: {}", blockLen); 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); }