summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorPatrick Georgi <patrick@coreboot.org>2023-10-06 20:19:15 +0200
committerFelix Held <felix-coreboot@felixheld.de>2023-12-13 16:17:34 +0000
commit1d029b40c9deca792ccc5820293d3bc8f8b8a2a4 (patch)
tree8936e4f3aeb4d8c0beed486bb3d7de62d858a373 /src/lib
parent54662610197d7304b48d8e85a5b13263db3357f2 (diff)
lib/jpeg: Replace decoder with Wuffs' implementation
To quote its repo[0]: Wuffs is a memory-safe programming language (and a standard library written in that language) for Wrangling Untrusted File Formats Safely. Wrangling includes parsing, decoding and encoding. It compiles its library, written in its own language, to a C/C++ source file that can then be used independently without needing support for the language. That library is now imported to src/vendorcode/wuffs/. This change modifies our linters to ignore that directory because it's supposed to contain the wuffs compiler's result verbatim. Nigel Tao provided an initial wrapper around wuffs' jpeg decoder that implements our JPEG API. I further changed it a bit regarding data placement, dropped stuff from our API that wasn't ever used, or isn't used anymore, and generally made it fit coreboot a bit better. Features are Nigel's, bugs are mine. This commit also adapts our jpeg fuzz test to work with the modified API. After limiting it to deal only with approximately screen sized inputs, it fuzzed for 25 hours CPU time without a single hang or crash. This is a notable improvement over running the test with our old decoder which crashes within a minute. Finally, I tried the new parser with a pretty-much-random JPEG file I got from the internet, and it just showed it (once the resolution matched), which is also a notable improvement over the old decoder which is very particular about the subset of JPEG it supports. In terms of code size, a QEmu build's ramstage increases from 128060 bytes decompressed (64121 bytes after LZMA) to 172304 bytes decompressed (82734 bytes after LZMA). [0] https://github.com/google/wuffs Change-Id: If8fa7da69da1ad412f27c2c5e882393c7739bc82 Signed-off-by: Patrick Georgi <patrick@coreboot.org> Based-on-work-by: Nigel Tao <nigeltao@golang.org> Reviewed-on: https://review.coreboot.org/c/coreboot/+/78271 Reviewed-by: Paul Menzel <paulepanter@mailbox.org> Reviewed-by: Martin L Roth <gaumless@gmail.com> Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/bootsplash.c28
-rw-r--r--src/lib/jpeg.c1047
-rw-r--r--src/lib/jpeg.h36
3 files changed, 110 insertions, 1001 deletions
diff --git a/src/lib/bootsplash.c b/src/lib/bootsplash.c
index 3ab11aca6f..0512770668 100644
--- a/src/lib/bootsplash.c
+++ b/src/lib/bootsplash.c
@@ -14,34 +14,40 @@ void set_bootsplash(unsigned char *framebuffer, unsigned int x_resolution,
unsigned int y_resolution, unsigned int bytes_per_line,
unsigned int fb_resolution)
{
+ if ((x_resolution > INT_MAX) || (y_resolution) > INT_MAX) {
+ printk(BIOS_ERR, "Display resolution way too large.\n");
+ return;
+ }
+ int xres = x_resolution, yres = y_resolution;
printk(BIOS_INFO, "Setting up bootsplash in %dx%d@%d\n", x_resolution, y_resolution,
fb_resolution);
- struct jpeg_decdata *decdata;
- unsigned char *jpeg = cbfs_map("bootsplash.jpg", NULL);
+ size_t filesize;
+ unsigned char *jpeg = cbfs_map("bootsplash.jpg", &filesize);
if (!jpeg) {
printk(BIOS_ERR, "Could not find bootsplash.jpg\n");
return;
}
- int image_width, image_height;
- jpeg_fetch_size(jpeg, &image_width, &image_height);
+ unsigned int image_width, image_height;
+ if (jpeg_fetch_size(jpeg, filesize, &image_width, &image_height) != 0) {
+ printk(BIOS_ERR, "Could not parse bootsplash.jpg\n");
+ return;
+ }
printk(BIOS_DEBUG, "Bootsplash image resolution: %dx%d\n", image_width, image_height);
- if (image_width > x_resolution || image_height > y_resolution) {
+ if (image_width > xres || image_height > yres) {
printk(BIOS_NOTICE, "Bootsplash image can't fit framebuffer.\n");
cbfs_unmap(jpeg);
return;
}
/* center image: */
- framebuffer += (y_resolution - image_height) / 2 * bytes_per_line +
- (x_resolution - image_width) / 2 * (fb_resolution / 8);
+ framebuffer += (yres - image_height) / 2 * bytes_per_line
+ + (xres - image_width) / 2 * (fb_resolution / 8);
- decdata = malloc(sizeof(*decdata));
- int ret = jpeg_decode(jpeg, framebuffer, image_width, image_height,
- bytes_per_line, fb_resolution, decdata);
- free(decdata);
+ int ret = jpeg_decode(jpeg, filesize, framebuffer, image_width, image_height,
+ bytes_per_line, fb_resolution);
cbfs_unmap(jpeg);
if (ret != 0) {
printk(BIOS_ERR, "Bootsplash could not be decoded. jpeg_decode returned %d.\n",
diff --git a/src/lib/jpeg.c b/src/lib/jpeg.c
index ed4377f41a..242cf0ca8e 100644
--- a/src/lib/jpeg.c
+++ b/src/lib/jpeg.c
@@ -1,1000 +1,125 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
- * a tiny jpeg decoder.
- *
- * written in August 2001 by Michael Schroeder <mls@suse.de>
- *
+ * Provide a simple API around the Wuffs JPEG decoder
+ * Uses the heap (and lots of it) for the image-size specific
+ * work buffer, so ramstage-only.
*/
-#define __LITTLE_ENDIAN
-#include <string.h>
-#include "jpeg.h"
-#define ISHIFT 11
-
-#define IFIX(a) ((int)((a) * (1 << ISHIFT) + .5))
-#define IMULT(a, b) (((a) * (b)) >> ISHIFT)
-#define ITOINT(a) ((a) >> ISHIFT)
-
-#ifndef __P
-# define __P(x) x
-#endif
-
-/* special markers */
-#define M_BADHUFF -1
-#define M_EOF 0x80
-
-struct in {
- unsigned char *p;
- unsigned int bits;
- int left;
- int marker;
-
- int (*func) __P((void *));
- void *data;
-};
-
-/*********************************/
-struct dec_hufftbl;
-struct enc_hufftbl;
-
-union hufftblp {
- struct dec_hufftbl *dhuff;
- struct enc_hufftbl *ehuff;
-};
-
-struct scan {
- int dc; /* old dc value */
-
- union hufftblp hudc;
- union hufftblp huac;
- int next; /* when to switch to next scan */
-
- int cid; /* component id */
- int hv; /* horiz/vert, copied from comp */
- int tq; /* quant tbl, copied from comp */
-};
-
-/*********************************/
-
-#define DECBITS 10 /* seems to be the optimum */
-
-struct dec_hufftbl {
- int maxcode[17];
- int valptr[16];
- unsigned char vals[256];
- unsigned int llvals[1 << DECBITS];
-};
-
-static void decode_mcus __P((struct in *, int *, int, struct scan *, int *));
-static int dec_readmarker __P((struct in *));
-static void dec_makehuff __P((struct dec_hufftbl *, int *, unsigned char *));
-
-static void setinput __P((struct in *, unsigned char *));
-/*********************************/
-
-#undef PREC
-#define PREC int
-
-static void idctqtab __P((unsigned char *, PREC *));
-static void idct __P((int *, int *, PREC *, PREC, int));
-static void scaleidctqtab __P((PREC *, PREC));
-
-/*********************************/
-
-static void initcol __P((PREC[][64]));
+#include <stdint.h>
-static void col221111 __P((int *, unsigned char *, int));
-static void col221111_16 __P((int *, unsigned char *, int));
-static void col221111_32 __P((int *, unsigned char *, int));
-
-/*********************************/
-
-#define M_SOI 0xd8
-#define M_APP0 0xe0
-#define M_DQT 0xdb
-#define M_SOF0 0xc0
-#define M_DHT 0xc4
-#define M_DRI 0xdd
-#define M_SOS 0xda
-#define M_RST0 0xd0
-#define M_EOI 0xd9
-#define M_COM 0xfe
-
-static unsigned char *datap;
-
-static int getbyte(void)
-{
- return *datap++;
-}
-
-static int getword(void)
-{
- int c1, c2;
- c1 = *datap++;
- c2 = *datap++;
- return c1 << 8 | c2;
-}
-
-struct comp {
- int cid;
- int hv;
- int tq;
-};
-
-#define MAXCOMP 4
-struct jpginfo {
- int nc; /* number of components */
- int ns; /* number of scans */
- int dri; /* restart interval */
- int nm; /* mcus til next marker */
- int rm; /* next restart marker */
-};
-
-static struct jpginfo info;
-static struct comp comps[MAXCOMP];
-
-static struct scan dscans[MAXCOMP];
-
-static unsigned char quant[4][64];
-
-static struct dec_hufftbl dhuff[4];
+#include "jpeg.h"
-#define dec_huffdc (dhuff + 0)
-#define dec_huffac (dhuff + 2)
+#define WUFFS_CONFIG__AVOID_CPU_ARCH
+#define WUFFS_CONFIG__MODULES
+#define WUFFS_CONFIG__MODULE__BASE
+#define WUFFS_CONFIG__MODULE__JPEG
+#define WUFFS_CONFIG__STATIC_FUNCTIONS
+#define WUFFS_IMPLEMENTATION
+#include "../vendorcode/wuffs/wuffs-v0.4.c"
-static struct in glob_in;
+/* ~16K is big enough to move this off the stack */
+static wuffs_jpeg__decoder dec;
-static int readtables(int till)
+int jpeg_fetch_size(unsigned char *filedata, size_t filesize, unsigned int *width,
+ unsigned int *height)
{
- int m, l, i, j, lq, pq, tq;
- int tc, th, tt;
-
- for (;;) {
- if (getbyte() != 0xff)
- return -1;
- m = getbyte();
- if (m == till)
- break;
-
- switch (m) {
- case 0xc2:
- return 0;
-
- case M_DQT:
- lq = getword();
- while (lq > 2) {
- pq = getbyte();
- tq = pq & 15;
- if (tq > 3)
- return -1;
- pq >>= 4;
- if (pq != 0)
- return -1;
- for (i = 0; i < 64; i++)
- quant[tq][i] = getbyte();
- lq -= 64 + 1;
- }
- break;
-
- case M_DHT:
- l = getword();
- while (l > 2) {
- int hufflen[16], k;
- unsigned char huffvals[256];
-
- tc = getbyte();
- th = tc & 15;
- tc >>= 4;
- tt = tc * 2 + th;
- if (tc > 1 || th > 1)
- return -1;
- for (i = 0; i < 16; i++)
- hufflen[i] = getbyte();
- l -= 1 + 16;
- k = 0;
- for (i = 0; i < 16; i++) {
- for (j = 0; j < hufflen[i]; j++)
- huffvals[k++] = getbyte();
- l -= hufflen[i];
- }
- dec_makehuff(dhuff + tt, hufflen,
- huffvals);
- }
- break;
-
- case M_DRI:
- l = getword();
- info.dri = getword();
- break;
-
- default:
- l = getword();
- while (l-- > 2)
- getbyte();
- break;
- }
+ if (!width || !height) {
+ return JPEG_DECODE_FAILED;
}
- return 0;
-}
-
-static void dec_initscans(void)
-{
- int i;
-
- info.nm = info.dri + 1;
- info.rm = M_RST0;
- for (i = 0; i < info.ns; i++)
- dscans[i].dc = 0;
-}
-static int dec_checkmarker(void)
-{
- int i;
-
- if (dec_readmarker(&glob_in) != info.rm)
- return -1;
- info.nm = info.dri;
- info.rm = (info.rm + 1) & ~0x08;
- for (i = 0; i < info.ns; i++)
- dscans[i].dc = 0;
- return 0;
-}
-
-void jpeg_fetch_size(unsigned char *buf, int *width, int *height)
-{
- datap = buf;
- getbyte();
- getbyte();
- readtables(M_SOF0);
- getword();
- getbyte();
- *height = getword();
- *width = getword();
-}
-
-int jpeg_check_size(unsigned char *buf, int width, int height)
-{
- datap = buf;
- getbyte();
- getbyte();
- readtables(M_SOF0);
- getword();
- getbyte();
- if (height != getword() || width != getword())
- return 0;
- return 1;
-}
-
-int jpeg_decode(unsigned char *buf, unsigned char *pic,
- int width, int height, int bytes_per_line, int depth,
- struct jpeg_decdata *decdata)
-{
- int i, j, m, tac, tdc;
- int mcusx, mcusy, mx, my;
- int max[6];
-
- if (!decdata || !buf || !pic)
- return -1;
- datap = buf;
- if (getbyte() != 0xff)
- return ERR_NO_SOI;
- if (getbyte() != M_SOI)
- return ERR_NO_SOI;
- if (readtables(M_SOF0))
- return ERR_BAD_TABLES;
- getword();
- i = getbyte();
- if (i != 8)
- return ERR_NOT_8BIT;
- if (((getword() + 15) & ~15) != height)
- return ERR_HEIGHT_MISMATCH;
- if (((getword() + 15) & ~15) != width)
- return ERR_WIDTH_MISMATCH;
- if ((height & 15) || (width & 15))
- return ERR_BAD_WIDTH_OR_HEIGHT;
- info.nc = getbyte();
- if (info.nc > MAXCOMP)
- return ERR_TOO_MANY_COMPPS;
- for (i = 0; i < info.nc; i++) {
- int h, v;
- comps[i].cid = getbyte();
- comps[i].hv = getbyte();
- v = comps[i].hv & 15;
- h = comps[i].hv >> 4;
- comps[i].tq = getbyte();
- if (h > 3 || v > 3)
- return ERR_ILLEGAL_HV;
- if (comps[i].tq > 3)
- return ERR_QUANT_TABLE_SELECTOR;
+ wuffs_base__status status = wuffs_jpeg__decoder__initialize(
+ &dec, sizeof(dec), WUFFS_VERSION, WUFFS_INITIALIZE__DEFAULT_OPTIONS);
+ if (status.repr) {
+ return JPEG_DECODE_FAILED;
}
- if (readtables(M_SOS))
- return ERR_BAD_TABLES;
- getword();
- info.ns = getbyte();
- if (info.ns != 3)
- return ERR_NOT_YCBCR_221111;
- for (i = 0; i < 3; i++) {
- dscans[i].cid = getbyte();
- tdc = getbyte();
- tac = tdc & 15;
- tdc >>= 4;
- if (tdc > 1 || tac > 1)
- return ERR_QUANT_TABLE_SELECTOR;
- for (j = 0; j < info.nc; j++)
- if (comps[j].cid == dscans[i].cid)
- break;
- if (j == info.nc)
- return ERR_UNKNOWN_CID_IN_SCAN;
- dscans[i].hv = comps[j].hv;
- dscans[i].tq = comps[j].tq;
- dscans[i].hudc.dhuff = dec_huffdc + tdc;
- dscans[i].huac.dhuff = dec_huffac + tac;
- }
-
- i = getbyte();
- j = getbyte();
- m = getbyte();
-
- if (i != 0 || j != 63 || m != 0)
- return ERR_NOT_SEQUENTIAL_DCT;
-
- if (dscans[0].cid != 1 || dscans[1].cid != 2 || dscans[2].cid != 3)
- return ERR_NOT_YCBCR_221111;
-
- if (dscans[0].hv != 0x22 || dscans[1].hv != 0x11
- || dscans[2].hv != 0x11)
- return ERR_NOT_YCBCR_221111;
-
- mcusx = width >> 4;
- mcusy = height >> 4;
-
- idctqtab(quant[dscans[0].tq], decdata->dquant[0]);
- idctqtab(quant[dscans[1].tq], decdata->dquant[1]);
- idctqtab(quant[dscans[2].tq], decdata->dquant[2]);
- initcol(decdata->dquant);
- setinput(&glob_in, datap);
-
- dec_initscans();
-
- dscans[0].next = 6 - 4;
- dscans[1].next = 6 - 4 - 1;
- dscans[2].next = 6 - 4 - 1 - 1; /* 411 encoding */
- for (my = 0; my < mcusy; my++) {
- for (mx = 0; mx < mcusx; mx++) {
- if (info.dri && !--info.nm)
- if (dec_checkmarker())
- return ERR_WRONG_MARKER;
-
- decode_mcus(&glob_in, decdata->dcts, 6, dscans, max);
- idct(decdata->dcts, decdata->out, decdata->dquant[0],
- IFIX(128.5), max[0]);
- idct(decdata->dcts + 64, decdata->out + 64,
- decdata->dquant[0], IFIX(128.5), max[1]);
- idct(decdata->dcts + 128, decdata->out + 128,
- decdata->dquant[0], IFIX(128.5), max[2]);
- idct(decdata->dcts + 192, decdata->out + 192,
- decdata->dquant[0], IFIX(128.5), max[3]);
- idct(decdata->dcts + 256, decdata->out + 256,
- decdata->dquant[1], IFIX(0.5), max[4]);
- idct(decdata->dcts + 320, decdata->out + 320,
- decdata->dquant[2], IFIX(0.5), max[5]);
-
- switch (depth) {
- case 32:
- col221111_32(decdata->out,
- pic + my * 16 * bytes_per_line + mx * 16 * 4,
- bytes_per_line);
- break;
- case 24:
- col221111(decdata->out,
- pic + my * 16 * bytes_per_line + mx * 16 * 3,
- bytes_per_line);
- break;
- case 16:
- col221111_16(decdata->out,
- pic + my * 16 * bytes_per_line + mx * 16 * 2,
- bytes_per_line);
- break;
- default:
- return ERR_DEPTH_MISMATCH;
- }
- }
+ wuffs_base__image_config imgcfg;
+ wuffs_base__io_buffer src = wuffs_base__ptr_u8__reader(filedata, filesize, true);
+ status = wuffs_jpeg__decoder__decode_image_config(&dec, &imgcfg, &src);
+ if (status.repr) {
+ return JPEG_DECODE_FAILED;
}
- m = dec_readmarker(&glob_in);
- if (m != M_EOI)
- return ERR_NO_EOI;
+ *width = wuffs_base__pixel_config__width(&imgcfg.pixcfg);
+ *height = wuffs_base__pixel_config__height(&imgcfg.pixcfg);
return 0;
}
-/****************************************************************/
-/************** huffman decoder ***************/
-/****************************************************************/
-
-static int fillbits __P((struct in *, int, unsigned int));
-static int dec_rec2
-__P((struct in *, struct dec_hufftbl *, int *, int, int));
-
-static void setinput(struct in *in, unsigned char *p)
-{
- in->p = p;
- in->left = 0;
- in->bits = 0;
- in->marker = 0;
-}
-
-static int fillbits(struct in *in, int le, unsigned int bi)
+int jpeg_decode(unsigned char *filedata, size_t filesize, unsigned char *pic,
+ unsigned int width, unsigned int height, unsigned int bytes_per_line,
+ unsigned int depth)
{
- int b, m;
-
- if (in->marker) {
- if (le <= 16)
- in->bits = bi << 16, le += 16;
- return le;
+ if (!filedata || !pic) {
+ return JPEG_DECODE_FAILED;
}
- while (le <= 24) {
- b = *in->p++;
- if (b == 0xff) {
- m = *in->p++;
- if (m != 0) {
- if (m == M_EOF) {
- if (in->func) {
- m = in->func(in->data);
- if (m == 0)
- continue;
- }
- }
- in->marker = m;
- if (le <= 16)
- bi = bi << 16, le += 16;
- break;
- }
- }
- bi = bi << 8 | b;
- le += 8;
+ /* Relatively arbitrary limit that shouldn't hurt anybody.
+ * 300M (10k*10k*3bytes/pixel) is already larger than our heap, so
+ * it's on the safe side.
+ * This avoids overflows when width or height are used for
+ * calculations in this function.
+ */
+ if ((width > 10000) || (height > 10000)) {
+ return JPEG_DECODE_FAILED;
}
- in->bits = bi; /* tmp... 2 return values needed */
- return le;
-}
-
-static int dec_readmarker(struct in *in)
-{
- int m;
-
- in->left = fillbits(in, in->left, in->bits);
- m = in->marker;
- if (m == 0)
- return 0;
- in->left = 0;
- in->marker = 0;
- return m;
-}
-
-#define LEBI_DCL int le, bi
-#define LEBI_GET(in) (le = in->left, bi = in->bits)
-#define LEBI_PUT(in) (in->left = le, in->bits = bi)
-
-#define GETBITS(in, n) ( \
- (le < (n) ? le = fillbits(in, le, bi), bi = in->bits : 0), \
- (le -= (n)), \
- bi >> le & ((1 << (n)) - 1) \
- )
-
-#define UNGETBITS(in, n) ( \
- le += (n) \
-)
-
-static int dec_rec2(struct in *in, struct dec_hufftbl *hu, int *runp, int c,
- int i)
-{
- LEBI_DCL;
-
- LEBI_GET(in);
- if (i) {
- UNGETBITS(in, i & 127);
- *runp = i >> 8 & 15;
- i >>= 16;
- } else {
- for (i = DECBITS; (c = ((c << 1) | GETBITS(in, 1)))
- >= (hu->maxcode[i]); i++)
- ;
- if (i >= 16) {
- in->marker = M_BADHUFF;
- return 0;
- }
- i = hu->vals[hu->valptr[i] + c - hu->maxcode[i - 1] * 2];
- *runp = i >> 4;
- i &= 15;
- }
- if (i == 0) { /* sigh, 0xf0 is 11 bit */
- LEBI_PUT(in);
- return 0;
+ uint32_t pixfmt;
+ switch (depth) {
+ case 16:
+ pixfmt = WUFFS_BASE__PIXEL_FORMAT__BGR_565;
+ break;
+ case 24:
+ pixfmt = WUFFS_BASE__PIXEL_FORMAT__BGR;
+ break;
+ case 32:
+ pixfmt = WUFFS_BASE__PIXEL_FORMAT__BGRA_NONPREMUL;
+ break;
+ default:
+ return JPEG_DECODE_FAILED;
}
- /* receive part */
- c = GETBITS(in, i);
- if (c < (1 << (i - 1)))
- c += (-1 << i) + 1;
- LEBI_PUT(in);
- return c;
-}
-
-#define DEC_REC(in, hu, r, i) ( \
- r = GETBITS(in, DECBITS), \
- i = hu->llvals[r], \
- i & 128 ? \
- ( \
- UNGETBITS(in, i & 127), \
- r = i >> 8 & 15, \
- i >> 16 \
- ) \
- : \
- ( \
- LEBI_PUT(in), \
- i = dec_rec2(in, hu, &r, r, i), \
- LEBI_GET(in), \
- i \
- ) \
-)
-static void decode_mcus(struct in *in, int *dct, int n, struct scan *sc,
- int *maxp)
-{
- struct dec_hufftbl *hu;
- int i, r, t;
- LEBI_DCL;
-
- memset(dct, 0, n * 64 * sizeof(*dct));
- LEBI_GET(in);
- while (n-- > 0) {
- hu = sc->hudc.dhuff;
- *dct++ = (sc->dc += DEC_REC(in, hu, r, t));
-
- hu = sc->huac.dhuff;
- i = 63;
- while (i > 0) {
- t = DEC_REC(in, hu, r, t);
- if (t == 0 && r == 0) {
- dct += i;
- break;
- }
- dct += r;
- *dct++ = t;
- i -= r + 1;
- }
- *maxp++ = 64 - i;
- if (n == sc->next)
- sc++;
+ wuffs_base__status status = wuffs_jpeg__decoder__initialize(
+ &dec, sizeof(dec), WUFFS_VERSION, WUFFS_INITIALIZE__DEFAULT_OPTIONS);
+ if (status.repr) {
+ return JPEG_DECODE_FAILED;
}
- LEBI_PUT(in);
-}
-static void dec_makehuff(struct dec_hufftbl *hu, int *hufflen,
- unsigned char *huffvals)
-{
- int code, k, i, j, d, x, c, v;
- for (i = 0; i < (1 << DECBITS); i++)
- hu->llvals[i] = 0;
-
-/*
- * llvals layout:
- *
- * value v already known, run r, backup u bits:
- * vvvvvvvvvvvvvvvv 0000 rrrr 1 uuuuuuu
- * value unknown, size b bits, run r, backup u bits:
- * 000000000000bbbb 0000 rrrr 0 uuuuuuu
- * value and size unknown:
- * 0000000000000000 0000 0000 0 0000000
- */
- code = 0;
- k = 0;
- for (i = 0; i < 16; i++, code <<= 1) { /* sizes */
- hu->valptr[i] = k;
- for (j = 0; j < hufflen[i]; j++) {
- hu->vals[k] = *huffvals++;
- if (i < DECBITS) {
- c = code << (DECBITS - 1 - i);
- v = hu->vals[k] & 0x0f; /* size */
- for (d = 1 << (DECBITS - 1 - i); --d >= 0;) {
- /* both fit in table */
- if (v + i < DECBITS) {
- x = d >> (DECBITS - 1 - v -
- i);
- if (v && x < (1 << (v - 1)))
- x += (-1 << v) + 1;
- x = x << 16 | (hu->vals[k]
- & 0xf0) << 4 |
- (DECBITS - (i + 1 + v))
- | 128;
- } else
- x = v << 16 | (hu->vals[k]
- & 0xf0) << 4 |
- (DECBITS - (i + 1));
- hu->llvals[c | d] = x;
- }
- }
- code++;
- k++;
- }
- hu->maxcode[i] = code;
+ wuffs_base__image_config imgcfg;
+ wuffs_base__io_buffer src = wuffs_base__ptr_u8__reader(filedata, filesize, true);
+ status = wuffs_jpeg__decoder__decode_image_config(&dec, &imgcfg, &src);
+ if (status.repr) {
+ return JPEG_DECODE_FAILED;
}
- hu->maxcode[16] = 0x20000; /* always terminate decode */
-}
-
-/****************************************************************/
-/************** idct ***************/
-/****************************************************************/
-
-#define ONE ((PREC)IFIX(1.))
-#define S2 ((PREC)IFIX(0.382683432))
-#define C2 ((PREC)IFIX(0.923879532))
-#define C4 ((PREC)IFIX(0.707106781))
-
-#define S22 ((PREC)IFIX(2 * 0.382683432))
-#define C22 ((PREC)IFIX(2 * 0.923879532))
-#define IC4 ((PREC)IFIX(1 / 0.707106781))
-
-#define C3IC1 ((PREC)IFIX(0.847759065)) /* c3/c1 */
-#define C5IC1 ((PREC)IFIX(0.566454497)) /* c5/c1 */
-#define C7IC1 ((PREC)IFIX(0.198912367)) /* c7/c1 */
-
-#define XPP(a, b) (t = a + b, b = a - b, a = t)
-#define XMP(a, b) (t = a - b, b = a + b, a = t)
-#define XPM(a, b) (t = a + b, b = b - a, a = t)
-
-#define ROT(a, b, s, c) (t = IMULT(a + b, s), \
- a = IMULT(a, c - s) + t, \
- b = IMULT(b, c + s) - t)
-#define IDCT \
-( \
- XPP(t0, t1), \
- XMP(t2, t3), \
- t2 = IMULT(t2, IC4) - t3, \
- XPP(t0, t3), \
- XPP(t1, t2), \
- XMP(t4, t7), \
- XPP(t5, t6), \
- XMP(t5, t7), \
- t5 = IMULT(t5, IC4), \
- ROT(t4, t6, S22, C22), \
- t6 -= t7, \
- t5 -= t6, \
- t4 -= t5, \
- XPP(t0, t7), \
- XPP(t1, t6), \
- XPP(t2, t5), \
- XPP(t3, t4) \
-)
+ wuffs_base__pixel_config pixcfg;
+ wuffs_base__pixel_config__set(&pixcfg, pixfmt, 0, width, height);
-static unsigned char zig2[64] = {
- 0, 2, 3, 9, 10, 20, 21, 35,
- 14, 16, 25, 31, 39, 46, 50, 57,
- 5, 7, 12, 18, 23, 33, 37, 48,
- 27, 29, 41, 44, 52, 55, 59, 62,
- 15, 26, 30, 40, 45, 51, 56, 58,
- 1, 4, 8, 11, 19, 22, 34, 36,
- 28, 42, 43, 53, 54, 60, 61, 63,
- 6, 13, 17, 24, 32, 38, 47, 49
-};
-
-void idct(int *in, int *out, PREC *lquant, PREC off, int max)
-{
- PREC t0, t1, t2, t3, t4, t5, t6, t7, t;
- PREC tmp[64], *tmpp;
- int i, j;
- unsigned char *zig2p;
-
- t0 = off;
- if (max == 1) {
- t0 += in[0] * lquant[0];
- for (i = 0; i < 64; i++)
- out[i] = ITOINT(t0);
- return;
- }
- zig2p = zig2;
- tmpp = tmp;
- for (i = 0; i < 8; i++) {
- j = *zig2p++;
- t0 += in[j] * lquant[j];
- j = *zig2p++;
- t5 = in[j] * lquant[j];
- j = *zig2p++;
- t2 = in[j] * lquant[j];
- j = *zig2p++;
- t7 = in[j] * lquant[j];
- j = *zig2p++;
- t1 = in[j] * lquant[j];
- j = *zig2p++;
- t4 = in[j] * lquant[j];
- j = *zig2p++;
- t3 = in[j] * lquant[j];
- j = *zig2p++;
- t6 = in[j] * lquant[j];
- IDCT;
- tmpp[0 * 8] = t0;
- tmpp[1 * 8] = t1;
- tmpp[2 * 8] = t2;
- tmpp[3 * 8] = t3;
- tmpp[4 * 8] = t4;
- tmpp[5 * 8] = t5;
- tmpp[6 * 8] = t6;
- tmpp[7 * 8] = t7;
- tmpp++;
- t0 = 0;
- }
- for (i = 0; i < 8; i++) {
- t0 = tmp[8 * i + 0];
- t1 = tmp[8 * i + 1];
- t2 = tmp[8 * i + 2];
- t3 = tmp[8 * i + 3];
- t4 = tmp[8 * i + 4];
- t5 = tmp[8 * i + 5];
- t6 = tmp[8 * i + 6];
- t7 = tmp[8 * i + 7];
- IDCT;
- out[8 * i + 0] = ITOINT(t0);
- out[8 * i + 1] = ITOINT(t1);
- out[8 * i + 2] = ITOINT(t2);
- out[8 * i + 3] = ITOINT(t3);
- out[8 * i + 4] = ITOINT(t4);
- out[8 * i + 5] = ITOINT(t5);
- out[8 * i + 6] = ITOINT(t6);
- out[8 * i + 7] = ITOINT(t7);
+ wuffs_base__pixel_buffer pixbuf;
+ status = wuffs_base__pixel_buffer__set_interleaved(
+ &pixbuf, &pixcfg,
+ wuffs_base__make_table_u8(pic, width * (depth / 8), height, bytes_per_line),
+ wuffs_base__empty_slice_u8());
+ if (status.repr) {
+ return JPEG_DECODE_FAILED;
}
-}
-
-static unsigned char zig[64] = {
- 0, 1, 5, 6, 14, 15, 27, 28,
- 2, 4, 7, 13, 16, 26, 29, 42,
- 3, 8, 12, 17, 25, 30, 41, 43,
- 9, 11, 18, 24, 31, 40, 44, 53,
- 10, 19, 23, 32, 39, 45, 52, 54,
- 20, 22, 33, 38, 46, 51, 55, 60,
- 21, 34, 37, 47, 50, 56, 59, 61,
- 35, 36, 48, 49, 57, 58, 62, 63
-};
-
-static PREC aaidct[8] = {
- IFIX(0.3535533906), IFIX(0.4903926402),
- IFIX(0.4619397663), IFIX(0.4157348062),
- IFIX(0.3535533906), IFIX(0.2777851165),
- IFIX(0.1913417162), IFIX(0.0975451610)
-};
-
-static void idctqtab(unsigned char *qin, PREC *qout)
-{
- int i, j;
-
- for (i = 0; i < 8; i++)
- for (j = 0; j < 8; j++)
- qout[zig[i * 8 + j]] = qin[zig[i * 8 + j]] *
- IMULT(aaidct[i], aaidct[j]);
-}
-
-static void scaleidctqtab(PREC *q, PREC sc)
-{
- int i;
-
- for (i = 0; i < 64; i++)
- q[i] = IMULT(q[i], sc);
-}
-
-/****************************************************************/
-/************** color decoder ***************/
-/****************************************************************/
-
-#define ROUND
-
-/*
- * YCbCr Color transformation:
- *
- * y:0..255 Cb:-128..127 Cr:-128..127
- *
- * R = Y + 1.40200 * Cr
- * G = Y - 0.34414 * Cb - 0.71414 * Cr
- * B = Y + 1.77200 * Cb
- *
- * =>
- * Cr *= 1.40200;
- * Cb *= 1.77200;
- * Cg = 0.19421 * Cb + .50937 * Cr;
- * R = Y + Cr;
- * G = Y - Cg;
- * B = Y + Cb;
- *
- * =>
- * Cg = (50 * Cb + 130 * Cr + 128) >> 8;
- */
-
-static void initcol(PREC q[][64])
-{
- scaleidctqtab(q[1], IFIX(1.77200));
- scaleidctqtab(q[2], IFIX(1.40200));
-}
-
-/* This is optimized for the stupid sun SUNWspro compiler. */
-#define STORECLAMP(a, x) \
-( \
- (a) = (x), \
- (unsigned int)(x) >= 256 ? \
- ((a) = (x) < 0 ? 0 : 255) \
- : \
- 0 \
-)
-
-#define CLAMP(x) ((unsigned int)(x) >= 256 ? ((x) < 0 ? 0 : 255) : (x))
-
-#ifdef ROUND
-
-#define CBCRCG(yin, xin) \
-( \
- cb = outc[0 + yin * 8 + xin], \
- cr = outc[64 + yin * 8 + xin], \
- cg = (50 * cb + 130 * cr + 128) >> 8 \
-)
-
-#else
-
-#define CBCRCG(yin, xin) \
-( \
- cb = outc[0 + yin*8 + xin], \
- cr = outc[64 + yin*8 + xin], \
- cg = (3 * cb + 8 * cr) >> 4 \
-)
-
-#endif
-
-#define PIC(yin, xin, p, xout) \
-( \
- y = outy[(yin) * 8 + xin], \
- STORECLAMP(p[(xout) * 3 + 0], y + cr), \
- STORECLAMP(p[(xout) * 3 + 1], y - cg), \
- STORECLAMP(p[(xout) * 3 + 2], y + cb) \
-)
-
-#ifdef __LITTLE_ENDIAN
-#define PIC_16(yin, xin, p, xout, add) \
-( \
- y = outy[(yin) * 8 + xin], \
- y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 8) | \
- ((CLAMP(y - cg + add) & 0xfc) << 3) | \
- ((CLAMP(y + cb + add*2+1)) >> 3), \
- p[(xout) * 2 + 0] = y & 0xff, \
- p[(xout) * 2 + 1] = y >> 8 \
-)
-#else
-#ifdef CONFIG_PPC
-#define PIC_16(yin, xin, p, xout, add) \
-( \
- y = outy[(yin) * 8 + xin], \
- y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 7) | \
- ((CLAMP(y - cg + add*2+1) & 0xf8) << 2) | \
- ((CLAMP(y + cb + add*2+1)) >> 3), \
- p[(xout) * 2 + 0] = y >> 8, \
- p[(xout) * 2 + 1] = y & 0xff \
-)
-#else
-#define PIC_16(yin, xin, p, xout, add) \
-( \
- y = outy[(yin) * 8 + xin], \
- y = ((CLAMP(y + cr + add*2+1) & 0xf8) << 8) | \
- ((CLAMP(y - cg + add) & 0xfc) << 3) | \
- ((CLAMP(y + cb + add*2+1)) >> 3), \
- p[(xout) * 2 + 0] = y >> 8, \
- p[(xout) * 2 + 1] = y & 0xff \
-)
-#endif
-#endif
-
-#define PIC_32(yin, xin, p, xout) \
-( \
- y = outy[(yin) * 8 + xin], \
- STORECLAMP(p[(xout) * 4 + 0], y + cr), \
- STORECLAMP(p[(xout) * 4 + 1], y - cg), \
- STORECLAMP(p[(xout) * 4 + 2], y + cb), \
- p[(xout) * 4 + 3] = 0 \
-)
-
-#define PIC221111(xin) \
-( \
- CBCRCG(0, xin), \
- PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0), \
- PIC(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1), \
- PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0), \
- PIC(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1) \
-)
-
-#define PIC221111_16(xin) \
-( \
- CBCRCG(0, xin), \
- PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0, 3), \
- PIC_16(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1, 0), \
- PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0, 1), \
- PIC_16(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1, 2) \
-)
-
-#define PIC221111_32(xin) \
-( \
- CBCRCG(0, xin), \
- PIC_32(xin / 4 * 8 + 0, (xin & 3) * 2 + 0, pic0, xin * 2 + 0), \
- PIC_32(xin / 4 * 8 + 0, (xin & 3) * 2 + 1, pic0, xin * 2 + 1), \
- PIC_32(xin / 4 * 8 + 1, (xin & 3) * 2 + 0, pic1, xin * 2 + 0), \
- PIC_32(xin / 4 * 8 + 1, (xin & 3) * 2 + 1, pic1, xin * 2 + 1) \
-)
-
-static void col221111(int *out, unsigned char *pic, int width)
-{
- int i, j, k;
- unsigned char *pic0, *pic1;
- int *outy, *outc;
- int cr, cg, cb, y;
-
- pic0 = pic;
- pic1 = pic + width;
- outy = out;
- outc = out + 64 * 4;
- for (i = 2; i > 0; i--) {
- for (j = 4; j > 0; j--) {
- for (k = 0; k < 8; k++)
- PIC221111(k);
- outc += 8;
- outy += 16;
- pic0 += 2 * width;
- pic1 += 2 * width;
- }
- outy += 64 * 2 - 16 * 4;
+ uint64_t workbuf_len_min_incl = wuffs_jpeg__decoder__workbuf_len(&dec).min_incl;
+ uint8_t *workbuf_array = malloc(workbuf_len_min_incl);
+ if ((workbuf_array == NULL) && workbuf_len_min_incl) {
+ return JPEG_DECODE_FAILED;
}
-}
-static void col221111_16(int *out, unsigned char *pic, int width)
-{
- int i, j, k;
- unsigned char *pic0, *pic1;
- int *outy, *outc;
- int cr, cg, cb, y;
+ wuffs_base__slice_u8 workbuf =
+ wuffs_base__make_slice_u8(workbuf_array, workbuf_len_min_incl);
+ status = wuffs_jpeg__decoder__decode_frame(&dec, &pixbuf, &src,
+ WUFFS_BASE__PIXEL_BLEND__SRC, workbuf, NULL);
- pic0 = pic;
- pic1 = pic + width;
- outy = out;
- outc = out + 64 * 4;
- for (i = 2; i > 0; i--) {
- for (j = 4; j > 0; j--) {
- for (k = 0; k < 8; k++)
- PIC221111_16(k);
- outc += 8;
- outy += 16;
- pic0 += 2 * width;
- pic1 += 2 * width;
- }
- outy += 64 * 2 - 16 * 4;
- }
-}
+ free(workbuf_array);
-static void col221111_32(int *out, unsigned char *pic, int width)
-{
- int i, j, k;
- unsigned char *pic0, *pic1;
- int *outy, *outc;
- int cr, cg, cb, y;
-
- pic0 = pic;
- pic1 = pic + width;
- outy = out;
- outc = out + 64 * 4;
- for (i = 2; i > 0; i--) {
- for (j = 4; j > 0; j--) {
- for (k = 0; k < 8; k++)
- PIC221111_32(k);
- outc += 8;
- outy += 16;
- pic0 += 2 * width;
- pic1 += 2 * width;
- }
- outy += 64 * 2 - 16 * 4;
+ if (status.repr) {
+ return JPEG_DECODE_FAILED;
}
+
+ return 0;
}
diff --git a/src/lib/jpeg.h b/src/lib/jpeg.h
index fdb2defab7..d2e9e5ffcf 100644
--- a/src/lib/jpeg.h
+++ b/src/lib/jpeg.h
@@ -1,38 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0-only */
-/*
- * a tiny jpeg decoder.
- *
- * written in August 2001 by Michael Schroeder <mls@suse.de>
- */
-
#ifndef __JPEG_H
#define __JPEG_H
-#define ERR_NO_SOI 1
-#define ERR_NOT_8BIT 2
-#define ERR_HEIGHT_MISMATCH 3
-#define ERR_WIDTH_MISMATCH 4
-#define ERR_BAD_WIDTH_OR_HEIGHT 5
-#define ERR_TOO_MANY_COMPPS 6
-#define ERR_ILLEGAL_HV 7
-#define ERR_QUANT_TABLE_SELECTOR 8
-#define ERR_NOT_YCBCR_221111 9
-#define ERR_UNKNOWN_CID_IN_SCAN 10
-#define ERR_NOT_SEQUENTIAL_DCT 11
-#define ERR_WRONG_MARKER 12
-#define ERR_NO_EOI 13
-#define ERR_BAD_TABLES 14
-#define ERR_DEPTH_MISMATCH 15
+#include <stdlib.h>
-struct jpeg_decdata {
- int dcts[6 * 64 + 16];
- int out[64 * 6];
- int dquant[3][64];
-};
+#define JPEG_DECODE_FAILED 1
-int jpeg_decode(unsigned char *, unsigned char *, int, int, int, int, struct jpeg_decdata *);
-void jpeg_fetch_size(unsigned char *buf, int *width, int *height);
-int jpeg_check_size(unsigned char *, int, int);
+int jpeg_fetch_size(unsigned char *filedata, size_t filesize, unsigned int *width,
+ unsigned int *height);
+int jpeg_decode(unsigned char *filedata, size_t filesize, unsigned char *framebuffer,
+ unsigned int width, unsigned int height, unsigned int bytes_per_line,
+ unsigned int depth);
#endif