staticlib_compress  1.2.0
 All Classes Namespaces Files Functions Enumerations
lzma_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: lzma_source.hpp
19  * Author: alex
20  *
21  * Created on January 29, 2016, 9:21 PM
22  */
23 
24 #ifndef STATICLIB_COMPRESS_LZMA_SOURCE_HPP
25 #define STATICLIB_COMPRESS_LZMA_SOURCE_HPP
26 
27 #include <cstdint>
28 #include <cstdlib>
29 #include <cstring>
30 #include <ios>
31 #include <memory>
32 #include <type_traits>
33 
34 #include "lzma.h"
35 
36 #include "staticlib/config.hpp"
37 #include "staticlib/io.hpp"
38 
40 
41 
42 namespace staticlib {
43 namespace compress {
44 
48 template <typename Source, std::size_t buf_size = 4096 >
49 class lzma_source {
53  Source src;
57  std::array<char, buf_size> buf;
61  lzma_stream* strm;
65  size_t pos = 0;
69  size_t avail = 0;
73  bool exhausted = false;
74 
75 public:
76 
82  lzma_source(Source src) :
83  src(std::move(src)),
84  strm([] {
85  lzma_stream* stream = static_cast<lzma_stream*> (std::malloc(sizeof(lzma_stream)));
86  if (nullptr == stream) throw compress_exception(TRACEMSG(
87  "Error creating lzma stream: 'malloc' failed"));
88  *stream = LZMA_STREAM_INIT;
89  auto err = lzma_stream_decoder(stream, UINT64_MAX, 0);
90  if (LZMA_OK != err) throw compress_exception(TRACEMSG(
91  "Error initializing LZMA stream, code: [" + sl::support::to_string(err) + "]"));
92  return stream;
93  }()) { }
94 
95  ~lzma_source() STATICLIB_NOEXCEPT {
96  if (nullptr == strm) return;
97  ::lzma_end(strm);
98  std::free(strm);
99  }
100 
106  lzma_source(const lzma_source&) = delete;
107 
114  lzma_source& operator=(const lzma_source&) = delete;
115 
122  src(std::move(other.src)),
123  buf(std::move(other.buf)),
124  strm(other.strm),
125  pos(other.pos),
126  avail(other.avail),
127  exhausted(other.exhausted) {
128  other.strm = nullptr;
129  }
130 
138  src = std::move(other.src);
139  buf = std::move(other.buf);
140  strm = other.strm;
141  other.strm = nullptr;
142  pos = other.pos;
143  avail = other.avail;
144  exhausted = other.exhausted;
145  return *this;
146  }
147 
154  std::streamsize read(sl::io::span<char> span) {
155  if (!exhausted) {
156  // fill buffer if empty
157  if (0 == avail) {
158  avail = sl::io::read_all(src, {buf.data(), buf.size()});
159  pos = 0;
160  }
161  // prepare zlib stream
162  strm->next_in = reinterpret_cast<uint8_t*> (buf.data() + pos);
163  strm->avail_in = avail;
164  strm->next_out = reinterpret_cast<uint8_t*> (span.data());
165  strm->avail_out = static_cast<size_t> (span.size());
166  // call inflate
167  auto err = ::lzma_code(strm, LZMA_RUN);
168  if (LZMA_OK == err || LZMA_STREAM_END == err) {
169  std::streamsize read = avail - strm->avail_in;
170  std::streamsize written = span.size_signed() - strm->avail_out;
171  size_t uread = static_cast<size_t> (read);
172  pos += uread;
173  avail -= uread;
174  if (written > 0 || LZMA_STREAM_END != err) {
175  return written;
176  }
177  exhausted = true;
178  return std::char_traits<char>::eof();
179  } else throw compress_exception(TRACEMSG(
180  + "LZMA error, code: [" + sl::support::to_string(err) + "]"));
181  } else {
182  return std::char_traits<char>::eof();
183  }
184  }
185 
191  Source& get_source() {
192  return src;
193  }
194 
195 };
196 
204 template <typename Source,
205 class = typename std::enable_if<!std::is_lvalue_reference<Source>::value>::type>
207  return lzma_source<Source>(std::move(source));
208 }
209 
217 template <typename Source>
220  sl::io::make_reference_source(source));
221 }
222 
223 } // namespace
224 }
225 
226 
227 #endif /* STATICLIB_COMPRESS_LZMA_SOURCE_HPP */
228