1*07fb1d06SElliott Hughes // Copyright 2017 The ChromiumOS Authors 2*07fb1d06SElliott Hughes // Use of this source code is governed by a BSD-style license that can be 3*07fb1d06SElliott Hughes // found in the LICENSE file. 4*07fb1d06SElliott Hughes 5*07fb1d06SElliott Hughes #include "puffin/src/puff_reader.h" 6*07fb1d06SElliott Hughes 7*07fb1d06SElliott Hughes #include <algorithm> 8*07fb1d06SElliott Hughes #include <memory> 9*07fb1d06SElliott Hughes #include <string> 10*07fb1d06SElliott Hughes #include <vector> 11*07fb1d06SElliott Hughes 12*07fb1d06SElliott Hughes #include "puffin/src/logging.h" 13*07fb1d06SElliott Hughes 14*07fb1d06SElliott Hughes namespace puffin { 15*07fb1d06SElliott Hughes 16*07fb1d06SElliott Hughes namespace { 17*07fb1d06SElliott Hughes // Reads a value from the buffer in big-endian mode. ReadByteArrayToUint16(const uint8_t * buffer)18*07fb1d06SElliott Hughesinline uint16_t ReadByteArrayToUint16(const uint8_t* buffer) { 19*07fb1d06SElliott Hughes return (*buffer << 8) | *(buffer + 1); 20*07fb1d06SElliott Hughes } 21*07fb1d06SElliott Hughes } // namespace 22*07fb1d06SElliott Hughes GetNext(PuffData * data)23*07fb1d06SElliott Hughesbool BufferPuffReader::GetNext(PuffData* data) { 24*07fb1d06SElliott Hughes PuffData& pd = *data; 25*07fb1d06SElliott Hughes size_t length = 0; 26*07fb1d06SElliott Hughes if (state_ == State::kReadingLenDist) { 27*07fb1d06SElliott Hughes // Boundary check 28*07fb1d06SElliott Hughes TEST_AND_RETURN_FALSE(index_ < puff_size_); 29*07fb1d06SElliott Hughes if (puff_buf_in_[index_] & 0x80) { // Reading length/distance. 30*07fb1d06SElliott Hughes if ((puff_buf_in_[index_] & 0x7F) < 127) { 31*07fb1d06SElliott Hughes length = puff_buf_in_[index_] & 0x7F; 32*07fb1d06SElliott Hughes } else { 33*07fb1d06SElliott Hughes index_++; 34*07fb1d06SElliott Hughes // Boundary check 35*07fb1d06SElliott Hughes TEST_AND_RETURN_FALSE(index_ < puff_size_); 36*07fb1d06SElliott Hughes length = puff_buf_in_[index_] + 127; 37*07fb1d06SElliott Hughes } 38*07fb1d06SElliott Hughes length += 3; 39*07fb1d06SElliott Hughes TEST_AND_RETURN_FALSE(length <= 259); 40*07fb1d06SElliott Hughes 41*07fb1d06SElliott Hughes index_++; 42*07fb1d06SElliott Hughes 43*07fb1d06SElliott Hughes // End of block. End of block is similar to length/distance but without 44*07fb1d06SElliott Hughes // distance value and length value set to 259. 45*07fb1d06SElliott Hughes if (length == 259) { 46*07fb1d06SElliott Hughes pd.type = PuffData::Type::kEndOfBlock; 47*07fb1d06SElliott Hughes state_ = State::kReadingBlockMetadata; 48*07fb1d06SElliott Hughes DVLOG(2) << "Read end of block"; 49*07fb1d06SElliott Hughes return true; 50*07fb1d06SElliott Hughes } 51*07fb1d06SElliott Hughes 52*07fb1d06SElliott Hughes // Boundary check 53*07fb1d06SElliott Hughes TEST_AND_RETURN_FALSE(index_ + 1 < puff_size_); 54*07fb1d06SElliott Hughes auto distance = ReadByteArrayToUint16(&puff_buf_in_[index_]); 55*07fb1d06SElliott Hughes // The distance in RFC is in the range [1..32768], but in the puff spec, 56*07fb1d06SElliott Hughes // we write zero-based distance in the puff stream. 57*07fb1d06SElliott Hughes TEST_AND_RETURN_FALSE(distance < (1 << 15)); 58*07fb1d06SElliott Hughes distance++; 59*07fb1d06SElliott Hughes index_ += 2; 60*07fb1d06SElliott Hughes 61*07fb1d06SElliott Hughes pd.type = PuffData::Type::kLenDist; 62*07fb1d06SElliott Hughes pd.length = length; 63*07fb1d06SElliott Hughes pd.distance = distance; 64*07fb1d06SElliott Hughes DVLOG(2) << "Read length: " << length << " distance: " << distance; 65*07fb1d06SElliott Hughes return true; 66*07fb1d06SElliott Hughes } else { // Reading literals. 67*07fb1d06SElliott Hughes // Boundary check 68*07fb1d06SElliott Hughes TEST_AND_RETURN_FALSE(index_ < puff_size_); 69*07fb1d06SElliott Hughes if ((puff_buf_in_[index_] & 0x7F) < 127) { 70*07fb1d06SElliott Hughes length = puff_buf_in_[index_] & 0x7F; 71*07fb1d06SElliott Hughes index_++; 72*07fb1d06SElliott Hughes } else { 73*07fb1d06SElliott Hughes index_++; 74*07fb1d06SElliott Hughes // Boundary check 75*07fb1d06SElliott Hughes TEST_AND_RETURN_FALSE(index_ + 1 < puff_size_); 76*07fb1d06SElliott Hughes length = ReadByteArrayToUint16(&puff_buf_in_[index_]) + 127; 77*07fb1d06SElliott Hughes index_ += 2; 78*07fb1d06SElliott Hughes } 79*07fb1d06SElliott Hughes length++; 80*07fb1d06SElliott Hughes DVLOG(2) << "Read literals length: " << length; 81*07fb1d06SElliott Hughes // Boundary check 82*07fb1d06SElliott Hughes TEST_AND_RETURN_FALSE(index_ + length <= puff_size_); 83*07fb1d06SElliott Hughes pd.type = PuffData::Type::kLiterals; 84*07fb1d06SElliott Hughes pd.length = length; 85*07fb1d06SElliott Hughes pd.read_fn = [this, length](uint8_t* buffer, size_t count) mutable { 86*07fb1d06SElliott Hughes TEST_AND_RETURN_FALSE(count <= length); 87*07fb1d06SElliott Hughes memcpy(buffer, &puff_buf_in_[index_], count); 88*07fb1d06SElliott Hughes index_ += count; 89*07fb1d06SElliott Hughes length -= count; 90*07fb1d06SElliott Hughes return true; 91*07fb1d06SElliott Hughes }; 92*07fb1d06SElliott Hughes return true; 93*07fb1d06SElliott Hughes } 94*07fb1d06SElliott Hughes } else { // Block metadata 95*07fb1d06SElliott Hughes pd.type = PuffData::Type::kBlockMetadata; 96*07fb1d06SElliott Hughes // Boundary check 97*07fb1d06SElliott Hughes TEST_AND_RETURN_FALSE(index_ + 2 < puff_size_); 98*07fb1d06SElliott Hughes length = ReadByteArrayToUint16(&puff_buf_in_[index_]) + 1; 99*07fb1d06SElliott Hughes index_ += 2; 100*07fb1d06SElliott Hughes DVLOG(2) << "Read block metadata length: " << length; 101*07fb1d06SElliott Hughes // Boundary check 102*07fb1d06SElliott Hughes TEST_AND_RETURN_FALSE(index_ + length <= puff_size_); 103*07fb1d06SElliott Hughes TEST_AND_RETURN_FALSE(length <= sizeof(pd.block_metadata)); 104*07fb1d06SElliott Hughes memcpy(pd.block_metadata, &puff_buf_in_[index_], length); 105*07fb1d06SElliott Hughes index_ += length; 106*07fb1d06SElliott Hughes pd.length = length; 107*07fb1d06SElliott Hughes state_ = State::kReadingLenDist; 108*07fb1d06SElliott Hughes } 109*07fb1d06SElliott Hughes return true; 110*07fb1d06SElliott Hughes } 111*07fb1d06SElliott Hughes BytesLeft() const112*07fb1d06SElliott Hughessize_t BufferPuffReader::BytesLeft() const { 113*07fb1d06SElliott Hughes return puff_size_ - index_; 114*07fb1d06SElliott Hughes } 115*07fb1d06SElliott Hughes 116*07fb1d06SElliott Hughes } // namespace puffin 117