1 : // Copyright 2012 Google Inc. All Rights Reserved.
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 E : void ZOutStream::z_stream_s_close::operator()(z_stream_s* zstream) const {
33 E : if (zstream != NULL) {
34 E : deflateEnd(zstream);
35 E : delete zstream;
36 : }
37 E : }
38 :
39 : ZOutStream::ZOutStream(OutStream* out_stream)
40 E : : out_stream_(out_stream), buffer_(kZStreamBufferSize, 0) {
41 E : }
42 :
43 E : ZOutStream::~ZOutStream() { }
44 :
45 E : bool ZOutStream::Init() {
46 E : return Init(Z_DEFAULT_COMPRESSION);
47 E : }
48 :
49 E : bool ZOutStream::Init(int level) {
50 E : DCHECK(level == Z_DEFAULT_COMPRESSION || (level >= 0 && level <= 9));
51 :
52 E : if (zstream_ != NULL)
53 i : return true;
54 :
55 E : scoped_ptr<z_stream_s> zstream(new z_stream_s);
56 E : ::memset(zstream.get(), 0, sizeof(*zstream.get()));
57 :
58 E : int ret = deflateInit(zstream.get(), level);
59 E : if (ret != Z_OK) {
60 i : LOG(ERROR) << "deflateInit returned " << ret << ": " << zstream_->msg
61 : << ".";
62 i : return false;
63 : }
64 :
65 E : zstream->next_out = reinterpret_cast<Bytef*>(&buffer_[0]);
66 E : zstream->avail_out = buffer_.size();
67 :
68 E : zstream_.reset(zstream.release());
69 :
70 E : return true;
71 E : }
72 :
73 E : bool ZOutStream::Write(size_t length, const Byte* bytes) {
74 E : DCHECK(zstream_.get() != NULL);
75 E : DCHECK_EQ(buffer_.size(), kZStreamBufferSize);
76 :
77 E : if (length == 0)
78 i : return true;
79 :
80 E : DCHECK(bytes != NULL);
81 :
82 : // Continue while we have data to process.
83 E : zstream_->avail_in = length;
84 E : zstream_->next_in = reinterpret_cast<Bytef*>(const_cast<Byte*>(bytes));
85 E : while (zstream_->avail_in > 0) {
86 : // We don't do any forced flushing so as to have maximum compression.
87 E : int ret = deflate(zstream_.get(), Z_NO_FLUSH);
88 E : if (ret != Z_OK && ret != Z_BUF_ERROR) {
89 i : LOG(ERROR) << "zlib deflate returned " << ret << ": " << zstream_->msg
90 : << ".";
91 i : return false;
92 : }
93 :
94 : // Spit out any output that was produced.
95 E : if (!FlushBuffer())
96 i : return false;
97 E : }
98 :
99 E : return true;
100 E : }
101 :
102 E : bool ZOutStream::Flush() {
103 E : DCHECK(zstream_.get() != NULL);
104 E : DCHECK_EQ(buffer_.size(), kZStreamBufferSize);
105 :
106 E : while (true) {
107 E : int ret = deflate(zstream_.get(), Z_FINISH);
108 E : if (ret != Z_OK && ret != Z_STREAM_END) {
109 i : LOG(ERROR) << "zlib deflate returned " << ret << ": " << zstream_->msg
110 : << ".";
111 : }
112 :
113 E : if (!FlushBuffer())
114 i : return false;
115 :
116 E : if (ret == Z_STREAM_END)
117 E : break;
118 E : }
119 :
120 E : zstream_.reset();
121 :
122 E : return true;
123 E : }
124 :
125 E : bool ZOutStream::FlushBuffer() {
126 E : DCHECK(zstream_.get() != NULL);
127 E : DCHECK_EQ(buffer_.size(), kZStreamBufferSize);
128 :
129 E : size_t bytes_to_write = buffer_.size() - zstream_->avail_out;
130 E : if (bytes_to_write == 0)
131 E : return true;
132 :
133 E : if (!out_stream_->Write(bytes_to_write, &buffer_[0])) {
134 i : LOG(ERROR) << "Unable to write compressed stream.";
135 i : return false;
136 : }
137 :
138 : // Update the output buffer data.
139 E : zstream_->next_out = reinterpret_cast<Bytef*>(&buffer_[0]);
140 E : zstream_->avail_out = buffer_.size();
141 :
142 E : return true;
143 E : }
144 :
145 E : void ZInStream::z_stream_s_close::operator()(z_stream_s* zstream) const {
146 E : if (zstream != NULL) {
147 E : inflateEnd(zstream);
148 E : delete zstream;
149 : }
150 E : }
151 :
152 : ZInStream::ZInStream(InStream* in_stream)
153 E : : in_stream_(in_stream), buffer_(kZStreamBufferSize, 0) {
154 E : DCHECK(in_stream != NULL);
155 E : }
156 :
157 E : ZInStream::~ZInStream() { }
158 :
159 E : bool ZInStream::Init() {
160 E : if (zstream_.get() != NULL)
161 i : return true;
162 :
163 E : scoped_ptr<z_stream_s> zstream(new z_stream_s);
164 E : ::memset(zstream.get(), 0, sizeof(*zstream.get()));
165 :
166 E : int ret = inflateInit(zstream.get());
167 E : if (ret != Z_OK) {
168 i : LOG(ERROR) << "inflateInit returned " << ret << ": " << zstream_->msg
169 : << ".";
170 i : return false;
171 : }
172 :
173 E : zstream_.reset(zstream.release());
174 :
175 E : return true;
176 E : }
177 :
178 E : bool ZInStream::ReadImpl(size_t length, Byte* bytes, size_t* bytes_read) {
179 E : DCHECK(bytes_read != NULL);
180 :
181 E : *bytes_read = 0;
182 E : if (length == 0)
183 i : return true;
184 :
185 E : DCHECK(bytes != NULL);
186 :
187 : // If we're not initialized we're at the end of the stream. This is not an
188 : // error, there's simply no more data to be consumed from this stream.
189 E : if (zstream_.get() == NULL)
190 i : return true;
191 :
192 E : DCHECK_EQ(buffer_.size(), kZStreamBufferSize);
193 :
194 E : zstream_->next_out = reinterpret_cast<Bytef*>(bytes);
195 E : zstream_->avail_out = length;
196 :
197 E : int ret = Z_OK;
198 E : while (true) {
199 : // Try reading from the zstream right away. It's possible for the input
200 : // buffer to be exhausted, but for there to still be data to output.
201 E : ret = inflate(zstream_.get(), Z_NO_FLUSH);
202 E : if (ret != Z_OK && ret != Z_BUF_ERROR && ret != Z_STREAM_END) {
203 i : LOG(ERROR) << "zlib inflate returned " << ret << ": " << zstream_->msg
204 : << ".";
205 i : return false;
206 : }
207 :
208 : // No more data, or no more room to write more data? Then we're done
209 : // for now.
210 E : if (ret == Z_STREAM_END || zstream_->avail_out == 0)
211 E : break;
212 :
213 : // If we get here, then there was room to output more data yet that wasn't
214 : // done. Thus, we must need more input.
215 E : if (zstream_->avail_in != 0) {
216 i : LOG(ERROR) << "zlib won't emit more data, but has input to work with.";
217 i : return false;
218 : }
219 :
220 : // We expect *some* data to be read.
221 E : size_t bytes_read = 0;
222 E : if (!in_stream_->Read(buffer_.size(), &buffer_[0], &bytes_read)) {
223 i : LOG(ERROR) << "Unable to read data from input stream.";
224 i : return false;
225 : }
226 E : if (bytes_read == 0) {
227 E : LOG(ERROR) << "zlib expects more data but input stream is exhausted.";
228 E : return false;
229 : }
230 E : zstream_->next_in = reinterpret_cast<Bytef*>(&buffer_[0]);
231 E : zstream_->avail_in = bytes_read;
232 E : }
233 :
234 E : *bytes_read = length - zstream_->avail_out;
235 :
236 : // Is the zstream exhausted? Then we can clean up this stream to indicate
237 : // end of stream to further calls.
238 E : if (ret == Z_STREAM_END && zstream_->avail_out == 0)
239 E : zstream_.reset();
240 :
241 E : return true;
242 E : }
243 :
244 : } // namespace core
|