Libosmium  2.15.6
Fast and flexible C++ library for working with OpenStreetMap data
gzip_compression.hpp
Go to the documentation of this file.
1 #ifndef OSMIUM_IO_GZIP_COMPRESSION_HPP
2 #define OSMIUM_IO_GZIP_COMPRESSION_HPP
3 
4 /*
5 
6 This file is part of Osmium (https://osmcode.org/libosmium).
7 
8 Copyright 2013-2020 Jochen Topf <jochen@topf.org> and others (see README).
9 
10 Boost Software License - Version 1.0 - August 17th, 2003
11 
12 Permission is hereby granted, free of charge, to any person or organization
13 obtaining a copy of the software and accompanying documentation covered by
14 this license (the "Software") to use, reproduce, display, distribute,
15 execute, and transmit the Software, and to prepare derivative works of the
16 Software, and to permit third-parties to whom the Software is furnished to
17 do so, all subject to the following:
18 
19 The copyright notices in the Software and this entire statement, including
20 the above license grant, this restriction and the following disclaimer,
21 must be included in all copies of the Software, in whole or in part, and
22 all derivative works of the Software, unless such copies or derivative
23 works are solely in the form of machine-executable object code generated by
24 a source language processor.
25 
26 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
29 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
30 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
31 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
32 DEALINGS IN THE SOFTWARE.
33 
34 */
35 
46 #include <osmium/io/detail/read_write.hpp>
47 #include <osmium/io/error.hpp>
50 
51 #include <zlib.h>
52 
53 #include <cassert>
54 #include <cerrno>
55 #include <cstddef>
56 #include <limits>
57 #include <string>
58 
59 #ifndef _MSC_VER
60 # include <unistd.h>
61 #endif
62 
63 namespace osmium {
64 
69  struct gzip_error : public io_error {
70 
71  int gzip_error_code = 0;
72  int system_errno = 0;
73 
74  explicit gzip_error(const std::string& what) :
75  io_error(what) {
76  }
77 
78  gzip_error(const std::string& what, const int error_code) :
79  io_error(what),
80  gzip_error_code(error_code) {
81  if (error_code == Z_ERRNO) {
82  system_errno = errno;
83  }
84  }
85 
86  }; // struct gzip_error
87 
88  namespace io {
89 
90  namespace detail {
91 
92  [[noreturn]] inline void throw_gzip_error(gzFile gzfile, const char* msg) {
93  std::string error{"gzip error: "};
94  error += msg;
95  error += ": ";
96  int error_code = 0;
97  if (gzfile) {
98  error += ::gzerror(gzfile, &error_code);
99  }
100  throw osmium::gzip_error{error, error_code};
101  }
102 
103  } // namespace detail
104 
105  class GzipCompressor final : public Compressor {
106 
107  int m_fd;
108  gzFile m_gzfile;
109 
110  public:
111 
112  explicit GzipCompressor(const int fd, const fsync sync) :
113  Compressor(sync),
114  m_fd(fd) {
115 #ifdef _MSC_VER
116  osmium::detail::disable_invalid_parameter_handler diph;
117 #endif
118  m_gzfile = ::gzdopen(osmium::io::detail::reliable_dup(fd), "wb");
119  if (!m_gzfile) {
120  throw gzip_error{"gzip error: write initialization failed"};
121  }
122  }
123 
124  GzipCompressor(const GzipCompressor&) = delete;
126 
129 
130  ~GzipCompressor() noexcept {
131  try {
132  close();
133  } catch (...) {
134  // Ignore any exceptions because destructor must not throw.
135  }
136  }
137 
138  void write(const std::string& data) override {
139 #ifdef _MSC_VER
140  osmium::detail::disable_invalid_parameter_handler diph;
141 #endif
142  assert(m_gzfile);
143  assert(data.size() < std::numeric_limits<unsigned int>::max());
144  if (!data.empty()) {
145  const int nwrite = ::gzwrite(m_gzfile, data.data(), static_cast<unsigned int>(data.size()));
146  if (nwrite == 0) {
147  detail::throw_gzip_error(m_gzfile, "write failed");
148  }
149  }
150  }
151 
152  void close() override {
153  if (m_gzfile) {
154 #ifdef _MSC_VER
155  osmium::detail::disable_invalid_parameter_handler diph;
156 #endif
157  const int result = ::gzclose_w(m_gzfile);
158  m_gzfile = nullptr;
159  if (result != Z_OK) {
160  throw gzip_error{"gzip error: write close failed", result};
161  }
162 
163  // Do not sync or close stdout
164  if (m_fd == 1) {
165  return;
166  }
167 
168  if (do_fsync()) {
169  osmium::io::detail::reliable_fsync(m_fd);
170  }
171  osmium::io::detail::reliable_close(m_fd);
172  }
173  }
174 
175  }; // class GzipCompressor
176 
177  class GzipDecompressor final : public Decompressor {
178 
179  gzFile m_gzfile = nullptr;
180 
181  public:
182 
183  explicit GzipDecompressor(const int fd) {
184 #ifdef _MSC_VER
185  osmium::detail::disable_invalid_parameter_handler diph;
186 #endif
187  m_gzfile = ::gzdopen(fd, "rb");
188  if (!m_gzfile) {
189  try {
190  osmium::io::detail::reliable_close(fd);
191  } catch (...) {
192  }
193  throw gzip_error{"gzip error: read initialization failed"};
194  }
195  }
196 
199 
202 
203  ~GzipDecompressor() noexcept {
204  try {
205  close();
206  } catch (...) {
207  // Ignore any exceptions because destructor must not throw.
208  }
209  }
210 
211  std::string read() override {
212 #ifdef _MSC_VER
213  osmium::detail::disable_invalid_parameter_handler diph;
214 #endif
215  assert(m_gzfile);
216  std::string buffer(osmium::io::Decompressor::input_buffer_size, '\0');
217  assert(buffer.size() < std::numeric_limits<unsigned int>::max());
218  int nread = ::gzread(m_gzfile, &*buffer.begin(), static_cast<unsigned int>(buffer.size()));
219  if (nread < 0) {
220  detail::throw_gzip_error(m_gzfile, "read failed");
221  }
222  buffer.resize(static_cast<std::string::size_type>(nread));
223 #if ZLIB_VERNUM >= 0x1240
224  set_offset(static_cast<std::size_t>(::gzoffset(m_gzfile)));
225 #endif
226  return buffer;
227  }
228 
229  void close() override {
230  if (m_gzfile) {
231 #ifdef _MSC_VER
232  osmium::detail::disable_invalid_parameter_handler diph;
233 #endif
234  const int result = ::gzclose_r(m_gzfile);
235  m_gzfile = nullptr;
236  if (result != Z_OK) {
237  throw gzip_error{"gzip error: read close failed", result};
238  }
239  }
240  }
241 
242  }; // class GzipDecompressor
243 
244  class GzipBufferDecompressor final : public Decompressor {
245 
246  const char* m_buffer;
247  std::size_t m_buffer_size;
248  z_stream m_zstream;
249 
250  public:
251 
252  GzipBufferDecompressor(const char* buffer, const std::size_t size) :
253  m_buffer(buffer),
254  m_buffer_size(size),
255  m_zstream() {
256  m_zstream.next_in = reinterpret_cast<unsigned char*>(const_cast<char*>(buffer));
257  assert(size < std::numeric_limits<unsigned int>::max());
258  m_zstream.avail_in = static_cast<unsigned int>(size);
259  const int result = inflateInit2(&m_zstream, MAX_WBITS | 32); // NOLINT(hicpp-signed-bitwise)
260  if (result != Z_OK) {
261  std::string message{"gzip error: decompression init failed: "};
262  if (m_zstream.msg) {
263  message.append(m_zstream.msg);
264  }
265  throw osmium::gzip_error{message, result};
266  }
267  }
268 
271 
274 
276  try {
277  close();
278  } catch (...) {
279  // Ignore any exceptions because destructor must not throw.
280  }
281  }
282 
283  std::string read() override {
284  std::string output;
285 
286  if (m_buffer) {
287  const std::size_t buffer_size = 10240;
288  output.append(buffer_size, '\0');
289  m_zstream.next_out = reinterpret_cast<unsigned char*>(&*output.begin());
290  m_zstream.avail_out = buffer_size;
291  const int result = inflate(&m_zstream, Z_SYNC_FLUSH);
292 
293  if (result != Z_OK) {
294  m_buffer = nullptr;
295  m_buffer_size = 0;
296  }
297 
298  if (result != Z_OK && result != Z_STREAM_END) {
299  std::string message{"gzip error: inflate failed: "};
300  if (m_zstream.msg) {
301  message.append(m_zstream.msg);
302  }
303  throw osmium::gzip_error{message, result};
304  }
305 
306  output.resize(static_cast<std::size_t>(m_zstream.next_out - reinterpret_cast<const unsigned char*>(output.data())));
307  }
308 
309  return output;
310  }
311 
312  void close() override {
313  inflateEnd(&m_zstream);
314  }
315 
316  }; // class GzipBufferDecompressor
317 
318  namespace detail {
319 
320  // we want the register_compression() function to run, setting
321  // the variable is only a side-effect, it will never be used
323  [](const int fd, const fsync sync) { return new osmium::io::GzipCompressor{fd, sync}; },
324  [](const int fd) { return new osmium::io::GzipDecompressor{fd}; },
325  [](const char* buffer, const std::size_t size) { return new osmium::io::GzipBufferDecompressor{buffer, size}; }
326  );
327 
328  // dummy function to silence the unused variable warning from above
329  inline bool get_registered_gzip_compression() noexcept {
330  return registered_gzip_compression;
331  }
332 
333  } // namespace detail
334 
335  } // namespace io
336 
337 } // namespace osmium
338 
339 #endif // OSMIUM_IO_GZIP_COMPRESSION_HPP
osmium::io::GzipBufferDecompressor::GzipBufferDecompressor
GzipBufferDecompressor(const char *buffer, const std::size_t size)
Definition: gzip_compression.hpp:252
osmium::io::GzipBufferDecompressor::close
void close() override
Definition: gzip_compression.hpp:312
osmium::io::GzipDecompressor::~GzipDecompressor
~GzipDecompressor() noexcept
Definition: gzip_compression.hpp:203
osmium::io::GzipCompressor::close
void close() override
Definition: gzip_compression.hpp:152
writer_options.hpp
osmium::io::CompressionFactory::instance
static CompressionFactory & instance()
Definition: compression.hpp:180
osmium::io::GzipBufferDecompressor::GzipBufferDecompressor
GzipBufferDecompressor(GzipBufferDecompressor &&)=delete
compression.hpp
osmium::io::GzipDecompressor::GzipDecompressor
GzipDecompressor(const int fd)
Definition: gzip_compression.hpp:183
osmium::io::GzipBufferDecompressor::~GzipBufferDecompressor
~GzipBufferDecompressor() noexcept
Definition: gzip_compression.hpp:275
osmium::io::GzipCompressor::GzipCompressor
GzipCompressor(const int fd, const fsync sync)
Definition: gzip_compression.hpp:112
osmium::gzip_error
Definition: gzip_compression.hpp:69
osmium::io::GzipCompressor
Definition: gzip_compression.hpp:105
osmium::io::GzipDecompressor::operator=
GzipDecompressor & operator=(GzipDecompressor &&)=delete
osmium::io::GzipDecompressor::m_gzfile
gzFile m_gzfile
Definition: gzip_compression.hpp:179
detail
Definition: attr.hpp:342
osmium::io::GzipDecompressor::operator=
GzipDecompressor & operator=(const GzipDecompressor &)=delete
osmium::io::Compressor
Definition: compression.hpp:57
osmium::io::GzipCompressor::operator=
GzipCompressor & operator=(const GzipCompressor &)=delete
osmium::io::file_compression::gzip
@ gzip
osmium::io::Decompressor
Definition: compression.hpp:87
osmium::io::GzipBufferDecompressor::operator=
GzipBufferDecompressor & operator=(GzipBufferDecompressor &&)=delete
osmium::gzip_error::gzip_error
gzip_error(const std::string &what)
Definition: gzip_compression.hpp:74
osmium::io::GzipDecompressor::GzipDecompressor
GzipDecompressor(const GzipDecompressor &)=delete
osmium::io::GzipCompressor::GzipCompressor
GzipCompressor(GzipCompressor &&)=delete
osmium::io::GzipDecompressor::GzipDecompressor
GzipDecompressor(GzipDecompressor &&)=delete
osmium::io::GzipBufferDecompressor::m_buffer
const char * m_buffer
Definition: gzip_compression.hpp:246
osmium
Namespace for everything in the Osmium library.
Definition: assembler.hpp:53
osmium::io::Decompressor::input_buffer_size
@ input_buffer_size
Definition: compression.hpp:95
osmium::gzip_error::gzip_error_code
int gzip_error_code
Definition: gzip_compression.hpp:71
osmium::io_error
Definition: error.hpp:44
osmium::io::GzipBufferDecompressor::operator=
GzipBufferDecompressor & operator=(const GzipBufferDecompressor &)=delete
osmium::io::GzipCompressor::~GzipCompressor
~GzipCompressor() noexcept
Definition: gzip_compression.hpp:130
osmium::io::GzipDecompressor::read
std::string read() override
Definition: gzip_compression.hpp:211
osmium::io::GzipCompressor::m_fd
int m_fd
Definition: gzip_compression.hpp:107
osmium::io::GzipCompressor::m_gzfile
gzFile m_gzfile
Definition: gzip_compression.hpp:108
osmium::io::GzipBufferDecompressor
Definition: gzip_compression.hpp:244
osmium::io::GzipCompressor::operator=
GzipCompressor & operator=(GzipCompressor &&)=delete
osmium::io::fsync
fsync
Definition: writer_options.hpp:51
osmium::io::GzipCompressor::GzipCompressor
GzipCompressor(const GzipCompressor &)=delete
osmium::gzip_error::system_errno
int system_errno
Definition: gzip_compression.hpp:72
osmium::io::GzipBufferDecompressor::m_zstream
z_stream m_zstream
Definition: gzip_compression.hpp:248
file_compression.hpp
osmium::io::Decompressor::set_offset
void set_offset(const std::size_t offset) noexcept
Definition: compression.hpp:124
osmium::io::CompressionFactory::register_compression
bool register_compression(osmium::io::file_compression compression, const create_compressor_type &create_compressor, const create_decompressor_type_fd &create_decompressor_fd, const create_decompressor_type_buffer &create_decompressor_buffer)
Definition: compression.hpp:185
osmium::io::GzipCompressor::write
void write(const std::string &data) override
Definition: gzip_compression.hpp:138
osmium::io::GzipBufferDecompressor::read
std::string read() override
Definition: gzip_compression.hpp:283
osmium::io::GzipBufferDecompressor::GzipBufferDecompressor
GzipBufferDecompressor(const GzipBufferDecompressor &)=delete
osmium::io::GzipDecompressor
Definition: gzip_compression.hpp:177
osmium::io::GzipDecompressor::close
void close() override
Definition: gzip_compression.hpp:229
osmium::io::Compressor::do_fsync
bool do_fsync() const noexcept
Definition: compression.hpp:63
osmium::gzip_error::gzip_error
gzip_error(const std::string &what, const int error_code)
Definition: gzip_compression.hpp:78
error.hpp
osmium::io::GzipBufferDecompressor::m_buffer_size
std::size_t m_buffer_size
Definition: gzip_compression.hpp:247