Coverage Report

Created: 2026-04-12 06:04

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