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