1*dfc6aa5cSAndroid Build Coastguard Worker /*
2*dfc6aa5cSAndroid Build Coastguard Worker * rdtarga.c
3*dfc6aa5cSAndroid Build Coastguard Worker *
4*dfc6aa5cSAndroid Build Coastguard Worker * This file was part of the Independent JPEG Group's software:
5*dfc6aa5cSAndroid Build Coastguard Worker * Copyright (C) 1991-1996, Thomas G. Lane.
6*dfc6aa5cSAndroid Build Coastguard Worker * Modified 2017 by Guido Vollbeding.
7*dfc6aa5cSAndroid Build Coastguard Worker * libjpeg-turbo Modifications:
8*dfc6aa5cSAndroid Build Coastguard Worker * Copyright (C) 2018, 2021-2022, D. R. Commander.
9*dfc6aa5cSAndroid Build Coastguard Worker * For conditions of distribution and use, see the accompanying README.ijg
10*dfc6aa5cSAndroid Build Coastguard Worker * file.
11*dfc6aa5cSAndroid Build Coastguard Worker *
12*dfc6aa5cSAndroid Build Coastguard Worker * This file contains routines to read input images in Targa format.
13*dfc6aa5cSAndroid Build Coastguard Worker *
14*dfc6aa5cSAndroid Build Coastguard Worker * These routines may need modification for non-Unix environments or
15*dfc6aa5cSAndroid Build Coastguard Worker * specialized applications. As they stand, they assume input from
16*dfc6aa5cSAndroid Build Coastguard Worker * an ordinary stdio stream. They further assume that reading begins
17*dfc6aa5cSAndroid Build Coastguard Worker * at the start of the file; start_input may need work if the
18*dfc6aa5cSAndroid Build Coastguard Worker * user interface has already read some data (e.g., to determine that
19*dfc6aa5cSAndroid Build Coastguard Worker * the file is indeed Targa format).
20*dfc6aa5cSAndroid Build Coastguard Worker *
21*dfc6aa5cSAndroid Build Coastguard Worker * Based on code contributed by Lee Daniel Crocker.
22*dfc6aa5cSAndroid Build Coastguard Worker */
23*dfc6aa5cSAndroid Build Coastguard Worker
24*dfc6aa5cSAndroid Build Coastguard Worker #include "cdjpeg.h" /* Common decls for cjpeg/djpeg applications */
25*dfc6aa5cSAndroid Build Coastguard Worker
26*dfc6aa5cSAndroid Build Coastguard Worker #ifdef TARGA_SUPPORTED
27*dfc6aa5cSAndroid Build Coastguard Worker
28*dfc6aa5cSAndroid Build Coastguard Worker
29*dfc6aa5cSAndroid Build Coastguard Worker /* Macros to deal with unsigned chars as efficiently as compiler allows */
30*dfc6aa5cSAndroid Build Coastguard Worker
31*dfc6aa5cSAndroid Build Coastguard Worker typedef unsigned char U_CHAR;
32*dfc6aa5cSAndroid Build Coastguard Worker #define UCH(x) ((int)(x))
33*dfc6aa5cSAndroid Build Coastguard Worker
34*dfc6aa5cSAndroid Build Coastguard Worker
35*dfc6aa5cSAndroid Build Coastguard Worker #define ReadOK(file, buffer, len) \
36*dfc6aa5cSAndroid Build Coastguard Worker (fread(buffer, 1, len, file) == ((size_t)(len)))
37*dfc6aa5cSAndroid Build Coastguard Worker
38*dfc6aa5cSAndroid Build Coastguard Worker
39*dfc6aa5cSAndroid Build Coastguard Worker /* Private version of data source object */
40*dfc6aa5cSAndroid Build Coastguard Worker
41*dfc6aa5cSAndroid Build Coastguard Worker typedef struct _tga_source_struct *tga_source_ptr;
42*dfc6aa5cSAndroid Build Coastguard Worker
43*dfc6aa5cSAndroid Build Coastguard Worker typedef struct _tga_source_struct {
44*dfc6aa5cSAndroid Build Coastguard Worker struct cjpeg_source_struct pub; /* public fields */
45*dfc6aa5cSAndroid Build Coastguard Worker
46*dfc6aa5cSAndroid Build Coastguard Worker j_compress_ptr cinfo; /* back link saves passing separate parm */
47*dfc6aa5cSAndroid Build Coastguard Worker
48*dfc6aa5cSAndroid Build Coastguard Worker JSAMPARRAY colormap; /* Targa colormap (converted to my format) */
49*dfc6aa5cSAndroid Build Coastguard Worker
50*dfc6aa5cSAndroid Build Coastguard Worker jvirt_sarray_ptr whole_image; /* Needed if funny input row order */
51*dfc6aa5cSAndroid Build Coastguard Worker JDIMENSION current_row; /* Current logical row number to read */
52*dfc6aa5cSAndroid Build Coastguard Worker
53*dfc6aa5cSAndroid Build Coastguard Worker /* Pointer to routine to extract next Targa pixel from input file */
54*dfc6aa5cSAndroid Build Coastguard Worker void (*read_pixel) (tga_source_ptr sinfo);
55*dfc6aa5cSAndroid Build Coastguard Worker
56*dfc6aa5cSAndroid Build Coastguard Worker /* Result of read_pixel is delivered here: */
57*dfc6aa5cSAndroid Build Coastguard Worker U_CHAR tga_pixel[4];
58*dfc6aa5cSAndroid Build Coastguard Worker
59*dfc6aa5cSAndroid Build Coastguard Worker int pixel_size; /* Bytes per Targa pixel (1 to 4) */
60*dfc6aa5cSAndroid Build Coastguard Worker int cmap_length; /* colormap length */
61*dfc6aa5cSAndroid Build Coastguard Worker
62*dfc6aa5cSAndroid Build Coastguard Worker /* State info for reading RLE-coded pixels; both counts must be init to 0 */
63*dfc6aa5cSAndroid Build Coastguard Worker int block_count; /* # of pixels remaining in RLE block */
64*dfc6aa5cSAndroid Build Coastguard Worker int dup_pixel_count; /* # of times to duplicate previous pixel */
65*dfc6aa5cSAndroid Build Coastguard Worker
66*dfc6aa5cSAndroid Build Coastguard Worker /* This saves the correct pixel-row-expansion method for preload_image */
67*dfc6aa5cSAndroid Build Coastguard Worker JDIMENSION (*get_pixel_rows) (j_compress_ptr cinfo, cjpeg_source_ptr sinfo);
68*dfc6aa5cSAndroid Build Coastguard Worker } tga_source_struct;
69*dfc6aa5cSAndroid Build Coastguard Worker
70*dfc6aa5cSAndroid Build Coastguard Worker
71*dfc6aa5cSAndroid Build Coastguard Worker /* For expanding 5-bit pixel values to 8-bit with best rounding */
72*dfc6aa5cSAndroid Build Coastguard Worker
73*dfc6aa5cSAndroid Build Coastguard Worker static const UINT8 c5to8bits[32] = {
74*dfc6aa5cSAndroid Build Coastguard Worker 0, 8, 16, 25, 33, 41, 49, 58,
75*dfc6aa5cSAndroid Build Coastguard Worker 66, 74, 82, 90, 99, 107, 115, 123,
76*dfc6aa5cSAndroid Build Coastguard Worker 132, 140, 148, 156, 165, 173, 181, 189,
77*dfc6aa5cSAndroid Build Coastguard Worker 197, 206, 214, 222, 230, 239, 247, 255
78*dfc6aa5cSAndroid Build Coastguard Worker };
79*dfc6aa5cSAndroid Build Coastguard Worker
80*dfc6aa5cSAndroid Build Coastguard Worker
81*dfc6aa5cSAndroid Build Coastguard Worker
82*dfc6aa5cSAndroid Build Coastguard Worker LOCAL(int)
read_byte(tga_source_ptr sinfo)83*dfc6aa5cSAndroid Build Coastguard Worker read_byte(tga_source_ptr sinfo)
84*dfc6aa5cSAndroid Build Coastguard Worker /* Read next byte from Targa file */
85*dfc6aa5cSAndroid Build Coastguard Worker {
86*dfc6aa5cSAndroid Build Coastguard Worker register FILE *infile = sinfo->pub.input_file;
87*dfc6aa5cSAndroid Build Coastguard Worker register int c;
88*dfc6aa5cSAndroid Build Coastguard Worker
89*dfc6aa5cSAndroid Build Coastguard Worker if ((c = getc(infile)) == EOF)
90*dfc6aa5cSAndroid Build Coastguard Worker ERREXIT(sinfo->cinfo, JERR_INPUT_EOF);
91*dfc6aa5cSAndroid Build Coastguard Worker return c;
92*dfc6aa5cSAndroid Build Coastguard Worker }
93*dfc6aa5cSAndroid Build Coastguard Worker
94*dfc6aa5cSAndroid Build Coastguard Worker
95*dfc6aa5cSAndroid Build Coastguard Worker LOCAL(void)
read_colormap(tga_source_ptr sinfo,int cmaplen,int mapentrysize)96*dfc6aa5cSAndroid Build Coastguard Worker read_colormap(tga_source_ptr sinfo, int cmaplen, int mapentrysize)
97*dfc6aa5cSAndroid Build Coastguard Worker /* Read the colormap from a Targa file */
98*dfc6aa5cSAndroid Build Coastguard Worker {
99*dfc6aa5cSAndroid Build Coastguard Worker int i;
100*dfc6aa5cSAndroid Build Coastguard Worker
101*dfc6aa5cSAndroid Build Coastguard Worker /* Presently only handles 24-bit BGR format */
102*dfc6aa5cSAndroid Build Coastguard Worker if (mapentrysize != 24)
103*dfc6aa5cSAndroid Build Coastguard Worker ERREXIT(sinfo->cinfo, JERR_TGA_BADCMAP);
104*dfc6aa5cSAndroid Build Coastguard Worker
105*dfc6aa5cSAndroid Build Coastguard Worker for (i = 0; i < cmaplen; i++) {
106*dfc6aa5cSAndroid Build Coastguard Worker sinfo->colormap[2][i] = (JSAMPLE)read_byte(sinfo);
107*dfc6aa5cSAndroid Build Coastguard Worker sinfo->colormap[1][i] = (JSAMPLE)read_byte(sinfo);
108*dfc6aa5cSAndroid Build Coastguard Worker sinfo->colormap[0][i] = (JSAMPLE)read_byte(sinfo);
109*dfc6aa5cSAndroid Build Coastguard Worker }
110*dfc6aa5cSAndroid Build Coastguard Worker }
111*dfc6aa5cSAndroid Build Coastguard Worker
112*dfc6aa5cSAndroid Build Coastguard Worker
113*dfc6aa5cSAndroid Build Coastguard Worker /*
114*dfc6aa5cSAndroid Build Coastguard Worker * read_pixel methods: get a single pixel from Targa file into tga_pixel[]
115*dfc6aa5cSAndroid Build Coastguard Worker */
116*dfc6aa5cSAndroid Build Coastguard Worker
117*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(void)
read_non_rle_pixel(tga_source_ptr sinfo)118*dfc6aa5cSAndroid Build Coastguard Worker read_non_rle_pixel(tga_source_ptr sinfo)
119*dfc6aa5cSAndroid Build Coastguard Worker /* Read one Targa pixel from the input file; no RLE expansion */
120*dfc6aa5cSAndroid Build Coastguard Worker {
121*dfc6aa5cSAndroid Build Coastguard Worker register int i;
122*dfc6aa5cSAndroid Build Coastguard Worker
123*dfc6aa5cSAndroid Build Coastguard Worker for (i = 0; i < sinfo->pixel_size; i++) {
124*dfc6aa5cSAndroid Build Coastguard Worker sinfo->tga_pixel[i] = (U_CHAR)read_byte(sinfo);
125*dfc6aa5cSAndroid Build Coastguard Worker }
126*dfc6aa5cSAndroid Build Coastguard Worker }
127*dfc6aa5cSAndroid Build Coastguard Worker
128*dfc6aa5cSAndroid Build Coastguard Worker
129*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(void)
read_rle_pixel(tga_source_ptr sinfo)130*dfc6aa5cSAndroid Build Coastguard Worker read_rle_pixel(tga_source_ptr sinfo)
131*dfc6aa5cSAndroid Build Coastguard Worker /* Read one Targa pixel from the input file, expanding RLE data as needed */
132*dfc6aa5cSAndroid Build Coastguard Worker {
133*dfc6aa5cSAndroid Build Coastguard Worker register int i;
134*dfc6aa5cSAndroid Build Coastguard Worker
135*dfc6aa5cSAndroid Build Coastguard Worker /* Duplicate previously read pixel? */
136*dfc6aa5cSAndroid Build Coastguard Worker if (sinfo->dup_pixel_count > 0) {
137*dfc6aa5cSAndroid Build Coastguard Worker sinfo->dup_pixel_count--;
138*dfc6aa5cSAndroid Build Coastguard Worker return;
139*dfc6aa5cSAndroid Build Coastguard Worker }
140*dfc6aa5cSAndroid Build Coastguard Worker
141*dfc6aa5cSAndroid Build Coastguard Worker /* Time to read RLE block header? */
142*dfc6aa5cSAndroid Build Coastguard Worker if (--sinfo->block_count < 0) { /* decrement pixels remaining in block */
143*dfc6aa5cSAndroid Build Coastguard Worker i = read_byte(sinfo);
144*dfc6aa5cSAndroid Build Coastguard Worker if (i & 0x80) { /* Start of duplicate-pixel block? */
145*dfc6aa5cSAndroid Build Coastguard Worker sinfo->dup_pixel_count = i & 0x7F; /* number of dups after this one */
146*dfc6aa5cSAndroid Build Coastguard Worker sinfo->block_count = 0; /* then read new block header */
147*dfc6aa5cSAndroid Build Coastguard Worker } else {
148*dfc6aa5cSAndroid Build Coastguard Worker sinfo->block_count = i & 0x7F; /* number of pixels after this one */
149*dfc6aa5cSAndroid Build Coastguard Worker }
150*dfc6aa5cSAndroid Build Coastguard Worker }
151*dfc6aa5cSAndroid Build Coastguard Worker
152*dfc6aa5cSAndroid Build Coastguard Worker /* Read next pixel */
153*dfc6aa5cSAndroid Build Coastguard Worker for (i = 0; i < sinfo->pixel_size; i++) {
154*dfc6aa5cSAndroid Build Coastguard Worker sinfo->tga_pixel[i] = (U_CHAR)read_byte(sinfo);
155*dfc6aa5cSAndroid Build Coastguard Worker }
156*dfc6aa5cSAndroid Build Coastguard Worker }
157*dfc6aa5cSAndroid Build Coastguard Worker
158*dfc6aa5cSAndroid Build Coastguard Worker
159*dfc6aa5cSAndroid Build Coastguard Worker /*
160*dfc6aa5cSAndroid Build Coastguard Worker * Read one row of pixels.
161*dfc6aa5cSAndroid Build Coastguard Worker *
162*dfc6aa5cSAndroid Build Coastguard Worker * We provide several different versions depending on input file format.
163*dfc6aa5cSAndroid Build Coastguard Worker */
164*dfc6aa5cSAndroid Build Coastguard Worker
165*dfc6aa5cSAndroid Build Coastguard Worker
166*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(JDIMENSION)
get_8bit_gray_row(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)167*dfc6aa5cSAndroid Build Coastguard Worker get_8bit_gray_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
168*dfc6aa5cSAndroid Build Coastguard Worker /* This version is for reading 8-bit grayscale pixels */
169*dfc6aa5cSAndroid Build Coastguard Worker {
170*dfc6aa5cSAndroid Build Coastguard Worker tga_source_ptr source = (tga_source_ptr)sinfo;
171*dfc6aa5cSAndroid Build Coastguard Worker register JSAMPROW ptr;
172*dfc6aa5cSAndroid Build Coastguard Worker register JDIMENSION col;
173*dfc6aa5cSAndroid Build Coastguard Worker
174*dfc6aa5cSAndroid Build Coastguard Worker ptr = source->pub.buffer[0];
175*dfc6aa5cSAndroid Build Coastguard Worker for (col = cinfo->image_width; col > 0; col--) {
176*dfc6aa5cSAndroid Build Coastguard Worker (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
177*dfc6aa5cSAndroid Build Coastguard Worker *ptr++ = (JSAMPLE)UCH(source->tga_pixel[0]);
178*dfc6aa5cSAndroid Build Coastguard Worker }
179*dfc6aa5cSAndroid Build Coastguard Worker return 1;
180*dfc6aa5cSAndroid Build Coastguard Worker }
181*dfc6aa5cSAndroid Build Coastguard Worker
182*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(JDIMENSION)
get_8bit_row(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)183*dfc6aa5cSAndroid Build Coastguard Worker get_8bit_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
184*dfc6aa5cSAndroid Build Coastguard Worker /* This version is for reading 8-bit colormap indexes */
185*dfc6aa5cSAndroid Build Coastguard Worker {
186*dfc6aa5cSAndroid Build Coastguard Worker tga_source_ptr source = (tga_source_ptr)sinfo;
187*dfc6aa5cSAndroid Build Coastguard Worker register int t;
188*dfc6aa5cSAndroid Build Coastguard Worker register JSAMPROW ptr;
189*dfc6aa5cSAndroid Build Coastguard Worker register JDIMENSION col;
190*dfc6aa5cSAndroid Build Coastguard Worker register JSAMPARRAY colormap = source->colormap;
191*dfc6aa5cSAndroid Build Coastguard Worker int cmaplen = source->cmap_length;
192*dfc6aa5cSAndroid Build Coastguard Worker
193*dfc6aa5cSAndroid Build Coastguard Worker ptr = source->pub.buffer[0];
194*dfc6aa5cSAndroid Build Coastguard Worker for (col = cinfo->image_width; col > 0; col--) {
195*dfc6aa5cSAndroid Build Coastguard Worker (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
196*dfc6aa5cSAndroid Build Coastguard Worker t = UCH(source->tga_pixel[0]);
197*dfc6aa5cSAndroid Build Coastguard Worker if (t >= cmaplen)
198*dfc6aa5cSAndroid Build Coastguard Worker ERREXIT(cinfo, JERR_TGA_BADPARMS);
199*dfc6aa5cSAndroid Build Coastguard Worker *ptr++ = colormap[0][t];
200*dfc6aa5cSAndroid Build Coastguard Worker *ptr++ = colormap[1][t];
201*dfc6aa5cSAndroid Build Coastguard Worker *ptr++ = colormap[2][t];
202*dfc6aa5cSAndroid Build Coastguard Worker }
203*dfc6aa5cSAndroid Build Coastguard Worker return 1;
204*dfc6aa5cSAndroid Build Coastguard Worker }
205*dfc6aa5cSAndroid Build Coastguard Worker
206*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(JDIMENSION)
get_16bit_row(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)207*dfc6aa5cSAndroid Build Coastguard Worker get_16bit_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
208*dfc6aa5cSAndroid Build Coastguard Worker /* This version is for reading 16-bit pixels */
209*dfc6aa5cSAndroid Build Coastguard Worker {
210*dfc6aa5cSAndroid Build Coastguard Worker tga_source_ptr source = (tga_source_ptr)sinfo;
211*dfc6aa5cSAndroid Build Coastguard Worker register int t;
212*dfc6aa5cSAndroid Build Coastguard Worker register JSAMPROW ptr;
213*dfc6aa5cSAndroid Build Coastguard Worker register JDIMENSION col;
214*dfc6aa5cSAndroid Build Coastguard Worker
215*dfc6aa5cSAndroid Build Coastguard Worker ptr = source->pub.buffer[0];
216*dfc6aa5cSAndroid Build Coastguard Worker for (col = cinfo->image_width; col > 0; col--) {
217*dfc6aa5cSAndroid Build Coastguard Worker (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
218*dfc6aa5cSAndroid Build Coastguard Worker t = UCH(source->tga_pixel[0]);
219*dfc6aa5cSAndroid Build Coastguard Worker t += UCH(source->tga_pixel[1]) << 8;
220*dfc6aa5cSAndroid Build Coastguard Worker /* We expand 5 bit data to 8 bit sample width.
221*dfc6aa5cSAndroid Build Coastguard Worker * The format of the 16-bit (LSB first) input word is
222*dfc6aa5cSAndroid Build Coastguard Worker * xRRRRRGGGGGBBBBB
223*dfc6aa5cSAndroid Build Coastguard Worker */
224*dfc6aa5cSAndroid Build Coastguard Worker ptr[2] = (JSAMPLE)c5to8bits[t & 0x1F];
225*dfc6aa5cSAndroid Build Coastguard Worker t >>= 5;
226*dfc6aa5cSAndroid Build Coastguard Worker ptr[1] = (JSAMPLE)c5to8bits[t & 0x1F];
227*dfc6aa5cSAndroid Build Coastguard Worker t >>= 5;
228*dfc6aa5cSAndroid Build Coastguard Worker ptr[0] = (JSAMPLE)c5to8bits[t & 0x1F];
229*dfc6aa5cSAndroid Build Coastguard Worker ptr += 3;
230*dfc6aa5cSAndroid Build Coastguard Worker }
231*dfc6aa5cSAndroid Build Coastguard Worker return 1;
232*dfc6aa5cSAndroid Build Coastguard Worker }
233*dfc6aa5cSAndroid Build Coastguard Worker
234*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(JDIMENSION)
get_24bit_row(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)235*dfc6aa5cSAndroid Build Coastguard Worker get_24bit_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
236*dfc6aa5cSAndroid Build Coastguard Worker /* This version is for reading 24-bit pixels */
237*dfc6aa5cSAndroid Build Coastguard Worker {
238*dfc6aa5cSAndroid Build Coastguard Worker tga_source_ptr source = (tga_source_ptr)sinfo;
239*dfc6aa5cSAndroid Build Coastguard Worker register JSAMPROW ptr;
240*dfc6aa5cSAndroid Build Coastguard Worker register JDIMENSION col;
241*dfc6aa5cSAndroid Build Coastguard Worker
242*dfc6aa5cSAndroid Build Coastguard Worker ptr = source->pub.buffer[0];
243*dfc6aa5cSAndroid Build Coastguard Worker for (col = cinfo->image_width; col > 0; col--) {
244*dfc6aa5cSAndroid Build Coastguard Worker (*source->read_pixel) (source); /* Load next pixel into tga_pixel */
245*dfc6aa5cSAndroid Build Coastguard Worker *ptr++ = (JSAMPLE)UCH(source->tga_pixel[2]); /* change BGR to RGB order */
246*dfc6aa5cSAndroid Build Coastguard Worker *ptr++ = (JSAMPLE)UCH(source->tga_pixel[1]);
247*dfc6aa5cSAndroid Build Coastguard Worker *ptr++ = (JSAMPLE)UCH(source->tga_pixel[0]);
248*dfc6aa5cSAndroid Build Coastguard Worker }
249*dfc6aa5cSAndroid Build Coastguard Worker return 1;
250*dfc6aa5cSAndroid Build Coastguard Worker }
251*dfc6aa5cSAndroid Build Coastguard Worker
252*dfc6aa5cSAndroid Build Coastguard Worker /*
253*dfc6aa5cSAndroid Build Coastguard Worker * Targa also defines a 32-bit pixel format with order B,G,R,A.
254*dfc6aa5cSAndroid Build Coastguard Worker * We presently ignore the attribute byte, so the code for reading
255*dfc6aa5cSAndroid Build Coastguard Worker * these pixels is identical to the 24-bit routine above.
256*dfc6aa5cSAndroid Build Coastguard Worker * This works because the actual pixel length is only known to read_pixel.
257*dfc6aa5cSAndroid Build Coastguard Worker */
258*dfc6aa5cSAndroid Build Coastguard Worker
259*dfc6aa5cSAndroid Build Coastguard Worker #define get_32bit_row get_24bit_row
260*dfc6aa5cSAndroid Build Coastguard Worker
261*dfc6aa5cSAndroid Build Coastguard Worker
262*dfc6aa5cSAndroid Build Coastguard Worker /*
263*dfc6aa5cSAndroid Build Coastguard Worker * This method is for re-reading the input data in standard top-down
264*dfc6aa5cSAndroid Build Coastguard Worker * row order. The entire image has already been read into whole_image
265*dfc6aa5cSAndroid Build Coastguard Worker * with proper conversion of pixel format, but it's in a funny row order.
266*dfc6aa5cSAndroid Build Coastguard Worker */
267*dfc6aa5cSAndroid Build Coastguard Worker
268*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(JDIMENSION)
get_memory_row(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)269*dfc6aa5cSAndroid Build Coastguard Worker get_memory_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
270*dfc6aa5cSAndroid Build Coastguard Worker {
271*dfc6aa5cSAndroid Build Coastguard Worker tga_source_ptr source = (tga_source_ptr)sinfo;
272*dfc6aa5cSAndroid Build Coastguard Worker JDIMENSION source_row;
273*dfc6aa5cSAndroid Build Coastguard Worker
274*dfc6aa5cSAndroid Build Coastguard Worker /* Compute row of source that maps to current_row of normal order */
275*dfc6aa5cSAndroid Build Coastguard Worker /* For now, assume image is bottom-up and not interlaced. */
276*dfc6aa5cSAndroid Build Coastguard Worker /* NEEDS WORK to support interlaced images! */
277*dfc6aa5cSAndroid Build Coastguard Worker source_row = cinfo->image_height - source->current_row - 1;
278*dfc6aa5cSAndroid Build Coastguard Worker
279*dfc6aa5cSAndroid Build Coastguard Worker /* Fetch that row from virtual array */
280*dfc6aa5cSAndroid Build Coastguard Worker source->pub.buffer = (*cinfo->mem->access_virt_sarray)
281*dfc6aa5cSAndroid Build Coastguard Worker ((j_common_ptr)cinfo, source->whole_image,
282*dfc6aa5cSAndroid Build Coastguard Worker source_row, (JDIMENSION)1, FALSE);
283*dfc6aa5cSAndroid Build Coastguard Worker
284*dfc6aa5cSAndroid Build Coastguard Worker source->current_row++;
285*dfc6aa5cSAndroid Build Coastguard Worker return 1;
286*dfc6aa5cSAndroid Build Coastguard Worker }
287*dfc6aa5cSAndroid Build Coastguard Worker
288*dfc6aa5cSAndroid Build Coastguard Worker
289*dfc6aa5cSAndroid Build Coastguard Worker /*
290*dfc6aa5cSAndroid Build Coastguard Worker * This method loads the image into whole_image during the first call on
291*dfc6aa5cSAndroid Build Coastguard Worker * get_pixel_rows. The get_pixel_rows pointer is then adjusted to call
292*dfc6aa5cSAndroid Build Coastguard Worker * get_memory_row on subsequent calls.
293*dfc6aa5cSAndroid Build Coastguard Worker */
294*dfc6aa5cSAndroid Build Coastguard Worker
295*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(JDIMENSION)
preload_image(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)296*dfc6aa5cSAndroid Build Coastguard Worker preload_image(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
297*dfc6aa5cSAndroid Build Coastguard Worker {
298*dfc6aa5cSAndroid Build Coastguard Worker tga_source_ptr source = (tga_source_ptr)sinfo;
299*dfc6aa5cSAndroid Build Coastguard Worker JDIMENSION row;
300*dfc6aa5cSAndroid Build Coastguard Worker cd_progress_ptr progress = (cd_progress_ptr)cinfo->progress;
301*dfc6aa5cSAndroid Build Coastguard Worker
302*dfc6aa5cSAndroid Build Coastguard Worker /* Read the data into a virtual array in input-file row order. */
303*dfc6aa5cSAndroid Build Coastguard Worker for (row = 0; row < cinfo->image_height; row++) {
304*dfc6aa5cSAndroid Build Coastguard Worker if (progress != NULL) {
305*dfc6aa5cSAndroid Build Coastguard Worker progress->pub.pass_counter = (long)row;
306*dfc6aa5cSAndroid Build Coastguard Worker progress->pub.pass_limit = (long)cinfo->image_height;
307*dfc6aa5cSAndroid Build Coastguard Worker (*progress->pub.progress_monitor) ((j_common_ptr)cinfo);
308*dfc6aa5cSAndroid Build Coastguard Worker }
309*dfc6aa5cSAndroid Build Coastguard Worker source->pub.buffer = (*cinfo->mem->access_virt_sarray)
310*dfc6aa5cSAndroid Build Coastguard Worker ((j_common_ptr)cinfo, source->whole_image, row, (JDIMENSION)1, TRUE);
311*dfc6aa5cSAndroid Build Coastguard Worker (*source->get_pixel_rows) (cinfo, sinfo);
312*dfc6aa5cSAndroid Build Coastguard Worker }
313*dfc6aa5cSAndroid Build Coastguard Worker if (progress != NULL)
314*dfc6aa5cSAndroid Build Coastguard Worker progress->completed_extra_passes++;
315*dfc6aa5cSAndroid Build Coastguard Worker
316*dfc6aa5cSAndroid Build Coastguard Worker /* Set up to read from the virtual array in unscrambled order */
317*dfc6aa5cSAndroid Build Coastguard Worker source->pub.get_pixel_rows = get_memory_row;
318*dfc6aa5cSAndroid Build Coastguard Worker source->current_row = 0;
319*dfc6aa5cSAndroid Build Coastguard Worker /* And read the first row */
320*dfc6aa5cSAndroid Build Coastguard Worker return get_memory_row(cinfo, sinfo);
321*dfc6aa5cSAndroid Build Coastguard Worker }
322*dfc6aa5cSAndroid Build Coastguard Worker
323*dfc6aa5cSAndroid Build Coastguard Worker
324*dfc6aa5cSAndroid Build Coastguard Worker /*
325*dfc6aa5cSAndroid Build Coastguard Worker * Read the file header; return image size and component count.
326*dfc6aa5cSAndroid Build Coastguard Worker */
327*dfc6aa5cSAndroid Build Coastguard Worker
328*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(void)
start_input_tga(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)329*dfc6aa5cSAndroid Build Coastguard Worker start_input_tga(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
330*dfc6aa5cSAndroid Build Coastguard Worker {
331*dfc6aa5cSAndroid Build Coastguard Worker tga_source_ptr source = (tga_source_ptr)sinfo;
332*dfc6aa5cSAndroid Build Coastguard Worker U_CHAR targaheader[18];
333*dfc6aa5cSAndroid Build Coastguard Worker int idlen, cmaptype, subtype, flags, interlace_type, components;
334*dfc6aa5cSAndroid Build Coastguard Worker unsigned int width, height, maplen;
335*dfc6aa5cSAndroid Build Coastguard Worker boolean is_bottom_up;
336*dfc6aa5cSAndroid Build Coastguard Worker
337*dfc6aa5cSAndroid Build Coastguard Worker #define GET_2B(offset) \
338*dfc6aa5cSAndroid Build Coastguard Worker ((unsigned int)UCH(targaheader[offset]) + \
339*dfc6aa5cSAndroid Build Coastguard Worker (((unsigned int)UCH(targaheader[offset + 1])) << 8))
340*dfc6aa5cSAndroid Build Coastguard Worker
341*dfc6aa5cSAndroid Build Coastguard Worker if (!ReadOK(source->pub.input_file, targaheader, 18))
342*dfc6aa5cSAndroid Build Coastguard Worker ERREXIT(cinfo, JERR_INPUT_EOF);
343*dfc6aa5cSAndroid Build Coastguard Worker
344*dfc6aa5cSAndroid Build Coastguard Worker /* Pretend "15-bit" pixels are 16-bit --- we ignore attribute bit anyway */
345*dfc6aa5cSAndroid Build Coastguard Worker if (targaheader[16] == 15)
346*dfc6aa5cSAndroid Build Coastguard Worker targaheader[16] = 16;
347*dfc6aa5cSAndroid Build Coastguard Worker
348*dfc6aa5cSAndroid Build Coastguard Worker idlen = UCH(targaheader[0]);
349*dfc6aa5cSAndroid Build Coastguard Worker cmaptype = UCH(targaheader[1]);
350*dfc6aa5cSAndroid Build Coastguard Worker subtype = UCH(targaheader[2]);
351*dfc6aa5cSAndroid Build Coastguard Worker maplen = GET_2B(5);
352*dfc6aa5cSAndroid Build Coastguard Worker width = GET_2B(12);
353*dfc6aa5cSAndroid Build Coastguard Worker height = GET_2B(14);
354*dfc6aa5cSAndroid Build Coastguard Worker source->pixel_size = UCH(targaheader[16]) >> 3;
355*dfc6aa5cSAndroid Build Coastguard Worker flags = UCH(targaheader[17]); /* Image Descriptor byte */
356*dfc6aa5cSAndroid Build Coastguard Worker
357*dfc6aa5cSAndroid Build Coastguard Worker is_bottom_up = ((flags & 0x20) == 0); /* bit 5 set => top-down */
358*dfc6aa5cSAndroid Build Coastguard Worker interlace_type = flags >> 6; /* bits 6/7 are interlace code */
359*dfc6aa5cSAndroid Build Coastguard Worker
360*dfc6aa5cSAndroid Build Coastguard Worker if (cmaptype > 1 || /* cmaptype must be 0 or 1 */
361*dfc6aa5cSAndroid Build Coastguard Worker source->pixel_size < 1 || source->pixel_size > 4 ||
362*dfc6aa5cSAndroid Build Coastguard Worker (UCH(targaheader[16]) & 7) != 0 || /* bits/pixel must be multiple of 8 */
363*dfc6aa5cSAndroid Build Coastguard Worker interlace_type != 0 || /* currently don't allow interlaced image */
364*dfc6aa5cSAndroid Build Coastguard Worker width == 0 || height == 0) /* image width/height must be non-zero */
365*dfc6aa5cSAndroid Build Coastguard Worker ERREXIT(cinfo, JERR_TGA_BADPARMS);
366*dfc6aa5cSAndroid Build Coastguard Worker #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
367*dfc6aa5cSAndroid Build Coastguard Worker if (sinfo->max_pixels &&
368*dfc6aa5cSAndroid Build Coastguard Worker (unsigned long long)width * height > sinfo->max_pixels)
369*dfc6aa5cSAndroid Build Coastguard Worker ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
370*dfc6aa5cSAndroid Build Coastguard Worker #endif
371*dfc6aa5cSAndroid Build Coastguard Worker
372*dfc6aa5cSAndroid Build Coastguard Worker if (subtype > 8) {
373*dfc6aa5cSAndroid Build Coastguard Worker /* It's an RLE-coded file */
374*dfc6aa5cSAndroid Build Coastguard Worker source->read_pixel = read_rle_pixel;
375*dfc6aa5cSAndroid Build Coastguard Worker source->block_count = source->dup_pixel_count = 0;
376*dfc6aa5cSAndroid Build Coastguard Worker subtype -= 8;
377*dfc6aa5cSAndroid Build Coastguard Worker } else {
378*dfc6aa5cSAndroid Build Coastguard Worker /* Non-RLE file */
379*dfc6aa5cSAndroid Build Coastguard Worker source->read_pixel = read_non_rle_pixel;
380*dfc6aa5cSAndroid Build Coastguard Worker }
381*dfc6aa5cSAndroid Build Coastguard Worker
382*dfc6aa5cSAndroid Build Coastguard Worker /* Now should have subtype 1, 2, or 3 */
383*dfc6aa5cSAndroid Build Coastguard Worker components = 3; /* until proven different */
384*dfc6aa5cSAndroid Build Coastguard Worker cinfo->in_color_space = JCS_RGB;
385*dfc6aa5cSAndroid Build Coastguard Worker
386*dfc6aa5cSAndroid Build Coastguard Worker switch (subtype) {
387*dfc6aa5cSAndroid Build Coastguard Worker case 1: /* Colormapped image */
388*dfc6aa5cSAndroid Build Coastguard Worker if (source->pixel_size == 1 && cmaptype == 1)
389*dfc6aa5cSAndroid Build Coastguard Worker source->get_pixel_rows = get_8bit_row;
390*dfc6aa5cSAndroid Build Coastguard Worker else
391*dfc6aa5cSAndroid Build Coastguard Worker ERREXIT(cinfo, JERR_TGA_BADPARMS);
392*dfc6aa5cSAndroid Build Coastguard Worker TRACEMS2(cinfo, 1, JTRC_TGA_MAPPED, width, height);
393*dfc6aa5cSAndroid Build Coastguard Worker break;
394*dfc6aa5cSAndroid Build Coastguard Worker case 2: /* RGB image */
395*dfc6aa5cSAndroid Build Coastguard Worker switch (source->pixel_size) {
396*dfc6aa5cSAndroid Build Coastguard Worker case 2:
397*dfc6aa5cSAndroid Build Coastguard Worker source->get_pixel_rows = get_16bit_row;
398*dfc6aa5cSAndroid Build Coastguard Worker break;
399*dfc6aa5cSAndroid Build Coastguard Worker case 3:
400*dfc6aa5cSAndroid Build Coastguard Worker source->get_pixel_rows = get_24bit_row;
401*dfc6aa5cSAndroid Build Coastguard Worker break;
402*dfc6aa5cSAndroid Build Coastguard Worker case 4:
403*dfc6aa5cSAndroid Build Coastguard Worker source->get_pixel_rows = get_32bit_row;
404*dfc6aa5cSAndroid Build Coastguard Worker break;
405*dfc6aa5cSAndroid Build Coastguard Worker default:
406*dfc6aa5cSAndroid Build Coastguard Worker ERREXIT(cinfo, JERR_TGA_BADPARMS);
407*dfc6aa5cSAndroid Build Coastguard Worker break;
408*dfc6aa5cSAndroid Build Coastguard Worker }
409*dfc6aa5cSAndroid Build Coastguard Worker TRACEMS2(cinfo, 1, JTRC_TGA, width, height);
410*dfc6aa5cSAndroid Build Coastguard Worker break;
411*dfc6aa5cSAndroid Build Coastguard Worker case 3: /* Grayscale image */
412*dfc6aa5cSAndroid Build Coastguard Worker components = 1;
413*dfc6aa5cSAndroid Build Coastguard Worker cinfo->in_color_space = JCS_GRAYSCALE;
414*dfc6aa5cSAndroid Build Coastguard Worker if (source->pixel_size == 1)
415*dfc6aa5cSAndroid Build Coastguard Worker source->get_pixel_rows = get_8bit_gray_row;
416*dfc6aa5cSAndroid Build Coastguard Worker else
417*dfc6aa5cSAndroid Build Coastguard Worker ERREXIT(cinfo, JERR_TGA_BADPARMS);
418*dfc6aa5cSAndroid Build Coastguard Worker TRACEMS2(cinfo, 1, JTRC_TGA_GRAY, width, height);
419*dfc6aa5cSAndroid Build Coastguard Worker break;
420*dfc6aa5cSAndroid Build Coastguard Worker default:
421*dfc6aa5cSAndroid Build Coastguard Worker ERREXIT(cinfo, JERR_TGA_BADPARMS);
422*dfc6aa5cSAndroid Build Coastguard Worker break;
423*dfc6aa5cSAndroid Build Coastguard Worker }
424*dfc6aa5cSAndroid Build Coastguard Worker
425*dfc6aa5cSAndroid Build Coastguard Worker if (is_bottom_up) {
426*dfc6aa5cSAndroid Build Coastguard Worker /* Create a virtual array to buffer the upside-down image. */
427*dfc6aa5cSAndroid Build Coastguard Worker source->whole_image = (*cinfo->mem->request_virt_sarray)
428*dfc6aa5cSAndroid Build Coastguard Worker ((j_common_ptr)cinfo, JPOOL_IMAGE, FALSE,
429*dfc6aa5cSAndroid Build Coastguard Worker (JDIMENSION)width * components, (JDIMENSION)height, (JDIMENSION)1);
430*dfc6aa5cSAndroid Build Coastguard Worker if (cinfo->progress != NULL) {
431*dfc6aa5cSAndroid Build Coastguard Worker cd_progress_ptr progress = (cd_progress_ptr)cinfo->progress;
432*dfc6aa5cSAndroid Build Coastguard Worker progress->total_extra_passes++; /* count file input as separate pass */
433*dfc6aa5cSAndroid Build Coastguard Worker }
434*dfc6aa5cSAndroid Build Coastguard Worker /* source->pub.buffer will point to the virtual array. */
435*dfc6aa5cSAndroid Build Coastguard Worker source->pub.buffer_height = 1; /* in case anyone looks at it */
436*dfc6aa5cSAndroid Build Coastguard Worker source->pub.get_pixel_rows = preload_image;
437*dfc6aa5cSAndroid Build Coastguard Worker } else {
438*dfc6aa5cSAndroid Build Coastguard Worker /* Don't need a virtual array, but do need a one-row input buffer. */
439*dfc6aa5cSAndroid Build Coastguard Worker source->whole_image = NULL;
440*dfc6aa5cSAndroid Build Coastguard Worker source->pub.buffer = (*cinfo->mem->alloc_sarray)
441*dfc6aa5cSAndroid Build Coastguard Worker ((j_common_ptr)cinfo, JPOOL_IMAGE,
442*dfc6aa5cSAndroid Build Coastguard Worker (JDIMENSION)width * components, (JDIMENSION)1);
443*dfc6aa5cSAndroid Build Coastguard Worker source->pub.buffer_height = 1;
444*dfc6aa5cSAndroid Build Coastguard Worker source->pub.get_pixel_rows = source->get_pixel_rows;
445*dfc6aa5cSAndroid Build Coastguard Worker }
446*dfc6aa5cSAndroid Build Coastguard Worker
447*dfc6aa5cSAndroid Build Coastguard Worker while (idlen--) /* Throw away ID field */
448*dfc6aa5cSAndroid Build Coastguard Worker (void)read_byte(source);
449*dfc6aa5cSAndroid Build Coastguard Worker
450*dfc6aa5cSAndroid Build Coastguard Worker if (maplen > 0) {
451*dfc6aa5cSAndroid Build Coastguard Worker if (maplen > 256 || GET_2B(3) != 0)
452*dfc6aa5cSAndroid Build Coastguard Worker ERREXIT(cinfo, JERR_TGA_BADCMAP);
453*dfc6aa5cSAndroid Build Coastguard Worker /* Allocate space to store the colormap */
454*dfc6aa5cSAndroid Build Coastguard Worker source->colormap = (*cinfo->mem->alloc_sarray)
455*dfc6aa5cSAndroid Build Coastguard Worker ((j_common_ptr)cinfo, JPOOL_IMAGE, (JDIMENSION)maplen, (JDIMENSION)3);
456*dfc6aa5cSAndroid Build Coastguard Worker source->cmap_length = (int)maplen;
457*dfc6aa5cSAndroid Build Coastguard Worker /* and read it from the file */
458*dfc6aa5cSAndroid Build Coastguard Worker read_colormap(source, (int)maplen, UCH(targaheader[7]));
459*dfc6aa5cSAndroid Build Coastguard Worker } else {
460*dfc6aa5cSAndroid Build Coastguard Worker if (cmaptype) /* but you promised a cmap! */
461*dfc6aa5cSAndroid Build Coastguard Worker ERREXIT(cinfo, JERR_TGA_BADPARMS);
462*dfc6aa5cSAndroid Build Coastguard Worker source->colormap = NULL;
463*dfc6aa5cSAndroid Build Coastguard Worker source->cmap_length = 0;
464*dfc6aa5cSAndroid Build Coastguard Worker }
465*dfc6aa5cSAndroid Build Coastguard Worker
466*dfc6aa5cSAndroid Build Coastguard Worker cinfo->input_components = components;
467*dfc6aa5cSAndroid Build Coastguard Worker cinfo->data_precision = 8;
468*dfc6aa5cSAndroid Build Coastguard Worker cinfo->image_width = width;
469*dfc6aa5cSAndroid Build Coastguard Worker cinfo->image_height = height;
470*dfc6aa5cSAndroid Build Coastguard Worker }
471*dfc6aa5cSAndroid Build Coastguard Worker
472*dfc6aa5cSAndroid Build Coastguard Worker
473*dfc6aa5cSAndroid Build Coastguard Worker /*
474*dfc6aa5cSAndroid Build Coastguard Worker * Finish up at the end of the file.
475*dfc6aa5cSAndroid Build Coastguard Worker */
476*dfc6aa5cSAndroid Build Coastguard Worker
477*dfc6aa5cSAndroid Build Coastguard Worker METHODDEF(void)
finish_input_tga(j_compress_ptr cinfo,cjpeg_source_ptr sinfo)478*dfc6aa5cSAndroid Build Coastguard Worker finish_input_tga(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
479*dfc6aa5cSAndroid Build Coastguard Worker {
480*dfc6aa5cSAndroid Build Coastguard Worker /* no work */
481*dfc6aa5cSAndroid Build Coastguard Worker }
482*dfc6aa5cSAndroid Build Coastguard Worker
483*dfc6aa5cSAndroid Build Coastguard Worker
484*dfc6aa5cSAndroid Build Coastguard Worker /*
485*dfc6aa5cSAndroid Build Coastguard Worker * The module selection routine for Targa format input.
486*dfc6aa5cSAndroid Build Coastguard Worker */
487*dfc6aa5cSAndroid Build Coastguard Worker
488*dfc6aa5cSAndroid Build Coastguard Worker GLOBAL(cjpeg_source_ptr)
jinit_read_targa(j_compress_ptr cinfo)489*dfc6aa5cSAndroid Build Coastguard Worker jinit_read_targa(j_compress_ptr cinfo)
490*dfc6aa5cSAndroid Build Coastguard Worker {
491*dfc6aa5cSAndroid Build Coastguard Worker tga_source_ptr source;
492*dfc6aa5cSAndroid Build Coastguard Worker
493*dfc6aa5cSAndroid Build Coastguard Worker /* Create module interface object */
494*dfc6aa5cSAndroid Build Coastguard Worker source = (tga_source_ptr)
495*dfc6aa5cSAndroid Build Coastguard Worker (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
496*dfc6aa5cSAndroid Build Coastguard Worker sizeof(tga_source_struct));
497*dfc6aa5cSAndroid Build Coastguard Worker source->cinfo = cinfo; /* make back link for subroutines */
498*dfc6aa5cSAndroid Build Coastguard Worker /* Fill in method ptrs, except get_pixel_rows which start_input sets */
499*dfc6aa5cSAndroid Build Coastguard Worker source->pub.start_input = start_input_tga;
500*dfc6aa5cSAndroid Build Coastguard Worker source->pub.finish_input = finish_input_tga;
501*dfc6aa5cSAndroid Build Coastguard Worker #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
502*dfc6aa5cSAndroid Build Coastguard Worker source->pub.max_pixels = 0;
503*dfc6aa5cSAndroid Build Coastguard Worker #endif
504*dfc6aa5cSAndroid Build Coastguard Worker
505*dfc6aa5cSAndroid Build Coastguard Worker return (cjpeg_source_ptr)source;
506*dfc6aa5cSAndroid Build Coastguard Worker }
507*dfc6aa5cSAndroid Build Coastguard Worker
508*dfc6aa5cSAndroid Build Coastguard Worker #endif /* TARGA_SUPPORTED */
509