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 "imgdecode/image_load.h"
17 #include "gfx_utils/file.h"
18 #include "gfx_utils/graphic_log.h"
19 #include "gfx_utils/mem_api.h"
20 
21 namespace {
22 const uint8_t BITMAP_ZIP_LEN = 3;
23 const uint8_t BITMAP_MID_BIT = 1;
24 const uint8_t BITMAP_LOW_BIT = 2;
25 const uint32_t BITMAP_ZIP24_FLAG = 0x456789;
26 const uint32_t BITMAP_ZIP_FLAG = 0x23456789;
27 const uint32_t BITMAP_ALPHA_MASK = 0xFF000000;
28 const uint32_t BITMAP_MAXCON_PIXNUM = 0xCB100;
29 const uint32_t MOVE_HIGH = 16;
30 const uint32_t MOVE_LOW = 8;
31 } // namespace
32 
33 namespace OHOS {
CreateImage(ImageInfo & imageInfo)34 bool ImageLoad::CreateImage(ImageInfo& imageInfo)
35 {
36     uint32_t bytePerPixel = 4;
37     ImageHeader& imageHeader = imageInfo.header;
38 
39     switch (imageHeader.colorMode) {
40         case ARGB8888:
41             bytePerPixel = 4; // 4 bytes per pixel
42             break;
43         case RGB888:
44             bytePerPixel = 3; // 3 bytes per pixel
45             break;
46         case RGB565:
47             bytePerPixel = 2; // 2 bytes per pixel
48             break;
49         default:
50             GRAPHIC_LOGE("CreateImage invalid colorMode.");
51             return false;
52     }
53 
54     imageInfo.dataSize = imageHeader.width * imageHeader.height * bytePerPixel;
55     imageInfo.data = static_cast<uint8_t*>(ImageCacheMalloc(imageInfo));
56     if (imageInfo.data == nullptr) {
57         GRAPHIC_LOGE("ImageCacheMalloc error.");
58         return false;
59     }
60 
61     return true;
62 }
63 
UncompressImageInZip(ImageInfo & imageInfo,uint8_t * buffer,uint32_t size)64 bool ImageLoad::UncompressImageInZip(ImageInfo& imageInfo, uint8_t* buffer, uint32_t size)
65 {
66     if (!CreateImage(imageInfo)) {
67         GRAPHIC_LOGE("Create image error.");
68         return false;
69     }
70 
71     if (imageInfo.header.colorMode == RGB888) {
72         return Unzip24Image(buffer, size, imageInfo);
73     } else {
74         return UnzipImage(buffer, size, imageInfo);
75     }
76 }
77 
UnzipImage(uint8_t * imageBuffer,uint32_t size,ImageInfo & imageInfo)78 bool ImageLoad::UnzipImage(uint8_t* imageBuffer, uint32_t size, ImageInfo& imageInfo)
79 {
80     if ((imageBuffer == nullptr) || (size == 0)) {
81         GRAPHIC_LOGE("imageHeader is null.");
82         return false;
83     }
84 
85     uint32_t* source = reinterpret_cast<uint32_t*>(imageBuffer);
86     uint32_t* sourceEnd = reinterpret_cast<uint32_t*>(imageBuffer + size);
87     uint32_t* dest = nullptr;
88     uint32_t* destEnd = nullptr;
89 
90     dest = reinterpret_cast<uint32_t*>(const_cast<uint8_t*>(imageInfo.data));
91     destEnd = reinterpret_cast<uint32_t*>(const_cast<uint8_t*>(imageInfo.data) + imageInfo.dataSize);
92 
93     while ((source < sourceEnd) && (dest < destEnd)) {
94         if (*source != BITMAP_ZIP_FLAG) {
95             *dest++ = *source++;
96         } else {
97             source++;
98             uint32_t value = *source++;
99             uint32_t count = *source++;
100             if (destEnd < count + dest) {
101                 break;
102             }
103 
104             while (count--) {
105                 *dest++ = value;
106             }
107         }
108     }
109 
110     if (dest == destEnd) {
111         return true;
112     }
113     ImageCacheFree(imageInfo);
114     imageInfo.data = nullptr;
115     return false;
116 }
117 
Unzip24Image(uint8_t * imageBuffer,uint32_t size,ImageInfo & imageInfo)118 bool ImageLoad::Unzip24Image(uint8_t* imageBuffer, uint32_t size, ImageInfo& imageInfo)
119 {
120     if ((imageBuffer == nullptr) || (size == 0)) {
121         GRAPHIC_LOGE("imageHeader is null.");
122         return false;
123     }
124 
125     uint8_t* source = reinterpret_cast<uint8_t*>(imageBuffer);
126     uint8_t* sourceEnd = reinterpret_cast<uint8_t*>(imageBuffer + size);
127     uint32_t* dest = reinterpret_cast<uint32_t*>(const_cast<uint8_t*>(imageInfo.data));
128     uint32_t* destEnd = reinterpret_cast<uint32_t*>(const_cast<uint8_t*>(imageInfo.data) + imageInfo.dataSize);
129     while ((source < sourceEnd) && (dest < destEnd)) {
130         // Little endian
131         uint32_t value = ((*source)) + (*(source + BITMAP_MID_BIT) << MOVE_LOW)
132                          + (*(source + BITMAP_LOW_BIT) << MOVE_HIGH);
133         source = source + BITMAP_ZIP_LEN;
134         if (value != BITMAP_ZIP24_FLAG) {
135             *dest = value | BITMAP_ALPHA_MASK;
136             dest++;
137         } else {
138             value = ((*source)) + (*(source + BITMAP_MID_BIT) << MOVE_LOW) + (*(source + BITMAP_LOW_BIT) << MOVE_HIGH);
139             source = source + BITMAP_ZIP_LEN;
140 
141             uint32_t count = ((*source)) + (*(source + BITMAP_MID_BIT) << MOVE_LOW)
142                              + (*(source + BITMAP_LOW_BIT) << MOVE_HIGH);
143             source = source + BITMAP_ZIP_LEN;
144 
145             if (count > BITMAP_MAXCON_PIXNUM) {
146                 *dest = BITMAP_ZIP24_FLAG | BITMAP_ALPHA_MASK;
147                 dest++;
148                 *dest = value | BITMAP_ALPHA_MASK;
149                 dest++;
150                 *dest = count | BITMAP_ALPHA_MASK;
151                 dest++;
152                 continue;
153             }
154             if (static_cast<uintptr_t>(destEnd - dest) < static_cast<uintptr_t>(count)) {
155                 break;
156             }
157             while (count--) {
158                 *dest = value | BITMAP_ALPHA_MASK;
159                 dest++;
160             }
161         }
162     }
163 
164     if (dest == destEnd) {
165         return true;
166     }
167     ImageCacheFree(imageInfo);
168     imageInfo.data = nullptr;
169     return false;
170 }
171 
UnZip2ImageInfo(ImageInfo & imageInfo,uint8_t * buffer,uint32_t size)172 bool ImageLoad::UnZip2ImageInfo(ImageInfo& imageInfo, uint8_t* buffer, uint32_t size)
173 {
174     switch (imageInfo.header.compressMode) {
175         case COMPRESS_MODE__ZIP_ALG:
176             return UncompressImageInZip(imageInfo, buffer, size);
177         default:
178             return false;
179     }
180 }
181 
GetImageInfo(int32_t fd,uint32_t size,ImageInfo & imageInfo)182 bool ImageLoad::GetImageInfo(int32_t fd, uint32_t size, ImageInfo& imageInfo)
183 {
184     if (size == 0) {
185         return false;
186     }
187 
188     uint8_t* buffer = reinterpret_cast<uint8_t*>(UIMalloc(size));
189     if (buffer == nullptr) {
190         return false;
191     }
192 
193     if (read(fd, buffer, size) != static_cast<int32_t>(size)) {
194         UIFree(buffer);
195         GRAPHIC_LOGE("SeekImageFile error.");
196         return false;
197     }
198     bool ret = UnZip2ImageInfo(imageInfo, buffer, size);
199     UIFree(buffer);
200     return ret;
201 }
202 } // namespace OHOS
203