/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 | } |