Merge remote-tracking branch 'origin/tizen' into devel/new_mesh
[platform/core/uifw/dali-adaptor.git] / platform-abstractions / tizen / image-loaders / loader-ico.cpp
1 /*
2  * Copyright (c) 2014 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  * Derived from Enlightenment file evas_image_load_ico.c[1]  which is licensed
19  * under the BSD 2-clause license[2] reproduced below.
20  *
21  * [1][http://web.archive.org/web/20141201151111/http://git.enlightenment.org/core/efl.git/tree/src/modules/evas/loaders/ico/evas_image_load_ico.c]
22  * [2][http://web.archive.org/web/20140717012400/https://git.enlightenment.org/core/efl.git/about/]
23  *
24  * Copyright (C) 2002-2012 Carsten Haitzler, Dan Sinclair, Mike Blumenkrantz,
25  * Samsung Electronics and various contributors (see AUTHORS)
26  *
27  * All rights reserved.
28  *
29  * Redistribution and use in source and binary forms, with or without
30  * modification, are permitted provided that the following conditions are met:
31  *
32  *    1. Redistributions of source code must retain the above copyright
33  *       notice, this list of conditions and the following disclaimer.
34  *    2. Redistributions in binary form must reproduce the above copyright
35  *       notice, this list of conditions and the following disclaimer in the
36  *       documentation and/or other materials provided with the distribution.
37  *
38  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
39  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
40  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
41  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
42  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
44  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
45  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
46  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
47  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48  */
49
50 // HEADER
51 #include "loader-ico.h"
52
53 // EXTERNAL INCLUDES
54 #include <cstring>
55 #include <dali/public-api/common/dali-vector.h>
56
57 // INTERNAL INCLUDES
58 #include <dali/integration-api/debug.h>
59 #include <dali/integration-api/bitmap.h>
60
61 namespace Dali
62 {
63 using Integration::Bitmap;
64 using Dali::Integration::PixelBuffer;
65
66 namespace TizenPlatform
67 {
68
69 namespace
70 {
71 //reserved 2 bytes + type 2 bytes + count 2 bytes + count * 16 bytes
72 const unsigned char ICO_FILE_HEADER = 22;
73 // info header 40 bytes = size 4 bytes + width 4 bytes + height 4 bytes + planes 2 bytes + bitcount 2 bytes
74 // + compression 4 bytes + imagesize 4 bytes + xpixelsPerM 4 bytes + ypixelsPerM 4 bytes + colorsUsed 4 bytes + colorImportant 4 bytes
75 // besides, there are rgba color data = numberOfColors * 4 bytes
76 const unsigned char ICO_IMAGE_INFO_HEADER = 40;
77
78 typedef unsigned char  DATA8;
79 #define A_VAL(p) (((DATA8 *)(p))[3])
80
81 #define RGB_JOIN(r,g,b) \
82                 (((r) << 16) + ((g) << 8) + (b))
83
84 #define ARGB_JOIN(a,r,g,b) \
85                 (((a) << 24) + ((r) << 16) + ((g) << 8) + (b))
86 #define IMG_TOO_BIG(w, h) \
87        ((((unsigned long long)w) * ((unsigned long long)h)) >= \
88            ((1ULL << (29 * (sizeof(void *) / 4))) - 2048))
89
90 bool read_ushort(unsigned char *map, size_t length, size_t *position, unsigned short *ret)
91 {
92   unsigned char b[2];
93
94   if (*position + 2 > length)
95   {
96     return false;
97   }
98   b[0] = map[(*position)++];
99   b[1] = map[(*position)++];
100   *ret = (b[1] << 8) | b[0];
101   return true;
102 }
103
104 bool read_uint(unsigned char *map, size_t length, size_t *position, unsigned int *ret)
105 {
106   unsigned char b[4];
107   unsigned int i;
108
109   if (*position + 4 > length)
110   {
111     return false;
112   }
113   for (i = 0; i < 4; i++)
114   {
115     b[i] = map[(*position)++];
116   }
117   *ret = ARGB_JOIN(b[3], b[2], b[1], b[0]);
118   return true;
119 }
120
121 bool read_uchar(unsigned char *map, size_t length, size_t *position, unsigned char *ret)
122 {
123   if (*position + 1 > length)
124   {
125     return false;
126   }
127   *ret = map[(*position)++];
128   return true;
129 }
130
131 bool read_mem(unsigned char *map, size_t length, size_t *position, void *buffer, int size)
132 {
133   if (*position + size > length)
134   {
135     return false;
136   }
137   memcpy(buffer, map + *position, size);
138   *position += size;
139   return true;
140 }
141
142 enum
143 {
144   SMALLEST,
145   BIGGEST,
146   SMALLER,
147   BIGGER
148 };
149
150 enum
151 {
152   ICON = 1,
153   CURSOR = 2
154 };
155
156 struct IcoData
157 {
158   int pdelta;
159   int w, h;
160   int cols;
161   int bpp, planes;
162   int hot_x, hot_y;
163   unsigned int bmoffset, bmsize;
164 };
165
166 bool LoadIcoHeaderHelper( FILE* fp,
167                           IcoData& chosen,
168                           Dali::Vector<unsigned char>& map,
169                           unsigned int& fsize )
170 {
171   memset( &chosen, 0, sizeof(chosen) );
172
173   if(fp == NULL)
174   {
175     DALI_LOG_ERROR("Error loading bitmap\n");
176     return false;
177   }
178   size_t position = 0;
179   unsigned short word;
180   unsigned char byte;
181
182   if( fseek(fp,0,SEEK_END) )
183   {
184     DALI_LOG_ERROR("Error seeking ICO data\n");
185     return false;
186   }
187
188   long positionIndicator = ftell(fp);
189   fsize = 0u;
190
191   if( positionIndicator > -1L )
192   {
193     fsize = static_cast<unsigned int>(positionIndicator);
194   }
195
196   if( 0u == fsize )
197   {
198     return false;
199   }
200
201   if( fseek(fp, 0, SEEK_SET) )
202   {
203     DALI_LOG_ERROR("Error seeking ICO data\n");
204     return false;
205   }
206
207   if (fsize < (ICO_FILE_HEADER + ICO_IMAGE_INFO_HEADER)) //6 + 16 + 40
208   {
209     return false;
210   }
211   map.Resize(fsize);
212
213   if(fread(&map[0], 1, fsize, fp) != fsize)
214   {
215     DALI_LOG_WARNING("image file read opeation error!");
216     return false;
217   }
218
219   int search = BIGGEST;
220   unsigned short reserved, type, count;
221   if (!read_ushort(&map[0], fsize, &position, &reserved))
222   {
223     return false;
224   }
225   if (!read_ushort(&map[0], fsize, &position, &type))
226   {
227     return false;
228   }
229   if (!read_ushort(&map[0], fsize, &position, &count))
230   {
231     return false;
232   }
233   if (!((reserved == 0) &&
234        ((type == ICON) || (type == CURSOR)) && (count != 0)))
235   {
236     return false;
237   }
238   search = BIGGEST;
239   chosen.pdelta = 0;
240   bool have_choice = false;
241
242   for (unsigned short i = 0; i < count; i++)
243   {
244     unsigned char tw = 0, th = 0, tcols = 0;
245     if (!read_uchar(&map[0], fsize, &position, &tw))
246     {
247       return false;
248     }
249     int w = tw;
250     if (w <= 0)
251     {
252       w = 256;
253     }
254     if (!read_uchar(&map[0], fsize, &position, &th))
255     {
256       return false;
257
258     }
259     int h = th;
260     if (h <= 0)
261     {
262       h = 256;
263     }
264     if (!read_uchar(&map[0], fsize, &position, &tcols))
265     {
266       return false;
267     }
268     int cols = tcols;
269     if (cols <= 0)
270     {
271       cols = 256;
272     }
273     if (!read_uchar(&map[0], fsize, &position, &byte))
274     {
275       return false;
276     }
277     if (!read_ushort(&map[0], fsize, &position, &word))
278     {
279       return false;
280     }
281     int planes=0;
282     if (type == 1)
283     {
284       planes = word;
285     }
286     //else hot_x = word;
287     if (!read_ushort(&map[0], fsize, &position, &word))
288     {
289       return false;
290     }
291     int bpp=0;
292     if (type == 1)
293     {
294       bpp = word;
295     }
296     //else hot_y = word;
297     unsigned int bmoffset, bmsize;
298     if (!read_uint(&map[0], fsize, &position, &bmsize))
299     {
300       return false;
301     }
302     if (!read_uint(&map[0], fsize, &position, &bmoffset))
303     {
304       return false;
305     }
306     if ((bmsize <= 0) || (bmoffset <= 0) || (bmoffset >= fsize))
307     {
308       return false;
309     }
310     if (search == BIGGEST)
311     {
312       int pdelta = w * h;
313       if ((!have_choice) ||
314        ((pdelta >= chosen.pdelta) &&
315            (((bpp >= 3) && (bpp >= chosen.bpp)) ||
316                ((bpp < 3) && (cols >= chosen.cols)))))
317       {
318         have_choice = true;
319         chosen.pdelta = pdelta;
320         chosen.w = w;
321         chosen.h = h;
322         chosen.cols = cols;
323         chosen.bpp = bpp;
324         chosen.planes = planes;
325         chosen.bmsize = bmsize;
326         chosen.bmoffset = bmoffset;
327       }
328     }
329   }
330
331   if (chosen.bmoffset == 0)
332   {
333     return false;
334   }
335
336   return true;
337 }
338
339 }//unnamed namespace
340
341 bool LoadIcoHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height )
342 {
343   IcoData chosen;
344   Dali::Vector<unsigned char> map;
345   unsigned int fsize;
346   FILE* const fp = input.file;
347
348   if ( false == LoadIcoHeaderHelper(fp, chosen, map, fsize) )
349   {
350     return false;
351   }
352
353   width = chosen.w;
354   height = chosen.h;
355
356   return true;
357 }
358
359 bool LoadBitmapFromIco( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap )
360 {
361   IcoData chosen;
362   Dali::Vector<unsigned char> map;
363   unsigned int fsize;
364   FILE* const fp = input.file;
365
366   if ( false == LoadIcoHeaderHelper(fp, chosen, map, fsize) )
367   {
368     return false;
369   }
370
371   Dali::Vector<unsigned int> pal;
372   Dali::Vector<unsigned int> surface;
373   Dali::Vector<unsigned char> maskbuf;
374   Dali::Vector<unsigned char> pixbuf;
375   pal.Resize(256 * 4);
376
377   unsigned int dword;
378   unsigned short word;
379
380   int diff_size = 0;
381   unsigned int* pix;
382   PixelBuffer* pixels = NULL;
383
384   size_t position = chosen.bmoffset;//22 == position
385
386   int w = chosen.w;
387   int h = chosen.h;
388   int cols = chosen.cols;
389
390   // read bmp header time... let's do some checking
391   if (!read_uint(&map[0], fsize, &position, &dword))
392   {
393     return false; // headersize - dont care
394   }
395   if (!read_uint(&map[0], fsize, &position, &dword))
396   {
397     return false; // width
398   }
399   if (dword > 0)
400   {
401     if ((int)dword != w)
402     {
403       w = dword;
404       diff_size = 1;
405     }
406   }
407   if (!read_uint(&map[0], fsize, &position, &dword))
408   {
409     return false; // height
410   }
411   if (dword > 0)
412   {
413     if ((int)dword != (h * 2))
414     {
415       h = dword / 2;
416       diff_size = 1;
417     }
418   }
419   if (diff_size)
420   {
421     DALI_LOG_WARNING("Broken ICO file!");
422   }
423   if (!read_ushort(&map[0], fsize, &position, &word))
424   {
425     return false; // planes
426   }
427   //planes2 = word;
428   if (!read_ushort(&map[0], fsize, &position, &word))
429   {
430     return false; // bitcount
431   }
432   unsigned int bitcount = word;
433   if (!read_uint(&map[0], fsize, &position, &dword))
434   {
435     return false; // compression
436   }
437   //compression = dword;
438   if (!read_uint(&map[0], fsize, &position, &dword))
439   {
440     return false; // imagesize
441   }
442   //imagesize = dword;
443   if (!read_uint(&map[0], fsize, &position, &dword))
444   {
445     return false; // z pixels per m
446   }
447   if (!read_uint(&map[0], fsize, &position, &dword))
448   {
449     return false; // y pizels per m
450   }
451   if (!read_uint(&map[0], fsize, &position, &dword))
452   {
453     return false; // colors used
454   }
455   //colorsused = dword;
456   if (!read_uint(&map[0], fsize, &position, &dword))
457   {
458     return false; // colors important
459   }
460   //colorsimportant = dword;
461   surface.Resize(w * h * 4);
462
463   memset(&surface[0], 0, w * h * 4);
464
465   for(int i = 0; i < cols ; i ++)
466   {
467     unsigned char a, r, g, b;
468
469     if (!read_uchar(&map[0], fsize, &position, &b))
470     {
471       return false;
472     }
473     if (!read_uchar(&map[0], fsize, &position, &g))
474     {
475       return false;
476     }
477     if (!read_uchar(&map[0], fsize, &position, &r))
478     {
479       return false;
480     }
481     if (!read_uchar(&map[0], fsize, &position, &a))
482     {
483       return false;
484     }
485     a = 0xff;
486     pal[i] = ARGB_JOIN(a, r, g, b);
487   }
488
489   if (!((bitcount == 1) || (bitcount == 4) || (bitcount == 8) ||
490        (bitcount == 24) || (bitcount == 32)))
491   {
492     return false;
493   }
494   int stride = ((w + 31) / 32);
495
496   maskbuf.Resize(stride * h);
497   pixbuf.Resize(stride * 32 * 4); // more than enough
498
499   unsigned int none_zero_alpha = 0;
500   if (bitcount == 1)
501   {
502     int pstride = stride * 4;
503     for (int i = 0; i < h; i++)
504     {
505       pix = &surface[0] + ((h - 1 - i) * w);
506
507       if (!read_mem(&map[0], fsize, &position, &pixbuf[0], pstride))
508       {
509         return false;
510       }
511       unsigned char* p = &pixbuf[0];
512       if (i >= (int)h)
513       {
514         continue;
515       }
516       for (int j = 0; j < w; j++)
517       {
518         if (j >= (int)w)
519         {
520           break;
521         }
522         if ((j & 0x7) == 0x0)
523         {
524           *pix = pal[*p >> 7];
525         }
526         else if ((j & 0x7) == 0x1)
527         {
528           *pix = pal[(*p >> 6) & 0x1];
529         }
530         else if ((j & 0x7) == 0x2)
531         {
532           *pix = pal[(*p >> 5) & 0x1];
533         }
534         else if ((j & 0x7) == 0x3)
535         {
536           *pix = pal[(*p >> 4) & 0x1];
537         }
538         else if ((j & 0x7) == 0x4)
539         {
540           *pix = pal[(*p >> 3) & 0x1];
541         }
542         else if ((j & 0x7) == 0x5)
543         {
544           *pix = pal[(*p >> 2) & 0x1];
545         }
546         else if ((j & 0x7) == 0x6)
547         {
548           *pix = pal[(*p >> 1) & 0x1];
549         }
550         else
551         {
552           *pix = pal[*p & 0x1];
553           p++;
554         }
555         pix++;
556       }
557     }
558   }
559   else if (bitcount == 4)
560   {
561     int pstride = ((w + 7) / 8) * 4;
562     for (int i = 0; i < h; i++)
563     {
564       pix = &surface[0] + ((h - 1 - i) * w);
565
566       if (!read_mem(&map[0], fsize, &position, &pixbuf[0], pstride))
567       {
568         return false;
569       }
570       unsigned char* p = &pixbuf[0];
571       if (i >= (int)h)
572       {
573         continue;
574       }
575       for (int j = 0; j < w; j++)
576       {
577         if (j >= (int)w)
578         {
579           break;
580         }
581         if ((j & 0x1) == 0x1)
582         {
583           *pix = pal[*p & 0x0f];
584           p++;
585         }
586         else
587         {
588           *pix = pal[*p >> 4];
589         }
590         pix++;
591       }
592     }
593   }
594   else if (bitcount == 8)
595   {
596     int pstride = ((w + 3) / 4) * 4;
597     for (int i = 0; i < h; i++)
598     {
599       pix = &surface[0] + ((h - 1 - i) * w);
600
601       if (!read_mem(&map[0], fsize, &position, &pixbuf[0], pstride))
602       {
603         return false;
604       }
605       unsigned char* p = &pixbuf[0];
606       if (i >= (int)h)
607       {
608         continue;
609       }
610       for (int j = 0; j < w; j++)
611       {
612         if (j >= (int)w)
613         {
614           break;
615         }
616         *pix = pal[*p];
617         p++;
618         pix++;
619       }
620     }
621   }
622   else if (bitcount == 24)
623   {
624     int pstride = w * 3;
625     for (int i = 0; i < h; i++)
626     {
627       pix = &surface[0] + ((h - 1 - i) * w);
628
629       if (!read_mem(&map[0], fsize, &position, &pixbuf[0], pstride))
630       {
631         return false;
632       }
633       unsigned char* p = &pixbuf[0];
634       if (i >= (int)h)
635       {
636         continue;
637       }
638       for (int j = 0; j < w; j++)
639       {
640         unsigned char a, r, g, b;
641
642         if (j >= (int)w)
643         {
644           break;
645         }
646         b = p[0];
647         g = p[1];
648         r = p[2];
649         p += 3;
650         a = 0xff;
651         *pix = ARGB_JOIN(a, r, g, b);
652         pix++;
653       }
654     }
655   }
656   else if (bitcount == 32)
657   {
658     int pstride = w * 4;
659     for (int i = 0; i < h; i++)
660     {
661       pix = &surface[0] + ((h - 1 - i) * w);
662
663       if (!read_mem(&map[0], fsize, &position, &pixbuf[0], pstride))
664       {
665         return false;
666       }
667       unsigned char* p = &pixbuf[0];
668       if (i >= (int)h)
669       {
670         continue;
671       }
672       for (int j = 0; j < w; j++)
673       {
674         unsigned char a, r, g, b;
675         if (j >= (int)w)
676         {
677           break;
678         }
679         b = p[0];
680         g = p[1];
681         r = p[2];
682         a = p[3];
683         p += 4;
684         if (a)
685         {
686           none_zero_alpha = 1;
687         }
688         *pix = ARGB_JOIN(a, r, g, b);
689         pix++;
690       }
691     }
692   }
693   if (!none_zero_alpha)
694   {
695     if (!read_mem(&map[0], fsize, &position, &maskbuf[0], stride * 4 * h))
696     {
697       return false;
698     }
699     // apply mask
700     for (int i = 0; i < h; i++)
701     {
702       unsigned char *m;
703
704       pix = &surface[0] + ((h - 1 - i) * w);
705
706       m = &maskbuf[0] + (stride * i * 4);
707       if (i >= (int)h)
708       {
709         continue;
710       }
711       for (int j = 0; j < w; j++)
712       {
713         if (j >= (int)w)
714         {
715           break;
716         }
717         if (*m & (1 << (7 - (j & 0x7))))
718         {
719           A_VAL(pix) = 0x00;
720         }
721         else
722         {
723           A_VAL(pix) = 0xff;
724         }
725         if ((j & 0x7) == 0x7)
726         {
727           m++;
728         }
729         pix++;
730       }
731     }
732   }
733   pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(Pixel::RGBA8888, w, h);
734   memset(pixels, 0, w * h * 4);
735   memcpy(pixels, (unsigned char*)&surface[0], w * h * 4);
736
737   return true;
738 }
739
740 }
741
742 }