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