rspangler@google.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 1 | // Copyright (c) 2009 The Chromium OS Authors. All rights reserved. |
| 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #include "update_engine/decompressing_file_writer.h" |
| 6 | |
| 7 | namespace chromeos_update_engine { |
| 8 | |
| 9 | // typedef struct z_stream_s { |
| 10 | // Bytef *next_in; /* next input byte */ |
| 11 | // uInt avail_in; /* number of bytes available at next_in */ |
| 12 | // uLong total_in; /* total nb of input bytes read so far */ |
| 13 | // |
| 14 | // Bytef *next_out; /* next output byte should be put there */ |
| 15 | // uInt avail_out; /* remaining free space at next_out */ |
| 16 | // uLong total_out; /* total nb of bytes output so far */ |
| 17 | // |
| 18 | // char *msg; /* last error message, NULL if no error */ |
| 19 | // struct internal_state FAR *state; /* not visible by applications */ |
| 20 | // |
| 21 | // alloc_func zalloc; /* used to allocate the internal state */ |
| 22 | // free_func zfree; /* used to free the internal state */ |
| 23 | // voidpf opaque; /* private data object passed to zalloc and zfree */ |
| 24 | // |
| 25 | // int data_type; /* best guess about the data type: binary or text */ |
| 26 | // uLong adler; /* adler32 value of the uncompressed data */ |
| 27 | // uLong reserved; /* reserved for future use */ |
| 28 | // } z_stream; |
| 29 | |
Andrew de los Reyes | 0cca421 | 2010-04-29 14:00:58 -0700 | [diff] [blame] | 30 | ssize_t GzipDecompressingFileWriter::Write(const void* bytes, size_t count) { |
rspangler@google.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 31 | // Steps: |
| 32 | // put the data on next_in |
| 33 | // call inflate until it returns nothing, each time writing what we get |
| 34 | // check that next_in has no data left. |
| 35 | |
| 36 | // It seems that zlib can keep internal buffers in the stream object, |
| 37 | // so not all data we get fed to us this time will necessarily |
| 38 | // be written out this time (in decompressed form). |
| 39 | |
adlr@google.com | c98a7ed | 2009-12-04 18:54:03 +0000 | [diff] [blame] | 40 | if (stream_.avail_in) { |
| 41 | LOG(ERROR) << "Have data already. Bailing"; |
| 42 | return -1; |
| 43 | } |
rspangler@google.com | 49fdf18 | 2009-10-10 00:57:34 +0000 | [diff] [blame] | 44 | char buf[1024]; |
| 45 | |
| 46 | buffer_.reserve(count); |
| 47 | buffer_.clear(); |
| 48 | CHECK_GE(buffer_.capacity(), count); |
| 49 | const char* char_bytes = reinterpret_cast<const char*>(bytes); |
| 50 | buffer_.insert(buffer_.end(), char_bytes, char_bytes + count); |
| 51 | |
| 52 | stream_.next_in = reinterpret_cast<Bytef*>(&buffer_[0]); |
| 53 | stream_.avail_in = count; |
| 54 | int retcode = Z_OK; |
| 55 | |
| 56 | while (Z_OK == retcode) { |
| 57 | stream_.next_out = reinterpret_cast<Bytef*>(buf); |
| 58 | stream_.avail_out = sizeof(buf); |
| 59 | int retcode = inflate(&stream_, Z_NO_FLUSH); |
| 60 | // check for Z_STREAM_END, Z_OK, or Z_BUF_ERROR (which is non-fatal) |
| 61 | if (Z_STREAM_END != retcode && Z_OK != retcode && Z_BUF_ERROR != retcode) { |
| 62 | LOG(ERROR) << "zlib inflate() error:" << retcode; |
| 63 | if (stream_.msg) |
| 64 | LOG(ERROR) << "message:" << stream_.msg; |
| 65 | return 0; |
| 66 | } |
| 67 | int count_received = sizeof(buf) - stream_.avail_out; |
| 68 | if (count_received > 0) { |
| 69 | next_->Write(buf, count_received); |
| 70 | } else { |
| 71 | // Inflate returned no data; we're done for now. Make sure no |
| 72 | // input data remain. |
| 73 | CHECK_EQ(0, stream_.avail_in); |
| 74 | break; |
| 75 | } |
| 76 | } |
| 77 | return count; |
| 78 | } |
| 79 | |
| 80 | } // namespace chromeos_update_engine |