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 
21 namespace OHOS {
GetInstance()22 FileImgDecoder& FileImgDecoder::GetInstance()
23 {
24     static FileImgDecoder instance;
25     return instance;
26 }
27 
Open(ImgResDsc & dsc)28 RetCode 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 
Close(ImgResDsc & dsc)50 RetCode 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 
GetHeader(ImgResDsc & dsc)64 RetCode 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 
ReadLine(ImgResDsc & dsc,const Point & start,int16_t len,uint8_t * buf)90 RetCode 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 
ReadToCache(ImgResDsc & dsc)98 RetCode 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 
ReadLineTrueColor(ImgResDsc & dsc,const Point & start,int16_t len,uint8_t * buf)146 RetCode 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