OTest2
A C++ testing framework
bzip2ostream.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2020 Ondrej Starek
3  *
4  * This file is part of OTest2.
5  *
6  * OTest2 is free software: you can redistribute it and/or modify it under
7  * the terms of the GNU Lesser General Public License as published by
8  * the Free Software Foundation, either version 3 of the License,
9  * or (at your option) any later version.
10  *
11  * OTest2 is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14  * License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with OTest2. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <bzip2ostream.h>
21 
22 #include <assert.h>
23 #include <bzlib.h>
24 #include <cstring>
25 #include <streambuf>
26 
27 #include <utils.h>
28 
29 namespace OTest2 {
30 
31 class Bzip2OStream::Buffer : public std::streambuf {
32  private:
33  std::ostream* decorated;
34 
35  enum { BUFFER_SIZE = 5000 };
36  char buffer[BUFFER_SIZE];
37  bz_stream bzip_stream;
38 
39  public:
40  explicit Buffer(
41  std::ostream* decorated_);
42  virtual ~Buffer();
43 
44  /* -- avoid copying */
45  Buffer(
46  const Buffer&) = delete;
48  const Buffer&) = delete;
49 
50  void finish(
51  bool reuse_);
52 
53  private:
54  virtual int overflow(
55  int c_) override;
56 };
57 
59  std::ostream* decorated_) :
60  decorated(decorated_) {
61  assert(decorated != nullptr);
62 
63  /* -- initialize the Bzip2 stream structure */
64  std::memset(&bzip_stream, 0, sizeof(bzip_stream));
65  auto info_(BZ2_bzCompressInit(&bzip_stream, 1, 0, 0 /* -- default workload */));
66  assert(info_ == BZ_OK);
67 
68  /* -- initialize the streambuffer pointers */
69  setp(buffer, buffer + BUFFER_SIZE);
70 }
71 
73  finish(false);
74 }
75 
77  bool reuse_) {
78  /* -- get size of already written data */
79  unsigned int data_size_(static_cast<unsigned int>(pptr() - buffer));
80  assert(data_size_ <= BUFFER_SIZE);
81  if(data_size_ == 0) /* -- nothing to do */
82  return;
83 
84  /* -- prepare input buffer */
85  bzip_stream.next_in = buffer;
86  bzip_stream.avail_in = data_size_;
87 
88  /* -- repeatedly compress remaining data until all is done */
89  int info_;
90  char obuffer_[BUFFER_SIZE];
91  do {
92  /* -- compress data */
93  bzip_stream.next_out = obuffer_;
94  bzip_stream.avail_out = BUFFER_SIZE;
95  info_ = BZ2_bzCompress(&bzip_stream, BZ_FINISH);
96  assert(info_ == BZ_FINISH_OK || info_ == BZ_STREAM_END);
97 
98  /* -- push the compressed data into the decorated stream */
99  decorated->write(obuffer_, BUFFER_SIZE - bzip_stream.avail_out);
100  }
101  while(info_ != BZ_STREAM_END);
102 
103  /* -- clean up the old bzip context and create new one */
104  info_ = BZ2_bzCompressEnd(&bzip_stream);
105  assert(info_ == BZ_OK);
106  if(reuse_) {
107  info_ = BZ2_bzCompressInit(&bzip_stream, 1, 0, 0 /* -- default workLoad */);
108  assert(info_ == BZ_OK);
109  }
110 
111  /* -- reset the stream buffer pointers */
112  setp(buffer, buffer + BUFFER_SIZE);
113 }
114 
115 int Bzip2OStream::Buffer::overflow(
116  int c_) {
117  assert(pptr() - buffer == BUFFER_SIZE);
118 
119  /* -- compress data */
120  char obuffer_[BUFFER_SIZE];
121  bzip_stream.next_in = buffer;
122  bzip_stream.avail_in = BUFFER_SIZE;
123  bzip_stream.next_out = obuffer_;
124  bzip_stream.avail_out = BUFFER_SIZE;
125  auto info_(BZ2_bzCompress(&bzip_stream, BZ_RUN));
126  assert(info_ == BZ_RUN_OK);
127  assert(bzip_stream.avail_in < BUFFER_SIZE); /* -- at least 1 B in the buffer */
128 
129  /* -- push compressed data into the decorated stream */
130  decorated->write(obuffer_, BUFFER_SIZE - bzip_stream.avail_out);
131 
132  /* -- move remaining input data at the beginning of the buffer */
133  std::memmove(buffer, bzip_stream.next_in, bzip_stream.avail_in);
134 
135  /* -- reset the stream buffer pointers */
136  setp(buffer, buffer + BUFFER_SIZE);
137  pbump(bzip_stream.avail_in);
138 
139  /* -- write next character */
140  if(c_ != traits_type::eof()) {
141  *pptr() = traits_type::to_char_type(c_);
142  pbump(1);
143  }
144 
145  return traits_type::not_eof(c_);
146 }
147 
149  std::ostream* decorated_) :
150  buffer(new Buffer(decorated_)) {
151  rdbuf(buffer);
152 }
153 
155  odelete(buffer);
156 }
157 
159  buffer->finish(true);
160 }
161 
162 } /* -- namespace OTest2 */
OTest2::Bzip2OStream::Bzip2OStream
Bzip2OStream(std::ostream *decorated_)
Ctor.
Definition: bzip2ostream.cpp:148
OTest2::Bzip2OStream::Buffer
Definition: bzip2ostream.cpp:31
OTest2::Bzip2OStream::Buffer::operator=
Buffer & operator=(const Buffer &)=delete
utils.h
OTest2::Bzip2OStream::finish
void finish()
Finish the compressed stream.
Definition: bzip2ostream.cpp:158
OTest2
Definition: assertbean.h:25
OTest2::Bzip2OStream::Buffer::Buffer
Buffer(std::ostream *decorated_)
Definition: bzip2ostream.cpp:58
OTest2::Bzip2OStream::Buffer::~Buffer
virtual ~Buffer()
Definition: bzip2ostream.cpp:72
OTest2::Bzip2OStream::~Bzip2OStream
virtual ~Bzip2OStream()
Dtor.
Definition: bzip2ostream.cpp:154
bzip2ostream.h
OTest2::odelete
void odelete(T_ *&object_)
Delete a pointer and set it invalid.
Definition: utils.h:34
OTest2::Bzip2OStream::Buffer::finish
void finish(bool reuse_)
Definition: bzip2ostream.cpp:76