Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/contrib/pcl3/eprn/mediasize.c
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
  File:     $Id: mediasize.c,v 1.11 2001/04/12 18:35:26 Martin Rel $
3
  Contents: Operations and data for handling media sizes
4
  Author:   Martin Lottermoser, Greifswaldstrasse 28, 38124 Braunschweig,
5
            Germany. E-mail: Martin.Lottermoser@t-online.de.
6
7
*******************************************************************************
8
*                       *
9
* Copyright (C) 1999, 2000 by Martin Lottermoser            *
10
* All rights reserved                 *
11
*                       *
12
******************************************************************************/
13
14
/*****************************************************************************/
15
16
#ifndef _XOPEN_SOURCE
17
#define _XOPEN_SOURCE 500
18
#endif
19
20
#include "std.h"
21
22
/* Standard headers */
23
#include <assert_.h>
24
#include <errno.h>
25
#include <stdlib.h>
26
#include <string.h>
27
28
/* Special headers */
29
#include "mediasize.h"
30
31
/*****************************************************************************/
32
33
/* Number of elements in an array */
34
0
#define array_size(a) (sizeof(a)/sizeof(a[0]))
35
36
/* String length of string literals */
37
0
#define STRLEN(s) (sizeof(s) - 1)
38
39
/*****************************************************************************/
40
41
/* To ensure consistency I generate the size constant and the name from the
42
   keyword: */
43
#define sn(keyword) ms_##keyword, #keyword
44
45
/*  Size list
46
47
    This list is ordered such that the size code is the index in the list and
48
    that entries are sorted by first and second dimension except at the end.
49
    If you compile without NDEBUG being defined these constraints will be
50
    checked at runtime before they are needed for the first time.
51
52
    The information on the sizes is mostly taken from table B.2 in PPD 4.3.
53
54
    The extensions for the A and ISO B series agree with DIN 476 part 1
55
    (February 1991) which is the German version of EN 20216:1990 which in turn
56
    is identical with ISO 216:1975. The C series values agree with DIN 476
57
    part 2 (February 1991). Some values for the A and C series are not listed
58
    in PPD 4.3 and are taken from DIN 476.
59
 */
60
static const ms_SizeDescription list[] = {
61
  {ms_none, "",   {0.0,   0.0}},  /* never returned */
62
  {sn(A10),   {26*BP_PER_MM,  37*BP_PER_MM}},
63
  {sn(EnvC10),    {28*BP_PER_MM,  40*BP_PER_MM}}, /* DIN 476 T2: 1991 */
64
  {sn(ISOB10),    {31*BP_PER_MM,  44*BP_PER_MM}},
65
  {sn(JISB10),    {32*BP_PER_MM,  45*BP_PER_MM}},
66
  {sn(A9),    {37*BP_PER_MM,  52*BP_PER_MM}},
67
  {sn(EnvC9),   {40*BP_PER_MM,  57*BP_PER_MM}}, /* DIN 476 T2: 1991 */
68
  {sn(ISOB9),   {44*BP_PER_MM,  62*BP_PER_MM}},
69
  {sn(JISB9),   {45*BP_PER_MM,  64*BP_PER_MM}},
70
  {sn(A8),    {52*BP_PER_MM,  74*BP_PER_MM}},
71
  {sn(EnvC8),   {57*BP_PER_MM,  81*BP_PER_MM}}, /* DIN 476 T2: 1991 */
72
  {sn(ISOB8),   {62*BP_PER_MM,  88*BP_PER_MM}},
73
  {sn(JISB8),   {64*BP_PER_MM,  91*BP_PER_MM}},
74
  {sn(A7),    {74*BP_PER_MM,  105*BP_PER_MM}},
75
  {sn(Index3x5in),  {3*BP_PER_IN, 5*BP_PER_IN}},       /* 76.2 x 127 mm */
76
  {sn(EnvC7),   {81*BP_PER_MM,  114*BP_PER_MM}},
77
  {sn(ISOB7),   {88*BP_PER_MM,  125*BP_PER_MM}},
78
  {sn(EnvChou4),  {90*BP_PER_MM,  205*BP_PER_MM}},
79
  {sn(JISB7),   {91*BP_PER_MM,  128*BP_PER_MM}},
80
  {sn(EnvMonarch),  {3.875*BP_PER_IN, 7.5*BP_PER_IN}}, /* 98.4 x 190.5 mm */
81
  {sn(Env9),    {3.875*BP_PER_IN, 8.875*BP_PER_IN}}, /* 98.4x225.4 mm */
82
  {sn(Postcard),  {100*BP_PER_MM, 148*BP_PER_MM}},
83
  {sn(Index4x6in),  {4.0*BP_PER_IN, 6.0*BP_PER_IN}},  /* 101.6 x 152.4 mm */
84
  {sn(Env10),   {4.125*BP_PER_IN, 9.5*BP_PER_IN}}, /* 104.8 x 241.3 mm*/
85
  {sn(A6),    {105*BP_PER_MM, 148*BP_PER_MM}},
86
  {sn(EnvDL),   {110*BP_PER_MM, 220*BP_PER_MM}},
87
  {sn(EnvUS_A2),  {4.375*BP_PER_IN, 5.75*BP_PER_IN}}, /* 111.1x146.1 mm */
88
  {sn(EnvC6),   {114*BP_PER_MM, 162*BP_PER_MM}},
89
  {sn(EnvChou3),  {120*BP_PER_MM, 235*BP_PER_MM}},
90
  {sn(ISOB6),   {125*BP_PER_MM, 176*BP_PER_MM}},
91
  {sn(Index5x8in),  {5.0*BP_PER_IN, 8.0*BP_PER_IN}},    /* 127 x 203.2 mm */
92
  {sn(JISB6),   {128*BP_PER_MM, 182*BP_PER_MM}},
93
  {sn(Statement), {5.5*BP_PER_IN, 8.5*BP_PER_IN}},  /* 139.7 x 215.9 mm */
94
  {sn(DoublePostcard),  {148*BP_PER_MM, 200*BP_PER_MM}},
95
  {sn(A5),    {148*BP_PER_MM, 210*BP_PER_MM}},
96
  {sn(EnvC5),   {162*BP_PER_MM, 229*BP_PER_MM}},
97
  {sn(ISOB5),   {176*BP_PER_MM, 250*BP_PER_MM}},
98
  {sn(JISB5),   {182*BP_PER_MM, 257*BP_PER_MM}},
99
  {sn(Executive), {7.25*BP_PER_IN, 10.5*BP_PER_IN}}, /* 184.2 x 266.7 mm*/
100
    /* Media called by this name may vary up to 0.5" in dimension (PPD 4.3). */
101
  {sn(A4),    {210*BP_PER_MM, 297*BP_PER_MM}},
102
  {sn(Folio),   {210*BP_PER_MM, 330*BP_PER_MM}},
103
  {sn(Quarto),    {8.5f*BP_PER_IN,  10.83f*BP_PER_IN}},  /* 215.9 x 275.1 mm
104
        PPD 4.3 uses bp values for the definition, but this does not agree
105
        with the mm values it specifies. The inch specifications fit. */
106
  {sn(Letter),    {8.5f*BP_PER_IN,  11.0f*BP_PER_IN}}, /* 215.9 x 279.4 mm */
107
  {sn(Legal),   {8.5f*BP_PER_IN,  14.0f*BP_PER_IN}}, /* 215.9 x 355.6 mm */
108
  {sn(EnvKaku3),  {216*BP_PER_MM, 277*BP_PER_MM}},
109
  {sn(SuperA),    {227*BP_PER_MM, 356*BP_PER_MM}},
110
  {sn(ARCHA),   {9*BP_PER_IN, 12*BP_PER_IN}},   /* 228.6 x 304.8 mm */
111
  {sn(EnvC4),   {229*BP_PER_MM, 324*BP_PER_MM}},
112
  {sn(EnvKaku2),  {240*BP_PER_MM, 332*BP_PER_MM}},
113
  {sn(ISOB4),   {250*BP_PER_MM, 353*BP_PER_MM}},
114
  {sn(JISB4),   {257*BP_PER_MM, 364*BP_PER_MM}},
115
  {sn(Tabloid),   {11*BP_PER_IN,  17*BP_PER_IN}},   /* 279.4 x 431.8 mm */
116
  {sn(A3),    {297*BP_PER_MM, 420*BP_PER_MM}},
117
  {sn(ARCHB),   {12*BP_PER_IN,  18*BP_PER_IN}},   /* 304.8 x 457.2 mm */
118
  {sn(SuperB),    {305*BP_PER_MM, 487*BP_PER_MM}},
119
  {sn(EnvC3),   {324*BP_PER_MM, 458*BP_PER_MM}},
120
  {sn(HPSuperB),  {13*BP_PER_IN,  19*BP_PER_IN}},   /* 330.2 x 482.6 mm */
121
  {sn(ISOB3),   {353*BP_PER_MM, 500*BP_PER_MM}},
122
  {sn(JISB3),   {364*BP_PER_MM, 515*BP_PER_MM}},
123
  {sn(A2),    {420*BP_PER_MM, 594*BP_PER_MM}},
124
  {sn(ARCHC),   {18*BP_PER_IN,  24*BP_PER_IN}},   /* 457.2 x 609.6 mm */
125
  {sn(EnvC2),   {458*BP_PER_MM, 648*BP_PER_MM}},
126
  {sn(ISOB2),   {500*BP_PER_MM, 707*BP_PER_MM}},
127
  {sn(JISB2),   {515*BP_PER_MM, 728*BP_PER_MM}},
128
  {sn(A1),    {594*BP_PER_MM, 841*BP_PER_MM}},
129
  {sn(ARCHD),   {24*BP_PER_IN,  36*BP_PER_IN}},   /* 609.6 x 914.4 mm */
130
  {sn(EnvC1),   {648*BP_PER_MM, 917*BP_PER_MM}},
131
  {sn(ISOB1),   {707*BP_PER_MM, 1000*BP_PER_MM}},
132
  {sn(JISB1),   {728*BP_PER_MM, 1030*BP_PER_MM}},
133
  {sn(A0),    {841*BP_PER_MM, 1189*BP_PER_MM}},
134
  {sn(ARCHE),   {36*BP_PER_IN,  48*BP_PER_IN}},  /* 914.4 x 1219.2 mm */
135
  {sn(EnvC0),   {917*BP_PER_MM, 1297*BP_PER_MM}},
136
  {sn(ISOB0),   {1000*BP_PER_MM, 1414*BP_PER_MM}},
137
  {sn(JISB0),   {1030*BP_PER_MM, 1456*BP_PER_MM}},
138
  {sn(2A0),   {1189*BP_PER_MM, 1682*BP_PER_MM}}, /* DIN 476 T1:1991 */
139
  {sn(4A0),   {1682*BP_PER_MM, 2378*BP_PER_MM}}, /* DIN 476 T1:1991 */
140
  /* End of discrete sizes */
141
  {sn(CustomPageSize),  {0.0, 0.0}},
142
  {sn(MaxPage),   {0.0, 0.0}}
143
};
144
145
#undef sn
146
147
/* Constant which is at least 1 longer than the longest known name */
148
0
#define LONGER_THAN_NAMES 15
149
150
/*****************************************************************************/
151
152
#undef CHECK_CONSTRAINTS
153
154
#ifdef CHECK_CONSTRAINTS
155
static char checked = 0;
156
157
/* Function to check constraints on table entries */
158
static void check(void)
159
{
160
  int j;
161
162
  /* ms_none */
163
  assert(list[0].size == 0);
164
165
  for (j = 1; j < array_size(list); j++) {
166
    assert(list[j].size == j);
167
    assert(list[j].dimen[0] <= list[j].dimen[1]);
168
    assert(strlen(list[j].name) < LONGER_THAN_NAMES);
169
    assert(list[j].dimen[0] == 0.0 || list[j-1].dimen[0] < list[j].dimen[0] ||
170
           (list[j-1].dimen[0] == list[j].dimen[0] &&
171
            list[j-1].dimen[1] <= list[j].dimen[1]));
172
  }
173
174
  /* Check that the highest accepted value does not collide with the flags */
175
  assert((ms_MaxPage & MS_FLAG_MASK) == 0);
176
177
  checked = 1;
178
179
  return;
180
}
181
182
#endif  /* !NDEBUG */
183
184
/*****************************************************************************/
185
186
const ms_SizeDescription *ms_find_size_from_code(ms_MediaCode code)
187
0
{
188
#ifdef CHECK_CONSTRAINTS
189
  if (!checked) check();
190
#endif
191
0
  code = ms_without_flags(code);
192
0
  if (code < 1 || array_size(list) <= code) return NULL;
193
194
0
  return list + code;
195
0
}
196
197
/*****************************************************************************/
198
199
/* Function to compare two pointers to 'ms_SizeDescription *' by the 'name'
200
   fields pointed to. */
201
202
static int cmp_by_name(const void *a, const void *b)
203
0
{
204
0
  return strcmp((*(const ms_SizeDescription *const *)a)->name,
205
0
    (*(const ms_SizeDescription *const *)b)->name);
206
0
}
207
208
/******************************************************************************
209
210
  Function: find_flag
211
212
  This function searches for a number of flags at the end of 'name' which is
213
  taken to be a string of length '*length'. If a matching entry is found,
214
  '*length' is decreased by the length of the string matched and the flag value
215
  is returned. On failure, the return value is zero and '*length' is not
216
  modified.
217
218
******************************************************************************/
219
220
static ms_MediaCode find_flag(const char *name, size_t *length,
221
  const ms_Flag *flag_list)
222
0
{
223
0
  int j = 0;
224
0
  size_t L;
225
226
0
  while (flag_list[j].code != 0 &&
227
0
    ((L = strlen(flag_list[j].name)) >= *length ||
228
0
      strncmp(name + *length - L, flag_list[j].name, L) != 0)) j++;
229
0
  if (flag_list[j].code == 0) return 0;
230
231
0
  *length -= L;
232
233
0
  return flag_list[j].code;
234
0
}
235
236
/*****************************************************************************/
237
238
/* Table of standard substrings, sorted in the order preferred for name
239
   generation */
240
static const ms_Flag substrings[] = {
241
  {MS_BIG_FLAG,   MS_BIG_STRING},
242
  {MS_SMALL_FLAG, MS_SMALL_STRING},
243
  {MS_ROTATED_FLAG, MS_ROTATED_STRING},
244
  {MS_EXTRA_FLAG, MS_EXTRA_STRING},
245
  {0, NULL}
246
};
247
248
/* If you get an error when compiling the following, then MAX_MEDIASIZES
249
 * (defined in pcltables.h) must be increased. */
250
typedef struct
251
{
252
        char compile_time_assert[array_size(list) <= MAX_MEDIASIZES ? 1 : -1];
253
} compile_time_assert_for_list_length;
254
255
/*****************************************************************************/
256
257
ms_MediaCode ms_find_code_from_name(mediasize_table *tables,
258
                                    const char *name,
259
                                    const ms_Flag *user_flag_list)
260
0
{
261
0
  const char *end;
262
0
  char stripped_name[LONGER_THAN_NAMES];
263
0
  ms_SizeDescription
264
0
    keydata,
265
0
    *key = &keydata;
266
0
  const ms_SizeDescription **found;
267
0
  ms_MediaCode flags = 0;
268
0
  size_t l;
269
270
  /* On the first use of this function, compile a table of pointers into the
271
     list which is sorted by the names of the sizes. */
272
0
  if (tables->mediasize_list_inited == 0) {
273
0
    int entries = 1; /* ignore 'ms_none' */
274
0
    while (entries < array_size(list)) {
275
0
      tables->mediasize_list[entries] = list + entries;
276
0
      entries++;
277
0
    }
278
0
    qsort(tables->mediasize_list, array_size(list) - 1, sizeof(ms_SizeDescription *), &cmp_by_name);
279
0
    tables->mediasize_list_inited = 1;
280
0
  }
281
282
  /* Prevent idiots (like myself) from crashing the routine */
283
0
  if (name == NULL) return ms_none;
284
285
  /* Identify trailing qualifiers */
286
0
  end = strchr(name, '.');  /* before first qualifier */
287
0
  if (end == NULL) end = strchr(name, '\0');
288
0
  else {
289
0
    const char *s = end, *t;
290
0
    do {
291
0
      ms_MediaCode flag;
292
293
0
      s++;
294
0
      if ((t = strchr(s, '.')) == NULL) t = strchr(s, '\0');
295
0
      l = t - s;
296
0
#define set_if(keyword)         \
297
0
        if (l == STRLEN(MS_##keyword##_STRING) &&  \
298
0
          strncmp(s, MS_##keyword##_STRING, l) == 0) flag = MS_##keyword##_FLAG
299
0
      set_if(TRANSVERSE);
300
0
      else set_if(BIG);
301
0
      else set_if(SMALL);
302
0
      else set_if(EXTRA);
303
0
      else return ms_none;
304
0
#undef set_if
305
0
      if ((flag & flags) != 0) return ms_none; /* no duplicates */
306
0
      flags |= flag;
307
0
      s = t;
308
0
    } while (*t != '\0');
309
0
  }
310
311
  /* Now search for recognizable substrings */
312
0
  l = end - name; /* length of uninterpreted part of the name */
313
0
  while (1) {
314
0
    ms_MediaCode flag;
315
316
0
    if ((flag = find_flag(name, &l, substrings)) == 0 &&
317
0
        (user_flag_list == NULL ||
318
0
           (flag = find_flag(name, &l, user_flag_list)) == 0))
319
0
      break; /* loop exit */
320
321
0
    if ((flag & flags) != 0) return ms_none; /* no duplicates */
322
0
    flags |= flag;
323
0
  }
324
0
  end = name + l;
325
326
0
  if ((flags & MS_BIG_FLAG) != 0 && (flags & MS_SMALL_FLAG) != 0)
327
0
    return ms_none;
328
329
  /* Prepare key for looking up the size part of the name */
330
0
  l = end - name;
331
0
  if (l >= LONGER_THAN_NAMES) return ms_none;
332
0
  strncpy(stripped_name, name, l);
333
0
  stripped_name[l] = '\0';
334
0
  keydata.name = stripped_name;
335
336
  /* Search */
337
0
  found = (const ms_SizeDescription **)bsearch(&key, tables->mediasize_list, array_size(list) - 1,
338
0
    sizeof(ms_SizeDescription *), &cmp_by_name);
339
340
0
  return found == NULL? ms_none: ((*found)->size | flags);
341
0
}
342
343
/******************************************************************************
344
345
  Function: add_substrings
346
347
  This function appends names for the flags in '*code' to 'buffer', identifying
348
  flags by means of 'flag_list' which must be terminated with an entry having
349
  'code' == 0.
350
351
  'buffer' must point to a NUL-terminated string, '*length' must be the number
352
  of characters which this routine may write after the NUL.
353
354
  The function will return zero on success and a non-zero value of error.
355
  All flags matched will be removed from '*code' and '*length' will be updated
356
  to reflect the number of characters still available.
357
358
******************************************************************************/
359
360
static int add_substrings(char *buffer, size_t *length, ms_MediaCode *code,
361
  const ms_Flag *flag_list)
362
0
{
363
0
  int j;
364
0
  size_t l;
365
366
0
  j = 0;
367
0
  buffer = strchr(buffer, '\0');
368
0
  while (flag_list[j].code != 0) {
369
0
    if (flag_list[j].code & *code) {
370
0
      l = strlen(flag_list[j].name);
371
0
      if (*length < l) {
372
0
        errno = ERANGE;
373
0
        return -1;
374
0
      }
375
0
      *code &= ~flag_list[j].code;
376
0
      strcpy(buffer, flag_list[j].name);
377
0
      buffer += l;
378
0
      *length -= l;
379
0
    }
380
0
    j++;
381
0
  }
382
383
0
  return 0;
384
0
}
385
386
/*****************************************************************************/
387
388
extern int ms_find_name_from_code(char *buffer, size_t length,
389
  ms_MediaCode code, const ms_Flag *user_flag_list)
390
0
{
391
0
  const ms_SizeDescription *desc = ms_find_size_from_code(code);
392
0
  size_t l;
393
394
0
  if (buffer == NULL || length == 0) {
395
0
    errno = EINVAL;
396
0
    return -1;
397
0
  }
398
399
  /* Size name */
400
0
  if (desc == NULL) {
401
0
    errno = EDOM;
402
0
    return -1;
403
0
  }
404
0
  l = strlen(desc->name);
405
0
  if (length <= l) {
406
0
    errno = ERANGE;
407
0
    return -1;
408
0
  }
409
0
  strcpy(buffer, desc->name);
410
0
  length -= l + 1;
411
0
  code = ms_flags(code);
412
413
  /* Substrings */
414
0
  if ((user_flag_list != NULL &&
415
0
       add_substrings(buffer, &length, &code, user_flag_list) != 0) ||
416
0
      add_substrings(buffer, &length, &code, substrings) != 0) return -1;
417
418
  /* Transverse qualifier */
419
0
  if (code & MS_TRANSVERSE_FLAG) {
420
0
    if (length < 1 + STRLEN(MS_TRANSVERSE_STRING)) {
421
0
      errno = ERANGE;
422
0
      return -1;
423
0
    }
424
0
    strcat(buffer, "." MS_TRANSVERSE_STRING);
425
0
    code &= ~MS_TRANSVERSE_FLAG;
426
0
  }
427
428
  /* Check for unrecognized flags */
429
0
  if (code != 0) {
430
0
    errno = EDOM;
431
0
    return -1;
432
0
  }
433
434
0
  return 0;
435
0
}