The optimized encoder and decoder in C. One file, tables and all, every function static inline, and byte for byte the same output as the reference — download, 29596 bytes, 697 lines.
#ifndef BNG_FAST_H
#define BNG_FAST_H
#include <stddef.h>
#include <stdint.h>
#include <string.h>
#if defined(__SSE2__)
#include <emmintrin.h>
#endif
#define TDIR 63
#define KEXP 6
#define ALPHA 144
#define TOK_EOL (2 * TDIR + 1 + 2 * (8 - KEXP))
#define TOK_RUN (TOK_EOL + 1)
#define MAXCODE 12
#define MAXCODE_MASK ((1u << MAXCODE) - 1)
#define PIC_MAX_PIXELS (1u << 28)
#define P4_MAGIC "\xFF\x0E\x38\x30\x2A\x1A\x18"
#define P4_VERSION 0x01
#define P4_HEADER 20
#define P4_RAW_FLAG 0x80000000u
#define P4_COUNT_MASK 0x7FFFFFFFu
#define BNG_MAX_ENCODED(w, h) ((size_t)P4_HEADER + 4 * (size_t)(w) * (size_t)(h))
#define P4_B 0
#define P4_G 1
#define P4_R 2
#define P4_X 3
typedef struct {
int16_t base;
uint8_t len;
uint8_t nbits;
uint8_t kind;
uint8_t pad[3];
} Dec_Entry;
static const uint32_t mask_lut[13] = {
0u, 1u, 3u, 7u, 15u, 31u, 63u, 127u, 255u, 511u, 1023u, 2047u, 4095u,
};
static const uint32_t ecl[ALPHA] = {
196608u, 196609u, 196610u, 262150u, 262151u, 262152u, 262153u, 327702u,
327703u, 393264u, 393265u, 393266u, 393267u, 458858u, 458859u, 458860u,
458861u, 458862u, 458863u, 524518u, 524519u, 524520u, 524521u, 524522u,
524523u, 524524u, 524525u, 590302u, 590303u, 590304u, 590305u, 590306u,
590307u, 590308u, 590309u, 590310u, 590311u, 656340u, 656341u, 656342u,
656343u, 656344u, 656345u, 656346u, 656347u, 656348u, 656349u, 656350u,
656351u, 656352u, 656353u, 656354u, 656355u, 722892u, 722893u, 722894u,
722895u, 722896u, 722897u, 722898u, 722899u, 722900u, 722901u, 722902u,
722903u, 722904u, 722905u, 722906u, 722907u, 722908u, 722909u, 722910u,
722911u, 790470u, 790471u, 790472u, 790473u, 790474u, 790475u, 790476u,
790477u, 790478u, 790479u, 790480u, 790481u, 790482u, 790483u, 790484u,
790485u, 790486u, 790487u, 790488u, 790489u, 790490u, 790491u, 790492u,
790493u, 790494u, 790495u, 790496u, 790497u, 790498u, 790499u, 790500u,
790501u, 790502u, 790503u, 790504u, 790505u, 790506u, 790507u, 790508u,
790509u, 790510u, 790511u, 790512u, 790513u, 790514u, 790515u, 790516u,
790517u, 790518u, 790519u, 790520u, 790521u, 722912u, 790522u, 458864u,
458865u, 790523u, 722913u, 590312u, 262154u, 393268u, 458866u, 524526u,
590313u, 656356u, 656357u, 722914u, 790524u, 790525u, 790526u, 790527u,
};
static const uint8_t exp_of[256] = {
0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
};
static const Dec_Entry dtab[256] = {
{0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}},
{0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}},
{0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}},
{0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}},
{0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}},
{0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}},
{0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}},
{0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}}, {0,3,0,0,{0,0,0}},
{1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}},
{1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}},
{1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}},
{1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}},
{1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}},
{1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}},
{1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}},
{1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}}, {1,3,0,0,{0,0,0}},
{1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}},
{1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}},
{1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}},
{1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}},
{1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}},
{1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}},
{1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}},
{1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}}, {1,3,0,1,{0,0,0}},
{2,4,0,0,{0,0,0}}, {2,4,0,0,{0,0,0}}, {2,4,0,0,{0,0,0}}, {2,4,0,0,{0,0,0}},
{2,4,0,0,{0,0,0}}, {2,4,0,0,{0,0,0}}, {2,4,0,0,{0,0,0}}, {2,4,0,0,{0,0,0}},
{2,4,0,0,{0,0,0}}, {2,4,0,0,{0,0,0}}, {2,4,0,0,{0,0,0}}, {2,4,0,0,{0,0,0}},
{2,4,0,0,{0,0,0}}, {2,4,0,0,{0,0,0}}, {2,4,0,0,{0,0,0}}, {2,4,0,0,{0,0,0}},
{2,4,0,1,{0,0,0}}, {2,4,0,1,{0,0,0}}, {2,4,0,1,{0,0,0}}, {2,4,0,1,{0,0,0}},
{2,4,0,1,{0,0,0}}, {2,4,0,1,{0,0,0}}, {2,4,0,1,{0,0,0}}, {2,4,0,1,{0,0,0}},
{2,4,0,1,{0,0,0}}, {2,4,0,1,{0,0,0}}, {2,4,0,1,{0,0,0}}, {2,4,0,1,{0,0,0}},
{2,4,0,1,{0,0,0}}, {2,4,0,1,{0,0,0}}, {2,4,0,1,{0,0,0}}, {2,4,0,1,{0,0,0}},
{3,4,0,0,{0,0,0}}, {3,4,0,0,{0,0,0}}, {3,4,0,0,{0,0,0}}, {3,4,0,0,{0,0,0}},
{3,4,0,0,{0,0,0}}, {3,4,0,0,{0,0,0}}, {3,4,0,0,{0,0,0}}, {3,4,0,0,{0,0,0}},
{3,4,0,0,{0,0,0}}, {3,4,0,0,{0,0,0}}, {3,4,0,0,{0,0,0}}, {3,4,0,0,{0,0,0}},
{3,4,0,0,{0,0,0}}, {3,4,0,0,{0,0,0}}, {3,4,0,0,{0,0,0}}, {3,4,0,0,{0,0,0}},
{3,4,0,1,{0,0,0}}, {3,4,0,1,{0,0,0}}, {3,4,0,1,{0,0,0}}, {3,4,0,1,{0,0,0}},
{3,4,0,1,{0,0,0}}, {3,4,0,1,{0,0,0}}, {3,4,0,1,{0,0,0}}, {3,4,0,1,{0,0,0}},
{3,4,0,1,{0,0,0}}, {3,4,0,1,{0,0,0}}, {3,4,0,1,{0,0,0}}, {3,4,0,1,{0,0,0}},
{3,4,0,1,{0,0,0}}, {3,4,0,1,{0,0,0}}, {3,4,0,1,{0,0,0}}, {3,4,0,1,{0,0,0}},
{2,4,1,3,{0,0,0}}, {2,4,1,3,{0,0,0}}, {2,4,1,3,{0,0,0}}, {2,4,1,3,{0,0,0}},
{2,4,1,3,{0,0,0}}, {2,4,1,3,{0,0,0}}, {2,4,1,3,{0,0,0}}, {2,4,1,3,{0,0,0}},
{2,4,1,3,{0,0,0}}, {2,4,1,3,{0,0,0}}, {2,4,1,3,{0,0,0}}, {2,4,1,3,{0,0,0}},
{2,4,1,3,{0,0,0}}, {2,4,1,3,{0,0,0}}, {2,4,1,3,{0,0,0}}, {2,4,1,3,{0,0,0}},
{4,5,0,0,{0,0,0}}, {4,5,0,0,{0,0,0}}, {4,5,0,0,{0,0,0}}, {4,5,0,0,{0,0,0}},
{4,5,0,0,{0,0,0}}, {4,5,0,0,{0,0,0}}, {4,5,0,0,{0,0,0}}, {4,5,0,0,{0,0,0}},
{4,5,0,1,{0,0,0}}, {4,5,0,1,{0,0,0}}, {4,5,0,1,{0,0,0}}, {4,5,0,1,{0,0,0}},
{4,5,0,1,{0,0,0}}, {4,5,0,1,{0,0,0}}, {4,5,0,1,{0,0,0}}, {4,5,0,1,{0,0,0}},
{5,6,0,0,{0,0,0}}, {5,6,0,0,{0,0,0}}, {5,6,0,0,{0,0,0}}, {5,6,0,0,{0,0,0}},
{5,6,0,1,{0,0,0}}, {5,6,0,1,{0,0,0}}, {5,6,0,1,{0,0,0}}, {5,6,0,1,{0,0,0}},
{6,6,0,0,{0,0,0}}, {6,6,0,0,{0,0,0}}, {6,6,0,0,{0,0,0}}, {6,6,0,0,{0,0,0}},
{6,6,0,1,{0,0,0}}, {6,6,0,1,{0,0,0}}, {6,6,0,1,{0,0,0}}, {6,6,0,1,{0,0,0}},
{4,6,2,3,{0,0,0}}, {4,6,2,3,{0,0,0}}, {4,6,2,3,{0,0,0}}, {4,6,2,3,{0,0,0}},
{7,7,0,0,{0,0,0}}, {7,7,0,0,{0,0,0}}, {7,7,0,1,{0,0,0}}, {7,7,0,1,{0,0,0}},
{8,7,0,0,{0,0,0}}, {8,7,0,0,{0,0,0}}, {8,7,0,1,{0,0,0}}, {8,7,0,1,{0,0,0}},
{9,7,0,0,{0,0,0}}, {9,7,0,0,{0,0,0}}, {9,7,0,1,{0,0,0}}, {9,7,0,1,{0,0,0}},
{64,7,6,0,{0,0,0}}, {64,7,6,0,{0,0,0}}, {64,7,6,1,{0,0,0}}, {64,7,6,1,{0,0,0}},
{8,7,3,3,{0,0,0}}, {8,7,3,3,{0,0,0}}, {10,8,0,0,{0,0,0}}, {10,8,0,1,{0,0,0}},
{11,8,0,0,{0,0,0}}, {11,8,0,1,{0,0,0}}, {12,8,0,0,{0,0,0}}, {12,8,0,1,{0,0,0}},
{13,8,0,0,{0,0,0}}, {13,8,0,1,{0,0,0}}, {16,8,4,3,{0,0,0}}, {0,0,0,0,{0,0,0}},
{1,0,0,0,{0,0,0}}, {2,0,0,1,{0,0,0}}, {3,0,0,0,{0,0,0}}, {4,0,0,1,{0,0,0}},
{16,0,0,1,{0,0,0}}, {5,0,0,0,{0,0,0}}, {6,0,0,1,{0,0,0}}, {7,0,0,0,{0,0,0}},
{8,0,0,1,{0,0,0}}, {9,0,0,0,{0,0,0}}, {10,0,0,1,{0,0,0}}, {11,0,0,0,{0,0,0}},
{12,0,0,1,{0,0,0}}, {13,0,0,0,{0,0,0}}, {14,0,0,1,{0,0,0}}, {15,0,0,0,{0,0,0}},
};
static const Dec_Entry dsub[272] = {
{14,9,0,0,{0,0,0}}, {14,9,0,0,{0,0,0}}, {14,9,0,0,{0,0,0}}, {14,9,0,0,{0,0,0}},
{14,9,0,0,{0,0,0}}, {14,9,0,0,{0,0,0}}, {14,9,0,0,{0,0,0}}, {14,9,0,0,{0,0,0}},
{14,9,0,1,{0,0,0}}, {14,9,0,1,{0,0,0}}, {14,9,0,1,{0,0,0}}, {14,9,0,1,{0,0,0}},
{14,9,0,1,{0,0,0}}, {14,9,0,1,{0,0,0}}, {14,9,0,1,{0,0,0}}, {14,9,0,1,{0,0,0}},
{15,9,0,0,{0,0,0}}, {15,9,0,0,{0,0,0}}, {15,9,0,0,{0,0,0}}, {15,9,0,0,{0,0,0}},
{15,9,0,0,{0,0,0}}, {15,9,0,0,{0,0,0}}, {15,9,0,0,{0,0,0}}, {15,9,0,0,{0,0,0}},
{15,9,0,1,{0,0,0}}, {15,9,0,1,{0,0,0}}, {15,9,0,1,{0,0,0}}, {15,9,0,1,{0,0,0}},
{15,9,0,1,{0,0,0}}, {15,9,0,1,{0,0,0}}, {15,9,0,1,{0,0,0}}, {15,9,0,1,{0,0,0}},
{16,9,0,0,{0,0,0}}, {16,9,0,0,{0,0,0}}, {16,9,0,0,{0,0,0}}, {16,9,0,0,{0,0,0}},
{16,9,0,0,{0,0,0}}, {16,9,0,0,{0,0,0}}, {16,9,0,0,{0,0,0}}, {16,9,0,0,{0,0,0}},
{16,9,0,1,{0,0,0}}, {16,9,0,1,{0,0,0}}, {16,9,0,1,{0,0,0}}, {16,9,0,1,{0,0,0}},
{16,9,0,1,{0,0,0}}, {16,9,0,1,{0,0,0}}, {16,9,0,1,{0,0,0}}, {16,9,0,1,{0,0,0}},
{17,9,0,0,{0,0,0}}, {17,9,0,0,{0,0,0}}, {17,9,0,0,{0,0,0}}, {17,9,0,0,{0,0,0}},
{17,9,0,0,{0,0,0}}, {17,9,0,0,{0,0,0}}, {17,9,0,0,{0,0,0}}, {17,9,0,0,{0,0,0}},
{17,9,0,1,{0,0,0}}, {17,9,0,1,{0,0,0}}, {17,9,0,1,{0,0,0}}, {17,9,0,1,{0,0,0}},
{17,9,0,1,{0,0,0}}, {17,9,0,1,{0,0,0}}, {17,9,0,1,{0,0,0}}, {17,9,0,1,{0,0,0}},
{18,9,0,0,{0,0,0}}, {18,9,0,0,{0,0,0}}, {18,9,0,0,{0,0,0}}, {18,9,0,0,{0,0,0}},
{18,9,0,0,{0,0,0}}, {18,9,0,0,{0,0,0}}, {18,9,0,0,{0,0,0}}, {18,9,0,0,{0,0,0}},
{18,9,0,1,{0,0,0}}, {18,9,0,1,{0,0,0}}, {18,9,0,1,{0,0,0}}, {18,9,0,1,{0,0,0}},
{18,9,0,1,{0,0,0}}, {18,9,0,1,{0,0,0}}, {18,9,0,1,{0,0,0}}, {18,9,0,1,{0,0,0}},
{19,10,0,0,{0,0,0}}, {19,10,0,0,{0,0,0}}, {19,10,0,0,{0,0,0}}, {19,10,0,0,{0,0,0}},
{19,10,0,1,{0,0,0}}, {19,10,0,1,{0,0,0}}, {19,10,0,1,{0,0,0}}, {19,10,0,1,{0,0,0}},
{20,10,0,0,{0,0,0}}, {20,10,0,0,{0,0,0}}, {20,10,0,0,{0,0,0}}, {20,10,0,0,{0,0,0}},
{20,10,0,1,{0,0,0}}, {20,10,0,1,{0,0,0}}, {20,10,0,1,{0,0,0}}, {20,10,0,1,{0,0,0}},
{21,10,0,0,{0,0,0}}, {21,10,0,0,{0,0,0}}, {21,10,0,0,{0,0,0}}, {21,10,0,0,{0,0,0}},
{21,10,0,1,{0,0,0}}, {21,10,0,1,{0,0,0}}, {21,10,0,1,{0,0,0}}, {21,10,0,1,{0,0,0}},
{22,10,0,0,{0,0,0}}, {22,10,0,0,{0,0,0}}, {22,10,0,0,{0,0,0}}, {22,10,0,0,{0,0,0}},
{22,10,0,1,{0,0,0}}, {22,10,0,1,{0,0,0}}, {22,10,0,1,{0,0,0}}, {22,10,0,1,{0,0,0}},
{23,10,0,0,{0,0,0}}, {23,10,0,0,{0,0,0}}, {23,10,0,0,{0,0,0}}, {23,10,0,0,{0,0,0}},
{23,10,0,1,{0,0,0}}, {23,10,0,1,{0,0,0}}, {23,10,0,1,{0,0,0}}, {23,10,0,1,{0,0,0}},
{24,10,0,0,{0,0,0}}, {24,10,0,0,{0,0,0}}, {24,10,0,0,{0,0,0}}, {24,10,0,0,{0,0,0}},
{24,10,0,1,{0,0,0}}, {24,10,0,1,{0,0,0}}, {24,10,0,1,{0,0,0}}, {24,10,0,1,{0,0,0}},
{25,10,0,0,{0,0,0}}, {25,10,0,0,{0,0,0}}, {25,10,0,0,{0,0,0}}, {25,10,0,0,{0,0,0}},
{25,10,0,1,{0,0,0}}, {25,10,0,1,{0,0,0}}, {25,10,0,1,{0,0,0}}, {25,10,0,1,{0,0,0}},
{26,10,0,0,{0,0,0}}, {26,10,0,0,{0,0,0}}, {26,10,0,0,{0,0,0}}, {26,10,0,0,{0,0,0}},
{26,10,0,1,{0,0,0}}, {26,10,0,1,{0,0,0}}, {26,10,0,1,{0,0,0}}, {26,10,0,1,{0,0,0}},
{64,10,6,3,{0,0,0}}, {64,10,6,3,{0,0,0}}, {64,10,6,3,{0,0,0}}, {64,10,6,3,{0,0,0}},
{128,10,7,3,{0,0,0}}, {128,10,7,3,{0,0,0}}, {128,10,7,3,{0,0,0}}, {128,10,7,3,{0,0,0}},
{27,11,0,0,{0,0,0}}, {27,11,0,0,{0,0,0}}, {27,11,0,1,{0,0,0}}, {27,11,0,1,{0,0,0}},
{28,11,0,0,{0,0,0}}, {28,11,0,0,{0,0,0}}, {28,11,0,1,{0,0,0}}, {28,11,0,1,{0,0,0}},
{29,11,0,0,{0,0,0}}, {29,11,0,0,{0,0,0}}, {29,11,0,1,{0,0,0}}, {29,11,0,1,{0,0,0}},
{30,11,0,0,{0,0,0}}, {30,11,0,0,{0,0,0}}, {30,11,0,1,{0,0,0}}, {30,11,0,1,{0,0,0}},
{31,11,0,0,{0,0,0}}, {31,11,0,0,{0,0,0}}, {31,11,0,1,{0,0,0}}, {31,11,0,1,{0,0,0}},
{32,11,0,0,{0,0,0}}, {32,11,0,0,{0,0,0}}, {32,11,0,1,{0,0,0}}, {32,11,0,1,{0,0,0}},
{33,11,0,0,{0,0,0}}, {33,11,0,0,{0,0,0}}, {33,11,0,1,{0,0,0}}, {33,11,0,1,{0,0,0}},
{34,11,0,0,{0,0,0}}, {34,11,0,0,{0,0,0}}, {34,11,0,1,{0,0,0}}, {34,11,0,1,{0,0,0}},
{35,11,0,0,{0,0,0}}, {35,11,0,0,{0,0,0}}, {35,11,0,1,{0,0,0}}, {35,11,0,1,{0,0,0}},
{36,11,0,0,{0,0,0}}, {36,11,0,0,{0,0,0}}, {36,11,0,1,{0,0,0}}, {36,11,0,1,{0,0,0}},
{63,11,0,0,{0,0,0}}, {63,11,0,0,{0,0,0}}, {128,11,7,1,{0,0,0}}, {128,11,7,1,{0,0,0}},
{256,11,8,3,{0,0,0}}, {256,11,8,3,{0,0,0}}, {37,12,0,0,{0,0,0}}, {37,12,0,1,{0,0,0}},
{38,12,0,0,{0,0,0}}, {38,12,0,1,{0,0,0}}, {39,12,0,0,{0,0,0}}, {39,12,0,1,{0,0,0}},
{40,12,0,0,{0,0,0}}, {40,12,0,1,{0,0,0}}, {41,12,0,0,{0,0,0}}, {41,12,0,1,{0,0,0}},
{42,12,0,0,{0,0,0}}, {42,12,0,1,{0,0,0}}, {43,12,0,0,{0,0,0}}, {43,12,0,1,{0,0,0}},
{44,12,0,0,{0,0,0}}, {44,12,0,1,{0,0,0}}, {45,12,0,0,{0,0,0}}, {45,12,0,1,{0,0,0}},
{46,12,0,0,{0,0,0}}, {46,12,0,1,{0,0,0}}, {47,12,0,0,{0,0,0}}, {47,12,0,1,{0,0,0}},
{48,12,0,0,{0,0,0}}, {48,12,0,1,{0,0,0}}, {49,12,0,0,{0,0,0}}, {49,12,0,1,{0,0,0}},
{50,12,0,0,{0,0,0}}, {50,12,0,1,{0,0,0}}, {51,12,0,0,{0,0,0}}, {51,12,0,1,{0,0,0}},
{52,12,0,0,{0,0,0}}, {52,12,0,1,{0,0,0}}, {53,12,0,0,{0,0,0}}, {53,12,0,1,{0,0,0}},
{54,12,0,0,{0,0,0}}, {54,12,0,1,{0,0,0}}, {55,12,0,0,{0,0,0}}, {55,12,0,1,{0,0,0}},
{56,12,0,0,{0,0,0}}, {56,12,0,1,{0,0,0}}, {57,12,0,0,{0,0,0}}, {57,12,0,1,{0,0,0}},
{58,12,0,0,{0,0,0}}, {58,12,0,1,{0,0,0}}, {59,12,0,0,{0,0,0}}, {59,12,0,1,{0,0,0}},
{60,12,0,0,{0,0,0}}, {60,12,0,1,{0,0,0}}, {61,12,0,0,{0,0,0}}, {61,12,0,1,{0,0,0}},
{62,12,0,0,{0,0,0}}, {62,12,0,1,{0,0,0}}, {63,12,0,1,{0,0,0}}, {128,12,7,0,{0,0,0}},
{512,12,9,3,{0,0,0}}, {1024,12,10,3,{0,0,0}}, {2048,12,11,3,{0,0,0}}, {4096,12,12,3,{0,0,0}},
{8192,9,0,2,{0,0,0}}, {8192,9,0,2,{0,0,0}}, {8192,9,0,2,{0,0,0}}, {8192,9,0,2,{0,0,0}},
{8192,9,0,2,{0,0,0}}, {8192,9,0,2,{0,0,0}}, {8192,9,0,2,{0,0,0}}, {8192,9,0,2,{0,0,0}},
{32,9,5,3,{0,0,0}}, {32,9,5,3,{0,0,0}}, {32,9,5,3,{0,0,0}}, {32,9,5,3,{0,0,0}},
{32,9,5,3,{0,0,0}}, {32,9,5,3,{0,0,0}}, {32,9,5,3,{0,0,0}}, {32,9,5,3,{0,0,0}},
};
static inline int med(int L, int T, int TL) {
int mn = L < T ? L : T, mx = L > T ? L : T;
int g = L + T - TL;
g = g < mn ? mn : g;
return g > mx ? mx : g;
}
static inline void to_ycocg(uint8_t *y, uint8_t *co, uint8_t *cg, int R, int G,
int B) {
int c = (R - B) & 0xFF;
int t = (B + ((int8_t)c >> 1)) & 0xFF;
int g = (G - t) & 0xFF;
*co = (uint8_t)c;
*cg = (uint8_t)g;
*y = (uint8_t)((t + ((int8_t)g >> 1)) & 0xFF);
}
#if defined(__SSE2__)
static __attribute__((noinline)) void ycocg_row_rgba(const uint8_t *Y, const uint8_t *Co,
const uint8_t *Cg, const uint8_t *A, uint8_t *out,
int w_) {
const __m128i m7f = _mm_set1_epi8(0x7f);
const __m128i m80 = _mm_set1_epi8((char)0x80);
int x = 0;
for (; x + 16 <= w_; x += 16) {
__m128i y = _mm_loadu_si128((const __m128i *)(Y + x));
__m128i co = _mm_loadu_si128((const __m128i *)(Co + x));
__m128i cg = _mm_loadu_si128((const __m128i *)(Cg + x));
__m128i a = _mm_loadu_si128((const __m128i *)(A + x));
__m128i cgs = _mm_or_si128(_mm_and_si128(_mm_srli_epi16(cg, 1), m7f),
_mm_and_si128(cg, m80));
__m128i t = _mm_sub_epi8(y, cgs);
__m128i g = _mm_add_epi8(cg, t);
__m128i cos = _mm_or_si128(_mm_and_si128(_mm_srli_epi16(co, 1), m7f),
_mm_and_si128(co, m80));
__m128i b = _mm_sub_epi8(t, cos);
__m128i r = _mm_add_epi8(b, co);
__m128i rg0 = _mm_unpacklo_epi8(b, g);
__m128i rg1 = _mm_unpackhi_epi8(b, g);
__m128i ba0 = _mm_unpacklo_epi8(r, a);
__m128i ba1 = _mm_unpackhi_epi8(r, a);
_mm_storeu_si128((__m128i *)(out + x * 4 + 0),
_mm_unpacklo_epi16(rg0, ba0));
_mm_storeu_si128((__m128i *)(out + x * 4 + 16),
_mm_unpackhi_epi16(rg0, ba0));
_mm_storeu_si128((__m128i *)(out + x * 4 + 32),
_mm_unpacklo_epi16(rg1, ba1));
_mm_storeu_si128((__m128i *)(out + x * 4 + 48),
_mm_unpackhi_epi16(rg1, ba1));
}
for (; x < w_; x++) {
int t = (Y[x] - ((int8_t)Cg[x] >> 1)) & 0xFF;
int g = (Cg[x] + t) & 0xFF;
int b = (t - ((int8_t)Co[x] >> 1)) & 0xFF;
out[x * 4 + P4_R] = (uint8_t)((b + Co[x]) & 0xFF);
out[x * 4 + P4_G] = (uint8_t)g;
out[x * 4 + P4_B] = (uint8_t)b;
out[x * 4 + P4_X] = A[x];
}
}
#endif
#if !defined(__SSE2__)
static inline void from_ycocg(int y, int co, int cg, uint8_t *R, uint8_t *G,
uint8_t *B) {
int t = (y - ((int8_t)cg >> 1)) & 0xFF;
int g = (cg + t) & 0xFF;
int b = (t - ((int8_t)co >> 1)) & 0xFF;
*R = (uint8_t)((b + co) & 0xFF);
*G = (uint8_t)g;
*B = (uint8_t)b;
}
#endif
typedef struct {
uint8_t *buf;
size_t cap, n;
uint64_t acc;
int nbits;
int overflow;
} Bit_Writer;
static inline void bw_flush(Bit_Writer *w) {
while (w->nbits >= 8) {
w->nbits -= 8;
if (w->n < w->cap) w->buf[w->n] = (uint8_t)(w->acc >> w->nbits);
else w->overflow = 1;
w->n++;
}
if (w->nbits) {
if (w->n < w->cap) w->buf[w->n] = (uint8_t)(w->acc << (8 - w->nbits));
else w->overflow = 1;
w->n++;
w->nbits = 0;
}
}
typedef struct {
const uint8_t *p, *end;
uint64_t acc;
int nbits;
int pad;
int bad;
} Bit_Reader;
static __attribute__((noinline)) void encode_row(Bit_Writer *w,
const int8_t *rc, int w_) {
uint8_t *buf = w->buf;
size_t cap = w->cap, n = w->n;
uint64_t acc = w->acc;
int nbits = w->nbits, ovf = w->overflow;
int x = 0;
#define PUTC(cl_) \
do { \
uint32_t p_ = (cl_); \
PUT(p_ & 0xFFFF, (int)(p_ >> 16)); \
} while (0)
#define PUT(code_, len_) \
do { \
acc = (acc << (len_)) | (uint64_t)(code_); \
nbits += (len_); \
if (nbits >= 32) { \
uint32_t v_ = __builtin_bswap32((uint32_t)(acc >> (nbits - 32))); \
\
if (n + 4 <= cap) memcpy(buf + n, &v_, 4); \
else ovf = 1; \
n += 4; \
nbits -= 32; \
} \
} while (0)
while (x < w_) {
int e = rc[x];
if (e) {
int a = e < 0 ? -e : e, tk;
if (a <= TDIR) {
tk = 2 * a - 1 + (e < 0);
PUTC(ecl[tk]);
} else {
int ex = exp_of[a];
tk = 2 * TDIR + 1 + 2 * (ex - KEXP) + (e < 0);
PUTC(ecl[tk]);
PUT((uint32_t)(a - (1 << ex)), ex);
}
x++;
continue;
}
{
int i = x + 1, run, j = 0;
while (i + 8 <= w_) {
uint64_t v;
memcpy(&v, rc + i, 8);
if (v) {
i += __builtin_ctzll(v) >> 3;
break;
}
i += 8;
}
while (i < w_ && rc[i] == 0) i++;
run = i - x;
if (x + run == w_) {
PUTC(ecl[TOK_EOL]);
x = w_;
continue;
}
if (run == 1) {
PUTC(ecl[0]);
x++;
continue;
}
if (run > 8191) run = 8191;
while (run >> (j + 1)) j++;
PUTC(ecl[TOK_RUN + j - 1]);
PUT((uint32_t)(run - (1 << j)), j);
x += run;
}
}
#undef PUT
#undef PUTC
w->n = n;
w->acc = acc;
w->nbits = nbits;
w->overflow = ovf;
}
#define BINBLK 64
static __attribute__((noinline)) int unpack_row(Bit_Reader *r, int8_t *rc,
int w_) {
const uint8_t *p = r->p, *end = r->end;
uint64_t acc = r->acc;
int nbits = r->nbits, pad = r->pad;
int x = 0, ok = 1;
memset(rc, 0, (size_t)w_);
while (x < w_) {
uint32_t idx, m;
Dec_Entry d;
if (nbits < 32) {
if (p + 8 <= end) {
int take = (64 - nbits) >> 3;
uint64_t v;
memcpy(&v, p, 8);
v = __builtin_bswap64(v);
acc |= v >> nbits;
p += take;
nbits += take << 3;
} else {
while (nbits <= 56) {
uint64_t b = 0;
if (p < end) {
b = *p++;
} else if (++pad > 16) {
ok = 0;
break;
}
acc |= b << (56 - nbits);
nbits += 8;
}
if (!ok) break;
}
}
idx = (uint32_t)(acc >> 52);
d = dtab[idx >> 4];
if (!d.len) {
d = dsub[(size_t)d.base * 16 + (idx & 15)];
if (!d.len) { ok = 0; break; }
}
acc <<= d.len;
nbits -= (int)d.len;
m = (uint32_t)(((acc >> 32) >> (32 - d.nbits)) & mask_lut[d.nbits]);
acc <<= d.nbits;
nbits -= (int)d.nbits;
{
int v = d.base + (int)m;
int isrun = d.kind >> 1;
int neg = d.kind & 1;
int adv, rem = w_ - x;
int val = neg ? -v : v;
val = isrun ? 0 : val;
adv = isrun ? v : 1;
if (adv > rem) adv = rem;
if (adv <= 0) { ok = 0; break; }
rc[x] = (int8_t)val;
x += adv;
}
}
r->p = p;
r->acc = acc;
r->nbits = nbits;
r->pad = pad;
if (!ok) r->bad = 1;
return ok;
}
static __attribute__((noinline)) void reconstruct_row4(uint8_t *cur[4], const uint8_t *prv[4],
const int8_t *rc[4], int w_, int y) {
if (!y) {
for (int p = 0; p < 4; p++) {
int acc = 0;
for (int x = 0; x < w_; x++) {
acc = (acc + rc[p][x]) & 0xFF;
cur[p][x] = (uint8_t)acc;
}
}
return;
}
for (int p = 0; p < 4; p++)
cur[p][0] = (uint8_t)((prv[p][0] + rc[p][0]) & 0xFF);
for (int x = 1; x < w_; x++) {
#define REC(P_) \
do { \
int T_ = prv[P_][x], L_ = cur[P_][x - 1], TL_ = prv[P_][x - 1]; \
int mn_ = L_ < T_ ? L_ : T_; \
int mx_ = L_ > T_ ? L_ : T_; \
int g_ = L_ + T_ - TL_; \
g_ = g_ < mn_ ? mn_ : g_; \
g_ = g_ > mx_ ? mx_ : g_; \
cur[P_][x] = (uint8_t)((g_ + rc[P_][x]) & 0xFF); \
} while (0)
REC(0);
REC(1);
REC(2);
REC(3);
#undef REC
}
}
static inline void put32(uint8_t *p, uint32_t v) {
p[0] = (uint8_t)v;
p[1] = (uint8_t)(v >> 8);
p[2] = (uint8_t)(v >> 16);
p[3] = (uint8_t)(v >> 24);
}
static inline uint32_t get32(const uint8_t *p) {
return (uint32_t)p[0] | ((uint32_t)p[1] << 8) | ((uint32_t)p[2] << 16) |
((uint32_t)p[3] << 24);
}
static inline size_t bng_encode_scratch(int w, int h) {
(void)h;
return 12 * (size_t)w + 64;
}
static inline size_t bng_decode_scratch(int w, int h) {
(void)h;
return 16 * (size_t)w + 64;
}
static inline int bng_info(const uint8_t *file, size_t len, int *w, int *h) {
if (len < P4_HEADER || memcmp(file, P4_MAGIC, 7)) return 0;
if (file[7] != P4_VERSION) return 0;
*w = (int)get32(file + 8);
*h = (int)get32(file + 12);
if (*w <= 0 || *h <= 0) return 0;
if ((uint64_t)*w * (uint64_t)*h > PIC_MAX_PIXELS) return 0;
return 1;
}
static inline size_t pic_encode_body(const uint8_t *px, int w, int h, size_t pitch,
uint8_t *buf, size_t cap, uint8_t *scratch) {
Bit_Writer w4;
uint8_t *sbuf = scratch;
int8_t *rbuf = (int8_t *)(scratch + (size_t)w * 8 + 32);
uint8_t *cur[4], *prv[4];
memset(&w4, 0, sizeof w4);
w4.buf = buf;
w4.cap = cap;
for (int pl = 0; pl < 4; pl++) {
cur[pl] = sbuf + (size_t)pl * w;
prv[pl] = sbuf + (size_t)(pl + 4) * w;
}
{
for (int y = 0; y < h; y++) {
const uint8_t *src = px + (size_t)y * pitch;
for (int x = 0; x < w; x++) {
to_ycocg(&cur[0][x], &cur[1][x], &cur[2][x], src[x * 4 + P4_R],
src[x * 4 + P4_G], src[x * 4 + P4_B]);
cur[3][x] = src[x * 4 + P4_X];
}
for (int pl = 0; pl < 4; pl++) {
const uint8_t *row = cur[pl], *prev = prv[pl];
int8_t *rr = rbuf + (size_t)pl * w;
if (!y) {
rr[0] = (int8_t)row[0];
for (int x = 1; x < w; x++)
rr[x] = (int8_t)((row[x] - row[x - 1]) & 0xFF);
} else {
rr[0] = (int8_t)((row[0] - prev[0]) & 0xFF);
for (int x = 1; x < w; x++)
rr[x] = (int8_t)((row[x] - med(row[x - 1], prev[x],
prev[x - 1])) &
0xFF);
}
}
for (int pl = 0; pl < 4; pl++)
encode_row(&w4, rbuf + (size_t)pl * w, w);
for (int pl = 0; pl < 4; pl++) {
uint8_t *t = cur[pl];
cur[pl] = prv[pl];
prv[pl] = t;
}
}
}
bw_flush(&w4);
return w4.n;
}
static inline size_t bng_encode(const uint8_t *px, int w, int h, size_t pitch, uint8_t *out,
size_t out_cap, void *scratch, size_t scratch_len) {
size_t n = (size_t)w * (size_t)h;
size_t raw_bytes = 4 * n;
size_t got;
if (w <= 0 || h <= 0) return 0;
if (pitch < (size_t)w * 4) return 0;
if (out_cap < P4_HEADER + raw_bytes) return 0;
if (scratch_len < bng_encode_scratch(w, h)) return 0;
got = pic_encode_body(px, w, h, pitch, out + P4_HEADER, raw_bytes,
(uint8_t *)scratch);
memcpy(out, P4_MAGIC, 7);
out[7] = P4_VERSION;
put32(out + 8, (uint32_t)w);
put32(out + 12, (uint32_t)h);
if (got >= raw_bytes) {
for (int y = 0; y < h; y++)
memcpy(out + P4_HEADER + (size_t)y * w * 4, px + (size_t)y * pitch,
(size_t)w * 4);
put32(out + 16, (uint32_t)(raw_bytes | P4_RAW_FLAG));
return P4_HEADER + raw_bytes;
}
put32(out + 16, (uint32_t)got);
return P4_HEADER + got;
}
static inline int bng_decode(const uint8_t *file, size_t len, uint8_t *out, size_t out_pitch,
size_t out_cap, void *scratch, size_t scratch_len) {
int w, h, raw;
size_t n, stream_byte_count;
Bit_Reader r;
uint8_t *sp = (uint8_t *)scratch;
if (!bng_info(file, len, &w, &h)) return 0;
n = (size_t)w * (size_t)h;
{
uint32_t field = get32(file + 16);
raw = (field & P4_RAW_FLAG) != 0;
stream_byte_count = field & P4_COUNT_MASK;
}
if (stream_byte_count > len - P4_HEADER) return 0;
len = P4_HEADER + stream_byte_count;
if (out_pitch < (size_t)w * 4) return 0;
if (out_cap < (size_t)(h - 1) * out_pitch + (size_t)w * 4) return 0;
if (raw) {
if (stream_byte_count != 4 * n) return 0;
for (int y = 0; y < h; y++)
memcpy(out + (size_t)y * out_pitch,
file + P4_HEADER + (size_t)y * w * 4, (size_t)w * 4);
return 1;
}
if (scratch_len < bng_decode_scratch(w, h)) return 0;
if ((uint64_t)stream_byte_count * 8 < (uint64_t)h) return 0;
memset(&r, 0, sizeof r);
r.p = file + P4_HEADER;
r.end = file + len;
{
int8_t *rbuf = (int8_t *)sp;
uint8_t *sbuf = sp + (size_t)w * 8 + 32;
int8_t *rc[4], *rp[4];
uint8_t *cur[4], *prv[4];
int fail = 0;
for (int p = 0; p < 4; p++) {
rc[p] = rbuf + (size_t)p * w;
rp[p] = rbuf + (size_t)(p + 4) * w;
cur[p] = sbuf + (size_t)p * w;
prv[p] = sbuf + (size_t)(p + 4) * w;
}
memset(rbuf, 0, (size_t)w * 8);
memset(sbuf, 0, (size_t)w * 8);
for (int y = 0; y < h && !fail; y++) {
uint8_t *o = out + (size_t)y * out_pitch;
for (int p = 0; p < 4; p++)
if (!unpack_row(&r, rc[p], w)) {
fail = 1;
break;
}
if (fail) break;
reconstruct_row4(cur, (const uint8_t **)prv, (const int8_t **)rc, w,
y);
#if defined(__SSE2__)
ycocg_row_rgba(cur[0], cur[1], cur[2], cur[3], o, w);
#else
for (int x = 0; x < w; x++) {
from_ycocg(cur[0][x], cur[1][x], cur[2][x], &o[x * 4 + P4_R],
&o[x * 4 + P4_G], &o[x * 4 + P4_B]);
o[x * 4 + P4_X] = cur[3][x];
}
#endif
for (int p = 0; p < 4; p++) {
int8_t *t = rc[p];
uint8_t *u = cur[p];
rc[p] = rp[p];
rp[p] = t;
cur[p] = prv[p];
prv[p] = u;
}
}
if (fail) return 0;
}
return 1;
}
#endif