jpeg: decode 16-bit quantization tables (SOF1)

Both decoders rejected extended sequential JPEGs (SOF1), which are
baseline files in all but name when they have 8-bit samples, and
16-bit quantization tables, which libjpeg writes for very low
quality settings unless told to force baseline.

Accept SOF1 with 8-bit samples, and read 16-bit table entries. The
core loader keeps its tables in 16 bits and scales them for the IDCT,
so it rejects entries over 8191; libjpeg's largest at quality 1 is
4950. Files using more than two Huffman tables are still rejected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: I705a61402b4a0ab252995f8559b7ff2f68b05d72
This commit is contained in:
Michael Giacomelli 2026-09-30 09:29:02 -04:00
parent 2890d4a40d
commit dcee3ce62f
2 changed files with 28 additions and 14 deletions

View file

@ -519,6 +519,7 @@ int process_markers(unsigned char* p_src, long size, struct jpeg* p_jpeg)
break; break;
case 0xC0: /* SOF Huff - Baseline DCT */ case 0xC0: /* SOF Huff - Baseline DCT */
case 0xC1: /* SOF Huff - Extended sequential DCT (8 bit samples) */
{ {
ret |= SOF0; ret |= SOF0;
marker_size = *p_src++ << 8; /* Highbyte */ marker_size = *p_src++ << 8; /* Highbyte */
@ -569,7 +570,6 @@ int process_markers(unsigned char* p_src, long size, struct jpeg* p_jpeg)
} }
break; break;
case 0xC1: /* SOF Huff - Extended sequential DCT*/
case 0xC2: /* SOF Huff - Progressive DCT*/ case 0xC2: /* SOF Huff - Progressive DCT*/
case 0xC3: /* SOF Huff - Spatial (sequential) lossless*/ case 0xC3: /* SOF Huff - Spatial (sequential) lossless*/
case 0xC5: /* SOF Huff - Differential sequential DCT*/ case 0xC5: /* SOF Huff - Differential sequential DCT*/
@ -695,18 +695,27 @@ int process_markers(unsigned char* p_src, long size, struct jpeg* p_jpeg)
ret |= DQT; ret |= DQT;
marker_size = *p_src++ << 8; /* Highbyte */ marker_size = *p_src++ << 8; /* Highbyte */
marker_size |= *p_src++; /* Lowbyte */ marker_size |= *p_src++; /* Lowbyte */
n = (marker_size-2)/(QUANT_TABLE_LENGTH+1); /* # of tables */ unsigned char *p_seg_end = p_src + marker_size - 2;
for (i=0; i<n; i++) while (p_seg_end - p_src > QUANT_TABLE_LENGTH) /* a table */
{ {
int id = *p_src++; /* ID */ int id = *p_src++; /* Pq: precision, Tq: ID */
if (id >= 4) int pq = id >> 4;
id &= 0x0F;
if (id >= 4 || pq > 1
|| p_seg_end - p_src < QUANT_TABLE_LENGTH * (pq + 1))
{ {
return (-8); /* Unsupported quantization table */ return (-8); /* Unsupported quantization table */
} }
/* Read Quantisation table: */ /* Read Quantisation table: */
for (j=0; j<QUANT_TABLE_LENGTH; j++) for (j=0; j<QUANT_TABLE_LENGTH; j++)
p_jpeg->quanttable[id][j] = *p_src++; {
int q = *p_src++;
if (pq) /* 16 bit entries (SOF1) */
q = q << 8 | *p_src++;
p_jpeg->quanttable[id][j] = q;
}
} }
p_src = p_seg_end;
} }
break; break;

View file

@ -1019,6 +1019,7 @@ static int process_markers(struct jpeg* p_jpeg)
break; /* discard */ break; /* discard */
case 0xC0: /* SOF Huff - Baseline DCT */ case 0xC0: /* SOF Huff - Baseline DCT */
case 0xC1: /* SOF Huff - Extended sequential DCT (8 bit samples) */
{ {
JDEBUGF("SOF marker "); JDEBUGF("SOF marker ");
ret |= SOF0; ret |= SOF0;
@ -1082,7 +1083,6 @@ static int process_markers(struct jpeg* p_jpeg)
} }
break; break;
case 0xC1: /* SOF Huff - Extended sequential DCT*/
case 0xC2: /* SOF Huff - Progressive DCT*/ case 0xC2: /* SOF Huff - Progressive DCT*/
case 0xC3: /* SOF Huff - Spatial (sequential) lossless*/ case 0xC3: /* SOF Huff - Spatial (sequential) lossless*/
case 0xC5: /* SOF Huff - Differential sequential DCT*/ case 0xC5: /* SOF Huff - Differential sequential DCT*/
@ -1231,20 +1231,25 @@ static int process_markers(struct jpeg* p_jpeg)
marker_size |= e_getc(p_jpeg, -1); /* Lowbyte */ marker_size |= e_getc(p_jpeg, -1); /* Lowbyte */
marker_size -= 2; marker_size -= 2;
n = (marker_size)/(QUANT_TABLE_LENGTH+1); /* # of tables */ while (marker_size > QUANT_TABLE_LENGTH) /* another table */
for (i=0; i<n; i++)
{ {
int id = e_getc(p_jpeg, -1); /* ID */ int id = e_getc(p_jpeg, -1); /* Pq: precision, Tq: ID */
marker_size--; int pq = id >> 4;
if (id >= 4) id &= 0x0F;
marker_size -= 1 + QUANT_TABLE_LENGTH * (pq + 1);
if (id >= 4 || pq > 1 || marker_size < 0)
{ {
return (-8); /* Unsupported quantization table */ return (-8); /* Unsupported quantization table */
} }
/* Read Quantisation table: */ /* Read Quantisation table: */
for (j=0; j<QUANT_TABLE_LENGTH; j++) for (j=0; j<QUANT_TABLE_LENGTH; j++)
{ {
p_jpeg->quanttable[id][j] = e_getc(p_jpeg, -1); int q = e_getc(p_jpeg, -1);
marker_size--; if (pq) /* 16 bit entries (SOF1) */
q = q << 8 | e_getc(p_jpeg, -1);
if (q > 8191)
return (-8); /* too big once scaled for the IDCT */
p_jpeg->quanttable[id][j] = q;
} }
} }
e_skip_bytes(p_jpeg, marker_size); e_skip_bytes(p_jpeg, marker_size);