1 : // Copyright 2012 Google Inc.
2 : //
3 : // Licensed under the Apache License, Version 2.0 (the "License");
4 : // you may not use this file except in compliance with the License.
5 : // You may obtain a copy of the License at
6 : //
7 : // http://www.apache.org/licenses/LICENSE-2.0
8 : //
9 : // Unless required by applicable law or agreed to in writing, software
10 : // distributed under the License is distributed on an "AS IS" BASIS,
11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 : // See the License for the specific language governing permissions and
13 : // limitations under the License.
14 :
15 : #include "syzygy/core/zstream.h"
16 :
17 : #include "syzygy/core/serialization.h"
18 : #include "third_party/zlib/zlib.h"
19 :
20 : namespace core {
21 :
22 : namespace {
23 :
24 : // The size of the intermediate buffers used by the streams. This has no
25 : // bearing on the compression performance, but rather limits how often we have
26 : // to go in and out of zlib. There is no meaningful way to have the buffers
27 : // grow dynamically so we simply use a page of memory.
28 : static const size_t kZStreamBufferSize = 4096;
29 :
30 : } // namespace
31 :
32 : // Functor that takes care of cleaning up a zstream object that was initialized
33 : // with deflateInit.
34 : struct ZOutStream::z_stream_s_close {
35 E : inline void operator()(z_stream_s* zstream) const {
36 E : if (zstream != NULL) {
37 E : deflateEnd(zstream);
38 E : delete zstream;
39 : }
40 E : }
41 : };
42 :
43 : ZOutStream::ZOutStream(OutStream* out_stream)
44 E : : out_stream_(out_stream), buffer_(kZStreamBufferSize, 0) {
45 E : }
46 :
47 E : ZOutStream::~ZOutStream() { }
48 :
49 E : bool ZOutStream::Init() {
50 E : return Init(Z_DEFAULT_COMPRESSION);
51 E : }
52 :
53 E : bool ZOutStream::Init(int level) {
54 E : DCHECK(level == Z_DEFAULT_COMPRESSION || (level >= 0 && level <= 9));
55 :
56 E : if (zstream_ != NULL)
57 i : return true;
58 :
59 E : scoped_ptr<z_stream_s> zstream(new z_stream_s);
60 E : ::memset(zstream.get(), 0, sizeof(*zstream.get()));
61 :
62 E : int ret = deflateInit(zstream.get(), level);
63 E : if (ret != Z_OK) {
64 i : LOG(ERROR) << "deflateInit returned " << ret << ": " << zstream_->msg
65 : << ".";
66 i : return false;
67 : }
68 :
69 E : zstream->next_out = reinterpret_cast<Bytef*>(&buffer_[0]);
70 E : zstream->avail_out = buffer_.size();
71 :
72 E : zstream_.reset(zstream.release());
73 :
74 E : return true;
75 E : }
76 :
77 E : bool ZOutStream::Write(size_t length, const Byte* bytes) {
78 E : DCHECK(zstream_.get() != NULL);
79 E : DCHECK_EQ(buffer_.size(), kZStreamBufferSize);
80 :
81 E : if (length == 0)
82 i : return true;
83 :
84 E : DCHECK(bytes != NULL);
85 :
86 : // Continue while we have data to process.
87 E : zstream_->avail_in = length;
88 E : zstream_->next_in = reinterpret_cast<Bytef*>(const_cast<Byte*>(bytes));
89 E : while (zstream_->avail_in > 0) {
90 : // We don't do any forced flushing so as to have maximum compression.
91 E : int ret = deflate(zstream_.get(), Z_NO_FLUSH);
92 E : if (ret != Z_OK && ret != Z_BUF_ERROR) {
93 i : LOG(ERROR) << "zlib deflate returned " << ret << ": " << zstream_->msg
94 : << ".";
95 i : return false;
96 : }
97 :
98 : // Spit out any output that was produced.
99 E : if (!FlushBuffer())
100 i : return false;
101 E : }
102 :
103 E : return true;
104 E : }
105 :
106 E : bool ZOutStream::Flush() {
107 E : DCHECK(zstream_.get() != NULL);
108 E : DCHECK_EQ(buffer_.size(), kZStreamBufferSize);
109 :
110 E : while (true) {
111 E : int ret = deflate(zstream_.get(), Z_FINISH);
112 E : if (ret != Z_OK && ret != Z_STREAM_END) {
113 i : LOG(ERROR) << "zlib deflate returned " << ret << ": " << zstream_->msg
114 : << ".";
115 : }
116 :
117 E : if (!FlushBuffer())
118 i : return false;
119 :
120 E : if (ret == Z_STREAM_END)
121 E : break;
122 E : }
123 :
124 E : zstream_.reset();
125 :
126 E : return true;
127 E : }
128 :
129 E : bool ZOutStream::FlushBuffer() {
130 E : DCHECK(zstream_.get() != NULL);
131 E : DCHECK_EQ(buffer_.size(), kZStreamBufferSize);
132 :
133 E : size_t bytes_to_write = buffer_.size() - zstream_->avail_out;
134 E : if (bytes_to_write == 0)
135 E : return true;
136 :
137 E : if (!out_stream_->Write(bytes_to_write, &buffer_[0])) {
138 i : LOG(ERROR) << "Unable to write compressed stream.";
139 i : return false;
140 : }
141 :
142 : // Update the output buffer data.
143 E : zstream_->next_out = reinterpret_cast<Bytef*>(&buffer_[0]);
144 E : zstream_->avail_out = buffer_.size();
145 :
146 E : return true;
147 E : }
148 :
149 : // Functor that takes care of cleaning up a zstream object that was initialized
150 : // with inflateInit.
151 : struct ZInStream::z_stream_s_close {
152 E : inline void operator()(z_stream_s* zstream) const {
153 E : if (zstream != NULL) {
154 E : inflateEnd(zstream);
155 E : delete zstream;
156 : }
157 E : }
158 : };
159 :
160 : ZInStream::ZInStream(InStream* in_stream)
161 E : : in_stream_(in_stream), buffer_(kZStreamBufferSize, 0) {
162 E : DCHECK(in_stream != NULL);
163 E : }
164 :
165 E : ZInStream::~ZInStream() { }
166 :
167 E : bool ZInStream::Init() {
168 E : if (zstream_.get() != NULL)
169 i : return true;
170 :
171 E : scoped_ptr<z_stream_s> zstream(new z_stream_s);
172 E : ::memset(zstream.get(), 0, sizeof(*zstream.get()));
173 :
174 E : int ret = inflateInit(zstream.get());
175 E : if (ret != Z_OK) {
176 i : LOG(ERROR) << "inflateInit returned " << ret << ": " << zstream_->msg
177 : << ".";
178 i : return false;
179 : }
180 :
181 E : zstream_.reset(zstream.release());
182 :
183 E : return true;
184 E : }
185 :
186 E : bool ZInStream::ReadImpl(size_t length, Byte* bytes, size_t* bytes_read) {
187 E : DCHECK(bytes_read != NULL);
188 :
189 E : *bytes_read = 0;
190 E : if (length == 0)
191 i : return true;
192 :
193 E : DCHECK(bytes != NULL);
194 :
195 : // If we're not initialized we're at the end of the stream. This is not an
196 : // error, there's simply no more data to be consumed from this stream.
197 E : if (zstream_.get() == NULL)
198 i : return true;
199 :
200 E : DCHECK_EQ(buffer_.size(), kZStreamBufferSize);
201 :
202 E : zstream_->next_out = reinterpret_cast<Bytef*>(bytes);
203 E : zstream_->avail_out = length;
204 :
205 E : int ret = Z_OK;
206 E : while (true) {
207 : // Try reading from the zstream right away. It's possible for the input
208 : // buffer to be exhausted, but for there to still be data to output.
209 E : ret = inflate(zstream_.get(), Z_NO_FLUSH);
210 E : if (ret != Z_OK && ret != Z_BUF_ERROR && ret != Z_STREAM_END) {
211 i : LOG(ERROR) << "zlib inflate returned " << ret << ": " << zstream_->msg
212 : << ".";
213 i : return false;
214 : }
215 :
216 : // No more data, or no more room to write more data? Then we're done
217 : // for now.
218 E : if (ret == Z_STREAM_END || zstream_->avail_out == 0)
219 E : break;
220 :
221 : // If we get here, then there was room to output more data yet that wasn't
222 : // done. Thus, we must need more input.
223 E : if (zstream_->avail_in != 0) {
224 i : LOG(ERROR) << "zlib won't emit more data, but has input to work with.";
225 i : return false;
226 : }
227 :
228 : // We expect *some* data to be read.
229 E : size_t bytes_read = 0;
230 E : if (!in_stream_->Read(buffer_.size(), &buffer_[0], &bytes_read)) {
231 i : LOG(ERROR) << "Unable to read data from input stream.";
232 i : return false;
233 : }
234 E : if (bytes_read == 0) {
235 E : LOG(ERROR) << "zlib expects more data but input stream is exhausted.";
236 E : return false;
237 : }
238 E : zstream_->next_in = reinterpret_cast<Bytef*>(&buffer_[0]);
239 E : zstream_->avail_in = bytes_read;
240 E : }
241 :
242 E : *bytes_read = length - zstream_->avail_out;
243 :
244 : // Is the zstream exhausted? Then we can clean up this stream to indicate
245 : // end of stream to further calls.
246 E : if (ret == Z_STREAM_END && zstream_->avail_out == 0)
247 E : zstream_.reset();
248 :
249 E : return true;
250 E : }
251 :
252 : } // namespace core
|