Coverage Report

Created: 2026-08-13 07:24

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