staticlib_compress  1.2.0
 All Classes Namespaces Files Functions Enumerations
inflate_source.hpp
Go to the documentation of this file.
1 /*
2  * Copyright 2016, alex at staticlibs.net
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /*
18  * File: inflate_source.hpp
19  * Author: alex
20  *
21  * Created on January 29, 2016, 9:19 PM
22  */
23 
24 #ifndef STATICLIB_COMPRESS_INFLATE_SOURCE_HPP
25 #define STATICLIB_COMPRESS_INFLATE_SOURCE_HPP
26 
27 #include <cstdint>
28 #include <cstring>
29 #include <ios>
30 #include <memory>
31 #include <type_traits>
32 
33 #include "zlib.h"
34 
35 #include "staticlib/config.hpp"
36 #include "staticlib/io.hpp"
37 
39 
40 
41 namespace staticlib {
42 namespace compress {
43 
47 template <typename Source, std::size_t buf_size = 4096>
52  Source src;
56  std::array<char, buf_size> buf;
60  z_stream* strm;
64  size_t pos = 0;
68  size_t avail = 0;
72  bool exhausted = false;
73 
74 public:
80  inflate_source(Source src) :
81  src(std::move(src)),
82  strm([]{
83  z_stream* stream = static_cast<z_stream*> (std::malloc(sizeof(z_stream)));
84  if (nullptr == stream) throw compress_exception(TRACEMSG(
85  "Error creating inflate stream: 'malloc' failed"));
86  std::memset(stream, 0, sizeof (z_stream));
87  auto err = inflateInit2(stream, -MAX_WBITS);
88  if (Z_OK != err) throw compress_exception(TRACEMSG(
89  "Error initializing inflate stream: [" + ::zError(err) + "]"));
90  return stream;
91  }()) { }
92 
93  ~inflate_source() STATICLIB_NOEXCEPT {
94  if (nullptr == strm) return;
95  ::inflateEnd(strm);
96  std::free(strm);
97  }
98 
104  inflate_source(const inflate_source&) = delete;
105 
112  inflate_source& operator=(const inflate_source&) = delete;
113 
120  src(std::move(other.src)),
121  buf(std::move(other.buf)),
122  strm(other.strm),
123  pos(other.pos),
124  avail(other.avail),
125  exhausted(other.exhausted) {
126  other.strm = nullptr;
127  }
128 
136  src = std::move(other.src);
137  buf = std::move(other.buf);
138  strm = other.strm;
139  other.strm = nullptr;
140  pos = other.pos;
141  avail = other.avail;
142  exhausted = other.exhausted;
143  return *this;
144  }
145 
152  std::streamsize read(sl::io::span<char> span) {
153  if (!exhausted) {
154  // fill buffer if empty
155  if (0 == avail) {
156  avail = sl::io::read_all(src, {buf.data(), buf.size()});
157  pos = 0;
158  }
159  // prepare zlib stream
160  strm->next_in = reinterpret_cast<unsigned char*> (buf.data() + pos);
161  strm->avail_in = static_cast<uInt> (avail);
162  strm->next_out = reinterpret_cast<unsigned char*> (span.data());
163  strm->avail_out = static_cast<uInt> (span.size());
164  // call inflate
165  auto err = ::inflate(strm, Z_FINISH);
166  if (Z_OK == err || Z_STREAM_END == err || Z_BUF_ERROR == err) {
167  std::streamsize read = avail - strm->avail_in;
168  std::streamsize written = span.size_signed() - strm->avail_out;
169  size_t uread = static_cast<size_t> (read);
170  pos += uread;
171  avail -= uread;
172  if (written > 0 || Z_STREAM_END != err) {
173  return written;
174  }
175  exhausted = true;
176  return std::char_traits<char>::eof();
177  } else throw compress_exception(TRACEMSG(
178  + "Inflate error: [" + ::zError(err) + "]"));
179  } else {
180  return std::char_traits<char>::eof();
181  }
182  }
183 
189  Source& get_source() {
190  return src;
191  }
192 
193 };
194 
202 template <typename Source,
203  class = typename std::enable_if<!std::is_lvalue_reference<Source>::value>::type>
205  return inflate_source<Source>(std::move(source));
206 }
207 
215 template <typename Source>
218  sl::io::make_reference_source(source));
219 }
220 
221 } // namespace
222 }
223 
224 #endif /* STATICLIB_COMPRESS_INFLATE_SOURCE_HPP */