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 DATA_DECODER_H
17 #define DATA_DECODER_H
18 
19 #include <string>
20 
21 #include "securec.h"
22 
23 #include "protocol/retcode_inner/aie_retcode_inner.h"
24 #include "protocol/struct_definition/aie_info_define.h"
25 #include "utils/log/aie_log.h"
26 
27 namespace OHOS {
28 namespace AI {
29 class DataDecoder {
30 public:
DataDecoder(const DataInfo dataInfo)31     explicit DataDecoder(const DataInfo dataInfo) : buffer_(dataInfo.data), size_(dataInfo.length), pos_(0)
32     {
33     }
34 
35     ~DataDecoder() = default;
36 
37     /**
38      * Delete copy constructor/assignment to avoid misuse.
39      */
40     DataDecoder(const DataDecoder &other) = delete;
41     DataDecoder& operator=(const DataDecoder &other) = delete;
42 
43     /**
44      * Decode all arguments in the DataInfo.
45      *
46      * Please note,
47      * 1. the arguments' order in decoder and encoder process should match strictly.
48      * 2. if decoding a pointer, the caller should allocate the memory first and handle the release.
49      *
50      * @param [out] arg argument need to be unserialized. Receive any number of arguments.
51      * @return Return 0 if decode successfully, returns a non-zero value otherwise.
52      */
53     template<typename Type, typename... Types>
RecursiveDecode(Type & arg,Types &...args)54     int RecursiveDecode(Type &arg, Types &...args)
55     {
56         int retCode = DecodeOneParameter<Type>(arg);
57         if (retCode != RETCODE_SUCCESS) {
58             return retCode;
59         }
60         return RecursiveDecode(args...);
61     }
62 
63     /**
64      * Check whether the decode data size matches the original data when decoding ends.
65      * It should be called after all data have been decoded.
66      *
67      * @return Returns true if decode data size matches, return false if decode data length fails to match.
68      */
CheckDataEnd()69     bool CheckDataEnd()
70     {
71         size_t dataSize = 0;
72         if (DecodeOneParameter(dataSize) != RETCODE_SUCCESS) {
73             return false;
74         }
75         if ((pos_ != size_) || (pos_ != dataSize + sizeof(dataSize))) {
76             HILOGE("[Encdec]Decoded length[%zu], encoded length[%zu], whole length[%zu] don't match.",
77                 pos_, dataSize, size_);
78             HILOGE("[Encdec]Possible reason: the caller doesn't include the specialized "\
79                 "EncodeOneParameter/DecoderOneParameter function.");
80             return false;
81         }
82         return true;
83     }
84 
85 private:
86     /**
87      * Decode the data buffer based on the data type that was transferred in.
88      * instantiate it for your own data type if needed.
89      *
90      * @param [out] val It provides a data type, the function will decode by it.
91      * @return Returns 0 if decode successful, otherwise it failed.
92      */
93     template<typename T>
DecodeOneParameter(T & val)94     int DecodeOneParameter(T &val)
95     {
96         // sizeof(T) is 0 when on gcc when T is defined as 0 length array.
97         // but it may not apply to other compilers.
98         // try a better type definition to avoid ambiguity.
99         if (sizeof(T) == 0) {
100             HILOGE("[Encdec]sizeof(T) is 0.");
101             return RETCODE_FAILURE;
102         }
103         if (!Ensure(sizeof(T))) {
104             HILOGE("[Encdec]Memory read out of boundary");
105             return RETCODE_FAILURE;
106         }
107 
108         // assign value without memory alignment cause crash
109         // so use memcpy_s to make sure success.
110         if (memcpy_s(&val, sizeof(val), buffer_ + pos_, sizeof(val)) != EOK) {
111             HILOGE("[Encdec]memcpy_s failed");
112             return RETCODE_FAILURE;
113         }
114         pos_ += sizeof(T);
115         return RETCODE_SUCCESS;
116     }
117 
118     /**
119      * To make sure that passed in data type will not exceed the original data buffer
120      *
121      * @return Return 1 if the size of data buffer is enough for decoding, otherwise it returns 0.
122      */
Ensure(const size_t size)123     inline bool Ensure(const size_t size) const
124     {
125         return (size <= size_ && (pos_ + size) <= size_);
126     }
127 
128     /**
129      * it offers a terminal call for RecursiveEncode.
130      *
131      * @return Returns 0.
132      */
RecursiveDecode()133     int RecursiveDecode()
134     {
135         return RETCODE_SUCCESS;
136     }
137 
138 private:
139     unsigned char *buffer_ {nullptr};
140     size_t size_ {0};
141     size_t pos_ {0};
142 };
143 
144 /**
145  * Encode std::string. It's a instantiation of template function (@link DataEncoder::EncodeOneParameter).
146  *
147  * @param [out] val The data that needs to be encoded.
148  * @return Returns 0 if the data has been written into the buffer successfully, otherwise, it will return -1.
149  */
150 template<>
151 int DataDecoder::DecodeOneParameter(std::string &val);
152 } // namespace AI
153 } // namespace OHOS
154 
155 #endif // DATA_DECODER_H
156