1 /*
2  * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef TS_PROTO_READER_H
17 #define TS_PROTO_READER_H
18 
19 #include <functional>
20 #include <limits>
21 #include <memory>
22 #include <stdint.h>
23 #include <string>
24 #include "data_area.h"
25 #include "log.h"
26 #include "proto_reader_help.h"
27 
28 namespace SysTuning {
29 namespace ProtoReader {
30 constexpr uint8_t DATA_AREA_TYPE_BITS = 3;
31 constexpr uint8_t DATA_AREA_TYPE_VALUE = 7;
32 constexpr uint32_t INVALID_DATA_AREA_ID = 0;
33 constexpr uint8_t BYTE_HIGHEST_BIT_MARK = 0x80;
34 const std::map<ProtoWireType, uint32_t> fixedTypeToSizeMap_ = {{ProtoWireType::kFixed32, sizeof(uint32_t)},
35                                                                {ProtoWireType::kFixed64, sizeof(uint64_t)}};
36 template <typename T>
37 class RepeatedDataAreaIterator {
38 public:
39     RepeatedDataAreaIterator() = default;
RepeatedDataAreaIterator(uint32_t dataAreaId, const DataArea *currentAddr, const DataArea *endAddr, const DataArea *lastAddr)40     RepeatedDataAreaIterator(uint32_t dataAreaId,
41                              const DataArea *currentAddr,
42                              const DataArea *endAddr,
43                              const DataArea *lastAddr)
44         : dataAreaId_(dataAreaId), currentAddr_(currentAddr), endAddr_(endAddr), lastAddr_(lastAddr)
45     {
46         FindNextMatchingDataAreaId();
47     }
48 
operator bool() const49     explicit operator bool() const
50     {
51         return currentAddr_ != endAddr_;
52     }
GetDataArea() const53     const DataArea &GetDataArea() const
54     {
55         return *currentAddr_;
56     }
57 
operator *() const58     T operator*() const
59     {
60         T value{};
61         currentAddr_->GetValue(&value);
62         return value;
63     }
operator ->() const64     const DataArea *operator->() const
65     {
66         return currentAddr_;
67     }
68 
operator ++()69     RepeatedDataAreaIterator &operator++()
70     {
71         if (currentAddr_ != lastAddr_) {
72             currentAddr_++;
73             FindNextMatchingDataAreaId();
74             return *this;
75         }
76         currentAddr_ = endAddr_;
77         return *this;
78     }
79 
operator ++(int32_t)80     RepeatedDataAreaIterator operator++(int32_t)
81     {
82         RepeatedDataAreaIterator itor(*this);
83         ++(*this);
84         return itor;
85     }
86 
87 private:
FindNextMatchingDataAreaId()88     void FindNextMatchingDataAreaId()
89     {
90         while (currentAddr_ != endAddr_) {
91             if (currentAddr_->DataAreaId() == dataAreaId_) {
92                 return;
93             }
94             ++currentAddr_;
95         }
96         currentAddr_ = lastAddr_->DataAreaValid() ? lastAddr_ : endAddr_;
97     }
98 
99     uint32_t dataAreaId_ = INVALID_DATA_AREA_ID;
100     const DataArea *currentAddr_ = nullptr;
101     const DataArea *endAddr_ = nullptr;
102     const DataArea *lastAddr_ = nullptr;
103 };
104 
105 template <ProtoWireType wireType, typename cppType>
106 class PackedRepeatedDataAreaIterator {
107 public:
PackedRepeatedDataAreaIterator(const uint8_t *startAddr, size_t length, bool *parseStatus)108     PackedRepeatedDataAreaIterator(const uint8_t *startAddr, size_t length, bool *parseStatus)
109         : endAddr_(startAddr ? startAddr + length : nullptr), currentReadAddr_(startAddr), parseStatus_(parseStatus)
110     {
111         static_assert(wireType != ProtoWireType::kLengthDelimited, "invalid type");
112 
113         if (length == 0) {
114             currentValueValid_ = false;
115             return;
116         }
117         auto itor = fixedTypeToSizeMap_.find(wireType);
118         if (itor != fixedTypeToSizeMap_.end() && (length % itor->second)) {
119             *parseStatus_ = false;
120             currentValueValid_ = false;
121             return;
122         }
123         ++(*this);
124     }
125 
operator *() const126     const cppType operator*() const
127     {
128         return currentValue_;
129     }
operator bool() const130     explicit operator bool() const
131     {
132         return currentValueValid_;
133     }
134 
operator ++()135     PackedRepeatedDataAreaIterator &operator++()
136     {
137         if (!currentValueValid_) {
138             return *this;
139         }
140 
141         if (currentReadAddr_ == endAddr_) {
142             currentValueValid_ = false;
143             return *this;
144         }
145 
146         if (wireType == ProtoWireType::kVarInt) {
147             uint64_t newValue = 0;
148             const uint8_t *nextPos = VarIntDecode(currentReadAddr_, endAddr_, &newValue);
149 
150             if (nextPos != currentReadAddr_) {
151                 currentReadAddr_ = nextPos;
152                 currentValue_ = static_cast<cppType>(newValue);
153             } else {
154                 *parseStatus_ = true;
155                 currentValueValid_ = false;
156             }
157         } else { // kFixed32 or kFixed64
158             auto step = fixedTypeToSizeMap_.at(wireType);
159             (void)memcpy_s(&currentValue_, sizeof(cppType), currentReadAddr_, sizeof(cppType));
160             currentReadAddr_ += step;
161         }
162 
163         return *this;
164     }
165 
operator ++(int32_t)166     PackedRepeatedDataAreaIterator operator++(int32_t)
167     {
168         PackedRepeatedDataAreaIterator itor(*this);
169         ++(*this);
170         return itor;
171     }
172 
173 private:
174     const uint8_t *const endAddr_;
175     const uint8_t *currentReadAddr_;
176     cppType currentValue_ = 0;
177     bool currentValueValid_ = true;
178     bool *const parseStatus_;
179 };
180 
181 enum ParseProtoStatus { ABORT, SKIP, OK };
182 struct ParseDataAreaResult {
183     ParseProtoStatus status;
184     const uint8_t *next;
185     DataArea dataArea;
186 };
187 
188 class ProtoReaderBase {
189 public:
ProtoReaderBase()190     ProtoReaderBase() : startAddr_(0), endAddr_(0), dataAreas_(nullptr), dataAreasCount_(0), size_(0), volume_(0) {}
191     ProtoReaderBase(DataArea *storage, uint32_t dataAreasCount, const uint8_t *buffer, size_t length);
GetStartAddr() const192     const uint8_t *GetStartAddr() const
193     {
194         return startAddr_;
195     }
GetEndAddr() const196     const uint8_t *GetEndAddr() const
197     {
198         return endAddr_;
199     }
ResetCurrentAddr()200     void ResetCurrentAddr()
201     {
202         currentReadAddr_ = startAddr_;
203     }
204 
ResetCurrentAddr(const uint8_t *pos)205     void ResetCurrentAddr(const uint8_t *pos)
206     {
207         currentReadAddr_ = pos;
208     }
209 
GetCurrentOffset() const210     size_t GetCurrentOffset() const
211     {
212         return static_cast<size_t>(currentReadAddr_ - startAddr_);
213     }
214 
GetCurrentLeft() const215     size_t GetCurrentLeft() const
216     {
217         return static_cast<size_t>(endAddr_ - currentReadAddr_);
218     }
219 
220     DataArea ReadNextDataArea();
221     DataArea FindDataArea(uint32_t dataAreaId);
Get(uint32_t id) const222     const DataArea &Get(uint32_t id) const
223     {
224         if (id < dataAreasCount_) {
225             return dataAreas_[id];
226         }
227         return dataAreas_[0];
228     }
229 
230     template <typename T>
GetRepeated(uint32_t dataAreaId) const231     RepeatedDataAreaIterator<T> GetRepeated(uint32_t dataAreaId) const
232     {
233         return RepeatedDataAreaIterator<T>(dataAreaId, &dataAreas_[dataAreasCount_], &dataAreas_[size_],
234                                            &dataAreas_[dataAreaId]);
235     }
236 
237     template <ProtoWireType wireType, typename cppType>
GetPackedRepeated(uint32_t dataAreaId, bool *parseErrorAddr) const238     PackedRepeatedDataAreaIterator<wireType, cppType> GetPackedRepeated(uint32_t dataAreaId, bool *parseErrorAddr) const
239     {
240         const DataArea &dataArea = Get(dataAreaId);
241         if (dataArea.DataAreaValid()) {
242             return PackedRepeatedDataAreaIterator<wireType, cppType>(dataArea.Data(), dataArea.Size(), parseErrorAddr);
243         } else {
244             return PackedRepeatedDataAreaIterator<wireType, cppType>(nullptr, 0, parseErrorAddr);
245         }
246     }
247 
248     using ParseDataAreaValueByType = std::function<bool(ParseDataAreaResult &, const uint8_t *, const uint8_t *const)>;
249     static std::map<ProtoWireType, ParseDataAreaValueByType> DATA_AREA_TYPE_TO_PARSE_FUNC_MAP;
250 
251 protected:
252     ParseDataAreaResult ParseOneDataArea(const uint8_t *const startAddr, const uint8_t *const endAddr);
253     void ParseAllDataAreas();
254     void MoveToLargerHeapStorage();
255 
256     const uint8_t *const startAddr_;
257     const uint8_t *const endAddr_;
258     const uint8_t *currentReadAddr_ = nullptr;
259     std::unique_ptr<DataArea[]> lagerHeapStorage_;
260     DataArea *dataAreas_;
261     uint32_t dataAreasCount_;
262     uint32_t size_;
263     uint32_t volume_;
264 
265 private:
266     const uint8_t *GetNextProtoTag(const uint8_t *const startAddr, const uint8_t *const endAddr, uint64_t *dataAreaTag);
267     static bool ParseVarIntValue(ParseDataAreaResult &result, const uint8_t *startAddr, const uint8_t *const endAddr);
268     static bool ParseLengthDelimitedValue(ParseDataAreaResult &result,
269                                           const uint8_t *startAddr,
270                                           const uint8_t *const endAddr);
271     static bool ParseFixed64Value(ParseDataAreaResult &result, const uint8_t *startAddr, const uint8_t *const endAddr);
272     static bool ParseFixed32Value(ParseDataAreaResult &result, const uint8_t *startAddr, const uint8_t *const endAddr);
273 };
274 
275 template <int32_t MAX_DATA_AREA_ID>
276 class TypedProtoReader : public ProtoReaderBase {
277 public:
TypedProtoReader(const uint8_t *buffer, size_t length)278     TypedProtoReader(const uint8_t *buffer, size_t length)
279         : ProtoReaderBase(defaultStorage_, MAX_DATA_AREA_ID + 1, buffer, length)
280     {
281         ProtoReaderBase::ParseAllDataAreas();
282     }
move(other)283     TypedProtoReader(TypedProtoReader &&other) noexcept : ProtoReaderBase(std::move(other))
284     {
285         if (dataAreas_ == other.defaultStorage_) {
286             dataAreas_ = defaultStorage_;
287             memcpy_s(defaultStorage_, sizeof(defaultStorage_), other.defaultStorage_, sizeof(defaultStorage_));
288         }
289     }
290     template <uint32_t DATA_AREA_ID>
at() const291     const DataArea &at() const
292     {
293         return dataAreas_[DATA_AREA_ID];
294     }
295 
296 private:
297     DataArea defaultStorage_[MAX_DATA_AREA_ID + 1];
298 };
299 } // namespace ProtoReader
300 } // namespace SysTuning
301 #endif // TS_PROTO_READER_H_
302