1 /* Copyright  (C) 2010-2020 The RetroArch team
2  *
3  * ---------------------------------------------------------------------------------------
4  * The following license statement only applies to this file (rpng.c).
5  * ---------------------------------------------------------------------------------------
6  *
7  * Permission is hereby granted, free of charge,
8  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 #ifdef DEBUG
24 #include <stdio.h>
25 #endif
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #ifdef GEKKO
31 #include <malloc.h>
32 #endif
33 
34 #include <boolean.h>
35 #include <formats/image.h>
36 #include <formats/rpng.h>
37 #include <streams/trans_stream.h>
38 #include <string/stdstring.h>
39 
40 #include "rpng_internal.h"
41 
42 enum png_ihdr_color_type
43 {
44    PNG_IHDR_COLOR_GRAY       = 0,
45    PNG_IHDR_COLOR_RGB        = 2,
46    PNG_IHDR_COLOR_PLT        = 3,
47    PNG_IHDR_COLOR_GRAY_ALPHA = 4,
48    PNG_IHDR_COLOR_RGBA       = 6
49 };
50 
51 enum png_line_filter
52 {
53    PNG_FILTER_NONE = 0,
54    PNG_FILTER_SUB,
55    PNG_FILTER_UP,
56    PNG_FILTER_AVERAGE,
57    PNG_FILTER_PAETH
58 };
59 
60 enum png_chunk_type
61 {
62    PNG_CHUNK_NOOP = 0,
63    PNG_CHUNK_ERROR,
64    PNG_CHUNK_IHDR,
65    PNG_CHUNK_IDAT,
66    PNG_CHUNK_PLTE,
67    PNG_CHUNK_tRNS,
68    PNG_CHUNK_IEND
69 };
70 
71 struct adam7_pass
72 {
73    unsigned x;
74    unsigned y;
75    unsigned stride_x;
76    unsigned stride_y;
77 };
78 
79 struct idat_buffer
80 {
81    uint8_t *data;
82    size_t size;
83 };
84 
85 struct rpng_process
86 {
87    uint32_t *data;
88    uint32_t *palette;
89    void *stream;
90    const struct trans_stream_backend *stream_backend;
91    uint8_t *prev_scanline;
92    uint8_t *decoded_scanline;
93    uint8_t *inflate_buf;
94    size_t restore_buf_size;
95    size_t adam7_restore_buf_size;
96    size_t data_restore_buf_size;
97    size_t inflate_buf_size;
98    size_t avail_in;
99    size_t avail_out;
100    size_t total_out;
101    size_t pass_size;
102    struct png_ihdr ihdr; /* uint32_t alignment */
103    unsigned bpp;
104    unsigned pitch;
105    unsigned h;
106    unsigned pass_width;
107    unsigned pass_height;
108    unsigned pass_pos;
109    bool inflate_initialized;
110    bool adam7_pass_initialized;
111    bool pass_initialized;
112 };
113 
114 struct rpng
115 {
116    struct rpng_process *process;
117    uint8_t *buff_data;
118    uint8_t *buff_end;
119    struct idat_buffer idat_buf; /* ptr alignment */
120    struct png_ihdr ihdr; /* uint32 alignment */
121    uint32_t palette[256];
122    bool has_ihdr;
123    bool has_idat;
124    bool has_iend;
125    bool has_plte;
126    bool has_trns;
127 };
128 
129 static const struct adam7_pass passes[] = {
130    { 0, 0, 8, 8 },
131    { 4, 0, 8, 8 },
132    { 0, 4, 4, 8 },
133    { 2, 0, 4, 4 },
134    { 0, 2, 2, 4 },
135    { 1, 0, 2, 2 },
136    { 0, 1, 1, 2 },
137 };
138 
dword_be(const uint8_t * buf)139 static INLINE uint32_t dword_be(const uint8_t *buf)
140 {
141    return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] << 0);
142 }
143 
144 #if defined(DEBUG) || defined(RPNG_TEST)
png_process_ihdr(struct png_ihdr * ihdr)145 static bool png_process_ihdr(struct png_ihdr *ihdr)
146 {
147    unsigned i;
148    uint8_t ihdr_depth = ihdr->depth;
149 
150    switch (ihdr->color_type)
151    {
152       case PNG_IHDR_COLOR_RGB:
153       case PNG_IHDR_COLOR_GRAY_ALPHA:
154       case PNG_IHDR_COLOR_RGBA:
155          if (ihdr_depth != 8 && ihdr_depth != 16)
156          {
157             fprintf(stderr, "[RPNG]: Error in line %d.\n", __LINE__);
158             return false;
159          }
160          break;
161       case PNG_IHDR_COLOR_GRAY:
162          /* Valid bitdepths are: 1, 2, 4, 8, 16 */
163          if (ihdr_depth > 16 || (0x977F7FFF << ihdr_depth) & 0x80000000)
164          {
165             fprintf(stderr, "[RPNG]: Error in line %d.\n", __LINE__);
166             return false;
167          }
168          break;
169       case PNG_IHDR_COLOR_PLT:
170          /* Valid bitdepths are: 1, 2, 4, 8 */
171          if (ihdr_depth > 8 || (0x977F7FFF << ihdr_depth)  & 0x80000000)
172          {
173             fprintf(stderr, "[RPNG]: Error in line %d.\n", __LINE__);
174             return false;
175          }
176          break;
177       default:
178          fprintf(stderr, "[RPNG]: Error in line %d.\n", __LINE__);
179          return false;
180    }
181 
182 #ifdef RPNG_TEST
183    fprintf(stderr, "IHDR: (%u x %u), bpc = %u, palette = %s, color = %s, alpha = %s, adam7 = %s.\n",
184          ihdr->width, ihdr->height,
185          ihdr_depth, (ihdr->color_type == PNG_IHDR_COLOR_PLT) ? "yes" : "no",
186          (ihdr->color_type & PNG_IHDR_COLOR_RGB)              ? "yes" : "no",
187          (ihdr->color_type & PNG_IHDR_COLOR_GRAY_ALPHA)       ? "yes" : "no",
188          ihdr->interlace == 1 ? "yes" : "no");
189 #endif
190 
191    return true;
192 }
193 #else
png_process_ihdr(struct png_ihdr * ihdr)194 static bool png_process_ihdr(struct png_ihdr *ihdr)
195 {
196    uint8_t ihdr_depth = ihdr->depth;
197 
198    switch (ihdr->color_type)
199    {
200       case PNG_IHDR_COLOR_RGB:
201       case PNG_IHDR_COLOR_GRAY_ALPHA:
202       case PNG_IHDR_COLOR_RGBA:
203          if (ihdr_depth != 8 && ihdr_depth != 16)
204             return false;
205          break;
206       case PNG_IHDR_COLOR_GRAY:
207          /* Valid bitdepths are: 1, 2, 4, 8, 16 */
208          if (ihdr_depth > 16 || (0x977F7FFF << ihdr_depth) & 0x80000000)
209             return false;
210          break;
211       case PNG_IHDR_COLOR_PLT:
212          /* Valid bitdepths are: 1, 2, 4, 8 */
213          if (ihdr_depth > 8 || (0x977F7FFF << ihdr_depth)  & 0x80000000)
214             return false;
215          break;
216       default:
217          return false;
218    }
219 
220    return true;
221 }
222 #endif
223 
png_reverse_filter_copy_line_rgb(uint32_t * data,const uint8_t * decoded,unsigned width,unsigned bpp)224 static void png_reverse_filter_copy_line_rgb(uint32_t *data,
225       const uint8_t *decoded, unsigned width, unsigned bpp)
226 {
227    unsigned i;
228 
229    bpp /= 8;
230 
231    for (i = 0; i < width; i++)
232    {
233       uint32_t r, g, b;
234 
235       r        = *decoded;
236       decoded += bpp;
237       g        = *decoded;
238       decoded += bpp;
239       b        = *decoded;
240       decoded += bpp;
241       data[i]  = (0xffu << 24) | (r << 16) | (g << 8) | (b << 0);
242    }
243 }
244 
png_reverse_filter_copy_line_rgba(uint32_t * data,const uint8_t * decoded,unsigned width,unsigned bpp)245 static void png_reverse_filter_copy_line_rgba(uint32_t *data,
246       const uint8_t *decoded, unsigned width, unsigned bpp)
247 {
248    unsigned i;
249 
250    bpp /= 8;
251 
252    for (i = 0; i < width; i++)
253    {
254       uint32_t r, g, b, a;
255       r        = *decoded;
256       decoded += bpp;
257       g        = *decoded;
258       decoded += bpp;
259       b        = *decoded;
260       decoded += bpp;
261       a        = *decoded;
262       decoded += bpp;
263       data[i]  = (a << 24) | (r << 16) | (g << 8) | (b << 0);
264    }
265 }
266 
png_reverse_filter_copy_line_bw(uint32_t * data,const uint8_t * decoded,unsigned width,unsigned depth)267 static void png_reverse_filter_copy_line_bw(uint32_t *data,
268       const uint8_t *decoded, unsigned width, unsigned depth)
269 {
270    unsigned i, bit;
271    static const unsigned mul_table[] = { 0, 0xff, 0x55, 0, 0x11, 0, 0, 0, 0x01 };
272    unsigned mul, mask;
273 
274    if (depth == 16)
275    {
276       for (i = 0; i < width; i++)
277       {
278          uint32_t val = decoded[i << 1];
279          data[i]      = (val * 0x010101) | (0xffu << 24);
280       }
281       return;
282    }
283 
284    mul  = mul_table[depth];
285    mask = (1 << depth) - 1;
286    bit  = 0;
287 
288    for (i = 0; i < width; i++, bit += depth)
289    {
290       unsigned byte = bit >> 3;
291       unsigned val  = decoded[byte] >> (8 - depth - (bit & 7));
292 
293       val          &= mask;
294       val          *= mul;
295       data[i]       = (val * 0x010101) | (0xffu << 24);
296    }
297 }
298 
png_reverse_filter_copy_line_gray_alpha(uint32_t * data,const uint8_t * decoded,unsigned width,unsigned bpp)299 static void png_reverse_filter_copy_line_gray_alpha(uint32_t *data,
300       const uint8_t *decoded, unsigned width,
301       unsigned bpp)
302 {
303    unsigned i;
304 
305    bpp /= 8;
306 
307    for (i = 0; i < width; i++)
308    {
309       uint32_t gray, alpha;
310 
311       gray     = *decoded;
312       decoded += bpp;
313       alpha    = *decoded;
314       decoded += bpp;
315 
316       data[i]  = (gray * 0x010101) | (alpha << 24);
317    }
318 }
319 
png_reverse_filter_copy_line_plt(uint32_t * data,const uint8_t * decoded,unsigned width,unsigned depth,const uint32_t * palette)320 static void png_reverse_filter_copy_line_plt(uint32_t *data,
321       const uint8_t *decoded, unsigned width,
322       unsigned depth, const uint32_t *palette)
323 {
324    switch (depth)
325    {
326       case 1:
327          {
328             unsigned w = width / 8;
329             unsigned i;
330 
331             for (i = 0; i < w; i++, decoded++)
332             {
333                *data++ = palette[(*decoded >> 7) & 1];
334                *data++ = palette[(*decoded >> 6) & 1];
335                *data++ = palette[(*decoded >> 5) & 1];
336                *data++ = palette[(*decoded >> 4) & 1];
337                *data++ = palette[(*decoded >> 3) & 1];
338                *data++ = palette[(*decoded >> 2) & 1];
339                *data++ = palette[(*decoded >> 1) & 1];
340                *data++ = palette[*decoded & 1];
341             }
342 
343             switch (width & 7)
344             {
345                case 7:
346                   data[6] = palette[(*decoded >> 1) & 1];
347                case 6:
348                   data[5] = palette[(*decoded >> 2) & 1];
349                case 5:
350                   data[4] = palette[(*decoded >> 3) & 1];
351                case 4:
352                   data[3] = palette[(*decoded >> 4) & 1];
353                case 3:
354                   data[2] = palette[(*decoded >> 5) & 1];
355                case 2:
356                   data[1] = palette[(*decoded >> 6) & 1];
357                case 1:
358                   data[0] = palette[(*decoded >> 7) & 1];
359                   break;
360             }
361          }
362          break;
363 
364       case 2:
365          {
366             unsigned w = width / 4;
367             unsigned i;
368 
369             for (i = 0; i < w; i++, decoded++)
370             {
371                *data++ = palette[(*decoded >> 6) & 3];
372                *data++ = palette[(*decoded >> 4) & 3];
373                *data++ = palette[(*decoded >> 2) & 3];
374                *data++ = palette[*decoded & 3];
375             }
376 
377             switch (width & 3)
378             {
379                case 3:
380                   data[2] = palette[(*decoded >> 2) & 3];
381                case 2:
382                   data[1] = palette[(*decoded >> 4) & 3];
383                case 1:
384                   data[0] = palette[(*decoded >> 6) & 3];
385                   break;
386             }
387          }
388          break;
389 
390       case 4:
391          {
392             unsigned w = width / 2;
393             unsigned i;
394 
395             for (i = 0; i < w; i++, decoded++)
396             {
397                *data++ = palette[*decoded >> 4];
398                *data++ = palette[*decoded & 0x0f];
399             }
400 
401             if (width & 1)
402                *data = palette[*decoded >> 4];
403          }
404          break;
405 
406       case 8:
407          {
408             unsigned i;
409 
410             for (i = 0; i < width; i++, decoded++, data++)
411                *data = palette[*decoded];
412          }
413          break;
414    }
415 }
416 
png_pass_geom(const struct png_ihdr * ihdr,unsigned width,unsigned height,unsigned * bpp_out,unsigned * pitch_out,size_t * pass_size)417 static void png_pass_geom(const struct png_ihdr *ihdr,
418       unsigned width, unsigned height,
419       unsigned *bpp_out, unsigned *pitch_out, size_t *pass_size)
420 {
421    unsigned bpp   = 0;
422    unsigned pitch = 0;
423 
424    switch (ihdr->color_type)
425    {
426       case PNG_IHDR_COLOR_GRAY:
427          bpp   = (ihdr->depth + 7) / 8;
428          pitch = (ihdr->width * ihdr->depth + 7) / 8;
429          break;
430       case PNG_IHDR_COLOR_RGB:
431          bpp   = (ihdr->depth * 3 + 7) / 8;
432          pitch = (ihdr->width * ihdr->depth * 3 + 7) / 8;
433          break;
434       case PNG_IHDR_COLOR_PLT:
435          bpp   = (ihdr->depth + 7) / 8;
436          pitch = (ihdr->width * ihdr->depth + 7) / 8;
437          break;
438       case PNG_IHDR_COLOR_GRAY_ALPHA:
439          bpp   = (ihdr->depth * 2 + 7) / 8;
440          pitch = (ihdr->width * ihdr->depth * 2 + 7) / 8;
441          break;
442       case PNG_IHDR_COLOR_RGBA:
443          bpp   = (ihdr->depth * 4 + 7) / 8;
444          pitch = (ihdr->width * ihdr->depth * 4 + 7) / 8;
445          break;
446       default:
447          break;
448    }
449 
450    if (pass_size)
451       *pass_size = (pitch + 1) * ihdr->height;
452    if (bpp_out)
453       *bpp_out   = bpp;
454    if (pitch_out)
455       *pitch_out = pitch;
456 }
457 
png_reverse_filter_adam7_deinterlace_pass(uint32_t * data,const struct png_ihdr * ihdr,const uint32_t * input,unsigned pass_width,unsigned pass_height,const struct adam7_pass * pass)458 static void png_reverse_filter_adam7_deinterlace_pass(uint32_t *data,
459       const struct png_ihdr *ihdr,
460       const uint32_t *input, unsigned pass_width, unsigned pass_height,
461       const struct adam7_pass *pass)
462 {
463    unsigned x, y;
464 
465    data += pass->y * ihdr->width + pass->x;
466 
467    for (y = 0; y < pass_height;
468          y++, data += ihdr->width * pass->stride_y, input += pass_width)
469    {
470       uint32_t *out = data;
471 
472       for (x = 0; x < pass_width; x++, out += pass->stride_x)
473          *out = input[x];
474    }
475 }
476 
png_reverse_filter_deinit(struct rpng_process * pngp)477 static void png_reverse_filter_deinit(struct rpng_process *pngp)
478 {
479    if (!pngp)
480       return;
481    if (pngp->decoded_scanline)
482       free(pngp->decoded_scanline);
483    pngp->decoded_scanline = NULL;
484    if (pngp->prev_scanline)
485       free(pngp->prev_scanline);
486    pngp->prev_scanline    = NULL;
487 
488    pngp->pass_initialized = false;
489    pngp->h                = 0;
490 }
491 
png_reverse_filter_init(const struct png_ihdr * ihdr,struct rpng_process * pngp)492 static int png_reverse_filter_init(const struct png_ihdr *ihdr,
493       struct rpng_process *pngp)
494 {
495    size_t pass_size;
496 
497    if (!pngp->adam7_pass_initialized && ihdr->interlace)
498    {
499       if (ihdr->width <= passes[pngp->pass_pos].x ||
500             ihdr->height <= passes[pngp->pass_pos].y) /* Empty pass */
501          return 1;
502 
503       pngp->pass_width  = (ihdr->width -
504             passes[pngp->pass_pos].x + passes[pngp->pass_pos].stride_x - 1) / passes[pngp->pass_pos].stride_x;
505       pngp->pass_height = (ihdr->height - passes[pngp->pass_pos].y +
506             passes[pngp->pass_pos].stride_y - 1) / passes[pngp->pass_pos].stride_y;
507 
508       pngp->data = (uint32_t*)malloc(
509             pngp->pass_width * pngp->pass_height * sizeof(uint32_t));
510 
511       if (!pngp->data)
512          return -1;
513 
514       pngp->ihdr        = *ihdr;
515       pngp->ihdr.width  = pngp->pass_width;
516       pngp->ihdr.height = pngp->pass_height;
517 
518       png_pass_geom(&pngp->ihdr, pngp->pass_width,
519             pngp->pass_height, NULL, NULL, &pngp->pass_size);
520 
521       if (pngp->pass_size > pngp->total_out)
522       {
523          free(pngp->data);
524          pngp->data = NULL;
525          return -1;
526       }
527 
528       pngp->adam7_pass_initialized = true;
529 
530       return 0;
531    }
532 
533    if (pngp->pass_initialized)
534       return 0;
535 
536    png_pass_geom(ihdr, ihdr->width, ihdr->height, &pngp->bpp, &pngp->pitch, &pass_size);
537 
538    if (pngp->total_out < pass_size)
539       return -1;
540 
541    pngp->restore_buf_size      = 0;
542    pngp->data_restore_buf_size = 0;
543    pngp->prev_scanline         = (uint8_t*)calloc(1, pngp->pitch);
544    pngp->decoded_scanline      = (uint8_t*)calloc(1, pngp->pitch);
545 
546    if (!pngp->prev_scanline || !pngp->decoded_scanline)
547       goto error;
548 
549    pngp->h = 0;
550    pngp->pass_initialized = true;
551 
552    return 0;
553 
554 error:
555    png_reverse_filter_deinit(pngp);
556    return -1;
557 }
558 
png_reverse_filter_copy_line(uint32_t * data,const struct png_ihdr * ihdr,struct rpng_process * pngp,unsigned filter)559 static int png_reverse_filter_copy_line(uint32_t *data, const struct png_ihdr *ihdr,
560       struct rpng_process *pngp, unsigned filter)
561 {
562    unsigned i;
563 
564    switch (filter)
565    {
566       case PNG_FILTER_NONE:
567          memcpy(pngp->decoded_scanline, pngp->inflate_buf, pngp->pitch);
568          break;
569       case PNG_FILTER_SUB:
570          for (i = 0; i < pngp->bpp; i++)
571             pngp->decoded_scanline[i] = pngp->inflate_buf[i];
572          for (i = pngp->bpp; i < pngp->pitch; i++)
573             pngp->decoded_scanline[i] = pngp->decoded_scanline[i - pngp->bpp] + pngp->inflate_buf[i];
574          break;
575       case PNG_FILTER_UP:
576          for (i = 0; i < pngp->pitch; i++)
577             pngp->decoded_scanline[i] = pngp->prev_scanline[i] + pngp->inflate_buf[i];
578          break;
579       case PNG_FILTER_AVERAGE:
580          for (i = 0; i < pngp->bpp; i++)
581          {
582             uint8_t avg = pngp->prev_scanline[i] >> 1;
583             pngp->decoded_scanline[i] = avg + pngp->inflate_buf[i];
584          }
585          for (i = pngp->bpp; i < pngp->pitch; i++)
586          {
587             uint8_t avg = (pngp->decoded_scanline[i - pngp->bpp] + pngp->prev_scanline[i]) >> 1;
588             pngp->decoded_scanline[i] = avg + pngp->inflate_buf[i];
589          }
590          break;
591       case PNG_FILTER_PAETH:
592          for (i = 0; i < pngp->bpp; i++)
593             pngp->decoded_scanline[i] = paeth(0, pngp->prev_scanline[i], 0) + pngp->inflate_buf[i];
594          for (i = pngp->bpp; i < pngp->pitch; i++)
595             pngp->decoded_scanline[i] = paeth(pngp->decoded_scanline[i - pngp->bpp],
596                   pngp->prev_scanline[i], pngp->prev_scanline[i - pngp->bpp]) + pngp->inflate_buf[i];
597          break;
598 
599       default:
600          return IMAGE_PROCESS_ERROR_END;
601    }
602 
603    switch (ihdr->color_type)
604    {
605       case PNG_IHDR_COLOR_GRAY:
606          png_reverse_filter_copy_line_bw(data, pngp->decoded_scanline, ihdr->width, ihdr->depth);
607          break;
608       case PNG_IHDR_COLOR_RGB:
609          png_reverse_filter_copy_line_rgb(data, pngp->decoded_scanline, ihdr->width, ihdr->depth);
610          break;
611       case PNG_IHDR_COLOR_PLT:
612          png_reverse_filter_copy_line_plt(data, pngp->decoded_scanline, ihdr->width,
613                ihdr->depth, pngp->palette);
614          break;
615       case PNG_IHDR_COLOR_GRAY_ALPHA:
616          png_reverse_filter_copy_line_gray_alpha(data, pngp->decoded_scanline, ihdr->width,
617                ihdr->depth);
618          break;
619       case PNG_IHDR_COLOR_RGBA:
620          png_reverse_filter_copy_line_rgba(data, pngp->decoded_scanline, ihdr->width, ihdr->depth);
621          break;
622    }
623 
624    memcpy(pngp->prev_scanline, pngp->decoded_scanline, pngp->pitch);
625 
626    return IMAGE_PROCESS_NEXT;
627 }
628 
png_reverse_filter_regular_iterate(uint32_t ** data,const struct png_ihdr * ihdr,struct rpng_process * pngp)629 static int png_reverse_filter_regular_iterate(uint32_t **data, const struct png_ihdr *ihdr,
630       struct rpng_process *pngp)
631 {
632    int ret = IMAGE_PROCESS_END;
633 
634    if (pngp->h < ihdr->height)
635    {
636       unsigned filter = *pngp->inflate_buf++;
637       pngp->restore_buf_size += 1;
638       ret = png_reverse_filter_copy_line(*data,
639             ihdr, pngp, filter);
640    }
641 
642    if (ret == IMAGE_PROCESS_END || ret == IMAGE_PROCESS_ERROR_END)
643       goto end;
644 
645    pngp->h++;
646    pngp->inflate_buf           += pngp->pitch;
647    pngp->restore_buf_size      += pngp->pitch;
648 
649    *data                       += ihdr->width;
650    pngp->data_restore_buf_size += ihdr->width;
651 
652    return IMAGE_PROCESS_NEXT;
653 
654 end:
655    png_reverse_filter_deinit(pngp);
656 
657    pngp->inflate_buf -= pngp->restore_buf_size;
658    *data             -= pngp->data_restore_buf_size;
659    pngp->data_restore_buf_size = 0;
660    return ret;
661 }
662 
png_reverse_filter_adam7_iterate(uint32_t ** data_,const struct png_ihdr * ihdr,struct rpng_process * pngp)663 static int png_reverse_filter_adam7_iterate(uint32_t **data_,
664       const struct png_ihdr *ihdr,
665       struct rpng_process *pngp)
666 {
667    int        ret = 0;
668    bool   to_next = pngp->pass_pos < ARRAY_SIZE(passes);
669    uint32_t *data = *data_;
670 
671    if (!to_next)
672       return IMAGE_PROCESS_END;
673 
674    ret = png_reverse_filter_init(ihdr, pngp);
675 
676    if (ret == 1)
677       return IMAGE_PROCESS_NEXT;
678    if (ret == -1)
679       return IMAGE_PROCESS_ERROR_END;
680 
681    if (png_reverse_filter_init(&pngp->ihdr, pngp) == -1)
682       return IMAGE_PROCESS_ERROR;
683 
684    do
685    {
686       ret = png_reverse_filter_regular_iterate(&pngp->data,
687             &pngp->ihdr, pngp);
688    } while (ret == IMAGE_PROCESS_NEXT);
689 
690    if (ret == IMAGE_PROCESS_ERROR || ret == IMAGE_PROCESS_ERROR_END)
691       return IMAGE_PROCESS_ERROR;
692 
693    pngp->inflate_buf            += pngp->pass_size;
694    pngp->adam7_restore_buf_size += pngp->pass_size;
695 
696    pngp->total_out              -= pngp->pass_size;
697 
698    png_reverse_filter_adam7_deinterlace_pass(data,
699          ihdr, pngp->data, pngp->pass_width, pngp->pass_height, &passes[pngp->pass_pos]);
700 
701    free(pngp->data);
702 
703    pngp->data = NULL;
704    pngp->pass_width  = 0;
705    pngp->pass_height = 0;
706    pngp->pass_size   = 0;
707    pngp->adam7_pass_initialized = false;
708 
709    return IMAGE_PROCESS_NEXT;
710 }
711 
png_reverse_filter_adam7(uint32_t ** data_,const struct png_ihdr * ihdr,struct rpng_process * pngp)712 static int png_reverse_filter_adam7(uint32_t **data_,
713       const struct png_ihdr *ihdr,
714       struct rpng_process *pngp)
715 {
716    int ret = png_reverse_filter_adam7_iterate(data_,
717          ihdr, pngp);
718 
719    switch (ret)
720    {
721       case IMAGE_PROCESS_ERROR_END:
722       case IMAGE_PROCESS_END:
723          break;
724       case IMAGE_PROCESS_NEXT:
725          pngp->pass_pos++;
726          return 0;
727       case IMAGE_PROCESS_ERROR:
728          if (pngp->data)
729          {
730             free(pngp->data);
731             pngp->data = NULL;
732          }
733          pngp->inflate_buf -= pngp->adam7_restore_buf_size;
734          pngp->adam7_restore_buf_size = 0;
735          return -1;
736    }
737 
738    pngp->inflate_buf            -= pngp->adam7_restore_buf_size;
739    pngp->adam7_restore_buf_size  = 0;
740    return ret;
741 }
742 
png_reverse_filter_iterate(rpng_t * rpng,uint32_t ** data)743 static int png_reverse_filter_iterate(rpng_t *rpng, uint32_t **data)
744 {
745    if (!rpng)
746       return false;
747 
748    if (rpng->ihdr.interlace && rpng->process)
749       return png_reverse_filter_adam7(data, &rpng->ihdr, rpng->process);
750 
751    return png_reverse_filter_regular_iterate(data, &rpng->ihdr, rpng->process);
752 }
753 
rpng_load_image_argb_process_inflate_init(rpng_t * rpng,uint32_t ** data)754 static int rpng_load_image_argb_process_inflate_init(rpng_t *rpng, uint32_t **data)
755 {
756    bool zstatus;
757    enum trans_stream_error terror;
758    uint32_t rd, wn;
759    struct rpng_process *process = (struct rpng_process*)rpng->process;
760    bool to_continue        = (process->avail_in > 0
761          && process->avail_out > 0);
762 
763    if (!to_continue)
764       goto end;
765 
766    zstatus = process->stream_backend->trans(process->stream, false, &rd, &wn, &terror);
767 
768    if (!zstatus && terror != TRANS_STREAM_ERROR_BUFFER_FULL)
769       goto error;
770 
771    process->avail_in -= rd;
772    process->avail_out -= wn;
773    process->total_out += wn;
774 
775    if (terror)
776       return 0;
777 
778 end:
779    process->stream_backend->stream_free(process->stream);
780    process->stream = NULL;
781 
782 #ifdef GEKKO
783    /* we often use these in textures, make sure they're 32-byte aligned */
784    *data = (uint32_t*)memalign(32, rpng->ihdr.width *
785          rpng->ihdr.height * sizeof(uint32_t));
786 #else
787    *data = (uint32_t*)malloc(rpng->ihdr.width *
788          rpng->ihdr.height * sizeof(uint32_t));
789 #endif
790    if (!*data)
791       goto false_end;
792 
793    process->adam7_restore_buf_size = 0;
794    process->restore_buf_size       = 0;
795    process->palette                = rpng->palette;
796 
797    if (rpng->ihdr.interlace != 1)
798       if (png_reverse_filter_init(&rpng->ihdr, process) == -1)
799          goto false_end;
800 
801    process->inflate_initialized = true;
802    return 1;
803 
804 error:
805 false_end:
806    process->inflate_initialized = false;
807    return -1;
808 }
809 
png_read_plte(uint8_t * buf,uint32_t * buffer,unsigned entries)810 static bool png_read_plte(uint8_t *buf,
811       uint32_t *buffer, unsigned entries)
812 {
813    unsigned i;
814 
815    for (i = 0; i < entries; i++)
816    {
817       uint32_t r = buf[3 * i + 0];
818       uint32_t g = buf[3 * i + 1];
819       uint32_t b = buf[3 * i + 2];
820       buffer[i] = (r << 16) | (g << 8) | (b << 0) | (0xffu << 24);
821    }
822 
823    return true;
824 }
825 
png_read_trns(uint8_t * buf,uint32_t * palette,unsigned entries)826 static bool png_read_trns(uint8_t *buf, uint32_t *palette, unsigned entries)
827 {
828    unsigned i;
829 
830    for (i = 0; i < entries; i++, buf++, palette++)
831       *palette = (*palette & 0x00ffffff) | (unsigned)*buf << 24;
832 
833    return true;
834 }
835 
png_realloc_idat(struct idat_buffer * buf,uint32_t chunk_size)836 bool png_realloc_idat(struct idat_buffer *buf, uint32_t chunk_size)
837 {
838    uint8_t *new_buffer = (uint8_t*)realloc(buf->data, buf->size + chunk_size);
839 
840    if (!new_buffer)
841       return false;
842 
843    buf->data  = new_buffer;
844    return true;
845 }
846 
rpng_process_init(rpng_t * rpng)847 static struct rpng_process *rpng_process_init(rpng_t *rpng)
848 {
849    uint8_t *inflate_buf            = NULL;
850    struct rpng_process *process    = (struct rpng_process*)malloc(sizeof(*process));
851 
852    if (!process)
853       return NULL;
854 
855    process->inflate_initialized    = false;
856    process->adam7_pass_initialized = false;
857    process->pass_initialized       = false;
858    process->prev_scanline          = NULL;
859    process->decoded_scanline       = NULL;
860    process->inflate_buf            = NULL;
861 
862    process->ihdr.width             = 0;
863    process->ihdr.height            = 0;
864    process->ihdr.depth             = 0;
865    process->ihdr.color_type        = 0;
866    process->ihdr.compression       = 0;
867    process->ihdr.filter            = 0;
868    process->ihdr.interlace         = 0;
869 
870    process->restore_buf_size       = 0;
871    process->adam7_restore_buf_size = 0;
872    process->data_restore_buf_size  = 0;
873    process->inflate_buf_size       = 0;
874    process->avail_in               = 0;
875    process->avail_out              = 0;
876    process->total_out              = 0;
877    process->pass_size              = 0;
878    process->bpp                    = 0;
879    process->pitch                  = 0;
880    process->h                      = 0;
881    process->pass_width             = 0;
882    process->pass_height            = 0;
883    process->pass_pos               = 0;
884    process->data                   = 0;
885    process->palette                = 0;
886    process->stream                 = NULL;
887    process->stream_backend         = trans_stream_get_zlib_inflate_backend();
888 
889    png_pass_geom(&rpng->ihdr, rpng->ihdr.width,
890          rpng->ihdr.height, NULL, NULL, &process->inflate_buf_size);
891    if (rpng->ihdr.interlace == 1) /* To be sure. */
892       process->inflate_buf_size *= 2;
893 
894    process->stream = process->stream_backend->stream_new();
895 
896    if (!process->stream)
897    {
898       free(process);
899       return NULL;
900    }
901 
902    inflate_buf = (uint8_t*)malloc(process->inflate_buf_size);
903    if (!inflate_buf)
904       goto error;
905 
906    process->inflate_buf = inflate_buf;
907    process->avail_in    = rpng->idat_buf.size;
908    process->avail_out   = process->inflate_buf_size;
909 
910    process->stream_backend->set_in(
911          process->stream,
912          rpng->idat_buf.data,
913          (uint32_t)rpng->idat_buf.size);
914    process->stream_backend->set_out(
915          process->stream,
916          process->inflate_buf,
917          (uint32_t)process->inflate_buf_size);
918 
919    return process;
920 
921 error:
922    if (process)
923    {
924       if (process->stream)
925          process->stream_backend->stream_free(process->stream);
926       free(process);
927    }
928    return NULL;
929 }
930 
read_chunk_header(uint8_t * buf,uint32_t chunk_size)931 static enum png_chunk_type read_chunk_header(
932       uint8_t *buf, uint32_t chunk_size)
933 {
934    unsigned i;
935    char type[4];
936 
937    for (i = 0; i < 4; i++)
938    {
939       uint8_t byte = buf[i + 4];
940 
941       /* All four bytes of the chunk type must be
942        * ASCII letters (codes 65-90 and 97-122) */
943       if ((byte < 65) || ((byte > 90) && (byte < 97)) || (byte > 122))
944          return PNG_CHUNK_ERROR;
945       type[i]      = byte;
946    }
947 
948    if (
949             type[0] == 'I'
950          && type[1] == 'H'
951          && type[2] == 'D'
952          && type[3] == 'R'
953       )
954       return PNG_CHUNK_IHDR;
955    else if
956       (
957           type[0] == 'I'
958        && type[1] == 'D'
959        && type[2] == 'A'
960        && type[3] == 'T'
961       )
962          return PNG_CHUNK_IDAT;
963    else if
964       (
965           type[0] == 'I'
966        && type[1] == 'E'
967        && type[2] == 'N'
968        && type[3] == 'D'
969       )
970          return PNG_CHUNK_IEND;
971    else if
972       (
973           type[0] == 'P'
974        && type[1] == 'L'
975        && type[2] == 'T'
976        && type[3] == 'E'
977       )
978          return PNG_CHUNK_PLTE;
979    else if
980       (
981           type[0] == 't'
982        && type[1] == 'R'
983        && type[2] == 'N'
984        && type[3] == 'S'
985       )
986          return PNG_CHUNK_tRNS;
987 
988    return PNG_CHUNK_NOOP;
989 }
990 
rpng_iterate_image(rpng_t * rpng)991 bool rpng_iterate_image(rpng_t *rpng)
992 {
993    unsigned i;
994    uint8_t *buf             = (uint8_t*)rpng->buff_data;
995    uint32_t chunk_size      = 0;
996 
997    /* Check whether data buffer pointer is valid */
998    if (buf > rpng->buff_end)
999       return false;
1000 
1001    /* Check whether reading the header will overflow
1002     * the data buffer */
1003    if (rpng->buff_end - buf < 8)
1004       return false;
1005 
1006    chunk_size = dword_be(buf);
1007 
1008    /* Check whether chunk will overflow the data buffer */
1009    if (buf + 8 + chunk_size > rpng->buff_end)
1010       return false;
1011 
1012    switch (read_chunk_header(buf, chunk_size))
1013    {
1014       case PNG_CHUNK_NOOP:
1015       default:
1016          break;
1017 
1018       case PNG_CHUNK_ERROR:
1019          return false;
1020 
1021       case PNG_CHUNK_IHDR:
1022          if (rpng->has_ihdr || rpng->has_idat || rpng->has_iend)
1023             return false;
1024 
1025          if (chunk_size != 13)
1026             return false;
1027 
1028          buf                    += 4 + 4;
1029 
1030          rpng->ihdr.width        = dword_be(buf + 0);
1031          rpng->ihdr.height       = dword_be(buf + 4);
1032          rpng->ihdr.depth        = buf[8];
1033          rpng->ihdr.color_type   = buf[9];
1034          rpng->ihdr.compression  = buf[10];
1035          rpng->ihdr.filter       = buf[11];
1036          rpng->ihdr.interlace    = buf[12];
1037 
1038          if (     rpng->ihdr.width  == 0
1039                || rpng->ihdr.height == 0)
1040             return false;
1041 
1042          if (!png_process_ihdr(&rpng->ihdr))
1043             return false;
1044 
1045          if (rpng->ihdr.compression != 0)
1046          {
1047 #if defined(DEBUG) || defined(RPNG_TEST)
1048             fprintf(stderr, "[RPNG]: Error in line %d.\n", __LINE__);
1049 #endif
1050             return false;
1051          }
1052 
1053          rpng->has_ihdr = true;
1054          break;
1055 
1056       case PNG_CHUNK_PLTE:
1057          {
1058             unsigned entries = chunk_size / 3;
1059 
1060             if (     !rpng->has_ihdr
1061                   ||  rpng->has_plte
1062                   ||  rpng->has_iend
1063                   ||  rpng->has_idat
1064                   ||  rpng->has_trns)
1065                return false;
1066 
1067             if (chunk_size % 3)
1068                return false;
1069 
1070             if (entries > 256)
1071                return false;
1072 
1073             buf += 8;
1074 
1075             if (!png_read_plte(buf, rpng->palette, entries))
1076                return false;
1077 
1078             rpng->has_plte = true;
1079          }
1080          break;
1081 
1082       case PNG_CHUNK_tRNS:
1083          if (rpng->has_idat)
1084             return false;
1085 
1086          if (rpng->ihdr.color_type == PNG_IHDR_COLOR_PLT)
1087          {
1088             /* we should compare with the number of palette entries */
1089             if (chunk_size > 256)
1090                return false;
1091 
1092             buf += 8;
1093 
1094             if (!png_read_trns(buf, rpng->palette, chunk_size))
1095                return false;
1096          }
1097          /* TODO: support colorkey in grayscale and truecolor images */
1098 
1099          rpng->has_trns = true;
1100          break;
1101 
1102       case PNG_CHUNK_IDAT:
1103          if (!(rpng->has_ihdr) || rpng->has_iend || (rpng->ihdr.color_type == PNG_IHDR_COLOR_PLT && !(rpng->has_plte)))
1104             return false;
1105 
1106          if (!png_realloc_idat(&rpng->idat_buf, chunk_size))
1107             return false;
1108 
1109          buf += 8;
1110 
1111          for (i = 0; i < chunk_size; i++)
1112             rpng->idat_buf.data[i + rpng->idat_buf.size] = buf[i];
1113 
1114          rpng->idat_buf.size += chunk_size;
1115 
1116          rpng->has_idat = true;
1117          break;
1118 
1119       case PNG_CHUNK_IEND:
1120          if (!(rpng->has_ihdr) || !(rpng->has_idat))
1121             return false;
1122 
1123          rpng->has_iend = true;
1124          return false;
1125    }
1126 
1127    rpng->buff_data += chunk_size + 12;
1128 
1129    /* Check whether data buffer pointer is valid */
1130    if (rpng->buff_data > rpng->buff_end)
1131       return false;
1132    return true;
1133 }
1134 
rpng_process_image(rpng_t * rpng,void ** _data,size_t size,unsigned * width,unsigned * height)1135 int rpng_process_image(rpng_t *rpng,
1136       void **_data, size_t size, unsigned *width, unsigned *height)
1137 {
1138    uint32_t **data = (uint32_t**)_data;
1139 
1140    (void)size;
1141 
1142    if (!rpng->process)
1143    {
1144       struct rpng_process *process = rpng_process_init(rpng);
1145 
1146       if (!process)
1147          goto error;
1148 
1149       rpng->process = process;
1150       return IMAGE_PROCESS_NEXT;
1151    }
1152 
1153    if (!rpng->process->inflate_initialized)
1154    {
1155       if (rpng_load_image_argb_process_inflate_init(rpng, data) == -1)
1156          goto error;
1157       return IMAGE_PROCESS_NEXT;
1158    }
1159 
1160    *width  = rpng->ihdr.width;
1161    *height = rpng->ihdr.height;
1162 
1163    return png_reverse_filter_iterate(rpng, data);
1164 
1165 error:
1166    if (rpng->process)
1167    {
1168       if (rpng->process->inflate_buf)
1169          free(rpng->process->inflate_buf);
1170       if (rpng->process->stream)
1171          rpng->process->stream_backend->stream_free(rpng->process->stream);
1172       free(rpng->process);
1173    }
1174    return IMAGE_PROCESS_ERROR;
1175 }
1176 
rpng_free(rpng_t * rpng)1177 void rpng_free(rpng_t *rpng)
1178 {
1179    if (!rpng)
1180       return;
1181 
1182    if (rpng->idat_buf.data)
1183       free(rpng->idat_buf.data);
1184    if (rpng->process)
1185    {
1186       if (rpng->process->inflate_buf)
1187          free(rpng->process->inflate_buf);
1188       if (rpng->process->stream)
1189       {
1190          if (rpng->process->stream_backend && rpng->process->stream_backend->stream_free)
1191             rpng->process->stream_backend->stream_free(rpng->process->stream);
1192          else
1193             free(rpng->process->stream);
1194       }
1195       free(rpng->process);
1196    }
1197 
1198    free(rpng);
1199 }
1200 
rpng_start(rpng_t * rpng)1201 bool rpng_start(rpng_t *rpng)
1202 {
1203    if (!rpng)
1204       return false;
1205 
1206    /* Check whether reading the header will overflow
1207     * the data buffer */
1208    if (rpng->buff_end - rpng->buff_data < 8)
1209       return false;
1210 
1211    if (string_is_not_equal_fast(
1212             rpng->buff_data, png_magic, sizeof(png_magic)))
1213       return false;
1214 
1215    rpng->buff_data += 8;
1216 
1217    return true;
1218 }
1219 
rpng_is_valid(rpng_t * rpng)1220 bool rpng_is_valid(rpng_t *rpng)
1221 {
1222    /* A valid PNG image must contain an IHDR chunk,
1223     * one or more IDAT chunks, and an IEND chunk */
1224    if (rpng && rpng->has_ihdr && rpng->has_idat && rpng->has_iend)
1225       return true;
1226 
1227    return false;
1228 }
1229 
rpng_set_buf_ptr(rpng_t * rpng,void * data,size_t len)1230 bool rpng_set_buf_ptr(rpng_t *rpng, void *data, size_t len)
1231 {
1232    if (!rpng || (len < 1))
1233       return false;
1234 
1235    rpng->buff_data = (uint8_t*)data;
1236    rpng->buff_end  = rpng->buff_data + (len - 1);
1237 
1238    return true;
1239 }
1240 
rpng_alloc(void)1241 rpng_t *rpng_alloc(void)
1242 {
1243    rpng_t *rpng = (rpng_t*)calloc(1, sizeof(*rpng));
1244    if (!rpng)
1245       return NULL;
1246    return rpng;
1247 }
1248