blob: 0a3280de0004b0715e310583281930ef9889845a [file] [log] [blame]
// Copyright (c) 2009 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "update_engine/decompressing_file_writer.h"
namespace chromeos_update_engine {
// typedef struct z_stream_s {
// Bytef *next_in; /* next input byte */
// uInt avail_in; /* number of bytes available at next_in */
// uLong total_in; /* total nb of input bytes read so far */
//
// Bytef *next_out; /* next output byte should be put there */
// uInt avail_out; /* remaining free space at next_out */
// uLong total_out; /* total nb of bytes output so far */
//
// char *msg; /* last error message, NULL if no error */
// struct internal_state FAR *state; /* not visible by applications */
//
// alloc_func zalloc; /* used to allocate the internal state */
// free_func zfree; /* used to free the internal state */
// voidpf opaque; /* private data object passed to zalloc and zfree */
//
// int data_type; /* best guess about the data type: binary or text */
// uLong adler; /* adler32 value of the uncompressed data */
// uLong reserved; /* reserved for future use */
// } z_stream;
ssize_t GzipDecompressingFileWriter::Write(const void* bytes, size_t count) {
// Steps:
// put the data on next_in
// call inflate until it returns nothing, each time writing what we get
// check that next_in has no data left.
// It seems that zlib can keep internal buffers in the stream object,
// so not all data we get fed to us this time will necessarily
// be written out this time (in decompressed form).
if (stream_.avail_in) {
LOG(ERROR) << "Have data already. Bailing";
return -1;
}
char buf[1024];
buffer_.reserve(count);
buffer_.clear();
CHECK_GE(buffer_.capacity(), count);
const char* char_bytes = reinterpret_cast<const char*>(bytes);
buffer_.insert(buffer_.end(), char_bytes, char_bytes + count);
stream_.next_in = reinterpret_cast<Bytef*>(&buffer_[0]);
stream_.avail_in = count;
int retcode = Z_OK;
while (Z_OK == retcode) {
stream_.next_out = reinterpret_cast<Bytef*>(buf);
stream_.avail_out = sizeof(buf);
int retcode = inflate(&stream_, Z_NO_FLUSH);
// check for Z_STREAM_END, Z_OK, or Z_BUF_ERROR (which is non-fatal)
if (Z_STREAM_END != retcode && Z_OK != retcode && Z_BUF_ERROR != retcode) {
LOG(ERROR) << "zlib inflate() error:" << retcode;
if (stream_.msg)
LOG(ERROR) << "message:" << stream_.msg;
return 0;
}
int count_received = sizeof(buf) - stream_.avail_out;
if (count_received > 0) {
next_->Write(buf, count_received);
} else {
// Inflate returned no data; we're done for now. Make sure no
// input data remain.
CHECK_EQ(0, stream_.avail_in);
break;
}
}
return count;
}
} // namespace chromeos_update_engine