Coverage Report

Created: 2025-07-01 06:27

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