1/*
2 * Copyright (c) 2020-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 "gfx_utils/file.h"
17#include "gfx_utils/mem_api.h"
18#include "imgdecode/file_img_decoder.h"
19#include "imgdecode/image_load.h"
20
21namespace OHOS {
22FileImgDecoder& FileImgDecoder::GetInstance()
23{
24    static FileImgDecoder instance;
25    return instance;
26}
27
28RetCode FileImgDecoder::Open(ImgResDsc& dsc)
29{
30#ifdef _WIN32
31    int32_t fd = open(dsc.path, O_RDONLY | O_BINARY);
32#else
33    int32_t fd = open(dsc.path, O_RDONLY);
34#endif
35    if (fd == -1) {
36        return RetCode::FAIL;
37    }
38    dsc.fd = fd;
39
40    dsc.imgInfo.data = nullptr;
41    dsc.inCache_ = false;
42    uint8_t colorMode = dsc.imgInfo.header.colorMode;
43    if (IsImgValidMode(colorMode)) {
44        return RetCode::OK;
45    } else {
46        return RetCode::FAIL;
47    }
48}
49
50RetCode FileImgDecoder::Close(ImgResDsc& dsc)
51{
52    if (dsc.imgInfo.data != nullptr) {
53        ImageCacheFree(dsc.imgInfo);
54        dsc.imgInfo.data = nullptr;
55    }
56    if (dsc.fd && (dsc.fd != -1)) {
57        close(dsc.fd);
58        dsc.fd = -1;
59    }
60
61    return RetCode::OK;
62}
63
64RetCode FileImgDecoder::GetHeader(ImgResDsc& dsc)
65{
66    int32_t fd;
67    int32_t readCount;
68#ifdef _WIN32
69    fd = open(dsc.path, O_BINARY);
70#else
71    fd = open(dsc.path, O_RDONLY);
72#endif
73    if (fd == -1) {
74        return RetCode::FAIL;
75    }
76
77    readCount = read(fd, &dsc.imgInfo.header, sizeof(ImageHeader));
78    close(fd);
79    dsc.fd = -1;
80    if (readCount != sizeof(ImageHeader)) {
81        dsc.imgInfo.header.width = 0;
82        dsc.imgInfo.header.height = 0;
83        dsc.imgInfo.header.colorMode = UNKNOWN;
84        return RetCode::FAIL;
85    }
86
87    return RetCode::OK;
88}
89
90RetCode FileImgDecoder::ReadLine(ImgResDsc& dsc, const Point& start, int16_t len, uint8_t* buf)
91{
92    if (IsImgValidMode(dsc.imgInfo.header.colorMode)) {
93        return ReadLineTrueColor(dsc, start, len, buf);
94    }
95    return RetCode::FAIL;
96}
97
98RetCode FileImgDecoder::ReadToCache(ImgResDsc& dsc)
99{
100    struct stat info;
101    if (!dsc.inCache_) {
102        lseek(dsc.fd, 0, SEEK_SET);
103        int32_t readCount = read(dsc.fd, &dsc.imgInfo.header, sizeof(ImageHeader));
104        if (readCount != sizeof(ImageHeader)) {
105            return RetCode::FAIL;
106        }
107
108        int32_t ret = fstat(dsc.fd, &info);
109        if (ret != 0) {
110            return RetCode::FAIL;
111        }
112        uint32_t pxCount = info.st_size - readCount;
113        if (dsc.imgInfo.data != nullptr) {
114            ImageCacheFree(dsc.imgInfo);
115            dsc.imgInfo.data = nullptr;
116        }
117
118        bool readSuccess = false;
119        if (dsc.imgInfo.header.compressMode != COMPRESS_MODE_NONE) {
120            readSuccess = ImageLoad::GetImageInfo(dsc.fd, pxCount, dsc.imgInfo);
121        } else {
122            dsc.imgInfo.dataSize = pxCount;
123            dsc.imgInfo.data = reinterpret_cast<uint8_t*>(ImageCacheMalloc(dsc.imgInfo));
124            if (dsc.imgInfo.data == nullptr) {
125                return RetCode::OK;
126            }
127            uint8_t* tmp = const_cast<uint8_t*>(dsc.imgInfo.data);
128            readSuccess = (static_cast<int32_t>(pxCount) == read(dsc.fd, reinterpret_cast<void*>(tmp), pxCount));
129        }
130        if (!readSuccess) {
131            ImageCacheFree(dsc.imgInfo);
132            dsc.imgInfo.data = nullptr;
133            dsc.imgInfo.dataSize = 0;
134            close(dsc.fd);
135            dsc.fd = -1;
136            return RetCode::OK;
137        }
138        dsc.inCache_ = true;
139        close(dsc.fd);
140        dsc.fd = -1;
141    }
142
143    return RetCode::OK;
144}
145
146RetCode FileImgDecoder::ReadLineTrueColor(ImgResDsc& dsc, const Point& start, int16_t len, uint8_t* buf)
147{
148    uint8_t pxSizeInBit = DrawUtils::GetPxSizeByColorMode(dsc.imgInfo.header.colorMode);
149    off_t res;
150
151    uint32_t pos = ((start.y * dsc.imgInfo.header.width + start.x) * pxSizeInBit) >> BYTE_TO_BIT_SHIFT;
152    pos += sizeof(ImageHeader); /* Skip the header */
153    res = lseek(dsc.fd, pos, SEEK_SET);
154    if (res == -1) {
155        return RetCode::FAIL;
156    }
157    uint32_t btr = len * (pxSizeInBit >> BYTE_TO_BIT_SHIFT);
158    int32_t br = read(dsc.fd, buf, btr);
159    if ((br == -1) || (btr != static_cast<uint32_t>(br))) {
160        return RetCode::FAIL;
161    }
162
163    return RetCode::OK;
164}
165} // namespace OHOS
166