AU: Extent writer utility classes
These are similar to the FileWriter classes, but focus on writing to
extents within a file (or device) rather than writing a file in order.
Again there is a ExtentWriter interface from which all types of extent
writers interit.
There are also two basic extent writers: a direct extent writer that
writes data directly to the file descriptor, and a zero padding extent
writer that piggy-backs on another extent writer. When the
zero-padding extent writer is End()ed, it fills out the rest of the
extent with zeros.
Also, BzipExtentWriter: an ExtentWriter concrete subclass that writes
to another ExtentWriter. BzipExtentWriter bzip2 decompresses all data
passed through.
Review URL: http://codereview.chromium.org/551132
diff --git a/bzip_extent_writer.cc b/bzip_extent_writer.cc
new file mode 100644
index 0000000..cdf0ce3
--- /dev/null
+++ b/bzip_extent_writer.cc
@@ -0,0 +1,73 @@
+// 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/bzip_extent_writer.h"
+
+using std::vector;
+
+namespace chromeos_update_engine {
+
+namespace {
+const vector<char>::size_type kOutputBufferLength = 1024 * 1024;
+}
+
+bool BzipExtentWriter::Init(int fd,
+ const vector<Extent>& extents,
+ uint32 block_size) {
+ // Init bzip2 stream
+ int rc = BZ2_bzDecompressInit(&stream_,
+ 0, // verbosity. (0 == silent)
+ 0 // 0 = faster algo, more memory
+ );
+ TEST_AND_RETURN_FALSE(rc == BZ_OK);
+
+ return next_->Init(fd, extents, block_size);
+}
+
+bool BzipExtentWriter::Write(const void* bytes, size_t count) {
+ vector<char> output_buffer(kOutputBufferLength);
+
+ const char* c_bytes = reinterpret_cast<const char*>(bytes);
+
+ input_buffer_.insert(input_buffer_.end(), c_bytes, c_bytes + count);
+
+ stream_.next_in = &input_buffer_[0];
+ stream_.avail_in = input_buffer_.size();
+
+ for (;;) {
+ stream_.next_out = &output_buffer[0];
+ stream_.avail_out = output_buffer.size();
+
+ int rc = BZ2_bzDecompress(&stream_);
+ TEST_AND_RETURN_FALSE(rc == BZ_OK || rc == BZ_STREAM_END);
+
+ if (stream_.avail_out == output_buffer.size())
+ break; // got no new bytes
+
+ TEST_AND_RETURN_FALSE(
+ next_->Write(&output_buffer[0],
+ output_buffer.size() - stream_.avail_out));
+
+ if (rc == BZ_STREAM_END)
+ CHECK_EQ(stream_.avail_in, 0);
+ if (stream_.avail_in == 0)
+ break; // no more input to process
+ }
+
+ // store unconsumed data in input_buffer_.
+
+ vector<char> new_input_buffer(input_buffer_.end() - stream_.avail_in,
+ input_buffer_.end());
+ new_input_buffer.swap(input_buffer_);
+
+ return true;
+}
+
+bool BzipExtentWriter::EndImpl() {
+ TEST_AND_RETURN_FALSE(input_buffer_.empty());
+ TEST_AND_RETURN_FALSE(BZ2_bzDecompressEnd(&stream_) == BZ_OK);
+ return next_->End();
+}
+
+} // namespace chromeos_update_engine