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_ENCODER_H
17 #define DATA_ENCODER_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 struct MemBlock {
30     size_t blockSize;
31     unsigned char data[0];
32 };
33 
34 class DataEncoder {
35 public:
36     DataEncoder();
37     ~DataEncoder();
38 
39     /**
40      * Delete copy constructor/assignment to avoid misuse.
41      */
42     DataEncoder(const DataEncoder &other) = delete;
43     DataEncoder& operator=(const DataEncoder &other) = delete;
44 
45     /**
46      * Initializes memory for encoding data.
47      *
48      * @param [in] sz The size of the data which needs to be encoded.
49      * @return Return 0 if initialize successfully, returns a non-zero value otherwise.
50      */
51     int Init(size_t sz = INIT_BUFFER_SIZE);
52 
53     /**
54      * Encodes arguments.
55      *
56      * Please note,
57      * 1. the allowed input args contains:
58      *      - basic data types(int, double, boolean etc.), fix length arrays and structs containing them only.
59      *      - std::string
60      *
61      *    otherwise you should implement your own version of encoding/decoding
62      *    for pointers / struct containing pointers / struct containing std:string.
63      *    Specifically, you should instantiate template function (@link DataEncoder::EncodeOneParameter)
64      *    and (@link DataDecoder::DecodeOneParameter).
65      *
66      * 2.  class and container are not supported or tested.
67      *
68      * @param [in] arg argument need to be serialized. Receive any number of input.
69      * @return Return 0 if encode successfully, returns a non-zero value otherwise.
70      */
71     template<typename Type, typename... Types>
RecursiveEncode(const Type & arg,const Types &...args)72     int RecursiveEncode(const Type &arg, const Types &...args)
73     {
74         int retCode = EncodeOneParameter<Type>(arg);
75         if (retCode != RETCODE_SUCCESS) {
76             return retCode;
77         }
78         return RecursiveEncode(args...);
79     }
80 
81     /**
82      * Returns serialized data.
83      *
84      * Please note,
85      * 1. the memory in dataInfo should be released manually by the caller,
86      *    recommend to use guard macro immediately after ProcessEncode.
87      *    e.g.
88      *         MallocPointerGuard<unsigned char> dataInfoGuard(dataInfo.data);
89      *
90      * @param [out] dataInfo The serialized data.
91      * @return Return 0 if get data successfully, returns a non-zero value otherwise.
92      */
93     int GetSerializedData(DataInfo &dataInfo);
94 
95 private:
96     /**
97      * Ensure left memory length is bigger than incSize, otherwise expand it.
98      *
99      * @param [in] incSize Size to check.
100      * @return Return false if remaining memory is less than incSize, returns true otherwise.
101      */
102     bool Ensure(const size_t incSize);
103 
104     /**
105      * Write the data into the buffer. if the data size exceeds the buffer size, it will extend the buffer first.
106      * instantiate it for your own data type if needed.
107      *
108      * @param [in] val The data that needs to be encoded.
109      * @return Returns 0 if the data has been written into the buffer successfully, otherwise, it will return -1.
110      */
111     template<typename T>
EncodeOneParameter(const T & val)112     int EncodeOneParameter(const T &val)
113     {
114         if (!allocSuccess_) {
115             return RETCODE_FAILURE;
116         }
117 
118         size_t len = sizeof(T);
119         // on gcc, sizeof(T) is 0 when on gcc when T is defined as 0 length array.
120         // but it may not apply to other compilers.
121         // try a better type definition to avoid ambiguity.
122         if (len == 0) {
123             HILOGE("[Encdec]sizeof(T) is 0.");
124             return RETCODE_FAILURE;
125         }
126         if (!Ensure(len)) {
127             HILOGE("[Encdec]ReallocBuffer failed.");
128             return RETCODE_FAILURE;
129         }
130 
131         // assign value without memory alignment cause crash
132         // so use memcpy_s to make sure success.
133         if (memcpy_s(buffer_->data + pos_, len, &val, sizeof(val)) != EOK) {
134             HILOGE("[Encdec]memcpy_s failed.");
135             return RETCODE_FAILURE;
136         }
137         pos_ += len;
138         return RETCODE_SUCCESS;
139     }
140 
141     bool ReallocBuffer(const size_t newSize);
142 
143     /**
144      * it offers a terminal call for RecursiveEncode.
145      *
146      * @return Returns 0.
147      */
RecursiveEncode()148     int RecursiveEncode()
149     {
150         return RETCODE_SUCCESS;
151     }
152 
153 private:
154     static constexpr size_t INIT_BUFFER_SIZE = 256U;
155 
156     MemBlock *buffer_ {nullptr};
157     size_t pos_ {0};
158     bool allocSuccess_ {false};
159 };
160 
161 /**
162  * Decode std::string. It's a instantiation of template function (@link DataDecoder::DecodeOneParameter).
163  *
164  * @param [in] val The data that needs to be encoded.
165  * @return Returns 0 if the data has been written into the buffer successfully, otherwise, it will return -1.
166  */
167 template<>
168 int DataEncoder::EncodeOneParameter(const std::string &val);
169 } // namespace AI
170 } // namespace OHOS
171 
172 #endif // DATA_ENCODER_H
173