1 #ifndef OSMIUM_IO_BZIP2_COMPRESSION_HPP
2 #define OSMIUM_IO_BZIP2_COMPRESSION_HPP
46 #include <osmium/io/detail/read_write.hpp>
59 #include <system_error>
79 if (error_code == BZ_IO_ERROR) {
90 [[noreturn]]
inline void throw_bzip2_error(BZFILE* bzfile,
const char* msg,
const int bzlib_error) {
91 std::string error{
"bzip2 error: "};
94 int errnum = bzlib_error;
96 error += std::to_string(bzlib_error);
98 error += ::BZ2_bzerror(bzfile, &errnum);
105 FILE* m_file =
nullptr;
109 file_wrapper() noexcept =
default;
111 file_wrapper(
const int fd,
const char* mode) {
113 osmium::detail::disable_invalid_parameter_handler diph;
115 m_file = fdopen(fd, mode);
118 throw std::system_error{errno, std::system_category(),
"fdopen failed"};
122 file_wrapper(
const file_wrapper&) =
delete;
123 file_wrapper& operator=(
const file_wrapper&) =
delete;
125 file_wrapper(file_wrapper&&) =
delete;
126 file_wrapper& operator=(file_wrapper&&) =
delete;
128 ~file_wrapper() noexcept {
130 osmium::detail::disable_invalid_parameter_handler diph;
137 FILE* file()
const noexcept {
143 osmium::detail::disable_invalid_parameter_handler diph;
146 if (fclose(m_file) != 0) {
148 throw std::system_error{errno, std::system_category(),
"fclose failed"};
169 osmium::detail::disable_invalid_parameter_handler diph;
174 throw bzip2_error{
"bzip2 error: write open failed", bzerror};
192 void write(
const std::string& data)
final {
193 assert(data.size() < std::numeric_limits<int>::max());
196 osmium::detail::disable_invalid_parameter_handler diph;
199 ::BZ2_bzWrite(&bzerror,
m_bzfile,
const_cast<char*
>(data.data()),
static_cast<int>(data.size()));
200 if (bzerror != BZ_OK && bzerror != BZ_STREAM_END) {
201 detail::throw_bzip2_error(
m_bzfile,
"write failed", bzerror);
208 osmium::detail::disable_invalid_parameter_handler diph;
211 ::BZ2_bzWriteClose(&bzerror,
m_bzfile, 0,
nullptr,
nullptr);
214 osmium::io::detail::reliable_fsync(fileno(
m_file.file()));
217 if (bzerror != BZ_OK) {
218 throw bzip2_error{
"bzip2 error: write close failed", bzerror};
236 osmium::detail::disable_invalid_parameter_handler diph;
239 m_bzfile = ::BZ2_bzReadOpen(&bzerror,
m_file.file(), 0, 0,
nullptr, 0);
241 throw bzip2_error{
"bzip2 error: read open failed", bzerror};
261 osmium::detail::disable_invalid_parameter_handler diph;
269 assert(buffer.size() < std::numeric_limits<int>::max());
270 const int nread = ::BZ2_bzRead(&bzerror,
m_bzfile, &*buffer.begin(),
static_cast<int>(buffer.size()));
271 if (bzerror != BZ_OK && bzerror != BZ_STREAM_END) {
272 detail::throw_bzip2_error(
m_bzfile,
"read failed", bzerror);
274 if (bzerror == BZ_STREAM_END) {
277 if (!feof(
m_file.file())) {
278 ::BZ2_bzReadGetUnused(&bzerror,
m_bzfile, &unused, &nunused);
279 if (bzerror != BZ_OK) {
280 detail::throw_bzip2_error(
m_bzfile,
"get unused failed", bzerror);
282 std::string unused_data{
static_cast<const char*
>(unused),
static_cast<std::string::size_type
>(nunused)};
283 ::BZ2_bzReadClose(&bzerror,
m_bzfile);
284 if (bzerror != BZ_OK) {
285 throw bzip2_error{
"bzip2 error: read close failed", bzerror};
287 assert(unused_data.size() < std::numeric_limits<int>::max());
288 m_bzfile = ::BZ2_bzReadOpen(&bzerror,
m_file.file(), 0, 0, &*unused_data.begin(),
static_cast<int>(unused_data.size()));
290 throw bzip2_error{
"bzip2 error: read open failed", bzerror};
296 buffer.resize(
static_cast<std::string::size_type
>(nread));
307 osmium::detail::disable_invalid_parameter_handler diph;
310 ::BZ2_bzReadClose(&bzerror,
m_bzfile);
313 if (bzerror != BZ_OK) {
314 throw bzip2_error{
"bzip2 error: read close failed", bzerror};
333 m_bzstream.next_in =
const_cast<char*
>(buffer);
334 assert(size < std::numeric_limits<unsigned int>::max());
335 m_bzstream.avail_in =
static_cast<unsigned int>(size);
336 const int result = BZ2_bzDecompressInit(&
m_bzstream, 0, 0);
337 if (result != BZ_OK) {
338 throw bzip2_error{
"bzip2 error: decompression init failed: ", result};
360 const std::size_t buffer_size = 10240;
361 output.resize(buffer_size);
364 const int result = BZ2_bzDecompress(&
m_bzstream);
366 if (result != BZ_OK) {
371 if (result != BZ_OK && result != BZ_STREAM_END) {
372 throw bzip2_error{
"bzip2 error: decompress failed: ", result};
375 output.resize(
static_cast<std::size_t
>(
m_bzstream.next_out - output.data()));
398 inline bool get_registered_bzip2_compression() noexcept {
399 return registered_bzip2_compression;
408 #endif // OSMIUM_IO_BZIP2_COMPRESSION_HPP