24 #error "This file cannot be used when building without GZip-support." 25 #endif // SEQAN3_HAS_ZLIB 52 '\x00',
'\x00',
'\x00',
'\x00',
53 '\x00',
'\xff',
'\x06',
'\x00',
54 '\x42',
'\x43',
'\x02',
'\x00',
55 '\x1b',
'\x00',
'\x03',
'\x00',
56 '\x00',
'\x00',
'\x00',
'\x00',
57 '\x00',
'\x00',
'\x00',
'\x00'}};
59 template <
typename TAlgTag>
60 struct CompressionContext {};
62 template <
typename TAlgTag>
63 struct DefaultPageSize;
66 struct CompressionContext<detail::gz_compression>
77 struct CompressionContext<detail::bgzf_compression>:
78 CompressionContext<detail::gz_compression>
80 static constexpr
size_t BLOCK_HEADER_LENGTH = detail::magic_header<detail::bgzf_compression>.size();
81 unsigned char headerPos;
85 struct DefaultPageSize<detail::bgzf_compression>
87 static const unsigned MAX_BLOCK_SIZE = 64 * 1024;
88 static const unsigned BLOCK_FOOTER_LENGTH = 8;
90 static const unsigned ZLIB_BLOCK_OVERHEAD = 5;
94 enum { BLOCK_HEADER_LENGTH = CompressionContext<detail::bgzf_compression>::BLOCK_HEADER_LENGTH };
95 static const unsigned VALUE = MAX_BLOCK_SIZE - BLOCK_HEADER_LENGTH - BLOCK_FOOTER_LENGTH - ZLIB_BLOCK_OVERHEAD;
107 compressInit(CompressionContext<detail::gz_compression> & ctx)
109 const int GZIP_WINDOW_BITS = -15;
110 const int Z_DEFAULT_MEM_LEVEL = 8;
112 ctx.strm.zalloc = NULL;
113 ctx.strm.zfree = NULL;
119 int status = deflateInit2(&ctx.strm, Z_BEST_SPEED, Z_DEFLATED,
120 GZIP_WINDOW_BITS, Z_DEFAULT_MEM_LEVEL, Z_DEFAULT_STRATEGY);
122 throw io_error(
"Calling deflateInit2() failed for gz file.");
130 compressInit(CompressionContext<detail::bgzf_compression> & ctx)
132 compressInit(
static_cast<CompressionContext<detail::gz_compression> &
>(ctx));
141 _bgzfUnpack16(
char const * buffer)
145 return detail::to_little_endian(tmp);
149 _bgzfUnpack32(
char const * buffer)
153 return detail::to_little_endian(tmp);
161 _bgzfPack16(
char * buffer, uint16_t value)
163 value = detail::to_little_endian(value);
165 reinterpret_cast<char *>(&value) +
sizeof(uint16_t),
170 _bgzfPack32(
char * buffer, uint32_t value)
172 value = detail::to_little_endian(value);
174 reinterpret_cast<char *>(&value) +
sizeof(uint32_t),
182 template <
typename TDestValue,
typename TDestCapacity,
typename TSourceValue,
typename TSourceLength>
184 _compressBlock(TDestValue *dstBegin, TDestCapacity dstCapacity,
185 TSourceValue *srcBegin, TSourceLength srcLength, CompressionContext<detail::bgzf_compression> & ctx)
187 const size_t BLOCK_HEADER_LENGTH = DefaultPageSize<detail::bgzf_compression>::BLOCK_HEADER_LENGTH;
188 const size_t BLOCK_FOOTER_LENGTH = DefaultPageSize<detail::bgzf_compression>::BLOCK_FOOTER_LENGTH;
190 assert(dstCapacity > BLOCK_HEADER_LENGTH + BLOCK_FOOTER_LENGTH);
191 assert(
sizeof(TDestValue) == 1u);
192 assert(
sizeof(
unsigned) == 4u);
199 ctx.strm.next_in = (Bytef *)(srcBegin);
200 ctx.strm.next_out = (Bytef *)(dstBegin + BLOCK_HEADER_LENGTH);
201 ctx.strm.avail_in = srcLength *
sizeof(TSourceValue);
202 ctx.strm.avail_out = dstCapacity - BLOCK_HEADER_LENGTH - BLOCK_FOOTER_LENGTH;
204 int status = deflate(&ctx.strm, Z_FINISH);
205 if (status != Z_STREAM_END)
207 deflateEnd(&ctx.strm);
208 throw io_error(
"Deflation failed. Compressed BGZF data is too big.");
211 status = deflateEnd(&ctx.strm);
213 throw io_error(
"BGZF deflateEnd() failed.");
220 size_t len = dstCapacity - ctx.strm.avail_out;
221 _bgzfPack16(dstBegin + 16, len - 1);
223 dstBegin += len - BLOCK_FOOTER_LENGTH;
224 _bgzfPack32(dstBegin, crc32(crc32(0u, NULL, 0u), (Bytef *)(srcBegin), srcLength *
sizeof(TSourceValue)));
225 _bgzfPack32(dstBegin + 4, srcLength *
sizeof(TSourceValue));
227 return dstCapacity - ctx.strm.avail_out;
235 _bgzfCheckHeader(
char const * header)
237 const char FLG_FEXTRA = detail::magic_header<detail::bgzf_compression>[3];
238 const char BGZF_ID1 = detail::magic_header<detail::bgzf_compression>[12];
239 const char BGZF_ID2 = detail::magic_header<detail::bgzf_compression>[13];
240 const char BGZF_SLEN = detail::magic_header<detail::bgzf_compression>[14];
241 const char BGZF_XLEN = detail::magic_header<detail::bgzf_compression>[10];
243 return (header[0] == static_cast<char>(detail::magic_header<detail::gz_compression>[0]) &&
244 header[1] == static_cast<char>(detail::magic_header<detail::gz_compression>[1]) &&
245 header[2] == static_cast<char>(detail::magic_header<detail::gz_compression>[2]) &&
246 (header[3] & FLG_FEXTRA) != 0 &&
247 _bgzfUnpack16(header + 10) == BGZF_XLEN &&
248 header[12] == BGZF_ID1 &&
249 header[13] == BGZF_ID2 &&
250 _bgzfUnpack16(header + 14) == BGZF_SLEN);
258 decompressInit(CompressionContext<detail::gz_compression> & ctx)
260 const int GZIP_WINDOW_BITS = -15;
262 ctx.strm.zalloc = NULL;
263 ctx.strm.zfree = NULL;
264 int status = inflateInit2(&ctx.strm, GZIP_WINDOW_BITS);
266 throw io_error(
"GZip inflateInit2() failed.");
274 decompressInit(CompressionContext<detail::bgzf_compression> & ctx)
276 decompressInit(
static_cast<CompressionContext<detail::gz_compression> &
>(ctx));
284 template <
typename TDestValue,
typename TDestCapacity,
typename TSourceValue,
typename TSourceLength>
286 _decompressBlock(TDestValue *dstBegin, TDestCapacity dstCapacity,
287 TSourceValue *srcBegin, TSourceLength srcLength, CompressionContext<detail::bgzf_compression> & ctx)
289 const size_t BLOCK_HEADER_LENGTH = DefaultPageSize<detail::bgzf_compression>::BLOCK_HEADER_LENGTH;
290 const size_t BLOCK_FOOTER_LENGTH = DefaultPageSize<detail::bgzf_compression>::BLOCK_FOOTER_LENGTH;
292 assert(
sizeof(TSourceValue) == 1u);
293 assert(
sizeof(
unsigned) == 4u);
297 if (srcLength <= BLOCK_HEADER_LENGTH + BLOCK_FOOTER_LENGTH)
298 throw io_error(
"BGZF block too short.");
300 if (!_bgzfCheckHeader(srcBegin))
301 throw io_error(
"Invalid BGZF block header.");
303 size_t compressedLen = _bgzfUnpack16(srcBegin + 16) + 1u;
304 if (compressedLen != srcLength)
305 throw io_error(
"BGZF compressed size mismatch.");
311 ctx.strm.next_in = (Bytef *)(srcBegin + BLOCK_HEADER_LENGTH);
312 ctx.strm.next_out = (Bytef *)(dstBegin);
313 ctx.strm.avail_in = srcLength - BLOCK_HEADER_LENGTH - BLOCK_FOOTER_LENGTH;
314 ctx.strm.avail_out = dstCapacity *
sizeof(TDestValue);
316 int status = inflate(&ctx.strm, Z_FINISH);
317 if (status != Z_STREAM_END)
319 inflateEnd(&ctx.strm);
320 throw io_error(
"Inflation failed. Decompressed BGZF data is too big.");
323 status = inflateEnd(&ctx.strm);
325 throw io_error(
"BGZF inflateEnd() failed.");
332 unsigned crc = crc32(crc32(0u, NULL, 0u), (Bytef *)(dstBegin), dstCapacity - ctx.strm.avail_out);
334 srcBegin += compressedLen - BLOCK_FOOTER_LENGTH;
335 if (_bgzfUnpack32(srcBegin) != crc)
336 throw io_error(
"BGZF wrong checksum.");
338 if (_bgzfUnpack32(srcBegin + 4) != dstCapacity - ctx.strm.avail_out)
339 throw io_error(
"BGZF size mismatch.");
341 return (dstCapacity - ctx.strm.avail_out) /
sizeof(TDestValue);
Provides exceptions used in the I/O module.
T hardware_concurrency(T... args)
T uninitialized_copy(T... args)
Definition: buffer_queue.hpp:32
::ranges::copy copy
Alias for ranges::copy. Copies a range of elements to a new location.
Definition: algorithm:44
Adaptations of algorithms from the Ranges TS.
Provides utility functions for bit twiddling.
Provides various transformation traits used by the range module.