xref: /aosp_15_r20/external/puffin/src/puff_reader.cc (revision 07fb1d065b7cfb4729786fadd42a612532d2f466)
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 Hughes inline 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 Hughes bool 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 Hughes size_t BufferPuffReader::BytesLeft() const {
113*07fb1d06SElliott Hughes   return puff_size_ - index_;
114*07fb1d06SElliott Hughes }
115*07fb1d06SElliott Hughes 
116*07fb1d06SElliott Hughes }  // namespace puffin
117