Coverage Report

Created: 2026-07-30 06:41

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