blob: 0a3280de0004b0715e310583281930ef9889845a [file] [log] [blame]
rspangler@google.com49fdf182009-10-10 00:57:34 +00001// 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
7namespace 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 Reyes0cca4212010-04-29 14:00:58 -070030ssize_t GzipDecompressingFileWriter::Write(const void* bytes, size_t count) {
rspangler@google.com49fdf182009-10-10 00:57:34 +000031 // 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.comc98a7ed2009-12-04 18:54:03 +000040 if (stream_.avail_in) {
41 LOG(ERROR) << "Have data already. Bailing";
42 return -1;
43 }
rspangler@google.com49fdf182009-10-10 00:57:34 +000044 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