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 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 (void)memcpy_s(¤tValue_, 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 using ParseDataAreaValueByType = std::function<bool(ParseDataAreaResult &, const uint8_t *, const uint8_t *const)>; 250 static std::map<ProtoWireType, ParseDataAreaValueByType> DATA_AREA_TYPE_TO_PARSE_FUNC_MAP; 251 252 protected: 253 ParseDataAreaResult ParseOneDataArea(const uint8_t *const startAddr, const uint8_t *const endAddr); 254 void ParseAllDataAreas(); 255 void MoveToLargerHeapStorage(); 256 257 const uint8_t *const startAddr_; 258 const uint8_t *const endAddr_; 259 const uint8_t *currentReadAddr_ = nullptr; 260 std::unique_ptr<DataArea[]> lagerHeapStorage_; 261 DataArea *dataAreas_; 262 uint32_t dataAreasCount_; 263 uint32_t size_; 264 uint32_t volume_; 265 266 private: 267 const uint8_t *GetNextProtoTag(const uint8_t *const startAddr, const uint8_t *const endAddr, uint64_t *dataAreaTag); 268 static bool ParseVarIntValue(ParseDataAreaResult &result, const uint8_t *startAddr, const uint8_t *const endAddr); 269 static bool ParseLengthDelimitedValue(ParseDataAreaResult &result, 270 const uint8_t *startAddr, 271 const uint8_t *const endAddr); 272 static bool ParseFixed64Value(ParseDataAreaResult &result, const uint8_t *startAddr, const uint8_t *const endAddr); 273 static bool ParseFixed32Value(ParseDataAreaResult &result, const uint8_t *startAddr, const uint8_t *const endAddr); 274 }; 275 276 template <int32_t MAX_DATA_AREA_ID> 277 class TypedProtoReader : public ProtoReaderBase { 278 public: TypedProtoReader(const uint8_t * buffer,size_t length)279 TypedProtoReader(const uint8_t *buffer, size_t length) 280 : ProtoReaderBase(defaultStorage_, MAX_DATA_AREA_ID + 1, buffer, length) 281 { 282 ProtoReaderBase::ParseAllDataAreas(); 283 } TypedProtoReader(TypedProtoReader && other)284 TypedProtoReader(TypedProtoReader &&other) noexcept : ProtoReaderBase(std::move(other)) 285 { 286 if (dataAreas_ == other.defaultStorage_) { 287 dataAreas_ = defaultStorage_; 288 memcpy_s(defaultStorage_, sizeof(defaultStorage_), other.defaultStorage_, sizeof(defaultStorage_)); 289 } 290 } 291 template <uint32_t DATA_AREA_ID> at()292 const DataArea &at() const 293 { 294 return dataAreas_[DATA_AREA_ID]; 295 } 296 297 private: 298 DataArea defaultStorage_[MAX_DATA_AREA_ID + 1]; 299 }; 300 } // namespace ProtoReader 301 } // namespace SysTuning 302 #endif // TS_PROTO_READER_H_ 303