1/*
2 * Copyright (c) 2020-2022 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 "compare_tools.h"
17#include <cstring>
18#include "common/screen.h"
19#include "dock/screen_device_proxy.h"
20#include "draw/draw_utils.h"
21#include "gfx_utils/file.h"
22#include "gfx_utils/graphic_log.h"
23#include "gfx_utils/graphic_math.h"
24#include "graphic_config.h"
25#include "securec.h"
26
27#ifdef _WIN32
28    #define STR(STRING) #STRING
29    #define STRPATH(STRING) STR(STRING)
30#endif
31
32namespace OHOS {
33bool CompareTools::enableLog_ = false;
34char* CompareTools::logPath_ = nullptr;
35
36void CompareTools::WaitSuspend(const uint16_t waitTime)
37{
38    uint16_t sleepTime = waitTime == 0 ? DEFAULT_WAIT_TIME_MS : waitTime;
39#ifdef _WIN32
40    Sleep(sleepTime);
41#else
42    usleep(1000 * sleepTime); // 1000: us to ms
43#endif // _WIN32
44}
45
46bool CompareTools::StrnCatPath(char* filePath, size_t pathMax, const char* fileName, size_t count)
47{
48    if ((filePath == nullptr) || (pathMax > DEFAULT_FILE_NAME_MAX_LENGTH)) {
49        return false;
50    }
51#ifdef _WIN32
52    char dest[DEFAULT_FILE_NAME_MAX_LENGTH] = STRPATH(AUTO_TEST_RESOURCE_PATH);
53#else
54    char dest[DEFAULT_FILE_NAME_MAX_LENGTH] = AUTO_TEST_RESOURCE_PATH;
55#endif // _WIN32
56    if (strncat_s(dest, DEFAULT_FILE_NAME_MAX_LENGTH, fileName, count) != EOK) {
57        return false;
58    }
59    if (memcpy_s(static_cast<void *>(filePath), pathMax, dest, DEFAULT_FILE_NAME_MAX_LENGTH) != EOK) {
60        return false;
61    }
62    return true;
63}
64
65bool CompareTools::CompareByBit(uint32_t fd)
66{
67    ImageInfo imageBit;
68    if (!(Screen::GetInstance().GetCurrentScreenBitmap(imageBit))) {
69        return false;
70    }
71    struct BitmapInfoHeader bitmapInfo = {0};
72    lseek(fd, sizeof(uint16_t), SEEK_SET);
73    if (read(fd, &bitmapInfo, sizeof(bitmapInfo)) < 0) {
74        ImageCacheFree(imageBit);
75        return false;
76    }
77    if (bitmapInfo.biSizeImage != imageBit.dataSize) {
78        ImageCacheFree(imageBit);
79        return false;
80    }
81    bool flag = true;
82    uint32_t buffSize = bitmapInfo.biSizeImage / MATH_ABS(bitmapInfo.biHeight);
83    auto buff = new uint8_t[buffSize];
84    for (uint32_t i = 0; i < MATH_ABS(bitmapInfo.biHeight); i++) {
85        if (flag && (memset_s(buff, buffSize, 0, buffSize) != EOK)) {
86            flag = false;
87            break;
88        }
89        int32_t ret = read(fd, buff, buffSize);
90        if (ret < 0) {
91            flag = false;
92            break;
93        }
94        for (uint32_t j = 0; j < ret; j++) {
95            if (buff[j] != imageBit.data[i * buffSize + j]) {
96                flag = false;
97                break;
98            }
99        }
100    }
101    ImageCacheFree(imageBit);
102    delete [] buff;
103    buff = nullptr;
104    return flag;
105}
106
107bool CompareTools::CompareByBitmap(const BitmapInfoHeader bitmapInfoBase,
108    const BitmapInfoHeader bitmapInfoRun, uint32_t fdBase, uint32_t fdRun)
109{
110    bool flag = true;
111    uint32_t buffSizeBase = bitmapInfoBase.biSizeImage / MATH_ABS(bitmapInfoBase.biHeight);
112    auto buffBase = new uint8_t[buffSizeBase];
113
114    uint32_t buffSizeRun = bitmapInfoRun.biSizeImage / MATH_ABS(bitmapInfoRun.biHeight);
115    auto buffRun = new uint8_t[buffSizeRun];
116
117    for (uint32_t i = 0; i < MATH_ABS(bitmapInfoBase.biHeight); i++) {
118        if (flag && (memset_s(buffBase, buffSizeBase, 0, buffSizeBase) != EOK)) {
119            flag = false;
120            break;
121        }
122        if (flag && (memset_s(buffRun, buffSizeRun, 0, buffSizeRun) != EOK)) {
123            flag = false;
124            break;
125        }
126        int32_t retBase = read(fdBase, buffBase, buffSizeBase);
127        if (retBase < 0) {
128            flag = false;
129            break;
130        }
131        int32_t retRun = read(fdRun, buffRun, buffSizeBase);
132        if (retRun < 0) {
133            flag = false;
134            break;
135        }
136        if (retBase != retRun) {
137            flag = false;
138            break;
139        }
140
141        for (uint32_t j = 0; j < retBase; j++) {
142            if (buffBase[j] != buffRun[j]) {
143                flag = false;
144                break;
145            }
146        }
147    }
148
149    delete [] buffBase;
150    buffBase = nullptr;
151    delete [] buffRun;
152    buffRun = nullptr;
153
154    return flag;
155}
156
157
158bool CompareTools::CompareFile(const char* fileBasePath, const char* fileRunPath)
159{
160    if (fileBasePath == nullptr || fileRunPath == nullptr) {
161        return false;
162    }
163#ifdef _WIN32
164    uint32_t fdBase = open(fileBasePath, O_RDONLY | O_BINARY);
165    uint32_t fdRun = open(fileRunPath, O_RDONLY | O_BINARY);
166#else
167    uint32_t fdBase = open(fileBasePath, O_RDONLY);
168    uint32_t fdRun = open(fileRunPath, O_RDONLY);
169#endif
170    struct BitmapInfoHeader bitmapInfoBase = {0};
171    lseek(fdBase, sizeof(uint16_t), SEEK_SET);
172    if (read(fdBase, &bitmapInfoBase, sizeof(bitmapInfoBase)) < 0) {
173        close(fdBase);
174        close(fdRun);
175        return false;
176    }
177
178    struct BitmapInfoHeader bitmapInfoRun = {0};
179    lseek(fdRun, sizeof(uint16_t), SEEK_SET);
180    if (read(fdRun, &bitmapInfoRun, sizeof(bitmapInfoRun)) < 0) {
181        close(fdBase);
182        close(fdRun);
183        return false;
184    }
185
186    if (bitmapInfoBase.biSizeImage != bitmapInfoRun.biSizeImage) {
187        close(fdBase);
188        close(fdRun);
189        return false;
190    }
191
192    if (!CompareByBitmap(bitmapInfoBase, bitmapInfoRun, fdBase, fdRun)) {
193        close(fdBase);
194        close(fdRun);
195        return false;
196    }
197
198    close(fdBase);
199    close(fdRun);
200    return true;
201}
202
203bool CompareTools::CompareFile(const char* filePath, size_t length)
204{
205    if ((filePath == nullptr) || (length > DEFAULT_FILE_NAME_MAX_LENGTH)) {
206        return false;
207    }
208#ifdef _WIN32
209    uint32_t fd = open(filePath, O_RDONLY | O_BINARY);
210#else
211    uint32_t fd = open(filePath, O_RDONLY);
212#endif
213    if (fd == -1) {
214        return false;
215    }
216    bool flag = CompareByBit(fd);
217    close(fd);
218    if (flag) {
219        GRAPHIC_LOGI("[COMPARE_SUCCESS]:fileName=%s", filePath);
220        if (enableLog_) {
221            char logInfo[DEFAULT_FILE_NAME_MAX_LENGTH] = {0};
222            if (sprintf_s(logInfo, sizeof(logInfo), "[COMPARE_SUCCESS]:fileName=%s\n", filePath) < 0) {
223                return false;
224            }
225            SaveLog(logInfo, strlen(logInfo));
226        }
227    } else {
228        GRAPHIC_LOGI("[COMPARE_FAILURE]:fileName=%s", filePath);
229        if (enableLog_) {
230            char logInfo[DEFAULT_FILE_NAME_MAX_LENGTH] = {0};
231            if (sprintf_s(logInfo, sizeof(logInfo), "[COMPARE_FAILURE]:fileName=%s\n", filePath) < 0) {
232                return false;
233            }
234            SaveLog(logInfo, strlen(logInfo));
235        }
236    }
237    return flag;
238}
239
240bool CompareTools::SaveByBit(uint32_t fd)
241{
242    ImageInfo imageBit;
243    if (!(Screen::GetInstance().GetCurrentScreenBitmap(imageBit))) {
244        return false;
245    }
246    bool flag = false;
247    uint8_t sizeByColorMode = DrawUtils::GetByteSizeByColorMode(ScreenDeviceProxy::GetInstance()->GetBufferMode());
248    uint16_t bfType = 0x4D42;
249    struct BitmapInfoHeader bitmapInfo = {0};
250    bitmapInfo.bfSize = imageBit.dataSize + BITMAP_HEADER_SIZE;
251    bitmapInfo.bfOffBits = BITMAP_HEADER_SIZE;
252    bitmapInfo.biSize = 40; // 40: bitmap information header size
253    bitmapInfo.biWidth = imageBit.header.width;
254    bitmapInfo.biHeight = -imageBit.header.height;
255    bitmapInfo.biPlanes = 1;
256    bitmapInfo.biBitCount = sizeByColorMode * 8; // 8: uint8_t bit
257    bitmapInfo.biSizeImage = imageBit.dataSize;
258    if (write(fd, &bfType, sizeof(bfType)) > 0) {
259        if (write(fd, &bitmapInfo, sizeof(bitmapInfo)) > 0) {
260            if (write(fd, imageBit.data, imageBit.dataSize) > 0) {
261                flag = true;
262            }
263        }
264    }
265    ImageCacheFree(imageBit);
266    return flag;
267}
268
269void CompareTools::SaveResultLog(const char* filePath, const char* buff, size_t bufSize)
270{
271    if (filePath == nullptr || buff == nullptr || bufSize <= 0) {
272        return;
273    }
274
275    SaveLog(buff, bufSize, filePath);
276}
277
278bool CompareTools::SaveFile(const char* filePath, size_t length)
279{
280    if ((filePath == nullptr) || (length > DEFAULT_FILE_NAME_MAX_LENGTH)) {
281        return false;
282    }
283#ifdef _WIN32
284    uint32_t fd = open(filePath, O_WRONLY | O_CREAT | O_BINARY, DEFAULT_FILE_PERMISSION);
285#else
286    uint32_t fd = open(filePath, O_WRONLY | O_CREAT, DEFAULT_FILE_PERMISSION);
287#endif
288    if (fd == -1) {
289        return false;
290    }
291    bool flag = SaveByBit(fd);
292    close(fd);
293    return flag;
294}
295
296bool CompareTools::CheckFileExist(const char* filePath, size_t length)
297{
298    if ((filePath == nullptr) || (length > DEFAULT_FILE_NAME_MAX_LENGTH)) {
299        return false;
300    }
301    uint32_t fd = open(filePath, O_RDONLY);
302    if (fd == -1) {
303        return false;
304    }
305    close(fd);
306    return true;
307}
308
309void CompareTools::SetLogPath(const char* filePath, size_t length)
310{
311    if (logPath_ == nullptr) {
312        logPath_ = new char[length];
313        if (logPath_ == nullptr) {
314            return;
315        }
316        if (memcpy_s(logPath_, length, filePath, length) != EOK) {
317            GRAPHIC_LOGE("memcpy filepath failed");
318            return;
319        }
320        enableLog_ = true;
321    }
322}
323
324void CompareTools::UnsetLogPath()
325{
326    if (logPath_ != nullptr) {
327        delete[] logPath_;
328        logPath_ = nullptr;
329        enableLog_ = false;
330    }
331}
332
333bool CompareTools::SaveLog(const char* buff, size_t bufSize, const char* filePath)
334{
335    if (buff == nullptr) {
336        return false;
337    }
338
339    const char* useLogPath = filePath == nullptr ? logPath_ : filePath;
340    if (useLogPath == nullptr) {
341        return false;
342    }
343
344    uint32_t logFd = open(useLogPath, O_WRONLY | O_CREAT | O_APPEND, DEFAULT_FILE_PERMISSION);
345    if (logFd == -1) {
346        GRAPHIC_LOGE("open log failed");
347        return false;
348    }
349    if (write(logFd, buff, bufSize) < 0) {
350        close(logFd);
351        GRAPHIC_LOGE("write log failed");
352        return false;
353    }
354    close(logFd);
355    return true;
356}
357} // namespace OHOS
358