Merge pull request #22286 from asenyaev:asen/disabled_compiling_warnings_4.x
[platform/upstream/opencv.git] / 3rdparty / libspng / spng.c
1 /* SPDX-License-Identifier: (BSD-2-Clause AND libpng-2.0) */
2
3 #define SPNG__BUILD
4
5 #include "spng.h"
6
7 #include <limits.h>
8 #include <string.h>
9 #include <stdio.h>
10 #include <math.h>
11
12 #define ZLIB_CONST
13
14 #ifdef __FRAMAC__
15     #define SPNG_DISABLE_OPT
16     #include "tests/framac_stubs.h"
17 #else
18     #ifdef SPNG_USE_MINIZ
19         #include <miniz.h>
20     #else
21         #include <zlib.h>
22     #endif
23 #endif
24
25 #ifdef SPNG_MULTITHREADING
26     #include <pthread.h>
27 #endif
28
29 /* Not build options, edit at your own risk! */
30 #define SPNG_READ_SIZE (8192)
31 #define SPNG_WRITE_SIZE SPNG_READ_SIZE
32 #define SPNG_MAX_CHUNK_COUNT (1000)
33
34 #define SPNG_TARGET_CLONES(x)
35
36 #ifndef SPNG_DISABLE_OPT
37
38     #if defined(__i386__) || defined(__x86_64__) || defined(_M_IX86) || defined(_M_X64)
39         #define SPNG_X86
40
41         #if defined(__x86_64__) || defined(_M_X64)
42             #define SPNG_X86_64
43         #endif
44
45     #elif defined(__aarch64__) || defined(_M_ARM64) /* || defined(__ARM_NEON) */
46         #define SPNG_ARM /* NOTE: only arm64 builds are tested! */
47     #else
48         #pragma message "disabling SIMD optimizations for unknown target"
49         #define SPNG_DISABLE_OPT
50     #endif
51
52     #if defined(SPNG_X86_64) && defined(SPNG_ENABLE_TARGET_CLONES)
53         #undef SPNG_TARGET_CLONES
54         #define SPNG_TARGET_CLONES(x) __attribute__((target_clones(x)))
55     #else
56         #define SPNG_TARGET_CLONES(x)
57     #endif
58
59     #ifndef SPNG_DISABLE_OPT
60         static void defilter_sub3(size_t rowbytes, unsigned char *row);
61         static void defilter_sub4(size_t rowbytes, unsigned char *row);
62         static void defilter_avg3(size_t rowbytes, unsigned char *row, const unsigned char *prev);
63         static void defilter_avg4(size_t rowbytes, unsigned char *row, const unsigned char *prev);
64         static void defilter_paeth3(size_t rowbytes, unsigned char *row, const unsigned char *prev);
65         static void defilter_paeth4(size_t rowbytes, unsigned char *row, const unsigned char *prev);
66
67         #if defined(SPNG_ARM)
68         static uint32_t expand_palette_rgba8_neon(unsigned char *row, const unsigned char *scanline, const unsigned char *plte, uint32_t width);
69         static uint32_t expand_palette_rgb8_neon(unsigned char *row, const unsigned char *scanline, const unsigned char *plte, uint32_t width);
70         #endif
71     #endif
72 #endif
73
74 #if defined(_MSC_VER)
75     #pragma warning(push)
76     #pragma warning(disable: 4244)
77 #endif
78
79 #if (defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) || defined(__BIG_ENDIAN__)
80     #define SPNG_BIG_ENDIAN
81 #else
82     #define SPNG_LITTLE_ENDIAN
83 #endif
84
85 enum spng_state
86 {
87     SPNG_STATE_INVALID = 0,
88     SPNG_STATE_INIT = 1, /* No PNG buffer/stream is set */
89     SPNG_STATE_INPUT, /* Decoder input PNG was set */
90     SPNG_STATE_OUTPUT = SPNG_STATE_INPUT, /* Encoder output was set */
91     SPNG_STATE_IHDR, /* IHDR was read/written */
92     SPNG_STATE_FIRST_IDAT,  /* Encoded up to / reached first IDAT */
93     SPNG_STATE_DECODE_INIT, /* Decoder is ready for progressive reads */
94     SPNG_STATE_ENCODE_INIT = SPNG_STATE_DECODE_INIT,
95     SPNG_STATE_EOI, /* Reached the last scanline/row */
96     SPNG_STATE_LAST_IDAT, /* Reached last IDAT, set at end of decode_image() */
97     SPNG_STATE_AFTER_IDAT, /*  */
98     SPNG_STATE_IEND, /* Reached IEND */
99 };
100
101 enum spng__internal
102 {
103     SPNG__IO_SIGNAL = 1 << 9,
104     SPNG__CTX_FLAGS_ALL = (SPNG_CTX_IGNORE_ADLER32 | SPNG_CTX_ENCODER)
105 };
106
107 #define SPNG_STR(x) _SPNG_STR(x)
108 #define _SPNG_STR(x) #x
109
110 #define SPNG_VERSION_STRING SPNG_STR(SPNG_VERSION_MAJOR) "." \
111                             SPNG_STR(SPNG_VERSION_MINOR) "." \
112                             SPNG_STR(SPNG_VERSION_PATCH)
113
114 #define SPNG_GET_CHUNK_BOILERPLATE(chunk) \
115     if(ctx == NULL) return 1; \
116     int ret = read_chunks(ctx, 0); \
117     if(ret) return ret; \
118     if(!ctx->stored.chunk) return SPNG_ECHUNKAVAIL; \
119     if(chunk == NULL) return 1
120
121 #define SPNG_SET_CHUNK_BOILERPLATE(chunk) \
122     if(ctx == NULL || chunk == NULL) return 1; \
123     if(ctx->data == NULL && !ctx->encode_only) return SPNG_ENOSRC; \
124     int ret = read_chunks(ctx, 0); \
125     if(ret) return ret
126
127 /* Determine if the spng_option can be overriden/optimized */
128 #define spng__optimize(option) (ctx->optimize_option & (1 << option))
129
130 struct spng_subimage
131 {
132     uint32_t width;
133     uint32_t height;
134     size_t out_width; /* byte width based on output format */
135     size_t scanline_width;
136 };
137
138 struct spng_text2
139 {
140     int type;
141     char *keyword;
142     char *text;
143
144     size_t text_length;
145
146     uint8_t compression_flag; /* iTXt only */
147     char *language_tag; /* iTXt only */
148     char *translated_keyword; /* iTXt only */
149
150     size_t cache_usage;
151     char user_keyword_storage[80];
152 };
153
154 struct decode_flags
155 {
156     unsigned apply_trns:  1;
157     unsigned apply_gamma: 1;
158     unsigned use_sbit:    1;
159     unsigned indexed:     1;
160     unsigned do_scaling:  1;
161     unsigned interlaced:  1;
162     unsigned same_layout: 1;
163     unsigned zerocopy:    1;
164     unsigned unpack:      1;
165 };
166
167 struct encode_flags
168 {
169     unsigned interlace:      1;
170     unsigned same_layout:    1;
171     unsigned to_bigendian:   1;
172     unsigned progressive:    1;
173     unsigned finalize:       1;
174
175     enum spng_filter_choice filter_choice;
176 };
177
178 struct spng_chunk_bitfield
179 {
180     unsigned ihdr: 1;
181     unsigned plte: 1;
182     unsigned chrm: 1;
183     unsigned iccp: 1;
184     unsigned gama: 1;
185     unsigned sbit: 1;
186     unsigned srgb: 1;
187     unsigned text: 1;
188     unsigned bkgd: 1;
189     unsigned hist: 1;
190     unsigned trns: 1;
191     unsigned phys: 1;
192     unsigned splt: 1;
193     unsigned time: 1;
194     unsigned offs: 1;
195     unsigned exif: 1;
196     unsigned unknown: 1;
197 };
198
199 /* Packed sample iterator */
200 struct spng__iter
201 {
202     const uint8_t mask;
203     unsigned shift_amount;
204     const unsigned initial_shift, bit_depth;
205     const unsigned char *samples;
206 };
207
208 union spng__decode_plte
209 {
210     struct spng_plte_entry rgba[256];
211     unsigned char rgb[256 * 3];
212     unsigned char raw[256 * 4];
213     uint32_t align_this;
214 };
215
216 struct spng__zlib_options
217 {
218     int compression_level;
219     int window_bits;
220     int mem_level;
221     int strategy;
222     int data_type;
223 };
224
225 typedef void spng__undo(spng_ctx *ctx);
226
227 struct spng_ctx
228 {
229     size_t data_size;
230     size_t bytes_read;
231     size_t stream_buf_size;
232     unsigned char *stream_buf;
233     const unsigned char *data;
234
235     /* User-defined pointers for streaming */
236     spng_read_fn *read_fn;
237     spng_write_fn *write_fn;
238     void *stream_user_ptr;
239
240     /* Used for buffer reads */
241     const unsigned char *png_base;
242     size_t bytes_left;
243     size_t last_read_size;
244
245     /* Used for encoding */
246     int user_owns_out_png;
247     unsigned char *out_png;
248     unsigned char *write_ptr;
249     size_t out_png_size;
250     size_t bytes_encoded;
251
252     /* These are updated by read/write_header()/read_chunk_bytes() */
253     struct spng_chunk current_chunk;
254     uint32_t cur_chunk_bytes_left;
255     uint32_t cur_actual_crc;
256
257     struct spng_alloc alloc;
258
259     enum spng_ctx_flags flags;
260     enum spng_format fmt;
261
262     enum spng_state state;
263
264     unsigned streaming: 1;
265     unsigned internal_buffer: 1; /* encoding to internal buffer */
266
267     unsigned inflate: 1;
268     unsigned deflate: 1;
269     unsigned encode_only: 1;
270     unsigned strict: 1;
271     unsigned discard: 1;
272     unsigned skip_crc: 1;
273     unsigned keep_unknown: 1;
274     unsigned prev_was_idat: 1;
275
276     struct spng__zlib_options image_options;
277     struct spng__zlib_options text_options;
278
279     spng__undo *undo;
280
281     /* input file contains this chunk */
282     struct spng_chunk_bitfield file;
283
284     /* chunk was stored with spng_set_*() */
285     struct spng_chunk_bitfield user;
286
287     /* chunk was stored by reading or with spng_set_*() */
288     struct spng_chunk_bitfield stored;
289
290     /* used to reset the above in case of an error */
291     struct spng_chunk_bitfield prev_stored;
292
293     struct spng_chunk first_idat, last_idat;
294
295     uint32_t max_width, max_height;
296
297     size_t max_chunk_size;
298     size_t chunk_cache_limit;
299     size_t chunk_cache_usage;
300     uint32_t chunk_count_limit;
301     uint32_t chunk_count_total;
302
303     int crc_action_critical;
304     int crc_action_ancillary;
305
306     uint32_t optimize_option;
307
308     struct spng_ihdr ihdr;
309
310     struct spng_plte plte;
311
312     struct spng_chrm_int chrm_int;
313     struct spng_iccp iccp;
314
315     uint32_t gama;
316
317     struct spng_sbit sbit;
318
319     uint8_t srgb_rendering_intent;
320
321     uint32_t n_text;
322     struct spng_text2 *text_list;
323
324     struct spng_bkgd bkgd;
325     struct spng_hist hist;
326     struct spng_trns trns;
327     struct spng_phys phys;
328
329     uint32_t n_splt;
330     struct spng_splt *splt_list;
331
332     struct spng_time time;
333     struct spng_offs offs;
334     struct spng_exif exif;
335
336     uint32_t n_chunks;
337     struct spng_unknown_chunk *chunk_list;
338
339     struct spng_subimage subimage[7];
340
341     z_stream zstream;
342     unsigned char *scanline_buf, *prev_scanline_buf, *row_buf, *filtered_scanline_buf;
343     unsigned char *scanline, *prev_scanline, *row, *filtered_scanline;
344
345     /* based on fmt */
346     size_t image_size; /* may be zero */
347     size_t image_width;
348
349     unsigned bytes_per_pixel; /* derived from ihdr */
350     unsigned pixel_size; /* derived from spng_format+ihdr */
351     int widest_pass;
352     int last_pass; /* last non-empty pass */
353
354     uint16_t *gamma_lut; /* points to either _lut8 or _lut16 */
355     uint16_t *gamma_lut16;
356     uint16_t gamma_lut8[256];
357     unsigned char trns_px[8];
358     union spng__decode_plte decode_plte;
359     struct spng_sbit decode_sb;
360     struct decode_flags decode_flags;
361     struct spng_row_info row_info;
362
363     struct encode_flags encode_flags;
364 };
365
366 static const uint32_t spng_u32max = INT32_MAX;
367
368 static const uint32_t adam7_x_start[7] = { 0, 4, 0, 2, 0, 1, 0 };
369 static const uint32_t adam7_y_start[7] = { 0, 0, 4, 0, 2, 0, 1 };
370 static const uint32_t adam7_x_delta[7] = { 8, 8, 4, 4, 2, 2, 1 };
371 static const uint32_t adam7_y_delta[7] = { 8, 8, 8, 4, 4, 2, 2 };
372
373 static const uint8_t spng_signature[8] = { 137, 80, 78, 71, 13, 10, 26, 10 };
374
375 static const uint8_t type_ihdr[4] = { 73, 72, 68, 82 };
376 static const uint8_t type_plte[4] = { 80, 76, 84, 69 };
377 static const uint8_t type_idat[4] = { 73, 68, 65, 84 };
378 static const uint8_t type_iend[4] = { 73, 69, 78, 68 };
379
380 static const uint8_t type_trns[4] = { 116, 82, 78, 83 };
381 static const uint8_t type_chrm[4] = { 99,  72, 82, 77 };
382 static const uint8_t type_gama[4] = { 103, 65, 77, 65 };
383 static const uint8_t type_iccp[4] = { 105, 67, 67, 80 };
384 static const uint8_t type_sbit[4] = { 115, 66, 73, 84 };
385 static const uint8_t type_srgb[4] = { 115, 82, 71, 66 };
386 static const uint8_t type_text[4] = { 116, 69, 88, 116 };
387 static const uint8_t type_ztxt[4] = { 122, 84, 88, 116 };
388 static const uint8_t type_itxt[4] = { 105, 84, 88, 116 };
389 static const uint8_t type_bkgd[4] = { 98,  75, 71, 68 };
390 static const uint8_t type_hist[4] = { 104, 73, 83, 84 };
391 static const uint8_t type_phys[4] = { 112, 72, 89, 115 };
392 static const uint8_t type_splt[4] = { 115, 80, 76, 84 };
393 static const uint8_t type_time[4] = { 116, 73, 77, 69 };
394
395 static const uint8_t type_offs[4] = { 111, 70, 70, 115 };
396 static const uint8_t type_exif[4] = { 101, 88, 73, 102 };
397
398 static inline void *spng__malloc(spng_ctx *ctx,  size_t size)
399 {
400     return ctx->alloc.malloc_fn(size);
401 }
402
403 static inline void *spng__calloc(spng_ctx *ctx, size_t nmemb, size_t size)
404 {
405     return ctx->alloc.calloc_fn(nmemb, size);
406 }
407
408 static inline void *spng__realloc(spng_ctx *ctx, void *ptr, size_t size)
409 {
410     return ctx->alloc.realloc_fn(ptr, size);
411 }
412
413 static inline void spng__free(spng_ctx *ctx, void *ptr)
414 {
415     ctx->alloc.free_fn(ptr);
416 }
417
418 #if defined(SPNG_USE_MINIZ)
419 static void *spng__zalloc(void *opaque, size_t items, size_t size)
420 #else
421 static void *spng__zalloc(void *opaque, uInt items, uInt size)
422 #endif
423 {
424     spng_ctx *ctx = opaque;
425
426     if(size > SIZE_MAX / items) return NULL;
427
428     size_t len = (size_t)items * size;
429
430     return spng__malloc(ctx, len);
431 }
432
433 static void spng__zfree(void *opqaue, void *ptr)
434 {
435     spng_ctx *ctx = opqaue;
436     spng__free(ctx, ptr);
437 }
438
439 static inline uint16_t read_u16(const void *src)
440 {
441     const unsigned char *data = src;
442
443     return (data[0] & 0xFFU) << 8 | (data[1] & 0xFFU);
444 }
445
446 static inline uint32_t read_u32(const void *src)
447 {
448     const unsigned char *data = src;
449
450     return (data[0] & 0xFFUL) << 24 | (data[1] & 0xFFUL) << 16 |
451            (data[2] & 0xFFUL) << 8  | (data[3] & 0xFFUL);
452 }
453
454 static inline int32_t read_s32(const void *src)
455 {
456     int32_t ret = (int32_t)read_u32(src);
457
458     return ret;
459 }
460
461 static inline void write_u16(void *dest, uint16_t x)
462 {
463     unsigned char *data = dest;
464
465     data[0] = x >> 8;
466     data[1] = x & 0xFF;
467 }
468
469 static inline void write_u32(void *dest, uint32_t x)
470 {
471     unsigned char *data = dest;
472
473     data[0] = (x >> 24);
474     data[1] = (x >> 16) & 0xFF;
475     data[2] = (x >> 8) & 0xFF;
476     data[3] = x & 0xFF;
477 }
478
479 static inline void write_s32(void *dest, int32_t x)
480 {
481     uint32_t n = x;
482     write_u32(dest, n);
483 }
484
485 /* Returns an iterator for 1,2,4,8-bit samples */
486 static struct spng__iter spng__iter_init(unsigned bit_depth, const unsigned char *samples)
487 {
488     struct spng__iter iter =
489     {
490         .mask = (uint32_t)(1 << bit_depth) - 1,
491         .shift_amount = 8 - bit_depth,
492         .initial_shift = 8 - bit_depth,
493         .bit_depth = bit_depth,
494         .samples = samples
495     };
496
497     return iter;
498 }
499
500 /* Returns the current sample unpacked, iterates to the next one */
501 static inline uint8_t get_sample(struct spng__iter *iter)
502 {
503     uint8_t x = (iter->samples[0] >> iter->shift_amount) & iter->mask;
504
505     iter->shift_amount -= iter->bit_depth;
506
507     if(iter->shift_amount > 7)
508     {
509         iter->shift_amount = iter->initial_shift;
510         iter->samples++;
511     }
512
513     return x;
514 }
515
516 static void u16_row_to_host(void *row, size_t size)
517 {
518     uint16_t *px = row;
519     size_t i, n = size / 2;
520
521     for(i=0; i < n; i++)
522     {
523         px[i] = read_u16(&px[i]);
524     }
525 }
526
527 static void u16_row_to_bigendian(void *row, size_t size)
528 {
529     uint16_t *px = (uint16_t*)row;
530     size_t i, n = size / 2;
531
532     for(i=0; i < n; i++)
533     {
534         write_u16(&px[i], px[i]);
535     }
536 }
537
538 static void rgb8_row_to_rgba8(const unsigned char *row, unsigned char *out, uint32_t n)
539 {
540     uint32_t i;
541     for(i=0; i < n; i++)
542     {
543         memcpy(out + i * 4, row + i * 3, 3);
544         out[i*4+3] = 255;
545     }
546 }
547
548 static unsigned num_channels(const struct spng_ihdr *ihdr)
549 {
550     switch(ihdr->color_type)
551     {
552         case SPNG_COLOR_TYPE_TRUECOLOR: return 3;
553         case SPNG_COLOR_TYPE_GRAYSCALE_ALPHA: return 2;
554         case SPNG_COLOR_TYPE_TRUECOLOR_ALPHA: return 4;
555         case SPNG_COLOR_TYPE_GRAYSCALE:
556         case SPNG_COLOR_TYPE_INDEXED:
557             return 1;
558         default: return 0;
559     }
560 }
561
562 /* Calculate scanline width in bits, round up to the nearest byte */
563 static int calculate_scanline_width(const struct spng_ihdr *ihdr, uint32_t width, size_t *scanline_width)
564 {
565     if(ihdr == NULL || !width) return SPNG_EINTERNAL;
566
567     size_t res = num_channels(ihdr) * ihdr->bit_depth;
568
569     if(res > SIZE_MAX / width) return SPNG_EOVERFLOW;
570     res = res * width;
571
572     res += 15; /* Filter byte + 7 for rounding */
573
574     if(res < 15) return SPNG_EOVERFLOW;
575
576     res /= 8;
577
578     if(res > UINT32_MAX) return SPNG_EOVERFLOW;
579
580     *scanline_width = res;
581
582     return 0;
583 }
584
585 static int calculate_subimages(struct spng_ctx *ctx)
586 {
587     if(ctx == NULL) return SPNG_EINTERNAL;
588
589     struct spng_ihdr *ihdr = &ctx->ihdr;
590     struct spng_subimage *sub = ctx->subimage;
591
592     if(ihdr->interlace_method == 1)
593     {
594         sub[0].width = (ihdr->width + 7) >> 3;
595         sub[0].height = (ihdr->height + 7) >> 3;
596         sub[1].width = (ihdr->width + 3) >> 3;
597         sub[1].height = (ihdr->height + 7) >> 3;
598         sub[2].width = (ihdr->width + 3) >> 2;
599         sub[2].height = (ihdr->height + 3) >> 3;
600         sub[3].width = (ihdr->width + 1) >> 2;
601         sub[3].height = (ihdr->height + 3) >> 2;
602         sub[4].width = (ihdr->width + 1) >> 1;
603         sub[4].height = (ihdr->height + 1) >> 2;
604         sub[5].width = ihdr->width >> 1;
605         sub[5].height = (ihdr->height + 1) >> 1;
606         sub[6].width = ihdr->width;
607         sub[6].height = ihdr->height >> 1;
608     }
609     else
610     {
611         sub[0].width = ihdr->width;
612         sub[0].height = ihdr->height;
613     }
614
615     int i;
616     for(i=0; i < 7; i++)
617     {
618         if(sub[i].width == 0 || sub[i].height == 0) continue;
619
620         int ret = calculate_scanline_width(ihdr, sub[i].width, &sub[i].scanline_width);
621         if(ret) return ret;
622
623         if(sub[ctx->widest_pass].scanline_width < sub[i].scanline_width) ctx->widest_pass = i;
624
625         ctx->last_pass = i;
626     }
627
628     return 0;
629 }
630
631 static int check_decode_fmt(const struct spng_ihdr *ihdr, const int fmt)
632 {
633     switch(fmt)
634     {
635         case SPNG_FMT_RGBA8:
636         case SPNG_FMT_RGBA16:
637         case SPNG_FMT_RGB8:
638         case SPNG_FMT_PNG:
639         case SPNG_FMT_RAW:
640             return 0;
641         case SPNG_FMT_G8:
642         case SPNG_FMT_GA8:
643             if(ihdr->color_type == SPNG_COLOR_TYPE_GRAYSCALE && ihdr->bit_depth <= 8) return 0;
644             else return SPNG_EFMT;
645         case SPNG_FMT_GA16:
646             if(ihdr->color_type == SPNG_COLOR_TYPE_GRAYSCALE && ihdr->bit_depth == 16) return 0;
647             else return SPNG_EFMT;
648         default: return SPNG_EFMT;
649     }
650 }
651
652 static int calculate_image_width(const struct spng_ihdr *ihdr, int fmt, size_t *len)
653 {
654     if(ihdr == NULL || len == NULL) return SPNG_EINTERNAL;
655
656     size_t res = ihdr->width;
657     unsigned bytes_per_pixel;
658
659     switch(fmt)
660     {
661         case SPNG_FMT_RGBA8:
662         case SPNG_FMT_GA16:
663             bytes_per_pixel = 4;
664             break;
665         case SPNG_FMT_RGBA16:
666             bytes_per_pixel = 8;
667             break;
668         case SPNG_FMT_RGB8:
669             bytes_per_pixel = 3;
670             break;
671         case SPNG_FMT_PNG:
672         case SPNG_FMT_RAW:
673         {
674             int ret = calculate_scanline_width(ihdr, ihdr->width, &res);
675             if(ret) return ret;
676
677             res -= 1; /* exclude filter byte */
678             bytes_per_pixel = 1;
679             break;
680         }
681         case SPNG_FMT_G8:
682             bytes_per_pixel = 1;
683             break;
684         case SPNG_FMT_GA8:
685             bytes_per_pixel = 2;
686             break;
687         default: return SPNG_EINTERNAL;
688     }
689
690     if(res > SIZE_MAX / bytes_per_pixel) return SPNG_EOVERFLOW;
691     res = res * bytes_per_pixel;
692
693     *len = res;
694
695     return 0;
696 }
697
698 static int calculate_image_size(const struct spng_ihdr *ihdr, int fmt, size_t *len)
699 {
700     if(ihdr == NULL || len == NULL) return SPNG_EINTERNAL;
701
702     size_t res = 0;
703
704     int ret = calculate_image_width(ihdr, fmt, &res);
705     if(ret) return ret;
706
707     if(res > SIZE_MAX / ihdr->height) return SPNG_EOVERFLOW;
708     res = res * ihdr->height;
709
710     *len = res;
711
712     return 0;
713 }
714
715 static int increase_cache_usage(spng_ctx *ctx, size_t bytes, int new_chunk)
716 {
717     if(ctx == NULL || !bytes) return SPNG_EINTERNAL;
718
719     if(new_chunk)
720     {
721         ctx->chunk_count_total++;
722         if(ctx->chunk_count_total < 1) return SPNG_EOVERFLOW;
723
724         if(ctx->chunk_count_total > ctx->chunk_count_limit) return SPNG_ECHUNK_LIMITS;
725     }
726
727     size_t new_usage = ctx->chunk_cache_usage + bytes;
728
729     if(new_usage < ctx->chunk_cache_usage) return SPNG_EOVERFLOW;
730
731     if(new_usage > ctx->chunk_cache_limit) return SPNG_ECHUNK_LIMITS;
732
733     ctx->chunk_cache_usage = new_usage;
734
735     return 0;
736 }
737
738 static int decrease_cache_usage(spng_ctx *ctx, size_t usage)
739 {
740     if(ctx == NULL || !usage) return SPNG_EINTERNAL;
741     if(usage > ctx->chunk_cache_usage) return SPNG_EINTERNAL;
742
743     ctx->chunk_cache_usage -= usage;
744
745     return 0;
746 }
747
748 static int is_critical_chunk(struct spng_chunk *chunk)
749 {
750     if(chunk == NULL) return 0;
751     if((chunk->type[0] & (1 << 5)) == 0) return 1;
752
753     return 0;
754 }
755
756 static int decode_err(spng_ctx *ctx, int err)
757 {
758     ctx->state = SPNG_STATE_INVALID;
759
760     return err;
761 }
762
763 static int encode_err(spng_ctx *ctx, int err)
764 {
765     ctx->state = SPNG_STATE_INVALID;
766
767     return err;
768 }
769
770 static inline int read_data(spng_ctx *ctx, size_t bytes)
771 {
772     if(ctx == NULL) return SPNG_EINTERNAL;
773     if(!bytes) return 0;
774
775     if(ctx->streaming && (bytes > SPNG_READ_SIZE)) return SPNG_EINTERNAL;
776
777     int ret = ctx->read_fn(ctx, ctx->stream_user_ptr, ctx->stream_buf, bytes);
778
779     if(ret)
780     {
781         if(ret > 0 || ret < SPNG_IO_ERROR) ret = SPNG_IO_ERROR;
782
783         return ret;
784     }
785
786     ctx->bytes_read += bytes;
787     if(ctx->bytes_read < bytes) return SPNG_EOVERFLOW;
788
789     return 0;
790 }
791
792 /* Ensure there is enough space for encoding starting at ctx->write_ptr  */
793 static int require_bytes(spng_ctx *ctx, size_t bytes)
794 {
795     if(ctx == NULL) return SPNG_EINTERNAL;
796
797     if(ctx->streaming)
798     {
799         if(bytes > ctx->stream_buf_size)
800         {
801             size_t new_size = ctx->stream_buf_size;
802
803             /* Start at default IDAT size + header + crc */
804             if(new_size < (SPNG_WRITE_SIZE + 12)) new_size = SPNG_WRITE_SIZE + 12;
805
806             if(new_size < bytes) new_size = bytes;
807
808             void *temp = spng__realloc(ctx, ctx->stream_buf, new_size);
809
810             if(temp == NULL) return encode_err(ctx, SPNG_EMEM);
811
812             ctx->stream_buf = temp;
813             ctx->stream_buf_size = bytes;
814             ctx->write_ptr = ctx->stream_buf;
815         }
816
817         return 0;
818     }
819
820     if(!ctx->internal_buffer) return SPNG_ENODST;
821
822     size_t required = ctx->bytes_encoded + bytes;
823     if(required < bytes) return SPNG_EOVERFLOW;
824
825     if(required > ctx->out_png_size)
826     {
827         size_t new_size = ctx->out_png_size;
828
829         /* Start with a size that doesn't require a realloc() 100% of the time */
830         if(new_size < (SPNG_WRITE_SIZE * 2)) new_size = SPNG_WRITE_SIZE * 2;
831
832         /* Prefer the next power of two over the requested size */
833         while(new_size < required)
834         {
835             if(new_size / SIZE_MAX > 2) return encode_err(ctx, SPNG_EOVERFLOW);
836
837             new_size *= 2;
838         }
839
840         void *temp = spng__realloc(ctx, ctx->out_png, new_size);
841
842         if(temp == NULL) return encode_err(ctx, SPNG_EMEM);
843
844         ctx->out_png = temp;
845         ctx->out_png_size = new_size;
846         ctx->write_ptr = ctx->out_png + ctx->bytes_encoded;
847     }
848
849     return 0;
850 }
851
852 static int write_data(spng_ctx *ctx, const void *data, size_t bytes)
853 {
854     if(ctx == NULL) return SPNG_EINTERNAL;
855     if(!bytes) return 0;
856
857     if(ctx->streaming)
858     {
859         if(bytes > SPNG_WRITE_SIZE) return SPNG_EINTERNAL;
860
861         int ret = ctx->write_fn(ctx, ctx->stream_user_ptr, (void*)data, bytes);
862
863         if(ret)
864         {
865             if(ret > 0 || ret < SPNG_IO_ERROR) ret = SPNG_IO_ERROR;
866
867             return encode_err(ctx, ret);
868         }
869     }
870     else
871     {
872         int ret = require_bytes(ctx, bytes);
873         if(ret) return encode_err(ctx, ret);
874
875         memcpy(ctx->write_ptr, data, bytes);
876
877         ctx->write_ptr += bytes;
878     }
879
880     ctx->bytes_encoded += bytes;
881     if(ctx->bytes_encoded < bytes) return SPNG_EOVERFLOW;
882
883     return 0;
884 }
885
886 static int write_header(spng_ctx *ctx, const uint8_t chunk_type[4], size_t chunk_length, unsigned char **data)
887 {
888     if(ctx == NULL || chunk_type == NULL) return SPNG_EINTERNAL;
889     if(chunk_length > spng_u32max) return SPNG_EINTERNAL;
890
891     size_t total = chunk_length + 12;
892
893     int ret = require_bytes(ctx, total);
894     if(ret) return ret;
895
896     uint32_t crc = crc32(0, NULL, 0);
897     ctx->current_chunk.crc = crc32(crc, chunk_type, 4);
898
899     memcpy(&ctx->current_chunk.type, chunk_type, 4);
900     ctx->current_chunk.length = (uint32_t)chunk_length;
901
902     if(!data) return SPNG_EINTERNAL;
903
904     if(ctx->streaming) *data = ctx->stream_buf + 8;
905     else *data = ctx->write_ptr + 8;
906
907     return 0;
908 }
909
910 static int trim_chunk(spng_ctx *ctx, uint32_t length)
911 {
912     if(length > spng_u32max) return SPNG_EINTERNAL;
913     if(length > ctx->current_chunk.length) return SPNG_EINTERNAL;
914
915     ctx->current_chunk.length = length;
916
917     return 0;
918 }
919
920 static int finish_chunk(spng_ctx *ctx)
921 {
922     if(ctx == NULL) return SPNG_EINTERNAL;
923
924     struct spng_chunk *chunk = &ctx->current_chunk;
925
926     unsigned char *header;
927     unsigned char *chunk_data;
928
929     if(ctx->streaming)
930     {
931         chunk_data = ctx->stream_buf + 8;
932         header = ctx->stream_buf;
933     }
934     else
935     {
936         chunk_data = ctx->write_ptr + 8;
937         header = ctx->write_ptr;
938     }
939
940     write_u32(header, chunk->length);
941     memcpy(header + 4, chunk->type, 4);
942
943     chunk->crc = crc32(chunk->crc, chunk_data, chunk->length);
944
945     write_u32(chunk_data + chunk->length, chunk->crc);
946
947     if(ctx->streaming)
948     {
949         const unsigned char *ptr = ctx->stream_buf;
950         uint32_t bytes_left = chunk->length + 12;
951         uint32_t len = 0;
952
953         while(bytes_left)
954         {
955             ptr += len;
956             len = SPNG_WRITE_SIZE;
957
958             if(len > bytes_left) len = bytes_left;
959
960             int ret = write_data(ctx, ptr, len);
961             if(ret) return ret;
962
963             bytes_left -= len;
964         }
965     }
966     else
967     {
968         ctx->bytes_encoded += chunk->length;
969         if(ctx->bytes_encoded < chunk->length) return SPNG_EOVERFLOW;
970
971         ctx->bytes_encoded += 12;
972         if(ctx->bytes_encoded < 12) return SPNG_EOVERFLOW;
973
974         ctx->write_ptr += chunk->length + 12;
975     }
976
977     return 0;
978 }
979
980 static int write_chunk(spng_ctx *ctx, const uint8_t type[4], const void *data, size_t length)
981 {
982     if(ctx == NULL || type == NULL) return SPNG_EINTERNAL;
983     if(length && data == NULL) return SPNG_EINTERNAL;
984
985     unsigned char *write_ptr;
986
987     int ret = write_header(ctx, type, length, &write_ptr);
988     if(ret) return ret;
989
990     if(length) memcpy(write_ptr, data, length);
991
992     return finish_chunk(ctx);
993 }
994
995 static int write_iend(spng_ctx *ctx)
996 {
997     unsigned char iend_chunk[12] = { 0, 0, 0, 0, 73, 69, 78, 68, 174, 66, 96, 130 };
998     return write_data(ctx, iend_chunk, 12);
999 }
1000
1001 static int write_unknown_chunks(spng_ctx *ctx, enum spng_location location)
1002 {
1003     if(!ctx->stored.unknown) return 0;
1004
1005     const struct spng_unknown_chunk *chunk = ctx->chunk_list;
1006
1007     uint32_t i;
1008     for(i=0; i < ctx->n_chunks; i++, chunk++)
1009     {
1010         if(chunk->location != location) continue;
1011
1012         int ret = write_chunk(ctx, chunk->type, chunk->data, chunk->length);
1013         if(ret) return ret;
1014     }
1015
1016     return 0;
1017 }
1018
1019 /* Read and check the current chunk's crc,
1020    returns -SPNG_CRC_DISCARD if the chunk should be discarded */
1021 static inline int read_and_check_crc(spng_ctx *ctx)
1022 {
1023     if(ctx == NULL) return SPNG_EINTERNAL;
1024
1025     int ret;
1026     ret = read_data(ctx, 4);
1027     if(ret) return ret;
1028
1029     ctx->current_chunk.crc = read_u32(ctx->data);
1030
1031     if(ctx->skip_crc) return 0;
1032
1033     if(ctx->cur_actual_crc != ctx->current_chunk.crc)
1034     {
1035         if(is_critical_chunk(&ctx->current_chunk))
1036         {
1037             if(ctx->crc_action_critical == SPNG_CRC_USE) return 0;
1038         }
1039         else
1040         {
1041             if(ctx->crc_action_ancillary == SPNG_CRC_USE) return 0;
1042             if(ctx->crc_action_ancillary == SPNG_CRC_DISCARD) return -SPNG_CRC_DISCARD;
1043         }
1044
1045         return SPNG_ECHUNK_CRC;
1046     }
1047
1048     return 0;
1049 }
1050
1051 /* Read and validate the current chunk's crc and the next chunk header */
1052 static inline int read_header(spng_ctx *ctx)
1053 {
1054     if(ctx == NULL) return SPNG_EINTERNAL;
1055
1056     int ret;
1057     struct spng_chunk chunk = { 0 };
1058
1059     ret = read_and_check_crc(ctx);
1060     if(ret)
1061     {
1062         if(ret == -SPNG_CRC_DISCARD)
1063         {
1064             ctx->discard = 1;
1065         }
1066         else return ret;
1067     }
1068
1069     ret = read_data(ctx, 8);
1070     if(ret) return ret;
1071
1072     chunk.offset = ctx->bytes_read - 8;
1073
1074     chunk.length = read_u32(ctx->data);
1075
1076     memcpy(&chunk.type, ctx->data + 4, 4);
1077
1078     if(chunk.length > spng_u32max) return SPNG_ECHUNK_STDLEN;
1079
1080     ctx->cur_chunk_bytes_left = chunk.length;
1081
1082     if(is_critical_chunk(&chunk) && ctx->crc_action_critical == SPNG_CRC_USE) ctx->skip_crc = 1;
1083     else if(ctx->crc_action_ancillary == SPNG_CRC_USE) ctx->skip_crc = 1;
1084     else ctx->skip_crc = 0;
1085
1086     if(!ctx->skip_crc)
1087     {
1088         ctx->cur_actual_crc = crc32(0, NULL, 0);
1089         ctx->cur_actual_crc = crc32(ctx->cur_actual_crc, chunk.type, 4);
1090     }
1091
1092     ctx->current_chunk = chunk;
1093
1094     return 0;
1095 }
1096
1097 /* Read chunk bytes and update crc */
1098 static int read_chunk_bytes(spng_ctx *ctx, uint32_t bytes)
1099 {
1100     if(ctx == NULL) return SPNG_EINTERNAL;
1101     if(!ctx->cur_chunk_bytes_left || !bytes) return SPNG_EINTERNAL;
1102     if(bytes > ctx->cur_chunk_bytes_left) return SPNG_EINTERNAL; /* XXX: more specific error? */
1103
1104     int ret;
1105
1106     ret = read_data(ctx, bytes);
1107     if(ret) return ret;
1108
1109     if(!ctx->skip_crc) ctx->cur_actual_crc = crc32(ctx->cur_actual_crc, ctx->data, bytes);
1110
1111     ctx->cur_chunk_bytes_left -= bytes;
1112
1113     return ret;
1114 }
1115
1116 /* read_chunk_bytes() + read_data() with custom output buffer */
1117 static int read_chunk_bytes2(spng_ctx *ctx, void *out, uint32_t bytes)
1118 {
1119     if(ctx == NULL) return SPNG_EINTERNAL;
1120     if(!ctx->cur_chunk_bytes_left || !bytes) return SPNG_EINTERNAL;
1121     if(bytes > ctx->cur_chunk_bytes_left) return SPNG_EINTERNAL; /* XXX: more specific error? */
1122
1123     int ret;
1124     uint32_t len = bytes;
1125
1126     if(ctx->streaming && len > SPNG_READ_SIZE) len = SPNG_READ_SIZE;
1127
1128     while(bytes)
1129     {
1130         if(len > bytes) len = bytes;
1131
1132         ret = ctx->read_fn(ctx, ctx->stream_user_ptr, out, len);
1133         if(ret) return ret;
1134
1135         if(!ctx->streaming) memcpy(out, ctx->data, len);
1136
1137         ctx->bytes_read += len;
1138         if(ctx->bytes_read < len) return SPNG_EOVERFLOW;
1139
1140         if(!ctx->skip_crc) ctx->cur_actual_crc = crc32(ctx->cur_actual_crc, out, len);
1141
1142         ctx->cur_chunk_bytes_left -= len;
1143
1144         out = (char*)out + len;
1145         bytes -= len;
1146         len = SPNG_READ_SIZE;
1147     }
1148
1149     return 0;
1150 }
1151
1152 static int discard_chunk_bytes(spng_ctx *ctx, uint32_t bytes)
1153 {
1154     if(ctx == NULL) return SPNG_EINTERNAL;
1155     if(!bytes) return 0;
1156
1157     int ret;
1158
1159     if(ctx->streaming) /* Do small, consecutive reads */
1160     {
1161         while(bytes)
1162         {
1163             uint32_t len = SPNG_READ_SIZE;
1164
1165             if(len > bytes) len = bytes;
1166
1167             ret = read_chunk_bytes(ctx, len);
1168             if(ret) return ret;
1169
1170             bytes -= len;
1171         }
1172     }
1173     else
1174     {
1175         ret = read_chunk_bytes(ctx, bytes);
1176         if(ret) return ret;
1177     }
1178
1179     return 0;
1180 }
1181
1182 static int spng__inflate_init(spng_ctx *ctx, int window_bits)
1183 {
1184     if(ctx->zstream.state) inflateEnd(&ctx->zstream);
1185
1186     ctx->inflate = 1;
1187
1188     ctx->zstream.zalloc = spng__zalloc;
1189     ctx->zstream.zfree = spng__zfree;
1190     ctx->zstream.opaque = ctx;
1191
1192     if(inflateInit2(&ctx->zstream, window_bits) != Z_OK) return SPNG_EZLIB_INIT;
1193
1194 #if ZLIB_VERNUM >= 0x1290 && !defined(SPNG_USE_MINIZ)
1195
1196     int validate = 1;
1197
1198     if(ctx->flags & SPNG_CTX_IGNORE_ADLER32) validate = 0;
1199
1200     if(is_critical_chunk(&ctx->current_chunk))
1201     {
1202         if(ctx->crc_action_critical == SPNG_CRC_USE) validate = 0;
1203     }
1204     else /* ancillary */
1205     {
1206         if(ctx->crc_action_ancillary == SPNG_CRC_USE) validate = 0;
1207     }
1208
1209     if(inflateValidate(&ctx->zstream, validate)) return SPNG_EZLIB_INIT;
1210
1211 #else /* This requires zlib >= 1.2.11 */
1212     #pragma message ("inflateValidate() not available, SPNG_CTX_IGNORE_ADLER32 will be ignored")
1213 #endif
1214
1215     return 0;
1216 }
1217
1218 static int spng__deflate_init(spng_ctx *ctx, struct spng__zlib_options *options)
1219 {
1220     if(ctx->zstream.state) deflateEnd(&ctx->zstream);
1221
1222     ctx->deflate = 1;
1223
1224     z_stream *zstream = &ctx->zstream;
1225     zstream->zalloc = spng__zalloc;
1226     zstream->zfree = spng__zfree;
1227     zstream->opaque = ctx;
1228     zstream->data_type = options->data_type;
1229
1230     int ret = deflateInit2(zstream, options->compression_level, Z_DEFLATED, options->window_bits, options->mem_level, options->strategy);
1231
1232     if(ret != Z_OK) return SPNG_EZLIB_INIT;
1233
1234     return 0;
1235 }
1236
1237 /* Inflate a zlib stream starting with start_buf if non-NULL,
1238    continuing from the datastream till an end marker,
1239    allocating and writing the inflated stream to *out,
1240    leaving "extra" bytes at the end, final buffer length is *len.
1241
1242    Takes into account the chunk size and cache limits.
1243 */
1244 static int spng__inflate_stream(spng_ctx *ctx, char **out, size_t *len, size_t extra, const void *start_buf, size_t start_len)
1245 {
1246     int ret = spng__inflate_init(ctx, 15);
1247     if(ret) return ret;
1248
1249     size_t max = ctx->chunk_cache_limit - ctx->chunk_cache_usage;
1250
1251     if(ctx->max_chunk_size < max) max = ctx->max_chunk_size;
1252
1253     if(extra > max) return SPNG_ECHUNK_LIMITS;
1254     max -= extra;
1255
1256     uint32_t read_size;
1257     size_t size = 8 * 1024;
1258     void *t, *buf = spng__malloc(ctx, size);
1259
1260     if(buf == NULL) return SPNG_EMEM;
1261
1262     z_stream *stream = &ctx->zstream;
1263
1264     if(start_buf != NULL && start_len)
1265     {
1266         stream->avail_in = (uInt)start_len;
1267         stream->next_in = start_buf;
1268     }
1269     else
1270     {
1271         stream->avail_in = 0;
1272         stream->next_in = NULL;
1273     }
1274
1275     stream->avail_out = (uInt)size;
1276     stream->next_out = buf;
1277
1278     while(ret != Z_STREAM_END)
1279     {
1280         ret = inflate(stream, Z_NO_FLUSH);
1281
1282         if(ret == Z_STREAM_END) break;
1283
1284         if(ret != Z_OK && ret != Z_BUF_ERROR)
1285         {
1286             ret = SPNG_EZLIB;
1287             goto err;
1288         }
1289
1290         if(!stream->avail_out) /* Resize buffer */
1291         {
1292             /* overflow or reached chunk/cache limit */
1293             if( (2 > SIZE_MAX / size) || (size > max / 2) )
1294             {
1295                 ret = SPNG_ECHUNK_LIMITS;
1296                 goto err;
1297             }
1298
1299             size *= 2;
1300
1301             t = spng__realloc(ctx, buf, size);
1302             if(t == NULL) goto mem;
1303
1304             buf = t;
1305
1306             stream->avail_out = (uInt)size / 2;
1307             stream->next_out = (unsigned char*)buf + size / 2;
1308         }
1309         else if(!stream->avail_in) /* Read more chunk bytes */
1310         {
1311             read_size = ctx->cur_chunk_bytes_left;
1312             if(ctx->streaming && read_size > SPNG_READ_SIZE) read_size = SPNG_READ_SIZE;
1313
1314             ret = read_chunk_bytes(ctx, read_size);
1315
1316             if(ret)
1317             {
1318                 if(!read_size) ret = SPNG_EZLIB;
1319
1320                 goto err;
1321             }
1322
1323             stream->avail_in = read_size;
1324             stream->next_in = ctx->data;
1325         }
1326     }
1327
1328     size = stream->total_out;
1329
1330     if(!size)
1331     {
1332         ret = SPNG_EZLIB;
1333         goto err;
1334     }
1335
1336     size += extra;
1337     if(size < extra) goto mem;
1338
1339     t = spng__realloc(ctx, buf, size);
1340     if(t == NULL) goto mem;
1341
1342     buf = t;
1343
1344     (void)increase_cache_usage(ctx, size, 0);
1345
1346     *out = buf;
1347     *len = size;
1348
1349     return 0;
1350
1351 mem:
1352     ret = SPNG_EMEM;
1353 err:
1354     spng__free(ctx, buf);
1355     return ret;
1356 }
1357
1358 /* Read at least one byte from the IDAT stream */
1359 static int read_idat_bytes(spng_ctx *ctx, uint32_t *bytes_read)
1360 {
1361     if(ctx == NULL || bytes_read == NULL) return SPNG_EINTERNAL;
1362     if(memcmp(ctx->current_chunk.type, type_idat, 4)) return SPNG_EIDAT_TOO_SHORT;
1363
1364     int ret;
1365     uint32_t len;
1366
1367     while(!ctx->cur_chunk_bytes_left)
1368     {
1369         ret = read_header(ctx);
1370         if(ret) return ret;
1371
1372         if(memcmp(ctx->current_chunk.type, type_idat, 4)) return SPNG_EIDAT_TOO_SHORT;
1373     }
1374
1375     if(ctx->streaming)
1376     {/* TODO: estimate bytes to read for progressive reads */
1377         len = SPNG_READ_SIZE;
1378         if(len > ctx->cur_chunk_bytes_left) len = ctx->cur_chunk_bytes_left;
1379     }
1380     else len = ctx->current_chunk.length;
1381
1382     ret = read_chunk_bytes(ctx, len);
1383
1384     *bytes_read = len;
1385
1386     return ret;
1387 }
1388
1389 static int read_scanline_bytes(spng_ctx *ctx, unsigned char *dest, size_t len)
1390 {
1391     if(ctx == NULL || dest == NULL) return SPNG_EINTERNAL;
1392
1393     int ret = Z_OK;
1394     uint32_t bytes_read;
1395
1396     z_stream *zstream = &ctx->zstream;
1397
1398     zstream->avail_out = (uInt)len;
1399     zstream->next_out = dest;
1400
1401     while(zstream->avail_out != 0)
1402     {
1403         ret = inflate(zstream, Z_NO_FLUSH);
1404
1405         if(ret == Z_OK) continue;
1406
1407         if(ret == Z_STREAM_END) /* Reached an end-marker */
1408         {
1409             if(zstream->avail_out != 0) return SPNG_EIDAT_TOO_SHORT;
1410         }
1411         else if(ret == Z_BUF_ERROR) /* Read more IDAT bytes */
1412         {
1413             ret = read_idat_bytes(ctx, &bytes_read);
1414             if(ret) return ret;
1415
1416             zstream->avail_in = bytes_read;
1417             zstream->next_in = ctx->data;
1418         }
1419         else return SPNG_EIDAT_STREAM;
1420     }
1421
1422     return 0;
1423 }
1424
1425 static uint8_t paeth(uint8_t a, uint8_t b, uint8_t c)
1426 {
1427     int16_t p = a + b - c;
1428     int16_t pa = abs(p - a);
1429     int16_t pb = abs(p - b);
1430     int16_t pc = abs(p - c);
1431
1432     if(pa <= pb && pa <= pc) return a;
1433     else if(pb <= pc) return b;
1434
1435     return c;
1436 }
1437
1438 SPNG_TARGET_CLONES("default,avx2")
1439 static void defilter_up(size_t bytes, unsigned char *row, const unsigned char *prev)
1440 {
1441     size_t i;
1442     for(i=0; i < bytes; i++)
1443     {
1444         row[i] += prev[i];
1445     }
1446 }
1447
1448 /* Defilter *scanline in-place.
1449    *prev_scanline and *scanline should point to the first pixel,
1450    scanline_width is the width of the scanline including the filter byte.
1451 */
1452 static int defilter_scanline(const unsigned char *prev_scanline, unsigned char *scanline,
1453                              size_t scanline_width, unsigned bytes_per_pixel, unsigned filter)
1454 {
1455     if(prev_scanline == NULL || scanline == NULL || !scanline_width) return SPNG_EINTERNAL;
1456
1457     size_t i;
1458     scanline_width--;
1459
1460     if(filter == 0) return 0;
1461
1462 #ifndef SPNG_DISABLE_OPT
1463     if(filter == SPNG_FILTER_UP) goto no_opt;
1464
1465     if(bytes_per_pixel == 4)
1466     {
1467         if(filter == SPNG_FILTER_SUB)
1468             defilter_sub4(scanline_width, scanline);
1469         else if(filter == SPNG_FILTER_AVERAGE)
1470             defilter_avg4(scanline_width, scanline, prev_scanline);
1471         else if(filter == SPNG_FILTER_PAETH)
1472             defilter_paeth4(scanline_width, scanline, prev_scanline);
1473         else return SPNG_EFILTER;
1474
1475         return 0;
1476     }
1477     else if(bytes_per_pixel == 3)
1478     {
1479         if(filter == SPNG_FILTER_SUB)
1480             defilter_sub3(scanline_width, scanline);
1481         else if(filter == SPNG_FILTER_AVERAGE)
1482             defilter_avg3(scanline_width, scanline, prev_scanline);
1483         else if(filter == SPNG_FILTER_PAETH)
1484             defilter_paeth3(scanline_width, scanline, prev_scanline);
1485         else return SPNG_EFILTER;
1486
1487         return 0;
1488     }
1489 no_opt:
1490 #endif
1491
1492     if(filter == SPNG_FILTER_UP)
1493     {
1494         defilter_up(scanline_width, scanline, prev_scanline);
1495         return 0;
1496     }
1497
1498     for(i=0; i < scanline_width; i++)
1499     {
1500         uint8_t x, a, b, c;
1501
1502         if(i >= bytes_per_pixel)
1503         {
1504             a = scanline[i - bytes_per_pixel];
1505             b = prev_scanline[i];
1506             c = prev_scanline[i - bytes_per_pixel];
1507         }
1508         else /* First pixel in row */
1509         {
1510             a = 0;
1511             b = prev_scanline[i];
1512             c = 0;
1513         }
1514
1515         x = scanline[i];
1516
1517         switch(filter)
1518         {
1519             case SPNG_FILTER_SUB:
1520             {
1521                 x = x + a;
1522                 break;
1523             }
1524             case SPNG_FILTER_AVERAGE:
1525             {
1526                 uint16_t avg = (a + b) / 2;
1527                 x = x + avg;
1528                 break;
1529             }
1530             case SPNG_FILTER_PAETH:
1531             {
1532                 x = x + paeth(a,b,c);
1533                 break;
1534             }
1535         }
1536
1537         scanline[i] = x;
1538     }
1539
1540     return 0;
1541 }
1542
1543 static int filter_scanline(unsigned char *filtered, const unsigned char *prev_scanline, const unsigned char *scanline,
1544                            size_t scanline_width, unsigned bytes_per_pixel, const unsigned filter)
1545 {
1546     if(prev_scanline == NULL || scanline == NULL || scanline_width <= 1) return SPNG_EINTERNAL;
1547
1548     if(filter > 4) return SPNG_EFILTER;
1549     if(filter == 0) return 0;
1550
1551     scanline_width--;
1552
1553     uint32_t i;
1554     for(i=0; i < scanline_width; i++)
1555     {
1556         uint8_t x, a, b, c;
1557
1558         if(i >= bytes_per_pixel)
1559         {
1560             a = scanline[i - bytes_per_pixel];
1561             b = prev_scanline[i];
1562             c = prev_scanline[i - bytes_per_pixel];
1563         }
1564         else /* first pixel in row */
1565         {
1566             a = 0;
1567             b = prev_scanline[i];
1568             c = 0;
1569         }
1570
1571         x = scanline[i];
1572
1573         switch(filter)
1574         {
1575             case SPNG_FILTER_SUB:
1576             {
1577                 x = x - a;
1578                 break;
1579             }
1580             case SPNG_FILTER_UP:
1581             {
1582                 x = x - b;
1583                 break;
1584             }
1585             case SPNG_FILTER_AVERAGE:
1586             {
1587                 uint16_t avg = (a + b) / 2;
1588                 x = x - avg;
1589                 break;
1590             }
1591             case SPNG_FILTER_PAETH:
1592             {
1593                 x = x - paeth(a,b,c);
1594                 break;
1595             }
1596         }
1597
1598         filtered[i] = x;
1599     }
1600
1601     return 0;
1602 }
1603
1604 static int32_t filter_sum(const unsigned char *prev_scanline, const unsigned char *scanline,
1605                           size_t size, unsigned bytes_per_pixel, const unsigned filter)
1606 {
1607     /* prevent potential over/underflow, bails out at a width of ~8M pixels for RGBA8 */
1608     if(size > (INT32_MAX / 128)) return INT32_MAX;
1609
1610     uint32_t i;
1611     int32_t sum = 0;
1612     uint8_t x, a, b, c;
1613
1614     for(i=0; i < size; i++)
1615     {
1616         if(i >= bytes_per_pixel)
1617         {
1618             a = scanline[i - bytes_per_pixel];
1619             b = prev_scanline[i];
1620             c = prev_scanline[i - bytes_per_pixel];
1621         }
1622         else /* first pixel in row */
1623         {
1624             a = 0;
1625             b = prev_scanline[i];
1626             c = 0;
1627         }
1628
1629         x = scanline[i];
1630
1631         switch(filter)
1632         {
1633             case SPNG_FILTER_NONE:
1634             {
1635                 break;
1636             }
1637             case SPNG_FILTER_SUB:
1638             {
1639                 x = x - a;
1640                 break;
1641             }
1642             case SPNG_FILTER_UP:
1643             {
1644                 x = x - b;
1645                 break;
1646             }
1647             case SPNG_FILTER_AVERAGE:
1648             {
1649                 uint16_t avg = (a + b) / 2;
1650                 x = x - avg;
1651                 break;
1652             }
1653             case SPNG_FILTER_PAETH:
1654             {
1655                 x = x - paeth(a,b,c);
1656                 break;
1657             }
1658         }
1659
1660         sum += 128 - abs((int)x - 128);
1661     }
1662
1663     return sum;
1664 }
1665
1666 static unsigned get_best_filter(const unsigned char *prev_scanline, const unsigned char *scanline,
1667                                 size_t scanline_width, unsigned bytes_per_pixel, const int choices)
1668 {
1669     if(!choices) return SPNG_FILTER_NONE;
1670
1671     scanline_width--;
1672
1673     int i;
1674     unsigned int best_filter = 0;
1675     enum spng_filter_choice flag;
1676     int32_t sum, best_score = INT32_MAX;
1677     int32_t filter_scores[5] = { INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX };
1678
1679     if( !(choices & (choices - 1)) )
1680     {/* only one choice/bit is set */
1681         for(i=0; i < 5; i++)
1682         {
1683             if(choices == 1 << (i + 3)) return i;
1684         }
1685     }
1686
1687     for(i=0; i < 5; i++)
1688     {
1689         flag = 1 << (i + 3);
1690
1691         if(choices & flag) sum = filter_sum(prev_scanline, scanline, scanline_width, bytes_per_pixel, i);
1692         else continue;
1693
1694         filter_scores[i] = abs(sum);
1695
1696         if(filter_scores[i] < best_score)
1697         {
1698             best_score = filter_scores[i];
1699             best_filter = i;
1700         }
1701     }
1702
1703     return best_filter;
1704 }
1705
1706 /* Scale "sbits" significant bits in "sample" from "bit_depth" to "target"
1707
1708    "bit_depth" must be a valid PNG depth
1709    "sbits" must be less than or equal to "bit_depth"
1710    "target" must be between 1 and 16
1711 */
1712 static uint16_t sample_to_target(uint16_t sample, unsigned bit_depth, unsigned sbits, unsigned target)
1713 {
1714     if(bit_depth == sbits)
1715     {
1716         if(target == sbits) return sample; /* No scaling */
1717     }/* bit_depth > sbits */
1718     else sample = sample >> (bit_depth - sbits); /* Shift significant bits to bottom */
1719
1720     /* Downscale */
1721     if(target < sbits) return sample >> (sbits - target);
1722
1723     /* Upscale using left bit replication */
1724     int8_t shift_amount = target - sbits;
1725     uint16_t sample_bits = sample;
1726     sample = 0;
1727
1728     while(shift_amount >= 0)
1729     {
1730         sample = sample | (sample_bits << shift_amount);
1731         shift_amount -= sbits;
1732     }
1733
1734     int8_t partial = shift_amount + (int8_t)sbits;
1735
1736     if(partial != 0) sample = sample | (sample_bits >> abs(shift_amount));
1737
1738     return sample;
1739 }
1740
1741 static inline void gamma_correct_row(unsigned char *row, uint32_t pixels, int fmt, const uint16_t *gamma_lut)
1742 {
1743     uint32_t i;
1744
1745     if(fmt == SPNG_FMT_RGBA8)
1746     {
1747         unsigned char *px;
1748         for(i=0; i < pixels; i++)
1749         {
1750             px = row + i * 4;
1751
1752             px[0] = gamma_lut[px[0]];
1753             px[1] = gamma_lut[px[1]];
1754             px[2] = gamma_lut[px[2]];
1755         }
1756     }
1757     else if(fmt == SPNG_FMT_RGBA16)
1758     {
1759         for(i=0; i < pixels; i++)
1760         {
1761             uint16_t px[4];
1762             memcpy(px, row + i * 8, 8);
1763
1764             px[0] = gamma_lut[px[0]];
1765             px[1] = gamma_lut[px[1]];
1766             px[2] = gamma_lut[px[2]];
1767
1768             memcpy(row + i * 8, px, 8);
1769         }
1770     }
1771     else if(fmt == SPNG_FMT_RGB8)
1772     {
1773         unsigned char *px;
1774         for(i=0; i < pixels; i++)
1775         {
1776             px = row + i * 3;
1777
1778             px[0] = gamma_lut[px[0]];
1779             px[1] = gamma_lut[px[1]];
1780             px[2] = gamma_lut[px[2]];
1781         }
1782     }
1783 }
1784
1785 /* Apply transparency to output row */
1786 static inline void trns_row(unsigned char *row,
1787                             const unsigned char *scanline,
1788                             const unsigned char *trns,
1789                             unsigned scanline_stride,
1790                             struct spng_ihdr *ihdr,
1791                             uint32_t pixels,
1792                             int fmt)
1793 {
1794     uint32_t i;
1795     unsigned row_stride;
1796     unsigned depth = ihdr->bit_depth;
1797
1798     if(fmt == SPNG_FMT_RGBA8)
1799     {
1800         if(ihdr->color_type == SPNG_COLOR_TYPE_GRAYSCALE) return; /* already applied in the decoding loop */
1801
1802         row_stride = 4;
1803         for(i=0; i < pixels; i++, scanline+=scanline_stride, row+=row_stride)
1804         {
1805             if(!memcmp(scanline, trns, scanline_stride)) row[3] = 0;
1806         }
1807     }
1808     else if(fmt == SPNG_FMT_RGBA16)
1809     {
1810         if(ihdr->color_type == SPNG_COLOR_TYPE_GRAYSCALE) return; /* already applied in the decoding loop */
1811
1812         row_stride = 8;
1813         for(i=0; i < pixels; i++, scanline+=scanline_stride, row+=row_stride)
1814         {
1815             if(!memcmp(scanline, trns, scanline_stride)) memset(row + 6, 0, 2);
1816         }
1817     }
1818     else if(fmt == SPNG_FMT_GA8)
1819     {
1820         row_stride = 2;
1821
1822         if(depth == 16)
1823         {
1824             for(i=0; i < pixels; i++, scanline+=scanline_stride, row+=row_stride)
1825             {
1826                 if(!memcmp(scanline, trns, scanline_stride)) memset(row + 1, 0, 1);
1827             }
1828         }
1829         else /* depth <= 8 */
1830         {
1831             struct spng__iter iter = spng__iter_init(depth, scanline);
1832
1833             for(i=0; i < pixels; i++, row+=row_stride)
1834             {
1835                 if(trns[0] == get_sample(&iter)) row[1] = 0;
1836             }
1837         }
1838     }
1839     else if(fmt == SPNG_FMT_GA16)
1840     {
1841         row_stride = 4;
1842
1843         if(depth == 16)
1844         {
1845             for(i=0; i< pixels; i++, scanline+=scanline_stride, row+=row_stride)
1846             {
1847                 if(!memcmp(scanline, trns, 2)) memset(row + 2, 0, 2);
1848             }
1849         }
1850         else
1851         {
1852             struct spng__iter iter = spng__iter_init(depth, scanline);
1853
1854             for(i=0; i< pixels; i++, row+=row_stride)
1855             {
1856                 if(trns[0] == get_sample(&iter)) memset(row + 2, 0, 2);
1857             }
1858         }
1859     }
1860     else return;
1861 }
1862
1863 static inline void scale_row(unsigned char *row, uint32_t pixels, int fmt, unsigned depth, const struct spng_sbit *sbit)
1864 {
1865     uint32_t i;
1866
1867     if(fmt == SPNG_FMT_RGBA8)
1868     {
1869         unsigned char px[4];
1870         for(i=0; i < pixels; i++)
1871         {
1872             memcpy(px, row + i * 4, 4);
1873
1874             px[0] = sample_to_target(px[0], depth, sbit->red_bits, 8);
1875             px[1] = sample_to_target(px[1], depth, sbit->green_bits, 8);
1876             px[2] = sample_to_target(px[2], depth, sbit->blue_bits, 8);
1877             px[3] = sample_to_target(px[3], depth, sbit->alpha_bits, 8);
1878
1879             memcpy(row + i * 4, px, 4);
1880         }
1881     }
1882     else if(fmt == SPNG_FMT_RGBA16)
1883     {
1884         uint16_t px[4];
1885         for(i=0; i < pixels; i++)
1886         {
1887             memcpy(px, row + i * 8, 8);
1888
1889             px[0] = sample_to_target(px[0], depth, sbit->red_bits, 16);
1890             px[1] = sample_to_target(px[1], depth, sbit->green_bits, 16);
1891             px[2] = sample_to_target(px[2], depth, sbit->blue_bits, 16);
1892             px[3] = sample_to_target(px[3], depth, sbit->alpha_bits, 16);
1893
1894             memcpy(row + i * 8, px, 8);
1895         }
1896     }
1897     else if(fmt == SPNG_FMT_RGB8)
1898     {
1899         unsigned char px[4];
1900         for(i=0; i < pixels; i++)
1901         {
1902             memcpy(px, row + i * 3, 3);
1903
1904             px[0] = sample_to_target(px[0], depth, sbit->red_bits, 8);
1905             px[1] = sample_to_target(px[1], depth, sbit->green_bits, 8);
1906             px[2] = sample_to_target(px[2], depth, sbit->blue_bits, 8);
1907
1908             memcpy(row + i * 3, px, 3);
1909         }
1910     }
1911     else if(fmt == SPNG_FMT_G8)
1912     {
1913         for(i=0; i < pixels; i++)
1914         {
1915             row[i] = sample_to_target(row[i], depth, sbit->grayscale_bits, 8);
1916         }
1917     }
1918     else if(fmt == SPNG_FMT_GA8)
1919     {
1920         for(i=0; i < pixels; i++)
1921         {
1922             row[i*2] = sample_to_target(row[i*2], depth, sbit->grayscale_bits, 8);
1923         }
1924     }
1925 }
1926
1927 /* Expand to *row using 8-bit palette indices from *scanline */
1928 static void expand_row(unsigned char *row,
1929                        const unsigned char *scanline,
1930                        const union spng__decode_plte *decode_plte,
1931                        uint32_t width,
1932                        int fmt)
1933 {
1934     uint32_t i = 0;
1935     unsigned char *px;
1936     unsigned char entry;
1937     const struct spng_plte_entry *plte = decode_plte->rgba;
1938
1939 #if defined(SPNG_ARM)
1940     if(fmt == SPNG_FMT_RGBA8) i = expand_palette_rgba8_neon(row, scanline, decode_plte->raw, width);
1941     else if(fmt == SPNG_FMT_RGB8)
1942     {
1943         i = expand_palette_rgb8_neon(row, scanline, decode_plte->raw, width);
1944
1945         for(; i < width; i++)
1946         {/* In this case the LUT is 3 bytes packed */
1947             px = row + i * 3;
1948             entry = scanline[i];
1949             px[0] = decode_plte->raw[entry * 3 + 0];
1950             px[1] = decode_plte->raw[entry * 3 + 1];
1951             px[2] = decode_plte->raw[entry * 3 + 2];
1952         }
1953         return;
1954     }
1955 #endif
1956
1957     if(fmt == SPNG_FMT_RGBA8)
1958     {
1959         for(; i < width; i++)
1960         {
1961             px = row + i * 4;
1962             entry = scanline[i];
1963             px[0] = plte[entry].red;
1964             px[1] = plte[entry].green;
1965             px[2] = plte[entry].blue;
1966             px[3] = plte[entry].alpha;
1967         }
1968     }
1969     else if(fmt == SPNG_FMT_RGB8)
1970     {
1971         for(; i < width; i++)
1972         {
1973             px = row + i * 3;
1974             entry = scanline[i];
1975             px[0] = plte[entry].red;
1976             px[1] = plte[entry].green;
1977             px[2] = plte[entry].blue;
1978         }
1979     }
1980 }
1981
1982 /* Unpack 1/2/4/8-bit samples to G8/GA8/GA16 or G16 -> GA16 */
1983 static void unpack_scanline(unsigned char *out, const unsigned char *scanline, uint32_t width, unsigned bit_depth, int fmt)
1984 {
1985     struct spng__iter iter = spng__iter_init(bit_depth, scanline);
1986     uint32_t i;
1987     uint16_t sample, alpha = 65535;
1988
1989
1990     if(fmt == SPNG_FMT_GA8) goto ga8;
1991     else if(fmt == SPNG_FMT_GA16) goto ga16;
1992
1993     /* 1/2/4-bit -> 8-bit */
1994     for(i=0; i < width; i++) out[i] = get_sample(&iter);
1995
1996     return;
1997
1998 ga8:
1999     /* 1/2/4/8-bit -> GA8 */
2000     for(i=0; i < width; i++)
2001     {
2002         out[i*2] = get_sample(&iter);
2003         out[i*2 + 1] = 255;
2004     }
2005
2006     return;
2007
2008 ga16:
2009
2010     /* 16 -> GA16 */
2011     if(bit_depth == 16)
2012     {
2013         for(i=0; i < width; i++)
2014         {
2015             memcpy(out + i * 4, scanline + i * 2, 2);
2016             memcpy(out + i * 4 + 2, &alpha, 2);
2017         }
2018         return;
2019     }
2020
2021      /* 1/2/4/8-bit -> GA16 */
2022     for(i=0; i < width; i++)
2023     {
2024         sample = get_sample(&iter);
2025         memcpy(out + i * 4, &sample, 2);
2026         memcpy(out + i * 4 + 2, &alpha, 2);
2027     }
2028 }
2029
2030 static int check_ihdr(const struct spng_ihdr *ihdr, uint32_t max_width, uint32_t max_height)
2031 {
2032     if(ihdr->width > spng_u32max || !ihdr->width) return SPNG_EWIDTH;
2033     if(ihdr->height > spng_u32max || !ihdr->height) return SPNG_EHEIGHT;
2034
2035     if(ihdr->width > max_width) return SPNG_EUSER_WIDTH;
2036     if(ihdr->height > max_height) return SPNG_EUSER_HEIGHT;
2037
2038     switch(ihdr->color_type)
2039     {
2040         case SPNG_COLOR_TYPE_GRAYSCALE:
2041         {
2042             if( !(ihdr->bit_depth == 1 || ihdr->bit_depth == 2 ||
2043                   ihdr->bit_depth == 4 || ihdr->bit_depth == 8 ||
2044                   ihdr->bit_depth == 16) )
2045                   return SPNG_EBIT_DEPTH;
2046
2047             break;
2048         }
2049         case SPNG_COLOR_TYPE_TRUECOLOR:
2050         case SPNG_COLOR_TYPE_GRAYSCALE_ALPHA:
2051         case SPNG_COLOR_TYPE_TRUECOLOR_ALPHA:
2052         {
2053             if( !(ihdr->bit_depth == 8 || ihdr->bit_depth == 16) )
2054                 return SPNG_EBIT_DEPTH;
2055
2056             break;
2057         }
2058         case SPNG_COLOR_TYPE_INDEXED:
2059         {
2060             if( !(ihdr->bit_depth == 1 || ihdr->bit_depth == 2 ||
2061                   ihdr->bit_depth == 4 || ihdr->bit_depth == 8) )
2062                 return SPNG_EBIT_DEPTH;
2063
2064             break;
2065         }
2066         default: return SPNG_ECOLOR_TYPE;
2067     }
2068
2069     if(ihdr->compression_method) return SPNG_ECOMPRESSION_METHOD;
2070     if(ihdr->filter_method) return SPNG_EFILTER_METHOD;
2071
2072     if(ihdr->interlace_method > 1) return SPNG_EINTERLACE_METHOD;
2073
2074     return 0;
2075 }
2076
2077 static int check_plte(const struct spng_plte *plte, const struct spng_ihdr *ihdr)
2078 {
2079     if(plte == NULL || ihdr == NULL) return 1;
2080
2081     if(plte->n_entries == 0) return 1;
2082     if(plte->n_entries > 256) return 1;
2083
2084     if(ihdr->color_type == SPNG_COLOR_TYPE_INDEXED)
2085     {
2086         if(plte->n_entries > (1U << ihdr->bit_depth)) return 1;
2087     }
2088
2089     return 0;
2090 }
2091
2092 static int check_sbit(const struct spng_sbit *sbit, const struct spng_ihdr *ihdr)
2093 {
2094     if(sbit == NULL || ihdr == NULL) return 1;
2095
2096     if(ihdr->color_type == 0)
2097     {
2098         if(sbit->grayscale_bits == 0) return SPNG_ESBIT;
2099         if(sbit->grayscale_bits > ihdr->bit_depth) return SPNG_ESBIT;
2100     }
2101     else if(ihdr->color_type == 2 || ihdr->color_type == 3)
2102     {
2103         if(sbit->red_bits == 0) return SPNG_ESBIT;
2104         if(sbit->green_bits == 0) return SPNG_ESBIT;
2105         if(sbit->blue_bits == 0) return SPNG_ESBIT;
2106
2107         uint8_t bit_depth;
2108         if(ihdr->color_type == 3) bit_depth = 8;
2109         else bit_depth = ihdr->bit_depth;
2110
2111         if(sbit->red_bits > bit_depth) return SPNG_ESBIT;
2112         if(sbit->green_bits > bit_depth) return SPNG_ESBIT;
2113         if(sbit->blue_bits > bit_depth) return SPNG_ESBIT;
2114     }
2115     else if(ihdr->color_type == 4)
2116     {
2117         if(sbit->grayscale_bits == 0) return SPNG_ESBIT;
2118         if(sbit->alpha_bits == 0) return SPNG_ESBIT;
2119
2120         if(sbit->grayscale_bits > ihdr->bit_depth) return SPNG_ESBIT;
2121         if(sbit->alpha_bits > ihdr->bit_depth) return SPNG_ESBIT;
2122     }
2123     else if(ihdr->color_type == 6)
2124     {
2125         if(sbit->red_bits == 0) return SPNG_ESBIT;
2126         if(sbit->green_bits == 0) return SPNG_ESBIT;
2127         if(sbit->blue_bits == 0) return SPNG_ESBIT;
2128         if(sbit->alpha_bits == 0) return SPNG_ESBIT;
2129
2130         if(sbit->red_bits > ihdr->bit_depth) return SPNG_ESBIT;
2131         if(sbit->green_bits > ihdr->bit_depth) return SPNG_ESBIT;
2132         if(sbit->blue_bits > ihdr->bit_depth) return SPNG_ESBIT;
2133         if(sbit->alpha_bits > ihdr->bit_depth) return SPNG_ESBIT;
2134     }
2135
2136     return 0;
2137 }
2138
2139 static int check_chrm_int(const struct spng_chrm_int *chrm_int)
2140 {
2141     if(chrm_int == NULL) return 1;
2142
2143     if(chrm_int->white_point_x > spng_u32max ||
2144        chrm_int->white_point_y > spng_u32max ||
2145        chrm_int->red_x > spng_u32max ||
2146        chrm_int->red_y > spng_u32max ||
2147        chrm_int->green_x  > spng_u32max ||
2148        chrm_int->green_y  > spng_u32max ||
2149        chrm_int->blue_x > spng_u32max ||
2150        chrm_int->blue_y > spng_u32max) return SPNG_ECHRM;
2151
2152     return 0;
2153 }
2154
2155 static int check_phys(const struct spng_phys *phys)
2156 {
2157     if(phys == NULL) return 1;
2158
2159     if(phys->unit_specifier > 1) return SPNG_EPHYS;
2160
2161     if(phys->ppu_x > spng_u32max) return SPNG_EPHYS;
2162     if(phys->ppu_y > spng_u32max) return SPNG_EPHYS;
2163
2164     return 0;
2165 }
2166
2167 static int check_time(const struct spng_time *time)
2168 {
2169     if(time == NULL) return 1;
2170
2171     if(time->month == 0 || time->month > 12) return 1;
2172     if(time->day == 0 || time->day > 31) return 1;
2173     if(time->hour > 23) return 1;
2174     if(time->minute > 59) return 1;
2175     if(time->second > 60) return 1;
2176
2177     return 0;
2178 }
2179
2180 static int check_offs(const struct spng_offs *offs)
2181 {
2182     if(offs == NULL) return 1;
2183
2184     if(offs->unit_specifier > 1) return 1;
2185
2186     return 0;
2187 }
2188
2189 static int check_exif(const struct spng_exif *exif)
2190 {
2191     if(exif == NULL) return 1;
2192     if(exif->data == NULL) return 1;
2193
2194     if(exif->length < 4) return SPNG_ECHUNK_SIZE;
2195     if(exif->length > spng_u32max) return SPNG_ECHUNK_STDLEN;
2196
2197     const uint8_t exif_le[4] = { 73, 73, 42, 0 };
2198     const uint8_t exif_be[4] = { 77, 77, 0, 42 };
2199
2200     if(memcmp(exif->data, exif_le, 4) && memcmp(exif->data, exif_be, 4)) return 1;
2201
2202     return 0;
2203 }
2204
2205 /* Validate PNG keyword */
2206 static int check_png_keyword(const char *str)
2207 {
2208     if(str == NULL) return 1;
2209     size_t len = strlen(str);
2210     const char *end = str + len;
2211
2212     if(!len) return 1;
2213     if(len > 79) return 1;
2214     if(str[0] == ' ') return 1; /* Leading space */
2215     if(end[-1] == ' ') return 1; /* Trailing space */
2216     if(strstr(str, "  ") != NULL) return 1; /* Consecutive spaces */
2217
2218     uint8_t c;
2219     while(str != end)
2220     {
2221         memcpy(&c, str, 1);
2222
2223         if( (c >= 32 && c <= 126) || (c >= 161) ) str++;
2224         else return 1; /* Invalid character */
2225     }
2226
2227     return 0;
2228 }
2229
2230 /* Validate PNG text *str up to 'len' bytes */
2231 static int check_png_text(const char *str, size_t len)
2232 {/* XXX: are consecutive newlines permitted? */
2233     if(str == NULL || len == 0) return 1;
2234
2235     uint8_t c;
2236     size_t i = 0;
2237     while(i < len)
2238     {
2239         memcpy(&c, str + i, 1);
2240
2241         if( (c >= 32 && c <= 126) || (c >= 161) || c == 10) i++;
2242         else return 1; /* Invalid character */
2243     }
2244
2245     return 0;
2246 }
2247
2248 /* Returns non-zero for standard chunks which are stored without allocating memory */
2249 static int is_small_chunk(uint8_t type[4])
2250 {
2251     if(!memcmp(type, type_plte, 4)) return 1;
2252     else if(!memcmp(type, type_chrm, 4)) return 1;
2253     else if(!memcmp(type, type_gama, 4)) return 1;
2254     else if(!memcmp(type, type_sbit, 4)) return 1;
2255     else if(!memcmp(type, type_srgb, 4)) return 1;
2256     else if(!memcmp(type, type_bkgd, 4)) return 1;
2257     else if(!memcmp(type, type_trns, 4)) return 1;
2258     else if(!memcmp(type, type_hist, 4)) return 1;
2259     else if(!memcmp(type, type_phys, 4)) return 1;
2260     else if(!memcmp(type, type_time, 4)) return 1;
2261     else if(!memcmp(type, type_offs, 4)) return 1;
2262     else return 0;
2263 }
2264
2265 static int read_ihdr(spng_ctx *ctx)
2266 {
2267     int ret;
2268     struct spng_chunk *chunk = &ctx->current_chunk;
2269     const unsigned char *data;
2270
2271     chunk->offset = 8;
2272     chunk->length = 13;
2273     size_t sizeof_sig_ihdr = 29;
2274
2275     ret = read_data(ctx, sizeof_sig_ihdr);
2276     if(ret) return ret;
2277
2278     data = ctx->data;
2279
2280     if(memcmp(data, spng_signature, sizeof(spng_signature))) return SPNG_ESIGNATURE;
2281
2282     chunk->length = read_u32(data + 8);
2283     memcpy(&chunk->type, data + 12, 4);
2284
2285     if(chunk->length != 13) return SPNG_EIHDR_SIZE;
2286     if(memcmp(chunk->type, type_ihdr, 4)) return SPNG_ENOIHDR;
2287
2288     ctx->cur_actual_crc = crc32(0, NULL, 0);
2289     ctx->cur_actual_crc = crc32(ctx->cur_actual_crc, data + 12, 17);
2290
2291     ctx->ihdr.width = read_u32(data + 16);
2292     ctx->ihdr.height = read_u32(data + 20);
2293     ctx->ihdr.bit_depth = data[24];
2294     ctx->ihdr.color_type = data[25];
2295     ctx->ihdr.compression_method = data[26];
2296     ctx->ihdr.filter_method = data[27];
2297     ctx->ihdr.interlace_method = data[28];
2298
2299     ret = check_ihdr(&ctx->ihdr, ctx->max_width, ctx->max_height);
2300     if(ret) return ret;
2301
2302     ctx->file.ihdr = 1;
2303     ctx->stored.ihdr = 1;
2304
2305     if(ctx->ihdr.bit_depth < 8) ctx->bytes_per_pixel = 1;
2306     else ctx->bytes_per_pixel = num_channels(&ctx->ihdr) * (ctx->ihdr.bit_depth / 8);
2307
2308     ret = calculate_subimages(ctx);
2309     if(ret) return ret;
2310
2311     return 0;
2312 }
2313
2314 static void splt_undo(spng_ctx *ctx)
2315 {
2316     struct spng_splt *splt = &ctx->splt_list[ctx->n_splt - 1];
2317
2318     spng__free(ctx, splt->entries);
2319
2320     decrease_cache_usage(ctx, sizeof(struct spng_splt));
2321     decrease_cache_usage(ctx, splt->n_entries * sizeof(struct spng_splt_entry));
2322
2323     splt->entries = NULL;
2324
2325     ctx->n_splt--;
2326 }
2327
2328 static void text_undo(spng_ctx *ctx)
2329 {
2330     struct spng_text2 *text = &ctx->text_list[ctx->n_text - 1];
2331
2332     spng__free(ctx, text->keyword);
2333     if(text->compression_flag) spng__free(ctx, text->text);
2334
2335     decrease_cache_usage(ctx, text->cache_usage);
2336     decrease_cache_usage(ctx, sizeof(struct spng_text2));
2337
2338     text->keyword = NULL;
2339     text->text = NULL;
2340
2341     ctx->n_text--;
2342 }
2343
2344 static void chunk_undo(spng_ctx *ctx)
2345 {
2346     struct spng_unknown_chunk *chunk = &ctx->chunk_list[ctx->n_chunks - 1];
2347
2348     spng__free(ctx, chunk->data);
2349
2350     decrease_cache_usage(ctx, chunk->length);
2351     decrease_cache_usage(ctx, sizeof(struct spng_unknown_chunk));
2352
2353     chunk->data = NULL;
2354
2355     ctx->n_chunks--;
2356 }
2357
2358 static int read_non_idat_chunks(spng_ctx *ctx)
2359 {
2360     int ret;
2361     struct spng_chunk chunk;
2362     const unsigned char *data;
2363
2364     ctx->discard = 0;
2365     ctx->undo = NULL;
2366     ctx->prev_stored = ctx->stored;
2367
2368     while( !(ret = read_header(ctx)))
2369     {
2370         if(ctx->discard)
2371         {
2372             if(ctx->undo) ctx->undo(ctx);
2373
2374             ctx->stored = ctx->prev_stored;
2375         }
2376
2377         ctx->discard = 0;
2378         ctx->undo = NULL;
2379
2380         ctx->prev_stored = ctx->stored;
2381         chunk = ctx->current_chunk;
2382
2383         if(!memcmp(chunk.type, type_idat, 4))
2384         {
2385             if(ctx->state < SPNG_STATE_FIRST_IDAT)
2386             {
2387                 if(ctx->ihdr.color_type == 3 && !ctx->stored.plte) return SPNG_ENOPLTE;
2388
2389                 ctx->first_idat = chunk;
2390                 return 0;
2391             }
2392
2393             if(ctx->prev_was_idat)
2394             {
2395                 /* Ignore extra IDAT's */
2396                 ret = discard_chunk_bytes(ctx, chunk.length);
2397                 if(ret) return ret;
2398
2399                 continue;
2400             }
2401             else return SPNG_ECHUNK_POS; /* IDAT chunk not at the end of the IDAT sequence */
2402         }
2403
2404         ctx->prev_was_idat = 0;
2405
2406         if(is_small_chunk(chunk.type))
2407         {
2408             /* None of the known chunks can be zero length */
2409             if(!chunk.length) return SPNG_ECHUNK_SIZE;
2410
2411             /* The largest of these chunks is PLTE with 256 entries */
2412             ret = read_chunk_bytes(ctx, chunk.length > 768 ? 768 : chunk.length);
2413             if(ret) return ret;
2414         }
2415
2416         data = ctx->data;
2417
2418         if(is_critical_chunk(&chunk))
2419         {
2420             if(!memcmp(chunk.type, type_plte, 4))
2421             {
2422                 if(ctx->file.trns || ctx->file.hist || ctx->file.bkgd) return SPNG_ECHUNK_POS;
2423                 if(chunk.length % 3 != 0) return SPNG_ECHUNK_SIZE;
2424
2425                 ctx->plte.n_entries = chunk.length / 3;
2426
2427                 if(check_plte(&ctx->plte, &ctx->ihdr)) return SPNG_ECHUNK_SIZE; /* XXX: EPLTE? */
2428
2429                 size_t i;
2430                 for(i=0; i < ctx->plte.n_entries; i++)
2431                 {
2432                     ctx->plte.entries[i].red   = data[i * 3];
2433                     ctx->plte.entries[i].green = data[i * 3 + 1];
2434                     ctx->plte.entries[i].blue  = data[i * 3 + 2];
2435                 }
2436
2437                 ctx->file.plte = 1;
2438                 ctx->stored.plte = 1;
2439             }
2440             else if(!memcmp(chunk.type, type_iend, 4))
2441             {
2442                 if(ctx->state == SPNG_STATE_AFTER_IDAT)
2443                 {
2444                     if(chunk.length) return SPNG_ECHUNK_SIZE;
2445
2446                     ret = read_and_check_crc(ctx);
2447                     if(ret == -SPNG_CRC_DISCARD) ret = 0;
2448
2449                     return ret;
2450                 }
2451                 else return SPNG_ECHUNK_POS;
2452             }
2453             else if(!memcmp(chunk.type, type_ihdr, 4)) return SPNG_ECHUNK_POS;
2454             else return SPNG_ECHUNK_UNKNOWN_CRITICAL;
2455         }
2456         else if(!memcmp(chunk.type, type_chrm, 4)) /* Ancillary chunks */
2457         {
2458             if(ctx->file.plte) return SPNG_ECHUNK_POS;
2459             if(ctx->state == SPNG_STATE_AFTER_IDAT) return SPNG_ECHUNK_POS;
2460             if(ctx->file.chrm) return SPNG_EDUP_CHRM;
2461
2462             if(chunk.length != 32) return SPNG_ECHUNK_SIZE;
2463
2464             ctx->chrm_int.white_point_x = read_u32(data);
2465             ctx->chrm_int.white_point_y = read_u32(data + 4);
2466             ctx->chrm_int.red_x = read_u32(data + 8);
2467             ctx->chrm_int.red_y = read_u32(data + 12);
2468             ctx->chrm_int.green_x = read_u32(data + 16);
2469             ctx->chrm_int.green_y = read_u32(data + 20);
2470             ctx->chrm_int.blue_x = read_u32(data + 24);
2471             ctx->chrm_int.blue_y = read_u32(data + 28);
2472
2473             if(check_chrm_int(&ctx->chrm_int)) return SPNG_ECHRM;
2474
2475             ctx->file.chrm = 1;
2476             ctx->stored.chrm = 1;
2477         }
2478         else if(!memcmp(chunk.type, type_gama, 4))
2479         {
2480             if(ctx->file.plte) return SPNG_ECHUNK_POS;
2481             if(ctx->state == SPNG_STATE_AFTER_IDAT) return SPNG_ECHUNK_POS;
2482             if(ctx->file.gama) return SPNG_EDUP_GAMA;
2483
2484             if(chunk.length != 4) return SPNG_ECHUNK_SIZE;
2485
2486             ctx->gama = read_u32(data);
2487
2488             if(!ctx->gama) return SPNG_EGAMA;
2489             if(ctx->gama > spng_u32max) return SPNG_EGAMA;
2490
2491             ctx->file.gama = 1;
2492             ctx->stored.gama = 1;
2493         }
2494         else if(!memcmp(chunk.type, type_sbit, 4))
2495         {
2496             if(ctx->file.plte) return SPNG_ECHUNK_POS;
2497             if(ctx->state == SPNG_STATE_AFTER_IDAT) return SPNG_ECHUNK_POS;
2498             if(ctx->file.sbit) return SPNG_EDUP_SBIT;
2499
2500             if(ctx->ihdr.color_type == 0)
2501             {
2502                 if(chunk.length != 1) return SPNG_ECHUNK_SIZE;
2503
2504                 ctx->sbit.grayscale_bits = data[0];
2505             }
2506             else if(ctx->ihdr.color_type == 2 || ctx->ihdr.color_type == 3)
2507             {
2508                 if(chunk.length != 3) return SPNG_ECHUNK_SIZE;
2509
2510                 ctx->sbit.red_bits = data[0];
2511                 ctx->sbit.green_bits = data[1];
2512                 ctx->sbit.blue_bits = data[2];
2513             }
2514             else if(ctx->ihdr.color_type == 4)
2515             {
2516                 if(chunk.length != 2) return SPNG_ECHUNK_SIZE;
2517
2518                 ctx->sbit.grayscale_bits = data[0];
2519                 ctx->sbit.alpha_bits = data[1];
2520             }
2521             else if(ctx->ihdr.color_type == 6)
2522             {
2523                 if(chunk.length != 4) return SPNG_ECHUNK_SIZE;
2524
2525                 ctx->sbit.red_bits = data[0];
2526                 ctx->sbit.green_bits = data[1];
2527                 ctx->sbit.blue_bits = data[2];
2528                 ctx->sbit.alpha_bits = data[3];
2529             }
2530
2531             if(check_sbit(&ctx->sbit, &ctx->ihdr)) return SPNG_ESBIT;
2532
2533             ctx->file.sbit = 1;
2534             ctx->stored.sbit = 1;
2535         }
2536         else if(!memcmp(chunk.type, type_srgb, 4))
2537         {
2538             if(ctx->file.plte) return SPNG_ECHUNK_POS;
2539             if(ctx->state == SPNG_STATE_AFTER_IDAT) return SPNG_ECHUNK_POS;
2540             if(ctx->file.srgb) return SPNG_EDUP_SRGB;
2541
2542             if(chunk.length != 1) return SPNG_ECHUNK_SIZE;
2543
2544             ctx->srgb_rendering_intent = data[0];
2545
2546             if(ctx->srgb_rendering_intent > 3) return SPNG_ESRGB;
2547
2548             ctx->file.srgb = 1;
2549             ctx->stored.srgb = 1;
2550         }
2551         else if(!memcmp(chunk.type, type_bkgd, 4))
2552         {
2553             if(ctx->state == SPNG_STATE_AFTER_IDAT) return SPNG_ECHUNK_POS;
2554             if(ctx->file.bkgd) return SPNG_EDUP_BKGD;
2555
2556             if(ctx->ihdr.color_type == 0 || ctx->ihdr.color_type == 4)
2557             {
2558                 if(chunk.length != 2) return SPNG_ECHUNK_SIZE;
2559
2560                 ctx->bkgd.gray = read_u16(data);
2561             }
2562             else if(ctx->ihdr.color_type == 2 || ctx->ihdr.color_type == 6)
2563             {
2564                 if(chunk.length != 6) return SPNG_ECHUNK_SIZE;
2565
2566                 ctx->bkgd.red = read_u16(data);
2567                 ctx->bkgd.green = read_u16(data + 2);
2568                 ctx->bkgd.blue = read_u16(data + 4);
2569             }
2570             else if(ctx->ihdr.color_type == 3)
2571             {
2572                 if(chunk.length != 1) return SPNG_ECHUNK_SIZE;
2573                 if(!ctx->file.plte) return SPNG_EBKGD_NO_PLTE;
2574
2575                 ctx->bkgd.plte_index = data[0];
2576                 if(ctx->bkgd.plte_index >= ctx->plte.n_entries) return SPNG_EBKGD_PLTE_IDX;
2577             }
2578
2579             ctx->file.bkgd = 1;
2580             ctx->stored.bkgd = 1;
2581         }
2582         else if(!memcmp(chunk.type, type_trns, 4))
2583         {
2584             if(ctx->state == SPNG_STATE_AFTER_IDAT) return SPNG_ECHUNK_POS;
2585             if(ctx->file.trns) return SPNG_EDUP_TRNS;
2586             if(!chunk.length) return SPNG_ECHUNK_SIZE;
2587
2588             if(ctx->ihdr.color_type == 0)
2589             {
2590                 if(chunk.length != 2) return SPNG_ECHUNK_SIZE;
2591
2592                 ctx->trns.gray = read_u16(data);
2593             }
2594             else if(ctx->ihdr.color_type == 2)
2595             {
2596                 if(chunk.length != 6) return SPNG_ECHUNK_SIZE;
2597
2598                 ctx->trns.red = read_u16(data);
2599                 ctx->trns.green = read_u16(data + 2);
2600                 ctx->trns.blue = read_u16(data + 4);
2601             }
2602             else if(ctx->ihdr.color_type == 3)
2603             {
2604                 if(chunk.length > ctx->plte.n_entries) return SPNG_ECHUNK_SIZE;
2605                 if(!ctx->file.plte) return SPNG_ETRNS_NO_PLTE;
2606
2607                 memcpy(ctx->trns.type3_alpha, data, chunk.length);
2608                 ctx->trns.n_type3_entries = chunk.length;
2609             }
2610
2611             if(ctx->ihdr.color_type == 4 || ctx->ihdr.color_type == 6)  return SPNG_ETRNS_COLOR_TYPE;
2612
2613             ctx->file.trns = 1;
2614             ctx->stored.trns = 1;
2615         }
2616         else if(!memcmp(chunk.type, type_hist, 4))
2617         {
2618             if(!ctx->file.plte) return SPNG_EHIST_NO_PLTE;
2619             if(ctx->state == SPNG_STATE_AFTER_IDAT) return SPNG_ECHUNK_POS;
2620             if(ctx->file.hist) return SPNG_EDUP_HIST;
2621
2622             if( (chunk.length / 2) != (ctx->plte.n_entries) ) return SPNG_ECHUNK_SIZE;
2623
2624             size_t k;
2625             for(k=0; k < (chunk.length / 2); k++)
2626             {
2627                 ctx->hist.frequency[k] = read_u16(data + k*2);
2628             }
2629
2630             ctx->file.hist = 1;
2631             ctx->stored.hist = 1;
2632         }
2633         else if(!memcmp(chunk.type, type_phys, 4))
2634         {
2635             if(ctx->state == SPNG_STATE_AFTER_IDAT) return SPNG_ECHUNK_POS;
2636             if(ctx->file.phys) return SPNG_EDUP_PHYS;
2637
2638             if(chunk.length != 9) return SPNG_ECHUNK_SIZE;
2639
2640             ctx->phys.ppu_x = read_u32(data);
2641             ctx->phys.ppu_y = read_u32(data + 4);
2642             ctx->phys.unit_specifier = data[8];
2643
2644             if(check_phys(&ctx->phys)) return SPNG_EPHYS;
2645
2646             ctx->file.phys = 1;
2647             ctx->stored.phys = 1;
2648         }
2649         else if(!memcmp(chunk.type, type_time, 4))
2650         {
2651             if(ctx->file.time) return SPNG_EDUP_TIME;
2652
2653             if(chunk.length != 7) return SPNG_ECHUNK_SIZE;
2654
2655             struct spng_time time;
2656
2657             time.year = read_u16(data);
2658             time.month = data[2];
2659             time.day = data[3];
2660             time.hour = data[4];
2661             time.minute = data[5];
2662             time.second = data[6];
2663
2664             if(check_time(&time)) return SPNG_ETIME;
2665
2666             ctx->file.time = 1;
2667
2668             if(!ctx->user.time) ctx->time = time;
2669
2670             ctx->stored.time = 1;
2671         }
2672         else if(!memcmp(chunk.type, type_offs, 4))
2673         {
2674             if(ctx->state == SPNG_STATE_AFTER_IDAT) return SPNG_ECHUNK_POS;
2675             if(ctx->file.offs) return SPNG_EDUP_OFFS;
2676
2677             if(chunk.length != 9) return SPNG_ECHUNK_SIZE;
2678
2679             ctx->offs.x = read_s32(data);
2680             ctx->offs.y = read_s32(data + 4);
2681             ctx->offs.unit_specifier = data[8];
2682
2683             if(check_offs(&ctx->offs)) return SPNG_EOFFS;
2684
2685             ctx->file.offs = 1;
2686             ctx->stored.offs = 1;
2687         }
2688         else /* Arbitrary-length chunk */
2689         {
2690
2691             if(!memcmp(chunk.type, type_exif, 4))
2692             {
2693                 if(ctx->file.exif) return SPNG_EDUP_EXIF;
2694
2695                 ctx->file.exif = 1;
2696
2697                 if(ctx->user.exif) goto discard;
2698
2699                 if(increase_cache_usage(ctx, chunk.length, 1)) return SPNG_ECHUNK_LIMITS;
2700
2701                 struct spng_exif exif;
2702
2703                 exif.length = chunk.length;
2704
2705                 exif.data = spng__malloc(ctx, chunk.length);
2706                 if(exif.data == NULL) return SPNG_EMEM;
2707
2708                 ret = read_chunk_bytes2(ctx, exif.data, chunk.length);
2709                 if(ret)
2710                 {
2711                     spng__free(ctx, exif.data);
2712                     return ret;
2713                 }
2714
2715                 if(check_exif(&exif))
2716                 {
2717                     spng__free(ctx, exif.data);
2718                     return SPNG_EEXIF;
2719                 }
2720
2721                 ctx->exif = exif;
2722
2723                 ctx->stored.exif = 1;
2724             }
2725             else if(!memcmp(chunk.type, type_iccp, 4))
2726             {/* TODO: add test file with color profile */
2727                 if(ctx->file.plte) return SPNG_ECHUNK_POS;
2728                 if(ctx->state == SPNG_STATE_AFTER_IDAT) return SPNG_ECHUNK_POS;
2729                 if(ctx->file.iccp) return SPNG_EDUP_ICCP;
2730                 if(!chunk.length) return SPNG_ECHUNK_SIZE;
2731
2732                 ctx->file.iccp = 1;
2733
2734                 uint32_t peek_bytes =  81 > chunk.length ? chunk.length : 81;
2735
2736                 ret = read_chunk_bytes(ctx, peek_bytes);
2737                 if(ret) return ret;
2738
2739                 unsigned char *keyword_nul = memchr(ctx->data, '\0', peek_bytes);
2740                 if(keyword_nul == NULL) return SPNG_EICCP_NAME;
2741
2742                 uint32_t keyword_len = keyword_nul - ctx->data;
2743
2744                 if(keyword_len > 79) return SPNG_EICCP_NAME;
2745
2746                 memcpy(ctx->iccp.profile_name, ctx->data, keyword_len);
2747
2748                 if(check_png_keyword(ctx->iccp.profile_name)) return SPNG_EICCP_NAME;
2749
2750                 if(chunk.length < (keyword_len + 2)) return SPNG_ECHUNK_SIZE;
2751
2752                 if(ctx->data[keyword_len + 1] != 0) return SPNG_EICCP_COMPRESSION_METHOD;
2753
2754                 ret = spng__inflate_stream(ctx, &ctx->iccp.profile, &ctx->iccp.profile_len, 0, ctx->data + keyword_len + 2, peek_bytes - (keyword_len + 2));
2755
2756                 if(ret) return ret;
2757
2758                 ctx->stored.iccp = 1;
2759             }
2760              else if(!memcmp(chunk.type, type_text, 4) ||
2761                      !memcmp(chunk.type, type_ztxt, 4) ||
2762                      !memcmp(chunk.type, type_itxt, 4))
2763             {
2764                 if(!chunk.length) return SPNG_ECHUNK_SIZE;
2765
2766                 ctx->file.text = 1;
2767
2768                 if(ctx->user.text) goto discard;
2769
2770                 if(increase_cache_usage(ctx, sizeof(struct spng_text2), 1)) return SPNG_ECHUNK_LIMITS;
2771
2772                 ctx->n_text++;
2773                 if(ctx->n_text < 1) return SPNG_EOVERFLOW;
2774                 if(sizeof(struct spng_text2) > SIZE_MAX / ctx->n_text) return SPNG_EOVERFLOW;
2775
2776                 void *buf = spng__realloc(ctx, ctx->text_list, ctx->n_text * sizeof(struct spng_text2));
2777                 if(buf == NULL) return SPNG_EMEM;
2778                 ctx->text_list = buf;
2779
2780                 struct spng_text2 *text = &ctx->text_list[ctx->n_text - 1];
2781                 memset(text, 0, sizeof(struct spng_text2));
2782
2783                 ctx->undo = text_undo;
2784
2785                 uint32_t text_offset = 0, language_tag_offset = 0, translated_keyword_offset = 0;
2786                 uint32_t peek_bytes = 256; /* enough for 3 80-byte keywords and some text bytes */
2787                 uint32_t keyword_len;
2788
2789                 if(peek_bytes > chunk.length) peek_bytes = chunk.length;
2790
2791                 ret = read_chunk_bytes(ctx, peek_bytes);
2792                 if(ret) return ret;
2793
2794                 data = ctx->data;
2795
2796                 const unsigned char *zlib_stream = NULL;
2797                 const unsigned char *peek_end = data + peek_bytes;
2798                 const unsigned char *keyword_nul = memchr(data, 0, chunk.length > 80 ? 80 : chunk.length);
2799
2800                 if(keyword_nul == NULL) return SPNG_ETEXT_KEYWORD;
2801
2802                 keyword_len = keyword_nul - data;
2803
2804                 if(!memcmp(chunk.type, type_text, 4))
2805                 {
2806                     text->type = SPNG_TEXT;
2807
2808                     text->text_length = chunk.length - keyword_len - 1;
2809
2810                     text_offset = keyword_len;
2811
2812                     /* increment past nul if there is a text field */
2813                     if(text->text_length) text_offset++;
2814                 }
2815                 else if(!memcmp(chunk.type, type_ztxt, 4))
2816                 {
2817                     text->type = SPNG_ZTXT;
2818
2819                     if((peek_bytes - keyword_len) <= 2) return SPNG_EZTXT;
2820
2821                     if(keyword_nul[1]) return SPNG_EZTXT_COMPRESSION_METHOD;
2822
2823                     text->compression_flag = 1;
2824
2825                     text_offset = keyword_len + 2;
2826                 }
2827                 else if(!memcmp(chunk.type, type_itxt, 4))
2828                 {
2829                     text->type = SPNG_ITXT;
2830
2831                     /* at least two 1-byte fields, two >=0 length strings, and one byte of (compressed) text */
2832                     if((peek_bytes - keyword_len) < 5) return SPNG_EITXT;
2833
2834                     text->compression_flag = keyword_nul[1];
2835
2836                     if(text->compression_flag > 1) return SPNG_EITXT_COMPRESSION_FLAG;
2837
2838                     if(keyword_nul[2]) return SPNG_EITXT_COMPRESSION_METHOD;
2839
2840                     language_tag_offset = keyword_len + 3;
2841
2842                     const unsigned char *term;
2843                     term = memchr(data + language_tag_offset, 0, peek_bytes - language_tag_offset);
2844                     if(term == NULL) return SPNG_EITXT_LANG_TAG;
2845
2846                     if((peek_end - term) < 2) return SPNG_EITXT;
2847
2848                     translated_keyword_offset = term - data + 1;
2849
2850                     zlib_stream = memchr(data + translated_keyword_offset, 0, peek_bytes - translated_keyword_offset);
2851                     if(zlib_stream == NULL) return SPNG_EITXT;
2852                     if(zlib_stream == peek_end) return SPNG_EITXT;
2853
2854                     text_offset = zlib_stream - data + 1;
2855                     text->text_length = chunk.length - text_offset;
2856                 }
2857                 else return SPNG_EINTERNAL;
2858
2859
2860                 if(text->compression_flag)
2861                 {
2862                     /* cache usage = peek_bytes + decompressed text size + nul */
2863                     if(increase_cache_usage(ctx, peek_bytes, 0)) return SPNG_ECHUNK_LIMITS;
2864
2865                     text->keyword = spng__calloc(ctx, 1, peek_bytes);
2866                     if(text->keyword == NULL) return SPNG_EMEM;
2867
2868                     memcpy(text->keyword, data, peek_bytes);
2869
2870                     zlib_stream = ctx->data + text_offset;
2871
2872                     ret = spng__inflate_stream(ctx, &text->text, &text->text_length, 1, zlib_stream, peek_bytes - text_offset);
2873
2874                     if(ret) return ret;
2875
2876                     text->text[text->text_length - 1] = '\0';
2877                     text->cache_usage = text->text_length + peek_bytes;
2878                 }
2879                 else
2880                 {
2881                     if(increase_cache_usage(ctx, chunk.length + 1, 0)) return SPNG_ECHUNK_LIMITS;
2882
2883                     text->keyword = spng__malloc(ctx, chunk.length + 1);
2884                     if(text->keyword == NULL) return SPNG_EMEM;
2885
2886                     memcpy(text->keyword, data, peek_bytes);
2887
2888                     if(chunk.length > peek_bytes)
2889                     {
2890                         ret = read_chunk_bytes2(ctx, text->keyword + peek_bytes, chunk.length - peek_bytes);
2891                         if(ret) return ret;
2892                     }
2893
2894                     text->text = text->keyword + text_offset;
2895
2896                     text->text_length = chunk.length - text_offset;
2897
2898                     text->text[text->text_length] = '\0';
2899                     text->cache_usage = chunk.length + 1;
2900                 }
2901
2902                 if(check_png_keyword(text->keyword)) return SPNG_ETEXT_KEYWORD;
2903
2904                 text->text_length = strlen(text->text);
2905
2906                 if(text->type != SPNG_ITXT)
2907                 {
2908                     language_tag_offset = keyword_len;
2909                     translated_keyword_offset = keyword_len;
2910
2911                     if(ctx->strict && check_png_text(text->text, text->text_length))
2912                     {
2913                         if(text->type == SPNG_ZTXT) return SPNG_EZTXT;
2914                         else return SPNG_ETEXT;
2915                     }
2916                 }
2917
2918                 text->language_tag = text->keyword + language_tag_offset;
2919                 text->translated_keyword = text->keyword + translated_keyword_offset;
2920
2921                 ctx->stored.text = 1;
2922             }
2923             else if(!memcmp(chunk.type, type_splt, 4))
2924             {
2925                 if(ctx->state == SPNG_STATE_AFTER_IDAT) return SPNG_ECHUNK_POS;
2926                 if(ctx->user.splt) goto discard; /* XXX: could check profile names for uniqueness */
2927                 if(!chunk.length) return SPNG_ECHUNK_SIZE;
2928
2929                 ctx->file.splt = 1;
2930
2931                 /* chunk.length + sizeof(struct spng_splt) + splt->n_entries * sizeof(struct spng_splt_entry) */
2932                 if(increase_cache_usage(ctx, chunk.length + sizeof(struct spng_splt), 1)) return SPNG_ECHUNK_LIMITS;
2933
2934                 ctx->n_splt++;
2935                 if(ctx->n_splt < 1) return SPNG_EOVERFLOW;
2936                 if(sizeof(struct spng_splt) > SIZE_MAX / ctx->n_splt) return SPNG_EOVERFLOW;
2937
2938                 void *buf = spng__realloc(ctx, ctx->splt_list, ctx->n_splt * sizeof(struct spng_splt));
2939                 if(buf == NULL) return SPNG_EMEM;
2940                 ctx->splt_list = buf;
2941
2942                 struct spng_splt *splt = &ctx->splt_list[ctx->n_splt - 1];
2943
2944                 memset(splt, 0, sizeof(struct spng_splt));
2945
2946                 ctx->undo = splt_undo;
2947
2948                 void *t = spng__malloc(ctx, chunk.length);
2949                 if(t == NULL) return SPNG_EMEM;
2950
2951                 splt->entries = t; /* simplifies error handling */
2952                 data = t;
2953
2954                 ret = read_chunk_bytes2(ctx, t, chunk.length);
2955                 if(ret) return ret;
2956
2957                 uint32_t keyword_len = chunk.length < 80 ? chunk.length : 80;
2958
2959                 const unsigned char *keyword_nul = memchr(data, 0, keyword_len);
2960                 if(keyword_nul == NULL) return SPNG_ESPLT_NAME;
2961
2962                 keyword_len = keyword_nul - data;
2963
2964                 memcpy(splt->name, data, keyword_len);
2965
2966                 if(check_png_keyword(splt->name)) return SPNG_ESPLT_NAME;
2967
2968                 uint32_t j;
2969                 for(j=0; j < (ctx->n_splt - 1); j++)
2970                 {
2971                     if(!strcmp(ctx->splt_list[j].name, splt->name)) return SPNG_ESPLT_DUP_NAME;
2972                 }
2973
2974                 if( (chunk.length - keyword_len) <= 2) return SPNG_ECHUNK_SIZE;
2975
2976                 splt->sample_depth = data[keyword_len + 1];
2977
2978                 uint32_t entries_len = chunk.length - keyword_len - 2;
2979                 if(!entries_len) return SPNG_ECHUNK_SIZE;
2980
2981                 if(splt->sample_depth == 16)
2982                 {
2983                     if(entries_len % 10 != 0) return SPNG_ECHUNK_SIZE;
2984                     splt->n_entries = entries_len / 10;
2985                 }
2986                 else if(splt->sample_depth == 8)
2987                 {
2988                     if(entries_len % 6 != 0) return SPNG_ECHUNK_SIZE;
2989                     splt->n_entries = entries_len / 6;
2990                 }
2991                 else return SPNG_ESPLT_DEPTH;
2992
2993                 if(!splt->n_entries) return SPNG_ECHUNK_SIZE;
2994
2995                 size_t list_size = splt->n_entries;
2996
2997                 if(list_size > SIZE_MAX / sizeof(struct spng_splt_entry)) return SPNG_EOVERFLOW;
2998
2999                 list_size *= sizeof(struct spng_splt_entry);
3000
3001                 if(increase_cache_usage(ctx, list_size, 0)) return SPNG_ECHUNK_LIMITS;
3002
3003                 splt->entries = spng__malloc(ctx, list_size);
3004                 if(splt->entries == NULL)
3005                 {
3006                     spng__free(ctx, t);
3007                     return SPNG_EMEM;
3008                 }
3009
3010                 data = (unsigned char*)t + keyword_len + 2;
3011
3012                 uint32_t k;
3013                 if(splt->sample_depth == 16)
3014                 {
3015                     for(k=0; k < splt->n_entries; k++)
3016                     {
3017                         splt->entries[k].red =   read_u16(data + k * 10);
3018                         splt->entries[k].green = read_u16(data + k * 10 + 2);
3019                         splt->entries[k].blue =  read_u16(data + k * 10 + 4);
3020                         splt->entries[k].alpha = read_u16(data + k * 10 + 6);
3021                         splt->entries[k].frequency = read_u16(data + k * 10 + 8);
3022                     }
3023                 }
3024                 else if(splt->sample_depth == 8)
3025                 {
3026                     for(k=0; k < splt->n_entries; k++)
3027                     {
3028                         splt->entries[k].red =   data[k * 6];
3029                         splt->entries[k].green = data[k * 6 + 1];
3030                         splt->entries[k].blue =  data[k * 6 + 2];
3031                         splt->entries[k].alpha = data[k * 6 + 3];
3032                         splt->entries[k].frequency = read_u16(data + k * 6 + 4);
3033                     }
3034                 }
3035
3036                 spng__free(ctx, t);
3037                 decrease_cache_usage(ctx, chunk.length);
3038
3039                 ctx->stored.splt = 1;
3040             }
3041             else /* Unknown chunk */
3042             {
3043                 ctx->file.unknown = 1;
3044
3045                 if(!ctx->keep_unknown) goto discard;
3046                 if(ctx->user.unknown) goto discard;
3047
3048                 if(increase_cache_usage(ctx, chunk.length + sizeof(struct spng_unknown_chunk), 1)) return SPNG_ECHUNK_LIMITS;
3049
3050                 ctx->n_chunks++;
3051                 if(ctx->n_chunks < 1) return SPNG_EOVERFLOW;
3052                 if(sizeof(struct spng_unknown_chunk) > SIZE_MAX / ctx->n_chunks) return SPNG_EOVERFLOW;
3053
3054                 void *buf = spng__realloc(ctx, ctx->chunk_list, ctx->n_chunks * sizeof(struct spng_unknown_chunk));
3055                 if(buf == NULL) return SPNG_EMEM;
3056                 ctx->chunk_list = buf;
3057
3058                 struct spng_unknown_chunk *chunkp = &ctx->chunk_list[ctx->n_chunks - 1];
3059
3060                 memset(chunkp, 0, sizeof(struct spng_unknown_chunk));
3061
3062                 ctx->undo = chunk_undo;
3063
3064                 memcpy(chunkp->type, chunk.type, 4);
3065
3066                 if(ctx->state < SPNG_STATE_FIRST_IDAT)
3067                 {
3068                     if(ctx->file.plte) chunkp->location = SPNG_AFTER_PLTE;
3069                     else chunkp->location = SPNG_AFTER_IHDR;
3070                 }
3071                 else if(ctx->state >= SPNG_STATE_AFTER_IDAT) chunkp->location = SPNG_AFTER_IDAT;
3072
3073                 if(chunk.length > 0)
3074                 {
3075                     void *t = spng__malloc(ctx, chunk.length);
3076                     if(t == NULL) return SPNG_EMEM;
3077
3078                     ret = read_chunk_bytes2(ctx, t, chunk.length);
3079                     if(ret)
3080                     {
3081                         spng__free(ctx, t);
3082                         return ret;
3083                     }
3084
3085                     chunkp->length = chunk.length;
3086                     chunkp->data = t;
3087                 }
3088
3089                 ctx->stored.unknown = 1;
3090             }
3091
3092 discard:
3093             ret = discard_chunk_bytes(ctx, ctx->cur_chunk_bytes_left);
3094             if(ret) return ret;
3095         }
3096
3097     }
3098
3099     return ret;
3100 }
3101
3102 /* Read chunks before or after the IDAT chunks depending on state */
3103 static int read_chunks(spng_ctx *ctx, int only_ihdr)
3104 {
3105     if(ctx == NULL) return SPNG_EINTERNAL;
3106     if(!ctx->state) return SPNG_EBADSTATE;
3107     if(ctx->data == NULL)
3108     {
3109         if(ctx->encode_only) return 0;
3110         else return SPNG_EINTERNAL;
3111     }
3112
3113     int ret = 0;
3114
3115     if(ctx->state == SPNG_STATE_INPUT)
3116     {
3117         ret = read_ihdr(ctx);
3118
3119         if(ret) return decode_err(ctx, ret);
3120
3121         ctx->state = SPNG_STATE_IHDR;
3122     }
3123
3124     if(only_ihdr) return 0;
3125
3126     if(ctx->state == SPNG_STATE_EOI)
3127     {
3128         ctx->state = SPNG_STATE_AFTER_IDAT;
3129         ctx->prev_was_idat = 1;
3130     }
3131
3132     while(ctx->state < SPNG_STATE_FIRST_IDAT || ctx->state == SPNG_STATE_AFTER_IDAT)
3133     {
3134         ret = read_non_idat_chunks(ctx);
3135
3136         if(!ret)
3137         {
3138             if(ctx->state < SPNG_STATE_FIRST_IDAT) ctx->state = SPNG_STATE_FIRST_IDAT;
3139             else if(ctx->state == SPNG_STATE_AFTER_IDAT) ctx->state = SPNG_STATE_IEND;
3140         }
3141         else
3142         {
3143             switch(ret)
3144             {
3145                 case SPNG_ECHUNK_POS:
3146                 case SPNG_ECHUNK_SIZE: /* size != expected size, SPNG_ECHUNK_STDLEN = invalid size */
3147                 case SPNG_EDUP_PLTE:
3148                 case SPNG_EDUP_CHRM:
3149                 case SPNG_EDUP_GAMA:
3150                 case SPNG_EDUP_ICCP:
3151                 case SPNG_EDUP_SBIT:
3152                 case SPNG_EDUP_SRGB:
3153                 case SPNG_EDUP_BKGD:
3154                 case SPNG_EDUP_HIST:
3155                 case SPNG_EDUP_TRNS:
3156                 case SPNG_EDUP_PHYS:
3157                 case SPNG_EDUP_TIME:
3158                 case SPNG_EDUP_OFFS:
3159                 case SPNG_EDUP_EXIF:
3160                 case SPNG_ECHRM:
3161                 case SPNG_ETRNS_COLOR_TYPE:
3162                 case SPNG_ETRNS_NO_PLTE:
3163                 case SPNG_EGAMA:
3164                 case SPNG_EICCP_NAME:
3165                 case SPNG_EICCP_COMPRESSION_METHOD:
3166                 case SPNG_ESBIT:
3167                 case SPNG_ESRGB:
3168                 case SPNG_ETEXT:
3169                 case SPNG_ETEXT_KEYWORD:
3170                 case SPNG_EZTXT:
3171                 case SPNG_EZTXT_COMPRESSION_METHOD:
3172                 case SPNG_EITXT:
3173                 case SPNG_EITXT_COMPRESSION_FLAG:
3174                 case SPNG_EITXT_COMPRESSION_METHOD:
3175                 case SPNG_EITXT_LANG_TAG:
3176                 case SPNG_EITXT_TRANSLATED_KEY:
3177                 case SPNG_EBKGD_NO_PLTE:
3178                 case SPNG_EBKGD_PLTE_IDX:
3179                 case SPNG_EHIST_NO_PLTE:
3180                 case SPNG_EPHYS:
3181                 case SPNG_ESPLT_NAME:
3182                 case SPNG_ESPLT_DUP_NAME:
3183                 case SPNG_ESPLT_DEPTH:
3184                 case SPNG_ETIME:
3185                 case SPNG_EOFFS:
3186                 case SPNG_EEXIF:
3187                 case SPNG_EZLIB:
3188                 {
3189                     if(!ctx->strict && !is_critical_chunk(&ctx->current_chunk))
3190                     {
3191                         ret = discard_chunk_bytes(ctx, ctx->cur_chunk_bytes_left);
3192                         if(ret) return decode_err(ctx, ret);
3193
3194                         if(ctx->undo) ctx->undo(ctx);
3195
3196                         ctx->stored = ctx->prev_stored;
3197
3198                         ctx->discard = 0;
3199                         ctx->undo = NULL;
3200
3201                         continue;
3202                     }
3203                     else return decode_err(ctx, ret);
3204
3205                     break;
3206                 }
3207                 default: return decode_err(ctx, ret);
3208             }
3209         }
3210     }
3211
3212     return ret;
3213 }
3214
3215 static int read_scanline(spng_ctx *ctx)
3216 {
3217     int ret, pass = ctx->row_info.pass;
3218     struct spng_row_info *ri = &ctx->row_info;
3219     const struct spng_subimage *sub = ctx->subimage;
3220     size_t scanline_width = sub[pass].scanline_width;
3221     uint32_t scanline_idx = ri->scanline_idx;
3222
3223     uint8_t next_filter = 0;
3224
3225     if(scanline_idx == (sub[pass].height - 1) && ri->pass == ctx->last_pass)
3226     {
3227         ret = read_scanline_bytes(ctx, ctx->scanline, scanline_width - 1);
3228     }
3229     else
3230     {
3231         ret = read_scanline_bytes(ctx, ctx->scanline, scanline_width);
3232         if(ret) return ret;
3233
3234         next_filter = ctx->scanline[scanline_width - 1];
3235         if(next_filter > 4) ret = SPNG_EFILTER;
3236     }
3237
3238     if(ret) return ret;
3239
3240     if(!scanline_idx && ri->filter > 1)
3241     {
3242         /* prev_scanline is all zeros for the first scanline */
3243         memset(ctx->prev_scanline, 0, scanline_width);
3244     }
3245
3246     if(ctx->ihdr.bit_depth == 16 && ctx->fmt != SPNG_FMT_RAW) u16_row_to_host(ctx->scanline, scanline_width - 1);
3247
3248     ret = defilter_scanline(ctx->prev_scanline, ctx->scanline, scanline_width, ctx->bytes_per_pixel, ri->filter);
3249     if(ret) return ret;
3250
3251     ri->filter = next_filter;
3252
3253     return 0;
3254 }
3255
3256 static int update_row_info(spng_ctx *ctx)
3257 {
3258     int interlacing = ctx->ihdr.interlace_method;
3259     struct spng_row_info *ri = &ctx->row_info;
3260     const struct spng_subimage *sub = ctx->subimage;
3261
3262     if(ri->scanline_idx == (sub[ri->pass].height - 1)) /* Last scanline */
3263     {
3264         if(ri->pass == ctx->last_pass)
3265         {
3266             ctx->state = SPNG_STATE_EOI;
3267
3268             return SPNG_EOI;
3269         }
3270
3271         ri->scanline_idx = 0;
3272         ri->pass++;
3273
3274         /* Skip empty passes */
3275         while( (!sub[ri->pass].width || !sub[ri->pass].height) && (ri->pass < ctx->last_pass)) ri->pass++;
3276     }
3277     else
3278     {
3279         ri->row_num++;
3280         ri->scanline_idx++;
3281     }
3282
3283     if(interlacing) ri->row_num = adam7_y_start[ri->pass] + ri->scanline_idx * adam7_y_delta[ri->pass];
3284
3285     return 0;
3286 }
3287
3288 int spng_decode_scanline(spng_ctx *ctx, void *out, size_t len)
3289 {
3290     if(ctx == NULL || out == NULL) return 1;
3291
3292     if(ctx->state >= SPNG_STATE_EOI) return SPNG_EOI;
3293
3294     struct decode_flags f = ctx->decode_flags;
3295
3296     struct spng_row_info *ri = &ctx->row_info;
3297     const struct spng_subimage *sub = ctx->subimage;
3298
3299     const struct spng_ihdr *ihdr = &ctx->ihdr;
3300     const uint16_t *gamma_lut = ctx->gamma_lut;
3301     unsigned char *trns_px = ctx->trns_px;
3302     const struct spng_sbit *sb = &ctx->decode_sb;
3303     const struct spng_plte_entry *plte = ctx->decode_plte.rgba;
3304     struct spng__iter iter = spng__iter_init(ihdr->bit_depth, ctx->scanline);
3305
3306     const unsigned char *scanline;
3307
3308     const int pass = ri->pass;
3309     const int fmt = ctx->fmt;
3310     const size_t scanline_width = sub[pass].scanline_width;
3311     const uint32_t width = sub[pass].width;
3312     uint32_t k;
3313     uint8_t r_8, g_8, b_8, a_8, gray_8;
3314     uint16_t r_16, g_16, b_16, a_16, gray_16;
3315     r_8=0; g_8=0; b_8=0; a_8=0; gray_8=0;
3316     r_16=0; g_16=0; b_16=0; a_16=0; gray_16=0;
3317     size_t pixel_size = 4; /* SPNG_FMT_RGBA8 */
3318     size_t pixel_offset = 0;
3319     unsigned char *pixel;
3320     unsigned processing_depth = ihdr->bit_depth;
3321
3322     if(f.indexed) processing_depth = 8;
3323
3324     if(fmt == SPNG_FMT_RGBA16) pixel_size = 8;
3325     else if(fmt == SPNG_FMT_RGB8) pixel_size = 3;
3326
3327     if(len < sub[pass].out_width) return SPNG_EBUFSIZ;
3328
3329     int ret = read_scanline(ctx);
3330
3331     if(ret) return decode_err(ctx, ret);
3332
3333     scanline = ctx->scanline;
3334
3335     for(k=0; k < width; k++)
3336     {
3337         pixel = (unsigned char*)out + pixel_offset;
3338         pixel_offset += pixel_size;
3339
3340         if(f.same_layout)
3341         {
3342             if(f.zerocopy) break;
3343
3344             memcpy(out, scanline, scanline_width - 1);
3345             break;
3346         }
3347
3348         if(f.unpack)
3349         {
3350             unpack_scanline(out, scanline, width, ihdr->bit_depth, fmt);
3351             break;
3352         }
3353
3354         if(ihdr->color_type == SPNG_COLOR_TYPE_TRUECOLOR)
3355         {
3356             if(ihdr->bit_depth == 16)
3357             {
3358                 memcpy(&r_16, scanline + (k * 6), 2);
3359                 memcpy(&g_16, scanline + (k * 6) + 2, 2);
3360                 memcpy(&b_16, scanline + (k * 6) + 4, 2);
3361
3362                 a_16 = 65535;
3363             }
3364             else /* == 8 */
3365             {
3366                 if(fmt == SPNG_FMT_RGBA8)
3367                 {
3368                     rgb8_row_to_rgba8(scanline, out, width);
3369                     break;
3370                 }
3371
3372                 r_8 = scanline[k * 3];
3373                 g_8 = scanline[k * 3 + 1];
3374                 b_8 = scanline[k * 3 + 2];
3375
3376                 a_8 = 255;
3377             }
3378         }
3379         else if(ihdr->color_type == SPNG_COLOR_TYPE_INDEXED)
3380         {
3381             uint8_t entry = 0;
3382
3383             if(ihdr->bit_depth == 8)
3384             {
3385                 if(fmt & (SPNG_FMT_RGBA8 | SPNG_FMT_RGB8))
3386                 {
3387                     expand_row(out, scanline, &ctx->decode_plte, width, fmt);
3388                     break;
3389                 }
3390
3391                 entry = scanline[k];
3392             }
3393             else /* < 8 */
3394             {
3395                 entry = get_sample(&iter);
3396             }
3397
3398             if(fmt & (SPNG_FMT_RGBA8 | SPNG_FMT_RGB8))
3399             {
3400                 pixel[0] = plte[entry].red;
3401                 pixel[1] = plte[entry].green;
3402                 pixel[2] = plte[entry].blue;
3403                 if(fmt == SPNG_FMT_RGBA8) pixel[3] = plte[entry].alpha;
3404
3405                 continue;
3406             }
3407             else /* RGBA16 */
3408             {
3409                 r_16 = plte[entry].red;
3410                 g_16 = plte[entry].green;
3411                 b_16 = plte[entry].blue;
3412                 a_16 = plte[entry].alpha;
3413
3414                 r_16 = (r_16 << 8) | r_16;
3415                 g_16 = (g_16 << 8) | g_16;
3416                 b_16 = (b_16 << 8) | b_16;
3417                 a_16 = (a_16 << 8) | a_16;
3418
3419                 memcpy(pixel, &r_16, 2);
3420                 memcpy(pixel + 2, &g_16, 2);
3421                 memcpy(pixel + 4, &b_16, 2);
3422                 memcpy(pixel + 6, &a_16, 2);
3423
3424                 continue;
3425             }
3426         }
3427         else if(ihdr->color_type == SPNG_COLOR_TYPE_TRUECOLOR_ALPHA)
3428         {
3429             if(ihdr->bit_depth == 16)
3430             {
3431                 memcpy(&r_16, scanline + (k * 8), 2);
3432                 memcpy(&g_16, scanline + (k * 8) + 2, 2);
3433                 memcpy(&b_16, scanline + (k * 8) + 4, 2);
3434                 memcpy(&a_16, scanline + (k * 8) + 6, 2);
3435             }
3436             else /* == 8 */
3437             {
3438                 r_8 = scanline[k * 4];
3439                 g_8 = scanline[k * 4 + 1];
3440                 b_8 = scanline[k * 4 + 2];
3441                 a_8 = scanline[k * 4 + 3];
3442             }
3443         }
3444         else if(ihdr->color_type == SPNG_COLOR_TYPE_GRAYSCALE)
3445         {
3446             if(ihdr->bit_depth == 16)
3447             {
3448                 memcpy(&gray_16, scanline + k * 2, 2);
3449
3450                 if(f.apply_trns && ctx->trns.gray == gray_16) a_16 = 0;
3451                 else a_16 = 65535;
3452
3453                 r_16 = gray_16;
3454                 g_16 = gray_16;
3455                 b_16 = gray_16;
3456             }
3457             else /* <= 8 */
3458             {
3459                 gray_8 = get_sample(&iter);
3460
3461                 if(f.apply_trns && ctx->trns.gray == gray_8) a_8 = 0;
3462                 else a_8 = 255;
3463
3464                 r_8 = gray_8; g_8 = gray_8; b_8 = gray_8;
3465             }
3466         }
3467         else if(ihdr->color_type == SPNG_COLOR_TYPE_GRAYSCALE_ALPHA)
3468         {
3469             if(ihdr->bit_depth == 16)
3470             {
3471                 memcpy(&gray_16, scanline + (k * 4), 2);
3472                 memcpy(&a_16, scanline + (k * 4) + 2, 2);
3473
3474                 r_16 = gray_16;
3475                 g_16 = gray_16;
3476                 b_16 = gray_16;
3477             }
3478             else /* == 8 */
3479             {
3480                 gray_8 = scanline[k * 2];
3481                 a_8 = scanline[k * 2 + 1];
3482
3483                 r_8 = gray_8;
3484                 g_8 = gray_8;
3485                 b_8 = gray_8;
3486             }
3487         }
3488
3489
3490         if(fmt & (SPNG_FMT_RGBA8 | SPNG_FMT_RGB8))
3491         {
3492             if(ihdr->bit_depth == 16)
3493             {
3494                 r_8 = r_16 >> 8;
3495                 g_8 = g_16 >> 8;
3496                 b_8 = b_16 >> 8;
3497                 a_8 = a_16 >> 8;
3498             }
3499
3500             pixel[0] = r_8;
3501             pixel[1] = g_8;
3502             pixel[2] = b_8;
3503
3504             if(fmt == SPNG_FMT_RGBA8) pixel[3] = a_8;
3505         }
3506         else if(fmt == SPNG_FMT_RGBA16)
3507         {
3508             if(ihdr->bit_depth != 16)
3509             {
3510                 r_16 = r_8;
3511                 g_16 = g_8;
3512                 b_16 = b_8;
3513                 a_16 = a_8;
3514             }
3515
3516             memcpy(pixel, &r_16, 2);
3517             memcpy(pixel + 2, &g_16, 2);
3518             memcpy(pixel + 4, &b_16, 2);
3519             memcpy(pixel + 6, &a_16, 2);
3520         }
3521     }/* for(k=0; k < width; k++) */
3522
3523     if(f.apply_trns) trns_row(out, scanline, trns_px, ctx->bytes_per_pixel, &ctx->ihdr, width, fmt);
3524
3525     if(f.do_scaling) scale_row(out, width, fmt, processing_depth, sb);
3526
3527     if(f.apply_gamma) gamma_correct_row(out, width, fmt, gamma_lut);
3528
3529     /* The previous scanline is always defiltered */
3530     void *t = ctx->prev_scanline;
3531     ctx->prev_scanline = ctx->scanline;
3532     ctx->scanline = t;
3533
3534     ret = update_row_info(ctx);
3535
3536     if(ret == SPNG_EOI)
3537     {
3538         if(ctx->cur_chunk_bytes_left) /* zlib stream ended before an IDAT chunk boundary */
3539         {/* Discard the rest of the chunk */
3540             int error = discard_chunk_bytes(ctx, ctx->cur_chunk_bytes_left);
3541             if(error) return decode_err(ctx, error);
3542         }
3543
3544         ctx->last_idat = ctx->current_chunk;
3545     }
3546
3547     return ret;
3548 }
3549
3550 int spng_decode_row(spng_ctx *ctx, void *out, size_t len)
3551 {
3552     if(ctx == NULL || out == NULL) return 1;
3553     if(ctx->state >= SPNG_STATE_EOI) return SPNG_EOI;
3554     if(len < ctx->image_width) return SPNG_EBUFSIZ;
3555
3556     const struct spng_ihdr *ihdr = &ctx->ihdr;
3557     int ret, pass = ctx->row_info.pass;
3558     unsigned char *outptr = out;
3559
3560     if(!ihdr->interlace_method || pass == 6) return spng_decode_scanline(ctx, out, len);
3561
3562     ret = spng_decode_scanline(ctx, ctx->row, ctx->image_width);
3563     if(ret && ret != SPNG_EOI) return ret;
3564
3565     uint32_t k;
3566     unsigned pixel_size = 4; /* RGBA8 */
3567     if(ctx->fmt == SPNG_FMT_RGBA16) pixel_size = 8;
3568     else if(ctx->fmt == SPNG_FMT_RGB8) pixel_size = 3;
3569     else if(ctx->fmt == SPNG_FMT_G8) pixel_size = 1;
3570     else if(ctx->fmt == SPNG_FMT_GA8) pixel_size = 2;
3571     else if(ctx->fmt & (SPNG_FMT_PNG | SPNG_FMT_RAW))
3572     {
3573         if(ihdr->bit_depth < 8)
3574         {
3575             struct spng__iter iter = spng__iter_init(ihdr->bit_depth, ctx->row);
3576             const uint8_t samples_per_byte = 8 / ihdr->bit_depth;
3577             uint8_t sample;
3578
3579             for(k=0; k < ctx->subimage[pass].width; k++)
3580             {
3581                 sample = get_sample(&iter);
3582
3583                 size_t ioffset = adam7_x_start[pass] + k * adam7_x_delta[pass];
3584
3585                 sample = sample << (iter.initial_shift - ioffset * ihdr->bit_depth % 8);
3586
3587                 ioffset /= samples_per_byte;
3588
3589                 outptr[ioffset] |= sample;
3590             }
3591
3592             return 0;
3593         }
3594         else pixel_size = ctx->bytes_per_pixel;
3595     }
3596
3597     for(k=0; k < ctx->subimage[pass].width; k++)
3598     {
3599         size_t ioffset = (adam7_x_start[pass] + (size_t) k * adam7_x_delta[pass]) * pixel_size;
3600
3601         memcpy(outptr + ioffset, ctx->row + k * pixel_size, pixel_size);
3602     }
3603
3604     return 0;
3605 }
3606
3607 int spng_decode_chunks(spng_ctx *ctx)
3608 {
3609     if(ctx == NULL) return 1;
3610     if(ctx->encode_only) return SPNG_ECTXTYPE;
3611     if(ctx->state < SPNG_STATE_INPUT) return SPNG_ENOSRC;
3612     if(ctx->state == SPNG_STATE_IEND) return 0;
3613
3614     return read_chunks(ctx, 0);
3615 }
3616
3617 int spng_decode_image(spng_ctx *ctx, void *out, size_t len, int fmt, int flags)
3618 {
3619     if(ctx == NULL) return 1;
3620     if(ctx->encode_only) return SPNG_ECTXTYPE;
3621     if(ctx->state >= SPNG_STATE_EOI) return SPNG_EOI;
3622
3623     const struct spng_ihdr *ihdr = &ctx->ihdr;
3624
3625     int ret = read_chunks(ctx, 0);
3626     if(ret) return decode_err(ctx, ret);
3627
3628     ret = check_decode_fmt(ihdr, fmt);
3629     if(ret) return ret;
3630
3631     ret = calculate_image_width(ihdr, fmt, &ctx->image_width);
3632     if(ret) return decode_err(ctx, ret);
3633
3634     if(ctx->image_width > SIZE_MAX / ihdr->height) ctx->image_size = 0; /* overflow */
3635     else ctx->image_size = ctx->image_width * ihdr->height;
3636
3637     if( !(flags & SPNG_DECODE_PROGRESSIVE) )
3638     {
3639         if(out == NULL) return 1;
3640         if(!ctx->image_size) return SPNG_EOVERFLOW;
3641         if(len < ctx->image_size) return SPNG_EBUFSIZ;
3642     }
3643
3644     uint32_t bytes_read = 0;
3645
3646     ret = read_idat_bytes(ctx, &bytes_read);
3647     if(ret) return decode_err(ctx, ret);
3648
3649     if(bytes_read > 1)
3650     {
3651         int valid = read_u16(ctx->data) % 31 ? 0 : 1;
3652
3653         unsigned flg = ctx->data[1];
3654         unsigned flevel = flg >> 6;
3655         int compression_level = Z_DEFAULT_COMPRESSION;
3656
3657         if(flevel == 0) compression_level = 0; /* fastest */
3658         else if(flevel == 1) compression_level = 1; /* fast */
3659         else if(flevel == 2) compression_level = 6; /* default */
3660         else if(flevel == 3) compression_level = 9; /* slowest, max compression */
3661
3662         if(valid) ctx->image_options.compression_level = compression_level;
3663     }
3664
3665     ret = spng__inflate_init(ctx, ctx->image_options.window_bits);
3666     if(ret) return decode_err(ctx, ret);
3667
3668     ctx->zstream.avail_in = bytes_read;
3669     ctx->zstream.next_in = ctx->data;
3670
3671     size_t scanline_buf_size = ctx->subimage[ctx->widest_pass].scanline_width;
3672
3673     scanline_buf_size += 32;
3674
3675     if(scanline_buf_size < 32) return SPNG_EOVERFLOW;
3676
3677     ctx->scanline_buf = spng__malloc(ctx, scanline_buf_size);
3678     ctx->prev_scanline_buf = spng__malloc(ctx, scanline_buf_size);
3679
3680     ctx->scanline = ctx->scanline_buf;
3681     ctx->prev_scanline = ctx->prev_scanline_buf;
3682
3683     struct decode_flags f = {0};
3684
3685     ctx->fmt = fmt;
3686
3687     if(ihdr->color_type == SPNG_COLOR_TYPE_INDEXED) f.indexed = 1;
3688
3689     unsigned processing_depth = ihdr->bit_depth;
3690
3691     if(f.indexed) processing_depth = 8;
3692
3693     if(ihdr->interlace_method)
3694     {
3695         f.interlaced = 1;
3696         ctx->row_buf = spng__malloc(ctx, ctx->image_width);
3697         ctx->row = ctx->row_buf;
3698
3699         if(ctx->row == NULL) return decode_err(ctx, SPNG_EMEM);
3700     }
3701
3702     if(ctx->scanline == NULL || ctx->prev_scanline == NULL)
3703     {
3704         return decode_err(ctx, SPNG_EMEM);
3705     }
3706
3707     f.do_scaling = 1;
3708     if(f.indexed) f.do_scaling = 0;
3709
3710     unsigned depth_target = 8; /* FMT_RGBA8, G8 */
3711     if(fmt == SPNG_FMT_RGBA16) depth_target = 16;
3712
3713     if(flags & SPNG_DECODE_TRNS && ctx->stored.trns) f.apply_trns = 1;
3714     else flags &= ~SPNG_DECODE_TRNS;
3715
3716     if(ihdr->color_type == SPNG_COLOR_TYPE_GRAYSCALE_ALPHA ||
3717        ihdr->color_type == SPNG_COLOR_TYPE_TRUECOLOR_ALPHA) flags &= ~SPNG_DECODE_TRNS;
3718
3719     if(flags & SPNG_DECODE_GAMMA && ctx->stored.gama) f.apply_gamma = 1;
3720     else flags &= ~SPNG_DECODE_GAMMA;
3721
3722     if(flags & SPNG_DECODE_USE_SBIT && ctx->stored.sbit) f.use_sbit = 1;
3723     else flags &= ~SPNG_DECODE_USE_SBIT;
3724
3725     if(fmt & (SPNG_FMT_RGBA8 | SPNG_FMT_RGBA16))
3726     {
3727         if(ihdr->color_type == SPNG_COLOR_TYPE_TRUECOLOR_ALPHA &&
3728            ihdr->bit_depth == depth_target) f.same_layout = 1;
3729     }
3730     else if(fmt == SPNG_FMT_RGB8)
3731     {
3732         if(ihdr->color_type == SPNG_COLOR_TYPE_TRUECOLOR &&
3733            ihdr->bit_depth == depth_target) f.same_layout = 1;
3734
3735         f.apply_trns = 0; /* not applicable */
3736     }
3737     else if(fmt & (SPNG_FMT_PNG | SPNG_FMT_RAW))
3738     {
3739         f.same_layout = 1;
3740         f.do_scaling = 0;
3741         f.apply_gamma = 0; /* for now */
3742         f.apply_trns = 0;
3743     }
3744     else if(fmt == SPNG_FMT_G8 && ihdr->color_type == SPNG_COLOR_TYPE_GRAYSCALE && ihdr->bit_depth <= 8)
3745     {
3746         if(ihdr->bit_depth == depth_target) f.same_layout = 1;
3747         else if(ihdr->bit_depth < 8) f.unpack = 1;
3748
3749         f.apply_trns = 0;
3750     }
3751     else if(fmt == SPNG_FMT_GA8 && ihdr->color_type == SPNG_COLOR_TYPE_GRAYSCALE && ihdr->bit_depth <= 8)
3752     {
3753         if(ihdr->color_type == SPNG_COLOR_TYPE_GRAYSCALE_ALPHA &&
3754            ihdr->bit_depth == depth_target) f.same_layout = 1;
3755         else if(ihdr->bit_depth <= 8) f.unpack = 1;
3756     }
3757     else if(fmt == SPNG_FMT_GA16 && ihdr->color_type == SPNG_COLOR_TYPE_GRAYSCALE && ihdr->bit_depth == 16)
3758     {
3759         if(ihdr->color_type == SPNG_COLOR_TYPE_GRAYSCALE_ALPHA &&
3760            ihdr->bit_depth == depth_target) f.same_layout = 1;
3761         else if(ihdr->bit_depth == 16) f.unpack = 1;
3762     }
3763
3764     /*if(f.same_layout && !flags && !f.interlaced) f.zerocopy = 1;*/
3765
3766     uint16_t *gamma_lut = NULL;
3767
3768     if(f.apply_gamma)
3769     {
3770         float file_gamma = (float)ctx->gama / 100000.0f;
3771         float max;
3772
3773         unsigned lut_entries;
3774
3775         if(fmt & (SPNG_FMT_RGBA8 | SPNG_FMT_RGB8))
3776         {
3777             lut_entries = 256;
3778             max = 255.0f;
3779
3780             gamma_lut = ctx->gamma_lut8;
3781             ctx->gamma_lut = ctx->gamma_lut8;
3782         }
3783         else /* SPNG_FMT_RGBA16 */
3784         {
3785             lut_entries = 65536;
3786             max = 65535.0f;
3787
3788             ctx->gamma_lut16 = spng__malloc(ctx, lut_entries * sizeof(uint16_t));
3789             if(ctx->gamma_lut16 == NULL) return decode_err(ctx, SPNG_EMEM);
3790
3791             gamma_lut = ctx->gamma_lut16;
3792             ctx->gamma_lut = ctx->gamma_lut16;
3793         }
3794
3795         float screen_gamma = 2.2f;
3796         float exponent = file_gamma * screen_gamma;
3797
3798         if(FP_ZERO == fpclassify(exponent)) return decode_err(ctx, SPNG_EGAMA);
3799
3800         exponent = 1.0f / exponent;
3801
3802         unsigned i;
3803         for(i=0; i < lut_entries; i++)
3804         {
3805             float c = pow((float)i / max, exponent) * max;
3806             if(c > max) c = max;
3807
3808             gamma_lut[i] = (uint16_t)c;
3809         }
3810     }
3811
3812     struct spng_sbit *sb = &ctx->decode_sb;
3813
3814     sb->red_bits = processing_depth;
3815     sb->green_bits = processing_depth;
3816     sb->blue_bits = processing_depth;
3817     sb->alpha_bits = processing_depth;
3818     sb->grayscale_bits = processing_depth;
3819
3820     if(f.use_sbit)
3821     {
3822         if(ihdr->color_type == 0)
3823         {
3824             sb->grayscale_bits = ctx->sbit.grayscale_bits;
3825             sb->alpha_bits = ihdr->bit_depth;
3826         }
3827         else if(ihdr->color_type == 2 || ihdr->color_type == 3)
3828         {
3829             sb->red_bits = ctx->sbit.red_bits;
3830             sb->green_bits = ctx->sbit.green_bits;
3831             sb->blue_bits = ctx->sbit.blue_bits;
3832             sb->alpha_bits = ihdr->bit_depth;
3833         }
3834         else if(ihdr->color_type == 4)
3835         {
3836             sb->grayscale_bits = ctx->sbit.grayscale_bits;
3837             sb->alpha_bits = ctx->sbit.alpha_bits;
3838         }
3839         else /* == 6 */
3840         {
3841             sb->red_bits = ctx->sbit.red_bits;
3842             sb->green_bits = ctx->sbit.green_bits;
3843             sb->blue_bits = ctx->sbit.blue_bits;
3844             sb->alpha_bits = ctx->sbit.alpha_bits;
3845         }
3846     }
3847
3848     if(ihdr->bit_depth == 16 && fmt & (SPNG_FMT_RGBA8 | SPNG_FMT_RGB8))
3849     {/* samples are scaled down by 8 bits in the decode loop */
3850         sb->red_bits -= 8;
3851         sb->green_bits -= 8;
3852         sb->blue_bits -= 8;
3853         sb->alpha_bits -= 8;
3854         sb->grayscale_bits -= 8;
3855
3856         processing_depth = 8;
3857     }
3858
3859     /* Prevent infinite loops in sample_to_target() */
3860     if(!depth_target || depth_target > 16 ||
3861        !processing_depth || processing_depth > 16 ||
3862        !sb->grayscale_bits || sb->grayscale_bits > processing_depth ||
3863        !sb->alpha_bits || sb->alpha_bits > processing_depth ||
3864        !sb->red_bits || sb->red_bits > processing_depth ||
3865        !sb->green_bits || sb->green_bits > processing_depth ||
3866        !sb->blue_bits || sb->blue_bits > processing_depth)
3867     {
3868         return decode_err(ctx, SPNG_ESBIT);
3869     }
3870
3871     if(sb->red_bits == sb->green_bits &&
3872        sb->green_bits == sb->blue_bits &&
3873        sb->blue_bits == sb->alpha_bits &&
3874        sb->alpha_bits == processing_depth &&
3875        processing_depth == depth_target) f.do_scaling = 0;
3876
3877     struct spng_plte_entry *plte = ctx->decode_plte.rgba;
3878
3879     /* Pre-process palette entries */
3880     if(f.indexed)
3881     {
3882         uint8_t red, green, blue, alpha;
3883
3884         uint32_t i;
3885         for(i=0; i < 256; i++)
3886         {
3887             if(f.apply_trns && i < ctx->trns.n_type3_entries)
3888                 ctx->plte.entries[i].alpha = ctx->trns.type3_alpha[i];
3889             else
3890                 ctx->plte.entries[i].alpha = 255;
3891
3892             red   = sample_to_target(ctx->plte.entries[i].red, 8, sb->red_bits, 8);
3893             green = sample_to_target(ctx->plte.entries[i].green, 8, sb->green_bits, 8);
3894             blue  = sample_to_target(ctx->plte.entries[i].blue, 8, sb->blue_bits, 8);
3895             alpha = sample_to_target(ctx->plte.entries[i].alpha, 8, sb->alpha_bits, 8);
3896
3897 #if defined(SPNG_ARM)
3898             if(fmt == SPNG_FMT_RGB8 && ihdr->bit_depth == 8)
3899             {/* Working with 3 bytes at a time is more of an ARM thing */
3900                 ctx->decode_plte.rgb[i * 3 + 0] = red;
3901                 ctx->decode_plte.rgb[i * 3 + 1] = green;
3902                 ctx->decode_plte.rgb[i * 3 + 2] = blue;
3903                 continue;
3904             }
3905 #endif
3906             plte[i].red = red;
3907             plte[i].green = green;
3908             plte[i].blue = blue;
3909             plte[i].alpha = alpha;
3910         }
3911
3912         f.apply_trns = 0;
3913     }
3914
3915     unsigned char *trns_px = ctx->trns_px;
3916
3917     if(f.apply_trns)
3918     {
3919         uint16_t mask = ~0;
3920         if(ctx->ihdr.bit_depth < 16) mask = (1 << ctx->ihdr.bit_depth) - 1;
3921
3922         if(fmt & (SPNG_FMT_RGBA8 | SPNG_FMT_RGBA16))
3923         {
3924             if(ihdr->color_type == SPNG_COLOR_TYPE_TRUECOLOR)
3925             {
3926                 if(ihdr->bit_depth == 16)
3927                 {
3928                     memcpy(trns_px, &ctx->trns.red, 2);
3929                     memcpy(trns_px + 2, &ctx->trns.green, 2);
3930                     memcpy(trns_px + 4, &ctx->trns.blue, 2);
3931                 }
3932                 else
3933                 {
3934                     trns_px[0] = ctx->trns.red & mask;
3935                     trns_px[1] = ctx->trns.green & mask;
3936                     trns_px[2] = ctx->trns.blue & mask;
3937                 }
3938             }
3939         }
3940         else if(ihdr->color_type == SPNG_COLOR_TYPE_GRAYSCALE) // fmt == SPNG_FMT_GA8 &&
3941         {
3942             if(ihdr->bit_depth == 16)
3943             {
3944                 memcpy(trns_px, &ctx->trns.gray, 2);
3945             }
3946             else
3947             {
3948                 trns_px[0] = ctx->trns.gray & mask;
3949             }
3950         }
3951     }
3952
3953     ctx->decode_flags = f;
3954
3955     ctx->state = SPNG_STATE_DECODE_INIT;
3956
3957     struct spng_row_info *ri = &ctx->row_info;
3958     struct spng_subimage *sub = ctx->subimage;
3959
3960     while(!sub[ri->pass].width || !sub[ri->pass].height) ri->pass++;
3961
3962     if(f.interlaced) ri->row_num = adam7_y_start[ri->pass];
3963
3964     unsigned pixel_size = 4; /* SPNG_FMT_RGBA8 */
3965
3966     if(fmt == SPNG_FMT_RGBA16) pixel_size = 8;
3967     else if(fmt == SPNG_FMT_RGB8) pixel_size = 3;
3968     else if(fmt == SPNG_FMT_G8) pixel_size = 1;
3969     else if(fmt == SPNG_FMT_GA8) pixel_size = 2;
3970
3971     int i;
3972     for(i=ri->pass; i <= ctx->last_pass; i++)
3973     {
3974         if(!sub[i].scanline_width) continue;
3975
3976         if(fmt & (SPNG_FMT_PNG | SPNG_FMT_RAW)) sub[i].out_width = sub[i].scanline_width - 1;
3977         else sub[i].out_width = (size_t)sub[i].width * pixel_size;
3978
3979         if(sub[i].out_width > UINT32_MAX) return decode_err(ctx, SPNG_EOVERFLOW);
3980     }
3981
3982     /* Read the first filter byte, offsetting all reads by 1 byte.
3983     The scanlines will be aligned with the start of the array with
3984     the next scanline's filter byte at the end,
3985     the last scanline will end up being 1 byte "shorter". */
3986     ret = read_scanline_bytes(ctx, &ri->filter, 1);
3987     if(ret) return decode_err(ctx, ret);
3988
3989     if(ri->filter > 4) return decode_err(ctx, SPNG_EFILTER);
3990
3991     if(flags & SPNG_DECODE_PROGRESSIVE)
3992     {
3993         return 0;
3994     }
3995
3996     do
3997     {
3998         size_t ioffset = ri->row_num * ctx->image_width;
3999
4000         ret = spng_decode_row(ctx, (unsigned char*)out + ioffset, ctx->image_width);
4001     }while(!ret);
4002
4003     if(ret != SPNG_EOI) return decode_err(ctx, ret);
4004
4005     return 0;
4006 }
4007
4008 int spng_get_row_info(spng_ctx *ctx, struct spng_row_info *row_info)
4009 {
4010     if(ctx == NULL || row_info == NULL || ctx->state < SPNG_STATE_DECODE_INIT) return 1;
4011
4012     if(ctx->state >= SPNG_STATE_EOI) return SPNG_EOI;
4013
4014     *row_info = ctx->row_info;
4015
4016     return 0;
4017 }
4018
4019 static int write_chunks_before_idat(spng_ctx *ctx)
4020 {
4021     if(ctx == NULL) return SPNG_EINTERNAL;
4022     if(!ctx->encode_only) return SPNG_EINTERNAL;
4023     if(!ctx->stored.ihdr) return SPNG_EINTERNAL;
4024
4025     int ret;
4026     uint32_t i;
4027     size_t length;
4028     const struct spng_ihdr *ihdr = &ctx->ihdr;
4029     unsigned char *data = ctx->decode_plte.raw;
4030
4031     ret = write_data(ctx, spng_signature, 8);
4032     if(ret) return ret;
4033
4034     write_u32(data,     ihdr->width);
4035     write_u32(data + 4, ihdr->height);
4036     data[8]  = ihdr->bit_depth;
4037     data[9]  = ihdr->color_type;
4038     data[10] = ihdr->compression_method;
4039     data[11] = ihdr->filter_method;
4040     data[12] = ihdr->interlace_method;
4041
4042     ret = write_chunk(ctx, type_ihdr, data, 13);
4043     if(ret) return ret;
4044
4045     if(ctx->stored.chrm)
4046     {
4047         write_u32(data,      ctx->chrm_int.white_point_x);
4048         write_u32(data + 4,  ctx->chrm_int.white_point_y);
4049         write_u32(data + 8,  ctx->chrm_int.red_x);
4050         write_u32(data + 12, ctx->chrm_int.red_y);
4051         write_u32(data + 16, ctx->chrm_int.green_x);
4052         write_u32(data + 20, ctx->chrm_int.green_y);
4053         write_u32(data + 24, ctx->chrm_int.blue_x);
4054         write_u32(data + 28, ctx->chrm_int.blue_y);
4055
4056         ret = write_chunk(ctx, type_chrm, data, 32);
4057         if(ret) return ret;
4058     }
4059
4060     if(ctx->stored.gama)
4061     {
4062         write_u32(data, ctx->gama);
4063
4064         ret = write_chunk(ctx, type_gama, data, 4);
4065         if(ret) return ret;
4066     }
4067
4068     if(ctx->stored.iccp)
4069     {
4070         uLongf dest_len = compressBound((uLong)ctx->iccp.profile_len);
4071
4072         Bytef *buf = spng__malloc(ctx, dest_len);
4073         if(buf == NULL) return SPNG_EMEM;
4074
4075         ret = compress2(buf, &dest_len, (void*)ctx->iccp.profile, (uLong)ctx->iccp.profile_len, Z_DEFAULT_COMPRESSION);
4076
4077         if(ret != Z_OK)
4078         {
4079             spng__free(ctx, buf);
4080             return SPNG_EZLIB;
4081         }
4082
4083         size_t name_len = strlen(ctx->iccp.profile_name);
4084
4085         length = name_len + 2;
4086         length += dest_len;
4087
4088         if(dest_len > length) return SPNG_EOVERFLOW;
4089
4090         unsigned char *cdata = NULL;
4091
4092         ret = write_header(ctx, type_iccp, length, &cdata);
4093
4094         if(ret)
4095         {
4096             spng__free(ctx, buf);
4097             return ret;
4098         }
4099
4100         memcpy(cdata, ctx->iccp.profile_name, name_len + 1);
4101         cdata[name_len + 1] = 0; /* compression method */
4102         memcpy(cdata + name_len + 2, buf, dest_len);
4103
4104         spng__free(ctx, buf);
4105
4106         ret = finish_chunk(ctx);
4107         if(ret) return ret;
4108     }
4109
4110     if(ctx->stored.sbit)
4111     {
4112         switch(ctx->ihdr.color_type)
4113         {
4114             case SPNG_COLOR_TYPE_GRAYSCALE:
4115             {
4116                 length = 1;
4117
4118                 data[0] = ctx->sbit.grayscale_bits;
4119
4120                 break;
4121             }
4122             case SPNG_COLOR_TYPE_TRUECOLOR:
4123             case SPNG_COLOR_TYPE_INDEXED:
4124             {
4125                 length = 3;
4126
4127                 data[0] = ctx->sbit.red_bits;
4128                 data[1] = ctx->sbit.green_bits;
4129                 data[2] = ctx->sbit.blue_bits;
4130
4131                 break;
4132             }
4133             case SPNG_COLOR_TYPE_GRAYSCALE_ALPHA:
4134             {
4135                 length = 2;
4136
4137                 data[0] = ctx->sbit.grayscale_bits;
4138                 data[1] = ctx->sbit.alpha_bits;
4139
4140                 break;
4141             }
4142             case SPNG_COLOR_TYPE_TRUECOLOR_ALPHA:
4143             {
4144                 length = 4;
4145
4146                 data[0] = ctx->sbit.red_bits;
4147                 data[1] = ctx->sbit.green_bits;
4148                 data[2] = ctx->sbit.blue_bits;
4149                 data[3] = ctx->sbit.alpha_bits;
4150
4151                 break;
4152             }
4153             default: return SPNG_EINTERNAL;
4154         }
4155
4156         ret = write_chunk(ctx, type_sbit, data, length);
4157         if(ret) return ret;
4158     }
4159
4160     if(ctx->stored.srgb)
4161     {
4162         ret = write_chunk(ctx, type_srgb, &ctx->srgb_rendering_intent, 1);
4163         if(ret) return ret;
4164     }
4165
4166     ret = write_unknown_chunks(ctx, SPNG_AFTER_IHDR);
4167     if(ret) return ret;
4168
4169     if(ctx->stored.plte)
4170     {
4171         for(i=0; i < ctx->plte.n_entries; i++)
4172         {
4173             data[i * 3 + 0] = ctx->plte.entries[i].red;
4174             data[i * 3 + 1] = ctx->plte.entries[i].green;
4175             data[i * 3 + 2] = ctx->plte.entries[i].blue;
4176         }
4177
4178         ret = write_chunk(ctx, type_plte, data, ctx->plte.n_entries * 3);
4179         if(ret) return ret;
4180     }
4181
4182     if(ctx->stored.bkgd)
4183     {
4184         switch(ctx->ihdr.color_type)
4185         {
4186             case SPNG_COLOR_TYPE_GRAYSCALE:
4187             case SPNG_COLOR_TYPE_GRAYSCALE_ALPHA:
4188             {
4189                 length = 2;
4190
4191                 write_u16(data, ctx->bkgd.gray);
4192
4193                 break;
4194             }
4195             case SPNG_COLOR_TYPE_TRUECOLOR:
4196             case SPNG_COLOR_TYPE_TRUECOLOR_ALPHA:
4197             {
4198                 length = 6;
4199
4200                 write_u16(data,     ctx->bkgd.red);
4201                 write_u16(data + 2, ctx->bkgd.green);
4202                 write_u16(data + 4, ctx->bkgd.blue);
4203
4204                 break;
4205             }
4206             case SPNG_COLOR_TYPE_INDEXED:
4207             {
4208                 length = 1;
4209
4210                 data[0] = ctx->bkgd.plte_index;
4211
4212                 break;
4213             }
4214             default: return SPNG_EINTERNAL;
4215         }
4216
4217         ret = write_chunk(ctx, type_bkgd, data, length);
4218         if(ret) return ret;
4219     }
4220
4221     if(ctx->stored.hist)
4222     {
4223         length = ctx->plte.n_entries * 2;
4224
4225         for(i=0; i < ctx->plte.n_entries; i++)
4226         {
4227             write_u16(data + i * 2, ctx->hist.frequency[i]);
4228         }
4229
4230         ret = write_chunk(ctx, type_hist, data, length);
4231         if(ret) return ret;
4232     }
4233
4234     if(ctx->stored.trns)
4235     {
4236         if(ctx->ihdr.color_type == SPNG_COLOR_TYPE_GRAYSCALE)
4237         {
4238             write_u16(data, ctx->trns.gray);
4239
4240             ret = write_chunk(ctx, type_trns, data, 2);
4241         }
4242         else if(ctx->ihdr.color_type == SPNG_COLOR_TYPE_TRUECOLOR)
4243         {
4244             write_u16(data,     ctx->trns.red);
4245             write_u16(data + 2, ctx->trns.green);
4246             write_u16(data + 4, ctx->trns.blue);
4247
4248             ret = write_chunk(ctx, type_trns, data, 6);
4249         }
4250         else if(ctx->ihdr.color_type == SPNG_COLOR_TYPE_INDEXED)
4251         {
4252             ret = write_chunk(ctx, type_trns, ctx->trns.type3_alpha, ctx->trns.n_type3_entries);
4253         }
4254
4255         if(ret) return ret;
4256     }
4257
4258     if(ctx->stored.phys)
4259     {
4260         write_u32(data,     ctx->phys.ppu_x);
4261         write_u32(data + 4, ctx->phys.ppu_y);
4262         data[8] = ctx->phys.unit_specifier;
4263
4264         ret = write_chunk(ctx, type_phys, data, 9);
4265         if(ret) return ret;
4266     }
4267
4268     if(ctx->stored.splt)
4269     {
4270         const struct spng_splt *splt;
4271         unsigned char *cdata = NULL;
4272
4273         uint32_t k;
4274         for(i=0; i < ctx->n_splt; i++)
4275         {
4276             splt = &ctx->splt_list[i];
4277
4278             size_t name_len = strlen(splt->name);
4279             length = name_len + 1;
4280
4281             if(splt->sample_depth == 8) length += splt->n_entries * 6 + 1;
4282             else if(splt->sample_depth == 16) length += splt->n_entries * 10 + 1;
4283
4284             ret = write_header(ctx, type_splt, length, &cdata);
4285             if(ret) return ret;
4286
4287             memcpy(cdata, splt->name, name_len + 1);
4288             cdata += name_len + 2;
4289             cdata[-1] = splt->sample_depth;
4290
4291             if(splt->sample_depth == 8)
4292             {
4293                 for(k=0; k < splt->n_entries; k++)
4294                 {
4295                     cdata[k * 6 + 0] = splt->entries[k].red;
4296                     cdata[k * 6 + 1] = splt->entries[k].green;
4297                     cdata[k * 6 + 2] = splt->entries[k].blue;
4298                     cdata[k * 6 + 3] = splt->entries[k].alpha;
4299                     write_u16(cdata + k * 6 + 4, splt->entries[k].frequency);
4300                 }
4301             }
4302             else if(splt->sample_depth == 16)
4303             {
4304                 for(k=0; k < splt->n_entries; k++)
4305                 {
4306                     write_u16(cdata + k * 10 + 0, splt->entries[k].red);
4307                     write_u16(cdata + k * 10 + 2, splt->entries[k].green);
4308                     write_u16(cdata + k * 10 + 4, splt->entries[k].blue);
4309                     write_u16(cdata + k * 10 + 6, splt->entries[k].alpha);
4310                     write_u16(cdata + k * 10 + 8, splt->entries[k].frequency);
4311                 }
4312             }
4313
4314             ret = finish_chunk(ctx);
4315             if(ret) return ret;
4316         }
4317     }
4318
4319     if(ctx->stored.time)
4320     {
4321         write_u16(data, ctx->time.year);
4322         data[2] = ctx->time.month;
4323         data[3] = ctx->time.day;
4324         data[4] = ctx->time.hour;
4325         data[5] = ctx->time.minute;
4326         data[6] = ctx->time.second;
4327
4328         ret = write_chunk(ctx, type_time, data, 7);
4329         if(ret) return ret;
4330     }
4331
4332     if(ctx->stored.text)
4333     {
4334         unsigned char *cdata = NULL;
4335         const struct spng_text2 *text;
4336         const uint8_t *text_type_array[4] = { 0, type_text, type_ztxt, type_itxt };
4337
4338         for(i=0; i < ctx->n_text; i++)
4339         {
4340             text = &ctx->text_list[i];
4341
4342             const uint8_t *text_chunk_type = text_type_array[text->type];
4343             Bytef *compressed_text = NULL;
4344             size_t keyword_len = 0;
4345             size_t language_tag_len = 0;
4346             size_t translated_keyword_len = 0;
4347             size_t compressed_length = 0;
4348             size_t text_length = 0;
4349
4350             keyword_len = strlen(text->keyword);
4351             text_length = strlen(text->text);
4352
4353             length = keyword_len + 1;
4354
4355             if(text->type == SPNG_ZTXT)
4356             {
4357                 length += 1; /* compression method */
4358             }
4359             else if(text->type == SPNG_ITXT)
4360             {
4361                 if(!text->language_tag || !text->translated_keyword) return SPNG_EINTERNAL;
4362
4363                 language_tag_len = strlen(text->language_tag);
4364                 translated_keyword_len = strlen(text->translated_keyword);
4365
4366                 length += language_tag_len;
4367                 if(length < language_tag_len) return SPNG_EOVERFLOW;
4368
4369                 length += translated_keyword_len;
4370                 if(length < translated_keyword_len) return SPNG_EOVERFLOW;
4371
4372                 length += 4; /* compression flag + method + nul for the two strings */
4373                 if(length < 4) return SPNG_EOVERFLOW;
4374             }
4375
4376             if(text->compression_flag)
4377             {
4378                 ret = spng__deflate_init(ctx, &ctx->text_options);
4379                 if(ret) return ret;
4380
4381                 z_stream *zstream = &ctx->zstream;
4382                 uLongf dest_len = deflateBound(zstream, (uLong)text_length);
4383
4384                 compressed_text = spng__malloc(ctx, dest_len);
4385
4386                 if(compressed_text == NULL) return SPNG_EMEM;
4387
4388                 zstream->next_in = (void*)text->text;
4389                 zstream->avail_in = (uInt)text_length;
4390
4391                 zstream->next_out = compressed_text;
4392                 zstream->avail_out = dest_len;
4393
4394                 ret = deflate(zstream, Z_FINISH);
4395
4396                 if(ret != Z_STREAM_END)
4397                 {
4398                     spng__free(ctx, compressed_text);
4399                     return SPNG_EZLIB;
4400                 }
4401
4402                 compressed_length = zstream->total_out;
4403
4404                 length += compressed_length;
4405                 if(length < compressed_length) return SPNG_EOVERFLOW;
4406             }
4407             else
4408             {
4409                 text_length = strlen(text->text);
4410
4411                 length += text_length;
4412                 if(length < text_length) return SPNG_EOVERFLOW;
4413             }
4414
4415             ret = write_header(ctx, text_chunk_type, length, &cdata);
4416             if(ret)
4417             {
4418                 spng__free(ctx, compressed_text);
4419                 return ret;
4420             }
4421
4422             memcpy(cdata, text->keyword, keyword_len + 1);
4423             cdata += keyword_len + 1;
4424
4425             if(text->type == SPNG_ITXT)
4426             {
4427                 cdata[0] = text->compression_flag;
4428                 cdata[1] = 0; /* compression method */
4429                 cdata += 2;
4430
4431                 memcpy(cdata, text->language_tag, language_tag_len + 1);
4432                 cdata += language_tag_len + 1;
4433
4434                 memcpy(cdata, text->translated_keyword, translated_keyword_len + 1);
4435                 cdata += translated_keyword_len + 1;
4436             }
4437             else if(text->type == SPNG_ZTXT)
4438             {
4439                 cdata[0] = 0; /* compression method */
4440                 cdata++;
4441             }
4442
4443             if(text->compression_flag) memcpy(cdata, compressed_text, compressed_length);
4444             else memcpy(cdata, text->text, text_length);
4445
4446             spng__free(ctx, compressed_text);
4447
4448             ret = finish_chunk(ctx);
4449             if(ret) return ret;
4450         }
4451     }
4452
4453     if(ctx->stored.offs)
4454     {
4455         write_s32(data,     ctx->offs.x);
4456         write_s32(data + 4, ctx->offs.y);
4457         data[8] = ctx->offs.unit_specifier;
4458
4459         ret = write_chunk(ctx, type_offs, data, 9);
4460         if(ret) return ret;
4461     }
4462
4463     if(ctx->stored.exif)
4464     {
4465         ret = write_chunk(ctx, type_exif, ctx->exif.data, ctx->exif.length);
4466         if(ret) return ret;
4467     }
4468
4469     ret = write_unknown_chunks(ctx, SPNG_AFTER_PLTE);
4470     if(ret) return ret;
4471
4472     return 0;
4473 }
4474
4475 static int write_chunks_after_idat(spng_ctx *ctx)
4476 {
4477     if(ctx == NULL) return SPNG_EINTERNAL;
4478
4479     int ret = write_unknown_chunks(ctx, SPNG_AFTER_IDAT);
4480     if(ret) return ret;
4481
4482     return write_iend(ctx);
4483 }
4484
4485 /* Compress and write scanline to IDAT stream */
4486 static int write_idat_bytes(spng_ctx *ctx, const void *scanline, size_t len, int flush)
4487 {
4488     if(ctx == NULL || scanline == NULL) return SPNG_EINTERNAL;
4489     if(len > UINT_MAX) return SPNG_EINTERNAL;
4490
4491     int ret = 0;
4492     unsigned char *data = NULL;
4493     z_stream *zstream = &ctx->zstream;
4494     uint32_t idat_length = SPNG_WRITE_SIZE;
4495
4496     zstream->next_in = scanline;
4497     zstream->avail_in = (uInt)len;
4498
4499     do
4500     {
4501         ret = deflate(zstream, flush);
4502
4503         if(zstream->avail_out == 0)
4504         {
4505             ret = finish_chunk(ctx);
4506             if(ret) return encode_err(ctx, ret);
4507
4508             ret = write_header(ctx, type_idat, idat_length, &data);
4509             if(ret) return encode_err(ctx, ret);
4510
4511             zstream->next_out = data;
4512             zstream->avail_out = idat_length;
4513         }
4514
4515     }while(zstream->avail_in);
4516
4517     if(ret != Z_OK) return SPNG_EZLIB;
4518
4519     return 0;
4520 }
4521
4522 static int finish_idat(spng_ctx *ctx)
4523 {
4524     int ret = 0;
4525     unsigned char *data = NULL;
4526     z_stream *zstream = &ctx->zstream;
4527     uint32_t idat_length = SPNG_WRITE_SIZE;
4528
4529     while(ret != Z_STREAM_END)
4530     {
4531         ret = deflate(zstream, Z_FINISH);
4532
4533         if(ret)
4534         {
4535             if(ret == Z_STREAM_END) break;
4536
4537             if(ret != Z_BUF_ERROR) return SPNG_EZLIB;
4538         }
4539
4540         if(zstream->avail_out == 0)
4541         {
4542             ret = finish_chunk(ctx);
4543             if(ret) return encode_err(ctx, ret);
4544
4545             ret = write_header(ctx, type_idat, idat_length, &data);
4546             if(ret) return encode_err(ctx, ret);
4547
4548             zstream->next_out = data;
4549             zstream->avail_out = idat_length;
4550         }
4551     }
4552
4553     uint32_t trimmed_length = idat_length - zstream->avail_out;
4554
4555     ret = trim_chunk(ctx, trimmed_length);
4556     if(ret) return ret;
4557
4558     return finish_chunk(ctx);
4559 }
4560
4561 static int encode_scanline(spng_ctx *ctx, const void *scanline, size_t len)
4562 {
4563     if(ctx == NULL || scanline == NULL) return SPNG_EINTERNAL;
4564
4565     int ret, pass = ctx->row_info.pass;
4566     uint8_t filter = 0;
4567     struct spng_row_info *ri = &ctx->row_info;
4568     const struct spng_subimage *sub = ctx->subimage;
4569     struct encode_flags f = ctx->encode_flags;
4570     unsigned char *filtered_scanline = ctx->filtered_scanline;
4571     size_t scanline_width = sub[pass].scanline_width;
4572
4573     if(len < scanline_width - 1) return SPNG_EINTERNAL;
4574
4575     /* encode_row() interlaces directly to ctx->scanline */
4576     if(scanline != ctx->scanline) memcpy(ctx->scanline, scanline, scanline_width - 1);
4577
4578     if(f.to_bigendian) u16_row_to_bigendian(ctx->scanline, scanline_width - 1);
4579     const int requires_previous = f.filter_choice & (SPNG_FILTER_CHOICE_UP | SPNG_FILTER_CHOICE_AVG | SPNG_FILTER_CHOICE_PAETH);
4580
4581     /* XXX: exclude 'requires_previous' filters by default for first scanline? */
4582     if(!ri->scanline_idx && requires_previous)
4583     {
4584         /* prev_scanline is all zeros for the first scanline */
4585         memset(ctx->prev_scanline, 0, scanline_width);
4586     }
4587
4588     filter = get_best_filter(ctx->prev_scanline, ctx->scanline, scanline_width, ctx->bytes_per_pixel, f.filter_choice);
4589
4590     if(!filter) filtered_scanline = ctx->scanline;
4591
4592     filtered_scanline[-1] = filter;
4593
4594     if(filter)
4595     {
4596         ret = filter_scanline(filtered_scanline, ctx->prev_scanline, ctx->scanline, scanline_width, ctx->bytes_per_pixel, filter);
4597         if(ret) return encode_err(ctx, ret);
4598     }
4599
4600     ret = write_idat_bytes(ctx, filtered_scanline - 1, scanline_width, Z_NO_FLUSH);
4601     if(ret) return encode_err(ctx, ret);
4602
4603     /* The previous scanline is always unfiltered */
4604     void *t = ctx->prev_scanline;
4605     ctx->prev_scanline = ctx->scanline;
4606     ctx->scanline = t;
4607
4608     ret = update_row_info(ctx);
4609
4610     if(ret == SPNG_EOI)
4611     {
4612         int error = finish_idat(ctx);
4613         if(error) encode_err(ctx, error);
4614
4615         if(f.finalize)
4616         {
4617             error = spng_encode_chunks(ctx);
4618             if(error) return encode_err(ctx, error);
4619         }
4620     }
4621
4622     return ret;
4623 }
4624
4625 static int encode_row(spng_ctx *ctx, const void *row, size_t len)
4626 {
4627     if(ctx == NULL || row == NULL) return SPNG_EINTERNAL;
4628
4629     const int pass = ctx->row_info.pass;
4630
4631     if(!ctx->ihdr.interlace_method || pass == 6) return encode_scanline(ctx, row, len);
4632
4633     uint32_t k;
4634     const unsigned pixel_size = ctx->pixel_size;
4635     const unsigned bit_depth = ctx->ihdr.bit_depth;
4636
4637     if(bit_depth < 8)
4638     {
4639         const unsigned samples_per_byte = 8 / bit_depth;
4640         const uint8_t mask = (1 << bit_depth) - 1;
4641         const unsigned initial_shift = 8 - bit_depth;
4642         unsigned shift_amount = initial_shift;
4643
4644         unsigned char *scanline = ctx->scanline;
4645         const unsigned char *row_uc = row;
4646         uint8_t sample;
4647
4648         memset(scanline, 0, ctx->subimage[pass].scanline_width);
4649
4650         for(k=0; k < ctx->subimage[pass].width; k++)
4651         {
4652             size_t ioffset = adam7_x_start[pass] + k * adam7_x_delta[pass];
4653
4654             sample = row_uc[ioffset / samples_per_byte];
4655
4656             sample = sample >> (initial_shift - ioffset * bit_depth % 8);
4657             sample = sample & mask;
4658             sample = sample << shift_amount;
4659
4660             scanline[0] |= sample;
4661
4662             shift_amount -= bit_depth;
4663
4664             if(shift_amount > 7)
4665             {
4666                 shift_amount = initial_shift;
4667                 scanline++;
4668             }
4669         }
4670
4671         return encode_scanline(ctx, ctx->scanline, len);
4672     }
4673
4674     for(k=0; k < ctx->subimage[pass].width; k++)
4675     {
4676         size_t ioffset = (adam7_x_start[pass] + (size_t) k * adam7_x_delta[pass]) * pixel_size;
4677
4678         memcpy(ctx->scanline + k * pixel_size, (unsigned char*)row + ioffset, pixel_size);
4679     }
4680
4681     return encode_scanline(ctx, ctx->scanline, len);
4682 }
4683
4684 int spng_encode_scanline(spng_ctx *ctx, const void *scanline, size_t len)
4685 {
4686     if(ctx == NULL || scanline == NULL) return SPNG_EINVAL;
4687     if(ctx->state >= SPNG_STATE_EOI) return SPNG_EOI;
4688     if(len < (ctx->subimage[ctx->row_info.pass].scanline_width -1) ) return SPNG_EBUFSIZ;
4689
4690     return encode_scanline(ctx, scanline, len);
4691 }
4692
4693 int spng_encode_row(spng_ctx *ctx, const void *row, size_t len)
4694 {
4695     if(ctx == NULL || row == NULL) return SPNG_EINVAL;
4696     if(ctx->state >= SPNG_STATE_EOI) return SPNG_EOI;
4697     if(len < ctx->image_width) return SPNG_EBUFSIZ;
4698
4699     return encode_row(ctx, row, len);
4700 }
4701
4702 int spng_encode_chunks(spng_ctx *ctx)
4703 {
4704     if(ctx == NULL) return 1;
4705     if(!ctx->state) return SPNG_EBADSTATE;
4706     if(ctx->state < SPNG_STATE_OUTPUT) return SPNG_ENODST;
4707     if(!ctx->encode_only) return SPNG_ECTXTYPE;
4708
4709     int ret = 0;
4710
4711     if(ctx->state < SPNG_STATE_FIRST_IDAT)
4712     {
4713         if(!ctx->stored.ihdr) return SPNG_ENOIHDR;
4714
4715         ret = write_chunks_before_idat(ctx);
4716         if(ret) return encode_err(ctx, ret);
4717
4718         ctx->state = SPNG_STATE_FIRST_IDAT;
4719     }
4720     else if(ctx->state == SPNG_STATE_FIRST_IDAT)
4721     {
4722         return 0;
4723     }
4724     else if(ctx->state == SPNG_STATE_EOI)
4725     {
4726         ret = write_chunks_after_idat(ctx);
4727         if(ret) return encode_err(ctx, ret);
4728
4729         ctx->state = SPNG_STATE_IEND;
4730     }
4731     else return SPNG_EOPSTATE;
4732
4733     return 0;
4734 }
4735
4736 int spng_encode_image(spng_ctx *ctx, const void *img, size_t len, int fmt, int flags)
4737 {
4738     if(ctx == NULL) return 1;
4739     if(!ctx->state) return SPNG_EBADSTATE;
4740     if(!ctx->encode_only) return SPNG_ECTXTYPE;
4741     if(!ctx->stored.ihdr) return SPNG_ENOIHDR;
4742     if( !(fmt == SPNG_FMT_PNG || fmt == SPNG_FMT_RAW) ) return SPNG_EFMT;
4743
4744     int ret = 0;
4745     const struct spng_ihdr *ihdr = &ctx->ihdr;
4746     struct encode_flags *encode_flags = &ctx->encode_flags;
4747
4748     if(ihdr->color_type == SPNG_COLOR_TYPE_INDEXED && !ctx->stored.plte) return SPNG_ENOPLTE;
4749
4750     ret = calculate_image_width(ihdr, fmt, &ctx->image_width);
4751     if(ret) return encode_err(ctx, ret);
4752
4753     if(ctx->image_width > SIZE_MAX / ihdr->height) ctx->image_size = 0; /* overflow */
4754     else ctx->image_size = ctx->image_width * ihdr->height;
4755
4756     if( !(flags & SPNG_ENCODE_PROGRESSIVE) )
4757     {
4758         if(img == NULL) return 1;
4759         if(!ctx->image_size) return SPNG_EOVERFLOW;
4760         if(len != ctx->image_size) return SPNG_EBUFSIZ;
4761     }
4762
4763     ret = spng_encode_chunks(ctx);
4764     if(ret) return encode_err(ctx, ret);
4765
4766     ret = calculate_subimages(ctx);
4767     if(ret) return encode_err(ctx, ret);
4768
4769     if(ihdr->bit_depth < 8) ctx->bytes_per_pixel = 1;
4770     else ctx->bytes_per_pixel = num_channels(ihdr) * (ihdr->bit_depth / 8);
4771
4772     if(spng__optimize(SPNG_FILTER_CHOICE))
4773     {
4774         /* Filtering would make no difference */
4775         if(!ctx->image_options.compression_level)
4776         {
4777             encode_flags->filter_choice = SPNG_DISABLE_FILTERING;
4778         }
4779
4780         /* Palette indices and low bit-depth images do not benefit from filtering */
4781         if(ihdr->color_type == SPNG_COLOR_TYPE_INDEXED || ihdr->bit_depth < 8)
4782         {
4783             encode_flags->filter_choice = SPNG_DISABLE_FILTERING;
4784         }
4785     }
4786
4787     /* This is technically the same as disabling filtering */
4788     if(encode_flags->filter_choice == SPNG_FILTER_CHOICE_NONE)
4789     {
4790         encode_flags->filter_choice = SPNG_DISABLE_FILTERING;
4791     }
4792
4793     if(!encode_flags->filter_choice && spng__optimize(SPNG_IMG_COMPRESSION_STRATEGY))
4794     {
4795         ctx->image_options.strategy = Z_DEFAULT_STRATEGY;
4796     }
4797
4798     ret = spng__deflate_init(ctx, &ctx->image_options);
4799     if(ret) return encode_err(ctx, ret);
4800
4801     size_t scanline_buf_size = ctx->subimage[ctx->widest_pass].scanline_width;
4802
4803     scanline_buf_size += 32;
4804
4805     if(scanline_buf_size < 32) return SPNG_EOVERFLOW;
4806
4807     ctx->scanline_buf = spng__malloc(ctx, scanline_buf_size);
4808     ctx->prev_scanline_buf = spng__malloc(ctx, scanline_buf_size);
4809
4810     if(ctx->scanline_buf == NULL || ctx->prev_scanline_buf == NULL) return encode_err(ctx, SPNG_EMEM);
4811
4812     /* Maintain alignment for pixels, filter at [-1] */
4813     ctx->scanline = ctx->scanline_buf + 16;
4814     ctx->prev_scanline = ctx->prev_scanline_buf + 16;
4815
4816     if(encode_flags->filter_choice)
4817     {
4818         ctx->filtered_scanline_buf = spng__malloc(ctx, scanline_buf_size);
4819         if(ctx->filtered_scanline_buf == NULL) return encode_err(ctx, SPNG_EMEM);
4820
4821         ctx->filtered_scanline = ctx->filtered_scanline_buf + 16;
4822     }
4823
4824     struct spng_subimage *sub = ctx->subimage;
4825     struct spng_row_info *ri = &ctx->row_info;
4826
4827     ctx->fmt = fmt;
4828
4829     z_stream *zstream = &ctx->zstream;
4830     zstream->avail_out = SPNG_WRITE_SIZE;
4831
4832     ret = write_header(ctx, type_idat, zstream->avail_out, &zstream->next_out);
4833     if(ret) return encode_err(ctx, ret);
4834
4835     if(ihdr->interlace_method) encode_flags->interlace = 1;
4836
4837     if(fmt & (SPNG_FMT_PNG | SPNG_FMT_RAW) ) encode_flags->same_layout = 1;
4838
4839     if(ihdr->bit_depth == 16 && fmt != SPNG_FMT_RAW) encode_flags->to_bigendian = 1;
4840
4841     if(flags & SPNG_ENCODE_FINALIZE) encode_flags->finalize = 1;
4842
4843     while(!sub[ri->pass].width || !sub[ri->pass].height) ri->pass++;
4844
4845     if(encode_flags->interlace) ri->row_num = adam7_y_start[ri->pass];
4846
4847     ctx->pixel_size = 4; /* SPNG_FMT_RGBA8 */
4848
4849     if(fmt == SPNG_FMT_RGBA16) ctx->pixel_size = 8;
4850     else if(fmt == SPNG_FMT_RGB8) ctx->pixel_size = 3;
4851     else if(fmt == SPNG_FMT_G8) ctx->pixel_size = 1;
4852     else if(fmt == SPNG_FMT_GA8) ctx->pixel_size = 2;
4853     else if(fmt & (SPNG_FMT_PNG | SPNG_FMT_RAW)) ctx->pixel_size = ctx->bytes_per_pixel;
4854
4855     ctx->state = SPNG_STATE_ENCODE_INIT;
4856
4857     if(flags & SPNG_ENCODE_PROGRESSIVE)
4858     {
4859         encode_flags->progressive = 1;
4860
4861         return 0;
4862     }
4863
4864     do
4865     {
4866         size_t ioffset = ri->row_num * ctx->image_width;
4867
4868         ret = encode_row(ctx, (unsigned char*)img + ioffset, ctx->image_width);
4869
4870     }while(!ret);
4871
4872     if(ret != SPNG_EOI) return encode_err(ctx, ret);
4873
4874     return 0;
4875 }
4876
4877 spng_ctx *spng_ctx_new(int flags)
4878 {
4879     struct spng_alloc alloc =
4880     {
4881         .malloc_fn = malloc,
4882         .realloc_fn = realloc,
4883         .calloc_fn = calloc,
4884         .free_fn = free
4885     };
4886
4887     return spng_ctx_new2(&alloc, flags);
4888 }
4889
4890 spng_ctx *spng_ctx_new2(struct spng_alloc *alloc, int flags)
4891 {
4892     if(alloc == NULL) return NULL;
4893     if(flags != (flags & SPNG__CTX_FLAGS_ALL)) return NULL;
4894
4895     if(alloc->malloc_fn == NULL) return NULL;
4896     if(alloc->realloc_fn == NULL) return NULL;
4897     if(alloc->calloc_fn == NULL) return NULL;
4898     if(alloc->free_fn == NULL) return NULL;
4899
4900     spng_ctx *ctx = alloc->calloc_fn(1, sizeof(spng_ctx));
4901     if(ctx == NULL) return NULL;
4902
4903     ctx->alloc = *alloc;
4904
4905     ctx->max_width = spng_u32max;
4906     ctx->max_height = spng_u32max;
4907
4908     ctx->max_chunk_size = spng_u32max;
4909     ctx->chunk_cache_limit = SIZE_MAX;
4910     ctx->chunk_count_limit = SPNG_MAX_CHUNK_COUNT;
4911
4912     ctx->state = SPNG_STATE_INIT;
4913
4914     ctx->crc_action_critical = SPNG_CRC_ERROR;
4915     ctx->crc_action_ancillary = SPNG_CRC_DISCARD;
4916
4917     const struct spng__zlib_options image_defaults =
4918     {
4919         .compression_level = Z_DEFAULT_COMPRESSION,
4920         .window_bits = 15,
4921         .mem_level = 8,
4922         .strategy = Z_FILTERED,
4923         .data_type = 0 /* Z_BINARY */
4924     };
4925
4926     const struct spng__zlib_options text_defaults =
4927     {
4928         .compression_level = Z_DEFAULT_COMPRESSION,
4929         .window_bits = 15,
4930         .mem_level = 8,
4931         .strategy = Z_DEFAULT_STRATEGY,
4932         .data_type = 1 /* Z_TEXT */
4933     };
4934
4935     ctx->image_options = image_defaults;
4936     ctx->text_options = text_defaults;
4937
4938     ctx->optimize_option = ~0;
4939     ctx->encode_flags.filter_choice = SPNG_FILTER_CHOICE_ALL;
4940
4941     ctx->flags = flags;
4942
4943     if(flags & SPNG_CTX_ENCODER) ctx->encode_only = 1;
4944
4945     return ctx;
4946 }
4947
4948 void spng_ctx_free(spng_ctx *ctx)
4949 {
4950     if(ctx == NULL) return;
4951
4952     if(ctx->streaming && ctx->stream_buf != NULL) spng__free(ctx, ctx->stream_buf);
4953
4954     if(!ctx->user.exif) spng__free(ctx, ctx->exif.data);
4955
4956     if(!ctx->user.iccp) spng__free(ctx, ctx->iccp.profile);
4957
4958     uint32_t i;
4959
4960     if(ctx->splt_list != NULL && !ctx->user.splt)
4961     {
4962         for(i=0; i < ctx->n_splt; i++)
4963         {
4964             spng__free(ctx, ctx->splt_list[i].entries);
4965         }
4966         spng__free(ctx, ctx->splt_list);
4967     }
4968
4969     if(ctx->text_list != NULL)
4970     {
4971         for(i=0; i< ctx->n_text; i++)
4972         {
4973             if(ctx->user.text) break;
4974
4975             spng__free(ctx, ctx->text_list[i].keyword);
4976             if(ctx->text_list[i].compression_flag) spng__free(ctx, ctx->text_list[i].text);
4977         }
4978         spng__free(ctx, ctx->text_list);
4979     }
4980
4981     if(ctx->chunk_list != NULL && !ctx->user.unknown)
4982     {
4983         for(i=0; i< ctx->n_chunks; i++)
4984         {
4985             spng__free(ctx, ctx->chunk_list[i].data);
4986         }
4987         spng__free(ctx, ctx->chunk_list);
4988     }
4989
4990     if(ctx->deflate) deflateEnd(&ctx->zstream);
4991     else inflateEnd(&ctx->zstream);
4992
4993     if(!ctx->user_owns_out_png) spng__free(ctx, ctx->out_png);
4994
4995     spng__free(ctx, ctx->gamma_lut16);
4996
4997     spng__free(ctx, ctx->row_buf);
4998     spng__free(ctx, ctx->scanline_buf);
4999     spng__free(ctx, ctx->prev_scanline_buf);
5000     spng__free(ctx, ctx->filtered_scanline_buf);
5001
5002     spng_free_fn *free_func = ctx->alloc.free_fn;
5003
5004     memset(ctx, 0, sizeof(spng_ctx));
5005
5006     free_func(ctx);
5007 }
5008
5009 static int buffer_read_fn(spng_ctx *ctx, void *user, void *data, size_t n)
5010 {
5011     if(n > ctx->bytes_left) return SPNG_IO_EOF;
5012
5013     (void)user;
5014     (void)data;
5015     ctx->data = ctx->data + ctx->last_read_size;
5016
5017     ctx->last_read_size = n;
5018     ctx->bytes_left -= n;
5019
5020     return 0;
5021 }
5022
5023 static int file_read_fn(spng_ctx *ctx, void *user, void *data, size_t n)
5024 {
5025     FILE *file = user;
5026     (void)ctx;
5027
5028     if(fread(data, n, 1, file) != 1)
5029     {
5030         if(feof(file)) return SPNG_IO_EOF;
5031         else return SPNG_IO_ERROR;
5032     }
5033
5034     return 0;
5035 }
5036
5037 static int file_write_fn(spng_ctx *ctx, void *user, void *data, size_t n)
5038 {
5039     FILE *file = user;
5040     (void)ctx;
5041
5042     if(fwrite(data, n, 1, file) != 1) return SPNG_IO_ERROR;
5043
5044     return 0;
5045 }
5046
5047 int spng_set_png_buffer(spng_ctx *ctx, const void *buf, size_t size)
5048 {
5049     if(ctx == NULL || buf == NULL) return 1;
5050     if(!ctx->state) return SPNG_EBADSTATE;
5051     if(ctx->encode_only) return SPNG_ECTXTYPE; /* not supported */
5052
5053     if(ctx->data != NULL) return SPNG_EBUF_SET;
5054
5055     ctx->data = buf;
5056     ctx->png_base = buf;
5057     ctx->data_size = size;
5058     ctx->bytes_left = size;
5059
5060     ctx->read_fn = buffer_read_fn;
5061
5062     ctx->state = SPNG_STATE_INPUT;
5063
5064     return 0;
5065 }
5066
5067 int spng_set_png_stream(spng_ctx *ctx, spng_rw_fn *rw_func, void *user)
5068 {
5069     if(ctx == NULL || rw_func == NULL) return 1;
5070     if(!ctx->state) return SPNG_EBADSTATE;
5071
5072     /* SPNG_STATE_OUTPUT shares the same value */
5073     if(ctx->state >= SPNG_STATE_INPUT) return SPNG_EBUF_SET;
5074
5075     if(ctx->encode_only)
5076     {
5077         if(ctx->out_png != NULL) return SPNG_EBUF_SET;
5078
5079         ctx->write_fn = rw_func;
5080         ctx->write_ptr = ctx->stream_buf;
5081
5082         ctx->state = SPNG_STATE_OUTPUT;
5083     }
5084     else
5085     {
5086         ctx->stream_buf = spng__malloc(ctx, SPNG_READ_SIZE);
5087         if(ctx->stream_buf == NULL) return SPNG_EMEM;
5088
5089         ctx->read_fn = rw_func;
5090         ctx->data = ctx->stream_buf;
5091         ctx->data_size = SPNG_READ_SIZE;
5092
5093         ctx->state = SPNG_STATE_INPUT;
5094     }
5095
5096     ctx->stream_user_ptr = user;
5097
5098     ctx->streaming = 1;
5099
5100     return 0;
5101 }
5102
5103 int spng_set_png_file(spng_ctx *ctx, FILE *file)
5104 {
5105     if(file == NULL) return 1;
5106
5107     if(ctx->encode_only) return spng_set_png_stream(ctx, file_write_fn, file);
5108
5109     return spng_set_png_stream(ctx, file_read_fn, file);
5110 }
5111
5112 void *spng_get_png_buffer(spng_ctx *ctx, size_t *len, int *error)
5113 {
5114     int tmp = 0;
5115     error = error ? error : &tmp;
5116     *error = 0;
5117
5118     if(ctx == NULL || !len) *error = SPNG_EINVAL;
5119
5120     if(*error) return NULL;
5121
5122     if(!ctx->encode_only) *error = SPNG_ECTXTYPE;
5123     else if(!ctx->state) *error = SPNG_EBADSTATE;
5124     else if(!ctx->internal_buffer) *error = SPNG_EOPSTATE;
5125     else if(ctx->state < SPNG_STATE_EOI) *error = SPNG_EOPSTATE;
5126     else if(ctx->state != SPNG_STATE_IEND) *error = SPNG_ENOTFINAL;
5127
5128     if(*error) return NULL;
5129
5130     ctx->user_owns_out_png = 1;
5131
5132     *len = ctx->bytes_encoded;
5133
5134     return ctx->out_png;
5135 }
5136
5137 int spng_set_image_limits(spng_ctx *ctx, uint32_t width, uint32_t height)
5138 {
5139     if(ctx == NULL) return 1;
5140
5141     if(width > spng_u32max || height > spng_u32max) return 1;
5142
5143     ctx->max_width = width;
5144     ctx->max_height = height;
5145
5146     return 0;
5147 }
5148
5149 int spng_get_image_limits(spng_ctx *ctx, uint32_t *width, uint32_t *height)
5150 {
5151     if(ctx == NULL || width == NULL || height == NULL) return 1;
5152
5153     *width = ctx->max_width;
5154     *height = ctx->max_height;
5155
5156     return 0;
5157 }
5158
5159 int spng_set_chunk_limits(spng_ctx *ctx, size_t chunk_size, size_t cache_limit)
5160 {
5161     if(ctx == NULL || chunk_size > spng_u32max || chunk_size > cache_limit) return 1;
5162
5163     ctx->max_chunk_size = chunk_size;
5164
5165     ctx->chunk_cache_limit = cache_limit;
5166
5167     return 0;
5168 }
5169
5170 int spng_get_chunk_limits(spng_ctx *ctx, size_t *chunk_size, size_t *cache_limit)
5171 {
5172     if(ctx == NULL || chunk_size == NULL || cache_limit == NULL) return 1;
5173
5174     *chunk_size = ctx->max_chunk_size;
5175
5176     *cache_limit = ctx->chunk_cache_limit;
5177
5178     return 0;
5179 }
5180
5181 int spng_set_crc_action(spng_ctx *ctx, int critical, int ancillary)
5182 {
5183     if(ctx == NULL) return 1;
5184     if(ctx->encode_only) return SPNG_ECTXTYPE;
5185
5186     if(critical > 2 || critical < 0) return 1;
5187     if(ancillary > 2 || ancillary < 0) return 1;
5188
5189     if(critical == SPNG_CRC_DISCARD) return 1;
5190
5191     ctx->crc_action_critical = critical;
5192     ctx->crc_action_ancillary = ancillary;
5193
5194     return 0;
5195 }
5196
5197 int spng_set_option(spng_ctx *ctx, enum spng_option option, int value)
5198 {
5199     if(ctx == NULL) return 1;
5200     if(!ctx->state) return SPNG_EBADSTATE;
5201
5202     switch(option)
5203     {
5204         case SPNG_KEEP_UNKNOWN_CHUNKS:
5205         {
5206             ctx->keep_unknown = value ? 1 : 0;
5207             break;
5208         }
5209         case SPNG_IMG_COMPRESSION_LEVEL:
5210         {
5211             ctx->image_options.compression_level = value;
5212             break;
5213         }
5214         case SPNG_IMG_WINDOW_BITS:
5215         {
5216             ctx->image_options.window_bits = value;
5217             break;
5218         }
5219         case SPNG_IMG_MEM_LEVEL:
5220         {
5221             ctx->image_options.mem_level = value;
5222             break;
5223         }
5224         case SPNG_IMG_COMPRESSION_STRATEGY:
5225         {
5226             ctx->image_options.strategy = value;
5227             break;
5228         }
5229         case SPNG_TEXT_COMPRESSION_LEVEL:
5230         {
5231             ctx->text_options.compression_level = value;
5232             break;
5233         }
5234         case SPNG_TEXT_WINDOW_BITS:
5235         {
5236             ctx->text_options.window_bits = value;
5237             break;
5238         }
5239         case SPNG_TEXT_MEM_LEVEL:
5240         {
5241             ctx->text_options.mem_level = value;
5242             break;
5243         }
5244         case SPNG_TEXT_COMPRESSION_STRATEGY:
5245         {
5246             ctx->text_options.strategy = value;
5247             break;
5248         }
5249         case SPNG_FILTER_CHOICE:
5250         {
5251             if(value & ~SPNG_FILTER_CHOICE_ALL) return 1;
5252             ctx->encode_flags.filter_choice = value;
5253             break;
5254         }
5255         case SPNG_CHUNK_COUNT_LIMIT:
5256         {
5257             if(value < 0) return 1;
5258             if(value > (int)ctx->chunk_count_total) return 1;
5259             ctx->chunk_count_limit = value;
5260             break;
5261         }
5262         case SPNG_ENCODE_TO_BUFFER:
5263         {
5264             if(value < 0) return 1;
5265             if(!ctx->encode_only) return SPNG_ECTXTYPE;
5266             if(ctx->state >= SPNG_STATE_OUTPUT) return SPNG_EOPSTATE;
5267
5268             if(!value) break;
5269
5270             ctx->internal_buffer = 1;
5271             ctx->state = SPNG_STATE_OUTPUT;
5272
5273             break;
5274         }
5275         default: return 1;
5276     }
5277
5278     /* Option can no longer be overriden by the library */
5279     if(option < 32) ctx->optimize_option &= ~(1 << option);
5280
5281     return 0;
5282 }
5283
5284 int spng_get_option(spng_ctx *ctx, enum spng_option option, int *value)
5285 {
5286     if(ctx == NULL || value == NULL) return 1;
5287     if(!ctx->state) return SPNG_EBADSTATE;
5288
5289     switch(option)
5290     {
5291         case SPNG_KEEP_UNKNOWN_CHUNKS:
5292         {
5293             *value = ctx->keep_unknown;
5294             break;
5295         }
5296         case SPNG_IMG_COMPRESSION_LEVEL:
5297         {
5298             *value = ctx->image_options.compression_level;
5299             break;
5300         }
5301             case SPNG_IMG_WINDOW_BITS:
5302         {
5303             *value = ctx->image_options.window_bits;
5304             break;
5305         }
5306         case SPNG_IMG_MEM_LEVEL:
5307         {
5308             *value = ctx->image_options.mem_level;
5309             break;
5310         }
5311         case SPNG_IMG_COMPRESSION_STRATEGY:
5312         {
5313             *value = ctx->image_options.strategy;
5314             break;
5315         }
5316         case SPNG_TEXT_COMPRESSION_LEVEL:
5317         {
5318             *value = ctx->text_options.compression_level;
5319             break;
5320         }
5321             case SPNG_TEXT_WINDOW_BITS:
5322         {
5323             *value = ctx->text_options.window_bits;
5324             break;
5325         }
5326         case SPNG_TEXT_MEM_LEVEL:
5327         {
5328             *value = ctx->text_options.mem_level;
5329             break;
5330         }
5331         case SPNG_TEXT_COMPRESSION_STRATEGY:
5332         {
5333             *value = ctx->text_options.strategy;
5334             break;
5335         }
5336         case SPNG_FILTER_CHOICE:
5337         {
5338             *value = ctx->encode_flags.filter_choice;
5339             break;
5340         }
5341         case SPNG_CHUNK_COUNT_LIMIT:
5342         {
5343             *value = ctx->chunk_count_limit;
5344             break;
5345         }
5346         case SPNG_ENCODE_TO_BUFFER:
5347         {
5348             if(ctx->internal_buffer) *value = 1;
5349             else *value = 0;
5350
5351             break;
5352         }
5353         default: return 1;
5354     }
5355
5356     return 0;
5357 }
5358
5359 int spng_decoded_image_size(spng_ctx *ctx, int fmt, size_t *len)
5360 {
5361     if(ctx == NULL || len == NULL) return 1;
5362
5363     int ret = read_chunks(ctx, 1);
5364     if(ret) return ret;
5365
5366     ret = check_decode_fmt(&ctx->ihdr, fmt);
5367     if(ret) return ret;
5368
5369     return calculate_image_size(&ctx->ihdr, fmt, len);
5370 }
5371
5372 int spng_get_ihdr(spng_ctx *ctx, struct spng_ihdr *ihdr)
5373 {
5374     if(ctx == NULL) return 1;
5375     int ret = read_chunks(ctx, 1);
5376     if(ret) return ret;
5377     if(ihdr == NULL) return 1;
5378
5379     *ihdr = ctx->ihdr;
5380
5381     return 0;
5382 }
5383
5384 int spng_get_plte(spng_ctx *ctx, struct spng_plte *plte)
5385 {
5386     SPNG_GET_CHUNK_BOILERPLATE(plte);
5387
5388     *plte = ctx->plte;
5389
5390     return 0;
5391 }
5392
5393 int spng_get_trns(spng_ctx *ctx, struct spng_trns *trns)
5394 {
5395     SPNG_GET_CHUNK_BOILERPLATE(trns);
5396
5397     *trns = ctx->trns;
5398
5399     return 0;
5400 }
5401
5402 int spng_get_chrm(spng_ctx *ctx, struct spng_chrm *chrm)
5403 {
5404     SPNG_GET_CHUNK_BOILERPLATE(chrm);
5405
5406     chrm->white_point_x = (double)ctx->chrm_int.white_point_x / 100000.0;
5407     chrm->white_point_y = (double)ctx->chrm_int.white_point_y / 100000.0;
5408     chrm->red_x = (double)ctx->chrm_int.red_x / 100000.0;
5409     chrm->red_y = (double)ctx->chrm_int.red_y / 100000.0;
5410     chrm->blue_y = (double)ctx->chrm_int.blue_y / 100000.0;
5411     chrm->blue_x = (double)ctx->chrm_int.blue_x / 100000.0;
5412     chrm->green_x = (double)ctx->chrm_int.green_x / 100000.0;
5413     chrm->green_y = (double)ctx->chrm_int.green_y / 100000.0;
5414
5415     return 0;
5416 }
5417
5418 int spng_get_chrm_int(spng_ctx *ctx, struct spng_chrm_int *chrm)
5419 {
5420     SPNG_GET_CHUNK_BOILERPLATE(chrm);
5421
5422     *chrm = ctx->chrm_int;
5423
5424     return 0;
5425 }
5426
5427 int spng_get_gama(spng_ctx *ctx, double *gamma)
5428 {
5429     double *gama = gamma;
5430     SPNG_GET_CHUNK_BOILERPLATE(gama);
5431
5432     *gama = (double)ctx->gama / 100000.0;
5433
5434     return 0;
5435 }
5436
5437 int spng_get_gama_int(spng_ctx *ctx, uint32_t *gama_int)
5438 {
5439     uint32_t *gama = gama_int;
5440     SPNG_GET_CHUNK_BOILERPLATE(gama);
5441
5442     *gama_int = ctx->gama;
5443
5444     return 0;
5445 }
5446
5447 int spng_get_iccp(spng_ctx *ctx, struct spng_iccp *iccp)
5448 {
5449     SPNG_GET_CHUNK_BOILERPLATE(iccp);
5450
5451     *iccp = ctx->iccp;
5452
5453     return 0;
5454 }
5455
5456 int spng_get_sbit(spng_ctx *ctx, struct spng_sbit *sbit)
5457 {
5458     SPNG_GET_CHUNK_BOILERPLATE(sbit);
5459
5460     *sbit = ctx->sbit;
5461
5462     return 0;
5463 }
5464
5465 int spng_get_srgb(spng_ctx *ctx, uint8_t *rendering_intent)
5466 {
5467     uint8_t *srgb = rendering_intent;
5468     SPNG_GET_CHUNK_BOILERPLATE(srgb);
5469
5470     *srgb = ctx->srgb_rendering_intent;
5471
5472     return 0;
5473 }
5474
5475 int spng_get_text(spng_ctx *ctx, struct spng_text *text, uint32_t *n_text)
5476 {
5477     if(ctx == NULL) return 1;
5478     int ret = read_chunks(ctx, 0);
5479     if(ret) return ret;
5480     if(!ctx->stored.text) return SPNG_ECHUNKAVAIL;
5481     if(n_text == NULL) return 1;
5482
5483     if(text == NULL)
5484     {
5485         *n_text = ctx->n_text;
5486         return 0;
5487     }
5488
5489     if(*n_text < ctx->n_text) return 1;
5490
5491     uint32_t i;
5492     for(i=0; i< ctx->n_text; i++)
5493     {
5494         text[i].type = ctx->text_list[i].type;
5495         memcpy(&text[i].keyword, ctx->text_list[i].keyword, strlen(ctx->text_list[i].keyword) + 1);
5496         text[i].compression_method = 0;
5497         text[i].compression_flag = ctx->text_list[i].compression_flag;
5498         text[i].language_tag = ctx->text_list[i].language_tag;
5499         text[i].translated_keyword = ctx->text_list[i].translated_keyword;
5500         text[i].length = ctx->text_list[i].text_length;
5501         text[i].text = ctx->text_list[i].text;
5502     }
5503
5504     return ret;
5505 }
5506
5507 int spng_get_bkgd(spng_ctx *ctx, struct spng_bkgd *bkgd)
5508 {
5509     SPNG_GET_CHUNK_BOILERPLATE(bkgd);
5510
5511     *bkgd = ctx->bkgd;
5512
5513     return 0;
5514 }
5515
5516 int spng_get_hist(spng_ctx *ctx, struct spng_hist *hist)
5517 {
5518     SPNG_GET_CHUNK_BOILERPLATE(hist);
5519
5520     *hist = ctx->hist;
5521
5522     return 0;
5523 }
5524
5525 int spng_get_phys(spng_ctx *ctx, struct spng_phys *phys)
5526 {
5527     SPNG_GET_CHUNK_BOILERPLATE(phys);
5528
5529     *phys = ctx->phys;
5530
5531     return 0;
5532 }
5533
5534 int spng_get_splt(spng_ctx *ctx, struct spng_splt *splt, uint32_t *n_splt)
5535 {
5536     if(ctx == NULL) return 1;
5537     int ret = read_chunks(ctx, 0);
5538     if(ret) return ret;
5539     if(!ctx->stored.splt) return SPNG_ECHUNKAVAIL;
5540     if(n_splt == NULL) return 1;
5541
5542     if(splt == NULL)
5543     {
5544         *n_splt = ctx->n_splt;
5545         return 0;
5546     }
5547
5548     if(*n_splt < ctx->n_splt) return 1;
5549
5550     memcpy(splt, ctx->splt_list, ctx->n_splt * sizeof(struct spng_splt));
5551
5552     return 0;
5553 }
5554
5555 int spng_get_time(spng_ctx *ctx, struct spng_time *time)
5556 {
5557     SPNG_GET_CHUNK_BOILERPLATE(time);
5558
5559     *time = ctx->time;
5560
5561     return 0;
5562 }
5563
5564 int spng_get_unknown_chunks(spng_ctx *ctx, struct spng_unknown_chunk *chunks, uint32_t *n_chunks)
5565 {
5566     if(ctx == NULL) return 1;
5567     int ret = read_chunks(ctx, 0);
5568     if(ret) return ret;
5569     if(!ctx->stored.unknown) return SPNG_ECHUNKAVAIL;
5570     if(n_chunks == NULL) return 1;
5571
5572     if(chunks == NULL)
5573     {
5574         *n_chunks = ctx->n_chunks;
5575         return 0;
5576     }
5577
5578     if(*n_chunks < ctx->n_chunks) return 1;
5579
5580     memcpy(chunks, ctx->chunk_list, sizeof(struct spng_unknown_chunk));
5581
5582     return 0;
5583 }
5584
5585 int spng_get_offs(spng_ctx *ctx, struct spng_offs *offs)
5586 {
5587     SPNG_GET_CHUNK_BOILERPLATE(offs);
5588
5589     *offs = ctx->offs;
5590
5591     return 0;
5592 }
5593
5594 int spng_get_exif(spng_ctx *ctx, struct spng_exif *exif)
5595 {
5596     SPNG_GET_CHUNK_BOILERPLATE(exif);
5597
5598     *exif = ctx->exif;
5599
5600     return 0;
5601 }
5602
5603 int spng_set_ihdr(spng_ctx *ctx, struct spng_ihdr *ihdr)
5604 {
5605     SPNG_SET_CHUNK_BOILERPLATE(ihdr);
5606
5607     if(ctx->stored.ihdr) return 1;
5608
5609     ret = check_ihdr(ihdr, ctx->max_width, ctx->max_height);
5610     if(ret) return ret;
5611
5612     ctx->ihdr = *ihdr;
5613
5614     ctx->stored.ihdr = 1;
5615     ctx->user.ihdr = 1;
5616
5617     return 0;
5618 }
5619
5620 int spng_set_plte(spng_ctx *ctx, struct spng_plte *plte)
5621 {
5622     SPNG_SET_CHUNK_BOILERPLATE(plte);
5623
5624     if(!ctx->stored.ihdr) return 1;
5625
5626     if(check_plte(plte, &ctx->ihdr)) return 1;
5627
5628     ctx->plte.n_entries = plte->n_entries;
5629
5630     memcpy(ctx->plte.entries, plte->entries, plte->n_entries * sizeof(struct spng_plte_entry));
5631
5632     ctx->stored.plte = 1;
5633     ctx->user.plte = 1;
5634
5635     return 0;
5636 }
5637
5638 int spng_set_trns(spng_ctx *ctx, struct spng_trns *trns)
5639 {
5640     SPNG_SET_CHUNK_BOILERPLATE(trns);
5641
5642     if(!ctx->stored.ihdr) return SPNG_ENOIHDR;
5643
5644     if(ctx->ihdr.color_type == SPNG_COLOR_TYPE_GRAYSCALE)
5645     {
5646         ctx->trns.gray = trns->gray;
5647     }
5648     else if(ctx->ihdr.color_type == SPNG_COLOR_TYPE_TRUECOLOR)
5649     {
5650         ctx->trns.red = trns->red;
5651         ctx->trns.green = trns->green;
5652         ctx->trns.blue = trns->blue;
5653     }
5654     else if(ctx->ihdr.color_type == SPNG_COLOR_TYPE_INDEXED)
5655     {
5656         if(!ctx->stored.plte) return SPNG_ETRNS_NO_PLTE;
5657         if(trns->n_type3_entries > ctx->plte.n_entries) return 1;
5658
5659         ctx->trns.n_type3_entries = trns->n_type3_entries;
5660         memcpy(ctx->trns.type3_alpha, trns->type3_alpha, trns->n_type3_entries);
5661     }
5662     else return SPNG_ETRNS_COLOR_TYPE;
5663
5664     ctx->stored.trns = 1;
5665     ctx->user.trns = 1;
5666
5667     return 0;
5668 }
5669
5670 int spng_set_chrm(spng_ctx *ctx, struct spng_chrm *chrm)
5671 {
5672     SPNG_SET_CHUNK_BOILERPLATE(chrm);
5673
5674     struct spng_chrm_int chrm_int;
5675
5676     chrm_int.white_point_x = (uint32_t)(chrm->white_point_x * 100000.0);
5677     chrm_int.white_point_y = (uint32_t)(chrm->white_point_y * 100000.0);
5678     chrm_int.red_x = (uint32_t)(chrm->red_x * 100000.0);
5679     chrm_int.red_y = (uint32_t)(chrm->red_y * 100000.0);
5680     chrm_int.green_x = (uint32_t)(chrm->green_x * 100000.0);
5681     chrm_int.green_y = (uint32_t)(chrm->green_y * 100000.0);
5682     chrm_int.blue_x = (uint32_t)(chrm->blue_x * 100000.0);
5683     chrm_int.blue_y = (uint32_t)(chrm->blue_y * 100000.0);
5684
5685     if(check_chrm_int(&chrm_int)) return SPNG_ECHRM;
5686
5687     ctx->chrm_int = chrm_int;
5688
5689     ctx->stored.chrm = 1;
5690     ctx->user.chrm = 1;
5691
5692     return 0;
5693 }
5694
5695 int spng_set_chrm_int(spng_ctx *ctx, struct spng_chrm_int *chrm_int)
5696 {
5697     SPNG_SET_CHUNK_BOILERPLATE(chrm_int);
5698
5699     if(check_chrm_int(chrm_int)) return SPNG_ECHRM;
5700
5701     ctx->chrm_int = *chrm_int;
5702
5703     ctx->stored.chrm = 1;
5704     ctx->user.chrm = 1;
5705
5706     return 0;
5707 }
5708
5709 int spng_set_gama(spng_ctx *ctx, double gamma)
5710 {
5711     SPNG_SET_CHUNK_BOILERPLATE(ctx);
5712
5713     uint32_t gama = gamma * 100000.0;
5714
5715     if(!gama) return 1;
5716     if(gama > spng_u32max) return 1;
5717
5718     ctx->gama = gama;
5719
5720     ctx->stored.gama = 1;
5721     ctx->user.gama = 1;
5722
5723     return 0;
5724 }
5725
5726 int spng_set_gama_int(spng_ctx *ctx, uint32_t gamma)
5727 {
5728     SPNG_SET_CHUNK_BOILERPLATE(ctx);
5729
5730     if(!gamma) return 1;
5731     if(gamma > spng_u32max) return 1;
5732
5733     ctx->gama = gamma;
5734
5735     ctx->stored.gama = 1;
5736     ctx->user.gama = 1;
5737
5738     return 0;
5739 }
5740
5741 int spng_set_iccp(spng_ctx *ctx, struct spng_iccp *iccp)
5742 {
5743     SPNG_SET_CHUNK_BOILERPLATE(iccp);
5744
5745     if(check_png_keyword(iccp->profile_name)) return SPNG_EICCP_NAME;
5746     if(!iccp->profile_len || iccp->profile_len > UINT_MAX) return 1;
5747
5748     if(ctx->iccp.profile && !ctx->user.iccp) spng__free(ctx, ctx->iccp.profile);
5749
5750     ctx->iccp = *iccp;
5751
5752     ctx->stored.iccp = 1;
5753     ctx->user.iccp = 1;
5754
5755     return 0;
5756 }
5757
5758 int spng_set_sbit(spng_ctx *ctx, struct spng_sbit *sbit)
5759 {
5760     SPNG_SET_CHUNK_BOILERPLATE(sbit);
5761
5762     if(check_sbit(sbit, &ctx->ihdr)) return 1;
5763
5764     if(!ctx->stored.ihdr) return 1;
5765
5766     ctx->sbit = *sbit;
5767
5768     ctx->stored.sbit = 1;
5769     ctx->user.sbit = 1;
5770
5771     return 0;
5772 }
5773
5774 int spng_set_srgb(spng_ctx *ctx, uint8_t rendering_intent)
5775 {
5776     SPNG_SET_CHUNK_BOILERPLATE(ctx);
5777
5778     if(rendering_intent > 3) return 1;
5779
5780     ctx->srgb_rendering_intent = rendering_intent;
5781
5782     ctx->stored.srgb = 1;
5783     ctx->user.srgb = 1;
5784
5785     return 0;
5786 }
5787
5788 int spng_set_text(spng_ctx *ctx, struct spng_text *text, uint32_t n_text)
5789 {
5790     if(!n_text) return 1;
5791     SPNG_SET_CHUNK_BOILERPLATE(text);
5792
5793     uint32_t i;
5794     for(i=0; i < n_text; i++)
5795     {
5796         if(check_png_keyword(text[i].keyword)) return SPNG_ETEXT_KEYWORD;
5797         if(!text[i].length) return 1;
5798         if(text[i].length > UINT_MAX) return 1;
5799         if(text[i].text == NULL) return 1;
5800
5801         if(text[i].type == SPNG_TEXT)
5802         {
5803             if(ctx->strict && check_png_text(text[i].text, text[i].length)) return 1;
5804         }
5805         else if(text[i].type == SPNG_ZTXT)
5806         {
5807             if(ctx->strict && check_png_text(text[i].text, text[i].length)) return 1;
5808
5809             if(text[i].compression_method != 0) return SPNG_EZTXT_COMPRESSION_METHOD;
5810         }
5811         else if(text[i].type == SPNG_ITXT)
5812         {
5813             if(text[i].compression_flag > 1) return SPNG_EITXT_COMPRESSION_FLAG;
5814             if(text[i].compression_method != 0) return SPNG_EITXT_COMPRESSION_METHOD;
5815             if(text[i].language_tag == NULL) return SPNG_EITXT_LANG_TAG;
5816             if(text[i].translated_keyword == NULL) return SPNG_EITXT_TRANSLATED_KEY;
5817         }
5818         else return 1;
5819
5820     }
5821
5822     struct spng_text2 *text_list = spng__calloc(ctx, sizeof(struct spng_text2), n_text);
5823
5824     if(!text_list) return SPNG_EMEM;
5825
5826     if(ctx->text_list != NULL)
5827     {
5828         for(i=0; i < ctx->n_text; i++)
5829         {
5830             if(ctx->user.text) break;
5831
5832             spng__free(ctx, ctx->text_list[i].keyword);
5833             if(ctx->text_list[i].compression_flag) spng__free(ctx, ctx->text_list[i].text);
5834         }
5835         spng__free(ctx, ctx->text_list);
5836     }
5837
5838     for(i=0; i < n_text; i++)
5839     {
5840         text_list[i].type = text[i].type;
5841         /* Prevent issues with spng_text.keyword[80] going out of scope */
5842         text_list[i].keyword = text_list[i].user_keyword_storage;
5843         memcpy(text_list[i].user_keyword_storage, text[i].keyword, strlen(text[i].keyword));
5844         text_list[i].text = text[i].text;
5845         text_list[i].text_length = text[i].length;
5846
5847         if(text[i].type == SPNG_ZTXT)
5848         {
5849             text_list[i].compression_flag = 1;
5850         }
5851         else if(text[i].type == SPNG_ITXT)
5852         {
5853             text_list[i].compression_flag = text[i].compression_flag;
5854             text_list[i].language_tag = text[i].language_tag;
5855             text_list[i].translated_keyword = text[i].translated_keyword;
5856         }
5857     }
5858
5859     ctx->text_list = text_list;
5860     ctx->n_text = n_text;
5861
5862     ctx->stored.text = 1;
5863     ctx->user.text = 1;
5864
5865     return 0;
5866 }
5867
5868 int spng_set_bkgd(spng_ctx *ctx, struct spng_bkgd *bkgd)
5869 {
5870     SPNG_SET_CHUNK_BOILERPLATE(bkgd);
5871
5872     if(!ctx->stored.ihdr)  return 1;
5873
5874     if(ctx->ihdr.color_type == 0 || ctx->ihdr.color_type == 4)
5875     {
5876         ctx->bkgd.gray = bkgd->gray;
5877     }
5878     else if(ctx->ihdr.color_type == 2 || ctx->ihdr.color_type == 6)
5879     {
5880         ctx->bkgd.red = bkgd->red;
5881         ctx->bkgd.green = bkgd->green;
5882         ctx->bkgd.blue = bkgd->blue;
5883     }
5884     else if(ctx->ihdr.color_type == 3)
5885     {
5886         if(!ctx->stored.plte) return SPNG_EBKGD_NO_PLTE;
5887         if(bkgd->plte_index >= ctx->plte.n_entries) return SPNG_EBKGD_PLTE_IDX;
5888
5889         ctx->bkgd.plte_index = bkgd->plte_index;
5890     }
5891
5892     ctx->stored.bkgd = 1;
5893     ctx->user.bkgd = 1;
5894
5895     return 0;
5896 }
5897
5898 int spng_set_hist(spng_ctx *ctx, struct spng_hist *hist)
5899 {
5900     SPNG_SET_CHUNK_BOILERPLATE(hist);
5901
5902     if(!ctx->stored.plte) return SPNG_EHIST_NO_PLTE;
5903
5904     ctx->hist = *hist;
5905
5906     ctx->stored.hist = 1;
5907     ctx->user.hist = 1;
5908
5909     return 0;
5910 }
5911
5912 int spng_set_phys(spng_ctx *ctx, struct spng_phys *phys)
5913 {
5914     SPNG_SET_CHUNK_BOILERPLATE(phys);
5915
5916     if(check_phys(phys)) return SPNG_EPHYS;
5917
5918     ctx->phys = *phys;
5919
5920     ctx->stored.phys = 1;
5921     ctx->user.phys = 1;
5922
5923     return 0;
5924 }
5925
5926 int spng_set_splt(spng_ctx *ctx, struct spng_splt *splt, uint32_t n_splt)
5927 {
5928     if(!n_splt) return 1;
5929     SPNG_SET_CHUNK_BOILERPLATE(splt);
5930
5931     uint32_t i;
5932     for(i=0; i < n_splt; i++)
5933     {
5934         if(check_png_keyword(splt[i].name)) return SPNG_ESPLT_NAME;
5935         if( !(splt[i].sample_depth == 8 || splt[i].sample_depth == 16) ) return SPNG_ESPLT_DEPTH;
5936     }
5937
5938     if(ctx->stored.splt && !ctx->user.splt)
5939     {
5940         for(i=0; i < ctx->n_splt; i++)
5941         {
5942             if(ctx->splt_list[i].entries != NULL) spng__free(ctx, ctx->splt_list[i].entries);
5943         }
5944         spng__free(ctx, ctx->splt_list);
5945     }
5946
5947     ctx->splt_list = splt;
5948     ctx->n_splt = n_splt;
5949
5950     ctx->stored.splt = 1;
5951     ctx->user.splt = 1;
5952
5953     return 0;
5954 }
5955
5956 int spng_set_time(spng_ctx *ctx, struct spng_time *time)
5957 {
5958     SPNG_SET_CHUNK_BOILERPLATE(time);
5959
5960     if(check_time(time)) return SPNG_ETIME;
5961
5962     ctx->time = *time;
5963
5964     ctx->stored.time = 1;
5965     ctx->user.time = 1;
5966
5967     return 0;
5968 }
5969
5970 int spng_set_unknown_chunks(spng_ctx *ctx, struct spng_unknown_chunk *chunks, uint32_t n_chunks)
5971 {
5972     if(!n_chunks) return 1;
5973     SPNG_SET_CHUNK_BOILERPLATE(chunks);
5974
5975     uint32_t i;
5976     for(i=0; i < n_chunks; i++)
5977     {
5978         if(chunks[i].length > spng_u32max) return SPNG_ECHUNK_STDLEN;
5979         if(chunks[i].length && chunks[i].data == NULL) return 1;
5980
5981         switch(chunks[i].location)
5982         {
5983             case SPNG_AFTER_IHDR:
5984             case SPNG_AFTER_PLTE:
5985             case SPNG_AFTER_IDAT:
5986             break;
5987             default: return SPNG_ECHUNK_POS;
5988         }
5989     }
5990
5991     if(ctx->stored.unknown && !ctx->user.unknown)
5992     {
5993         for(i=0; i < ctx->n_chunks; i++)
5994         {
5995             spng__free(ctx, ctx->chunk_list[i].data);
5996         }
5997         spng__free(ctx, ctx->chunk_list);
5998     }
5999
6000     ctx->chunk_list = chunks;
6001     ctx->n_chunks = n_chunks;
6002
6003     ctx->stored.unknown = 1;
6004     ctx->user.unknown = 1;
6005
6006     return 0;
6007 }
6008
6009 int spng_set_offs(spng_ctx *ctx, struct spng_offs *offs)
6010 {
6011     SPNG_SET_CHUNK_BOILERPLATE(offs);
6012
6013     if(check_offs(offs)) return SPNG_EOFFS;
6014
6015     ctx->offs = *offs;
6016
6017     ctx->stored.offs = 1;
6018     ctx->user.offs = 1;
6019
6020     return 0;
6021 }
6022
6023 int spng_set_exif(spng_ctx *ctx, struct spng_exif *exif)
6024 {
6025     SPNG_SET_CHUNK_BOILERPLATE(exif);
6026
6027     if(check_exif(exif)) return SPNG_EEXIF;
6028
6029     if(ctx->exif.data != NULL && !ctx->user.exif) spng__free(ctx, ctx->exif.data);
6030
6031     ctx->exif = *exif;
6032
6033     ctx->stored.exif = 1;
6034     ctx->user.exif = 1;
6035
6036     return 0;
6037 }
6038
6039 const char *spng_strerror(int err)
6040 {
6041     switch(err)
6042     {
6043         case SPNG_IO_EOF: return "end of stream";
6044         case SPNG_IO_ERROR: return "stream error";
6045         case SPNG_OK: return "success";
6046         case SPNG_EINVAL: return "invalid argument";
6047         case SPNG_EMEM: return "out of memory";
6048         case SPNG_EOVERFLOW: return "arithmetic overflow";
6049         case SPNG_ESIGNATURE: return "invalid signature";
6050         case SPNG_EWIDTH: return "invalid image width";
6051         case SPNG_EHEIGHT: return "invalid image height";
6052         case SPNG_EUSER_WIDTH: return "image width exceeds user limit";
6053         case SPNG_EUSER_HEIGHT: return "image height exceeds user limit";
6054         case SPNG_EBIT_DEPTH: return "invalid bit depth";
6055         case SPNG_ECOLOR_TYPE: return "invalid color type";
6056         case SPNG_ECOMPRESSION_METHOD: return "invalid compression method";
6057         case SPNG_EFILTER_METHOD: return "invalid filter method";
6058         case SPNG_EINTERLACE_METHOD: return "invalid interlace method";
6059         case SPNG_EIHDR_SIZE: return "invalid IHDR chunk size";
6060         case SPNG_ENOIHDR: return "missing IHDR chunk";
6061         case SPNG_ECHUNK_POS: return "invalid chunk position";
6062         case SPNG_ECHUNK_SIZE: return "invalid chunk length";
6063         case SPNG_ECHUNK_CRC: return "invalid chunk checksum";
6064         case SPNG_ECHUNK_TYPE: return "invalid chunk type";
6065         case SPNG_ECHUNK_UNKNOWN_CRITICAL: return "unknown critical chunk";
6066         case SPNG_EDUP_PLTE: return "duplicate PLTE chunk";
6067         case SPNG_EDUP_CHRM: return "duplicate cHRM chunk";
6068         case SPNG_EDUP_GAMA: return "duplicate gAMA chunk";
6069         case SPNG_EDUP_ICCP: return "duplicate iCCP chunk";
6070         case SPNG_EDUP_SBIT: return "duplicate sBIT chunk";
6071         case SPNG_EDUP_SRGB: return "duplicate sRGB chunk";
6072         case SPNG_EDUP_BKGD: return "duplicate bKGD chunk";
6073         case SPNG_EDUP_HIST: return "duplicate hIST chunk";
6074         case SPNG_EDUP_TRNS: return "duplicate tRNS chunk";
6075         case SPNG_EDUP_PHYS: return "duplicate pHYs chunk";
6076         case SPNG_EDUP_TIME: return "duplicate tIME chunk";
6077         case SPNG_EDUP_OFFS: return "duplicate oFFs chunk";
6078         case SPNG_EDUP_EXIF: return "duplicate eXIf chunk";
6079         case SPNG_ECHRM: return "invalid cHRM chunk";
6080         case SPNG_EPLTE_IDX: return "invalid palette (PLTE) index";
6081         case SPNG_ETRNS_COLOR_TYPE: return "tRNS chunk with incompatible color type";
6082         case SPNG_ETRNS_NO_PLTE: return "missing palette (PLTE) for tRNS chunk";
6083         case SPNG_EGAMA: return "invalid gAMA chunk";
6084         case SPNG_EICCP_NAME: return "invalid iCCP profile name";
6085         case SPNG_EICCP_COMPRESSION_METHOD: return "invalid iCCP compression method";
6086         case SPNG_ESBIT: return "invalid sBIT chunk";
6087         case SPNG_ESRGB: return "invalid sRGB chunk";
6088         case SPNG_ETEXT: return "invalid tEXt chunk";
6089         case SPNG_ETEXT_KEYWORD: return "invalid tEXt keyword";
6090         case SPNG_EZTXT: return "invalid zTXt chunk";
6091         case SPNG_EZTXT_COMPRESSION_METHOD: return "invalid zTXt compression method";
6092         case SPNG_EITXT: return "invalid iTXt chunk";
6093         case SPNG_EITXT_COMPRESSION_FLAG: return "invalid iTXt compression flag";
6094         case SPNG_EITXT_COMPRESSION_METHOD: return "invalid iTXt compression method";
6095         case SPNG_EITXT_LANG_TAG: return "invalid iTXt language tag";
6096         case SPNG_EITXT_TRANSLATED_KEY: return "invalid iTXt translated key";
6097         case SPNG_EBKGD_NO_PLTE: return "missing palette for bKGD chunk";
6098         case SPNG_EBKGD_PLTE_IDX: return "invalid palette index for bKGD chunk";
6099         case SPNG_EHIST_NO_PLTE: return "missing palette for hIST chunk";
6100         case SPNG_EPHYS: return "invalid pHYs chunk";
6101         case SPNG_ESPLT_NAME: return "invalid suggested palette name";
6102         case SPNG_ESPLT_DUP_NAME: return "duplicate suggested palette (sPLT) name";
6103         case SPNG_ESPLT_DEPTH: return "invalid suggested palette (sPLT) sample depth";
6104         case SPNG_ETIME: return "invalid tIME chunk";
6105         case SPNG_EOFFS: return "invalid oFFs chunk";
6106         case SPNG_EEXIF: return "invalid eXIf chunk";
6107         case SPNG_EIDAT_TOO_SHORT: return "IDAT stream too short";
6108         case SPNG_EIDAT_STREAM: return "IDAT stream error";
6109         case SPNG_EZLIB: return "zlib error";
6110         case SPNG_EFILTER: return "invalid scanline filter";
6111         case SPNG_EBUFSIZ: return "invalid buffer size";
6112         case SPNG_EIO: return "i/o error";
6113         case SPNG_EOF: return "end of file";
6114         case SPNG_EBUF_SET: return "buffer already set";
6115         case SPNG_EBADSTATE: return "non-recoverable state";
6116         case SPNG_EFMT: return "invalid format";
6117         case SPNG_EFLAGS: return "invalid flags";
6118         case SPNG_ECHUNKAVAIL: return "chunk not available";
6119         case SPNG_ENCODE_ONLY: return "encode only context";
6120         case SPNG_EOI: return "reached end-of-image state";
6121         case SPNG_ENOPLTE: return "missing PLTE for indexed image";
6122         case SPNG_ECHUNK_LIMITS: return "reached chunk/cache limits";
6123         case SPNG_EZLIB_INIT: return "zlib init error";
6124         case SPNG_ECHUNK_STDLEN: return "chunk exceeds maximum standard length";
6125         case SPNG_EINTERNAL: return "internal error";
6126         case SPNG_ECTXTYPE: return "invalid operation for context type";
6127         case SPNG_ENOSRC: return "source PNG not set";
6128         case SPNG_ENODST: return "PNG output not set";
6129         case SPNG_EOPSTATE: return "invalid operation for state";
6130         case SPNG_ENOTFINAL: return "PNG not finalized";
6131         default: return "unknown error";
6132     }
6133 }
6134
6135 const char *spng_version_string(void)
6136 {
6137     return SPNG_VERSION_STRING;
6138 }
6139
6140 #if defined(_MSC_VER)
6141     #pragma warning(pop)
6142 #endif
6143
6144 /* The following SIMD optimizations are derived from libpng source code. */
6145
6146 /*
6147 * PNG Reference Library License version 2
6148 *
6149 * Copyright (c) 1995-2019 The PNG Reference Library Authors.
6150 * Copyright (c) 2018-2019 Cosmin Truta.
6151 * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson.
6152 * Copyright (c) 1996-1997 Andreas Dilger.
6153 * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
6154 *
6155 * The software is supplied "as is", without warranty of any kind,
6156 * express or implied, including, without limitation, the warranties
6157 * of merchantability, fitness for a particular purpose, title, and
6158 * non-infringement.  In no event shall the Copyright owners, or
6159 * anyone distributing the software, be liable for any damages or
6160 * other liability, whether in contract, tort or otherwise, arising
6161 * from, out of, or in connection with the software, or the use or
6162 * other dealings in the software, even if advised of the possibility
6163 * of such damage.
6164 *
6165 * Permission is hereby granted to use, copy, modify, and distribute
6166 * this software, or portions hereof, for any purpose, without fee,
6167 * subject to the following restrictions:
6168 *
6169 *  1. The origin of this software must not be misrepresented; you
6170 *     must not claim that you wrote the original software.  If you
6171 *     use this software in a product, an acknowledgment in the product
6172 *     documentation would be appreciated, but is not required.
6173 *
6174 *  2. Altered source versions must be plainly marked as such, and must
6175 *     not be misrepresented as being the original software.
6176 *
6177 *  3. This Copyright notice may not be removed or altered from any
6178 *     source or altered source distribution.
6179 */
6180
6181 #if defined(SPNG_X86)
6182
6183 #ifndef SPNG_SSE
6184     #define SPNG_SSE 1
6185 #endif
6186
6187 #if defined(__GNUC__) && !defined(__clang__)
6188     #if SPNG_SSE == 3
6189         #pragma GCC target("ssse3")
6190     #elif SPNG_SSE == 4
6191         #pragma GCC target("sse4.1")
6192     #else
6193         #pragma GCC target("sse2")
6194     #endif
6195 #endif
6196
6197 /* SSE2 optimised filter functions
6198  * Derived from filter_neon_intrinsics.c
6199  *
6200  * Copyright (c) 2018 Cosmin Truta
6201  * Copyright (c) 2016-2017 Glenn Randers-Pehrson
6202  * Written by Mike Klein and Matt Sarett
6203  * Derived from arm/filter_neon_intrinsics.c
6204  *
6205  * This code is derived from libpng source code.
6206  * For conditions of distribution and use, see the disclaimer
6207  * and license above.
6208  */
6209
6210 #include <immintrin.h>
6211 #include <inttypes.h>
6212 #include <string.h>
6213
6214 /* Functions in this file look at most 3 pixels (a,b,c) to predict the 4th (d).
6215  * They're positioned like this:
6216  *    prev:  c b
6217  *    row:   a d
6218  * The Sub filter predicts d=a, Avg d=(a+b)/2, and Paeth predicts d to be
6219  * whichever of a, b, or c is closest to p=a+b-c.
6220  */
6221
6222 static __m128i load4(const void* p)
6223 {
6224     int tmp;
6225     memcpy(&tmp, p, sizeof(tmp));
6226     return _mm_cvtsi32_si128(tmp);
6227 }
6228
6229 static void store4(void* p, __m128i v)
6230 {
6231     int tmp = _mm_cvtsi128_si32(v);
6232     memcpy(p, &tmp, sizeof(int));
6233 }
6234
6235 static __m128i load3(const void* p)
6236 {
6237     uint32_t tmp = 0;
6238     memcpy(&tmp, p, 3);
6239     return _mm_cvtsi32_si128(tmp);
6240 }
6241
6242 static void store3(void* p, __m128i v)
6243 {
6244     int tmp = _mm_cvtsi128_si32(v);
6245     memcpy(p, &tmp, 3);
6246 }
6247
6248 static void defilter_sub3(size_t rowbytes, unsigned char *row)
6249 {
6250     /* The Sub filter predicts each pixel as the previous pixel, a.
6251      * There is no pixel to the left of the first pixel.  It's encoded directly.
6252      * That works with our main loop if we just say that left pixel was zero.
6253      */
6254     size_t rb = rowbytes;
6255
6256     __m128i a, d = _mm_setzero_si128();
6257
6258     while(rb >= 4)
6259     {
6260         a = d; d = load4(row);
6261         d = _mm_add_epi8(d, a);
6262         store3(row, d);
6263
6264         row += 3;
6265         rb  -= 3;
6266     }
6267
6268     if(rb > 0)
6269     {
6270         a = d; d = load3(row);
6271         d = _mm_add_epi8(d, a);
6272         store3(row, d);
6273     }
6274 }
6275
6276 static void defilter_sub4(size_t rowbytes, unsigned char *row)
6277 {
6278     /* The Sub filter predicts each pixel as the previous pixel, a.
6279      * There is no pixel to the left of the first pixel.  It's encoded directly.
6280      * That works with our main loop if we just say that left pixel was zero.
6281      */
6282     size_t rb = rowbytes+4;
6283
6284     __m128i a, d = _mm_setzero_si128();
6285
6286     while(rb > 4)
6287     {
6288         a = d; d = load4(row);
6289         d = _mm_add_epi8(d, a);
6290         store4(row, d);
6291
6292         row += 4;
6293         rb  -= 4;
6294     }
6295 }
6296
6297 static void defilter_avg3(size_t rowbytes, unsigned char *row, const unsigned char *prev)
6298 {
6299     /* The Avg filter predicts each pixel as the (truncated) average of a and b.
6300      * There's no pixel to the left of the first pixel.  Luckily, it's
6301      * predicted to be half of the pixel above it.  So again, this works
6302      * perfectly with our loop if we make sure a starts at zero.
6303      */
6304
6305     size_t rb = rowbytes;
6306
6307     const __m128i zero = _mm_setzero_si128();
6308
6309     __m128i b;
6310     __m128i a, d = zero;
6311
6312     while(rb >= 4)
6313     {
6314         __m128i avg;
6315                b = load4(prev);
6316         a = d; d = load4(row );
6317
6318         /* PNG requires a truncating average, so we can't just use _mm_avg_epu8 */
6319         avg = _mm_avg_epu8(a,b);
6320         /* ...but we can fix it up by subtracting off 1 if it rounded up. */
6321         avg = _mm_sub_epi8(avg, _mm_and_si128(_mm_xor_si128(a, b),
6322                                             _mm_set1_epi8(1)));
6323         d = _mm_add_epi8(d, avg);
6324         store3(row, d);
6325
6326         prev += 3;
6327         row  += 3;
6328         rb   -= 3;
6329     }
6330
6331     if(rb > 0)
6332     {
6333         __m128i avg;
6334                b = load3(prev);
6335         a = d; d = load3(row );
6336
6337         /* PNG requires a truncating average, so we can't just use _mm_avg_epu8 */
6338         avg = _mm_avg_epu8(a, b);
6339         /* ...but we can fix it up by subtracting off 1 if it rounded up. */
6340         avg = _mm_sub_epi8(avg, _mm_and_si128(_mm_xor_si128(a, b),
6341                                             _mm_set1_epi8(1)));
6342
6343         d = _mm_add_epi8(d, avg);
6344         store3(row, d);
6345     }
6346 }
6347
6348 static void defilter_avg4(size_t rowbytes, unsigned char *row, const unsigned char *prev)
6349 {
6350     /* The Avg filter predicts each pixel as the (truncated) average of a and b.
6351      * There's no pixel to the left of the first pixel.  Luckily, it's
6352      * predicted to be half of the pixel above it.  So again, this works
6353      * perfectly with our loop if we make sure a starts at zero.
6354      */
6355     size_t rb = rowbytes+4;
6356
6357     const __m128i zero = _mm_setzero_si128();
6358     __m128i    b;
6359     __m128i a, d = zero;
6360
6361     while(rb > 4)
6362     {
6363         __m128i avg;
6364                b = load4(prev);
6365         a = d; d = load4(row );
6366
6367         /* PNG requires a truncating average, so we can't just use _mm_avg_epu8 */
6368         avg = _mm_avg_epu8(a,b);
6369         /* ...but we can fix it up by subtracting off 1 if it rounded up. */
6370         avg = _mm_sub_epi8(avg, _mm_and_si128(_mm_xor_si128(a, b),
6371                                             _mm_set1_epi8(1)));
6372
6373         d = _mm_add_epi8(d, avg);
6374         store4(row, d);
6375
6376         prev += 4;
6377         row  += 4;
6378         rb   -= 4;
6379     }
6380 }
6381
6382 /* Returns |x| for 16-bit lanes. */
6383 #if (SPNG_SSE >= 3) && !defined(_MSC_VER)
6384 __attribute__((target("ssse3")))
6385 #endif
6386 static __m128i abs_i16(__m128i x)
6387 {
6388 #if SPNG_SSE >= 3
6389     return _mm_abs_epi16(x);
6390 #else
6391     /* Read this all as, return x<0 ? -x : x.
6392      * To negate two's complement, you flip all the bits then add 1.
6393      */
6394     __m128i is_negative = _mm_cmplt_epi16(x, _mm_setzero_si128());
6395
6396     /* Flip negative lanes. */
6397     x = _mm_xor_si128(x, is_negative);
6398
6399     /* +1 to negative lanes, else +0. */
6400     x = _mm_sub_epi16(x, is_negative);
6401     return x;
6402 #endif
6403 }
6404
6405 /* Bytewise c ? t : e. */
6406 static __m128i if_then_else(__m128i c, __m128i t, __m128i e)
6407 {
6408 #if SPNG_SSE >= 4
6409     return _mm_blendv_epi8(e, t, c);
6410 #else
6411     return _mm_or_si128(_mm_and_si128(c, t), _mm_andnot_si128(c, e));
6412 #endif
6413 }
6414
6415 static void defilter_paeth3(size_t rowbytes, unsigned char *row, const unsigned char *prev)
6416 {
6417     /* Paeth tries to predict pixel d using the pixel to the left of it, a,
6418      * and two pixels from the previous row, b and c:
6419      *   prev: c b
6420      *   row:  a d
6421      * The Paeth function predicts d to be whichever of a, b, or c is nearest to
6422      * p=a+b-c.
6423      *
6424      * The first pixel has no left context, and so uses an Up filter, p = b.
6425      * This works naturally with our main loop's p = a+b-c if we force a and c
6426      * to zero.
6427      * Here we zero b and d, which become c and a respectively at the start of
6428      * the loop.
6429      */
6430     size_t rb = rowbytes;
6431     const __m128i zero = _mm_setzero_si128();
6432     __m128i c, b = zero,
6433             a, d = zero;
6434
6435     while(rb >= 4)
6436     {
6437         /* It's easiest to do this math (particularly, deal with pc) with 16-bit
6438          * intermediates.
6439          */
6440         __m128i pa,pb,pc,smallest,nearest;
6441         c = b; b = _mm_unpacklo_epi8(load4(prev), zero);
6442         a = d; d = _mm_unpacklo_epi8(load4(row ), zero);
6443
6444         /* (p-a) == (a+b-c - a) == (b-c) */
6445
6446         pa = _mm_sub_epi16(b, c);
6447
6448         /* (p-b) == (a+b-c - b) == (a-c) */
6449         pb = _mm_sub_epi16(a, c);
6450
6451         /* (p-c) == (a+b-c - c) == (a+b-c-c) == (b-c)+(a-c) */
6452         pc = _mm_add_epi16(pa, pb);
6453
6454         pa = abs_i16(pa);  /* |p-a| */
6455         pb = abs_i16(pb);  /* |p-b| */
6456         pc = abs_i16(pc);  /* |p-c| */
6457
6458         smallest = _mm_min_epi16(pc, _mm_min_epi16(pa, pb));
6459
6460         /* Paeth breaks ties favoring a over b over c. */
6461         nearest  = if_then_else(_mm_cmpeq_epi16(smallest, pa), a,
6462                             if_then_else(_mm_cmpeq_epi16(smallest, pb), b, c));
6463
6464         /* Note `_epi8`: we need addition to wrap modulo 255. */
6465         d = _mm_add_epi8(d, nearest);
6466         store3(row, _mm_packus_epi16(d, d));
6467
6468         prev += 3;
6469         row  += 3;
6470         rb   -= 3;
6471     }
6472
6473     if(rb > 0)
6474     {
6475         /* It's easiest to do this math (particularly, deal with pc) with 16-bit
6476          * intermediates.
6477          */
6478         __m128i pa, pb, pc, smallest, nearest;
6479         c = b; b = _mm_unpacklo_epi8(load3(prev), zero);
6480         a = d; d = _mm_unpacklo_epi8(load3(row ), zero);
6481
6482         /* (p-a) == (a+b-c - a) == (b-c) */
6483         pa = _mm_sub_epi16(b, c);
6484
6485         /* (p-b) == (a+b-c - b) == (a-c) */
6486         pb = _mm_sub_epi16(a, c);
6487
6488         /* (p-c) == (a+b-c - c) == (a+b-c-c) == (b-c)+(a-c) */
6489         pc = _mm_add_epi16(pa, pb);
6490
6491         pa = abs_i16(pa);  /* |p-a| */
6492         pb = abs_i16(pb);  /* |p-b| */
6493         pc = abs_i16(pc);  /* |p-c| */
6494
6495         smallest = _mm_min_epi16(pc, _mm_min_epi16(pa, pb));
6496
6497         /* Paeth breaks ties favoring a over b over c. */
6498         nearest  = if_then_else(_mm_cmpeq_epi16(smallest, pa), a,
6499                             if_then_else(_mm_cmpeq_epi16(smallest, pb), b, c));
6500
6501         /* Note `_epi8`: we need addition to wrap modulo 255. */
6502         d = _mm_add_epi8(d, nearest);
6503         store3(row, _mm_packus_epi16(d, d));
6504     }
6505 }
6506
6507 static void defilter_paeth4(size_t rowbytes, unsigned char *row, const unsigned char *prev)
6508 {
6509     /* Paeth tries to predict pixel d using the pixel to the left of it, a,
6510      * and two pixels from the previous row, b and c:
6511      *   prev: c b
6512      *   row:  a d
6513      * The Paeth function predicts d to be whichever of a, b, or c is nearest to
6514      * p=a+b-c.
6515      *
6516      * The first pixel has no left context, and so uses an Up filter, p = b.
6517      * This works naturally with our main loop's p = a+b-c if we force a and c
6518      * to zero.
6519      * Here we zero b and d, which become c and a respectively at the start of
6520      * the loop.
6521      */
6522     size_t rb = rowbytes+4;
6523
6524     const __m128i zero = _mm_setzero_si128();
6525     __m128i pa, pb, pc, smallest, nearest;
6526     __m128i c, b = zero,
6527             a, d = zero;
6528
6529     while(rb > 4)
6530     {
6531         /* It's easiest to do this math (particularly, deal with pc) with 16-bit
6532          * intermediates.
6533          */
6534         c = b; b = _mm_unpacklo_epi8(load4(prev), zero);
6535         a = d; d = _mm_unpacklo_epi8(load4(row ), zero);
6536
6537         /* (p-a) == (a+b-c - a) == (b-c) */
6538         pa = _mm_sub_epi16(b, c);
6539
6540         /* (p-b) == (a+b-c - b) == (a-c) */
6541         pb = _mm_sub_epi16(a, c);
6542
6543         /* (p-c) == (a+b-c - c) == (a+b-c-c) == (b-c)+(a-c) */
6544         pc = _mm_add_epi16(pa, pb);
6545
6546         pa = abs_i16(pa);  /* |p-a| */
6547         pb = abs_i16(pb);  /* |p-b| */
6548         pc = abs_i16(pc);  /* |p-c| */
6549
6550         smallest = _mm_min_epi16(pc, _mm_min_epi16(pa, pb));
6551
6552         /* Paeth breaks ties favoring a over b over c. */
6553         nearest  = if_then_else(_mm_cmpeq_epi16(smallest, pa), a,
6554                             if_then_else(_mm_cmpeq_epi16(smallest, pb), b, c));
6555
6556         /* Note `_epi8`: we need addition to wrap modulo 255. */
6557         d = _mm_add_epi8(d, nearest);
6558         store4(row, _mm_packus_epi16(d, d));
6559
6560         prev += 4;
6561         row  += 4;
6562         rb   -= 4;
6563     }
6564 }
6565
6566 #endif /* SPNG_X86 */
6567
6568
6569 #if defined(SPNG_ARM)
6570
6571 /* NEON optimised filter functions
6572  * Derived from filter_neon_intrinsics.c
6573  *
6574  * Copyright (c) 2018 Cosmin Truta
6575  * Copyright (c) 2014,2016 Glenn Randers-Pehrson
6576  * Written by James Yu <james.yu at linaro.org>, October 2013.
6577  * Based on filter_neon.S, written by Mans Rullgard, 2011.
6578  *
6579  * This code is derived from libpng source code.
6580  * For conditions of distribution and use, see the disclaimer
6581  * and license in this file.
6582  */
6583
6584 #define png_aligncast(type, value) ((void*)(value))
6585 #define png_aligncastconst(type, value) ((const void*)(value))
6586
6587 /* libpng row pointers are not necessarily aligned to any particular boundary,
6588  * however this code will only work with appropriate alignment. mips/mips_init.c
6589  * checks for this (and will not compile unless it is done). This code uses
6590  * variants of png_aligncast to avoid compiler warnings.
6591  */
6592 #define png_ptr(type,pointer) png_aligncast(type *,pointer)
6593 #define png_ptrc(type,pointer) png_aligncastconst(const type *,pointer)
6594
6595 /* The following relies on a variable 'temp_pointer' being declared with type
6596  * 'type'.  This is written this way just to hide the GCC strict aliasing
6597  * warning; note that the code is safe because there never is an alias between
6598  * the input and output pointers.
6599  */
6600 #define png_ldr(type,pointer)\
6601    (temp_pointer = png_ptr(type,pointer), *temp_pointer)
6602
6603
6604 #if defined(_MSC_VER) && !defined(__clang__) && defined(_M_ARM64)
6605     #include <arm64_neon.h>
6606 #else
6607     #include <arm_neon.h>
6608 #endif
6609
6610 static void defilter_sub3(size_t rowbytes, unsigned char *row)
6611 {
6612     unsigned char *rp = row;
6613     unsigned char *rp_stop = row + rowbytes;
6614
6615     uint8x16_t vtmp = vld1q_u8(rp);
6616     uint8x8x2_t *vrpt = png_ptr(uint8x8x2_t, &vtmp);
6617     uint8x8x2_t vrp = *vrpt;
6618
6619     uint8x8x4_t vdest;
6620     vdest.val[3] = vdup_n_u8(0);
6621
6622     for (; rp < rp_stop;)
6623     {
6624         uint8x8_t vtmp1, vtmp2;
6625         uint32x2_t *temp_pointer;
6626
6627         vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 3);
6628         vdest.val[0] = vadd_u8(vdest.val[3], vrp.val[0]);
6629         vtmp2 = vext_u8(vrp.val[0], vrp.val[1], 6);
6630         vdest.val[1] = vadd_u8(vdest.val[0], vtmp1);
6631
6632         vtmp1 = vext_u8(vrp.val[1], vrp.val[1], 1);
6633         vdest.val[2] = vadd_u8(vdest.val[1], vtmp2);
6634         vdest.val[3] = vadd_u8(vdest.val[2], vtmp1);
6635
6636         vtmp = vld1q_u8(rp + 12);
6637         vrpt = png_ptr(uint8x8x2_t, &vtmp);
6638         vrp = *vrpt;
6639
6640         vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[0]), 0);
6641         rp += 3;
6642         vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[1]), 0);
6643         rp += 3;
6644         vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[2]), 0);
6645         rp += 3;
6646         vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[3]), 0);
6647         rp += 3;
6648     }
6649 }
6650
6651 static void defilter_sub4(size_t rowbytes, unsigned char *row)
6652 {
6653     unsigned char *rp = row;
6654     unsigned char *rp_stop = row + rowbytes;
6655
6656     uint8x8x4_t vdest;
6657     vdest.val[3] = vdup_n_u8(0);
6658
6659     for (; rp < rp_stop; rp += 16)
6660     {
6661         uint32x2x4_t vtmp = vld4_u32(png_ptr(uint32_t,rp));
6662         uint8x8x4_t *vrpt = png_ptr(uint8x8x4_t,&vtmp);
6663         uint8x8x4_t vrp = *vrpt;
6664         uint32x2x4_t *temp_pointer;
6665         uint32x2x4_t vdest_val;
6666
6667         vdest.val[0] = vadd_u8(vdest.val[3], vrp.val[0]);
6668         vdest.val[1] = vadd_u8(vdest.val[0], vrp.val[1]);
6669         vdest.val[2] = vadd_u8(vdest.val[1], vrp.val[2]);
6670         vdest.val[3] = vadd_u8(vdest.val[2], vrp.val[3]);
6671
6672         vdest_val = png_ldr(uint32x2x4_t, &vdest);
6673         vst4_lane_u32(png_ptr(uint32_t,rp), vdest_val, 0);
6674     }
6675 }
6676
6677 static void defilter_avg3(size_t rowbytes, unsigned char *row, const unsigned char *prev_row)
6678 {
6679     unsigned char *rp = row;
6680     const unsigned char *pp = prev_row;
6681     unsigned char *rp_stop = row + rowbytes;
6682
6683     uint8x16_t vtmp;
6684     uint8x8x2_t *vrpt;
6685     uint8x8x2_t vrp;
6686     uint8x8x4_t vdest;
6687     vdest.val[3] = vdup_n_u8(0);
6688
6689     vtmp = vld1q_u8(rp);
6690     vrpt = png_ptr(uint8x8x2_t,&vtmp);
6691     vrp = *vrpt;
6692
6693     for (; rp < rp_stop; pp += 12)
6694     {
6695         uint8x8_t vtmp1, vtmp2, vtmp3;
6696
6697         uint8x8x2_t *vppt;
6698         uint8x8x2_t vpp;
6699
6700         uint32x2_t *temp_pointer;
6701
6702         vtmp = vld1q_u8(pp);
6703         vppt = png_ptr(uint8x8x2_t,&vtmp);
6704         vpp = *vppt;
6705
6706         vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 3);
6707         vdest.val[0] = vhadd_u8(vdest.val[3], vpp.val[0]);
6708         vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]);
6709
6710         vtmp2 = vext_u8(vpp.val[0], vpp.val[1], 3);
6711         vtmp3 = vext_u8(vrp.val[0], vrp.val[1], 6);
6712         vdest.val[1] = vhadd_u8(vdest.val[0], vtmp2);
6713         vdest.val[1] = vadd_u8(vdest.val[1], vtmp1);
6714
6715         vtmp2 = vext_u8(vpp.val[0], vpp.val[1], 6);
6716         vtmp1 = vext_u8(vrp.val[1], vrp.val[1], 1);
6717
6718         vtmp = vld1q_u8(rp + 12);
6719         vrpt = png_ptr(uint8x8x2_t,&vtmp);
6720         vrp = *vrpt;
6721
6722         vdest.val[2] = vhadd_u8(vdest.val[1], vtmp2);
6723         vdest.val[2] = vadd_u8(vdest.val[2], vtmp3);
6724
6725         vtmp2 = vext_u8(vpp.val[1], vpp.val[1], 1);
6726
6727         vdest.val[3] = vhadd_u8(vdest.val[2], vtmp2);
6728         vdest.val[3] = vadd_u8(vdest.val[3], vtmp1);
6729
6730         vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[0]), 0);
6731         rp += 3;
6732         vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[1]), 0);
6733         rp += 3;
6734         vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[2]), 0);
6735         rp += 3;
6736         vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[3]), 0);
6737         rp += 3;
6738     }
6739 }
6740
6741 static void defilter_avg4(size_t rowbytes, unsigned char *row, const unsigned char *prev_row)
6742 {
6743     unsigned char *rp = row;
6744     unsigned char *rp_stop = row + rowbytes;
6745     const unsigned char *pp = prev_row;
6746
6747     uint8x8x4_t vdest;
6748     vdest.val[3] = vdup_n_u8(0);
6749
6750     for (; rp < rp_stop; rp += 16, pp += 16)
6751     {
6752         uint32x2x4_t vtmp;
6753         uint8x8x4_t *vrpt, *vppt;
6754         uint8x8x4_t vrp, vpp;
6755         uint32x2x4_t *temp_pointer;
6756         uint32x2x4_t vdest_val;
6757
6758         vtmp = vld4_u32(png_ptr(uint32_t,rp));
6759         vrpt = png_ptr(uint8x8x4_t,&vtmp);
6760         vrp = *vrpt;
6761         vtmp = vld4_u32(png_ptrc(uint32_t,pp));
6762         vppt = png_ptr(uint8x8x4_t,&vtmp);
6763         vpp = *vppt;
6764
6765         vdest.val[0] = vhadd_u8(vdest.val[3], vpp.val[0]);
6766         vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]);
6767         vdest.val[1] = vhadd_u8(vdest.val[0], vpp.val[1]);
6768         vdest.val[1] = vadd_u8(vdest.val[1], vrp.val[1]);
6769         vdest.val[2] = vhadd_u8(vdest.val[1], vpp.val[2]);
6770         vdest.val[2] = vadd_u8(vdest.val[2], vrp.val[2]);
6771         vdest.val[3] = vhadd_u8(vdest.val[2], vpp.val[3]);
6772         vdest.val[3] = vadd_u8(vdest.val[3], vrp.val[3]);
6773
6774         vdest_val = png_ldr(uint32x2x4_t, &vdest);
6775         vst4_lane_u32(png_ptr(uint32_t,rp), vdest_val, 0);
6776     }
6777 }
6778
6779 static uint8x8_t paeth_arm(uint8x8_t a, uint8x8_t b, uint8x8_t c)
6780 {
6781     uint8x8_t d, e;
6782     uint16x8_t p1, pa, pb, pc;
6783
6784     p1 = vaddl_u8(a, b); /* a + b */
6785     pc = vaddl_u8(c, c); /* c * 2 */
6786     pa = vabdl_u8(b, c); /* pa */
6787     pb = vabdl_u8(a, c); /* pb */
6788     pc = vabdq_u16(p1, pc); /* pc */
6789
6790     p1 = vcleq_u16(pa, pb); /* pa <= pb */
6791     pa = vcleq_u16(pa, pc); /* pa <= pc */
6792     pb = vcleq_u16(pb, pc); /* pb <= pc */
6793
6794     p1 = vandq_u16(p1, pa); /* pa <= pb && pa <= pc */
6795
6796     d = vmovn_u16(pb);
6797     e = vmovn_u16(p1);
6798
6799     d = vbsl_u8(d, b, c);
6800     e = vbsl_u8(e, a, d);
6801
6802     return e;
6803 }
6804
6805 static void defilter_paeth3(size_t rowbytes, unsigned char *row, const unsigned char *prev_row)
6806 {
6807     unsigned char *rp = row;
6808     const unsigned char *pp = prev_row;
6809     unsigned char *rp_stop = row + rowbytes;
6810
6811     uint8x16_t vtmp;
6812     uint8x8x2_t *vrpt;
6813     uint8x8x2_t vrp;
6814     uint8x8_t vlast = vdup_n_u8(0);
6815     uint8x8x4_t vdest;
6816     vdest.val[3] = vdup_n_u8(0);
6817
6818     vtmp = vld1q_u8(rp);
6819     vrpt = png_ptr(uint8x8x2_t,&vtmp);
6820     vrp = *vrpt;
6821
6822     for (; rp < rp_stop; pp += 12)
6823     {
6824         uint8x8x2_t *vppt;
6825         uint8x8x2_t vpp;
6826         uint8x8_t vtmp1, vtmp2, vtmp3;
6827         uint32x2_t *temp_pointer;
6828
6829         vtmp = vld1q_u8(pp);
6830         vppt = png_ptr(uint8x8x2_t,&vtmp);
6831         vpp = *vppt;
6832
6833         vdest.val[0] = paeth_arm(vdest.val[3], vpp.val[0], vlast);
6834         vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]);
6835
6836         vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 3);
6837         vtmp2 = vext_u8(vpp.val[0], vpp.val[1], 3);
6838         vdest.val[1] = paeth_arm(vdest.val[0], vtmp2, vpp.val[0]);
6839         vdest.val[1] = vadd_u8(vdest.val[1], vtmp1);
6840
6841         vtmp1 = vext_u8(vrp.val[0], vrp.val[1], 6);
6842         vtmp3 = vext_u8(vpp.val[0], vpp.val[1], 6);
6843         vdest.val[2] = paeth_arm(vdest.val[1], vtmp3, vtmp2);
6844         vdest.val[2] = vadd_u8(vdest.val[2], vtmp1);
6845
6846         vtmp1 = vext_u8(vrp.val[1], vrp.val[1], 1);
6847         vtmp2 = vext_u8(vpp.val[1], vpp.val[1], 1);
6848
6849         vtmp = vld1q_u8(rp + 12);
6850         vrpt = png_ptr(uint8x8x2_t,&vtmp);
6851         vrp = *vrpt;
6852
6853         vdest.val[3] = paeth_arm(vdest.val[2], vtmp2, vtmp3);
6854         vdest.val[3] = vadd_u8(vdest.val[3], vtmp1);
6855
6856         vlast = vtmp2;
6857
6858         vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[0]), 0);
6859         rp += 3;
6860         vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[1]), 0);
6861         rp += 3;
6862         vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[2]), 0);
6863         rp += 3;
6864         vst1_lane_u32(png_ptr(uint32_t,rp), png_ldr(uint32x2_t,&vdest.val[3]), 0);
6865         rp += 3;
6866     }
6867 }
6868
6869 static void defilter_paeth4(size_t rowbytes, unsigned char *row, const unsigned char *prev_row)
6870 {
6871     unsigned char *rp = row;
6872     unsigned char *rp_stop = row + rowbytes;
6873     const unsigned char *pp = prev_row;
6874
6875     uint8x8_t vlast = vdup_n_u8(0);
6876     uint8x8x4_t vdest;
6877     vdest.val[3] = vdup_n_u8(0);
6878
6879     for (; rp < rp_stop; rp += 16, pp += 16)
6880     {
6881         uint32x2x4_t vtmp;
6882         uint8x8x4_t *vrpt, *vppt;
6883         uint8x8x4_t vrp, vpp;
6884         uint32x2x4_t *temp_pointer;
6885         uint32x2x4_t vdest_val;
6886
6887         vtmp = vld4_u32(png_ptr(uint32_t,rp));
6888         vrpt = png_ptr(uint8x8x4_t,&vtmp);
6889         vrp = *vrpt;
6890         vtmp = vld4_u32(png_ptrc(uint32_t,pp));
6891         vppt = png_ptr(uint8x8x4_t,&vtmp);
6892         vpp = *vppt;
6893
6894         vdest.val[0] = paeth_arm(vdest.val[3], vpp.val[0], vlast);
6895         vdest.val[0] = vadd_u8(vdest.val[0], vrp.val[0]);
6896         vdest.val[1] = paeth_arm(vdest.val[0], vpp.val[1], vpp.val[0]);
6897         vdest.val[1] = vadd_u8(vdest.val[1], vrp.val[1]);
6898         vdest.val[2] = paeth_arm(vdest.val[1], vpp.val[2], vpp.val[1]);
6899         vdest.val[2] = vadd_u8(vdest.val[2], vrp.val[2]);
6900         vdest.val[3] = paeth_arm(vdest.val[2], vpp.val[3], vpp.val[2]);
6901         vdest.val[3] = vadd_u8(vdest.val[3], vrp.val[3]);
6902
6903         vlast = vpp.val[3];
6904
6905         vdest_val = png_ldr(uint32x2x4_t, &vdest);
6906         vst4_lane_u32(png_ptr(uint32_t,rp), vdest_val, 0);
6907     }
6908 }
6909
6910 /* NEON optimised palette expansion functions
6911  * Derived from palette_neon_intrinsics.c
6912  *
6913  * Copyright (c) 2018-2019 Cosmin Truta
6914  * Copyright (c) 2017-2018 Arm Holdings. All rights reserved.
6915  * Written by Richard Townsend <Richard.Townsend@arm.com>, February 2017.
6916  *
6917  * This code is derived from libpng source code.
6918  * For conditions of distribution and use, see the disclaimer
6919  * and license in this file.
6920  *
6921  * Related: https://developer.arm.com/documentation/101964/latest/Color-palette-expansion
6922  *
6923  * The functions were refactored to iterate forward.
6924  *
6925  */
6926
6927 /* Expands a palettized row into RGBA8. */
6928 static uint32_t expand_palette_rgba8_neon(unsigned char *row, const unsigned char *scanline, const unsigned char *plte, uint32_t width)
6929 {
6930     const uint32_t scanline_stride = 4;
6931     const uint32_t row_stride = scanline_stride * 4;
6932     const uint32_t count = width / scanline_stride;
6933     const uint32_t *palette = (const uint32_t*)plte;
6934
6935     if(!count) return 0;
6936
6937     uint32_t i;
6938     uint32x4_t cur;
6939     for(i=0; i < count; i++, scanline += scanline_stride)
6940     {
6941         cur = vld1q_dup_u32 (palette + scanline[0]);
6942         cur = vld1q_lane_u32(palette + scanline[1], cur, 1);
6943         cur = vld1q_lane_u32(palette + scanline[2], cur, 2);
6944         cur = vld1q_lane_u32(palette + scanline[3], cur, 3);
6945         vst1q_u32((uint32_t*)(row + i * row_stride), cur);
6946     }
6947
6948     return count * scanline_stride;
6949 }
6950
6951 /* Expands a palettized row into RGB8. */
6952 static uint32_t expand_palette_rgb8_neon(unsigned char *row, const unsigned char *scanline, const unsigned char *plte, uint32_t width)
6953 {
6954     const uint32_t scanline_stride = 8;
6955     const uint32_t row_stride = scanline_stride * 3;
6956     const uint32_t count = width / scanline_stride;
6957
6958     if(!count) return 0;
6959
6960     uint32_t i;
6961     uint8x8x3_t cur;
6962     for(i=0; i < count; i++, scanline += scanline_stride)
6963     {
6964         cur = vld3_dup_u8 (plte + 3 * scanline[0]);
6965         cur = vld3_lane_u8(plte + 3 * scanline[1], cur, 1);
6966         cur = vld3_lane_u8(plte + 3 * scanline[2], cur, 2);
6967         cur = vld3_lane_u8(plte + 3 * scanline[3], cur, 3);
6968         cur = vld3_lane_u8(plte + 3 * scanline[4], cur, 4);
6969         cur = vld3_lane_u8(plte + 3 * scanline[5], cur, 5);
6970         cur = vld3_lane_u8(plte + 3 * scanline[6], cur, 6);
6971         cur = vld3_lane_u8(plte + 3 * scanline[7], cur, 7);
6972         vst3_u8(row + i * row_stride, cur);
6973     }
6974
6975     return count * scanline_stride;
6976 }
6977
6978 #endif /* SPNG_ARM */