Coverage Report

Created: 2023-06-07 06:03

/src/libjpeg-turbo.2.0.x/rdswitch.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * rdswitch.c
3
 *
4
 * This file was part of the Independent JPEG Group's software:
5
 * Copyright (C) 1991-1996, Thomas G. Lane.
6
 * libjpeg-turbo Modifications:
7
 * Copyright (C) 2010, 2018, D. R. Commander.
8
 * For conditions of distribution and use, see the accompanying README.ijg
9
 * file.
10
 *
11
 * This file contains routines to process some of cjpeg's more complicated
12
 * command-line switches.  Switches processed here are:
13
 *      -qtables file           Read quantization tables from text file
14
 *      -scans file             Read scan script from text file
15
 *      -quality N[,N,...]      Set quality ratings
16
 *      -qslots N[,N,...]       Set component quantization table selectors
17
 *      -sample HxV[,HxV,...]   Set component sampling factors
18
 */
19
20
#include "cdjpeg.h"             /* Common decls for cjpeg/djpeg applications */
21
#include <ctype.h>              /* to declare isdigit(), isspace() */
22
23
24
LOCAL(int)
25
text_getc(FILE *file)
26
/* Read next char, skipping over any comments (# to end of line) */
27
/* A comment/newline sequence is returned as a newline */
28
0
{
29
0
  register int ch;
30
31
0
  ch = getc(file);
32
0
  if (ch == '#') {
33
0
    do {
34
0
      ch = getc(file);
35
0
    } while (ch != '\n' && ch != EOF);
36
0
  }
37
0
  return ch;
38
0
}
39
40
41
LOCAL(boolean)
42
read_text_integer(FILE *file, long *result, int *termchar)
43
/* Read an unsigned decimal integer from a file, store it in result */
44
/* Reads one trailing character after the integer; returns it in termchar */
45
0
{
46
0
  register int ch;
47
0
  register long val;
48
49
  /* Skip any leading whitespace, detect EOF */
50
0
  do {
51
0
    ch = text_getc(file);
52
0
    if (ch == EOF) {
53
0
      *termchar = ch;
54
0
      return FALSE;
55
0
    }
56
0
  } while (isspace(ch));
57
58
0
  if (!isdigit(ch)) {
59
0
    *termchar = ch;
60
0
    return FALSE;
61
0
  }
62
63
0
  val = ch - '0';
64
0
  while ((ch = text_getc(file)) != EOF) {
65
0
    if (!isdigit(ch))
66
0
      break;
67
0
    val *= 10;
68
0
    val += ch - '0';
69
0
  }
70
0
  *result = val;
71
0
  *termchar = ch;
72
0
  return TRUE;
73
0
}
74
75
76
#if JPEG_LIB_VERSION < 70
77
static int q_scale_factor[NUM_QUANT_TBLS] = { 100, 100, 100, 100 };
78
#endif
79
80
GLOBAL(boolean)
81
read_quant_tables(j_compress_ptr cinfo, char *filename, boolean force_baseline)
82
/* Read a set of quantization tables from the specified file.
83
 * The file is plain ASCII text: decimal numbers with whitespace between.
84
 * Comments preceded by '#' may be included in the file.
85
 * There may be one to NUM_QUANT_TBLS tables in the file, each of 64 values.
86
 * The tables are implicitly numbered 0,1,etc.
87
 * NOTE: does not affect the qslots mapping, which will default to selecting
88
 * table 0 for luminance (or primary) components, 1 for chrominance components.
89
 * You must use -qslots if you want a different component->table mapping.
90
 */
91
0
{
92
0
  FILE *fp;
93
0
  int tblno, i, termchar;
94
0
  long val;
95
0
  unsigned int table[DCTSIZE2];
96
97
0
  if ((fp = fopen(filename, "r")) == NULL) {
98
0
    fprintf(stderr, "Can't open table file %s\n", filename);
99
0
    return FALSE;
100
0
  }
101
0
  tblno = 0;
102
103
0
  while (read_text_integer(fp, &val, &termchar)) { /* read 1st element of table */
104
0
    if (tblno >= NUM_QUANT_TBLS) {
105
0
      fprintf(stderr, "Too many tables in file %s\n", filename);
106
0
      fclose(fp);
107
0
      return FALSE;
108
0
    }
109
0
    table[0] = (unsigned int)val;
110
0
    for (i = 1; i < DCTSIZE2; i++) {
111
0
      if (!read_text_integer(fp, &val, &termchar)) {
112
0
        fprintf(stderr, "Invalid table data in file %s\n", filename);
113
0
        fclose(fp);
114
0
        return FALSE;
115
0
      }
116
0
      table[i] = (unsigned int)val;
117
0
    }
118
#if JPEG_LIB_VERSION >= 70
119
    jpeg_add_quant_table(cinfo, tblno, table, cinfo->q_scale_factor[tblno],
120
                         force_baseline);
121
#else
122
0
    jpeg_add_quant_table(cinfo, tblno, table, q_scale_factor[tblno],
123
0
                         force_baseline);
124
0
#endif
125
0
    tblno++;
126
0
  }
127
128
0
  if (termchar != EOF) {
129
0
    fprintf(stderr, "Non-numeric data in file %s\n", filename);
130
0
    fclose(fp);
131
0
    return FALSE;
132
0
  }
133
134
0
  fclose(fp);
135
0
  return TRUE;
136
0
}
137
138
139
#ifdef C_MULTISCAN_FILES_SUPPORTED
140
141
LOCAL(boolean)
142
read_scan_integer(FILE *file, long *result, int *termchar)
143
/* Variant of read_text_integer that always looks for a non-space termchar;
144
 * this simplifies parsing of punctuation in scan scripts.
145
 */
146
0
{
147
0
  register int ch;
148
149
0
  if (!read_text_integer(file, result, termchar))
150
0
    return FALSE;
151
0
  ch = *termchar;
152
0
  while (ch != EOF && isspace(ch))
153
0
    ch = text_getc(file);
154
0
  if (isdigit(ch)) {            /* oops, put it back */
155
0
    if (ungetc(ch, file) == EOF)
156
0
      return FALSE;
157
0
    ch = ' ';
158
0
  } else {
159
    /* Any separators other than ';' and ':' are ignored;
160
     * this allows user to insert commas, etc, if desired.
161
     */
162
0
    if (ch != EOF && ch != ';' && ch != ':')
163
0
      ch = ' ';
164
0
  }
165
0
  *termchar = ch;
166
0
  return TRUE;
167
0
}
168
169
170
GLOBAL(boolean)
171
read_scan_script(j_compress_ptr cinfo, char *filename)
172
/* Read a scan script from the specified text file.
173
 * Each entry in the file defines one scan to be emitted.
174
 * Entries are separated by semicolons ';'.
175
 * An entry contains one to four component indexes,
176
 * optionally followed by a colon ':' and four progressive-JPEG parameters.
177
 * The component indexes denote which component(s) are to be transmitted
178
 * in the current scan.  The first component has index 0.
179
 * Sequential JPEG is used if the progressive-JPEG parameters are omitted.
180
 * The file is free format text: any whitespace may appear between numbers
181
 * and the ':' and ';' punctuation marks.  Also, other punctuation (such
182
 * as commas or dashes) can be placed between numbers if desired.
183
 * Comments preceded by '#' may be included in the file.
184
 * Note: we do very little validity checking here;
185
 * jcmaster.c will validate the script parameters.
186
 */
187
0
{
188
0
  FILE *fp;
189
0
  int scanno, ncomps, termchar;
190
0
  long val;
191
0
  jpeg_scan_info *scanptr;
192
0
#define MAX_SCANS  100          /* quite arbitrary limit */
193
0
  jpeg_scan_info scans[MAX_SCANS];
194
195
0
  if ((fp = fopen(filename, "r")) == NULL) {
196
0
    fprintf(stderr, "Can't open scan definition file %s\n", filename);
197
0
    return FALSE;
198
0
  }
199
0
  scanptr = scans;
200
0
  scanno = 0;
201
202
0
  while (read_scan_integer(fp, &val, &termchar)) {
203
0
    if (scanno >= MAX_SCANS) {
204
0
      fprintf(stderr, "Too many scans defined in file %s\n", filename);
205
0
      fclose(fp);
206
0
      return FALSE;
207
0
    }
208
0
    scanptr->component_index[0] = (int)val;
209
0
    ncomps = 1;
210
0
    while (termchar == ' ') {
211
0
      if (ncomps >= MAX_COMPS_IN_SCAN) {
212
0
        fprintf(stderr, "Too many components in one scan in file %s\n",
213
0
                filename);
214
0
        fclose(fp);
215
0
        return FALSE;
216
0
      }
217
0
      if (!read_scan_integer(fp, &val, &termchar))
218
0
        goto bogus;
219
0
      scanptr->component_index[ncomps] = (int)val;
220
0
      ncomps++;
221
0
    }
222
0
    scanptr->comps_in_scan = ncomps;
223
0
    if (termchar == ':') {
224
0
      if (!read_scan_integer(fp, &val, &termchar) || termchar != ' ')
225
0
        goto bogus;
226
0
      scanptr->Ss = (int)val;
227
0
      if (!read_scan_integer(fp, &val, &termchar) || termchar != ' ')
228
0
        goto bogus;
229
0
      scanptr->Se = (int)val;
230
0
      if (!read_scan_integer(fp, &val, &termchar) || termchar != ' ')
231
0
        goto bogus;
232
0
      scanptr->Ah = (int)val;
233
0
      if (!read_scan_integer(fp, &val, &termchar))
234
0
        goto bogus;
235
0
      scanptr->Al = (int)val;
236
0
    } else {
237
      /* set non-progressive parameters */
238
0
      scanptr->Ss = 0;
239
0
      scanptr->Se = DCTSIZE2 - 1;
240
0
      scanptr->Ah = 0;
241
0
      scanptr->Al = 0;
242
0
    }
243
0
    if (termchar != ';' && termchar != EOF) {
244
0
bogus:
245
0
      fprintf(stderr, "Invalid scan entry format in file %s\n", filename);
246
0
      fclose(fp);
247
0
      return FALSE;
248
0
    }
249
0
    scanptr++, scanno++;
250
0
  }
251
252
0
  if (termchar != EOF) {
253
0
    fprintf(stderr, "Non-numeric data in file %s\n", filename);
254
0
    fclose(fp);
255
0
    return FALSE;
256
0
  }
257
258
0
  if (scanno > 0) {
259
    /* Stash completed scan list in cinfo structure.
260
     * NOTE: for cjpeg's use, JPOOL_IMAGE is the right lifetime for this data,
261
     * but if you want to compress multiple images you'd want JPOOL_PERMANENT.
262
     */
263
0
    scanptr = (jpeg_scan_info *)
264
0
      (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE,
265
0
                                  scanno * sizeof(jpeg_scan_info));
266
0
    MEMCOPY(scanptr, scans, scanno * sizeof(jpeg_scan_info));
267
0
    cinfo->scan_info = scanptr;
268
0
    cinfo->num_scans = scanno;
269
0
  }
270
271
0
  fclose(fp);
272
0
  return TRUE;
273
0
}
274
275
#endif /* C_MULTISCAN_FILES_SUPPORTED */
276
277
278
#if JPEG_LIB_VERSION < 70
279
/* These are the sample quantization tables given in Annex K (Clause K.1) of
280
 * Recommendation ITU-T T.81 (1992) | ISO/IEC 10918-1:1994.
281
 * The spec says that the values given produce "good" quality, and
282
 * when divided by 2, "very good" quality.
283
 */
284
static const unsigned int std_luminance_quant_tbl[DCTSIZE2] = {
285
  16,  11,  10,  16,  24,  40,  51,  61,
286
  12,  12,  14,  19,  26,  58,  60,  55,
287
  14,  13,  16,  24,  40,  57,  69,  56,
288
  14,  17,  22,  29,  51,  87,  80,  62,
289
  18,  22,  37,  56,  68, 109, 103,  77,
290
  24,  35,  55,  64,  81, 104, 113,  92,
291
  49,  64,  78,  87, 103, 121, 120, 101,
292
  72,  92,  95,  98, 112, 100, 103,  99
293
};
294
static const unsigned int std_chrominance_quant_tbl[DCTSIZE2] = {
295
  17,  18,  24,  47,  99,  99,  99,  99,
296
  18,  21,  26,  66,  99,  99,  99,  99,
297
  24,  26,  56,  99,  99,  99,  99,  99,
298
  47,  66,  99,  99,  99,  99,  99,  99,
299
  99,  99,  99,  99,  99,  99,  99,  99,
300
  99,  99,  99,  99,  99,  99,  99,  99,
301
  99,  99,  99,  99,  99,  99,  99,  99,
302
  99,  99,  99,  99,  99,  99,  99,  99
303
};
304
305
306
LOCAL(void)
307
jpeg_default_qtables(j_compress_ptr cinfo, boolean force_baseline)
308
10.6k
{
309
10.6k
  jpeg_add_quant_table(cinfo, 0, std_luminance_quant_tbl, q_scale_factor[0],
310
10.6k
                       force_baseline);
311
10.6k
  jpeg_add_quant_table(cinfo, 1, std_chrominance_quant_tbl, q_scale_factor[1],
312
10.6k
                       force_baseline);
313
10.6k
}
314
#endif
315
316
317
GLOBAL(boolean)
318
set_quality_ratings(j_compress_ptr cinfo, char *arg, boolean force_baseline)
319
/* Process a quality-ratings parameter string, of the form
320
 *     N[,N,...]
321
 * If there are more q-table slots than parameters, the last value is replicated.
322
 */
323
10.6k
{
324
10.6k
  int val = 75;                 /* default value */
325
10.6k
  int tblno;
326
10.6k
  char ch;
327
328
53.3k
  for (tblno = 0; tblno < NUM_QUANT_TBLS; tblno++) {
329
42.6k
    if (*arg) {
330
31.9k
      ch = ',';                 /* if not set by sscanf, will be ',' */
331
31.9k
      if (sscanf(arg, "%d%c", &val, &ch) < 1)
332
0
        return FALSE;
333
31.9k
      if (ch != ',')            /* syntax check */
334
0
        return FALSE;
335
      /* Convert user 0-100 rating to percentage scaling */
336
#if JPEG_LIB_VERSION >= 70
337
      cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
338
#else
339
31.9k
      q_scale_factor[tblno] = jpeg_quality_scaling(val);
340
31.9k
#endif
341
101k
      while (*arg && *arg++ != ','); /* advance to next segment of arg
342
                                        string */
343
31.9k
    } else {
344
      /* reached end of parameter, set remaining factors to last value */
345
#if JPEG_LIB_VERSION >= 70
346
      cinfo->q_scale_factor[tblno] = jpeg_quality_scaling(val);
347
#else
348
10.6k
      q_scale_factor[tblno] = jpeg_quality_scaling(val);
349
10.6k
#endif
350
10.6k
    }
351
42.6k
  }
352
10.6k
  jpeg_default_qtables(cinfo, force_baseline);
353
10.6k
  return TRUE;
354
10.6k
}
355
356
357
GLOBAL(boolean)
358
set_quant_slots(j_compress_ptr cinfo, char *arg)
359
/* Process a quantization-table-selectors parameter string, of the form
360
 *     N[,N,...]
361
 * If there are more components than parameters, the last value is replicated.
362
 */
363
0
{
364
0
  int val = 0;                  /* default table # */
365
0
  int ci;
366
0
  char ch;
367
368
0
  for (ci = 0; ci < MAX_COMPONENTS; ci++) {
369
0
    if (*arg) {
370
0
      ch = ',';                 /* if not set by sscanf, will be ',' */
371
0
      if (sscanf(arg, "%d%c", &val, &ch) < 1)
372
0
        return FALSE;
373
0
      if (ch != ',')            /* syntax check */
374
0
        return FALSE;
375
0
      if (val < 0 || val >= NUM_QUANT_TBLS) {
376
0
        fprintf(stderr, "JPEG quantization tables are numbered 0..%d\n",
377
0
                NUM_QUANT_TBLS - 1);
378
0
        return FALSE;
379
0
      }
380
0
      cinfo->comp_info[ci].quant_tbl_no = val;
381
0
      while (*arg && *arg++ != ','); /* advance to next segment of arg
382
                                        string */
383
0
    } else {
384
      /* reached end of parameter, set remaining components to last table */
385
0
      cinfo->comp_info[ci].quant_tbl_no = val;
386
0
    }
387
0
  }
388
0
  return TRUE;
389
0
}
390
391
392
GLOBAL(boolean)
393
set_sample_factors(j_compress_ptr cinfo, char *arg)
394
/* Process a sample-factors parameter string, of the form
395
 *     HxV[,HxV,...]
396
 * If there are more components than parameters, "1x1" is assumed for the rest.
397
 */
398
10.6k
{
399
10.6k
  int ci, val1, val2;
400
10.6k
  char ch1, ch2;
401
402
117k
  for (ci = 0; ci < MAX_COMPONENTS; ci++) {
403
106k
    if (*arg) {
404
21.3k
      ch2 = ',';                /* if not set by sscanf, will be ',' */
405
21.3k
      if (sscanf(arg, "%d%c%d%c", &val1, &ch1, &val2, &ch2) < 3)
406
0
        return FALSE;
407
21.3k
      if ((ch1 != 'x' && ch1 != 'X') || ch2 != ',') /* syntax check */
408
0
        return FALSE;
409
21.3k
      if (val1 <= 0 || val1 > 4 || val2 <= 0 || val2 > 4) {
410
0
        fprintf(stderr, "JPEG sampling factors must be 1..4\n");
411
0
        return FALSE;
412
0
      }
413
21.3k
      cinfo->comp_info[ci].h_samp_factor = val1;
414
21.3k
      cinfo->comp_info[ci].v_samp_factor = val2;
415
85.3k
      while (*arg && *arg++ != ',');  /* advance to next segment of arg
416
                                         string */
417
85.3k
    } else {
418
      /* reached end of parameter, set remaining components to 1x1 sampling */
419
85.3k
      cinfo->comp_info[ci].h_samp_factor = 1;
420
85.3k
      cinfo->comp_info[ci].v_samp_factor = 1;
421
85.3k
    }
422
106k
  }
423
10.6k
  return TRUE;
424
10.6k
}