• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 Huawei Device Co., Ltd.
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 
25 #include "data_area.h"
26 #include "log.h"
27 #include "proto_reader_help.h"
28 
29 namespace SysTuning {
30 namespace ProtoReader {
31 constexpr uint8_t DATA_AREA_TYPE_BITS = 3;
32 constexpr uint8_t DATA_AREA_TYPE_VALUE = 7;
33 constexpr uint32_t INVALID_DATA_AREA_ID = 0;
34 constexpr uint8_t BYTE_HIGHEST_BIT_MARK = 0x80;
35 const std::map<ProtoWireType, uint32_t> fixedTypeToSizeMap_ = {{ProtoWireType::kFixed32, sizeof(uint32_t)},
36                                                                {ProtoWireType::kFixed64, sizeof(uint64_t)}};
37 template <typename T>
38 class RepeatedDataAreaIterator {
39 public:
40     RepeatedDataAreaIterator() = default;
RepeatedDataAreaIterator(uint32_t dataAreaId,const DataArea * currentAddr,const DataArea * endAddr,const DataArea * lastAddr)41     RepeatedDataAreaIterator(uint32_t dataAreaId,
42                              const DataArea* currentAddr,
43                              const DataArea* endAddr,
44                              const DataArea* lastAddr)
45         : dataAreaId_(dataAreaId), currentAddr_(currentAddr), endAddr_(endAddr), lastAddr_(lastAddr)
46     {
47         FindNextMatchingDataAreaId();
48     }
49 
50     explicit operator bool() const
51     {
52         return currentAddr_ != endAddr_;
53     }
GetDataArea()54     const DataArea& GetDataArea() const
55     {
56         return *currentAddr_;
57     }
58 
59     T operator*() const
60     {
61         T value{};
62         currentAddr_->GetValue(&value);
63         return value;
64     }
65     const DataArea* operator->() const
66     {
67         return currentAddr_;
68     }
69 
70     RepeatedDataAreaIterator& operator++()
71     {
72         if (currentAddr_ != lastAddr_) {
73             currentAddr_++;
74             FindNextMatchingDataAreaId();
75             return *this;
76         }
77         currentAddr_ = endAddr_;
78         return *this;
79     }
80 
81     RepeatedDataAreaIterator operator++(int32_t)
82     {
83         RepeatedDataAreaIterator itor(*this);
84         ++(*this);
85         return itor;
86     }
87 
88 private:
FindNextMatchingDataAreaId()89     void FindNextMatchingDataAreaId()
90     {
91         while (currentAddr_ != endAddr_) {
92             if (currentAddr_->DataAreaId() == dataAreaId_) {
93                 return;
94             }
95             ++currentAddr_;
96         }
97         currentAddr_ = lastAddr_->DataAreaValid() ? lastAddr_ : endAddr_;
98     }
99 
100     uint32_t dataAreaId_ = INVALID_DATA_AREA_ID;
101     const DataArea* currentAddr_ = nullptr;
102     const DataArea* endAddr_ = nullptr;
103     const DataArea* lastAddr_ = nullptr;
104 };
105 
106 template <ProtoWireType wireType, typename cppType>
107 class PackedRepeatedDataAreaIterator {
108 public:
PackedRepeatedDataAreaIterator(const uint8_t * startAddr,size_t length,bool * parseStatus)109     PackedRepeatedDataAreaIterator(const uint8_t* startAddr, size_t length, bool* parseStatus)
110         : endAddr_(startAddr ? startAddr + length : nullptr), currentReadAddr_(startAddr), parseStatus_(parseStatus)
111     {
112         static_assert(wireType != ProtoWireType::kLengthDelimited, "invalid type");
113 
114         if (length == 0) {
115             currentValueValid_ = false;
116             return;
117         }
118         auto itor = fixedTypeToSizeMap_.find(wireType);
119         if (itor != fixedTypeToSizeMap_.end() && (length % itor->second)) {
120             *parseStatus_ = false;
121             currentValueValid_ = false;
122             return;
123         }
124         ++(*this);
125     }
126 
127     const cppType operator*() const
128     {
129         return currentValue_;
130     }
131     explicit operator bool() const
132     {
133         return currentValueValid_;
134     }
135 
136     PackedRepeatedDataAreaIterator& operator++()
137     {
138         if (!currentValueValid_) {
139             return *this;
140         }
141 
142         if (currentReadAddr_ == endAddr_) {
143             currentValueValid_ = false;
144             return *this;
145         }
146 
147         if (wireType == ProtoWireType::kVarInt) {
148             uint64_t newValue = 0;
149             const uint8_t* nextPos = VarIntDecode(currentReadAddr_, endAddr_, &newValue);
150 
151             if (nextPos != currentReadAddr_) {
152                 currentReadAddr_ = nextPos;
153                 currentValue_ = static_cast<cppType>(newValue);
154             } else {
155                 *parseStatus_ = true;
156                 currentValueValid_ = false;
157             }
158         } else { // kFixed32 or kFixed64
159             auto step = fixedTypeToSizeMap_.at(wireType);
160             memcpy_s(&currentValue_, sizeof(cppType), currentReadAddr_, sizeof(cppType));
161             currentReadAddr_ += step;
162         }
163 
164         return *this;
165     }
166 
167     PackedRepeatedDataAreaIterator operator++(int32_t)
168     {
169         PackedRepeatedDataAreaIterator itor(*this);
170         ++(*this);
171         return itor;
172     }
173 
174 private:
175     const uint8_t* const endAddr_;
176     const uint8_t* currentReadAddr_;
177     cppType currentValue_ = 0;
178     bool currentValueValid_ = true;
179     bool* const parseStatus_;
180 };
181 
182 enum ParseProtoStatus { ABORT, SKIP, OK };
183 struct ParseDataAreaResult {
184     ParseProtoStatus status;
185     const uint8_t* next;
186     DataArea dataArea;
187 };
188 
189 class ProtoReaderBase {
190 public:
ProtoReaderBase()191     ProtoReaderBase() : startAddr_(0), endAddr_(0), dataAreas_(nullptr), dataAreasCount_(0), size_(0), volume_(0) {}
192     ProtoReaderBase(DataArea* storage, uint32_t dataAreasCount, const uint8_t* buffer, size_t length);
GetStartAddr()193     const uint8_t* GetStartAddr() const
194     {
195         return startAddr_;
196     }
GetEndAddr()197     const uint8_t* GetEndAddr() const
198     {
199         return endAddr_;
200     }
ResetCurrentAddr()201     void ResetCurrentAddr()
202     {
203         currentReadAddr_ = startAddr_;
204     }
205 
ResetCurrentAddr(const uint8_t * pos)206     void ResetCurrentAddr(const uint8_t* pos)
207     {
208         currentReadAddr_ = pos;
209     }
210 
GetCurrentOffset()211     size_t GetCurrentOffset() const
212     {
213         return static_cast<size_t>(currentReadAddr_ - startAddr_);
214     }
215 
GetCurrentLeft()216     size_t GetCurrentLeft() const
217     {
218         return static_cast<size_t>(endAddr_ - currentReadAddr_);
219     }
220 
221     DataArea ReadNextDataArea();
222     DataArea FindDataArea(uint32_t dataAreaId);
Get(uint32_t id)223     const DataArea& Get(uint32_t id) const
224     {
225         if (id < dataAreasCount_) {
226             return dataAreas_[id];
227         }
228         return dataAreas_[0];
229     }
230 
231     template <typename T>
GetRepeated(uint32_t dataAreaId)232     RepeatedDataAreaIterator<T> GetRepeated(uint32_t dataAreaId) const
233     {
234         return RepeatedDataAreaIterator<T>(dataAreaId, &dataAreas_[dataAreasCount_], &dataAreas_[size_],
235                                            &dataAreas_[dataAreaId]);
236     }
237 
238     template <ProtoWireType wireType, typename cppType>
GetPackedRepeated(uint32_t dataAreaId,bool * parseErrorAddr)239     PackedRepeatedDataAreaIterator<wireType, cppType> GetPackedRepeated(uint32_t dataAreaId, bool* parseErrorAddr) const
240     {
241         const DataArea& dataArea = Get(dataAreaId);
242         if (dataArea.DataAreaValid()) {
243             return PackedRepeatedDataAreaIterator<wireType, cppType>(dataArea.Data(), dataArea.Size(), parseErrorAddr);
244         } else {
245             return PackedRepeatedDataAreaIterator<wireType, cppType>(nullptr, 0, parseErrorAddr);
246         }
247     }
248 
249 protected:
250     ParseDataAreaResult ParseOneDataArea(const uint8_t* const startAddr, const uint8_t* const endAddr);
251     void ParseAllDataAreas();
252     void MoveToLargerHeapStorage();
253 
254     const uint8_t* const startAddr_;
255     const uint8_t* const endAddr_;
256     const uint8_t* currentReadAddr_ = nullptr;
257     std::unique_ptr<DataArea[]> lagerHeapStorage_;
258     DataArea* dataAreas_;
259     uint32_t dataAreasCount_;
260     uint32_t size_;
261     uint32_t volume_;
262 
263 private:
264     const uint8_t* GetNextProtoTag(const uint8_t* const startAddr, const uint8_t* const endAddr, uint64_t* dataAreaTag);
265     bool ParseVarIntValue(ParseDataAreaResult& result, const uint8_t* startAddr, const uint8_t* const endAddr);
266     bool ParseLengthDelimitedValue(ParseDataAreaResult& result, const uint8_t* startAddr, const uint8_t* const endAddr);
267     bool ParseFixed64Value(ParseDataAreaResult& result, const uint8_t* startAddr, const uint8_t* const endAddr);
268     bool ParseFixed32Value(ParseDataAreaResult& result, const uint8_t* startAddr, const uint8_t* const endAddr);
269     using ParseDataAreaValueByType = std::function<bool(ParseDataAreaResult&, const uint8_t*, const uint8_t* const)>;
270     std::map<ProtoWireType, ParseDataAreaValueByType> dataAreaTypeToParseFuncMap_ = {};
271 };
272 
273 template <int32_t MAX_DATA_AREA_ID>
274 class TypedProtoReader : public ProtoReaderBase {
275 public:
TypedProtoReader(const uint8_t * buffer,size_t length)276     TypedProtoReader(const uint8_t* buffer, size_t length)
277         : ProtoReaderBase(defaultStorage_, MAX_DATA_AREA_ID + 1, buffer, length)
278     {
279         ProtoReaderBase::ParseAllDataAreas();
280     }
TypedProtoReader(TypedProtoReader && other)281     TypedProtoReader(TypedProtoReader&& other) noexcept : ProtoReaderBase(std::move(other))
282     {
283         if (dataAreas_ == other.defaultStorage_) {
284             dataAreas_ = defaultStorage_;
285             memcpy_s(defaultStorage_, sizeof(defaultStorage_), other.defaultStorage_, sizeof(defaultStorage_));
286         }
287     }
288     template <uint32_t DATA_AREA_ID>
at()289     const DataArea& at() const
290     {
291         return dataAreas_[DATA_AREA_ID];
292     }
293 
294 private:
295     DataArea defaultStorage_[MAX_DATA_AREA_ID + 1];
296 };
297 } // namespace ProtoReader
298 } // namespace SysTuning
299 #endif // TS_PROTO_READER_H_
300