scc  2022.4.0
SystemC components library
lz4_streambuf.cpp
1 /*******************************************************************************
2  * Copyright 2022 MINRES Technologies GmbH
3  * SPDX-License-Identifier: Apache-2.0
4  ******************************************************************************/
5 
6 #include "lz4_streambuf.h"
7 #include <stdexcept>
8 
9 namespace util {
10 
11 lz4c_steambuf::lz4c_steambuf(std::ostream& sink, size_t buf_size)
12 : sink(sink)
13 , src_buf(buf_size)
14 , dest_buf(LZ4F_compressBound(buf_size, nullptr)) {
15  auto errCode = LZ4F_createCompressionContext(&ctx, LZ4F_VERSION);
16  if(LZ4F_isError(errCode) != 0)
17  throw std::runtime_error(std::string("Failed to create LZ4 context: ") + LZ4F_getErrorName(errCode));
18  size_t sz = LZ4F_compressBegin(ctx, dest_buf.data(), dest_buf.capacity(), nullptr);
19  if(LZ4F_isError(sz) != 0)
20  throw std::runtime_error(std::string("Failed to start LZ4 compression: ") + LZ4F_getErrorName(sz));
21  setp(src_buf.data(), src_buf.data() + src_buf.size() - 1);
22  sink.write(dest_buf.data(), sz);
23 }
24 
25 lz4c_steambuf::~lz4c_steambuf() { close(); }
26 
27 void lz4c_steambuf::close() {
28  if(closed)
29  return;
30  lz4c_steambuf::sync();
31  auto sz = LZ4F_compressEnd(ctx, dest_buf.data(), dest_buf.capacity(), nullptr);
32  if(LZ4F_isError(sz) != 0)
33  throw std::runtime_error(std::string("Failed to finish LZ4 compression: ") + LZ4F_getErrorName(sz));
34  if(sz) {
35  sink.write(dest_buf.data(), sz);
36  sink.flush();
37  }
38  LZ4F_freeCompressionContext(ctx);
39  closed = true;
40 }
41 
42 std::streambuf::int_type lz4c_steambuf::sync() {
43  compress_and_write();
44  sink.flush();
45  return 0;
46 }
47 
48 std::streambuf::int_type lz4c_steambuf::overflow(int_type ch) {
49  compress_and_write();
50  *pptr() = static_cast<char_type>(ch);
51  pbump(1);
52  return ch;
53 }
54 
55 void lz4c_steambuf::compress_and_write() {
56  if(closed)
57  throw std::runtime_error("Cannot write to closed stream");
58  if(auto orig_size = pptr() - pbase()) {
59  auto ret = LZ4F_compressUpdate(ctx, dest_buf.data(), dest_buf.capacity(), pbase(), orig_size, nullptr);
60  if(LZ4F_isError(ret) != 0)
61  throw std::runtime_error(std::string("LZ4 compression failed: ") + LZ4F_getErrorName(ret));
62  if(ret)
63  sink.write(dest_buf.data(), ret);
64  pbump(-orig_size);
65  }
66 }
67 
68 lz4d_streambuf::lz4d_streambuf(std::istream& source, size_t buf_size)
69 : src_str(source)
70 , src_buf(buf_size)
71 , dest_buf(4 * buf_size) {
72  auto ret = LZ4F_createDecompressionContext(&ctx, LZ4F_VERSION);
73  if(LZ4F_isError(ret) != 0)
74  throw std::runtime_error(std::string("Failed to create LZ4 context: ") + LZ4F_getErrorName(ret));
75  setg(src_buf.data(), src_buf.data(), src_buf.data());
76 }
77 
78 lz4d_streambuf::~lz4d_streambuf() { LZ4F_freeDecompressionContext(ctx); }
79 
80 std::streambuf::int_type lz4d_streambuf::underflow() {
81  auto written_size = 0UL;
82  do {
83  if(offset == src_buf_size) {
84  src_str.read(src_buf.data(), src_buf.size());
85  src_buf_size = static_cast<size_t>(src_str.gcount());
86  offset = 0;
87  }
88  if(src_buf_size == 0)
89  return traits_type::eof();
90  auto src_size = src_buf_size - offset;
91  auto dest_size = dest_buf.size();
92  auto ret = LZ4F_decompress(ctx, dest_buf.data(), &dest_size, src_buf.data() + offset, &src_size, nullptr);
93  if(LZ4F_isError(ret) != 0)
94  throw std::runtime_error(std::string("LZ4 decompression failed: ") + LZ4F_getErrorName(ret));
95  written_size = dest_size;
96  offset += src_size;
97  } while(written_size == 0);
98  setg(dest_buf.data(), dest_buf.data(), dest_buf.data() + written_size);
99  return traits_type::to_int_type(*gptr());
100 }
101 
102 } // namespace util
SCC common utilities.
Definition: bit_field.h:30