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 #include "utils/encdec/include/data_encoder.h"
17 
18 #include <climits>
19 
20 #include "utils/aie_macros.h"
21 
22 namespace OHOS {
23 namespace AI {
24 namespace {
25 constexpr size_t CHUNK_SIZE = 1024U * 15U;
26 constexpr unsigned BUFF_EXTENSION_FACTOR = 2U;
27 
AllocateMemBlock(const size_t sz)28 MemBlock *AllocateMemBlock(const size_t sz)
29 {
30     size_t size = sz + sizeof(MemBlock);
31     unsigned char *memBlock = nullptr;
32     AIE_NEW(memBlock, unsigned char[size]);
33     CHK_RET((memBlock == nullptr), nullptr);
34 
35     auto *block = reinterpret_cast<MemBlock*>(memBlock);
36     block->blockSize = sz;
37     return block;
38 }
39 
FreeMemBlock(MemBlock * block)40 void FreeMemBlock(MemBlock *block)
41 {
42     auto *memBlock = reinterpret_cast<unsigned char*>(block);
43     AIE_DELETE_ARRAY(memBlock);
44 }
45 }
46 
DataEncoder()47 DataEncoder::DataEncoder() : buffer_(nullptr), pos_(0), allocSuccess_(false)
48 {
49 }
50 
~DataEncoder()51 DataEncoder::~DataEncoder()
52 {
53     CHK_RET_NONE(!buffer_);
54     FreeMemBlock(buffer_);
55     buffer_ = nullptr;
56 }
57 
Init(size_t sz)58 int DataEncoder::Init(size_t sz)
59 {
60     buffer_ = AllocateMemBlock(sz);
61     CHK_RET(buffer_ == nullptr, RETCODE_OUT_OF_MEMORY);
62     allocSuccess_ = true;
63     return RETCODE_SUCCESS;
64 }
65 
GetSerializedData(DataInfo & dataInfo)66 int DataEncoder::GetSerializedData(DataInfo &dataInfo)
67 {
68     CHK_RET(EncodeOneParameter(pos_) != RETCODE_SUCCESS, RETCODE_FAILURE);
69     CHK_RET(buffer_ == nullptr || pos_ == 0, RETCODE_FAILURE);
70     if (pos_ > INT_MAX) { // pos_ is unsigned but data.length is signed, avoid implicit conversion.
71         HILOGE("[Encdec]The encoded data length exceed DataInfo's capacity, whose max is INT_MAX.");
72         return RETCODE_FAILURE;
73     }
74     dataInfo.length = pos_;
75     dataInfo.data = reinterpret_cast<unsigned char*>(malloc(dataInfo.length));
76     if (dataInfo.data == nullptr) {
77         return RETCODE_OUT_OF_MEMORY;
78     }
79     errno_t res = memcpy_s(dataInfo.data, dataInfo.length, buffer_->data, pos_);
80     if (res != EOK) {
81         free(dataInfo.data);
82         dataInfo.data = nullptr;
83         dataInfo.length = 0;
84         return RETCODE_MEMORY_COPY_FAILURE;
85     }
86     FreeMemBlock(buffer_);
87     buffer_ = nullptr;
88     pos_ = 0;
89     allocSuccess_ = false;
90 
91     return RETCODE_SUCCESS;
92 }
93 
Ensure(const size_t incSize)94 bool DataEncoder::Ensure(const size_t incSize)
95 {
96     if (buffer_->blockSize >= pos_ + incSize) {
97         return true;
98     }
99     return ReallocBuffer(buffer_->blockSize * BUFF_EXTENSION_FACTOR + incSize);
100 }
101 
ReallocBuffer(const size_t newSize)102 bool DataEncoder::ReallocBuffer(const size_t newSize)
103 {
104     CHK_RET(!allocSuccess_, false);
105 
106     MemBlock *p = AllocateMemBlock(newSize);
107     if (p == nullptr) {
108         allocSuccess_ = false;
109         return false;
110     }
111     unsigned char *dest = p->data;
112     unsigned char *src = buffer_->data;
113     size_t leftSize = pos_;
114     for (; leftSize >= CHUNK_SIZE; leftSize -= CHUNK_SIZE) {
115         errno_t err = memcpy_s(dest, CHUNK_SIZE, src, CHUNK_SIZE);
116         if (err != EOK) {
117             HILOGE("[Encdec]The memcpy_s error in the encdec process, err = %d.", err);
118             allocSuccess_ = false;
119             FreeMemBlock(p);
120             return false;
121         }
122         dest += CHUNK_SIZE;
123         src += CHUNK_SIZE;
124     }
125     if (leftSize > 0) {
126         errno_t errLeft = memcpy_s(dest, leftSize, src, leftSize);
127         if (errLeft != EOK) {
128             HILOGE("[Encdec]The memcpy_s error in the encdec process, err = %d.", errLeft);
129             allocSuccess_ = false;
130             FreeMemBlock(p);
131             return false;
132         }
133     }
134     FreeMemBlock(buffer_);
135     buffer_ = p;
136     return true;
137 }
138 
139 template<>
EncodeOneParameter(const std::string & val)140 int DataEncoder::EncodeOneParameter(const std::string &val)
141 {
142     if (!allocSuccess_) {
143         return RETCODE_FAILURE;
144     }
145 
146     if (val.length() == 0) { // 0 length string, save length only.
147         return EncodeOneParameter(val.length());
148     }
149     if (EncodeOneParameter(val.length()) != RETCODE_SUCCESS) {
150         return RETCODE_FAILURE;
151     }
152     if (!Ensure(val.length())) {
153         HILOGE("[Encdec]ReallocBuffer failed.");
154         return RETCODE_FAILURE;
155     }
156 
157     // assign value without memory alignment cause crash
158     // so use memcpy_s to make sure success.
159     if (memcpy_s(buffer_->data + pos_, val.length(), val.c_str(), val.length()) != EOK) {
160         HILOGE("[Encdec]memcpy_s failed.");
161         return RETCODE_FAILURE;
162     }
163     pos_ += val.length();
164     return RETCODE_SUCCESS;
165 }
166 } // namespace AI
167 } // namespace OHOS
168