20 #ifdef SEQAN3_HAS_BZIP2
21 #include <seqan3/contrib/stream/bz2_istream.hpp>
23 #ifdef SEQAN3_HAS_ZLIB
24 #include <seqan3/contrib/stream/bgzf_istream.hpp>
26 #include <seqan3/contrib/stream/gz_istream.hpp>
35 namespace seqan3::detail
42 template <std::ranges::forward_range ref_t, std::ranges::forward_range query_t>
43 inline bool starts_with(ref_t && reference, query_t && query)
45 requires std::equality_comparable_with<std::ranges::range_reference_t<ref_t>,
46 std::ranges::range_reference_t<query_t>>
50 auto rend = std::ranges::end(reference);
53 auto qend = std::ranges::end(query);
77 template <builtin_
character
char_t>
81 assert(primary_stream.good());
90 std::array<char, bgzf_compression::magic_header.
size()> magic_number{};
91 size_t read_chars = 0;
92 for (; read_chars < magic_number.size(); ++read_chars)
97 magic_number[read_chars] = *it;
102 for (
size_t i = 0 ; i < read_chars; ++i)
103 primary_stream.unget();
106 if (filename.has_extension())
107 extension = filename.extension().
string().substr(1);
110 [[maybe_unused]]
auto contains_extension = [] (
auto compression_tag,
auto const & extension) constexpr
112 return std::ranges::find(decltype(compression_tag)::file_extensions, extension) !=
113 std::ranges::end(decltype(compression_tag)::file_extensions);
117 if (read_chars == magic_number.size() && bgzf_compression::validate_header(
std::span{magic_number}))
119 #ifdef SEQAN3_HAS_ZLIB
120 if (contains_extension(gz_compression{}, extension) || contains_extension(bgzf_compression{}, extension))
121 filename.replace_extension();
123 return {
new contrib::basic_bgzf_istream<char_t>{primary_stream},
124 stream_deleter_default};
126 throw file_open_error{
"Trying to read from a bgzf file, but no ZLIB available."};
129 else if (starts_with(magic_number, gz_compression::magic_header))
131 #ifdef SEQAN3_HAS_ZLIB
132 if (contains_extension(gz_compression{}, extension) || contains_extension(bgzf_compression{}, extension))
133 filename.replace_extension();
135 return {
new contrib::basic_gz_istream<char_t>{primary_stream}, stream_deleter_default};
137 throw file_open_error{
"Trying to read from a gzipped file, but no ZLIB available."};
140 else if (starts_with(magic_number, bz2_compression::magic_header))
142 #ifdef SEQAN3_HAS_BZIP2
143 if (contains_extension(bz2_compression{}, extension))
144 filename.replace_extension();
146 return {
new contrib::basic_bz2_istream<char_t>{primary_stream}, stream_deleter_default};
148 throw file_open_error{
"Trying to read from a bzipped file, but no libbz2 available."};
151 else if (starts_with(magic_number, zstd_compression::magic_header))
153 throw file_open_error{
"Trying to read from a zst'ed file, but SeqAn does not yet support this."};
156 return {&primary_stream, stream_deleter_noop};
160 template <builtin_
character
char_t>
164 return make_secondary_istream(primary_stream, p);