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(¤tValue_, 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