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
24namespace OHOS {
25namespace HDI {
26namespace Display {
27class CommandDataPacker {
28public:
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
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
67    bool WriteUint64(uint64_t value)
68    {
69        return Write<uint64_t>(value);
70    }
71
72    bool WriteUint32(uint32_t value)
73    {
74        return Write<uint32_t>(value);
75    }
76
77    bool WriteUint8(uint8_t value)
78    {
79        return Write<uint32_t>(value);
80    }
81
82    bool WriteInt32(int32_t value)
83    {
84        return Write<int32_t>(value);
85    }
86
87    bool WriteBool(bool value)
88    {
89        return Write<int32_t>(value);
90    }
91
92    size_t ValidSize()
93    {
94        return writePos_;
95    }
96
97    size_t PackSize()
98    {
99        return packSize_;
100    }
101
102    char *GetDataPtr()
103    {
104        return data_;
105    }
106
107    void RollBack(size_t writePos)
108    {
109        writePos_ = writePos;
110    }
111
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
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
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
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
198private:
199    template <typename T>
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
231private:
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
239private:
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