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