/* * Copyright (c) 2021 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef DATA_DECODER_H #define DATA_DECODER_H #include <string> #include "securec.h" #include "protocol/retcode_inner/aie_retcode_inner.h" #include "protocol/struct_definition/aie_info_define.h" #include "utils/log/aie_log.h" namespace OHOS { namespace AI { class DataDecoder { public: explicit DataDecoder(const DataInfo dataInfo) : buffer_(dataInfo.data), size_(dataInfo.length), pos_(0) { } ~DataDecoder() = default; /** * Delete copy constructor/assignment to avoid misuse. */ DataDecoder(const DataDecoder &other) = delete; DataDecoder& operator=(const DataDecoder &other) = delete; /** * Decode all arguments in the DataInfo. * * Please note, * 1. the arguments' order in decoder and encoder process should match strictly. * 2. if decoding a pointer, the caller should allocate the memory first and handle the release. * * @param [out] arg argument need to be unserialized. Receive any number of arguments. * @return Return 0 if decode successfully, returns a non-zero value otherwise. */ template<typename Type, typename... Types> int RecursiveDecode(Type &arg, Types &...args) { int retCode = DecodeOneParameter<Type>(arg); if (retCode != RETCODE_SUCCESS) { return retCode; } return RecursiveDecode(args...); } /** * Check whether the decode data size matches the original data when decoding ends. * It should be called after all data have been decoded. * * @return Returns true if decode data size matches, return false if decode data length fails to match. */ bool CheckDataEnd() { size_t dataSize = 0; if (DecodeOneParameter(dataSize) != RETCODE_SUCCESS) { return false; } if ((pos_ != size_) || (pos_ != dataSize + sizeof(dataSize))) { HILOGE("[Encdec]Decoded length[%zu], encoded length[%zu], whole length[%zu] don't match.", pos_, dataSize, size_); HILOGE("[Encdec]Possible reason: the caller doesn't include the specialized "\ "EncodeOneParameter/DecoderOneParameter function."); return false; } return true; } private: /** * Decode the data buffer based on the data type that was transferred in. * instantiate it for your own data type if needed. * * @param [out] val It provides a data type, the function will decode by it. * @return Returns 0 if decode successful, otherwise it failed. */ template<typename T> int DecodeOneParameter(T &val) { // sizeof(T) is 0 when on gcc when T is defined as 0 length array. // but it may not apply to other compilers. // try a better type definition to avoid ambiguity. if (sizeof(T) == 0) { HILOGE("[Encdec]sizeof(T) is 0."); return RETCODE_FAILURE; } if (!Ensure(sizeof(T))) { HILOGE("[Encdec]Memory read out of boundary"); return RETCODE_FAILURE; } // assign value without memory alignment cause crash // so use memcpy_s to make sure success. if (memcpy_s(&val, sizeof(val), buffer_ + pos_, sizeof(val)) != EOK) { HILOGE("[Encdec]memcpy_s failed"); return RETCODE_FAILURE; } pos_ += sizeof(T); return RETCODE_SUCCESS; } /** * To make sure that passed in data type will not exceed the original data buffer * * @return Return 1 if the size of data buffer is enough for decoding, otherwise it returns 0. */ inline bool Ensure(const size_t size) const { return (size <= size_ && (pos_ + size) <= size_); } /** * it offers a terminal call for RecursiveEncode. * * @return Returns 0. */ int RecursiveDecode() { return RETCODE_SUCCESS; } private: unsigned char *buffer_ {nullptr}; size_t size_ {0}; size_t pos_ {0}; }; /** * Encode std::string. It's a instantiation of template function (@link DataEncoder::EncodeOneParameter). * * @param [out] val The data that needs to be encoded. * @return Returns 0 if the data has been written into the buffer successfully, otherwise, it will return -1. */ template<> int DataDecoder::DecodeOneParameter(std::string &val); } // namespace AI } // namespace OHOS #endif // DATA_DECODER_H