1 /*
2  * Copyright (c) 2023 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 DISPLAY_COMMAND_DATA_PACKER_H
17 #define DISPLAY_COMMAND_DATA_PACKER_H
18 
19 #include <memory>
20 #include <securec.h>
21 #include "common/include/display_interface_utils.h"
22 #include "hilog/log.h"
23 
24 namespace OHOS {
25 namespace HDI {
26 namespace Display {
27 class CommandDataPacker {
28 public:
CommandDataPacker()29     CommandDataPacker()
30         : packSize_(0),
31         writePos_(0),
32         curSecOffset_(0),
33         settingSecLen_(0),
34         curSecLenPos_(0),
35         data_(nullptr),
36         isAdaptiveGrowth_(false)
37     {
38     }
39 
~CommandDataPacker()40     ~CommandDataPacker()
41     {
42         if (data_ != nullptr) {
43             delete[] data_;
44         }
45     }
46 
47     bool Init(size_t size = INIT_DATA_SIZE, bool isAdaptiveGrowth = false)
48     {
49         writePos_ = 0;
50         curSecOffset_ = 0;
51         settingSecLen_ = 0;
52         curSecLenPos_ = 0;
53         isAdaptiveGrowth_ = false;
54         packSize_ = size;
55         uint32_t alignedSize = (packSize_ + ALLOC_PAGE_SIZE - 1) & (~(ALLOC_PAGE_SIZE - 1));
56         if (data_ != nullptr) {
57             delete[] data_;
58         }
59         data_ = new char[alignedSize];
60         DISPLAY_CHK_RETURN(data_ == nullptr, false,
61             HDF_LOGE("%{public}s, alloc memory failed", __func__));
62         packSize_ = alignedSize;
63         isAdaptiveGrowth_ = isAdaptiveGrowth;
64         return true;
65     }
66 
WriteUint64(uint64_t value)67     bool WriteUint64(uint64_t value)
68     {
69         return Write<uint64_t>(value);
70     }
71 
WriteUint32(uint32_t value)72     bool WriteUint32(uint32_t value)
73     {
74         return Write<uint32_t>(value);
75     }
76 
WriteUint8(uint8_t value)77     bool WriteUint8(uint8_t value)
78     {
79         return Write<uint32_t>(value);
80     }
81 
WriteInt32(int32_t value)82     bool WriteInt32(int32_t value)
83     {
84         return Write<int32_t>(value);
85     }
86 
WriteBool(bool value)87     bool WriteBool(bool value)
88     {
89         return Write<int32_t>(value);
90     }
91 
ValidSize()92     size_t ValidSize()
93     {
94         return writePos_;
95     }
96 
PackSize()97     size_t PackSize()
98     {
99         return packSize_;
100     }
101 
GetDataPtr()102     char *GetDataPtr()
103     {
104         return data_;
105     }
106 
RollBack(int32_t writePos)107     void RollBack(int32_t writePos)
108     {
109         writePos_ = writePos;
110     }
111 
PackBegin(int32_t beginCmd)112     bool PackBegin(int32_t beginCmd)
113     {
114         writePos_ = 0;
115         settingSecLen_ = sizeof(int32_t);
116         curSecLenPos_ = 0;
117         curSecOffset_ = writePos_;
118         DISPLAY_CHK_RETURN(WriteInt32(beginCmd) == false, false,
119             HDF_LOGE("%{public}s, write beginCmd error", __func__));
120         return true;
121     }
122 
123     bool BeginSection(int32_t cmdId, uint32_t len = 0)
124     {
125         // len must be 4 byte alignment.
126         DISPLAY_CHK_RETURN((len & SECTION_LEN_ALIGN - 1) != 0, false,
127             HDF_LOGE("%{public}s, length is not aligned by 4 bytes", __func__));
128         // Update current data before next section.
129         curSecOffset_ = writePos_;
130         DISPLAY_CHK_RETURN(WriteUint32(SECTION_END_MAGIC) == false, false,
131             HDF_LOGE("%{public}s, write SECTION_END_MAGIC error", __func__));
132         DISPLAY_CHK_RETURN(WriteInt32(cmdId) == false, false,
133             HDF_LOGE("%{public}s, write cmdID error", __func__));
134         curSecLenPos_ = writePos_;
135         settingSecLen_ = len;
136         // Now we don't write section len here,
137         // but write it on EndSection.
138         writePos_ += sizeof(uint32_t);
139         return true;
140     }
141 
EndSection()142     bool EndSection()
143     {
144         // Write cmd len before data related is updated.
145         DISPLAY_CHK_RETURN(writePos_ < curSecOffset_, false,
146             HDF_LOGE("%{public}s, error: writePos_ after curSecOffset_", __func__));
147         // Write cmd len before data related is updated.
148         uint32_t actualLen = writePos_ - curSecOffset_;
149         uint32_t updatedLen = actualLen > settingSecLen_ ? actualLen : settingSecLen_;
150         // We must check "writePos" < packSize_ Before write
151         if ((curSecLenPos_ + sizeof(updatedLen)) > packSize_) {
152             HDF_LOGE("%{public}s, error: current pos > packSize", __func__);
153             return false;
154         } else {
155             *reinterpret_cast<uint32_t *>(data_ + curSecLenPos_) = updatedLen;
156         }
157         writePos_ = curSecOffset_ + updatedLen;
158 
159         DISPLAY_CHK_RETURN(writePos_  >= packSize_, false,
160             HDF_LOGE("%{public}s, error: writePos_ > packSize", __func__));
161         return true;
162     }
163 
PackEnd(int32_t endCmd)164     bool PackEnd(int32_t endCmd)
165     {
166         DISPLAY_CHK_RETURN(WriteInt32(endCmd) == false, false,
167             HDF_LOGE("%{public}s, write endCmd error", __func__));
168         DISPLAY_CHK_RETURN(writePos_  >= packSize_, false,
169             HDF_LOGE("%{public}s, error: writePos_ > packSize", __func__));
170         return true;
171     }
172 
Dump()173     void Dump()
174     {
175         HDF_LOGI("---------------------------------------------\n");
176         HDF_LOGI("ALLOC_PAGE_SIZE       =%{public}d\n", ALLOC_PAGE_SIZE);
177         HDF_LOGI("INIT_DATA_SIZE        =%{public}d\n", INIT_DATA_SIZE);
178         HDF_LOGI("SECTION_END_MAGIC     =0x%{public}x\n", SECTION_END_MAGIC);
179         HDF_LOGI("packSize_             =%{public}zu\n", packSize_);
180         HDF_LOGI("writePos_             =%{public}zu\n", writePos_);
181         HDF_LOGI("curSecOffset_         =%{public}zu\n", curSecOffset_);
182         HDF_LOGI("settingSecLen_        =%{public}d\n", settingSecLen_);
183         HDF_LOGI("curSecLenPos_         =%{public}zu\n", curSecLenPos_);
184         uint32_t i = 0;
185         for (; sizeof(int32_t) * i < writePos_;) {
186             HDF_LOGI("%{public}08x ", *reinterpret_cast<uint32_t *>(data_ + sizeof(int32_t) * i));
187             i++;
188             if ((i % DUMP_LINE_LEN) == 0) {
189                 HDF_LOGI("\n");
190             } else if ((i % DUMP_HALF_LINE_SPACE) == 0) {
191                 HDF_LOGI(" ");
192             } else {
193             }
194         }
195         HDF_LOGI("\n");
196     }
197 
198 private:
199     template <typename T>
Write(T value)200     bool Write(T value)
201     {
202         size_t writeSize = sizeof(T);
203         size_t newSize = writePos_ + writeSize;
204         if (newSize > packSize_) {
205             if (!isAdaptiveGrowth_) {
206                 HDF_LOGE("%{public}s: command packer is overflow", __func__);
207                 return false;
208             }
209             newSize = (newSize + ALLOC_PAGE_SIZE - 1) & (~(ALLOC_PAGE_SIZE - 1));
210             char *newData = new char[newSize];
211             if (newData == nullptr) {
212                 HDF_LOGE("%{public}s: mem alloc failed", __func__);
213                 return false;
214             }
215             if (memcpy_s(newData, newSize, data_, packSize_) != EOK) {
216                 HDF_LOGE("%{public}s: memcpy_s failed", __func__);
217                 delete[] newData;
218                 newData = nullptr;
219                 return false;
220             }
221             delete[] data_;
222             data_ = newData;
223             packSize_ = newSize;
224         }
225         *reinterpret_cast<T *>(data_ + writePos_) = value;
226         writePos_ += writeSize;
227 
228         return true;
229     }
230 
231 private:
232     static constexpr uint32_t ALLOC_PAGE_SIZE = 1024;
233     static constexpr uint32_t INIT_DATA_SIZE = 32 * ALLOC_PAGE_SIZE;
234     static constexpr uint32_t SECTION_END_MAGIC = 0xB5B5B5B5;
235     static constexpr uint32_t SECTION_LEN_ALIGN = 4;
236     static constexpr uint32_t DUMP_HALF_LINE_SPACE = 4;
237     static constexpr uint32_t DUMP_LINE_LEN = 8;
238 
239 private:
240     size_t packSize_;
241     size_t writePos_;
242     size_t curSecOffset_;
243     uint32_t settingSecLen_;
244     size_t curSecLenPos_;
245     char *data_;
246     bool isAdaptiveGrowth_;
247 };
248 } // namespace Display
249 } // namespace HDI
250 } // namespace OHOS
251 #endif // DISPLAY_COMMAND_DATA_PACKER_H
252