f20b5ce0808ad0fbe79dcdded790e7cfd8052864
[platform/core/uifw/dali-adaptor.git] / dali / internal / imaging / common / loader-wbmp.cpp
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // HEADER
19 #include <dali/internal/imaging/common/loader-wbmp.h>
20
21 // EXTERNAL INCLUDES
22 #include <cstdio>
23 #include <cstdlib>
24 #include <cstring>
25
26 // INTERNAL INCLUDES
27 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
28 #include <dali/integration-api/debug.h>
29
30 namespace Dali
31 {
32 namespace TizenPlatform
33 {
34 namespace
35 {
36 #if defined(DEBUG_ENABLED)
37 Debug::Filter* gLogFilter = Debug::Filter::New(Debug::NoLogging, false, "LOG_LOADER_WBMP");
38 #endif
39
40 #define IMG_MAX_SIZE 65536
41
42 #define IMG_TOO_BIG(w, h)                                 \
43   ((((unsigned long long)w) * ((unsigned long long)h)) >= \
44    ((1ULL << (29)) - 2048))
45
46 //extract multiple bytes integer , and saved in *data
47 int extractMultiByteInteger(unsigned int* data, void* map, size_t length, size_t* position)
48 {
49   // the header field contains an image type indentifier of multi-byte length(TypeField), an octet of general header info(FixHeaderField)
50   //,  a multi-byte width field(Width) and a multi-byte height field(Height) and so on.
51   // The actual organisation of the image data depends on the image type
52   // for Ext Headers flag (7th bit), 1 = More will follow, 0 = Last octet
53   // so in the for loop, if(buf & 0x80 == 0), loop will be exited
54   int           targetMultiByteInteger = 0, readBufCount;
55   unsigned char buf;
56
57   for(readBufCount = 0;;)
58   {
59     // readBufCount means the count that fetched data from map
60     // extractMultiByteInteger() is to fetch wbmp type , width, and height
61     // for wbmp type, when readBufCount == 1, buf = 0x00, it will exit the loop
62     // for width, it have 4 bytes, so when readBufCount == 4, it must exit the loop
63     // for general width and height, if(buf & 0x80) == 0, then the next byte does not need to fetch again
64     // first step, readBufCount = 1 , read int(4 bytes) to buf, if buf & 0x80 !=0, the buf need to continue to fetch
65     // second step, readBufCount = 2, read next( 4 bytes) to buf, if buf & 0x80 == 0, then assigned the buf to target
66     if((readBufCount++) == 4)
67     {
68       return -1;
69     }
70     if(*position > length)
71     {
72       return -1;
73     }
74     buf                    = reinterpret_cast<unsigned char*>(map)[(*position)++];
75     targetMultiByteInteger = (targetMultiByteInteger << 7) | (buf & 0x7f);
76
77     if((buf & 0x80) == 0)
78     {
79       DALI_LOG_INFO(gLogFilter, Debug::Verbose, "position: %d, readBufCount: %d\n", *position, readBufCount);
80       break;
81     }
82   }
83   *data = targetMultiByteInteger;
84   return 0;
85 }
86
87 } // end unnamed namespace
88
89 bool LoadBitmapFromWbmp(const Dali::ImageLoader::Input& input, Dali::Devel::PixelBuffer& bitmap)
90 {
91   FILE* const fp = input.file;
92   if(fp == NULL)
93   {
94     DALI_LOG_ERROR("Error loading bitmap\n");
95     return false;
96   }
97   Dali::Vector<unsigned char> map;
98   Dali::Vector<unsigned char> surface; //unsigned int
99   size_t                      position = 0;
100
101   unsigned int   w, h;
102   unsigned int   type;
103   unsigned int   line_length;
104   unsigned char* line = NULL;
105   unsigned int   cur  = 0, x, y;
106
107   if(fseek(fp, 0, SEEK_END))
108   {
109     DALI_LOG_ERROR("Error seeking WBMP data\n");
110     return false;
111   }
112   long positionIndicator = ftell(fp);
113
114   unsigned int fsize(0u);
115   if(positionIndicator > -1L)
116   {
117     fsize = static_cast<unsigned int>(positionIndicator);
118   }
119
120   if(0u == fsize)
121   {
122     DALI_LOG_ERROR("Error: filesize is 0!\n");
123     return false;
124   }
125
126   if(fseek(fp, 0, SEEK_SET))
127   {
128     DALI_LOG_ERROR("Error seeking WBMP data\n");
129     return false;
130   }
131   if(fsize <= 4)
132   {
133     DALI_LOG_ERROR("Error: WBMP Raw Data Not Found!\n");
134     return false;
135   }
136   if(fsize > 4096 * 4096 * 4)
137   {
138     DALI_LOG_ERROR("Error: WBMP size is too large!\n");
139     return false;
140   }
141   map.ResizeUninitialized(fsize);
142
143   if(fread(&map[0], 1, fsize, fp) != fsize)
144   {
145     DALI_LOG_WARNING("image file read opeation error!\n");
146     return false;
147   }
148
149   if(extractMultiByteInteger(&type, &map[0], fsize, &position) < 0)
150   {
151     return false;
152   }
153
154   position++; /* skipping one byte */
155
156   if(extractMultiByteInteger(&w, &map[0], fsize, &position) < 0)
157   {
158     return false;
159   }
160   if(extractMultiByteInteger(&h, &map[0], fsize, &position) < 0)
161   {
162     return false;
163   }
164   if(type != 0)
165   {
166     DALI_LOG_ERROR("Unknown Format!\n");
167     return false;
168   }
169
170   if((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE))
171   {
172     return false;
173   }
174
175   surface.ResizeUninitialized(w * h); //(w * h * 4);
176   memset(&surface[0], 0, w * h);      // w * h * 4
177
178   line_length = (w + 7) >> 3;
179   for(y = 0; y < h; y++)
180   {
181     if(position + line_length > fsize)
182     {
183       return false;
184     }
185     line = &map[0] + position;
186     position += line_length;
187     for(x = 0; x < w; x++)
188     {
189       int idx    = x >> 3;
190       int offset = 1 << (0x07 - (x & 0x07));
191       if(line[idx] & offset)
192       {
193         surface[cur] = 0xff; //0xffffffff;
194       }
195       else
196       {
197         surface[cur] = 0x00; //0xff000000;
198       }
199       cur++;
200     }
201   }
202   auto pixels = (bitmap = Dali::Devel::PixelBuffer::New(w, h, Pixel::L8)).GetBuffer();
203
204   memcpy(pixels, &surface[0], w * h); //w * h * 4
205
206   return true;
207 }
208
209 bool LoadWbmpHeader(const Dali::ImageLoader::Input& input, unsigned int& width, unsigned int& height)
210 {
211   FILE* const fp = input.file;
212   if(fp == NULL)
213   {
214     DALI_LOG_ERROR("Error loading bitmap\n");
215     return false;
216   }
217   Dali::Vector<unsigned char> map;
218   size_t                      position = 0;
219
220   unsigned int w, h;
221   unsigned int type;
222   if(fseek(fp, 0, SEEK_END))
223   {
224     DALI_LOG_ERROR("Error seeking WBMP data\n");
225     return false;
226   }
227   long positionIndicator = ftell(fp);
228
229   unsigned int fsize(0u);
230   if(positionIndicator > -1L)
231   {
232     fsize = static_cast<unsigned int>(positionIndicator);
233   }
234
235   if(0u == fsize)
236   {
237     return false;
238   }
239
240   if(fseek(fp, 0, SEEK_SET))
241   {
242     DALI_LOG_ERROR("Error seeking WBMP data\n");
243     return false;
244   }
245   if(fsize <= 4)
246   {
247     DALI_LOG_ERROR("Error: WBMP Raw Data Not Found!\n");
248     return false;
249   }
250
251   // type(1 byte) + fixedheader(1 byte) + width(uint) + height(uint)
252   unsigned int headerSize = 1 + 1 + 4 + 4; // 8 + 8 + 32 + 32;
253   headerSize              = std::min(headerSize, fsize);
254
255   map.ResizeUninitialized(headerSize);
256   if(fread(&map[0], 1, headerSize, fp) != headerSize)
257   {
258     DALI_LOG_WARNING("image file read opeation error!\n");
259     return false;
260   }
261
262   if(extractMultiByteInteger(&type, &map[0], headerSize, &position) < 0)
263   {
264     DALI_LOG_ERROR("Error: unable to read type!\n");
265     return false;
266   }
267   position++; /* skipping one byte */
268   if(type != 0)
269   {
270     DALI_LOG_ERROR("Error: unknown format!\n");
271     return false;
272   }
273   if(extractMultiByteInteger(&w, &map[0], headerSize, &position) < 0)
274   {
275     DALI_LOG_ERROR("Error: can not read width!\n");
276     return false;
277   }
278   if(extractMultiByteInteger(&h, &map[0], headerSize, &position) < 0)
279   {
280     DALI_LOG_ERROR("Error: can not read height!\n");
281     return false;
282   }
283
284   if((w < 1) || (h < 1) || (w > IMG_MAX_SIZE) || (h > IMG_MAX_SIZE))
285   {
286     DALI_LOG_ERROR("Error: file size is not supported!\n");
287     return false;
288   }
289
290   width  = w;
291   height = h;
292   return true;
293 }
294
295 } // namespace TizenPlatform
296 } // namespace Dali