1// 2// Copyright (C) 2009 The Android Open Source Project 3// 4// Licensed under the Apache License, Version 2.0 (the "License"); 5// you may not use this file except in compliance with the License. 6// You may obtain a copy of the License at 7// 8// http://www.apache.org/licenses/LICENSE-2.0 9// 10// Unless required by applicable law or agreed to in writing, software 11// distributed under the License is distributed on an "AS IS" BASIS, 12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13// See the License for the specific language governing permissions and 14// limitations under the License. 15// 16 17#include "update_engine/payload_consumer/bzip_extent_writer.h" 18 19using std::vector; 20 21namespace chromeos_update_engine { 22 23namespace { 24const brillo::Blob::size_type kOutputBufferLength = 16 * 1024; 25} 26 27bool BzipExtentWriter::Init(FileDescriptorPtr fd, 28 const vector<Extent>& extents, 29 uint32_t block_size) { 30 // Init bzip2 stream 31 int rc = BZ2_bzDecompressInit(&stream_, 32 0, // verbosity. (0 == silent) 33 0); // 0 = faster algo, more memory 34 35 TEST_AND_RETURN_FALSE(rc == BZ_OK); 36 37 return next_->Init(fd, extents, block_size); 38} 39 40bool BzipExtentWriter::Write(const void* bytes, size_t count) { 41 brillo::Blob output_buffer(kOutputBufferLength); 42 43 // Copy the input data into |input_buffer_| only if |input_buffer_| already 44 // contains unconsumed data. Otherwise, process the data directly from the 45 // source. 46 const uint8_t* input = reinterpret_cast<const uint8_t*>(bytes); 47 const uint8_t* input_end = input + count; 48 if (!input_buffer_.empty()) { 49 input_buffer_.insert(input_buffer_.end(), input, input_end); 50 input = input_buffer_.data(); 51 input_end = input + input_buffer_.size(); 52 } 53 stream_.next_in = reinterpret_cast<char*>(const_cast<uint8_t*>(input)); 54 stream_.avail_in = input_end - input; 55 56 for (;;) { 57 stream_.next_out = reinterpret_cast<char*>(output_buffer.data()); 58 stream_.avail_out = output_buffer.size(); 59 60 int rc = BZ2_bzDecompress(&stream_); 61 TEST_AND_RETURN_FALSE(rc == BZ_OK || rc == BZ_STREAM_END); 62 63 if (stream_.avail_out == output_buffer.size()) 64 break; // got no new bytes 65 66 TEST_AND_RETURN_FALSE( 67 next_->Write(output_buffer.data(), 68 output_buffer.size() - stream_.avail_out)); 69 70 if (rc == BZ_STREAM_END) 71 CHECK_EQ(stream_.avail_in, 0u); 72 if (stream_.avail_in == 0) 73 break; // no more input to process 74 } 75 76 // Store unconsumed data (if any) in |input_buffer_|. 77 if (stream_.avail_in || !input_buffer_.empty()) { 78 brillo::Blob new_input_buffer(input_end - stream_.avail_in, input_end); 79 new_input_buffer.swap(input_buffer_); 80 } 81 82 return true; 83} 84 85bool BzipExtentWriter::EndImpl() { 86 TEST_AND_RETURN_FALSE(input_buffer_.empty()); 87 TEST_AND_RETURN_FALSE(BZ2_bzDecompressEnd(&stream_) == BZ_OK); 88 return next_->End(); 89} 90 91} // namespace chromeos_update_engine 92