scc 2025.09
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
9namespace util {
10
11lz4c_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
25lz4c_steambuf::~lz4c_steambuf() { close(); }
26
27void 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
42std::streambuf::int_type lz4c_steambuf::sync() {
43 compress_and_write();
44 sink.flush();
45 return 0;
46}
47
48std::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
55void 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
68lz4d_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
78lz4d_streambuf::~lz4d_streambuf() { LZ4F_freeDecompressionContext(ctx); }
79
80std::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