xref: /plan9/sys/src/cmd/gs/src/dscparse.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 2000-2003, Ghostgum Software Pty Ltd.  All rights reserved.
2 
3   This software is provided AS-IS with no warranty, either express or
4   implied.
5 
6   This software is distributed under license and may not be copied,
7   modified or distributed except as expressly authorized under the terms
8   of the license contained in the file LICENSE in this distribution.
9 
10   For more information about licensing, please refer to
11   http://www.ghostscript.com/licensing/. For information on
12   commercial licensing, go to http://www.artifex.com/licensing/ or
13   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
15 */
16 
17 /* $Id: dscparse.c,v 1.14 2003/09/13 02:04:15 ghostgum Exp $ */
18 
19 /*
20  * This is a DSC parser, based on the DSC 3.0 spec,
21  * with a few DSC 2.1 additions for page size.
22  *
23  * Current limitations:
24  * %%+ may be used after any comment in the comment or trailer,
25  * but is currently only supported by
26  *   %%DocumentMedia
27  *
28  * DSC 2.1 additions (discontinued in DSC 3.0):
29  * %%DocumentPaperColors:
30  * %%DocumentPaperForms:
31  * %%DocumentPaperSizes:
32  * %%DocumentPaperWeights:
33  * %%PaperColor:   (ignored)
34  * %%PaperForm:    (ignored)
35  * %%PaperSize:
36  * %%PaperWeight:  (ignored)
37  *
38  * Other additions for defaults or page section
39  % %%ViewingOrientation: xx xy yx yy
40 */
41 
42 #include <stdio.h>	/* for sprintf(), not file I/O */
43 #include <stdlib.h>
44 #include <string.h>
45 #include <ctype.h>
46 
47 #define MAXSTR 256
48 
49 #include "dscparse.h"
50 
51 /* Macros for comparing string literals
52  * For maximum speed, the length of the second macro argument is
53  * computed at compile time.
54  * THE SECOND MACRO ARGUMENT MUST BE A STRING LITERAL.
55  */
56 #define COMPARE(p,str) (strncmp((const char *)(p), (str), sizeof(str)-1)==0)
57 #define IS_DSC(line, str) (COMPARE((line), (str)))
58 
59 /* Macros for comparing the first one or two characters */
60 #define IS_WHITE(ch) (((ch)==' ') || ((ch)=='\t'))
61 #define IS_EOL(ch) (((ch)=='\r') || ((ch)=='\n'))
62 #define IS_WHITE_OR_EOL(ch) (IS_WHITE(ch) || IS_EOL(ch))
63 #define IS_BLANK(str) (IS_EOL(str[0]))
64 #define NOT_DSC_LINE(str) (((str)[0]!='%') || ((str)[1]!='%'))
65 
66 /* Macros for document offset to start and end of line */
67 #define DSC_START(dsc)  ((dsc)->data_offset + (dsc)->data_index - (dsc)->line_length)
68 #define DSC_END(dsc)  ((dsc)->data_offset + (dsc)->data_index)
69 
70 /* dsc_scan_SECTION() functions return one of
71  * CDSC_ERROR, CDSC_OK, CDSC_NOTDSC
72  * or one of the following
73  */
74 /* The line should be passed on to the next section parser. */
75 #define CDSC_PROPAGATE	10
76 
77 /* If document is DOS EPS and we haven't read 30 bytes, ask for more. */
78 #define CDSC_NEEDMORE 11
79 
80 /* local prototypes */
81 dsc_private void * dsc_memalloc(CDSC *dsc, size_t size);
82 dsc_private void dsc_memfree(CDSC*dsc, void *ptr);
83 dsc_private CDSC * dsc_init2(CDSC *dsc);
84 dsc_private void dsc_reset(CDSC *dsc);
85 dsc_private void dsc_section_join(DSC_OFFSET begin, DSC_OFFSET *pend, DSC_OFFSET **pplast);
86 dsc_private int dsc_read_line(CDSC *dsc);
87 dsc_private int dsc_read_doseps(CDSC *dsc);
88 dsc_private int dsc_read_macbin(CDSC *dsc);
89 dsc_private int dsc_read_applesingle(CDSC *dsc);
90 dsc_private char * dsc_alloc_string(CDSC *dsc, const char *str, int len);
91 dsc_private char * dsc_add_line(CDSC *dsc, const char *line, unsigned int len);
92 dsc_private char * dsc_copy_string(char *str, unsigned int slen,
93     char *line, unsigned int len, unsigned int *offset);
94 dsc_private GSDWORD dsc_get_dword(const unsigned char *buf);
95 dsc_private GSWORD dsc_get_word(const unsigned char *buf);
96 dsc_private GSDWORD dsc_get_bigendian_dword(const unsigned char *buf);
97 dsc_private GSWORD dsc_get_bigendian_word(const unsigned char *buf);
98 dsc_private int dsc_get_int(const char *line, unsigned int len, unsigned int *offset);
99 dsc_private float dsc_get_real(const char *line, unsigned int len,
100     unsigned int *offset);
101 dsc_private void dsc_unknown(CDSC *dsc);
102 dsc_private GSBOOL dsc_is_section(char *line);
103 dsc_private int dsc_parse_pages(CDSC *dsc);
104 dsc_private int dsc_parse_bounding_box(CDSC *dsc, CDSCBBOX** pbbox, int offset);
105 dsc_private int dsc_parse_float_bounding_box(CDSC *dsc, CDSCFBBOX** pfbbox, int offset);
106 dsc_private int dsc_parse_orientation(CDSC *dsc, unsigned int *porientation,
107     int offset);
108 dsc_private int dsc_parse_order(CDSC *dsc);
109 dsc_private int dsc_parse_media(CDSC *dsc, const CDSCMEDIA **page_media);
110 dsc_private int dsc_parse_document_media(CDSC *dsc);
111 dsc_private int dsc_parse_viewing_orientation(CDSC *dsc, CDSCCTM **pctm);
112 dsc_private int dsc_parse_page(CDSC *dsc);
113 dsc_private void dsc_save_line(CDSC *dsc);
114 dsc_private int dsc_scan_type(CDSC *dsc);
115 dsc_private int dsc_scan_comments(CDSC *dsc);
116 dsc_private int dsc_scan_preview(CDSC *dsc);
117 dsc_private int dsc_scan_defaults(CDSC *dsc);
118 dsc_private int dsc_scan_prolog(CDSC *dsc);
119 dsc_private int dsc_scan_setup(CDSC *dsc);
120 dsc_private int dsc_scan_page(CDSC *dsc);
121 dsc_private int dsc_scan_trailer(CDSC *dsc);
122 dsc_private int dsc_error(CDSC *dsc, unsigned int explanation,
123     char *line, unsigned int line_len);
124 dsc_private int dsc_dcs2_fixup(CDSC *dsc);
125 dsc_private int dsc_parse_platefile(CDSC *dsc);
126 dsc_private int dsc_parse_dcs1plate(CDSC *dsc);
127 dsc_private CDSCCOLOUR * dsc_find_colour(CDSC *dsc, const char *colourname);
128 dsc_private int dsc_parse_process_colours(CDSC *dsc);
129 dsc_private int dsc_parse_custom_colours(CDSC *dsc);
130 dsc_private int dsc_parse_cmyk_custom_colour(CDSC *dsc);
131 dsc_private int dsc_parse_rgb_custom_colour(CDSC *dsc);
132 
133 /* DSC error reporting */
134 dsc_private const int dsc_severity[] = {
135     CDSC_ERROR_WARN, 	/* CDSC_MESSAGE_BBOX */
136     CDSC_ERROR_WARN, 	/* CDSC_MESSAGE_EARLY_TRAILER */
137     CDSC_ERROR_WARN, 	/* CDSC_MESSAGE_EARLY_EOF */
138     CDSC_ERROR_ERROR, 	/* CDSC_MESSAGE_PAGE_IN_TRAILER */
139     CDSC_ERROR_ERROR, 	/* CDSC_MESSAGE_PAGE_ORDINAL */
140     CDSC_ERROR_ERROR, 	/* CDSC_MESSAGE_PAGES_WRONG */
141     CDSC_ERROR_ERROR, 	/* CDSC_MESSAGE_EPS_NO_BBOX */
142     CDSC_ERROR_ERROR, 	/* CDSC_MESSAGE_EPS_PAGES */
143     CDSC_ERROR_WARN, 	/* CDSC_MESSAGE_NO_MEDIA */
144     CDSC_ERROR_WARN, 	/* CDSC_MESSAGE_ATEND */
145     CDSC_ERROR_INFORM, 	/* CDSC_MESSAGE_DUP_COMMENT */
146     CDSC_ERROR_INFORM, 	/* CDSC_MESSAGE_DUP_TRAILER */
147     CDSC_ERROR_WARN, 	/* CDSC_MESSAGE_BEGIN_END */
148     CDSC_ERROR_INFORM, 	/* CDSC_MESSAGE_BAD_SECTION */
149     CDSC_ERROR_INFORM,  /* CDSC_MESSAGE_LONG_LINE */
150     CDSC_ERROR_WARN, 	/* CDSC_MESSAGE_INCORRECT_USAGE */
151     0
152 };
153 
154 #define DSC_MAX_ERROR ((sizeof(dsc_severity) / sizeof(int))-2)
155 
156 const CDSCMEDIA dsc_known_media[CDSC_KNOWN_MEDIA] = {
157     /* These sizes taken from Ghostscript gs_statd.ps */
158     {"11x17", 792, 1224, 0, NULL, NULL},
159     {"A3", 842, 1190, 0, NULL, NULL},
160     {"A4", 595, 842, 0, NULL, NULL},
161     {"A5", 421, 595, 0, NULL, NULL},
162     {"B4", 709, 1002, 0, NULL, NULL}, /* ISO, but not Adobe standard */
163     {"B5", 501, 709, 0, NULL, NULL},  /* ISO, but not Adobe standard */
164     {"Ledger", 1224, 792, 0, NULL, NULL},
165     {"Legal", 612, 1008, 0, NULL, NULL},
166     {"Letter", 612, 792, 0, NULL, NULL},
167     {"Note", 612, 792, 0, NULL, NULL},
168     {NULL, 0, 0, 0, NULL, NULL}
169 };
170 
171 /* parser state */
172 enum CDSC_SCAN_SECTION {
173     scan_none = 0,
174     scan_comments = 1,
175     scan_pre_preview = 2,
176     scan_preview = 3,
177     scan_pre_defaults = 4,
178     scan_defaults = 5,
179     scan_pre_prolog = 6,
180     scan_prolog = 7,
181     scan_pre_setup = 8,
182     scan_setup = 9,
183     scan_pre_pages = 10,
184     scan_pages = 11,
185     scan_pre_trailer = 12,
186     scan_trailer = 13,
187     scan_eof = 14
188 };
189 
190 static const char * const dsc_scan_section_name[15] = {
191  "Type", "Comments",
192  "pre-Preview", "Preview",
193  "pre-Defaults", "Defaults",
194  "pre-Prolog", "Prolog",
195  "pre-Setup", "Setup",
196  "pre-Page", "Page",
197  "pre-Trailer", "Trailer",
198  "EOF"
199 };
200 
201 
202 /******************************************************************/
203 /* Public functions                                               */
204 /******************************************************************/
205 
206 /* constructor */
207 CDSC *
dsc_init(void * caller_data)208 dsc_init(void *caller_data)
209 {
210     CDSC *dsc = (CDSC *)malloc(sizeof(CDSC));
211     if (dsc == NULL)
212 	return NULL;
213     memset(dsc, 0, sizeof(CDSC));
214     dsc->caller_data = caller_data;
215     dsc->ref_count = 0;
216     dsc_ref(dsc);
217 
218     return dsc_init2(dsc);
219 }
220 
221 /* constructor, with caller supplied memalloc */
222 CDSC *
dsc_init_with_alloc(void * caller_data,void * (* memalloc)(size_t size,void * closure_data),void (* memfree)(void * ptr,void * closure_data),void * closure_data)223 dsc_init_with_alloc(
224     void *caller_data,
225     void *(*memalloc)(size_t size, void *closure_data),
226     void (*memfree)(void *ptr, void *closure_data),
227     void *closure_data)
228 {
229     CDSC *dsc = (CDSC *)memalloc(sizeof(CDSC), closure_data);
230     if (dsc == NULL)
231 	return NULL;
232     memset(dsc, 0, sizeof(CDSC));
233     dsc->caller_data = caller_data;
234 
235     dsc->memalloc = memalloc;
236     dsc->memfree = memfree;
237     dsc->mem_closure_data = closure_data;
238     dsc->ref_count = 0;
239     dsc_ref(dsc);
240 
241     return dsc_init2(dsc);
242 }
243 
244 
245 
246 /* destructor */
247 void
dsc_free(CDSC * dsc)248 dsc_free(CDSC *dsc)
249 {
250     if (dsc == NULL)
251 	return;
252     dsc_reset(dsc);
253     dsc_memfree(dsc, dsc);
254 }
255 
256 
257 CDSC *
dsc_new(void * caller_data)258 dsc_new(void *caller_data)
259 {
260     return dsc_init(caller_data);
261 }
262 
263 int
dsc_ref(CDSC * dsc)264 dsc_ref(CDSC *dsc)
265 {
266     return ++(dsc->ref_count);
267 }
268 
269 int
dsc_unref(CDSC * dsc)270 dsc_unref(CDSC *dsc)
271 {
272     if (dsc->ref_count <= 0)
273 	return -1;
274     dsc->ref_count--;
275     if (dsc->ref_count == 0) {
276 	dsc_free(dsc);
277 	return 0;
278     }
279     return dsc->ref_count;
280 }
281 
282 
283 /* Tell DSC parser how long document will be, to allow ignoring
284  * of early %%Trailer and %%EOF.  This is optional.
285  */
286 void
dsc_set_length(CDSC * dsc,DSC_OFFSET len)287 dsc_set_length(CDSC *dsc, DSC_OFFSET len)
288 {
289     dsc->file_length = len;
290 }
291 
292 /* Process a buffer containing DSC comments and PostScript */
293 /* Return value is < 0 for error, >=0 for OK.
294  *  CDSC_ERROR
295  *  CDSC_OK
296  *  CDSC_NOTDSC (DSC will be ignored)
297  *  other values indicate the last DSC comment read
298  */
299 int
dsc_scan_data(CDSC * dsc,const char * data,int length)300 dsc_scan_data(CDSC *dsc, const char *data, int length)
301 {
302     int bytes_read;
303     int code = 0;
304 
305     if (dsc == NULL)
306 	return CDSC_ERROR;
307 
308     if (dsc->id == CDSC_NOTDSC)
309 	return CDSC_NOTDSC;
310     dsc->id = CDSC_OK;
311     if (dsc->eof)
312 	return CDSC_OK;	/* ignore */
313 
314     if (length == 0) {
315 	/* EOF, so process what remains */
316 	dsc->eof = TRUE;
317     }
318 
319     do {
320 	if (dsc->id == CDSC_NOTDSC)
321 	    break;
322 
323 	if (length != 0) {
324 	    /* move existing data if needed */
325 	    if (dsc->data_length > CDSC_DATA_LENGTH/2) {
326 		memmove(dsc->data, dsc->data + dsc->data_index,
327 		    dsc->data_length - dsc->data_index);
328 		dsc->data_offset += dsc->data_index;
329 		dsc->data_length -= dsc->data_index;
330 		dsc->data_index = 0;
331 	    }
332 	    /* append to buffer */
333 	    bytes_read = min(length, (int)(CDSC_DATA_LENGTH - dsc->data_length));
334 	    memcpy(dsc->data + dsc->data_length, data, bytes_read);
335 	    dsc->data_length += bytes_read;
336 	    data += bytes_read;
337 	    length -= bytes_read;
338 	}
339 	if (dsc->scan_section == scan_none) {
340 	    code = dsc_scan_type(dsc);
341 	    if (code == CDSC_NEEDMORE) {
342 		/* need more characters before we can identify type */
343 		code = CDSC_OK;
344 		break;
345 	    }
346 	    dsc->id = code;
347 	}
348 
349         if (code == CDSC_NOTDSC) {
350 	    dsc->id = CDSC_NOTDSC;
351 	    break;
352 	}
353 
354 	while ((code = dsc_read_line(dsc)) > 0) {
355 	    if (dsc->id == CDSC_NOTDSC)
356 		break;
357 	    if (dsc->file_length &&
358 		(dsc->data_offset + dsc->data_index > dsc->file_length)) {
359 		/* have read past end of where we need to parse. */
360 		return CDSC_OK;	/* ignore */
361 	    }
362 	    if (dsc->doseps_end &&
363 		(dsc->data_offset + dsc->data_index > dsc->doseps_end)) {
364 		/* have read past end of DOS EPS or Mac Binary
365 		 * PostScript section
366 		 */
367 		return CDSC_OK;	/* ignore */
368 	    }
369 	    if (dsc->eof)
370 		return CDSC_OK;
371 	    if (dsc->skip_document)
372 		continue;	/* embedded document */
373 	    if (dsc->skip_lines)
374 		continue;	/* embedded lines */
375 	    if (IS_DSC(dsc->line, "%%BeginData:"))
376 		continue;
377 	    if (IS_DSC(dsc->line, "%%BeginBinary:"))
378 		continue;
379 	    if (IS_DSC(dsc->line, "%%EndDocument"))
380 		continue;
381 	    if (IS_DSC(dsc->line, "%%EndData"))
382 		continue;
383 	    if (IS_DSC(dsc->line, "%%EndBinary"))
384 		continue;
385 
386 	    do {
387 		switch (dsc->scan_section) {
388 		    case scan_comments:
389 			code = dsc_scan_comments(dsc);
390 			break;
391 		    case scan_pre_preview:
392 		    case scan_preview:
393 			code = dsc_scan_preview(dsc);
394 			break;
395 		    case scan_pre_defaults:
396 		    case scan_defaults:
397 			code = dsc_scan_defaults(dsc);
398 			break;
399 		    case scan_pre_prolog:
400 		    case scan_prolog:
401 			code = dsc_scan_prolog(dsc);
402 			break;
403 		    case scan_pre_setup:
404 		    case scan_setup:
405 			code = dsc_scan_setup(dsc);
406 			break;
407 		    case scan_pre_pages:
408 		    case scan_pages:
409 			code = dsc_scan_page(dsc);
410 			break;
411 		    case scan_pre_trailer:
412 		    case scan_trailer:
413 			code = dsc_scan_trailer(dsc);
414 			break;
415 		    case scan_eof:
416 			code = CDSC_OK;
417 			break;
418 		    default:
419 			/* invalid state */
420 			code = CDSC_ERROR;
421 		}
422 		/* repeat if line is start of next section */
423 	    } while (code == CDSC_PROPAGATE);
424 
425 	    /* if DOS EPS header not complete, ask for more */
426 	    if (code == CDSC_NEEDMORE) {
427 		code = CDSC_OK;
428 		break;
429 	    }
430 	    if (code == CDSC_NOTDSC) {
431 		dsc->id = CDSC_NOTDSC;
432 		break;
433 	    }
434 	}
435     } while (length != 0);
436 
437     return (code < 0) ? code : dsc->id;
438 }
439 
440 /* Tidy up from incorrect DSC comments */
441 int
dsc_fixup(CDSC * dsc)442 dsc_fixup(CDSC *dsc)
443 {
444     unsigned int i;
445     char buf[32];
446     DSC_OFFSET *last;
447 
448     if (dsc->id == CDSC_NOTDSC)
449 	return 0;
450 
451     /* flush last partial line */
452     dsc_scan_data(dsc, NULL, 0);
453 
454 
455     /* Fix DSC error: EOF before end of %%BeginData */
456     if (dsc->eof &&
457 	(dsc->skip_lines || dsc->skip_bytes || dsc->skip_document)) {
458 	switch (dsc->scan_section) {
459 	    case scan_comments:
460 		dsc->endcomments = DSC_END(dsc);
461 		break;
462 	    case scan_preview:
463 		dsc->endpreview = DSC_END(dsc);
464 		break;
465 	    case scan_defaults:
466 		dsc->enddefaults = DSC_END(dsc);
467 		break;
468 	    case scan_prolog:
469 		dsc->endprolog = DSC_END(dsc);
470 		break;
471 	    case scan_setup:
472 		dsc->endsetup = DSC_END(dsc);
473 		break;
474 	    case scan_pages:
475 		if (dsc->page_count)
476 		    dsc->page[dsc->page_count-1].end = DSC_END(dsc);
477 		break;
478 	    case scan_trailer:
479 	    case scan_eof:
480 		dsc->endtrailer = DSC_END(dsc);
481 		break;
482 	}
483     }
484 
485     /* Fix DSC error: code between %%EndSetup and %%Page */
486     if (dsc->page_count && (dsc->page[0].begin != dsc->endsetup)
487 		&& (dsc->endsetup != dsc->beginsetup)) {
488 	dsc->endsetup = dsc->page[0].begin;
489 	dsc_debug_print(dsc, "Warning: code included between setup and first page\n");
490     }
491 
492     /* Last page contained a false trailer, */
493     /* so extend last page to start of trailer */
494     if (dsc->page_count && (dsc->begintrailer != 0) &&
495 	(dsc->page[dsc->page_count-1].end != dsc->begintrailer)) {
496 	dsc_debug_print(dsc, "Ignoring earlier misplaced trailer\n");
497 	dsc_debug_print(dsc, "and extending last page to start of trailer\n");
498 	dsc->page[dsc->page_count-1].end = dsc->begintrailer;
499     }
500 
501     /*
502      * Join up all sections.
503      * There might be extra code between them, or we might have
504      * missed including the \n which followed \r.
505      */
506     last = &dsc->endcomments;
507     dsc_section_join(dsc->beginpreview, &dsc->endpreview, &last);
508     dsc_section_join(dsc->begindefaults, &dsc->enddefaults, &last);
509     dsc_section_join(dsc->beginprolog, &dsc->endprolog, &last);
510     dsc_section_join(dsc->beginsetup, &dsc->endsetup, &last);
511     for (i=0; i<dsc->page_count; i++)
512 	dsc_section_join(dsc->page[i].begin, &dsc->page[i].end, &last);
513     if (dsc->begintrailer)
514 	*last = dsc->begintrailer;
515 
516     if ((dsc->page_pages == 0) && (dsc->page_count == 1)) {
517 	/* don't flag an error if %%Pages absent but one %%Page found */
518 	/* adjust incorrect page count */
519 	dsc->page_pages = dsc->page_count;
520     }
521 
522     /* Warnings and Errors that we can now identify */
523     if ((dsc->page_count != dsc->page_pages)) {
524 	int rc = dsc_error(dsc, CDSC_MESSAGE_PAGES_WRONG, NULL, 0);
525 	switch (rc) {
526 	    case CDSC_RESPONSE_OK:
527 		/* adjust incorrect page count */
528 		dsc->page_pages = dsc->page_count;
529 		break;
530 	    case CDSC_RESPONSE_CANCEL:
531 		break;;
532 	    case CDSC_RESPONSE_IGNORE_ALL:
533 		return CDSC_NOTDSC;
534 	}
535     }
536 
537     if (dsc->epsf && (dsc->bbox == (CDSCBBOX *)NULL)) {
538 	/* EPS files MUST include a BoundingBox */
539 	int rc = dsc_error(dsc, CDSC_MESSAGE_EPS_NO_BBOX, NULL, 0);
540 	switch (rc) {
541 	    case CDSC_RESPONSE_OK:
542 		/* Assume that it is EPS */
543 		break;
544 	    case CDSC_RESPONSE_CANCEL:
545 		/* Is NOT an EPS file */
546 		dsc->epsf = FALSE;
547 	    case CDSC_RESPONSE_IGNORE_ALL:
548 		return CDSC_NOTDSC;
549 	}
550     }
551 
552     if (dsc->epsf && ((dsc->page_count > 1) || (dsc->page_pages > 1))) {
553 	int rc = dsc_error(dsc, CDSC_MESSAGE_EPS_PAGES, NULL, 0);
554 	switch (rc) {
555 	    case CDSC_RESPONSE_OK:
556 		/* Is an EPS file */
557 		break;
558 	    case CDSC_RESPONSE_CANCEL:
559 		/* Is NOT an EPS file */
560 		dsc->epsf = FALSE;
561 		break;
562 	    case CDSC_RESPONSE_IGNORE_ALL:
563 		return CDSC_NOTDSC;
564 	}
565     }
566 
567     /* convert single file DSC 2.0 into multiple pages */
568     dsc_dcs2_fixup(dsc);
569 
570     if ((dsc->media_count == 1) && (dsc->page_media == NULL)) {
571 	/* if one only media was specified, and default page media */
572 	/* was not specified, assume that default is the only media. */
573 	dsc->page_media = dsc->media[0];
574     }
575 
576     if ((dsc->media_count != 0) && (dsc->page_media == NULL)) {
577 	int rc = dsc_error(dsc, CDSC_MESSAGE_NO_MEDIA, NULL, 0);
578 	switch (rc) {
579 	    case CDSC_RESPONSE_OK:
580 		/* default media is first listed */
581 		dsc->page_media = dsc->media[0];
582 		break;
583 	    case CDSC_RESPONSE_CANCEL:
584 		/* No default media */
585 		break;
586 	    case CDSC_RESPONSE_IGNORE_ALL:
587 		return CDSC_NOTDSC;
588 	}
589     }
590 
591     /* make sure all pages have a label */
592     for (i=0; i<dsc->page_count; i++) {
593 	if (strlen(dsc->page[i].label) == 0) {
594 	    sprintf(buf, "%d", i+1);
595 	    if ((dsc->page[i].label = dsc_alloc_string(dsc, buf, (int)strlen(buf)))
596 		== (char *)NULL)
597 		return CDSC_ERROR;	/* no memory */
598 	}
599     }
600     return CDSC_OK;
601 }
602 
603 /* Install a function to be used for displaying messages about
604  * DSC errors and warnings, and to request advice from user.
605  * Installing an error function is optional.
606  */
607 void
dsc_set_error_function(CDSC * dsc,int (* fn)(void * caller_data,CDSC * dsc,unsigned int explanation,const char * line,unsigned int line_len))608 dsc_set_error_function(CDSC *dsc,
609 	int (*fn)(void *caller_data, CDSC *dsc,
610 	unsigned int explanation, const char *line, unsigned int line_len))
611 {
612     dsc->dsc_error_fn = fn;
613 }
614 
615 
616 /* Install a function for printing debug messages */
617 /* This is optional */
618 void
dsc_set_debug_function(CDSC * dsc,void (* debug_fn)(void * caller_data,const char * str))619 dsc_set_debug_function(CDSC *dsc,
620 	void (*debug_fn)(void *caller_data, const char *str))
621 {
622     dsc->debug_print_fn = debug_fn;
623 }
624 
625 /* Doesn't need to be public for PostScript documents */
626 /* Made public so GSview can add pages when processing PDF files */
627 int
dsc_add_page(CDSC * dsc,int ordinal,char * label)628 dsc_add_page(CDSC *dsc, int ordinal, char *label)
629 {
630     dsc->page[dsc->page_count].ordinal = ordinal;
631     dsc->page[dsc->page_count].label =
632 	dsc_alloc_string(dsc, label, (int)strlen(label)+1);
633     dsc->page[dsc->page_count].begin = 0;
634     dsc->page[dsc->page_count].end = 0;
635     dsc->page[dsc->page_count].orientation = CDSC_ORIENT_UNKNOWN;
636     dsc->page[dsc->page_count].media = NULL;
637     dsc->page[dsc->page_count].bbox = NULL;
638     dsc->page[dsc->page_count].viewing_orientation = NULL;
639     dsc->page[dsc->page_count].crop_box = NULL;
640 
641     dsc->page_count++;
642     if (dsc->page_count >= dsc->page_chunk_length) {
643 	CDSCPAGE *new_page = (CDSCPAGE *)dsc_memalloc(dsc,
644 	    (CDSC_PAGE_CHUNK+dsc->page_count) * sizeof(CDSCPAGE));
645 	if (new_page == NULL)
646 	    return CDSC_ERROR;	/* out of memory */
647 	memcpy(new_page, dsc->page,
648 	    dsc->page_count * sizeof(CDSCPAGE));
649 	dsc_memfree(dsc, dsc->page);
650 	dsc->page= new_page;
651 	dsc->page_chunk_length = CDSC_PAGE_CHUNK+dsc->page_count;
652     }
653     return CDSC_OK;
654 }
655 
656 /* Doesn't need to be public for PostScript documents */
657 /* Made public so GSview can store PDF MediaBox */
658 int
dsc_add_media(CDSC * dsc,CDSCMEDIA * media)659 dsc_add_media(CDSC *dsc, CDSCMEDIA *media)
660 {
661     CDSCMEDIA **newmedia_array;
662     CDSCMEDIA *newmedia;
663 
664     /* extend media array  */
665     newmedia_array = (CDSCMEDIA **)dsc_memalloc(dsc,
666 	(dsc->media_count + 1) * sizeof(CDSCMEDIA *));
667     if (newmedia_array == NULL)
668 	return CDSC_ERROR;	/* out of memory */
669     if (dsc->media != NULL) {
670 	memcpy(newmedia_array, dsc->media,
671 	    dsc->media_count * sizeof(CDSCMEDIA *));
672 	dsc_memfree(dsc, dsc->media);
673     }
674     dsc->media = newmedia_array;
675 
676     /* allocate new media */
677     newmedia = dsc->media[dsc->media_count] =
678 	(CDSCMEDIA *)dsc_memalloc(dsc, sizeof(CDSCMEDIA));
679     if (newmedia == NULL)
680 	return CDSC_ERROR;	/* out of memory */
681     newmedia->name = NULL;
682     newmedia->width = 595.0;
683     newmedia->height = 842.0;
684     newmedia->weight = 80.0;
685     newmedia->colour = NULL;
686     newmedia->type = NULL;
687     newmedia->mediabox = NULL;
688 
689     dsc->media_count++;
690 
691     if (media->name) {
692 	newmedia->name = dsc_alloc_string(dsc, media->name,
693 	    (int)strlen(media->name));
694 	if (newmedia->name == NULL)
695 	    return CDSC_ERROR;	/* no memory */
696     }
697     newmedia->width = media->width;
698     newmedia->height = media->height;
699     newmedia->weight = media->weight;
700     if (media->colour) {
701 	newmedia->colour = dsc_alloc_string(dsc, media->colour,
702 	    (int)strlen(media->colour));
703         if (newmedia->colour == NULL)
704 	    return CDSC_ERROR;	/* no memory */
705     }
706     if (media->type) {
707 	newmedia->type = dsc_alloc_string(dsc, media->type,
708 	    (int)strlen(media->type));
709 	if (newmedia->type == NULL)
710 	    return CDSC_ERROR;	/* no memory */
711     }
712     newmedia->mediabox = NULL;
713 
714     if (media->mediabox) {
715 	newmedia->mediabox = (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX));
716 	if (newmedia->mediabox == NULL)
717 	    return CDSC_ERROR;	/* no memory */
718 	*newmedia->mediabox = *media->mediabox;
719     }
720     return CDSC_OK;
721 }
722 
723 /* Doesn't need to be public for PostScript documents */
724 /* Made public so GSview can store PDF CropBox */
725 int
dsc_set_page_bbox(CDSC * dsc,unsigned int page_number,int llx,int lly,int urx,int ury)726 dsc_set_page_bbox(CDSC *dsc, unsigned int page_number,
727     int llx, int lly, int urx, int ury)
728 {
729     CDSCBBOX *bbox;
730     if (page_number >= dsc->page_count)
731 	return CDSC_ERROR;
732     bbox = dsc->page[page_number].bbox;
733     if (bbox == NULL)
734 	dsc->page[page_number].bbox = bbox =
735 	    (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX));
736     if (bbox == NULL)
737 	return CDSC_ERROR;
738     bbox->llx = llx;
739     bbox->lly = lly;
740     bbox->urx = urx;
741     bbox->ury = ury;
742     return CDSC_OK;
743 }
744 
745 
746 /******************************************************************/
747 /* Private functions below here.                                  */
748 /******************************************************************/
749 
750 dsc_private void *
dsc_memalloc(CDSC * dsc,size_t size)751 dsc_memalloc(CDSC *dsc, size_t size)
752 {
753     if (dsc->memalloc)
754 	return dsc->memalloc(size, dsc->mem_closure_data);
755     return malloc(size);
756 }
757 
758 dsc_private void
dsc_memfree(CDSC * dsc,void * ptr)759 dsc_memfree(CDSC*dsc, void *ptr)
760 {
761     if (dsc->memfree)
762 	dsc->memfree(ptr, dsc->mem_closure_data);
763     else
764 	free(ptr);
765 }
766 
767 /* private constructor */
768 dsc_private CDSC *
dsc_init2(CDSC * dsc)769 dsc_init2(CDSC *dsc)
770 {
771     dsc_reset(dsc);
772 
773     dsc->string_head = (CDSCSTRING *)dsc_memalloc(dsc, sizeof(CDSCSTRING));
774     if (dsc->string_head == NULL) {
775 	dsc_free(dsc);
776 	return NULL;	/* no memory */
777     }
778     dsc->string = dsc->string_head;
779     dsc->string->next = NULL;
780     dsc->string->data = (char *)dsc_memalloc(dsc, CDSC_STRING_CHUNK);
781     if (dsc->string->data == NULL) {
782 	dsc_free(dsc);
783 	return NULL;	/* no memory */
784     }
785     dsc->string->index = 0;
786     dsc->string->length = CDSC_STRING_CHUNK;
787 
788     dsc->page = (CDSCPAGE *)dsc_memalloc(dsc, CDSC_PAGE_CHUNK * sizeof(CDSCPAGE));
789     if (dsc->page == NULL) {
790 	dsc_free(dsc);
791 	return NULL;	/* no memory */
792     }
793     dsc->page_chunk_length = CDSC_PAGE_CHUNK;
794     dsc->page_count = 0;
795 
796     dsc->line = NULL;
797     dsc->data_length = 0;
798     dsc->data_index = dsc->data_length;
799 
800     return dsc;
801 }
802 
803 
804 dsc_private void
dsc_reset(CDSC * dsc)805 dsc_reset(CDSC *dsc)
806 {
807     unsigned int i;
808     /* Clear public members */
809     dsc->dsc = FALSE;
810     dsc->ctrld = FALSE;
811     dsc->pjl = FALSE;
812     dsc->epsf = FALSE;
813     dsc->pdf = FALSE;
814     dsc->epsf = FALSE;
815     dsc->preview = CDSC_NOPREVIEW;
816     dsc->dsc_version = NULL;	/* stored in dsc->string */
817     dsc->language_level = 0;
818     dsc->document_data = CDSC_DATA_UNKNOWN;
819     dsc->begincomments = 0;
820     dsc->endcomments = 0;
821     dsc->beginpreview = 0;
822     dsc->endpreview = 0;
823     dsc->begindefaults = 0;
824     dsc->enddefaults = 0;
825     dsc->beginprolog = 0;
826     dsc->endprolog = 0;
827     dsc->beginsetup = 0;
828     dsc->endsetup = 0;
829     dsc->begintrailer = 0;
830     dsc->endtrailer = 0;
831 
832     for (i=0; i<dsc->page_count; i++) {
833 	/* page media is pointer to an element of media or dsc_known_media */
834 	/* do not free it. */
835 
836 	if (dsc->page[i].bbox)
837 	    dsc_memfree(dsc, dsc->page[i].bbox);
838 	if (dsc->page[i].viewing_orientation)
839 	    dsc_memfree(dsc, dsc->page[i].viewing_orientation);
840 	if (dsc->page[i].crop_box)
841 	    dsc_memfree(dsc, dsc->page[i].crop_box);
842     }
843     if (dsc->page)
844 	dsc_memfree(dsc, dsc->page);
845     dsc->page = NULL;
846 
847     dsc->page_count = 0;
848     dsc->page_pages = 0;
849     dsc->page_order = CDSC_ORDER_UNKNOWN;
850     dsc->page_orientation = CDSC_ORIENT_UNKNOWN;
851     if (dsc->viewing_orientation)
852 	dsc_memfree(dsc, dsc->viewing_orientation);
853     dsc->viewing_orientation = NULL;
854 
855     if (dsc->media) {
856 	for (i=0; i<dsc->media_count; i++) {
857 	    if (dsc->media[i]) {
858 		if (dsc->media[i]->mediabox)
859 		    dsc_memfree(dsc, dsc->media[i]->mediabox);
860 		dsc_memfree(dsc, dsc->media[i]);
861 	    }
862 	}
863 	dsc_memfree(dsc, dsc->media);
864     }
865     dsc->media_count = 0;
866     dsc->media = NULL;
867 
868     /* page_media is pointer to an element of media or dsc_known_media */
869     /* do not free it. */
870     dsc->page_media = NULL;
871 
872     if (dsc->bbox)
873 	dsc_memfree(dsc, dsc->bbox);
874     dsc->bbox = NULL;
875     if (dsc->page_bbox)
876 	dsc_memfree(dsc, dsc->page_bbox);
877     dsc->page_bbox = NULL;
878     if (dsc->doseps)
879 	dsc_memfree(dsc, dsc->doseps);
880     dsc->doseps = NULL;
881 
882     dsc->dsc_title = NULL;
883     dsc->dsc_creator = NULL;
884     dsc->dsc_date = NULL;
885     dsc->dsc_for = NULL;
886 
887 
888     dsc->max_error = DSC_MAX_ERROR;
889     dsc->severity = dsc_severity;
890 
891     /* Clear private members */
892     /* Don't touch dsc->caller_data */
893     dsc->id = CDSC_OK;
894     dsc->scan_section = scan_none;
895     dsc->doseps_end = 0;
896     dsc->page_chunk_length = 0;
897     dsc->file_length = 0;
898     dsc->skip_document = 0;
899     dsc->skip_bytes = 0;
900     dsc->skip_lines = 0;
901     dsc->skip_pjl = 0;
902     dsc->begin_font_count = 0;
903     dsc->begin_feature_count = 0;
904     dsc->begin_resource_count = 0;
905     dsc->begin_procset_count = 0;
906 
907     dsc->data_length = 0;
908     dsc->data_index = 0;
909     dsc->data_offset = 0;
910 
911     dsc->eof = 0;
912 
913     dsc->line = 0;
914     dsc->line_length = 0;
915     dsc->eol = 0;
916     dsc->last_cr = FALSE;
917     dsc->line_count = 1;
918     dsc->long_line = FALSE;
919     memset(dsc->last_line, 0, sizeof(dsc->last_line));
920 
921     dsc->string = dsc->string_head;
922     while (dsc->string != (CDSCSTRING *)NULL) {
923 	if (dsc->string->data)
924 	    dsc_memfree(dsc, dsc->string->data);
925 	dsc->string_head = dsc->string;
926 	dsc->string = dsc->string->next;
927 	dsc_memfree(dsc, dsc->string_head);
928     }
929     dsc->string_head = NULL;
930     dsc->string = NULL;
931 
932     /* don't touch caller functions */
933 
934     /* public data */
935     if (dsc->hires_bbox)
936 	dsc_memfree(dsc, dsc->hires_bbox);
937     dsc->hires_bbox = NULL;
938     if (dsc->crop_box)
939 	dsc_memfree(dsc, dsc->crop_box);
940     dsc->crop_box = NULL;
941 
942     if (dsc->dcs2) {
943 	CDCS2 *this_dcs, *next_dcs;
944 	this_dcs = dsc->dcs2;
945 	while (this_dcs) {
946 	    next_dcs = this_dcs->next;
947 	    /* strings have already been freed */
948 	    dsc_memfree(dsc, this_dcs);
949 	    this_dcs = next_dcs;
950 	}
951 	dsc->dcs2 = NULL;
952     }
953     if (dsc->colours) {
954 	CDSCCOLOUR *this_colour, *next_colour;
955 	this_colour = dsc->colours;
956 	while (this_colour) {
957 	    next_colour = this_colour->next;
958 	    /* strings have already been freed */
959 	    dsc_memfree(dsc, this_colour);
960 	    this_colour = next_colour;
961 	}
962 	dsc->colours = NULL;
963     }
964 
965     if (dsc->macbin)
966 	dsc_memfree(dsc, dsc->macbin);
967     dsc->macbin = NULL;
968 }
969 
970 /*
971 * Join up all sections.
972 * There might be extra code between them, or we might have
973 * missed including the \n which followed \r.
974 * begin is the start of this section
975 * pend is a pointer to the end of this section
976 * pplast is a pointer to a pointer of the end of the previous section
977 */
978 dsc_private void
dsc_section_join(DSC_OFFSET begin,DSC_OFFSET * pend,DSC_OFFSET ** pplast)979 dsc_section_join(DSC_OFFSET begin, DSC_OFFSET *pend, DSC_OFFSET **pplast)
980 {
981     if (begin)
982 	**pplast = begin;
983     if (*pend > begin)
984 	*pplast = pend;
985 }
986 
987 
988 /* return value is 0 if no line available, or length of line */
989 dsc_private int
dsc_read_line(CDSC * dsc)990 dsc_read_line(CDSC *dsc)
991 {
992     char *p, *last;
993     dsc->line = NULL;
994 
995     if (dsc->eof) {
996 	/* return all that remains, even if line incomplete */
997 	dsc->line = dsc->data + dsc->data_index;
998 	dsc->line_length = dsc->data_length - dsc->data_index;
999 	dsc->data_index = dsc->data_length;
1000 	return dsc->line_length;
1001     }
1002 
1003     if (dsc->file_length &&
1004 	(dsc->data_offset + dsc->data_index >= dsc->file_length)) {
1005 	/* Have read past where we need to parse. */
1006 	/* Ignore all that remains. */
1007 	dsc->line = dsc->data + dsc->data_index;
1008 	dsc->line_length = dsc->data_length - dsc->data_index;
1009 	dsc->data_index = dsc->data_length;
1010 	return dsc->line_length;
1011 
1012     }
1013     if (dsc->doseps_end &&
1014 	(dsc->data_offset + dsc->data_index >= dsc->doseps_end)) {
1015 	/* Have read past end of DOS EPS PostScript section. */
1016 	/* Ignore all that remains. */
1017 	dsc->line = dsc->data + dsc->data_index;
1018 	dsc->line_length = dsc->data_length - dsc->data_index;
1019 	dsc->data_index = dsc->data_length;
1020 	return dsc->line_length;
1021     }
1022 
1023     /* ignore embedded bytes */
1024     if (dsc->skip_bytes) {
1025 	int cnt = min(dsc->skip_bytes,
1026 		     (int)(dsc->data_length - dsc->data_index));
1027 	dsc->skip_bytes -= cnt;
1028 	dsc->data_index += cnt;
1029 	if (dsc->skip_bytes != 0)
1030 	    return 0;
1031     }
1032 
1033     do {
1034 	dsc->line = dsc->data + dsc->data_index;
1035 	last = dsc->data + dsc->data_length;
1036 	if (dsc->data_index == dsc->data_length) {
1037 	    dsc->line_length = 0;
1038 	    return 0;
1039 	}
1040 	if (dsc->eol) {
1041 	    /* if previous line was complete, increment line count */
1042 	    dsc->line_count++;
1043 	    if (dsc->skip_lines)
1044 		dsc->skip_lines--;
1045 	}
1046 
1047 	/* skip over \n which followed \r */
1048 	if (dsc->last_cr && dsc->line[0] == '\n') {
1049 	    dsc->data_index++;
1050 	    dsc->line++;
1051 	}
1052 	dsc->last_cr = FALSE;
1053 
1054 	/* look for EOL */
1055 	dsc->eol = FALSE;
1056 	for (p = dsc->line; p < last; p++) {
1057 	    if (*p == '\r') {
1058 		p++;
1059 		if ((p<last) && (*p == '\n'))
1060 		    p++;	/* include line feed also */
1061 		else
1062 		    dsc->last_cr = TRUE; /* we might need to skip \n */
1063 		dsc->eol = TRUE;	/* dsc->line is a complete line */
1064 		break;
1065 	    }
1066 	    if (*p == '\n') {
1067 		p++;
1068 		dsc->eol = TRUE;	/* dsc->line is a complete line */
1069 		break;
1070 	    }
1071 	    if (*p == '\032') {		/* MS-DOS Ctrl+Z */
1072 		dsc->eol = TRUE;
1073 	    }
1074 	}
1075 	if (dsc->eol == FALSE) {
1076 	    /* we haven't got a complete line yet */
1077 	    if (dsc->data_length - dsc->data_index < sizeof(dsc->data)/2) {
1078 		/* buffer is less than half full, ask for some more */
1079 		dsc->line_length = 0;
1080 		return 0;
1081 	    }
1082 	}
1083 	dsc->data_index += dsc->line_length = (int)(p - dsc->line);
1084     } while (dsc->skip_lines && dsc->line_length);
1085 
1086     if (dsc->line_length == 0)
1087 	return 0;
1088 
1089     if ((dsc->line[0]=='%') && (dsc->line[1]=='%'))  {
1090 	/* handle recursive %%BeginDocument */
1091 	if ((dsc->skip_document) && dsc->line_length &&
1092 		COMPARE(dsc->line, "%%EndDocument")) {
1093 	    dsc->skip_document--;
1094 	}
1095 
1096 	/* handle embedded lines or binary data */
1097 	if (COMPARE(dsc->line, "%%BeginData:")) {
1098 	    /* %%BeginData: <numberof>[ <type> [ <bytesorlines> ] ]
1099 	     * <numberof> ::= <uint> (Lines or physical bytes)
1100 	     * <type> ::= Hex | Binary | ASCII (Type of data)
1101 	     * <bytesorlines> ::= Bytes | Lines (Read in bytes or lines)
1102 	     */
1103 	    char begindata[MAXSTR+1];
1104 	    int cnt;
1105 	    const char *numberof, *bytesorlines;
1106 	    cnt = dsc->line_length;
1107 	    if (dsc->line_length > sizeof(begindata)-1)
1108 		cnt = sizeof(begindata)-1;
1109 	    memcpy(begindata, dsc->line, cnt);
1110 	    begindata[cnt] = '\0';
1111 	    numberof = strtok(begindata+12, " \r\n");
1112 	    strtok(NULL, " \r\n");	/* dump type */
1113 	    bytesorlines = strtok(NULL, " \r\n");
1114 	    if (bytesorlines == NULL)
1115 		bytesorlines = "Bytes";
1116 
1117 	    if ( (numberof == NULL) || (bytesorlines == NULL) ) {
1118 		/* invalid usage of %%BeginData */
1119 		/* ignore that we ever saw it */
1120 		int rc = dsc_error(dsc, CDSC_MESSAGE_INCORRECT_USAGE,
1121 			    dsc->line, dsc->line_length);
1122 		switch (rc) {
1123 		    case CDSC_RESPONSE_OK:
1124 		    case CDSC_RESPONSE_CANCEL:
1125 			break;
1126 		    case CDSC_RESPONSE_IGNORE_ALL:
1127 			return 0;
1128 		}
1129 	    }
1130 	    else {
1131 		cnt = atoi(numberof);
1132 		if (cnt) {
1133 		    if (bytesorlines && (dsc_stricmp(bytesorlines, "Lines")==0)) {
1134 			/* skip cnt lines */
1135 			if (dsc->skip_lines == 0) {
1136 			    /* we are not already skipping lines */
1137 			    dsc->skip_lines = cnt+1;
1138 			}
1139 		    }
1140 		    else {
1141 			/* byte count doesn't includes \n or \r\n  */
1142 			/* or \r of %%BeginData: */
1143 			/* skip cnt bytes */
1144 			if (dsc->skip_bytes == 0) {
1145 			    /* we are not already skipping lines */
1146 			    dsc->skip_bytes = cnt;
1147 			}
1148 
1149 		    }
1150 		}
1151 	    }
1152 	}
1153 	else if (COMPARE(dsc->line, "%%BeginBinary:")) {
1154 	    /* byte count doesn't includes \n or \r\n or \r of %%BeginBinary:*/
1155 	    int cnt = dsc_get_int(dsc->line + 14,
1156 		dsc->line_length - 14, NULL);
1157 	    if (dsc->skip_bytes == 0) {
1158 		/* we are not already skipping lines */
1159 		dsc->skip_bytes = cnt;
1160 	    }
1161 	}
1162     }
1163 
1164     if ((dsc->line[0]=='%') && (dsc->line[1]=='%') &&
1165 	COMPARE(dsc->line, "%%BeginDocument:") ) {
1166 	/* Skip over embedded document, recursively */
1167 	dsc->skip_document++;
1168     }
1169 
1170     if (!dsc->long_line && (dsc->line_length > DSC_LINE_LENGTH)) {
1171 	dsc_error(dsc, CDSC_MESSAGE_LONG_LINE, dsc->line, dsc->line_length);
1172         dsc->long_line = TRUE;
1173     }
1174 
1175     return dsc->line_length;
1176 }
1177 
1178 
1179 /* Save last DSC line, for use with %%+ */
1180 dsc_private void
dsc_save_line(CDSC * dsc)1181 dsc_save_line(CDSC *dsc)
1182 {
1183     int len = min(sizeof(dsc->last_line), dsc->line_length);
1184     memcpy(dsc->last_line, dsc->line, len);
1185 }
1186 
1187 /* display unknown DSC line */
1188 dsc_private void
dsc_unknown(CDSC * dsc)1189 dsc_unknown(CDSC *dsc)
1190 {
1191     if (dsc->debug_print_fn) {
1192 	char line[DSC_LINE_LENGTH];
1193 	unsigned int length = min(DSC_LINE_LENGTH-1, dsc->line_length);
1194 	sprintf(line, "Unknown in %s section at line %d:\n  ",
1195 	    dsc_scan_section_name[dsc->scan_section], dsc->line_count);
1196 	dsc_debug_print(dsc, line);
1197 	strncpy(line, dsc->line, length);
1198 	line[length] = '\0';
1199 	dsc_debug_print(dsc, line);
1200 	dsc_debug_print(dsc, "\n");
1201     }
1202 }
1203 
1204 
1205 dsc_private GSBOOL
dsc_is_section(char * line)1206 dsc_is_section(char *line)
1207 {
1208     if ( !((line[0]=='%') && (line[1]=='%')) )
1209 	return FALSE;
1210     if (IS_DSC(line, "%%BeginPreview"))
1211 	return TRUE;
1212     if (IS_DSC(line, "%%BeginDefaults"))
1213 	return TRUE;
1214     if (IS_DSC(line, "%%BeginProlog"))
1215 	return TRUE;
1216     if (IS_DSC(line, "%%BeginSetup"))
1217 	return TRUE;
1218     if (IS_DSC(line, "%%Page:"))
1219 	return TRUE;
1220     if (IS_DSC(line, "%%Trailer"))
1221 	return TRUE;
1222     if (IS_DSC(line, "%%EOF"))
1223 	return TRUE;
1224     return FALSE;
1225 }
1226 
1227 /* Get little-endian DWORD, used for DOS EPS files */
1228 dsc_private GSDWORD
dsc_get_dword(const unsigned char * buf)1229 dsc_get_dword(const unsigned char *buf)
1230 {
1231     GSDWORD dw;
1232     dw = (GSDWORD)buf[0];
1233     dw += ((GSDWORD)buf[1])<<8;
1234     dw += ((GSDWORD)buf[2])<<16;
1235     dw += ((GSDWORD)buf[3])<<24;
1236     return dw;
1237 }
1238 
1239 dsc_private GSWORD
dsc_get_word(const unsigned char * buf)1240 dsc_get_word(const unsigned char *buf)
1241 {
1242     GSWORD w;
1243     w = (GSWORD)buf[0];
1244     w |= (GSWORD)(buf[1]<<8);
1245     return w;
1246 }
1247 
1248 /* Get big-endian DWORD, used for Mac Binary files */
1249 dsc_private GSDWORD
dsc_get_bigendian_dword(const unsigned char * buf)1250 dsc_get_bigendian_dword(const unsigned char *buf)
1251 {
1252     GSDWORD dw;
1253     dw = (GSDWORD)buf[3];
1254     dw += ((GSDWORD)buf[2])<<8;
1255     dw += ((GSDWORD)buf[1])<<16;
1256     dw += ((GSDWORD)buf[0])<<24;
1257     return dw;
1258 }
1259 
1260 dsc_private GSWORD
dsc_get_bigendian_word(const unsigned char * buf)1261 dsc_get_bigendian_word(const unsigned char *buf)
1262 {
1263     GSWORD w;
1264     w = (GSWORD)buf[1];
1265     w |= (GSWORD)(buf[0]<<8);
1266     return w;
1267 }
1268 
1269 dsc_private int
dsc_read_doseps(CDSC * dsc)1270 dsc_read_doseps(CDSC *dsc)
1271 {
1272     unsigned char *line = (unsigned char *)dsc->line;
1273     if ((dsc->doseps = (CDSCDOSEPS *)dsc_memalloc(dsc, sizeof(CDSCDOSEPS))) == NULL)
1274 	return CDSC_ERROR;	/* no memory */
1275 
1276     dsc->doseps->ps_begin = dsc_get_dword(line+4);
1277     dsc->doseps->ps_length = dsc_get_dword(line+8);
1278     dsc->doseps->wmf_begin = dsc_get_dword(line+12);
1279     dsc->doseps->wmf_length = dsc_get_dword(line+16);
1280     dsc->doseps->tiff_begin = dsc_get_dword(line+20);
1281     dsc->doseps->tiff_length = dsc_get_dword(line+24);
1282     dsc->doseps->checksum = dsc_get_word(line+28);
1283 
1284     if (dsc->file_length &&
1285 	(dsc->doseps->ps_begin + dsc->doseps->ps_length > dsc->file_length)) {
1286 	/* Error in DOS EPS header.
1287 	 * Some files have been seen with a fixed large value as
1288 	 * the length of the PostScript section.
1289 	 * Correct for these erroneous files.
1290 	 */
1291 	 dsc->doseps->ps_length =
1292 	    (GSDWORD)(dsc->file_length - dsc->doseps->ps_begin);
1293     }
1294 
1295     dsc->doseps_end = dsc->doseps->ps_begin + dsc->doseps->ps_length;
1296 
1297     /* move data_index backwards to byte after doseps header */
1298     dsc->data_index -= dsc->line_length - 30;
1299     /* we haven't read a line of PostScript code yet */
1300     dsc->line_count = 0;
1301     /* skip from current position to start of PostScript section */
1302     dsc->skip_bytes = dsc->doseps->ps_begin - 30;
1303 
1304     if (dsc->doseps->tiff_begin)
1305 	dsc->preview = CDSC_TIFF;
1306     if (dsc->doseps->wmf_begin)
1307 	dsc->preview = CDSC_WMF;
1308 
1309     return CDSC_OK;
1310 }
1311 
1312 
1313 dsc_private int
dsc_read_macbin(CDSC * dsc)1314 dsc_read_macbin(CDSC *dsc)
1315 {
1316     unsigned char *line = (unsigned char *)dsc->line;
1317     if ((dsc->macbin =
1318 	(CDSCMACBIN *)dsc_memalloc(dsc, sizeof(CDSCMACBIN))) == NULL)
1319 	return CDSC_ERROR;	/* no memory */
1320 
1321     dsc->macbin->data_begin = 128;
1322     dsc->macbin->data_length = dsc_get_bigendian_dword(line+83);
1323     dsc->macbin->resource_begin =
1324 	(dsc->macbin->data_begin + dsc->macbin->data_length + 127 ) & ~127;
1325     dsc->macbin->resource_length = dsc_get_bigendian_dword(line+87);
1326 
1327     if (dsc->file_length &&
1328 	(((dsc->macbin->resource_begin + dsc->macbin->resource_length
1329 	  + 127) & ~127) > dsc->file_length)) {
1330 	return CDSC_ERROR;
1331     }
1332 
1333     dsc->doseps_end = dsc->macbin->data_begin + dsc->macbin->data_length;
1334 
1335     /* move data_index to byte after Mac Binary header */
1336     dsc->data_index -= dsc->line_length - 128;
1337     /* we haven't read a line of PostScript code yet */
1338     dsc->line_count = 0;
1339 
1340     dsc->preview = CDSC_PICT;
1341 
1342     return CDSC_OK;
1343 }
1344 
1345 
1346 dsc_private int
dsc_read_applesingle(CDSC * dsc)1347 dsc_read_applesingle(CDSC *dsc)
1348 {
1349     GSDWORD EntryID;
1350     GSDWORD Offset;
1351     GSDWORD Length;
1352     GSWORD entries;
1353     int index;
1354     int header;
1355     int i;
1356 
1357     unsigned char *line = (unsigned char *)dsc->line;
1358     if ((dsc->macbin =
1359 	(CDSCMACBIN *)dsc_memalloc(dsc, sizeof(CDSCMACBIN))) == NULL)
1360 	return CDSC_ERROR;	/* no memory */
1361     entries = dsc_get_bigendian_word(line+24);
1362     for (i=0; i<(int)entries; i++) {
1363 	index = 26 + i * 12;
1364 	EntryID = dsc_get_bigendian_dword(line+index);
1365 	Offset = dsc_get_bigendian_dword(line+index+4);
1366 	Length = dsc_get_bigendian_dword(line+index+8);
1367 	if (EntryID == 1) {
1368 	    /* data fork */
1369 	    dsc->macbin->data_begin = Offset;
1370 	    dsc->macbin->data_length = Length;
1371 	}
1372 	else if (EntryID == 2) {
1373 	    /* resource fork */
1374 	    dsc->macbin->resource_begin = Offset;
1375 	    dsc->macbin->resource_length = Length;
1376 	}
1377     }
1378 
1379     if (dsc->file_length &&
1380 	(dsc->macbin->resource_begin + dsc->macbin->resource_length
1381 	  > dsc->file_length)) {
1382 	return CDSC_ERROR;
1383     }
1384     if (dsc->file_length &&
1385 	(dsc->macbin->data_begin + dsc->macbin->data_length
1386 	  > dsc->file_length)) {
1387 	return CDSC_ERROR;
1388     }
1389 
1390     dsc->doseps_end = dsc->macbin->data_begin + dsc->macbin->data_length;
1391 
1392     header = 26 + entries * 12;
1393     /* move data_index to byte after AppleSingle/AppleDouble header */
1394     dsc->data_index -= dsc->line_length - header;
1395     /* we haven't read a line of PostScript code yet */
1396     dsc->line_count = 0;
1397     /* skip from current position to start of PostScript section */
1398     dsc->skip_bytes = dsc->macbin->data_begin - header;
1399 
1400     dsc->preview = CDSC_PICT;
1401 
1402     return CDSC_OK;
1403 }
1404 
1405 dsc_private int
dsc_parse_pages(CDSC * dsc)1406 dsc_parse_pages(CDSC *dsc)
1407 {
1408     int ip, io;
1409     unsigned int i;
1410     char *p;
1411     int n;
1412     if ((dsc->page_pages != 0) && (dsc->scan_section == scan_comments)) {
1413 	int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line,
1414 		dsc->line_length);
1415 	switch (rc) {
1416 	    case CDSC_RESPONSE_OK:
1417 	    case CDSC_RESPONSE_CANCEL:
1418 		return CDSC_OK;	/* ignore duplicate comments in header */
1419 	    case CDSC_RESPONSE_IGNORE_ALL:
1420 		return CDSC_NOTDSC;
1421 	}
1422     }
1423     if ((dsc->page_pages != 0) && (dsc->scan_section == scan_trailer)) {
1424 	int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line,
1425 		dsc->line_length);
1426 	switch (rc) {
1427 	    case CDSC_RESPONSE_OK:
1428 	    case CDSC_RESPONSE_CANCEL:
1429 		break;		/* use duplicate comments in header */
1430 	    case CDSC_RESPONSE_IGNORE_ALL:
1431 		return CDSC_NOTDSC;
1432 	}
1433     }
1434 
1435     n = IS_DSC(dsc->line, "%%+") ? 3 : 8;
1436     while (IS_WHITE(dsc->line[n]))
1437 	n++;
1438     p = dsc->line + n;
1439     if (COMPARE(p, "atend")) {
1440 	if (dsc->scan_section != scan_comments)
1441 	    dsc_unknown(dsc);
1442 	else {
1443 	    int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND,
1444 		dsc->line, dsc->line_length);
1445 	    switch (rc) {
1446 		case CDSC_RESPONSE_OK:
1447 		    /* assume (atend) */
1448 		    /* we should mark it as deferred */
1449 		    break;
1450 		case CDSC_RESPONSE_CANCEL:
1451 		    /* ignore it */
1452 		    break;
1453 		case CDSC_RESPONSE_IGNORE_ALL:
1454 		    return CDSC_NOTDSC;
1455 	    }
1456 	}
1457     }
1458     else if (COMPARE(p, "(atend)")) {
1459 	if (dsc->scan_section != scan_comments)
1460 	    dsc_unknown(dsc);
1461 	/* do nothing */
1462 	/* we should mark it as deferred */
1463     }
1464     else {
1465 	ip = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
1466         if (i) {
1467 	    n+=i;
1468 	    dsc->page_pages = ip;
1469 	    io = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
1470 	    if (i) {
1471 		/* DSC 2 uses extra integer to indicate page order */
1472 		/* DSC 3 uses %%PageOrder: */
1473 		if (dsc->page_order == CDSC_ORDER_UNKNOWN)
1474 		    switch (io) {
1475 			case -1:
1476 			    dsc->page_order = CDSC_DESCEND;
1477 			    break;
1478 			case 0:
1479 			    dsc->page_order = CDSC_SPECIAL;
1480 			    break;
1481 			case 1:
1482 			    dsc->page_order = CDSC_ASCEND;
1483 			    break;
1484 		    }
1485 	    }
1486 	}
1487 	else {
1488 	    int rc = dsc_error(dsc, CDSC_MESSAGE_INCORRECT_USAGE, dsc->line,
1489 		dsc->line_length);
1490 	    switch (rc) {
1491 		case CDSC_RESPONSE_OK:
1492 		case CDSC_RESPONSE_CANCEL:
1493 		    /* ignore it */
1494 		    break;
1495 		case CDSC_RESPONSE_IGNORE_ALL:
1496 		    return CDSC_NOTDSC;
1497 	    }
1498 	}
1499     }
1500     return CDSC_OK;
1501 }
1502 
1503 dsc_private int
dsc_parse_bounding_box(CDSC * dsc,CDSCBBOX ** pbbox,int offset)1504 dsc_parse_bounding_box(CDSC *dsc, CDSCBBOX** pbbox, int offset)
1505 {
1506     unsigned int i, n;
1507     int llx, lly, urx, ury;
1508     float fllx, flly, furx, fury;
1509     char *p;
1510     /* Process first %%BoundingBox: in comments, and last in trailer */
1511     if ((*pbbox != NULL) && (dsc->scan_section == scan_comments)) {
1512 	int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line,
1513 		dsc->line_length);
1514 	switch (rc) {
1515 	    case CDSC_RESPONSE_OK:
1516 	    case CDSC_RESPONSE_CANCEL:
1517 		return CDSC_OK;	/* ignore duplicate comments in header */
1518 	    case CDSC_RESPONSE_IGNORE_ALL:
1519 		return CDSC_NOTDSC;
1520 	}
1521     }
1522     if ((*pbbox != NULL) && (dsc->scan_section == scan_pages)) {
1523 	int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line,
1524 		dsc->line_length);
1525 	switch (rc) {
1526 	    case CDSC_RESPONSE_OK:
1527 	    case CDSC_RESPONSE_CANCEL:
1528 		return CDSC_OK;	/* ignore duplicate comments in header */
1529 	    case CDSC_RESPONSE_IGNORE_ALL:
1530 		return CDSC_NOTDSC;
1531 	}
1532     }
1533     if ((*pbbox != NULL) && (dsc->scan_section == scan_trailer)) {
1534 	int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line,
1535 		dsc->line_length);
1536 	switch (rc) {
1537 	    case CDSC_RESPONSE_OK:
1538 	    case CDSC_RESPONSE_CANCEL:
1539 		break;		/* use duplicate comments in trailer */
1540 	    case CDSC_RESPONSE_IGNORE_ALL:
1541 		return CDSC_NOTDSC;
1542 	}
1543     }
1544     if (*pbbox != NULL) {
1545 	dsc_memfree(dsc, *pbbox);
1546 	*pbbox = NULL;
1547     }
1548 
1549     /* should only process first %%BoundingBox: */
1550 
1551     while (IS_WHITE(dsc->line[offset]))
1552 	offset++;
1553     p = dsc->line + offset;
1554 
1555     if (COMPARE(p, "atend")) {
1556 	if (dsc->scan_section == scan_trailer)
1557 	    dsc_unknown(dsc);
1558 	else {
1559 	    int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line,
1560 		    dsc->line_length);
1561 	    switch (rc) {
1562 		case CDSC_RESPONSE_OK:
1563 		    /* assume (atend) */
1564 		    /* we should mark it as deferred */
1565 		    break;
1566 		case CDSC_RESPONSE_CANCEL:
1567 		    /* ignore it */
1568 		    break;
1569 		case CDSC_RESPONSE_IGNORE_ALL:
1570 		    return CDSC_NOTDSC;
1571 	    }
1572 	}
1573     }
1574     else if (COMPARE(p, "(atend)")) {
1575 	if (dsc->scan_section == scan_trailer)
1576 	    dsc_unknown(dsc);
1577 	/* do nothing */
1578 	/* we should mark it as deferred */
1579     }
1580     else {
1581         /* llx = */ lly = urx = ury = 0;
1582 	n = offset;
1583 	llx = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
1584 	n += i;
1585 	if (i)
1586 	    lly = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
1587 	n += i;
1588 	if (i)
1589 	    urx = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
1590 	n += i;
1591 	if (i)
1592 	    ury = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
1593 	if (i) {
1594 	    *pbbox = (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX));
1595 	    if (*pbbox == NULL)
1596 		return CDSC_ERROR;	/* no memory */
1597 	    (*pbbox)->llx = llx;
1598 	    (*pbbox)->lly = lly;
1599 	    (*pbbox)->urx = urx;
1600 	    (*pbbox)->ury = ury;
1601 	}
1602 	else {
1603 	    int rc = dsc_error(dsc, CDSC_MESSAGE_BBOX, dsc->line,
1604 		dsc->line_length);
1605 	    switch (rc) {
1606 	      case CDSC_RESPONSE_OK:
1607 		/* fllx = */ flly = furx = fury = 0.0;
1608 		n = offset;
1609 		n += i;
1610 		fllx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1611 		n += i;
1612 		if (i)
1613 		    flly = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1614 		n += i;
1615 		if (i)
1616 		    furx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1617 		n += i;
1618 		if (i)
1619 		    fury = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1620 		if (i) {
1621 		    *pbbox = (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX));
1622 		    if (*pbbox == NULL)
1623 			return CDSC_ERROR;	/* no memory */
1624 			(*pbbox)->llx = (int)fllx;
1625 			(*pbbox)->lly = (int)flly;
1626 			(*pbbox)->urx = (int)(furx+0.999);
1627 			(*pbbox)->ury = (int)(fury+0.999);
1628 		}
1629 		return CDSC_OK;
1630 	    case CDSC_RESPONSE_CANCEL:
1631 		return CDSC_OK;
1632 	    case CDSC_RESPONSE_IGNORE_ALL:
1633 		return CDSC_NOTDSC;
1634 	  }
1635 	}
1636     }
1637     return CDSC_OK;
1638 }
1639 
1640 dsc_private int
dsc_parse_float_bounding_box(CDSC * dsc,CDSCFBBOX ** pbbox,int offset)1641 dsc_parse_float_bounding_box(CDSC *dsc, CDSCFBBOX** pbbox, int offset)
1642 {
1643     unsigned int i, n;
1644     float fllx, flly, furx, fury;
1645     char *p;
1646     /* Process first %%HiResBoundingBox: or %%CropBox: in comments,
1647      * and last in trailer.
1648      */
1649     if ((*pbbox != NULL) && (dsc->scan_section == scan_comments)) {
1650 	int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line,
1651 		dsc->line_length);
1652 	switch (rc) {
1653 	    case CDSC_RESPONSE_OK:
1654 	    case CDSC_RESPONSE_CANCEL:
1655 		return CDSC_OK;	/* ignore duplicate comments in header */
1656 	    case CDSC_RESPONSE_IGNORE_ALL:
1657 		return CDSC_NOTDSC;
1658 	}
1659     }
1660     if ((*pbbox != NULL) && (dsc->scan_section == scan_pages)) {
1661 	int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line,
1662 		dsc->line_length);
1663 	switch (rc) {
1664 	    case CDSC_RESPONSE_OK:
1665 	    case CDSC_RESPONSE_CANCEL:
1666 		return CDSC_OK;	/* ignore duplicate comments in header */
1667 	    case CDSC_RESPONSE_IGNORE_ALL:
1668 		return CDSC_NOTDSC;
1669 	}
1670     }
1671     if ((*pbbox != NULL) && (dsc->scan_section == scan_trailer)) {
1672 	int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line,
1673 		dsc->line_length);
1674 	switch (rc) {
1675 	    case CDSC_RESPONSE_OK:
1676 	    case CDSC_RESPONSE_CANCEL:
1677 		break;		/* use duplicate comments in trailer */
1678 	    case CDSC_RESPONSE_IGNORE_ALL:
1679 		return CDSC_NOTDSC;
1680 	}
1681     }
1682     if (*pbbox != NULL) {
1683 	dsc_memfree(dsc, *pbbox);
1684 	*pbbox = NULL;
1685     }
1686 
1687     /* should only process first %%BoundingBox: */
1688 
1689     while (IS_WHITE(dsc->line[offset]))
1690 	offset++;
1691     p = dsc->line + offset;
1692 
1693     if (COMPARE(p, "atend")) {
1694 	if (dsc->scan_section == scan_trailer)
1695 	    dsc_unknown(dsc);
1696 	else {
1697 	    int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line,
1698 		    dsc->line_length);
1699 	    switch (rc) {
1700 		case CDSC_RESPONSE_OK:
1701 		    /* assume (atend) */
1702 		    /* we should mark it as deferred */
1703 		    break;
1704 		case CDSC_RESPONSE_CANCEL:
1705 		    /* ignore it */
1706 		    break;
1707 		case CDSC_RESPONSE_IGNORE_ALL:
1708 		    return CDSC_NOTDSC;
1709 	    }
1710 	}
1711     }
1712     else if (COMPARE(p, "(atend)")) {
1713 	if (dsc->scan_section == scan_trailer)
1714 	    dsc_unknown(dsc);
1715 	/* do nothing */
1716 	/* we should mark it as deferred */
1717     }
1718     else {
1719 	/* fllx = */ flly = furx = fury = 0.0;
1720 	n = offset;
1721 	fllx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1722 	n += i;
1723 	if (i)
1724 	    flly = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1725 	n += i;
1726 	if (i)
1727 	    furx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1728 	n += i;
1729 	if (i)
1730 	    fury = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1731 	if (i) {
1732 	    *pbbox = (CDSCFBBOX *)dsc_memalloc(dsc, sizeof(CDSCFBBOX));
1733 	    if (*pbbox == NULL)
1734 		return CDSC_ERROR;	/* no memory */
1735 	    (*pbbox)->fllx = fllx;
1736 	    (*pbbox)->flly = flly;
1737 	    (*pbbox)->furx = furx;
1738 	    (*pbbox)->fury = fury;
1739 	}
1740     }
1741     return CDSC_OK;
1742 }
1743 
1744 dsc_private int
dsc_parse_orientation(CDSC * dsc,unsigned int * porientation,int offset)1745 dsc_parse_orientation(CDSC *dsc, unsigned int *porientation, int offset)
1746 {
1747     char *p;
1748     if ((dsc->page_orientation != CDSC_ORIENT_UNKNOWN) &&
1749 	(dsc->scan_section == scan_comments)) {
1750 	int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line,
1751 		dsc->line_length);
1752 	switch (rc) {
1753 	    case CDSC_RESPONSE_OK:
1754 	    case CDSC_RESPONSE_CANCEL:
1755 		return CDSC_OK;	/* ignore duplicate comments in header */
1756 	    case CDSC_RESPONSE_IGNORE_ALL:
1757 		return CDSC_NOTDSC;
1758 	}
1759     }
1760     if ((dsc->page_orientation != CDSC_ORIENT_UNKNOWN) &&
1761 	(dsc->scan_section == scan_trailer)) {
1762 	int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line,
1763 		dsc->line_length);
1764 	switch (rc) {
1765 	    case CDSC_RESPONSE_OK:
1766 	    case CDSC_RESPONSE_CANCEL:
1767 		break;		/* use duplicate comments in header; */
1768 	    case CDSC_RESPONSE_IGNORE_ALL:
1769 		return CDSC_NOTDSC;
1770 	}
1771     }
1772     p = dsc->line + offset;
1773     while (IS_WHITE(*p))
1774 	p++;
1775     if (COMPARE(p, "atend")) {
1776 	if (dsc->scan_section == scan_trailer)
1777 	    dsc_unknown(dsc);
1778 	else {
1779 	    int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND,
1780 		dsc->line, dsc->line_length);
1781 	    switch (rc) {
1782 		case CDSC_RESPONSE_OK:
1783 		    /* assume (atend) */
1784 		    /* we should mark it as deferred */
1785 		    break;
1786 		case CDSC_RESPONSE_CANCEL:
1787 		    /* ignore it */
1788 		    break;
1789 		case CDSC_RESPONSE_IGNORE_ALL:
1790 		    return CDSC_NOTDSC;
1791 	    }
1792 	}
1793     }
1794     else if (COMPARE(p, "(atend)")) {
1795 	if (dsc->scan_section == scan_trailer)
1796 	    dsc_unknown(dsc);
1797 	/* do nothing */
1798 	/* we should mark it as deferred */
1799     }
1800     else if (COMPARE(p, "Portrait")) {
1801 	*porientation = CDSC_PORTRAIT;
1802     }
1803     else if (COMPARE(p, "Landscape")) {
1804 	*porientation = CDSC_LANDSCAPE;
1805     }
1806     else {
1807 	dsc_unknown(dsc);
1808     }
1809     return CDSC_OK;
1810 }
1811 
1812 dsc_private int
dsc_parse_order(CDSC * dsc)1813 dsc_parse_order(CDSC *dsc)
1814 {
1815     char *p;
1816     if ((dsc->page_order != CDSC_ORDER_UNKNOWN) &&
1817 	(dsc->scan_section == scan_comments)) {
1818 	int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line,
1819 		dsc->line_length);
1820 	switch (rc) {
1821 	    case CDSC_RESPONSE_OK:
1822 	    case CDSC_RESPONSE_CANCEL:
1823 		return CDSC_OK;	/* ignore duplicate comments in header */
1824 	    case CDSC_RESPONSE_IGNORE_ALL:
1825 		return CDSC_NOTDSC;
1826 	}
1827     }
1828     if ((dsc->page_order != CDSC_ORDER_UNKNOWN) &&
1829 	(dsc->scan_section == scan_trailer)) {
1830 	int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line,
1831 		dsc->line_length);
1832 	switch (rc) {
1833 	    case CDSC_RESPONSE_OK:
1834 	    case CDSC_RESPONSE_CANCEL:
1835 		break;		/* use duplicate comments in trailer */
1836 	    case CDSC_RESPONSE_IGNORE_ALL:
1837 		return CDSC_NOTDSC;
1838 	}
1839     }
1840 
1841     p = dsc->line + (IS_DSC(dsc->line, "%%+") ? 3 : 13);
1842     while (IS_WHITE(*p))
1843 	p++;
1844     if (COMPARE(p, "atend")) {
1845 	if (dsc->scan_section == scan_trailer)
1846 	    dsc_unknown(dsc);
1847 	else {
1848 	    int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line,
1849 		    dsc->line_length);
1850 	    switch (rc) {
1851 		case CDSC_RESPONSE_OK:
1852 		    /* assume (atend) */
1853 		    /* we should mark it as deferred */
1854 		    break;
1855 		case CDSC_RESPONSE_CANCEL:
1856 		    /* ignore it */
1857 		    break;
1858 		case CDSC_RESPONSE_IGNORE_ALL:
1859 		    return CDSC_NOTDSC;
1860 	    }
1861 	}
1862     }
1863     else if (COMPARE(p, "(atend)")) {
1864 	if (dsc->scan_section == scan_trailer)
1865 	    dsc_unknown(dsc);
1866 	/* do nothing */
1867 	/* we should mark it as deferred */
1868     }
1869     else if (COMPARE(p, "Ascend")) {
1870 	dsc->page_order = CDSC_ASCEND;
1871     }
1872     else if (COMPARE(p, "Descend")) {
1873 	dsc->page_order = CDSC_DESCEND;
1874     }
1875     else if (COMPARE(p, "Special")) {
1876 	dsc->page_order = CDSC_SPECIAL;
1877     }
1878     else {
1879 	dsc_unknown(dsc);
1880     }
1881     return CDSC_OK;
1882 }
1883 
1884 
1885 dsc_private int
dsc_parse_media(CDSC * dsc,const CDSCMEDIA ** page_media)1886 dsc_parse_media(CDSC *dsc, const CDSCMEDIA **page_media)
1887 {
1888     char media_name[MAXSTR];
1889     int n = IS_DSC(dsc->line, "%%+") ? 3 : 12; /* %%PageMedia: */
1890     unsigned int i;
1891 
1892     if (dsc_copy_string(media_name, sizeof(media_name)-1,
1893 	dsc->line+n, dsc->line_length-n, NULL)) {
1894 	for (i=0; i<dsc->media_count; i++) {
1895 	    if (dsc->media[i]->name &&
1896 		(dsc_stricmp(media_name, dsc->media[i]->name) == 0)) {
1897 		*page_media = dsc->media[i];
1898 		return CDSC_OK;
1899 	    }
1900 	}
1901     }
1902     dsc_unknown(dsc);
1903 
1904     return CDSC_OK;
1905 }
1906 
1907 
1908 dsc_private int
dsc_parse_document_media(CDSC * dsc)1909 dsc_parse_document_media(CDSC *dsc)
1910 {
1911     unsigned int i, n;
1912     CDSCMEDIA lmedia;
1913     GSBOOL blank_line;
1914 
1915     if (IS_DSC(dsc->line, "%%DocumentMedia:"))
1916 	n = 16;
1917     else if (IS_DSC(dsc->line, "%%+"))
1918 	n = 3;
1919     else
1920 	return CDSC_ERROR;	/* error */
1921 
1922     /* check for blank remainder of line */
1923     blank_line = TRUE;
1924     for (i=n; i<dsc->line_length; i++) {
1925 	if (!IS_WHITE_OR_EOL(dsc->line[i])) {
1926 	    blank_line = FALSE;
1927 	    break;
1928 	}
1929     }
1930 
1931     if (!blank_line) {
1932 	char name[MAXSTR];
1933 	char colour[MAXSTR];
1934 	char type[MAXSTR];
1935 	lmedia.name = lmedia.colour = lmedia.type = (char *)NULL;
1936 	lmedia.width = lmedia.height = lmedia.weight = 0;
1937 	lmedia.mediabox = (CDSCBBOX *)NULL;
1938 	lmedia.name = dsc_copy_string(name, sizeof(name),
1939 		dsc->line+n, dsc->line_length-n, &i);
1940 	n+=i;
1941 	if (i)
1942 	    lmedia.width = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1943 	n+=i;
1944 	if (i)
1945 	    lmedia.height = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1946 	n+=i;
1947 	if (i)
1948 	    lmedia.weight = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1949 	n+=i;
1950 	if (i)
1951 	    lmedia.colour = dsc_copy_string(colour, sizeof(colour),
1952 		dsc->line+n, dsc->line_length-n, &i);
1953 	n+=i;
1954 	if (i)
1955 	    lmedia.type = dsc_copy_string(type, sizeof(type),
1956 		dsc->line+n, dsc->line_length-n, &i);
1957 
1958 	if (i==0)
1959 	    dsc_unknown(dsc); /* we didn't get all fields */
1960 	else {
1961 	    if (dsc_add_media(dsc, &lmedia))
1962 		return CDSC_ERROR;	/* out of memory */
1963 	}
1964     }
1965     return CDSC_OK;
1966 }
1967 
1968 /* viewing orientation is believed to be the first four elements of
1969  * a CTM matrix
1970  */
1971 dsc_private int
dsc_parse_viewing_orientation(CDSC * dsc,CDSCCTM ** pctm)1972 dsc_parse_viewing_orientation(CDSC *dsc, CDSCCTM **pctm)
1973 {
1974     CDSCCTM ctm;
1975     unsigned int i, n;
1976 
1977     if (*pctm != NULL) {
1978 	dsc_memfree(dsc, *pctm);
1979 	*pctm = NULL;
1980     }
1981 
1982     n = IS_DSC(dsc->line, "%%+") ? 3 : 21;  /* %%ViewingOrientation: */
1983     while (IS_WHITE(dsc->line[n]))
1984 	n++;
1985 
1986     /* ctm.xx = */ ctm.xy = ctm.yx = ctm.yy = 0.0;
1987     ctm.xx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1988     n += i;
1989     if (i)
1990         ctm.xy = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1991     n += i;
1992     if (i)
1993         ctm.yx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1994     n += i;
1995     if (i)
1996         ctm.yy = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1997     if (i==0) {
1998 	dsc_unknown(dsc); /* we didn't get all fields */
1999     }
2000     else {
2001 	*pctm = (CDSCCTM *)dsc_memalloc(dsc, sizeof(CDSCCTM));
2002 	if (*pctm == NULL)
2003 	    return CDSC_ERROR;	/* no memory */
2004 	**pctm = ctm;
2005     }
2006     return CDSC_OK;
2007 }
2008 
2009 
2010 /* This is called before dsc_read_line(), since we may
2011  * need to skip a binary header which contains a new line
2012  * character
2013  */
2014 dsc_private int
dsc_scan_type(CDSC * dsc)2015 dsc_scan_type(CDSC *dsc)
2016 {
2017     unsigned char *p;
2018     unsigned char *line = (unsigned char *)(dsc->data + dsc->data_index);
2019     int length = dsc->data_length - dsc->data_index;
2020 
2021     /* Types that should be known:
2022      *   DSC
2023      *   EPSF
2024      *   PJL + any of above
2025      *   ^D + any of above
2026      *   DOS EPS
2027      *   PDF
2028      *   non-DSC
2029      */
2030 
2031     /* First process any non PostScript headers */
2032     /* At this stage we do not have a complete line */
2033 
2034     if (length == 0)
2035 	return CDSC_NEEDMORE;
2036 
2037     /* If we have already found a DOS EPS header, */
2038     /* ignore all until the PostScript section */
2039     if (dsc->skip_bytes) {
2040 	int cnt = min(dsc->skip_bytes,
2041 		     (int)(dsc->data_length - dsc->data_index));
2042 	dsc->skip_bytes -= cnt;
2043 	dsc->data_index += cnt;
2044 	length -= cnt;
2045 	line += cnt;
2046 	if (dsc->skip_bytes != 0)
2047 	    return CDSC_NEEDMORE;
2048     }
2049 
2050     if (dsc->skip_pjl) {
2051 	/* skip until first PostScript comment */
2052 	while (length >= 2) {
2053 	    while (length && !IS_EOL(line[0])) {
2054 		/* skip until EOL character */
2055 		line++;
2056 		dsc->data_index++;
2057 		length--;
2058 	    }
2059 	    while ((length >= 2) && IS_EOL(line[0]) && IS_EOL(line[1])) {
2060 		/* skip until EOL followed by non-EOL */
2061 		line++;
2062 		dsc->data_index++;
2063 		length--;
2064 	    }
2065 	    if (length < 2)
2066 		return CDSC_NEEDMORE;
2067 
2068 	    if (IS_EOL(line[0]) && line[1]=='%') {
2069 		line++;
2070 		dsc->data_index++;
2071 		length--;
2072 		dsc->skip_pjl = FALSE;
2073 		break;
2074 	    }
2075 	    else {
2076 		line++;
2077 		dsc->data_index++;
2078 		length--;
2079 	    }
2080 	}
2081 	if (dsc->skip_pjl)
2082 	    return CDSC_NEEDMORE;
2083     }
2084 
2085     if (length == 0)
2086 	return CDSC_NEEDMORE;
2087 
2088     if (line[0] == '\004') {
2089 	line++;
2090 	dsc->data_index++;
2091 	length--;
2092 	dsc->ctrld = TRUE;
2093     }
2094 
2095     if (line[0] == '\033') {
2096 	/* possibly PJL */
2097 	if (length < 9)
2098 	    return CDSC_NEEDMORE;
2099 	if (COMPARE(line, "\033%-12345X")) {
2100 	    dsc->skip_pjl = TRUE;  /* skip until first PostScript comment */
2101 	    dsc->pjl = TRUE;
2102 	    dsc->data_index += 9;
2103 	    return dsc_scan_type(dsc);
2104 	}
2105     }
2106 
2107     if ((line[0]==0x0) && (length < 2))
2108 	return CDSC_NEEDMORE;	/* Could be Mac Binary EPSF */
2109     if ((line[0]==0x0) && (line[1] >= 1) && (line[1] <= 63) && (length < 128))
2110 	return CDSC_NEEDMORE;	/* Could be Mac Binary EPSF */
2111     if ((line[0]==0x0) && (line[1] == 0x5) && (length < 4))
2112 	return CDSC_NEEDMORE;	/* Could be Mac AppleSingle/AppleDouble */
2113     if ((line[0]==0xc5) && (length < 4))
2114 	return CDSC_NEEDMORE;	/* Could be DOS EPS */
2115 
2116     if ((line[0]==0xc5) && (line[1]==0xd0) &&
2117 	 (line[2]==0xd3) && (line[3]==0xc6) ) {
2118 	/* id is "EPSF" with bit 7 set */
2119 	/* read DOS EPS header, then ignore all bytes until the PS section */
2120 	if (length < 30)
2121 	    return CDSC_NEEDMORE;
2122 	dsc->line = (char *)line;
2123 	if (dsc_read_doseps(dsc))
2124 	    return CDSC_ERROR;
2125     }
2126     else if ((line[0]==0x0) && (line[1]==0x05) &&
2127 	 (line[2]==0x16) && ((line[3]==0x0) || (line[3] == 0x07))) {
2128 	/* Mac AppleSingle or AppleDouble */
2129 	GSDWORD version;
2130 	GSWORD entries;
2131 	if (length < 26)
2132 	    return CDSC_NEEDMORE;
2133 	version = dsc_get_bigendian_dword(line+4);
2134 	entries = dsc_get_bigendian_word(line+24);
2135 	if ((version == 0x00010000) || (version == 0x00020000)) {
2136 	    if (length < (int)(26 + entries * 12))
2137 		return CDSC_NEEDMORE;
2138 	    dsc->line = (char *)line;
2139 	    if (dsc_read_applesingle(dsc))
2140 		return CDSC_ERROR;
2141 	}
2142     }
2143     else if ((line[0]==0x0) &&
2144 	(line[1] >= 1) && (line[1] <= 63) &&
2145         (line[74]==0x0) &&
2146         (line[65]=='E') && (line[66]=='P') &&
2147         (line[67]=='S') && (line[68]=='F')) {
2148 	/* Mac Binary EPSF */
2149 	dsc->line = (char *)line;
2150 	if (dsc_read_macbin(dsc))
2151 	    return CDSC_ERROR;
2152     }
2153     else {
2154 	if (length < 2)
2155 	    return CDSC_NEEDMORE;
2156 	if ((line[0] == '%') && (line[1] == 'P')) {
2157 	    if (length < 5)
2158 	        return CDSC_NEEDMORE;
2159 	    if (COMPARE(line, "%PDF-")) {
2160 		dsc->pdf = TRUE;
2161 		dsc->scan_section = scan_comments;
2162 		return CDSC_OK;
2163 	    }
2164 	}
2165     }
2166 
2167     /* Finally process PostScript headers */
2168 
2169     if (dsc_read_line(dsc) <= 0)
2170 	return CDSC_NEEDMORE;
2171 
2172     dsc->dsc_version = dsc_add_line(dsc, dsc->line, dsc->line_length);
2173     if (COMPARE(dsc->line, "%!PS-Adobe")) {
2174 	dsc->dsc = TRUE;
2175 	dsc->begincomments = DSC_START(dsc);
2176 	if (dsc->dsc_version == NULL)
2177 	    return CDSC_ERROR;	/* no memory */
2178 	p = (unsigned char *)dsc->line + 14;
2179 	while (IS_WHITE(*p))
2180 	    p++;
2181 	if (COMPARE(p, "EPSF-"))
2182 	    dsc->epsf = TRUE;
2183 	dsc->scan_section = scan_comments;
2184 	return CDSC_PSADOBE;
2185     }
2186     if (COMPARE(dsc->line, "%!")) {
2187 	dsc->scan_section = scan_comments;
2188 	return CDSC_NOTDSC;
2189     }
2190 
2191     dsc->scan_section = scan_comments;
2192     return CDSC_NOTDSC;	/* unrecognised */
2193 }
2194 
2195 
2196 
2197 dsc_private int
dsc_scan_comments(CDSC * dsc)2198 dsc_scan_comments(CDSC *dsc)
2199 {
2200     /* Comments section ends at */
2201     /*  %%EndComments */
2202     /*  another section */
2203     /*  line that does not start with %% */
2204     /* Save a few important lines */
2205 
2206     char *line = dsc->line;
2207     GSBOOL continued = FALSE;
2208     dsc->id = CDSC_OK;
2209     if (IS_DSC(line, "%%EndComments")) {
2210 	dsc->id = CDSC_ENDCOMMENTS;
2211 	dsc->endcomments = DSC_END(dsc);
2212 	dsc->scan_section = scan_pre_preview;
2213 	return CDSC_OK;
2214     }
2215     else if (IS_DSC(line, "%%BeginComments")) {
2216 	/* ignore because we are in this section */
2217 	dsc->id = CDSC_BEGINCOMMENTS;
2218     }
2219     else if (dsc_is_section(line)) {
2220 	dsc->endcomments = DSC_START(dsc);
2221 	dsc->scan_section = scan_pre_preview;
2222 	return CDSC_PROPAGATE;
2223     }
2224     else if (line[0] == '%' && IS_WHITE_OR_EOL(line[1])) {
2225 	dsc->endcomments = DSC_START(dsc);
2226 	dsc->scan_section = scan_pre_preview;
2227 	return CDSC_PROPAGATE;
2228     }
2229     else if (line[0] != '%') {
2230 	dsc->id = CDSC_OK;
2231 	dsc->endcomments = DSC_START(dsc);
2232 	dsc->scan_section = scan_pre_preview;
2233 	return CDSC_PROPAGATE;
2234     }
2235     else if (IS_DSC(line, "%%Begin")) {
2236 	dsc->endcomments = DSC_START(dsc);
2237 	dsc->scan_section = scan_pre_preview;
2238 	return CDSC_PROPAGATE;
2239     }
2240 
2241     /* Handle continuation lines.
2242      * To simply processing, we assume that contination lines
2243      * will only occur if repeat parameters are allowed and that
2244      * a complete set of these parameters appears on each line.
2245      * This is more restrictive than the DSC specification, but
2246      * is valid for the DSC comments understood by this parser
2247      * for all documents that we have seen.
2248      */
2249     if (IS_DSC(line, "%%+")) {
2250 	line = dsc->last_line;
2251 	continued = TRUE;
2252     }
2253     else
2254 	dsc_save_line(dsc);
2255 
2256     if (IS_DSC(line, "%%Pages:")) {
2257 	dsc->id = CDSC_PAGES;
2258 	if (dsc_parse_pages(dsc) != 0)
2259 	    return CDSC_ERROR;
2260     }
2261     else if (IS_DSC(line, "%%Creator:")) {
2262 	dsc->id = CDSC_CREATOR;
2263 	dsc->dsc_creator = dsc_add_line(dsc, dsc->line+10, dsc->line_length-10);
2264 	if (dsc->dsc_creator==NULL)
2265 	    return CDSC_ERROR;
2266     }
2267     else if (IS_DSC(line, "%%CreationDate:")) {
2268 	dsc->id = CDSC_CREATIONDATE;
2269 	dsc->dsc_date = dsc_add_line(dsc, dsc->line+15, dsc->line_length-15);
2270 	if (dsc->dsc_date==NULL)
2271 	    return CDSC_ERROR;
2272     }
2273     else if (IS_DSC(line, "%%Title:")) {
2274 	dsc->id = CDSC_TITLE;
2275 	dsc->dsc_title = dsc_add_line(dsc, dsc->line+8, dsc->line_length-8);
2276 	if (dsc->dsc_title==NULL)
2277 	    return CDSC_ERROR;
2278     }
2279     else if (IS_DSC(line, "%%For:")) {
2280 	dsc->id = CDSC_FOR;
2281 	dsc->dsc_for = dsc_add_line(dsc, dsc->line+6, dsc->line_length-6);
2282 	if (dsc->dsc_for==NULL)
2283 	    return CDSC_ERROR;
2284     }
2285     else if (IS_DSC(line, "%%LanguageLevel:")) {
2286 	unsigned int n = continued ? 3 : 16;
2287 	unsigned int i;
2288 	int ll;
2289 	dsc->id = CDSC_LANGUAGELEVEL;
2290 	ll = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
2291 	if (i) {
2292 	    if ( (ll==1) || (ll==2) || (ll==3) )
2293 		dsc->language_level = ll;
2294 	    else {
2295 		dsc_unknown(dsc);
2296 	    }
2297 	}
2298 	else
2299 	    dsc_unknown(dsc);
2300     }
2301     else if (IS_DSC(line, "%%BoundingBox:")) {
2302 	dsc->id = CDSC_BOUNDINGBOX;
2303 	if (dsc_parse_bounding_box(dsc, &(dsc->bbox), continued ? 3 : 14))
2304 	    return CDSC_ERROR;
2305     }
2306     else if (IS_DSC(line, "%%HiResBoundingBox:")) {
2307 	dsc->id = CDSC_HIRESBOUNDINGBOX;
2308 	if (dsc_parse_float_bounding_box(dsc, &(dsc->hires_bbox),
2309 	    continued ? 3 : 19))
2310 	    return CDSC_ERROR;
2311     }
2312     else if (IS_DSC(line, "%%CropBox:")) {
2313 	dsc->id = CDSC_CROPBOX;
2314 	if (dsc_parse_float_bounding_box(dsc, &(dsc->crop_box),
2315 	    continued ? 3 : 10))
2316 	    return CDSC_ERROR;
2317     }
2318     else if (IS_DSC(line, "%%Orientation:")) {
2319 	dsc->id = CDSC_ORIENTATION;
2320 	if (dsc_parse_orientation(dsc, &(dsc->page_orientation),
2321 		continued ? 3 : 14))
2322 	    return CDSC_ERROR;
2323     }
2324     else if (IS_DSC(line, "%%PageOrder:")) {
2325 	dsc->id = CDSC_PAGEORDER;
2326 	if (dsc_parse_order(dsc))
2327 	    return CDSC_ERROR;
2328     }
2329     else if (IS_DSC(line, "%%DocumentMedia:")) {
2330 	dsc->id = CDSC_DOCUMENTMEDIA;
2331 	if (dsc_parse_document_media(dsc))
2332 	    return CDSC_ERROR;
2333     }
2334     else if (IS_DSC(line, "%%DocumentPaperSizes:")) {
2335 	/* DSC 2.1 */
2336 	unsigned int n = continued ? 3 : 21;
2337 	unsigned int count = 0;
2338 	unsigned int i = 1;
2339 	char name[MAXSTR];
2340 	char *p;
2341 	dsc->id = CDSC_DOCUMENTPAPERSIZES;
2342 	while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) {
2343 	    p = dsc_copy_string(name, sizeof(name)-1,
2344 		    dsc->line+n, dsc->line_length-n, &i);
2345 	    if (i && p) {
2346 		const CDSCMEDIA *m = dsc_known_media;
2347 		if (count >= dsc->media_count) {
2348 		    /* set some default values */
2349 		    CDSCMEDIA lmedia;
2350 		    lmedia.name = p;
2351 		    lmedia.width = 595.0;
2352 		    lmedia.height = 842.0;
2353 		    lmedia.weight = 80.0;
2354 		    lmedia.colour = NULL;
2355 		    lmedia.type = NULL;
2356 		    lmedia.mediabox = NULL;
2357 		    if (dsc_add_media(dsc, &lmedia))
2358 			return CDSC_ERROR;
2359 		}
2360 		else
2361 		    dsc->media[count]->name =
2362 			dsc_alloc_string(dsc, p, (int)strlen(p));
2363 		/* find in list of known media */
2364 		while (m && m->name) {
2365 		    if (dsc_stricmp(p, m->name)==0) {
2366 			dsc->media[count]->width = m->width;
2367 			dsc->media[count]->height = m->height;
2368 			break;
2369 		    }
2370 		    m++;
2371 		}
2372 	    }
2373 	    n+=i;
2374 	    count++;
2375 	}
2376     }
2377     else if (IS_DSC(line, "%%DocumentPaperForms:")) {
2378 	/* DSC 2.1 */
2379 	unsigned int n = continued ? 3 : 21;
2380 	unsigned int count = 0;
2381 	unsigned int i = 1;
2382 	char type[MAXSTR];
2383 	char *p;
2384 	dsc->id = CDSC_DOCUMENTPAPERFORMS;
2385 	while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) {
2386 	    p = dsc_copy_string(type, sizeof(type)-1,
2387 		    dsc->line+n, dsc->line_length-n, &i);
2388 	    if (i && p) {
2389 		if (count >= dsc->media_count) {
2390 		    /* set some default values */
2391 		    CDSCMEDIA lmedia;
2392 		    lmedia.name = NULL;
2393 		    lmedia.width = 595.0;
2394 		    lmedia.height = 842.0;
2395 		    lmedia.weight = 80.0;
2396 		    lmedia.colour = NULL;
2397 		    lmedia.type = p;
2398 		    lmedia.mediabox = NULL;
2399 		    if (dsc_add_media(dsc, &lmedia))
2400 			return CDSC_ERROR;
2401 		}
2402 		else
2403 		    dsc->media[count]->type =
2404 			dsc_alloc_string(dsc, p, (int)strlen(p));
2405 	    }
2406 	    n+=i;
2407 	    count++;
2408 	}
2409     }
2410     else if (IS_DSC(line, "%%DocumentPaperColors:")) {
2411 	/* DSC 2.1 */
2412 	unsigned int n = continued ? 3 : 22;
2413 	unsigned int count = 0;
2414 	unsigned int i = 1;
2415 	char colour[MAXSTR];
2416 	char *p;
2417 	dsc->id = CDSC_DOCUMENTPAPERCOLORS;
2418 	while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) {
2419 	    p = dsc_copy_string(colour, sizeof(colour)-1,
2420 		    dsc->line+n, dsc->line_length-n, &i);
2421 	    if (i && p) {
2422 		if (count >= dsc->media_count) {
2423 		    /* set some default values */
2424 		    CDSCMEDIA lmedia;
2425 		    lmedia.name = NULL;
2426 		    lmedia.width = 595.0;
2427 		    lmedia.height = 842.0;
2428 		    lmedia.weight = 80.0;
2429 		    lmedia.colour = p;
2430 		    lmedia.type = NULL;
2431 		    lmedia.mediabox = NULL;
2432 		    if (dsc_add_media(dsc, &lmedia))
2433 			return CDSC_ERROR;
2434 		}
2435 		else
2436 		    dsc->media[count]->colour =
2437 			dsc_alloc_string(dsc, p, (int)strlen(p));
2438 	    }
2439 	    n+=i;
2440 	    count++;
2441 	}
2442     }
2443     else if (IS_DSC(line, "%%DocumentPaperWeights:")) {
2444 	/* DSC 2.1 */
2445 	unsigned int n = continued ? 3 : 23;
2446 	unsigned int count = 0;
2447 	unsigned int i = 1;
2448 	float w;
2449 	dsc->id = CDSC_DOCUMENTPAPERWEIGHTS;
2450 	while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) {
2451 	    w = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
2452 	    if (i) {
2453 		if (count >= dsc->media_count) {
2454 		    /* set some default values */
2455 		    CDSCMEDIA lmedia;
2456 		    lmedia.name = NULL;
2457 		    lmedia.width = 595.0;
2458 		    lmedia.height = 842.0;
2459 		    lmedia.weight = w;
2460 		    lmedia.colour = NULL;
2461 		    lmedia.type = NULL;
2462 		    lmedia.mediabox = NULL;
2463 		    if (dsc_add_media(dsc, &lmedia))
2464 			return CDSC_ERROR;
2465 		}
2466 		else
2467 		    dsc->media[count]->weight = w;
2468 	    }
2469 	    n+=i;
2470 	    count++;
2471 	}
2472     }
2473     else if (IS_DSC(line, "%%DocumentData:")) {
2474 	unsigned int n = continued ? 3 : 15;
2475 	char *p = dsc->line + n;
2476         while (IS_WHITE(*p))
2477 	    p++;
2478 	dsc->id = CDSC_DOCUMENTDATA;
2479 	if (COMPARE(p, "Clean7Bit"))
2480 	    dsc->document_data = CDSC_CLEAN7BIT;
2481 	else if (COMPARE(p, "Clean8Bit"))
2482 	    dsc->document_data = CDSC_CLEAN8BIT;
2483 	else if (COMPARE(p, "Binary"))
2484 	    dsc->document_data = CDSC_BINARY;
2485 	else
2486 	    dsc_unknown(dsc);
2487     }
2488     else if (IS_DSC(line, "%%Requirements:")) {
2489 	dsc->id = CDSC_REQUIREMENTS;
2490 	/* ignore */
2491     }
2492     else if (IS_DSC(line, "%%DocumentNeededFonts:")) {
2493 	dsc->id = CDSC_DOCUMENTNEEDEDFONTS;
2494 	/* ignore */
2495     }
2496     else if (IS_DSC(line, "%%DocumentSuppliedFonts:")) {
2497 	dsc->id = CDSC_DOCUMENTSUPPLIEDFONTS;
2498 	/* ignore */
2499     }
2500     else if (IS_DSC(line, "%%PlateFile:")) {
2501 	dsc->id = CDSC_PLATEFILE;
2502 	if (dsc_parse_platefile(dsc) != CDSC_OK)
2503 	    dsc->id = CDSC_UNKNOWNDSC;
2504     }
2505     else if (IS_DSC(line, "%%CyanPlate:") ||
2506 	IS_DSC(line, "%%MagentaPlate:") ||
2507 	IS_DSC(line, "%%YellowPlate:") ||
2508 	IS_DSC(line, "%%BlackPlate:")) {
2509 	dsc->id = CDSC_PLATEFILE;
2510 	if (dsc_parse_dcs1plate(dsc) != CDSC_OK)
2511 	    dsc->id = CDSC_UNKNOWNDSC;
2512     }
2513     else if (IS_DSC(line, "%%DocumentProcessColors:")) {
2514 	dsc->id = CDSC_DOCUMENTPROCESSCOLORS;
2515 	if (dsc_parse_process_colours(dsc) != CDSC_OK)
2516 	    dsc->id = CDSC_UNKNOWNDSC;
2517     }
2518     else if (IS_DSC(line, "%%DocumentCustomColors:")) {
2519 	dsc->id = CDSC_DOCUMENTCUSTOMCOLORS;
2520 	if (dsc_parse_custom_colours(dsc) != CDSC_OK)
2521 	    dsc->id = CDSC_UNKNOWNDSC;
2522     }
2523     else if (IS_DSC(line, "%%CMYKCustomColor:")) {
2524 	dsc->id = CDSC_CMYKCUSTOMCOLOR;
2525 	if (dsc_parse_cmyk_custom_colour(dsc) != CDSC_OK)
2526 	    dsc->id = CDSC_UNKNOWNDSC;
2527     }
2528     else if (IS_DSC(line, "%%RGBCustomColor:")) {
2529 	dsc->id = CDSC_RGBCUSTOMCOLOR;
2530 	if (dsc_parse_rgb_custom_colour(dsc) != CDSC_OK)
2531 	    dsc->id = CDSC_UNKNOWNDSC;
2532     }
2533     else if (dsc->line[0] == '%' && IS_WHITE_OR_EOL(dsc->line[1])) {
2534 	dsc->id = CDSC_OK;
2535 	/* ignore */
2536     }
2537     else {
2538 	dsc->id = CDSC_UNKNOWNDSC;
2539 	dsc_unknown(dsc);
2540     }
2541 
2542     dsc->endcomments = DSC_END(dsc);
2543     return CDSC_OK;
2544 }
2545 
2546 
2547 dsc_private int
dsc_scan_preview(CDSC * dsc)2548 dsc_scan_preview(CDSC *dsc)
2549 {
2550     /* Preview section ends at */
2551     /*  %%EndPreview */
2552     /*  another section */
2553     /* Preview section must start with %%BeginPreview */
2554     char *line = dsc->line;
2555     dsc->id = CDSC_OK;
2556 
2557     if (dsc->scan_section == scan_pre_preview) {
2558 	if (IS_BLANK(line))
2559 	    return CDSC_OK;	/* ignore blank lines before preview */
2560 	else if (IS_DSC(line, "%%BeginPreview")) {
2561 	    dsc->id = CDSC_BEGINPREVIEW;
2562 	    dsc->beginpreview = DSC_START(dsc);
2563 	    dsc->endpreview = DSC_END(dsc);
2564 	    dsc->scan_section = scan_preview;
2565 	    /* Don't mark the preview as EPSI if a DOS EPS header is present */
2566 	    if (dsc->preview == CDSC_NOPREVIEW)
2567 		dsc->preview = CDSC_EPSI;
2568 	    return CDSC_OK;
2569 	}
2570 	else {
2571 	    dsc->scan_section = scan_pre_defaults;
2572 	    return CDSC_PROPAGATE;
2573 	}
2574     }
2575 
2576     if (IS_DSC(line, "%%BeginPreview")) {
2577 	/* ignore because we are in this section */
2578     }
2579     else if (dsc_is_section(line)) {
2580 	dsc->endpreview = DSC_START(dsc);
2581 	dsc->scan_section = scan_pre_defaults;
2582 	return CDSC_PROPAGATE;
2583     }
2584     else if (IS_DSC(line, "%%EndPreview")) {
2585 	dsc->id = CDSC_ENDPREVIEW;
2586 	dsc->endpreview = DSC_END(dsc);
2587 	dsc->scan_section = scan_pre_defaults;
2588 	return CDSC_OK;
2589     }
2590     else if (line[0] == '%' && line[1] != '%') {
2591 	/* Ordinary comments are OK */
2592     }
2593     else {
2594 	dsc->id = CDSC_UNKNOWNDSC;
2595 	/* DSC comments should not occur in preview */
2596 	dsc_unknown(dsc);
2597     }
2598 
2599     dsc->endpreview = DSC_END(dsc);
2600     return CDSC_OK;
2601 }
2602 
2603 dsc_private int
dsc_scan_defaults(CDSC * dsc)2604 dsc_scan_defaults(CDSC *dsc)
2605 {
2606     /* Defaults section ends at */
2607     /*  %%EndDefaults */
2608     /*  another section */
2609     /* Defaults section must start with %%BeginDefaults */
2610     char *line = dsc->line;
2611     dsc->id = CDSC_OK;
2612 
2613     if (dsc->scan_section == scan_pre_defaults) {
2614 	if (IS_BLANK(line))
2615 	    return CDSC_OK;	/* ignore blank lines before defaults */
2616 	else if (IS_DSC(line, "%%BeginDefaults")) {
2617 	    dsc->id = CDSC_BEGINDEFAULTS;
2618 	    dsc->begindefaults = DSC_START(dsc);
2619 	    dsc->enddefaults = DSC_END(dsc);
2620 	    dsc->scan_section = scan_defaults;
2621 	    return CDSC_OK;
2622 	}
2623 	else {
2624 	    dsc->scan_section = scan_pre_prolog;
2625 	    return CDSC_PROPAGATE;
2626 	}
2627     }
2628 
2629     if (NOT_DSC_LINE(line)) {
2630 	/* ignore */
2631     }
2632     else if (IS_DSC(line, "%%BeginPreview")) {
2633 	/* ignore because we have already processed this section */
2634     }
2635     else if (IS_DSC(line, "%%BeginDefaults")) {
2636 	/* ignore because we are in this section */
2637     }
2638     else if (dsc_is_section(line)) {
2639 	dsc->enddefaults = DSC_START(dsc);
2640 	dsc->scan_section = scan_pre_prolog;
2641 	return CDSC_PROPAGATE;
2642     }
2643     else if (IS_DSC(line, "%%EndDefaults")) {
2644 	dsc->id = CDSC_ENDDEFAULTS;
2645 	dsc->enddefaults = DSC_END(dsc);
2646 	dsc->scan_section = scan_pre_prolog;
2647 	return CDSC_OK;
2648     }
2649     else if (IS_DSC(line, "%%PageMedia:")) {
2650 	dsc->id = CDSC_PAGEMEDIA;
2651 	dsc_parse_media(dsc, &dsc->page_media);
2652     }
2653     else if (IS_DSC(line, "%%PageOrientation:")) {
2654 	dsc->id = CDSC_PAGEORIENTATION;
2655 	/* This can override %%Orientation:  */
2656 	if (dsc_parse_orientation(dsc, &(dsc->page_orientation), 18))
2657 	    return CDSC_ERROR;
2658     }
2659     else if (IS_DSC(line, "%%PageBoundingBox:")) {
2660 	dsc->id = CDSC_PAGEBOUNDINGBOX;
2661 	if (dsc_parse_bounding_box(dsc, &(dsc->page_bbox), 18))
2662 	    return CDSC_ERROR;
2663     }
2664     else if (IS_DSC(line, "%%ViewingOrientation:")) {
2665 	dsc->id = CDSC_VIEWINGORIENTATION;
2666 	if (dsc_parse_viewing_orientation(dsc, &dsc->viewing_orientation))
2667 	    return CDSC_ERROR;
2668     }
2669     else if (IS_DSC(line, "%%PageCropBox:")) {
2670 	dsc->id = CDSC_PAGECROPBOX;
2671 	if (dsc_parse_float_bounding_box(dsc, &dsc->crop_box, 14))
2672 	    return CDSC_ERROR;
2673     }
2674     else {
2675 	dsc->id = CDSC_UNKNOWNDSC;
2676 	/* All other DSC comments are unknown, but not an error */
2677 	dsc_unknown(dsc);
2678     }
2679     dsc->enddefaults = DSC_END(dsc);
2680     return CDSC_OK;
2681 }
2682 
2683 /* CDSC_RESPONSE_OK and CDSC_RESPONSE_CANCEL mean ignore the
2684  * mismatch (default) */
2685 dsc_private int
dsc_check_match_prompt(CDSC * dsc,const char * str,int count)2686 dsc_check_match_prompt(CDSC *dsc, const char *str, int count)
2687 {
2688     if (count != 0) {
2689 	char buf[MAXSTR+MAXSTR];
2690 	if (dsc->line_length < (unsigned int)(sizeof(buf)/2-1))  {
2691 	    strncpy(buf, dsc->line, dsc->line_length);
2692 	    buf[dsc->line_length] = '\0';
2693 	}
2694 	sprintf(buf+strlen(buf), "\n%%%%Begin%.40s: / %%%%End%.40s\n", str, str);
2695 	return dsc_error(dsc, CDSC_MESSAGE_BEGIN_END, buf, (int)strlen(buf));
2696     }
2697     return CDSC_RESPONSE_CANCEL;
2698 }
2699 
2700 dsc_private int
dsc_check_match_type(CDSC * dsc,const char * str,int count)2701 dsc_check_match_type(CDSC *dsc, const char *str, int count)
2702 {
2703     if (dsc_check_match_prompt(dsc, str, count) == CDSC_RESPONSE_IGNORE_ALL)
2704 	return CDSC_NOTDSC;
2705     return CDSC_OK;
2706 }
2707 
2708 /* complain if Begin/End blocks didn't match */
2709 /* return non-zero if we should ignore all DSC */
2710 dsc_private int
dsc_check_match(CDSC * dsc)2711 dsc_check_match(CDSC *dsc)
2712 {
2713     int rc = 0;
2714     const char *font = "Font";
2715     const char *feature = "Feature";
2716     const char *resource = "Resource";
2717     const char *procset = "ProcSet";
2718 
2719     if (!rc)
2720 	rc = dsc_check_match_type(dsc, font, dsc->begin_font_count);
2721     if (!rc)
2722 	rc = dsc_check_match_type(dsc, feature, dsc->begin_feature_count);
2723     if (!rc)
2724 	rc = dsc_check_match_type(dsc, resource, dsc->begin_resource_count);
2725     if (!rc)
2726 	rc = dsc_check_match_type(dsc, procset, dsc->begin_procset_count);
2727 
2728     dsc->begin_font_count = 0;
2729     dsc->begin_feature_count = 0;
2730     dsc->begin_resource_count = 0;
2731     dsc->begin_procset_count = 0;
2732     return rc;
2733 }
2734 
2735 
2736 dsc_private int
dsc_scan_prolog(CDSC * dsc)2737 dsc_scan_prolog(CDSC *dsc)
2738 {
2739     /* Prolog section ends at */
2740     /*  %%EndProlog */
2741     /*  another section */
2742     /* Prolog section may start with %%BeginProlog or non-dsc line */
2743     char *line = dsc->line;
2744     dsc->id = CDSC_OK;
2745 
2746     if (dsc->scan_section == scan_pre_prolog) {
2747         if (dsc_is_section(line) && (!IS_DSC(line, "%%BeginProlog"))) {
2748 	    dsc->scan_section = scan_pre_setup;
2749 	    return CDSC_PROPAGATE;
2750 	}
2751 	dsc->id = CDSC_BEGINPROLOG;
2752 	dsc->beginprolog = DSC_START(dsc);
2753 	dsc->endprolog = DSC_END(dsc);
2754 	dsc->scan_section = scan_prolog;
2755 	if (IS_DSC(line, "%%BeginProlog"))
2756 	    return CDSC_OK;
2757     }
2758 
2759     if (NOT_DSC_LINE(line)) {
2760 	/* ignore */
2761     }
2762     else if (IS_DSC(line, "%%BeginPreview")) {
2763 	/* ignore because we have already processed this section */
2764     }
2765     else if (IS_DSC(line, "%%BeginDefaults")) {
2766 	/* ignore because we have already processed this section */
2767     }
2768     else if (IS_DSC(line, "%%BeginProlog")) {
2769 	/* ignore because we are in this section */
2770     }
2771     else if (dsc_is_section(line)) {
2772 	dsc->endprolog = DSC_START(dsc);
2773 	dsc->scan_section = scan_pre_setup;
2774 	if (dsc_check_match(dsc))
2775 	    return CDSC_NOTDSC;
2776 	return CDSC_PROPAGATE;
2777     }
2778     else if (IS_DSC(line, "%%EndProlog")) {
2779 	dsc->id = CDSC_ENDPROLOG;
2780 	dsc->endprolog = DSC_END(dsc);
2781 	dsc->scan_section = scan_pre_setup;
2782 	if (dsc_check_match(dsc))
2783 	    return CDSC_NOTDSC;
2784 	return CDSC_OK;
2785     }
2786     else if (IS_DSC(line, "%%BeginFont:")) {
2787 	dsc->id = CDSC_BEGINFONT;
2788 	/* ignore Begin/EndFont, apart form making sure */
2789 	/* that they are matched. */
2790 	dsc->begin_font_count++;
2791     }
2792     else if (IS_DSC(line, "%%EndFont")) {
2793 	dsc->id = CDSC_ENDFONT;
2794 	dsc->begin_font_count--;
2795     }
2796     else if (IS_DSC(line, "%%BeginFeature:")) {
2797 	dsc->id = CDSC_BEGINFEATURE;
2798 	/* ignore Begin/EndFeature, apart form making sure */
2799 	/* that they are matched. */
2800 	dsc->begin_feature_count++;
2801     }
2802     else if (IS_DSC(line, "%%EndFeature")) {
2803 	dsc->id = CDSC_ENDFEATURE;
2804 	dsc->begin_feature_count--;
2805     }
2806     else if (IS_DSC(line, "%%BeginResource:")) {
2807 	dsc->id = CDSC_BEGINRESOURCE;
2808 	/* ignore Begin/EndResource, apart form making sure */
2809 	/* that they are matched. */
2810 	dsc->begin_resource_count++;
2811     }
2812     else if (IS_DSC(line, "%%EndResource")) {
2813 	dsc->id = CDSC_ENDRESOURCE;
2814 	dsc->begin_resource_count--;
2815     }
2816     else if (IS_DSC(line, "%%BeginProcSet:")) {
2817 	dsc->id = CDSC_BEGINPROCSET;
2818 	/* ignore Begin/EndProcSet, apart form making sure */
2819 	/* that they are matched. */
2820 	dsc->begin_procset_count++;
2821     }
2822     else if (IS_DSC(line, "%%EndProcSet")) {
2823 	dsc->id = CDSC_ENDPROCSET;
2824 	dsc->begin_procset_count--;
2825     }
2826     else {
2827 	/* All other DSC comments are unknown, but not an error */
2828 	dsc->id = CDSC_UNKNOWNDSC;
2829 	dsc_unknown(dsc);
2830     }
2831 
2832     dsc->endprolog = DSC_END(dsc);
2833     return CDSC_OK;
2834 }
2835 
2836 dsc_private int
dsc_scan_setup(CDSC * dsc)2837 dsc_scan_setup(CDSC *dsc)
2838 {
2839     /* Setup section ends at */
2840     /*  %%EndSetup */
2841     /*  another section */
2842     /* Setup section must start with %%BeginSetup */
2843 
2844     char *line = dsc->line;
2845     dsc->id = CDSC_OK;
2846 
2847     if (dsc->scan_section == scan_pre_setup) {
2848 	if (IS_BLANK(line))
2849 	    return CDSC_OK;	/* ignore blank lines before setup */
2850 	else if (IS_DSC(line, "%%BeginSetup")) {
2851 	    dsc->id = CDSC_BEGINSETUP;
2852 	    dsc->beginsetup = DSC_START(dsc);
2853 	    dsc->endsetup = DSC_END(dsc);
2854 	    dsc->scan_section = scan_setup;
2855 	    return CDSC_OK;
2856 	}
2857 	else {
2858 	    dsc->scan_section = scan_pre_pages;
2859 	    return CDSC_PROPAGATE;
2860 	}
2861     }
2862 
2863     if (NOT_DSC_LINE(line)) {
2864 	/* ignore */
2865     }
2866     else if (IS_DSC(line, "%%BeginPreview")) {
2867 	/* ignore because we have already processed this section */
2868     }
2869     else if (IS_DSC(line, "%%BeginDefaults")) {
2870 	/* ignore because we have already processed this section */
2871     }
2872     else if (IS_DSC(line, "%%BeginProlog")) {
2873 	/* ignore because we have already processed this section */
2874     }
2875     else if (IS_DSC(line, "%%BeginSetup")) {
2876 	/* ignore because we are in this section */
2877     }
2878     else if (dsc_is_section(line)) {
2879 	dsc->endsetup = DSC_START(dsc);
2880 	dsc->scan_section = scan_pre_pages;
2881 	if (dsc_check_match(dsc))
2882 	    return CDSC_NOTDSC;
2883 	return CDSC_PROPAGATE;
2884     }
2885     else if (IS_DSC(line, "%%EndSetup")) {
2886 	dsc->id = CDSC_ENDSETUP;
2887 	dsc->endsetup = DSC_END(dsc);
2888 	dsc->scan_section = scan_pre_pages;
2889 	if (dsc_check_match(dsc))
2890 	    return CDSC_NOTDSC;
2891 	return CDSC_OK;
2892     }
2893     else if (IS_DSC(line, "%%BeginFeature:")) {
2894 	dsc->id = CDSC_BEGINFEATURE;
2895 	/* ignore Begin/EndFeature, apart form making sure */
2896 	/* that they are matched. */
2897 	dsc->begin_feature_count++;
2898     }
2899     else if (IS_DSC(line, "%%EndFeature")) {
2900 	dsc->id = CDSC_ENDFEATURE;
2901 	dsc->begin_feature_count--;
2902     }
2903     else if (IS_DSC(line, "%%Feature:")) {
2904 	dsc->id = CDSC_FEATURE;
2905 	/* ignore */
2906     }
2907     else if (IS_DSC(line, "%%BeginResource:")) {
2908 	dsc->id = CDSC_BEGINRESOURCE;
2909 	/* ignore Begin/EndResource, apart form making sure */
2910 	/* that they are matched. */
2911 	dsc->begin_resource_count++;
2912     }
2913     else if (IS_DSC(line, "%%EndResource")) {
2914 	dsc->id = CDSC_ENDRESOURCE;
2915 	dsc->begin_resource_count--;
2916     }
2917     else if (IS_DSC(line, "%%PaperColor:")) {
2918 	dsc->id = CDSC_PAPERCOLOR;
2919 	/* ignore */
2920     }
2921     else if (IS_DSC(line, "%%PaperForm:")) {
2922 	dsc->id = CDSC_PAPERFORM;
2923 	/* ignore */
2924     }
2925     else if (IS_DSC(line, "%%PaperWeight:")) {
2926 	dsc->id = CDSC_PAPERWEIGHT;
2927 	/* ignore */
2928     }
2929     else if (IS_DSC(line, "%%PaperSize:")) {
2930 	/* DSC 2.1 */
2931         GSBOOL found_media = FALSE;
2932 	int i;
2933 	int n = 12;
2934 	char buf[MAXSTR];
2935 	buf[0] = '\0';
2936 	dsc->id = CDSC_PAPERSIZE;
2937 	dsc_copy_string(buf, sizeof(buf)-1, dsc->line+n, dsc->line_length-n,
2938 		NULL);
2939  	for (i=0; i<(int)dsc->media_count; i++) {
2940 	    if (dsc->media[i] && dsc->media[i]->name &&
2941 		(dsc_stricmp(buf, dsc->media[i]->name)==0)) {
2942 		dsc->page_media = dsc->media[i];
2943 		found_media = TRUE;
2944 		break;
2945 	    }
2946 	}
2947 	if (!found_media) {
2948 	    /* It didn't match %%DocumentPaperSizes: */
2949 	    /* Try our known media */
2950 	    const CDSCMEDIA *m = dsc_known_media;
2951 	    while (m->name) {
2952 		if (dsc_stricmp(buf, m->name)==0) {
2953 		    dsc->page_media = m;
2954 		    break;
2955 		}
2956 		m++;
2957 	    }
2958 	    if (m->name == NULL)
2959 		dsc_unknown(dsc);
2960 	}
2961     }
2962     else {
2963 	/* All other DSC comments are unknown, but not an error */
2964 	dsc->id = CDSC_UNKNOWNDSC;
2965 	dsc_unknown(dsc);
2966     }
2967 
2968     dsc->endsetup = DSC_END(dsc);
2969     return CDSC_OK;
2970 }
2971 
2972 dsc_private int
dsc_scan_page(CDSC * dsc)2973 dsc_scan_page(CDSC *dsc)
2974 {
2975     /* Page section ends at */
2976     /*  %%Page */
2977     /*  %%Trailer */
2978     /*  %%EOF */
2979     char *line = dsc->line;
2980     dsc->id = CDSC_OK;
2981 
2982     if (dsc->scan_section == scan_pre_pages) {
2983 	if (IS_DSC(line, "%%Page:")) {
2984 	    dsc->scan_section = scan_pages;
2985 	    /* fall through */
2986 	}
2987 	else  {
2988 	    /* %%Page: didn't follow %%EndSetup
2989 	     * Keep reading until reach %%Page or %%Trailer
2990 	     * and add it to previous section.
2991 	     */
2992 	    DSC_OFFSET *last;
2993 	    if (dsc->endsetup != 0)
2994 		last = &dsc->endsetup;
2995 	    else if (dsc->endprolog != 0)
2996 		last = &dsc->endprolog;
2997 	    else if (dsc->enddefaults != 0)
2998 		last = &dsc->enddefaults;
2999 	    else if (dsc->endpreview != 0)
3000 		last = &dsc->endpreview;
3001 	    else if (dsc->endcomments != 0)
3002 		last = &dsc->endcomments;
3003 	    else
3004 		last = &dsc->begincomments;
3005 	    *last = DSC_START(dsc);
3006 	    if (IS_DSC(line, "%%Trailer") || IS_DSC(line, "%%EOF")) {
3007 		dsc->scan_section = scan_pre_trailer;
3008 		return CDSC_PROPAGATE;
3009 	    }
3010 	    *last = DSC_END(dsc);
3011 	    return CDSC_OK;
3012 	}
3013     }
3014 
3015     if (NOT_DSC_LINE(line)) {
3016 	/* ignore */
3017     }
3018     else if (IS_DSC(line, "%%Page:")) {
3019 	int code;
3020 	dsc->id = CDSC_PAGE;
3021 	if (dsc->page_count) {
3022 	    dsc->page[dsc->page_count-1].end = DSC_START(dsc);
3023 	    if (dsc_check_match(dsc))
3024 		return CDSC_NOTDSC;
3025 	}
3026 
3027 	if ( (code = dsc_parse_page(dsc)) != CDSC_OK)
3028 	    return code;
3029         if (dsc->page_count == 0)
3030 	    dsc->scan_section = scan_pre_pages;
3031     }
3032     else if (IS_DSC(line, "%%BeginPreview")) {
3033 	/* ignore because we have already processed this section */
3034     }
3035     else if (IS_DSC(line, "%%BeginDefaults")) {
3036 	/* ignore because we have already processed this section */
3037     }
3038     else if (IS_DSC(line, "%%BeginProlog")) {
3039 	/* ignore because we have already processed this section */
3040     }
3041     else if (IS_DSC(line, "%%BeginSetup")) {
3042 	/* ignore because we have already processed this section */
3043     }
3044     else if (dsc_is_section(line)) {
3045 	if (IS_DSC(line, "%%Trailer")) {
3046 	    if (dsc->page_count)
3047 		dsc->page[dsc->page_count-1].end = DSC_START(dsc);
3048 	    if (dsc->file_length) {
3049 		if ((!dsc->doseps_end &&
3050 			((DSC_END(dsc) + 32768) < dsc->file_length)) ||
3051 		     ((dsc->doseps_end) &&
3052 			((DSC_END(dsc) + 32768) < dsc->doseps_end))) {
3053 		    int rc = dsc_error(dsc, CDSC_MESSAGE_EARLY_TRAILER,
3054 			dsc->line, dsc->line_length);
3055 		    switch (rc) {
3056 			case CDSC_RESPONSE_OK:
3057 			    /* ignore early trailer */
3058 			    break;
3059 			case CDSC_RESPONSE_CANCEL:
3060 			    /* this is the trailer */
3061 			    dsc->scan_section = scan_pre_trailer;
3062 			    if (dsc_check_match(dsc))
3063 				return CDSC_NOTDSC;
3064 			    return CDSC_PROPAGATE;
3065 			case CDSC_RESPONSE_IGNORE_ALL:
3066 			    return CDSC_NOTDSC;
3067 		    }
3068 		}
3069 		else {
3070 		    dsc->scan_section = scan_pre_trailer;
3071 		    if (dsc_check_match(dsc))
3072 			return CDSC_NOTDSC;
3073 		    return CDSC_PROPAGATE;
3074 		}
3075 	    }
3076 	    else {
3077 		dsc->scan_section = scan_pre_trailer;
3078 		if (dsc_check_match(dsc))
3079 		    return CDSC_NOTDSC;
3080 		return CDSC_PROPAGATE;
3081 	    }
3082 	}
3083 	else if (IS_DSC(line, "%%EOF")) {
3084 	    if (dsc->page_count)
3085 		dsc->page[dsc->page_count-1].end = DSC_START(dsc);
3086 	    if (dsc->file_length) {
3087 		if ((!dsc->doseps_end &&
3088 			((DSC_END(dsc) + 100) < dsc->file_length)) ||
3089 		     ((dsc->doseps_end) &&
3090 			((DSC_END(dsc) + 100) < dsc->doseps_end))) {
3091 		    int rc = dsc_error(dsc, CDSC_MESSAGE_EARLY_EOF,
3092 			dsc->line, dsc->line_length);
3093 		    switch (rc) {
3094 			case CDSC_RESPONSE_OK:
3095 			    /* %%EOF is wrong, ignore it */
3096 			    break;
3097 			case CDSC_RESPONSE_CANCEL:
3098 			    /* %%EOF is correct */
3099 			    dsc->scan_section = scan_eof;
3100 			    dsc->eof = TRUE;
3101 			    if (dsc_check_match(dsc))
3102 				return CDSC_NOTDSC;
3103 			    return CDSC_PROPAGATE;
3104 			case CDSC_RESPONSE_IGNORE_ALL:
3105 			    return CDSC_NOTDSC;
3106 		    }
3107 		}
3108 	    }
3109 	    else {
3110 		/* ignore it */
3111 		if (dsc_check_match(dsc))
3112 		    return CDSC_NOTDSC;
3113 		return CDSC_OK;
3114 	    }
3115 	}
3116 	else {
3117 	    /* Section comment, probably from a badly */
3118 	    /* encapsulated EPS file. */
3119 	    int rc = dsc_error(dsc, CDSC_MESSAGE_BAD_SECTION,
3120 		    dsc->line, dsc->line_length);
3121 	    if (rc == CDSC_RESPONSE_IGNORE_ALL)
3122 		return CDSC_NOTDSC;
3123 	}
3124     }
3125     else if (IS_DSC(line, "%%PageTrailer")) {
3126 	dsc->id = CDSC_PAGETRAILER;
3127 	/* ignore */
3128     }
3129     else if (IS_DSC(line, "%%BeginPageSetup")) {
3130 	dsc->id = CDSC_BEGINPAGESETUP;
3131 	/* ignore */
3132     }
3133     else if (IS_DSC(line, "%%EndPageSetup")) {
3134 	dsc->id = CDSC_ENDPAGESETUP;
3135 	/* ignore */
3136     }
3137     else if (IS_DSC(line, "%%PageMedia:")) {
3138 	dsc->id = CDSC_PAGEMEDIA;
3139 	if (dsc->page_count)
3140 	    dsc_parse_media(dsc, &(dsc->page[dsc->page_count-1].media));
3141     }
3142     else if (IS_DSC(line, "%%PaperColor:")) {
3143 	dsc->id = CDSC_PAPERCOLOR;
3144 	/* ignore */
3145     }
3146     else if (IS_DSC(line, "%%PaperForm:")) {
3147 	dsc->id = CDSC_PAPERFORM;
3148 	/* ignore */
3149     }
3150     else if (IS_DSC(line, "%%PaperWeight:")) {
3151 	dsc->id = CDSC_PAPERWEIGHT;
3152 	/* ignore */
3153     }
3154     else if (IS_DSC(line, "%%PaperSize:")) {
3155 	/* DSC 2.1 */
3156         GSBOOL found_media = FALSE;
3157 	int i;
3158 	int n = 12;
3159 	char buf[MAXSTR];
3160 	buf[0] = '\0';
3161 	dsc_copy_string(buf, sizeof(buf)-1, dsc->line+n,
3162 	    dsc->line_length-n, NULL);
3163  	for (i=0; i<(int)dsc->media_count; i++) {
3164 	    if (dsc->media[i] && dsc->media[i]->name &&
3165 		(dsc_stricmp(buf, dsc->media[i]->name)==0)) {
3166 		if (dsc->page_count)
3167 		    dsc->page[dsc->page_count-1].media = dsc->media[i];
3168 		found_media = TRUE;
3169 		break;
3170 	    }
3171 	}
3172 	if (!found_media) {
3173 	    /* It didn't match %%DocumentPaperSizes: */
3174 	    /* Try our known media */
3175 	    const CDSCMEDIA *m = dsc_known_media;
3176 	    while (m->name) {
3177 		if (dsc_stricmp(buf, m->name)==0) {
3178 		    if (dsc->page_count)
3179 			dsc->page[dsc->page_count-1].media = m;
3180 		    break;
3181 		}
3182 		m++;
3183 	    }
3184 	    if (m->name == NULL)
3185 		dsc_unknown(dsc);
3186 	}
3187     }
3188     else if (IS_DSC(line, "%%PageOrientation:")) {
3189 	if (dsc->page_count) {
3190 	    dsc->id = CDSC_PAGEORIENTATION;
3191 	    if (dsc_parse_orientation(dsc,
3192 		&(dsc->page[dsc->page_count-1].orientation) ,18))
3193 		return CDSC_NOTDSC;
3194 	}
3195     }
3196     else if (IS_DSC(line, "%%PageBoundingBox:")) {
3197 	if (dsc->page_count) {
3198 	    dsc->id = CDSC_PAGEBOUNDINGBOX;
3199 	    if (dsc_parse_bounding_box(dsc,
3200 		&dsc->page[dsc->page_count-1].bbox, 18))
3201 		return CDSC_NOTDSC;
3202 	}
3203     }
3204     else if (IS_DSC(line, "%%ViewingOrientation:")) {
3205 	if (dsc->page_count) {
3206 	    dsc->id = CDSC_VIEWINGORIENTATION;
3207 	    if (dsc_parse_viewing_orientation(dsc,
3208 		&dsc->page[dsc->page_count-1].viewing_orientation))
3209 		return CDSC_ERROR;
3210 	}
3211     }
3212     else if (IS_DSC(line, "%%PageCropBox:")) {
3213 	if (dsc->page_count) {
3214 	    dsc->id = CDSC_PAGECROPBOX;
3215 	    if (dsc_parse_float_bounding_box(dsc,
3216 		&(dsc->page[dsc->page_count-1].crop_box), 14))
3217 		return CDSC_ERROR;
3218 	}
3219     }
3220     else if (IS_DSC(line, "%%BeginFont:")) {
3221 	dsc->id = CDSC_BEGINFONT;
3222 	/* ignore Begin/EndFont, apart form making sure */
3223 	/* that they are matched. */
3224 	dsc->begin_font_count++;
3225     }
3226     else if (IS_DSC(line, "%%EndFont")) {
3227 	dsc->id = CDSC_BEGINFONT;
3228 	dsc->begin_font_count--;
3229     }
3230     else if (IS_DSC(line, "%%BeginFeature:")) {
3231 	dsc->id = CDSC_BEGINFEATURE;
3232 	/* ignore Begin/EndFeature, apart form making sure */
3233 	/* that they are matched. */
3234 	dsc->begin_feature_count++;
3235     }
3236     else if (IS_DSC(line, "%%EndFeature")) {
3237 	dsc->id = CDSC_ENDFEATURE;
3238 	dsc->begin_feature_count--;
3239     }
3240     else if (IS_DSC(line, "%%BeginResource:")) {
3241 	dsc->id = CDSC_BEGINRESOURCE;
3242 	/* ignore Begin/EndResource, apart form making sure */
3243 	/* that they are matched. */
3244 	dsc->begin_resource_count++;
3245     }
3246     else if (IS_DSC(line, "%%EndResource")) {
3247 	dsc->id = CDSC_ENDRESOURCE;
3248 	dsc->begin_resource_count--;
3249     }
3250     else if (IS_DSC(line, "%%BeginProcSet:")) {
3251 	dsc->id = CDSC_BEGINPROCSET;
3252 	/* ignore Begin/EndProcSet, apart form making sure */
3253 	/* that they are matched. */
3254 	dsc->begin_procset_count++;
3255     }
3256     else if (IS_DSC(line, "%%EndProcSet")) {
3257 	dsc->id = CDSC_ENDPROCSET;
3258 	dsc->begin_procset_count--;
3259     }
3260     else if (IS_DSC(line, "%%IncludeFont:")) {
3261 	dsc->id = CDSC_INCLUDEFONT;
3262 	/* ignore */
3263     }
3264     else {
3265 	/* All other DSC comments are unknown, but not an error */
3266 	dsc->id = CDSC_UNKNOWNDSC;
3267 	dsc_unknown(dsc);
3268     }
3269 
3270     if (dsc->page_count)
3271 	dsc->page[dsc->page_count-1].end = DSC_END(dsc);
3272     return CDSC_OK;
3273 }
3274 
3275 /* Valid Trailer comments are
3276  * %%Trailer
3277  * %%EOF
3278  * or the following deferred with (atend)
3279  * %%BoundingBox:
3280  * %%DocumentCustomColors:
3281  * %%DocumentFiles:
3282  * %%DocumentFonts:
3283  * %%DocumentNeededFiles:
3284  * %%DocumentNeededFonts:
3285  * %%DocumentNeededProcSets:
3286  * %%DocumentNeededResources:
3287  * %%DocumentProcSets:
3288  * %%DocumentProcessColors:
3289  * %%DocumentSuppliedFiles:
3290  * %%DocumentSuppliedFonts:
3291  * %%DocumentSuppliedProcSets:
3292  * %%DocumentSuppliedResources:
3293  * %%Orientation:
3294  * %%Pages:
3295  * %%PageOrder:
3296  *
3297  * Our supported subset is
3298  * %%Trailer
3299  * %%EOF
3300  * %%BoundingBox:
3301  * %%CropBox:
3302  * %%HiResBoundingBox:
3303  * %%DocumentCustomColors:
3304  * %%DocumentProcessColors:
3305  * %%Orientation:
3306  * %%Pages:
3307  * %%PageOrder:
3308  * In addition to these, we support
3309  * %%DocumentMedia:
3310  *
3311  * A %%PageTrailer can have the following:
3312  * %%PageBoundingBox:
3313  * %%PageCustomColors:
3314  * %%PageFiles:
3315  * %%PageFonts:
3316  * %%PageOrientation:
3317  * %%PageProcessColors:
3318  * %%PageResources:
3319  */
3320 
3321 dsc_private int
dsc_scan_trailer(CDSC * dsc)3322 dsc_scan_trailer(CDSC *dsc)
3323 {
3324     /* Trailer section start at */
3325     /*  %%Trailer */
3326     /* and ends at */
3327     /*  %%EOF */
3328     char *line = dsc->line;
3329     GSBOOL continued = FALSE;
3330     dsc->id = CDSC_OK;
3331 
3332     if (dsc->scan_section == scan_pre_trailer) {
3333 	if (IS_DSC(line, "%%Trailer")) {
3334 	    dsc->id = CDSC_TRAILER;
3335 	    dsc->begintrailer = DSC_START(dsc);
3336 	    dsc->endtrailer = DSC_END(dsc);
3337 	    dsc->scan_section = scan_trailer;
3338 	    return CDSC_OK;
3339 	}
3340 	else if (IS_DSC(line, "%%EOF")) {
3341 	    dsc->id = CDSC_EOF;
3342 	    dsc->begintrailer = DSC_START(dsc);
3343 	    dsc->endtrailer = DSC_END(dsc);
3344 	    dsc->scan_section = scan_trailer;
3345 	    /* Continue, in case we found %%EOF in an embedded document */
3346 	    return CDSC_OK;
3347 	}
3348 	else {
3349 	    /* %%Page: didn't follow %%EndSetup
3350 	     * Keep reading until reach %%Page or %%Trailer
3351 	     * and add it to setup section
3352 	     */
3353 	    /* append to previous section */
3354 	    if (dsc->beginsetup)
3355 		dsc->endsetup = DSC_END(dsc);
3356 	    else if (dsc->beginprolog)
3357 		dsc->endprolog = DSC_END(dsc);
3358 	    else {
3359 		/* horribly confused */
3360 	    }
3361 	    return CDSC_OK;
3362 	}
3363     }
3364 
3365     /* Handle continuation lines.
3366      * See comment above about our restrictive processing of
3367      * continuation lines
3368      */
3369     if (IS_DSC(line, "%%+")) {
3370 	line = dsc->last_line;
3371 	continued = TRUE;
3372     }
3373     else
3374 	dsc_save_line(dsc);
3375 
3376     if (NOT_DSC_LINE(line)) {
3377 	/* ignore */
3378     }
3379     else if (IS_DSC(dsc->line, "%%EOF")) {
3380 	/* Keep scanning, in case we have a false trailer */
3381 	dsc->id = CDSC_EOF;
3382     }
3383     else if (IS_DSC(dsc->line, "%%Trailer")) {
3384 	/* Cope with no pages with code after setup and before trailer. */
3385 	/* Last trailer is the correct one. */
3386 	dsc->id = CDSC_TRAILER;
3387 	dsc->begintrailer = DSC_START(dsc);
3388     }
3389     else if (IS_DSC(line, "%%Pages:")) {
3390 	dsc->id = CDSC_PAGES;
3391 	if (dsc_parse_pages(dsc) != 0)
3392 	       return CDSC_ERROR;
3393     }
3394     else if (IS_DSC(line, "%%BoundingBox:")) {
3395 	dsc->id = CDSC_BOUNDINGBOX;
3396 	if (dsc_parse_bounding_box(dsc, &(dsc->bbox), continued ? 3 : 14))
3397 	    return CDSC_ERROR;
3398     }
3399     else if (IS_DSC(line, "%%HiResBoundingBox:")) {
3400 	dsc->id = CDSC_HIRESBOUNDINGBOX;
3401 	if (dsc_parse_float_bounding_box(dsc, &(dsc->hires_bbox),
3402 	    continued ? 3 : 19))
3403 	    return CDSC_ERROR;
3404     }
3405     else if (IS_DSC(line, "%%CropBox:")) {
3406 	dsc->id = CDSC_CROPBOX;
3407 	if (dsc_parse_float_bounding_box(dsc, &(dsc->crop_box),
3408 	    continued ? 3 : 10))
3409 	    return CDSC_ERROR;
3410     }
3411     else if (IS_DSC(line, "%%Orientation:")) {
3412 	dsc->id = CDSC_ORIENTATION;
3413 	if (dsc_parse_orientation(dsc, &(dsc->page_orientation), continued ? 3 : 14))
3414 	    return CDSC_ERROR;
3415     }
3416     else if (IS_DSC(line, "%%PageOrder:")) {
3417 	dsc->id = CDSC_PAGEORDER;
3418 	if (dsc_parse_order(dsc))
3419 	    return CDSC_ERROR;
3420     }
3421     else if (IS_DSC(line, "%%DocumentMedia:")) {
3422 	dsc->id = CDSC_DOCUMENTMEDIA;
3423 	if (dsc_parse_document_media(dsc))
3424 	    return CDSC_ERROR;
3425     }
3426     else if (IS_DSC(dsc->line, "%%Page:")) {
3427 	/* This should not occur in the trailer, but we might see
3428 	 * this if a document has been incorrectly embedded.
3429 	 */
3430 	int rc = dsc_error(dsc, CDSC_MESSAGE_PAGE_IN_TRAILER,
3431 		dsc->line, dsc->line_length);
3432 	switch (rc) {
3433 	    case CDSC_RESPONSE_OK:
3434 		/* Assume that we are really in the previous */
3435 		/* page, not the trailer */
3436 		dsc->scan_section = scan_pre_pages;
3437 		if (dsc->page_count)
3438 		    dsc->page[dsc->page_count-1].end = DSC_START(dsc);
3439 		return CDSC_PROPAGATE;	/* try again */
3440 	    case CDSC_RESPONSE_CANCEL:
3441 		/* ignore pages in trailer */
3442 		break;
3443 	    case CDSC_RESPONSE_IGNORE_ALL:
3444 		return CDSC_NOTDSC;
3445 	}
3446     }
3447     else if (IS_DSC(line, "%%DocumentNeededFonts:")) {
3448 	dsc->id = CDSC_DOCUMENTNEEDEDFONTS;
3449 	/* ignore */
3450     }
3451     else if (IS_DSC(line, "%%DocumentSuppliedFonts:")) {
3452 	dsc->id = CDSC_DOCUMENTSUPPLIEDFONTS;
3453 	/* ignore */
3454     }
3455     else if (IS_DSC(line, "%%DocumentProcessColors:")) {
3456 	dsc->id = CDSC_DOCUMENTPROCESSCOLORS;
3457 	if (dsc_parse_process_colours(dsc) != CDSC_OK)
3458 	    dsc->id = CDSC_UNKNOWNDSC;
3459     }
3460     else if (IS_DSC(line, "%%DocumentCustomColors:")) {
3461 	dsc->id = CDSC_DOCUMENTCUSTOMCOLORS;
3462 	if (dsc_parse_custom_colours(dsc) != CDSC_OK)
3463 	    dsc->id = CDSC_UNKNOWNDSC;
3464     }
3465     else {
3466 	/* All other DSC comments are unknown, but not an error */
3467 	dsc->id = CDSC_UNKNOWNDSC;
3468 	dsc_unknown(dsc);
3469     }
3470 
3471     dsc->endtrailer = DSC_END(dsc);
3472     return CDSC_OK;
3473 }
3474 
3475 
3476 dsc_private char *
dsc_alloc_string(CDSC * dsc,const char * str,int len)3477 dsc_alloc_string(CDSC *dsc, const char *str, int len)
3478 {
3479     char *p;
3480     if (dsc->string_head == NULL) {
3481 	dsc->string_head = (CDSCSTRING *)dsc_memalloc(dsc, sizeof(CDSCSTRING));
3482 	if (dsc->string_head == NULL)
3483 	    return NULL;	/* no memory */
3484 	dsc->string = dsc->string_head;
3485 	dsc->string->next = NULL;
3486 	dsc->string->data = (char *)dsc_memalloc(dsc, CDSC_STRING_CHUNK);
3487 	if (dsc->string->data == NULL) {
3488 	    dsc_reset(dsc);
3489 	    return NULL;	/* no memory */
3490 	}
3491 	dsc->string->index = 0;
3492 	dsc->string->length = CDSC_STRING_CHUNK;
3493     }
3494     if ( dsc->string->index + len + 1 > dsc->string->length) {
3495 	/* allocate another string block */
3496 	CDSCSTRING *newstring = (CDSCSTRING *)dsc_memalloc(dsc, sizeof(CDSCSTRING));
3497 	if (newstring == NULL) {
3498 	    dsc_debug_print(dsc, "Out of memory\n");
3499 	    return NULL;
3500 	}
3501         newstring->next = NULL;
3502 	newstring->length = 0;
3503 	newstring->index = 0;
3504 	newstring->data = (char *)dsc_memalloc(dsc, CDSC_STRING_CHUNK);
3505 	if (newstring->data == NULL) {
3506 	    dsc_memfree(dsc, newstring);
3507 	    dsc_debug_print(dsc, "Out of memory\n");
3508 	    return NULL;	/* no memory */
3509 	}
3510 	newstring->length = CDSC_STRING_CHUNK;
3511 	dsc->string->next = newstring;
3512 	dsc->string = newstring;
3513     }
3514     if ( dsc->string->index + len + 1 > dsc->string->length)
3515 	return NULL;	/* failed */
3516     p = dsc->string->data + dsc->string->index;
3517     memcpy(p, str, len);
3518     *(p+len) = '\0';
3519     dsc->string->index += len + 1;
3520     return p;
3521 }
3522 
3523 /* store line, ignoring leading spaces */
3524 dsc_private char *
dsc_add_line(CDSC * dsc,const char * line,unsigned int len)3525 dsc_add_line(CDSC *dsc, const char *line, unsigned int len)
3526 {
3527     char *newline;
3528     unsigned int i;
3529     while (len && (IS_WHITE(*line))) {
3530 	len--;
3531 	line++;
3532     }
3533     newline = dsc_alloc_string(dsc, line, len);
3534     if (newline == NULL)
3535 	return NULL;
3536 
3537     for (i=0; i<len; i++) {
3538 	if (newline[i] == '\r') {
3539 	    newline[i]='\0';
3540 	    break;
3541 	}
3542 	if (newline[i] == '\n') {
3543 	    newline[i]='\0';
3544 	    break;
3545 	}
3546     }
3547     return newline;
3548 }
3549 
3550 
3551 /* Copy string on line to new allocated string str */
3552 /* String is always null terminated */
3553 /* String is no longer than len */
3554 /* Return pointer to string  */
3555 /* Store number of used characters from line */
3556 /* Don't copy enclosing () */
3557 dsc_private char *
dsc_copy_string(char * str,unsigned int slen,char * line,unsigned int len,unsigned int * offset)3558 dsc_copy_string(char *str, unsigned int slen, char *line,
3559 	unsigned int len, unsigned int *offset)
3560 {
3561     int quoted = FALSE;
3562     int instring=0;
3563     unsigned int newlength = 0;
3564     unsigned int i = 0;
3565     unsigned char ch;
3566     if (len > slen)
3567 	len = slen-1;
3568     while ( (i<len) && IS_WHITE(line[i]))
3569 	i++;	/* skip leading spaces */
3570     if ((i < len) && (line[i]=='(')) {
3571 	quoted = TRUE;
3572 	instring++;
3573 	i++; /* don't copy outside () */
3574     }
3575     while (i < len) {
3576 	str[newlength] = ch = line[i];
3577 	i++;
3578 	if (quoted) {
3579 	    if (ch == '(')
3580 		    instring++;
3581 	    if (ch == ')')
3582 		    instring--;
3583 	    if (instring==0)
3584 		    break;
3585 	}
3586 	else if (ch == ' ')
3587 	    break;
3588 
3589 	if (ch == '\r')
3590 	    break;
3591 	if (ch == '\n')
3592 	    break;
3593 	else if ( (ch == '\\') && (i+1 < len) ) {
3594 	    ch = line[i];
3595 	    if ((ch >= '0') && (ch <= '9')) {
3596 		/* octal coded character */
3597 		int j = 3;
3598 		ch = 0;
3599 		while (j && (i < len) && line[i]>='0' && line[i]<='7') {
3600 		    ch = (unsigned char)((ch<<3) + (line[i]-'0'));
3601 		    i++;
3602 		    j--;
3603 		}
3604 		str[newlength] = ch;
3605 	    }
3606 	    else if (ch == '(') {
3607 		str[newlength] = ch;
3608 		i++;
3609 	    }
3610 	    else if (ch == ')') {
3611 		str[newlength] = ch;
3612 		i++;
3613 	    }
3614 	    else if (ch == 'b') {
3615 		str[newlength] = '\b';
3616 		i++;
3617 	    }
3618 	    else if (ch == 'f') {
3619 		str[newlength] = '\b';
3620 		i++;
3621 	    }
3622 	    else if (ch == 'n') {
3623 		str[newlength] = '\n';
3624 		i++;
3625 	    }
3626 	    else if (ch == 'r') {
3627 		str[newlength] = '\r';
3628 		i++;
3629 	    }
3630 	    else if (ch == 't') {
3631 		str[newlength] = '\t';
3632 		i++;
3633 	    }
3634 	    else if (ch == '\\') {
3635 		str[newlength] = '\\';
3636 		i++;
3637 	    }
3638 	}
3639 	newlength++;
3640     }
3641     str[newlength] = '\0';
3642     if (offset != (unsigned int *)NULL)
3643         *offset = i;
3644     return str;
3645 }
3646 
3647 dsc_private int
dsc_get_int(const char * line,unsigned int len,unsigned int * offset)3648 dsc_get_int(const char *line, unsigned int len, unsigned int *offset)
3649 {
3650     char newline[MAXSTR];
3651     int newlength = 0;
3652     unsigned int i = 0;
3653     unsigned char ch;
3654 
3655     len = min(len, sizeof(newline)-1);
3656     while ((i<len) && IS_WHITE(line[i]))
3657 	i++;	/* skip leading spaces */
3658     while (i < len) {
3659 	newline[newlength] = ch = line[i];
3660 	if (!(isdigit(ch) || (ch=='-') || (ch=='+')))
3661 	    break;  /* not part of an integer number */
3662 	i++;
3663 	newlength++;
3664     }
3665     while ((i<len) && IS_WHITE(line[i]))
3666 	i++;	/* skip trailing spaces */
3667     newline[newlength] = '\0';
3668     if (offset != (unsigned int *)NULL)
3669         *offset = i;
3670     return atoi(newline);
3671 }
3672 
3673 dsc_private float
dsc_get_real(const char * line,unsigned int len,unsigned int * offset)3674 dsc_get_real(const char *line, unsigned int len, unsigned int *offset)
3675 {
3676     char newline[MAXSTR];
3677     int newlength = 0;
3678     unsigned int i = 0;
3679     unsigned char ch;
3680 
3681     len = min(len, sizeof(newline)-1);
3682     while ((i<len) && IS_WHITE(line[i]))
3683 	i++;	/* skip leading spaces */
3684     while (i < len) {
3685 	newline[newlength] = ch = line[i];
3686 	if (!(isdigit(ch) || (ch=='.') || (ch=='-') || (ch=='+')
3687 	    || (ch=='e') || (ch=='E')))
3688 	    break;  /* not part of a real number */
3689 	i++;
3690 	newlength++;
3691     }
3692     while ((i<len) && IS_WHITE(line[i]))
3693 	i++;	/* skip trailing spaces */
3694 
3695     newline[newlength] = '\0';
3696 
3697     if (offset != (unsigned int *)NULL)
3698         *offset = i;
3699     return (float)atof(newline);
3700 }
3701 
3702 int
dsc_stricmp(const char * s,const char * t)3703 dsc_stricmp(const char *s, const char *t)
3704 {
3705     while (toupper(*s) == toupper(*t)) {
3706 	if (*s == '\0')
3707 	    return 0;
3708    	s++;
3709 	t++;
3710     }
3711     return (toupper(*s) - toupper(*t));
3712 }
3713 
3714 
3715 dsc_private int
dsc_parse_page(CDSC * dsc)3716 dsc_parse_page(CDSC *dsc)
3717 {
3718     char *p;
3719     unsigned int i;
3720     char page_label[MAXSTR];
3721     char *pl;
3722     int page_ordinal;
3723     int page_number;
3724 
3725     p = dsc->line + 7;
3726     pl = dsc_copy_string(page_label, sizeof(page_label), p, dsc->line_length-7, &i);
3727     if (pl == NULL)
3728 	return CDSC_ERROR;
3729     p += i;
3730     if (dsc->line_length - 7 - i == 0) {
3731 	/* Ordinal missing, or parentheses not matched in label */
3732 	/* Try to find ordinal at end of line */
3733 	while (i > 0) {
3734 	    if (!IS_WHITE_OR_EOL(p[-1]))
3735 		break;
3736 	    p--;
3737 	    i--;
3738 	}
3739 	while (i > 0) {
3740 	    if (!isdigit((int)p[-1]))
3741 		break;
3742 	    p--;
3743 	    i--;
3744 	}
3745     }
3746     page_ordinal = dsc_get_int(p, dsc->line_length - 7 - i, NULL);
3747 
3748     if ( (page_ordinal == 0) || (strlen(page_label) == 0) ||
3749        (dsc->page_count &&
3750 	    (page_ordinal != dsc->page[dsc->page_count-1].ordinal+1)) ) {
3751 	int rc = dsc_error(dsc, CDSC_MESSAGE_PAGE_ORDINAL, dsc->line,
3752 		dsc->line_length);
3753 	switch (rc) {
3754 	    case CDSC_RESPONSE_OK:
3755 		/* ignore this page */
3756 		return CDSC_OK;
3757 	    case CDSC_RESPONSE_CANCEL:
3758 		/* accept the page */
3759 		break;
3760 	    case CDSC_RESPONSE_IGNORE_ALL:
3761 		return CDSC_NOTDSC;
3762 	}
3763     }
3764 
3765     page_number = dsc->page_count;
3766     dsc_add_page(dsc, page_ordinal, page_label);
3767     dsc->page[page_number].begin = DSC_START(dsc);
3768     dsc->page[page_number].end = DSC_START(dsc);
3769 
3770     if (dsc->page[page_number].label == NULL)
3771 	return CDSC_ERROR;	/* no memory */
3772 
3773     return CDSC_OK;
3774 }
3775 
3776 
3777 
3778 /* DSC error reporting */
3779 
3780 void
dsc_debug_print(CDSC * dsc,const char * str)3781 dsc_debug_print(CDSC *dsc, const char *str)
3782 {
3783     if (dsc->debug_print_fn)
3784 	dsc->debug_print_fn(dsc->caller_data, str);
3785 }
3786 
3787 
3788 /* Display a message about a problem with the DSC comments.
3789  *
3790  * explanation = an index to to a multiline explanation in dsc_message[]
3791  * line = pointer to the offending DSC line (if any)
3792  * return code =
3793  *   CDSC_RESPONSE_OK 	       DSC was wrong, make a guess about what
3794  *                             was really meant.
3795  *   CDSC_RESPONSE_CANCEL      Assume DSC was correct, ignore if it
3796  *                             is misplaced.
3797  *   CDSC_RESPONSE_IGNORE_ALL  Ignore all DSC.
3798  */
3799 /* Silent operation.  Don't display errors. */
3800 dsc_private int
dsc_error(CDSC * dsc,unsigned int explanation,char * line,unsigned int line_len)3801 dsc_error(CDSC *dsc, unsigned int explanation,
3802 	char *line, unsigned int line_len)
3803 {
3804     /* if error function provided, use it */
3805     if (dsc->dsc_error_fn)
3806 	return dsc->dsc_error_fn(dsc->caller_data, dsc,
3807 	    explanation, line, line_len);
3808 
3809     /* treat DSC as being correct */
3810     return CDSC_RESPONSE_CANCEL;
3811 }
3812 
3813 
3814 /* Fixup if DCS 2.0 was used */
3815 dsc_private int
dsc_dcs2_fixup(CDSC * dsc)3816 dsc_dcs2_fixup(CDSC *dsc)
3817 {
3818     char composite[] = "Composite";
3819     /* If DCS 2.0 single file format found, expose the separations
3820      * as multiple pages.  Treat the initial EPS file as a single
3821      * page without comments, prolog or trailer.
3822      */
3823     if (dsc->dcs2) {
3824 	int code = CDSC_OK;
3825 	int page_number;
3826 	DSC_OFFSET *pbegin;
3827 	DSC_OFFSET *pend;
3828         DSC_OFFSET end;
3829 	CDCS2 *pdcs = dsc->dcs2;
3830 	/* Now treat the initial EPS file as a single page without
3831 	 * headers or trailer, so page extraction will fetch the
3832 	 * the correct separation. */
3833 	if (dsc->page_count == 0)
3834 	    code = dsc_add_page(dsc, 1, composite);
3835 	else if (dsc->page_count == 1)
3836 	    dsc->page[0].label =
3837 		dsc_alloc_string(dsc, composite, (int)strlen(composite)+1);
3838 	if (code != CDSC_OK)
3839 	    return code;
3840 	page_number = dsc->page_count - 1;
3841 	pbegin = &dsc->page[page_number].begin;
3842 	pend = &dsc->page[page_number].end;
3843 	if (*pbegin == *pend) {
3844 	    /* no page, so force it to conform to the following sections */
3845 	    *pbegin = 999999999;
3846 	    *pend = 0;
3847 	}
3848 
3849 	if (dsc->begincomments != dsc->endcomments) {
3850 	    *pbegin = min(dsc->begincomments, *pbegin);
3851 	    dsc->begincomments = 0;
3852 	    *pend = max(dsc->endcomments, *pend);
3853 	    dsc->endcomments = 0;
3854 	}
3855 
3856 	if (dsc->beginpreview != dsc->endpreview) {
3857 	    *pbegin = min(dsc->beginpreview, *pbegin);
3858 	    dsc->beginpreview = 0;
3859 	    *pend = max(dsc->endpreview, *pend);
3860 	    dsc->endpreview = 0;
3861 	}
3862 
3863 	if (dsc->begindefaults != dsc->enddefaults) {
3864 	    *pbegin = min(dsc->begindefaults, *pbegin);
3865 	    dsc->begindefaults = 0;
3866 	    *pend = max(dsc->enddefaults, *pend);
3867 	    dsc->enddefaults = 0;
3868 	}
3869 
3870 	if (dsc->beginprolog != dsc->endprolog) {
3871 	    *pbegin = min(dsc->beginprolog, *pbegin);
3872 	    dsc->beginprolog = 0;
3873 	    *pend = max(dsc->endprolog, *pend);
3874 	    dsc->endprolog = 0;
3875 	}
3876 
3877 	if (dsc->beginsetup != dsc->endsetup) {
3878 	    *pbegin = min(dsc->beginsetup, *pbegin);
3879 	    dsc->beginsetup = 0;
3880 	    *pend = max(dsc->endsetup, *pend);
3881 	    dsc->endsetup = 0;
3882 	}
3883 
3884 	if (dsc->begintrailer != dsc->endtrailer) {
3885 	    *pbegin = min(dsc->begintrailer, *pbegin);
3886 	    dsc->begintrailer = 0;
3887 	    *pend = max(dsc->endtrailer, *pend);
3888 	    dsc->endtrailer = 0;
3889 	}
3890 
3891 	if (*pbegin == 999999999)
3892 	    *pbegin = *pend;
3893 	end = 0;	/* end of composite is start of first separation */
3894 
3895 	while (pdcs) {
3896     	    page_number = dsc->page_count;
3897 	    if ((pdcs->begin) && (pdcs->colourname != NULL)) {
3898 		/* Single file DCS 2.0 */
3899 		code = dsc_add_page(dsc, page_number+1, pdcs->colourname);
3900 		if (code)
3901 		    return code;
3902 		dsc->page[page_number].begin = pdcs->begin;
3903 		dsc->page[page_number].end = pdcs->end;
3904 		if (end != 0)
3905 		    end = min(end, pdcs->begin);
3906 		else
3907 		    end = pdcs->begin;		/* first separation  */
3908 	    }
3909 	    else {
3910 		/* Multiple file DCS 2.0 */
3911 		if ((pdcs->location != NULL) &&
3912 		    (pdcs->filetype != NULL) &&
3913 		    (pdcs->colourname != NULL) &&
3914 		    (dsc_stricmp(pdcs->location, "Local") == 0) &&
3915 		    ((dsc_stricmp(pdcs->filetype, "EPS") == 0) ||
3916 		     (dsc_stricmp(pdcs->filetype, "EPSF") == 0))) {
3917 		    code = dsc_add_page(dsc, page_number+1, pdcs->colourname);
3918 		    if (code)
3919 			return code;
3920 		    dsc->page[page_number].begin = 0;
3921 		    dsc->page[page_number].end = 0;
3922 		}
3923 	    }
3924 	    pdcs = pdcs->next;
3925 	}
3926 	/* end of composite is start of first separation */
3927 	if (end != 0)
3928 	    *pend = end;
3929 	/* According to the DCS2 specification, the size of the composite
3930 	 * section can be determined by the smallest #offset.
3931 	 * Some incorrect DCS2 files don't put the separations inside
3932 	 * the DOS EPS PostScript section, and have a TIFF separation
3933 	 * between the composite and the first separation.  This
3934 	 * contravenes the DCS2 specification.  If we see one of these
3935  	 * files, bring the end of the composite back to the end of
3936 	 * the DOS EPS PostScript section.
3937 	 */
3938 	if (dsc->doseps_end && (*pend > dsc->doseps_end))
3939 	    *pend = dsc->doseps_end;
3940     }
3941     return 0;
3942 }
3943 
3944 
3945 dsc_private int
dsc_parse_platefile(CDSC * dsc)3946 dsc_parse_platefile(CDSC *dsc)
3947 {
3948     unsigned int i, n;
3949     CDCS2 dcs2;
3950     CDCS2 *pdcs2;
3951     char colourname[MAXSTR];
3952     char filetype[MAXSTR];
3953     char location[MAXSTR];
3954     char *filename = NULL;
3955     int filename_length = 0;
3956     GSBOOL blank_line;
3957     GSBOOL single = FALSE;
3958     if (IS_DSC(dsc->line, "%%PlateFile:"))
3959 	n = 12;
3960     else if (IS_DSC(dsc->line, "%%+"))
3961 	n = 3;
3962     else
3963 	return CDSC_ERROR;	/* error */
3964 
3965     memset(&dcs2, 0, sizeof(dcs2));
3966     memset(&colourname, 0, sizeof(colourname));
3967     memset(&filetype, 0, sizeof(filetype));
3968     memset(&location, 0, sizeof(location));
3969     memset(&filename, 0, sizeof(filename));
3970 
3971     /* check for blank remainder of line */
3972     blank_line = TRUE;
3973     for (i=n; i<dsc->line_length; i++) {
3974 	if (!IS_WHITE_OR_EOL(dsc->line[i])) {
3975 	    blank_line = FALSE;
3976 	    break;
3977 	}
3978     }
3979 
3980     if (!blank_line) {
3981 	dsc_copy_string(colourname, sizeof(colourname),
3982 		dsc->line+n, dsc->line_length-n, &i);
3983 	n+=i;
3984 	if (i)
3985 	    dsc_copy_string(filetype, sizeof(filetype),
3986 		dsc->line+n, dsc->line_length-n, &i);
3987 	n+=i;
3988 	while (IS_WHITE_OR_EOL(dsc->line[n]))
3989 	    n++;
3990 	if (dsc->line[n] == '#') {
3991 	    /* single file DCS 2.0 */
3992 	    single = TRUE;
3993 	    n++;
3994 	    if (i)
3995 		dcs2.begin= dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
3996 	    n+=i;
3997 	    if (i)
3998 		dcs2.end= dcs2.begin +
3999 		    dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
4000 	}
4001 	else {
4002 	    /* multiple file DCS 2.0 */
4003 	    if (i)
4004 		dsc_copy_string(location, sizeof(location),
4005 		    dsc->line+n, dsc->line_length-n, &i);
4006 	    n+=i;
4007 	    if (i) {
4008 		filename = dsc->line+n;
4009 		filename_length = dsc->line_length-n;
4010 	    }
4011 	}
4012 	if (i==0)
4013 	    dsc_unknown(dsc); /* we didn't get all fields */
4014 	else {
4015 	    /* Allocate strings */
4016 	    if (strlen(colourname))
4017 		dcs2.colourname = dsc_alloc_string(dsc,
4018 		    colourname, (int)strlen(colourname));
4019 	    if (strlen(filetype))
4020 		dcs2.filetype = dsc_alloc_string(dsc,
4021 		    filetype, (int)strlen(filetype));
4022 	    if (strlen(location))
4023 		dcs2.location = dsc_alloc_string(dsc,
4024 		    location, (int)strlen(location));
4025 	    if (filename)
4026 		dcs2.filename = dsc_add_line(dsc, filename, filename_length);
4027 
4028 	    /* Prevent parser from reading separations */
4029 	    if (single)
4030 	        dsc->file_length = min(dsc->file_length, dcs2.begin);
4031 	    /* Allocate it */
4032 	    pdcs2 = (CDCS2 *)dsc_memalloc(dsc, sizeof(CDCS2));
4033 	    if (pdcs2 == NULL)
4034 		return CDSC_ERROR;	/* out of memory */
4035 	    memcpy(pdcs2, &dcs2, sizeof(CDCS2));
4036 	    /* Then add to list of separations */
4037 	    if (dsc->dcs2 == NULL)
4038 		dsc->dcs2 = pdcs2;
4039 	    else {
4040 		CDCS2 *this_dcs2 = dsc->dcs2;
4041 		while (this_dcs2->next)
4042 		    this_dcs2 = this_dcs2->next;
4043 		this_dcs2->next = pdcs2;
4044 	    }
4045 	}
4046     }
4047     return CDSC_OK;
4048 }
4049 
4050 /* Parse a DCS 1.0 plate comment, storing like a multi file DSC 2.0 */
4051 dsc_private int
dsc_parse_dcs1plate(CDSC * dsc)4052 dsc_parse_dcs1plate(CDSC *dsc)
4053 {
4054     unsigned int i, n = 0;
4055     CDCS2 dcs2;
4056     CDCS2 *pdcs2;
4057     const char *colourname;
4058     char filename[MAXSTR];
4059     GSBOOL blank_line;
4060     GSBOOL continued = FALSE;
4061     char *line = dsc->line;
4062 
4063     memset(&dcs2, 0, sizeof(dcs2));
4064     memset(&filename, 0, sizeof(filename));
4065 
4066     if (IS_DSC(line, "%%+")) {
4067 	n = 3;
4068 	line = dsc->last_line;
4069 	continued = TRUE;
4070     }
4071 
4072     if (IS_DSC(line, "%%CyanPlate:")) {
4073 	colourname = "Cyan";
4074 	if (!continued)
4075 	    n = 12;
4076     }
4077     else if (IS_DSC(line, "%%MagentaPlate:")) {
4078 	colourname = "Magenta";
4079 	if (!continued)
4080 	    n = 15;
4081     }
4082     else if (IS_DSC(line, "%%YellowPlate:")) {
4083 	colourname = "Yellow";
4084 	if (!continued)
4085 	    n = 14;
4086     }
4087     else if (IS_DSC(line, "%%BlackPlate:")) {
4088 	colourname = "Black";
4089 	if (!continued)
4090 	    n = 13;
4091     }
4092     else
4093 	return CDSC_ERROR;	/* error */
4094 
4095     /* check for blank remainder of line */
4096     blank_line = TRUE;
4097     for (i=n; i<dsc->line_length; i++) {
4098 	if (!IS_WHITE_OR_EOL(dsc->line[i])) {
4099 	    blank_line = FALSE;
4100 	    break;
4101 	}
4102     }
4103 
4104     if (!blank_line) {
4105 	dsc_copy_string(filename, sizeof(filename),
4106 		    dsc->line+n, dsc->line_length-n, &i);
4107 	if (i==0)
4108 	    dsc_unknown(dsc); /* we didn't get all fields */
4109 	else {
4110 	    /* Allocate strings */
4111 	    dcs2.colourname = dsc_alloc_string(dsc,
4112 		    colourname, (int)strlen(colourname));
4113 	    dcs2.filetype = dsc_alloc_string(dsc, "EPS", 3);
4114 	    dcs2.location = dsc_alloc_string(dsc, "Local", 5);
4115 	    if (strlen(filename))
4116 		dcs2.filename = dsc_alloc_string(dsc,
4117 		    filename, (int)strlen(filename));
4118 	    /* Allocate it */
4119 	    pdcs2 = (CDCS2 *)dsc_memalloc(dsc, sizeof(CDCS2));
4120 	    if (pdcs2 == NULL)
4121 		return CDSC_ERROR;	/* out of memory */
4122 	    memcpy(pdcs2, &dcs2, sizeof(CDCS2));
4123 	    /* Then add to list of separations */
4124 	    if (dsc->dcs2 == NULL)
4125 		dsc->dcs2 = pdcs2;
4126 	    else {
4127 		CDCS2 *this_dcs2 = dsc->dcs2;
4128 		while (this_dcs2->next)
4129 		    this_dcs2 = this_dcs2->next;
4130 		this_dcs2->next = pdcs2;
4131 	    }
4132 	}
4133     }
4134     return CDSC_OK;
4135 }
4136 
4137 
4138 /* Find the filename which corresponds to this separation.
4139  * Used with multiple file DCS 2.0.
4140  * Returns NULL if there is no filename, or not DCS 2.0,
4141  * or single file DCS 2.0.
4142  * Caller will need to obtain the filesize from the file.
4143  */
4144 const char *
dsc_find_platefile(CDSC * dsc,int page)4145 dsc_find_platefile(CDSC *dsc, int page)
4146 {
4147     CDCS2 *pdcs = dsc->dcs2;
4148     int i = 1;
4149     while (pdcs) {
4150 	if (pdcs->begin != pdcs->end)
4151 	    return NULL;	/* Single file DCS 2.0 */
4152 	if (pdcs->location && pdcs->filetype && pdcs->colourname
4153 	    && (dsc_stricmp(pdcs->location, "Local") == 0)
4154 	    && ((dsc_stricmp(pdcs->filetype, "EPS") == 0) ||
4155 	        (dsc_stricmp(pdcs->filetype, "EPSF") == 0))) {
4156 	    if (i == page)
4157 		return pdcs->filename;
4158 	    i++;
4159 	}
4160 	pdcs = pdcs->next;
4161     }
4162     return NULL;
4163 }
4164 
4165 
4166 dsc_private CDSCCOLOUR *
dsc_find_colour(CDSC * dsc,const char * colourname)4167 dsc_find_colour(CDSC *dsc, const char *colourname)
4168 {
4169     CDSCCOLOUR *colour = dsc->colours;
4170     while (colour) {
4171 	if (colour->name && (dsc_stricmp(colour->name, colourname)==0))
4172 	    return colour;
4173 	colour = colour->next;
4174     }
4175     return 0;
4176 }
4177 
4178 dsc_private int
dsc_parse_process_colours(CDSC * dsc)4179 dsc_parse_process_colours(CDSC *dsc)
4180 {
4181     unsigned int i, n;
4182     CDSCCOLOUR *pcolour;
4183     char colourname[MAXSTR];
4184     GSBOOL blank_line;
4185     if (IS_DSC(dsc->line, "%%DocumentProcessColors:"))
4186 	n = 24;
4187     else if (IS_DSC(dsc->line, "%%+"))
4188 	n = 3;
4189     else
4190 	return CDSC_ERROR;	/* error */
4191 
4192     memset(&colourname, 0, sizeof(colourname));
4193 
4194     /* check for blank remainder of line */
4195     blank_line = TRUE;
4196     for (i=n; i<dsc->line_length; i++) {
4197 	if (!IS_WHITE_OR_EOL(dsc->line[i])) {
4198 	    blank_line = FALSE;
4199 	    break;
4200 	}
4201     }
4202     while (IS_WHITE(dsc->line[n]))
4203 	n++;
4204     if (COMPARE(dsc->line+n, "(atend)")) {
4205 	if (dsc->scan_section == scan_comments)
4206 	    blank_line = TRUE;
4207 	else {
4208 	    dsc_unknown(dsc);
4209 	    return CDSC_NOTDSC;
4210 	}
4211     }
4212 
4213     if (!blank_line) {
4214 	do {
4215 	    dsc_copy_string(colourname, sizeof(colourname),
4216 		dsc->line+n, dsc->line_length-n, &i);
4217 	    n+=i;
4218 	    if (i && strlen(colourname)) {
4219 		if ((pcolour = dsc_find_colour(dsc, colourname)) == NULL) {
4220 		    pcolour = (CDSCCOLOUR *)
4221 			dsc_memalloc(dsc, sizeof(CDSCCOLOUR));
4222 		    if (pcolour == NULL)
4223 			return CDSC_ERROR;	/* out of memory */
4224 		    memset(pcolour, 0, sizeof(CDSCCOLOUR));
4225 		    pcolour->custom = CDSC_CUSTOM_COLOUR_UNKNOWN;
4226 		    pcolour->name = dsc_alloc_string(dsc,
4227 			colourname, (int)strlen(colourname));
4228 		    if (dsc->colours == NULL)
4229 			dsc->colours = pcolour;
4230 		    else {
4231 			CDSCCOLOUR *this_colour = dsc->colours;
4232 			while (this_colour->next)
4233 			    this_colour = this_colour->next;
4234 			this_colour->next = pcolour;
4235 		    }
4236 		}
4237 	        pcolour->type = CDSC_COLOUR_PROCESS;
4238 		if (dsc_stricmp(colourname, "Cyan")==0) {
4239 		    pcolour->custom = CDSC_CUSTOM_COLOUR_CMYK;
4240 		    pcolour->cyan = 1.0;
4241 		    pcolour->magenta = pcolour->yellow = pcolour->black = 0.0;
4242 		}
4243 		else if (dsc_stricmp(colourname, "Magenta")==0) {
4244 		    pcolour->custom = CDSC_CUSTOM_COLOUR_CMYK;
4245 		    pcolour->magenta = 1.0;
4246 		    pcolour->cyan = pcolour->yellow = pcolour->black = 0.0;
4247 		}
4248 		else if (dsc_stricmp(colourname, "Yellow")==0) {
4249 		    pcolour->custom = CDSC_CUSTOM_COLOUR_CMYK;
4250 		    pcolour->yellow = 1.0;
4251 		    pcolour->cyan = pcolour->magenta = pcolour->black = 0.0;
4252 		}
4253 		else if (dsc_stricmp(colourname, "Black")==0) {
4254 		    pcolour->custom = CDSC_CUSTOM_COLOUR_CMYK;
4255 		    pcolour->black = 1.0;
4256 		    pcolour->cyan = pcolour->magenta = pcolour->yellow = 0.0;
4257 		}
4258 		else if (dsc_stricmp(colourname, "Red")==0) {
4259 		    pcolour->custom = CDSC_CUSTOM_COLOUR_RGB;
4260 		    pcolour->red = 1.0;
4261 		    pcolour->green = pcolour->blue = 0.0;
4262 		}
4263 		else if (dsc_stricmp(colourname, "Green")==0) {
4264 		    pcolour->custom = CDSC_CUSTOM_COLOUR_RGB;
4265 		    pcolour->green = 1.0;
4266 		    pcolour->red = pcolour->blue = 0.0;
4267 		}
4268 		else if (dsc_stricmp(colourname, "Blue")==0) {
4269 		    pcolour->custom = CDSC_CUSTOM_COLOUR_RGB;
4270 		    pcolour->blue = 1.0;
4271 		    pcolour->red = pcolour->green = 0.0;
4272 		}
4273 	    }
4274 	} while (i != 0);
4275     }
4276     return CDSC_OK;
4277 }
4278 
4279 dsc_private int
dsc_parse_custom_colours(CDSC * dsc)4280 dsc_parse_custom_colours(CDSC *dsc)
4281 {
4282     unsigned int i, n;
4283     CDSCCOLOUR *pcolour;
4284     char colourname[MAXSTR];
4285     GSBOOL blank_line;
4286     if (IS_DSC(dsc->line, "%%DocumentCustomColors:"))
4287 	n = 23;
4288     else if (IS_DSC(dsc->line, "%%+"))
4289 	n = 3;
4290     else
4291 	return CDSC_ERROR;	/* error */
4292 
4293     memset(&colourname, 0, sizeof(colourname));
4294 
4295     /* check for blank remainder of line */
4296     blank_line = TRUE;
4297     for (i=n; i<dsc->line_length; i++) {
4298 	if (!IS_WHITE_OR_EOL(dsc->line[i])) {
4299 	    blank_line = FALSE;
4300 	    break;
4301 	}
4302     }
4303     while (IS_WHITE(dsc->line[n]))
4304 	n++;
4305     if (COMPARE(dsc->line+n, "(atend)")) {
4306 	if (dsc->scan_section == scan_comments)
4307 	    blank_line = TRUE;
4308 	else {
4309 	    dsc_unknown(dsc);
4310 	    return CDSC_NOTDSC;
4311 	}
4312     }
4313 
4314     if (!blank_line) {
4315 	do {
4316 	    dsc_copy_string(colourname, sizeof(colourname),
4317 		dsc->line+n, dsc->line_length-n, &i);
4318 	    n+=i;
4319 	    if (i && strlen(colourname)) {
4320 		if ((pcolour = dsc_find_colour(dsc, colourname)) == NULL) {
4321 		    pcolour = (CDSCCOLOUR *)
4322 			dsc_memalloc(dsc, sizeof(CDSCCOLOUR));
4323 		    if (pcolour == NULL)
4324 			return CDSC_ERROR;	/* out of memory */
4325 		    memset(pcolour, 0, sizeof(CDSCCOLOUR));
4326 		    pcolour->name = dsc_alloc_string(dsc,
4327 			colourname, (int)strlen(colourname));
4328 		    pcolour->custom = CDSC_CUSTOM_COLOUR_UNKNOWN;
4329 		    if (dsc->colours == NULL)
4330 			dsc->colours = pcolour;
4331 		    else {
4332 			CDSCCOLOUR *this_colour = dsc->colours;
4333 			while (this_colour->next)
4334 			    this_colour = this_colour->next;
4335 			this_colour->next = pcolour;
4336 		    }
4337 		}
4338                 pcolour->type = CDSC_COLOUR_CUSTOM;
4339 	    }
4340 	} while (i != 0);
4341     }
4342     return CDSC_OK;
4343 }
4344 
4345 
4346 dsc_private int
dsc_parse_cmyk_custom_colour(CDSC * dsc)4347 dsc_parse_cmyk_custom_colour(CDSC *dsc)
4348 {
4349     unsigned int i, n;
4350     CDSCCOLOUR *pcolour;
4351     char colourname[MAXSTR];
4352     float cyan, magenta, yellow, black;
4353     GSBOOL blank_line;
4354     if (IS_DSC(dsc->line, "%%CMYKCustomColor:"))
4355 	n = 18;
4356     else if (IS_DSC(dsc->line, "%%+"))
4357 	n = 3;
4358     else
4359 	return CDSC_ERROR;	/* error */
4360 
4361     memset(&colourname, 0, sizeof(colourname));
4362 
4363     /* check for blank remainder of line */
4364 
4365     do {
4366 	blank_line = TRUE;
4367 	for (i=n; i<dsc->line_length; i++) {
4368 	    if (!IS_WHITE_OR_EOL(dsc->line[i])) {
4369 		blank_line = FALSE;
4370 		break;
4371 	    }
4372 	}
4373 	if (blank_line)
4374 	    break;
4375 	else {
4376 	    cyan = magenta = yellow = black = 0.0;
4377 	    cyan = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
4378 	    n += i;
4379 	    if (i)
4380 		magenta = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
4381 	    n += i;
4382 	    if (i)
4383 		yellow = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
4384 	    n += i;
4385 	    if (i)
4386 		black = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
4387 	    n += i;
4388 	    if (i)
4389 		dsc_copy_string(colourname, sizeof(colourname),
4390 		    dsc->line+n, dsc->line_length-n, &i);
4391 	    n+=i;
4392 	    if (i && strlen(colourname)) {
4393 		if ((pcolour = dsc_find_colour(dsc, colourname)) == NULL) {
4394 		    pcolour = (CDSCCOLOUR *)
4395 			dsc_memalloc(dsc, sizeof(CDSCCOLOUR));
4396 		    if (pcolour == NULL)
4397 			return CDSC_ERROR;	/* out of memory */
4398 		    memset(pcolour, 0, sizeof(CDSCCOLOUR));
4399 		    pcolour->name = dsc_alloc_string(dsc,
4400 			colourname, (int)strlen(colourname));
4401 	            pcolour->type = CDSC_COLOUR_UNKNOWN;
4402 		    if (dsc->colours == NULL)
4403 			dsc->colours = pcolour;
4404 		    else {
4405 			CDSCCOLOUR *this_colour = dsc->colours;
4406 			while (this_colour->next)
4407 			    this_colour = this_colour->next;
4408 			this_colour->next = pcolour;
4409 		    }
4410 		}
4411 		pcolour->custom = CDSC_CUSTOM_COLOUR_CMYK;
4412 		pcolour->cyan = cyan;
4413 		pcolour->magenta = magenta;
4414 		pcolour->yellow = yellow;
4415 		pcolour->black = black;
4416 	    }
4417 	}
4418     } while (i != 0);
4419     return CDSC_OK;
4420 }
4421 
4422 dsc_private int
dsc_parse_rgb_custom_colour(CDSC * dsc)4423 dsc_parse_rgb_custom_colour(CDSC *dsc)
4424 {
4425     unsigned int i, n;
4426     CDSCCOLOUR *pcolour;
4427     char colourname[MAXSTR];
4428     float red, green, blue;
4429     GSBOOL blank_line;
4430     if (IS_DSC(dsc->line, "%%RGBCustomColor:"))
4431 	n = 17;
4432     else if (IS_DSC(dsc->line, "%%+"))
4433 	n = 3;
4434     else
4435 	return CDSC_ERROR;	/* error */
4436 
4437     memset(&colourname, 0, sizeof(colourname));
4438 
4439     /* check for blank remainder of line */
4440 
4441     do {
4442 	blank_line = TRUE;
4443 	for (i=n; i<dsc->line_length; i++) {
4444 	    if (!IS_WHITE_OR_EOL(dsc->line[i])) {
4445 		blank_line = FALSE;
4446 		break;
4447 	    }
4448 	}
4449 	if (blank_line)
4450 	    break;
4451 	else {
4452 	    red = green = blue = 0.0;
4453 	    red = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
4454 	    n += i;
4455 	    if (i)
4456 		green = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
4457 	    n += i;
4458 	    if (i)
4459 		blue = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
4460 	    n += i;
4461 	    if (i)
4462 		dsc_copy_string(colourname, sizeof(colourname),
4463 		    dsc->line+n, dsc->line_length-n, &i);
4464 	    n+=i;
4465 	    if (i && strlen(colourname)) {
4466 		if ((pcolour = dsc_find_colour(dsc, colourname)) == NULL) {
4467 		    pcolour = (CDSCCOLOUR *)
4468 			dsc_memalloc(dsc, sizeof(CDSCCOLOUR));
4469 		    if (pcolour == NULL)
4470 			return CDSC_ERROR;	/* out of memory */
4471 		    memset(pcolour, 0, sizeof(CDSCCOLOUR));
4472 		    pcolour->name = dsc_alloc_string(dsc,
4473 			colourname, (int)strlen(colourname));
4474 	            pcolour->type = CDSC_COLOUR_UNKNOWN;
4475 		    if (dsc->colours == NULL)
4476 			dsc->colours = pcolour;
4477 		    else {
4478 			CDSCCOLOUR *this_colour = dsc->colours;
4479 			while (this_colour->next)
4480 			    this_colour = this_colour->next;
4481 			this_colour->next = pcolour;
4482 		    }
4483 		}
4484 		pcolour->custom = CDSC_CUSTOM_COLOUR_RGB;
4485 		pcolour->red = red;
4486 		pcolour->green = green;
4487 		pcolour->blue = blue;
4488 	    }
4489 	}
4490     } while (i != 0);
4491     return CDSC_OK;
4492 }
4493