File indexing completed on 2024-05-12 04:20:03

0001 /* Copyright (C) 2000-2001, Ghostgum Software Pty Ltd.  All rights reserved.
0002     
0003   This file is part of GSview.
0004    
0005   This file is distributed in the hope that it will be useful, but
0006   WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
0007   to anyone for the consequences of using it or for whether it serves any
0008   particular purpose or works at all, unless he says so in writing.  Refer
0009   to the GNU General Public License for full details.
0010    
0011   Everyone is granted permission to copy, modify and redistribute this
0012   file, but only under the conditions described in the GNU General
0013   Public License.  A copy of this license is supposed to have been given
0014   to you along with this file so you can know your rights and
0015   responsibilities.  It should be in a file named COPYING.  Among other
0016   things, the copyright notice and this notice must be preserved on all
0017   copies.
0018 */
0019 
0020 /* $Id$ */
0021 
0022 /* dscparse.c - DSC parser  */
0023 
0024 /*
0025  * This is a DSC parser, based on the DSC 3.0 spec, 
0026  * with a few DSC 2.1 additions for page size.
0027  *
0028  * Current limitations:
0029  * %%+ may be used after any comment in the comment or trailer, 
0030  * but is currently only supported by
0031  *   %%DocumentMedia
0032  *
0033  * DSC 2.1 additions (discontinued in DSC 3.0):
0034  * %%DocumentPaperColors: 
0035  * %%DocumentPaperForms: 
0036  * %%DocumentPaperSizes: 
0037  * %%DocumentPaperWeights: 
0038  * %%PaperColor:   (ignored)
0039  * %%PaperForm:    (ignored)
0040  * %%PaperSize: 
0041  * %%PaperWeight:  (ignored)
0042  *
0043  * Other additions for defaults or page section
0044  % %%ViewingOrientation: xx xy yx yy
0045 */
0046 
0047 #include <stdio.h>  /* for sprintf(), not file I/O */
0048 #include <stdlib.h>
0049 #include <string.h>
0050 #include <ctype.h>
0051 
0052 #define MAXSTR 256
0053 
0054 #include "dscparse.h"
0055 
0056 /* Macros for comparing string literals
0057  * For maximum speed, the length of the second macro argument is
0058  * computed at compile time.
0059  * THE SECOND MACRO ARGUMENT MUST BE A STRING LITERAL.
0060  */
0061 #define COMPARE(p,str) (strncmp((const char *)(p), (str), sizeof(str)-1)==0)
0062 #define IS_DSC(line, str) (COMPARE((line), (str)))
0063 
0064 /* Macros for comparing the first one or two characters */
0065 #define IS_WHITE(ch) (((ch)==' ') || ((ch)=='\t'))
0066 #define IS_EOL(ch) (((ch)=='\r') || ((ch)=='\n'))
0067 #define IS_WHITE_OR_EOL(ch) (IS_WHITE(ch) || IS_EOL(ch))
0068 #define IS_BLANK(str) (IS_EOL(str[0]))
0069 #define NOT_DSC_LINE(str) (((str)[0]!='%') || ((str)[1]!='%'))
0070 
0071 /* Macros for document offset to start and end of line */
0072 #define DSC_START(dsc)  ((dsc)->data_offset + (dsc)->data_index - (dsc)->line_length)
0073 #define DSC_END(dsc)  ((dsc)->data_offset + (dsc)->data_index)
0074 
0075 /* dsc_scan_SECTION() functions return one of 
0076  * CDSC_ERROR, CDSC_OK, CDSC_NOTDSC 
0077  * or one of the following
0078  */
0079 /* The line should be passed on to the next section parser. */
0080 #define CDSC_PROPAGATE  10
0081 
0082 /* If document is DOS EPS and we haven't read 30 bytes, ask for more. */
0083 #define CDSC_NEEDMORE 11
0084 
0085 /* local prototypes */
0086 dsc_private void * dsc_memalloc(P2(CDSC *dsc, size_t size));
0087 dsc_private void dsc_memfree(P2(CDSC*dsc, void *ptr));
0088 dsc_private CDSC * dsc_init2(P1(CDSC *dsc));
0089 dsc_private void dsc_reset(P1(CDSC *dsc));
0090 dsc_private void dsc_section_join(P3(unsigned long begin, unsigned long *pend, unsigned long **pplast));
0091 dsc_private int dsc_read_line(P1(CDSC *dsc));
0092 dsc_private int dsc_read_doseps(P1(CDSC *dsc));
0093 dsc_private char * dsc_alloc_string(P3(CDSC *dsc, const char *str, int len));
0094 dsc_private char * dsc_add_line(P3(CDSC *dsc, const char *line, unsigned int len));
0095 dsc_private char * dsc_copy_string(P5(char *str, unsigned int slen, 
0096     char *line, unsigned int len, unsigned int *offset));
0097 dsc_private GSDWORD dsc_get_dword(P1(const unsigned char *buf));
0098 dsc_private GSWORD dsc_get_word(P1(const unsigned char *buf));
0099 dsc_private int dsc_get_int(P3(const char *line, unsigned int len, unsigned int *offset));
0100 dsc_private float dsc_get_real(P3(const char *line, unsigned int len, 
0101     unsigned int *offset));
0102 dsc_private int dsc_stricmp(P2(const char *s, const char *t));
0103 dsc_private void dsc_unknown(P1(CDSC *dsc)); 
0104 dsc_private GSBOOL dsc_is_section(char *line);
0105 dsc_private int dsc_parse_pages(P1(CDSC *dsc));
0106 dsc_private int dsc_parse_bounding_box(P3(CDSC *dsc, CDSCBBOX** pbbox, int offset));
0107 dsc_private int dsc_parse_float_bounding_box(P3(CDSC *dsc, CDSCFBBOX** pfbbox, int offset));
0108 dsc_private int dsc_parse_orientation(P3(CDSC *dsc, unsigned int *porientation, 
0109     int offset));
0110 dsc_private int dsc_parse_order(P1(CDSC *dsc));
0111 dsc_private int dsc_parse_media(P2(CDSC *dsc, const CDSCMEDIA **page_media));
0112 dsc_private int dsc_parse_document_media(P1(CDSC *dsc));
0113 dsc_private int dsc_parse_viewing_orientation(P2(CDSC *dsc, CDSCCTM **pctm));
0114 dsc_private int dsc_parse_page(P1(CDSC *dsc));
0115 dsc_private void dsc_save_line(P1(CDSC *dsc));
0116 dsc_private int dsc_scan_type(P1(CDSC *dsc));
0117 dsc_private int dsc_scan_comments(P1(CDSC *dsc));
0118 dsc_private int dsc_scan_preview(P1(CDSC *dsc));
0119 dsc_private int dsc_scan_defaults(P1(CDSC *dsc));
0120 dsc_private int dsc_scan_prolog(P1(CDSC *dsc));
0121 dsc_private int dsc_scan_setup(P1(CDSC *dsc));
0122 dsc_private int dsc_scan_page(P1(CDSC *dsc));
0123 dsc_private int dsc_scan_trailer(P1(CDSC *dsc));
0124 dsc_private int dsc_error(P4(CDSC *dsc, unsigned int explanation, 
0125     char *line, unsigned int line_len));
0126 
0127 /* DSC error reporting */
0128 dsc_private const int dsc_severity[] = {
0129     CDSC_ERROR_WARN,    /* CDSC_MESSAGE_BBOX */
0130     CDSC_ERROR_WARN,    /* CDSC_MESSAGE_EARLY_TRAILER */
0131     CDSC_ERROR_WARN,    /* CDSC_MESSAGE_EARLY_EOF */
0132     CDSC_ERROR_ERROR,   /* CDSC_MESSAGE_PAGE_IN_TRAILER */
0133     CDSC_ERROR_ERROR,   /* CDSC_MESSAGE_PAGE_ORDINAL */
0134     CDSC_ERROR_ERROR,   /* CDSC_MESSAGE_PAGES_WRONG */
0135     CDSC_ERROR_ERROR,   /* CDSC_MESSAGE_EPS_NO_BBOX */
0136     CDSC_ERROR_ERROR,   /* CDSC_MESSAGE_EPS_PAGES */
0137     CDSC_ERROR_WARN,    /* CDSC_MESSAGE_NO_MEDIA */
0138     CDSC_ERROR_WARN,    /* CDSC_MESSAGE_ATEND */
0139     CDSC_ERROR_INFORM,  /* CDSC_MESSAGE_DUP_COMMENT */
0140     CDSC_ERROR_INFORM,  /* CDSC_MESSAGE_DUP_TRAILER */
0141     CDSC_ERROR_WARN,    /* CDSC_MESSAGE_BEGIN_END */
0142     CDSC_ERROR_INFORM,  /* CDSC_MESSAGE_BAD_SECTION */
0143     CDSC_ERROR_INFORM,  /* CDSC_MESSAGE_LONG_LINE */
0144     CDSC_ERROR_WARN,    /* CDSC_MESSAGE_INCORRECT_USAGE */
0145     0
0146 };
0147 
0148 #define DSC_MAX_ERROR ((sizeof(dsc_severity) / sizeof(int))-2)
0149 
0150 const CDSCMEDIA dsc_known_media[CDSC_KNOWN_MEDIA] = {
0151     /* These sizes taken from Ghostscript gs_statd.ps */
0152     {"11x17", 792, 1224, 0, NULL, NULL, NULL},
0153     {"A0", 2380, 3368, 0, NULL, NULL, NULL},
0154     {"A1", 1684, 2380, 0, NULL, NULL, NULL}, 
0155     {"A2", 1190, 1684, 0, NULL, NULL, NULL}, 
0156     {"A3", 842, 1190, 0, NULL, NULL, NULL},
0157     {"A4", 595, 842, 0, NULL, NULL, NULL},
0158     {"A5", 421, 595, 0, NULL, NULL, NULL},
0159     {"A6", 297, 421, 0, NULL, NULL, NULL}, 
0160     {"A7", 210, 297, 0, NULL, NULL, NULL}, 
0161     {"A8", 148, 210, 0, NULL, NULL, NULL}, 
0162     {"A9", 105, 148, 0, NULL, NULL, NULL}, 
0163     {"A10", 74, 105, 0, NULL, NULL, NULL}, 
0164     {"B0", 2836, 4008, 0, NULL, NULL, NULL}, 
0165     {"B1", 2004, 2836, 0, NULL, NULL, NULL}, 
0166     {"B2", 1418, 2004, 0, NULL, NULL, NULL}, 
0167     {"B3", 1002, 1418, 0, NULL, NULL, NULL}, 
0168     {"B4", 709, 1002, 0, NULL, NULL, NULL}, /* ISO, but not Adobe standard */
0169     {"B5", 501, 709, 0, NULL, NULL, NULL},  /* ISO, but not Adobe standard */
0170     {"B6", 354, 501, 0, NULL, NULL, NULL}, 
0171     {"C0", 2600, 3677, 0, NULL, NULL, NULL}, 
0172     {"C1", 1837, 2600, 0, NULL, NULL, NULL},  
0173     {"C2", 1298, 1837, 0, NULL, NULL, NULL}, 
0174     {"C3", 918, 1298, 0, NULL, NULL, NULL}, 
0175     {"C4", 649, 918, 0, NULL, NULL, NULL}, 
0176     {"C5", 459, 649, 0, NULL, NULL, NULL}, 
0177     {"C6", 323, 459, 0, NULL, NULL, NULL}, 
0178     {"Ledger", 1224, 792, 0, NULL, NULL, NULL},
0179     {"Legal", 612, 1008, 0, NULL, NULL, NULL},
0180     {"Letter", 612, 792, 0, NULL, NULL, NULL},
0181     {"Note", 612, 792, 0, NULL, NULL, NULL},
0182 // ISO and JIS B sizes are different....
0183     {"jisb0", 2916, 4128, 0, NULL, NULL, NULL},
0184     {"jisb1", 2064, 2916, 0, NULL, NULL, NULL}, 
0185     {"jisb2", 1458, 2064, 0, NULL, NULL, NULL}, 
0186     {"jisb3", 1032, 1458, 0, NULL, NULL, NULL}, 
0187     {"jisb4", 729, 1032, 0, NULL, NULL, NULL}, 
0188     {"jisb5", 516, 729, 0, NULL, NULL, NULL}, 
0189     {"jisb6", 363, 516, 0, NULL, NULL, NULL}, 
0190 // U.S. CAD standard paper sizes
0191     {"archE", 2592, 3456, 0, NULL, NULL, NULL}, 
0192     {"archD", 1728, 2592, 0, NULL, NULL, NULL}, 
0193     {"archC", 1296, 1728, 0, NULL, NULL, NULL}, 
0194     {"archB", 864, 1296, 0, NULL, NULL, NULL}, 
0195     {"archA", 648, 864, 0, NULL, NULL, NULL}, 
0196 // Other paper sizes
0197     {"flsa", 612, 936, 0, NULL, NULL, NULL}, /* U.S. foolscap */
0198     {"flse", 612, 936, 0, NULL, NULL, NULL}, /* European foolscap */
0199     {"halfletter", 396, 612, 0, NULL, NULL, NULL}, 
0200     {NULL, 0, 0, 0, NULL, NULL, NULL}
0201 };
0202 
0203 /* parser state */
0204 enum CDSC_SCAN_SECTION {
0205     scan_none = 0,
0206     scan_comments = 1,
0207     scan_pre_preview = 2,
0208     scan_preview = 3,
0209     scan_pre_defaults = 4,
0210     scan_defaults = 5,
0211     scan_pre_prolog = 6,
0212     scan_prolog = 7,
0213     scan_pre_setup = 8,
0214     scan_setup = 9,
0215     scan_pre_pages = 10,
0216     scan_pages = 11,
0217     scan_pre_trailer = 12,
0218     scan_trailer = 13,
0219     scan_eof = 14
0220 };
0221 
0222 static const char * const dsc_scan_section_name[15] = {
0223  "Type", "Comments", 
0224  "pre-Preview", "Preview",
0225  "pre-Defaults", "Defaults",
0226  "pre-Prolog", "Prolog",
0227  "pre-Setup", "Setup",
0228  "pre-Page", "Page",
0229  "pre-Trailer", "Trailer",
0230  "EOF"
0231 };
0232 
0233 /******************************************************************/
0234 /* Public functions                                               */
0235 /******************************************************************/
0236 
0237 /* constructor */
0238 CDSC *
0239 dsc_init(void *caller_data)
0240 {
0241     CDSC *dsc = (CDSC *)malloc(sizeof(CDSC));
0242     if (dsc == NULL)
0243     return NULL;
0244     memset(dsc, 0, sizeof(CDSC));
0245     dsc->caller_data = caller_data;
0246 
0247     return dsc_init2(dsc);
0248 }
0249 
0250 /* constructor, with caller supplied memalloc */
0251 CDSC *
0252 dsc_init_with_alloc(
0253     void *caller_data,
0254     void *(*memalloc)(size_t size, void *closure_data),
0255     void (*memfree)(void *ptr, void *closure_data),
0256     void *closure_data)
0257 {
0258     CDSC *dsc = (CDSC *)memalloc(sizeof(CDSC), closure_data);
0259     if (dsc == NULL)
0260     return NULL;
0261     memset(dsc, 0, sizeof(CDSC));
0262     dsc->caller_data = caller_data;
0263 
0264     dsc->memalloc = memalloc;
0265     dsc->memfree = memfree;
0266     dsc->mem_closure_data = closure_data;
0267     
0268     return dsc_init2(dsc);
0269 }
0270 
0271 
0272 
0273 /* destructor */
0274 void 
0275 dsc_free(CDSC *dsc)
0276 {
0277     if (dsc == NULL)
0278     return;
0279     dsc_reset(dsc);
0280     dsc_memfree(dsc, dsc);
0281 }
0282 
0283 
0284 /* Tell DSC parser how long document will be, to allow ignoring
0285  * of early %%Trailer and %%EOF.  This is optional.
0286  */
0287 void 
0288 dsc_set_length(CDSC *dsc, unsigned long len)
0289 {
0290     dsc->file_length = len;
0291 }
0292 
0293 /* Process a buffer containing DSC comments and PostScript */
0294 /* Return value is < 0 for error, >=0 for OK.
0295  *  CDSC_ERROR
0296  *  CDSC_OK
0297  *  CDSC_NOTDSC (DSC will be ignored)
0298  *  other values indicate the last DSC comment read
0299  */ 
0300 int
0301 dsc_scan_data(CDSC *dsc, const char *data, int length)
0302 {
0303     int bytes_read;
0304     int code = 0;
0305 
0306     if (dsc == NULL)
0307     return CDSC_ERROR;
0308 
0309     if (dsc->id == CDSC_NOTDSC)
0310     return CDSC_NOTDSC;
0311     dsc->id = CDSC_OK;
0312     if (dsc->eof)
0313     return CDSC_OK; /* ignore */
0314 
0315     if (length == 0) {
0316     /* EOF, so process what remains */
0317     dsc->eof = TRUE;
0318     }
0319 
0320     do {
0321     if (dsc->id == CDSC_NOTDSC)
0322         break;
0323 
0324     if (length != 0) {
0325         /* move existing data if needed */
0326         if (dsc->data_length > CDSC_DATA_LENGTH/2) {
0327         memmove(dsc->data, dsc->data + dsc->data_index,
0328             dsc->data_length - dsc->data_index);
0329         dsc->data_offset += dsc->data_index;
0330         dsc->data_length -= dsc->data_index;
0331         dsc->data_index = 0;
0332         }
0333         /* append to buffer */
0334         bytes_read = min(length, (int)(CDSC_DATA_LENGTH - dsc->data_length));
0335         memcpy(dsc->data + dsc->data_length, data, bytes_read);
0336         dsc->data_length += bytes_read;
0337         data += bytes_read;
0338         length -= bytes_read;
0339     }
0340     if (dsc->scan_section == scan_none) {
0341         code = dsc_scan_type(dsc);
0342         if (code == CDSC_NEEDMORE) {
0343         /* need more characters before we can identify type */
0344         code = CDSC_OK;
0345         break;
0346         }
0347         dsc->id = code;
0348     }
0349 
0350         if (code == CDSC_NOTDSC) {
0351         dsc->id = CDSC_NOTDSC;
0352         break;
0353     }
0354 
0355     while ((code = dsc_read_line(dsc)) > 0) {
0356         if (dsc->id == CDSC_NOTDSC)
0357         break;
0358         if (dsc->doseps_end && 
0359         (dsc->data_offset + dsc->data_index > dsc->doseps_end)) {
0360         /* have read past end of DOS EPS PostScript section */
0361         return CDSC_OK; /* ignore */
0362         }
0363         if (dsc->eof)
0364         return CDSC_OK;
0365         if (dsc->skip_document)
0366         continue;   /* embedded document */
0367         if (dsc->skip_lines)
0368         continue;   /* embedded lines */
0369         if (IS_DSC(dsc->line, "%%BeginData:"))
0370         continue;
0371         if (IS_DSC(dsc->line, "%%BeginBinary:"))
0372         continue;
0373         if (IS_DSC(dsc->line, "%%EndDocument"))
0374         continue;
0375         if (IS_DSC(dsc->line, "%%EndData"))
0376         continue;
0377         if (IS_DSC(dsc->line, "%%EndBinary"))
0378         continue;
0379 
0380         do {
0381         switch (dsc->scan_section) {
0382             case scan_comments:
0383             code = dsc_scan_comments(dsc);
0384             break;
0385             case scan_pre_preview:
0386             case scan_preview:
0387             code = dsc_scan_preview(dsc);
0388             break;
0389             case scan_pre_defaults:
0390             case scan_defaults:
0391             code = dsc_scan_defaults(dsc);
0392             break;
0393             case scan_pre_prolog:
0394             case scan_prolog:
0395             code = dsc_scan_prolog(dsc);
0396             break;
0397             case scan_pre_setup:
0398             case scan_setup:
0399             code = dsc_scan_setup(dsc);
0400             break;
0401             case scan_pre_pages:
0402             case scan_pages:
0403             code = dsc_scan_page(dsc);
0404             break;
0405             case scan_pre_trailer:
0406             case scan_trailer:
0407             code = dsc_scan_trailer(dsc);
0408             break;
0409             case scan_eof:
0410             code = CDSC_OK;
0411             break;
0412             default:
0413             /* invalid state */
0414             code = CDSC_ERROR;
0415         }
0416         /* repeat if line is start of next section */
0417         } while (code == CDSC_PROPAGATE);
0418 
0419         /* if DOS EPS header not complete, ask for more */
0420         if (code == CDSC_NEEDMORE) {
0421         code = CDSC_OK;
0422         break;
0423         }
0424         if (code == CDSC_NOTDSC) {
0425         dsc->id = CDSC_NOTDSC;
0426         break;
0427         }
0428     }
0429     } while (length != 0);
0430 
0431     return (code < 0) ? code : dsc->id;
0432 }
0433 
0434 /* Tidy up from incorrect DSC comments */
0435 int 
0436 dsc_fixup(CDSC *dsc)
0437 {
0438     unsigned int i;
0439     char buf[32];
0440     unsigned long *last;
0441 
0442     if (dsc->id == CDSC_NOTDSC)
0443     return 0;
0444 
0445     /* flush last partial line */
0446     dsc_scan_data(dsc, NULL, 0);
0447 
0448     /* Fix DSC error: code between %%EndSetup and %%Page */
0449     if (dsc->page_count && (dsc->page[0].begin != dsc->endsetup)
0450         && (dsc->endsetup != dsc->beginsetup)) {
0451     dsc->endsetup = dsc->page[0].begin;
0452     dsc_debug_print(dsc, "Warning: code included between setup and first page\n");
0453     }
0454 
0455     /* Last page contained a false trailer, */
0456     /* so extend last page to start of trailer */
0457     if (dsc->page_count && (dsc->begintrailer != 0) &&
0458     (dsc->page[dsc->page_count-1].end != dsc->begintrailer)) {
0459     dsc_debug_print(dsc, "Ignoring earlier misplaced trailer\n");
0460     dsc_debug_print(dsc, "and extending last page to start of trailer\n"); 
0461     dsc->page[dsc->page_count-1].end = dsc->begintrailer;
0462     }
0463 
0464     /* 
0465      * Join up all sections.
0466      * There might be extra code between them, or we might have
0467      * missed including the \n which followed \r.
0468      */
0469     last = &dsc->endcomments;
0470     dsc_section_join(dsc->beginpreview, &dsc->endpreview, &last);
0471     dsc_section_join(dsc->begindefaults, &dsc->enddefaults, &last);
0472     dsc_section_join(dsc->beginprolog, &dsc->endprolog, &last);
0473     dsc_section_join(dsc->beginsetup, &dsc->endsetup, &last);
0474     for (i=0; i<dsc->page_count; i++)
0475     dsc_section_join(dsc->page[i].begin, &dsc->page[i].end, &last);
0476     if (dsc->begintrailer)
0477     *last = dsc->begintrailer;
0478     
0479     if ((dsc->page_pages == 0) && (dsc->page_count == 1)) {
0480     /* don't flag an error if %%Pages absent but one %%Page found */
0481     /* adjust incorrect page count */
0482     dsc->page_pages = dsc->page_count;
0483     }
0484 
0485     /* Warnings and Errors that we can now identify */
0486     if ((dsc->page_count != dsc->page_pages)) {
0487     int rc = dsc_error(dsc, CDSC_MESSAGE_PAGES_WRONG, NULL, 0);
0488     switch (rc) {
0489         case CDSC_RESPONSE_OK:
0490         /* adjust incorrect page count */
0491         dsc->page_pages = dsc->page_count;
0492         break;
0493         case CDSC_RESPONSE_CANCEL:
0494         break;;
0495         case CDSC_RESPONSE_IGNORE_ALL:
0496         return CDSC_NOTDSC;
0497     }
0498     }
0499 
0500     if (dsc->epsf && (dsc->bbox == (CDSCBBOX *)NULL)) {
0501     /* EPS files MUST include a BoundingBox */
0502     int rc = dsc_error(dsc, CDSC_MESSAGE_EPS_NO_BBOX, NULL, 0);
0503     switch (rc) {
0504         case CDSC_RESPONSE_OK:
0505         /* Assume that it is EPS */
0506         break;
0507         case CDSC_RESPONSE_CANCEL:
0508         /* Is NOT an EPS file */
0509         dsc->epsf = FALSE;
0510         case CDSC_RESPONSE_IGNORE_ALL:
0511         return CDSC_NOTDSC;
0512     }
0513     }
0514 
0515     if (dsc->epsf && ((dsc->page_count > 1) || (dsc->page_pages > 1))) {
0516     int rc = dsc_error(dsc, CDSC_MESSAGE_EPS_PAGES, NULL, 0);
0517     switch (rc) {
0518         case CDSC_RESPONSE_OK:
0519         /* Is an EPS file */
0520         break;
0521         case CDSC_RESPONSE_CANCEL:
0522         /* Is NOT an EPS file */
0523         dsc->epsf = FALSE;
0524         break;
0525         case CDSC_RESPONSE_IGNORE_ALL:
0526         return CDSC_NOTDSC;
0527     }
0528     }
0529 
0530     if ((dsc->media_count == 1) && (dsc->page_media == NULL)) {
0531     /* if one only media was specified, and default page media */
0532     /* was not specified, assume that default is the only media. */
0533     dsc->page_media = dsc->media[0];
0534     }
0535 
0536     if ((dsc->media_count != 0) && (dsc->page_media == NULL)) {
0537     int rc = dsc_error(dsc, CDSC_MESSAGE_NO_MEDIA, NULL, 0);
0538     switch (rc) {
0539         case CDSC_RESPONSE_OK:
0540         /* default media is first listed */
0541         dsc->page_media = dsc->media[0];
0542         break;
0543         case CDSC_RESPONSE_CANCEL:
0544         /* No default media */
0545         break;
0546         case CDSC_RESPONSE_IGNORE_ALL:
0547         return CDSC_NOTDSC;
0548     }
0549     }
0550 
0551     /* make sure all pages have a label */
0552     for (i=0; i<dsc->page_count; i++) {
0553     if (strlen(dsc->page[i].label) == 0) {
0554         sprintf(buf, "%d", i+1);
0555         if ((dsc->page[i].label = dsc_alloc_string(dsc, buf, strlen(buf))) 
0556         == (char *)NULL)
0557         return CDSC_ERROR;  /* no memory */
0558     }
0559     }
0560     return CDSC_OK;
0561 }
0562 
0563 /* Install a function to be used for displaying messages about 
0564  * DSC errors and warnings, and to request advice from user.
0565  * Installing an error function is optional.
0566  */
0567 void 
0568 dsc_set_error_function(CDSC *dsc, 
0569     int (*fn)(P5(void *caller_data, CDSC *dsc, 
0570     unsigned int explanation, const char *line, unsigned int line_len)))
0571 {
0572     dsc->dsc_error_fn = fn;
0573 }
0574 
0575 
0576 /* Install a function for printing debug messages */
0577 /* This is optional */
0578 void 
0579 dsc_set_debug_function(CDSC *dsc, 
0580     void (*debug_fn)(P2(void *caller_data, const char *str)))
0581 {
0582     dsc->debug_print_fn = debug_fn;
0583 }
0584 
0585 /* Doesn't need to be public for PostScript documents */
0586 /* Made public so GSview can add pages when processing PDF files */
0587 int 
0588 dsc_add_page(CDSC *dsc, int ordinal, char *label)
0589 {
0590     dsc->page[dsc->page_count].ordinal = ordinal;
0591     dsc->page[dsc->page_count].label = 
0592     dsc_alloc_string(dsc, label, strlen(label)+1);
0593     dsc->page[dsc->page_count].begin = 0;
0594     dsc->page[dsc->page_count].end = 0;
0595     dsc->page[dsc->page_count].orientation = CDSC_ORIENT_UNKNOWN;
0596     dsc->page[dsc->page_count].media = NULL;
0597     dsc->page[dsc->page_count].bbox = NULL;
0598     dsc->page[dsc->page_count].viewing_orientation = NULL;
0599 
0600     dsc->page_count++;
0601     if (dsc->page_count >= dsc->page_chunk_length) {
0602     CDSCPAGE *new_page = (CDSCPAGE *)dsc_memalloc(dsc, 
0603         (CDSC_PAGE_CHUNK+dsc->page_count) * sizeof(CDSCPAGE));
0604     if (new_page == NULL)
0605         return CDSC_ERROR;  /* out of memory */
0606     memcpy(new_page, dsc->page, 
0607         dsc->page_count * sizeof(CDSCPAGE));
0608     dsc_memfree(dsc, dsc->page);
0609     dsc->page= new_page;
0610     dsc->page_chunk_length = CDSC_PAGE_CHUNK+dsc->page_count;
0611     }
0612     return CDSC_OK;
0613 }
0614 
0615 /* Doesn't need to be public for PostScript documents */
0616 /* Made public so GSview can store PDF MediaBox */
0617 int
0618 dsc_add_media(CDSC *dsc, CDSCMEDIA *media)
0619 {
0620     CDSCMEDIA **newmedia_array;
0621     CDSCMEDIA *newmedia;
0622 
0623     /* extend media array  */
0624     newmedia_array = (CDSCMEDIA **)dsc_memalloc(dsc, 
0625     (dsc->media_count + 1) * sizeof(CDSCMEDIA *));
0626     if (newmedia_array == NULL)
0627     return CDSC_ERROR;  /* out of memory */
0628     if (dsc->media != NULL) {
0629     memcpy(newmedia_array, dsc->media, 
0630         dsc->media_count * sizeof(CDSCMEDIA *));
0631     dsc_memfree(dsc, dsc->media);
0632     }
0633     dsc->media = newmedia_array;
0634 
0635     /* allocate new media */
0636     newmedia = dsc->media[dsc->media_count] =
0637     (CDSCMEDIA *)dsc_memalloc(dsc, sizeof(CDSCMEDIA));
0638     if (newmedia == NULL)
0639     return CDSC_ERROR;  /* out of memory */
0640     newmedia->name = NULL;
0641     newmedia->width = 595.0;
0642     newmedia->height = 842.0;
0643     newmedia->weight = 80.0;
0644     newmedia->colour = NULL;
0645     newmedia->type = NULL;
0646     newmedia->mediabox = NULL;
0647 
0648     dsc->media_count++;
0649 
0650     if (media->name) {
0651     newmedia->name = dsc_alloc_string(dsc, media->name,
0652         strlen(media->name));
0653     if (newmedia->name == NULL)
0654         return CDSC_ERROR;  /* no memory */
0655     }
0656     newmedia->width = media->width;
0657     newmedia->height = media->height;
0658     newmedia->weight = media->weight;
0659     if (media->colour) {
0660     newmedia->colour = dsc_alloc_string(dsc, media->colour, 
0661         strlen(media->colour));
0662         if (newmedia->colour == NULL)
0663         return CDSC_ERROR;  /* no memory */
0664     }
0665     if (media->type) {
0666     newmedia->type = dsc_alloc_string(dsc, media->type, 
0667         strlen(media->type));
0668     if (newmedia->type == NULL)
0669         return CDSC_ERROR;  /* no memory */
0670     }
0671     newmedia->mediabox = NULL;
0672 
0673     if (media->mediabox) {
0674     newmedia->mediabox = (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX));
0675     if (newmedia->mediabox == NULL)
0676         return CDSC_ERROR;  /* no memory */
0677     *newmedia->mediabox = *media->mediabox;
0678     }
0679     return CDSC_OK;
0680 }
0681 
0682 /* Doesn't need to be public for PostScript documents */
0683 /* Made public so GSview can store PDF CropBox */
0684 int
0685 dsc_set_page_bbox(CDSC *dsc, unsigned int page_number, 
0686     int llx, int lly, int urx, int ury)
0687 {
0688     CDSCBBOX *bbox;
0689     if (page_number >= dsc->page_count)
0690     return CDSC_ERROR;
0691     bbox = dsc->page[page_number].bbox;
0692     if (bbox == NULL)
0693     dsc->page[page_number].bbox = bbox = 
0694         (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX));
0695     if (bbox == NULL)
0696     return CDSC_ERROR;
0697     bbox->llx = llx;
0698     bbox->lly = lly;
0699     bbox->urx = urx;
0700     bbox->ury = ury;
0701     return CDSC_OK;
0702 }
0703 
0704 
0705 /******************************************************************/
0706 /* Private functions below here.                                  */
0707 /******************************************************************/
0708 
0709 dsc_private void *
0710 dsc_memalloc(CDSC *dsc, size_t size)
0711 {
0712     if (dsc->memalloc)
0713     return dsc->memalloc(size, dsc->mem_closure_data);
0714     return malloc(size);
0715 }
0716 
0717 dsc_private void
0718 dsc_memfree(CDSC*dsc, void *ptr)
0719 {
0720     if (dsc->memfree) 
0721     dsc->memfree(ptr, dsc->mem_closure_data);
0722     else
0723     free(ptr);
0724 }
0725 
0726 /* private constructor */
0727 dsc_private CDSC *
0728 dsc_init2(CDSC *dsc)
0729 {
0730     dsc_reset(dsc);
0731 
0732     dsc->string_head = (CDSCSTRING *)dsc_memalloc(dsc, sizeof(CDSCSTRING));
0733     if (dsc->string_head == NULL) {
0734     dsc_free(dsc);
0735     return NULL;    /* no memory */
0736     }
0737     dsc->string = dsc->string_head;
0738     dsc->string->next = NULL;
0739     dsc->string->data = (char *)dsc_memalloc(dsc, CDSC_STRING_CHUNK);
0740     if (dsc->string->data == NULL) {
0741     dsc_free(dsc);
0742     return NULL;    /* no memory */
0743     }
0744     dsc->string->index = 0;
0745     dsc->string->length = CDSC_STRING_CHUNK;
0746     
0747     dsc->page = (CDSCPAGE *)dsc_memalloc(dsc, CDSC_PAGE_CHUNK * sizeof(CDSCPAGE));
0748     if (dsc->page == NULL) {
0749     dsc_free(dsc);
0750     return NULL;    /* no memory */
0751     }
0752     dsc->page_chunk_length = CDSC_PAGE_CHUNK;
0753     dsc->page_count = 0;
0754     
0755     dsc->line = NULL;
0756     dsc->data_length = 0;
0757     dsc->data_index = dsc->data_length;
0758 
0759     return dsc;
0760 }
0761 
0762 
0763 dsc_private void 
0764 dsc_reset(CDSC *dsc)
0765 {
0766     unsigned int i;
0767     /* Clear public members */
0768     dsc->dsc = FALSE;
0769     dsc->ctrld = FALSE;
0770     dsc->pjl = FALSE;
0771     dsc->epsf = FALSE;
0772     dsc->pdf = FALSE;
0773     dsc->epsf = FALSE;
0774     dsc->preview = CDSC_NOPREVIEW;
0775     dsc->dsc_version = NULL;    /* stored in dsc->string */
0776     dsc->language_level = 0;
0777     dsc->document_data = CDSC_DATA_UNKNOWN;
0778     dsc->begincomments = 0;
0779     dsc->endcomments = 0;
0780     dsc->beginpreview = 0;
0781     dsc->endpreview = 0;
0782     dsc->begindefaults = 0;
0783     dsc->enddefaults = 0;
0784     dsc->beginprolog = 0;
0785     dsc->endprolog = 0;
0786     dsc->beginsetup = 0;
0787     dsc->endsetup = 0;
0788     dsc->begintrailer = 0;
0789     dsc->endtrailer = 0;
0790     
0791     for (i=0; i<dsc->page_count; i++) {
0792     /* page media is pointer to an element of media or dsc_known_media */
0793     /* do not free it. */
0794 
0795     if (dsc->page[i].bbox)
0796         dsc_memfree(dsc, dsc->page[i].bbox);
0797     if (dsc->page[i].viewing_orientation)
0798         dsc_memfree(dsc, dsc->page[i].viewing_orientation);
0799     }
0800     if (dsc->page)
0801     dsc_memfree(dsc, dsc->page);
0802     dsc->page = NULL;
0803     
0804     dsc->page_count = 0;
0805     dsc->page_pages = 0;
0806     dsc->page_order = CDSC_ORDER_UNKNOWN;
0807     dsc->page_orientation = CDSC_ORIENT_UNKNOWN;
0808     if (dsc->viewing_orientation)
0809     dsc_memfree(dsc, dsc->viewing_orientation);
0810     dsc->viewing_orientation = NULL;
0811     
0812     if (dsc->media) {
0813     for (i=0; i<dsc->media_count; i++) {
0814         if (dsc->media[i]) {
0815         if (dsc->media[i]->mediabox)
0816             dsc_memfree(dsc, dsc->media[i]->mediabox);
0817         dsc_memfree(dsc, dsc->media[i]);
0818         }
0819     }
0820     dsc_memfree(dsc, dsc->media);
0821     }
0822     dsc->media_count = 0;
0823     dsc->media = NULL;
0824 
0825     /* page_media is pointer to an element of media or dsc_known_media */
0826     /* do not free it. */
0827     dsc->page_media = NULL;
0828 
0829     if (dsc->bbox)
0830     dsc_memfree(dsc, dsc->bbox);
0831     dsc->bbox = NULL;
0832     if (dsc->page_bbox)
0833     dsc_memfree(dsc, dsc->page_bbox);
0834     dsc->page_bbox = NULL;
0835     if (dsc->doseps)
0836     dsc_memfree(dsc, dsc->doseps);
0837     dsc->doseps = NULL;
0838     
0839     dsc->dsc_title = NULL;
0840     dsc->dsc_creator = NULL;
0841     dsc->dsc_date = NULL;
0842     dsc->dsc_for = NULL;
0843     
0844 
0845     dsc->max_error = DSC_MAX_ERROR;
0846     dsc->severity = dsc_severity;
0847 
0848     /* Clear private members */
0849     /* Don't touch dsc->caller_data */
0850     dsc->id = CDSC_OK;
0851     dsc->scan_section = scan_none;
0852     dsc->doseps_end = 0;
0853     dsc->page_chunk_length = 0;
0854     dsc->file_length = 0;
0855     dsc->skip_document = 0;
0856     dsc->skip_bytes = 0;
0857     dsc->skip_lines = 0;
0858     dsc->skip_pjl = 0;
0859     dsc->begin_font_count = 0;
0860     dsc->begin_feature_count = 0;
0861     dsc->begin_resource_count = 0;
0862     dsc->begin_procset_count = 0;
0863 
0864     dsc->data_length = 0;
0865     dsc->data_index = 0;
0866     dsc->data_offset = 0;
0867 
0868     dsc->eof = 0;
0869     
0870     dsc->line = 0;
0871     dsc->line_length = 0;
0872     dsc->eol = 0;
0873     dsc->last_cr = FALSE;
0874     dsc->line_count = 1;
0875     dsc->long_line = FALSE;
0876     memset(dsc->last_line, 0, sizeof(dsc->last_line));
0877 
0878     dsc->string = dsc->string_head;
0879     while (dsc->string != (CDSCSTRING *)NULL) {
0880     if (dsc->string->data)
0881         dsc_memfree(dsc, dsc->string->data);
0882     dsc->string_head = dsc->string;
0883     dsc->string = dsc->string->next;
0884     dsc_memfree(dsc, dsc->string_head);
0885     }
0886     dsc->string_head = NULL;
0887     dsc->string = NULL;
0888 
0889     /* don't touch caller functions */
0890 
0891     /* public data */
0892     if (dsc->hires_bbox)
0893     dsc_memfree(dsc, dsc->hires_bbox);
0894     dsc->hires_bbox = NULL;
0895     if (dsc->crop_box)
0896     dsc_memfree(dsc, dsc->crop_box);
0897     dsc->crop_box = NULL;
0898 }
0899 
0900 /* 
0901 * Join up all sections.
0902 * There might be extra code between them, or we might have
0903 * missed including the \n which followed \r.
0904 * begin is the start of this section
0905 * pend is a pointer to the end of this section
0906 * pplast is a pointer to a pointer of the end of the previous section
0907 */
0908 dsc_private void 
0909 dsc_section_join(unsigned long begin, unsigned long *pend, unsigned long **pplast)
0910 {
0911     if (begin)
0912     **pplast = begin;
0913     if (*pend > begin)
0914     *pplast = pend;
0915 }
0916 
0917 
0918 /* return value is 0 if no line available, or length of line */
0919 dsc_private int
0920 dsc_read_line(CDSC *dsc)
0921 {
0922     char *p, *last;
0923     dsc->line = NULL;
0924 
0925     if (dsc->eof) {
0926     /* return all that remains, even if line incomplete */
0927     dsc->line = dsc->data + dsc->data_index;
0928     dsc->line_length = dsc->data_length - dsc->data_index;
0929     dsc->data_index = dsc->data_length;
0930     return dsc->line_length;
0931     }
0932 
0933     /* ignore embedded bytes */
0934     if (dsc->skip_bytes) {
0935     int cnt = min(dsc->skip_bytes,
0936              (int)(dsc->data_length - dsc->data_index));
0937     dsc->skip_bytes -= cnt;
0938     dsc->data_index += cnt;
0939     if (dsc->skip_bytes != 0)
0940         return 0;
0941     }
0942 
0943     do {
0944     dsc->line = dsc->data + dsc->data_index;
0945     last = dsc->data + dsc->data_length;
0946     if (dsc->data_index == dsc->data_length) {
0947         dsc->line_length = 0;
0948         return 0;
0949     }
0950     if (dsc->eol) {
0951         /* if previous line was complete, increment line count */
0952         dsc->line_count++;
0953         if (dsc->skip_lines)
0954         dsc->skip_lines--;
0955     }
0956         
0957     /* skip over \n which followed \r */
0958     if (dsc->last_cr && dsc->line[0] == '\n') {
0959         dsc->data_index++;
0960         dsc->line++;
0961     }
0962     dsc->last_cr = FALSE;
0963 
0964     /* look for EOL */
0965     dsc->eol = FALSE;
0966     for (p = dsc->line; p < last; p++) {
0967         if (*p == '\r') {
0968         p++;
0969         if ((p<last) && (*p == '\n'))
0970             p++;    /* include line feed also */
0971         else
0972             dsc->last_cr = TRUE; /* we might need to skip \n */
0973         dsc->eol = TRUE;    /* dsc->line is a complete line */
0974         break;
0975         }
0976         if (*p == '\n') {
0977         p++;
0978         dsc->eol = TRUE;    /* dsc->line is a complete line */
0979         break;
0980         }
0981         if (*p == '\032') {     /* MS-DOS Ctrl+Z */
0982         dsc->eol = TRUE;
0983         }
0984     }
0985     if (dsc->eol == FALSE) {
0986         /* we haven't got a complete line yet */
0987         if (dsc->data_length - dsc->data_index < sizeof(dsc->data)/2) {
0988         /* buffer is less than half full, ask for some more */
0989         dsc->line_length = 0;
0990         return 0;
0991         }
0992     }
0993     dsc->data_index += dsc->line_length = (p - dsc->line);
0994     } while (dsc->skip_lines && dsc->line_length);
0995 
0996     if (dsc->line_length == 0)
0997     return 0;
0998     
0999     if ((dsc->line[0]=='%') && (dsc->line[1]=='%'))  {
1000     /* handle recursive %%BeginDocument */
1001     if ((dsc->skip_document) && dsc->line_length &&
1002         COMPARE(dsc->line, "%%EndDocument")) {
1003         dsc->skip_document--;
1004     }
1005 
1006     /* handle embedded lines or binary data */
1007     if (COMPARE(dsc->line, "%%BeginData:")) {
1008         /* %%BeginData: <numberof>[ <type> [ <bytesorlines> ] ] 
1009          * <numberof> ::= <uint> (Lines or physical bytes) 
1010          * <type> ::= Hex | Binary | ASCII (Type of data) 
1011          * <bytesorlines> ::= Bytes | Lines (Read in bytes or lines) 
1012          */
1013         char begindata[MAXSTR+1];
1014         int cnt;
1015             unsigned int num;
1016         const char *numberof, *bytesorlines;
1017             if ((num = dsc->line_length) >= sizeof(begindata)-1)
1018                 num = sizeof(begindata)-1;
1019  
1020             memcpy(begindata, dsc->line, num);
1021             begindata[num] = '\0';
1022         numberof = strtok(begindata+12, " \r\n");
1023         strtok(NULL, " \r\n");  /* dump type */
1024         bytesorlines = strtok(NULL, " \r\n");
1025         if (bytesorlines == NULL)
1026         bytesorlines = "Bytes";
1027        
1028         if ( (numberof == NULL) || (bytesorlines == NULL) ) {
1029         /* invalid usage of %%BeginData */
1030         /* ignore that we ever saw it */
1031         int rc = dsc_error(dsc, CDSC_MESSAGE_INCORRECT_USAGE, 
1032                 dsc->line, dsc->line_length);
1033         switch (rc) {
1034             case CDSC_RESPONSE_OK:
1035             case CDSC_RESPONSE_CANCEL:
1036             break;
1037             case CDSC_RESPONSE_IGNORE_ALL:
1038             return 0;
1039         }
1040         }
1041         else {
1042         cnt = atoi(numberof);
1043         if (cnt) {
1044             if (bytesorlines && (dsc_stricmp(bytesorlines, "Lines")==0)) {
1045             /* skip cnt lines */
1046             if (dsc->skip_lines == 0) {
1047                 /* we are not already skipping lines */
1048                 dsc->skip_lines = cnt+1;
1049             }
1050             }
1051             else {
1052             /* byte count doesn't includes \n or \r\n  */
1053             /* or \r of %%BeginData: */
1054             /* skip cnt bytes */
1055             if (dsc->skip_bytes == 0) {
1056                 /* we are not already skipping lines */
1057                 dsc->skip_bytes = cnt;
1058             }
1059 
1060             }
1061         }
1062         }
1063     }
1064     else if (COMPARE(dsc->line, "%%BeginBinary:")) {
1065         /* byte count doesn't includes \n or \r\n or \r of %%BeginBinary:*/
1066         unsigned long cnt = atoi(dsc->line + 14);
1067         if (dsc->skip_bytes == 0) {
1068         /* we are not already skipping lines */
1069         dsc->skip_bytes = cnt;
1070         }
1071     }
1072     }
1073     
1074     if ((dsc->line[0]=='%') && (dsc->line[1]=='%') &&
1075     COMPARE(dsc->line, "%%BeginDocument:") ) {
1076     /* Skip over embedded document, recursively */
1077     dsc->skip_document++;
1078     }
1079 
1080     if (!dsc->long_line && (dsc->line_length > DSC_LINE_LENGTH)) {
1081     dsc_error(dsc, CDSC_MESSAGE_LONG_LINE, dsc->line, dsc->line_length);
1082         dsc->long_line = TRUE;
1083     }
1084     
1085     return dsc->line_length;
1086 }
1087 
1088 
1089 /* Save last DSC line, for use with %%+ */
1090 dsc_private void 
1091 dsc_save_line(CDSC *dsc)
1092 {
1093     int len = min(sizeof(dsc->last_line), dsc->line_length);
1094     memcpy(dsc->last_line, dsc->line, len);
1095 }
1096 
1097 /* display unknown DSC line */
1098 dsc_private void 
1099 dsc_unknown(CDSC *dsc)
1100 {
1101     if (dsc->debug_print_fn) {
1102     char line[DSC_LINE_LENGTH];
1103     unsigned int length = min(DSC_LINE_LENGTH-1, dsc->line_length);
1104     sprintf(line, "Unknown in %s section at line %d:\n  ", 
1105         dsc_scan_section_name[dsc->scan_section], dsc->line_count);
1106     dsc_debug_print(dsc, line);
1107     strncpy(line, dsc->line, length);
1108     line[length] = '\0';
1109     dsc_debug_print(dsc, line);
1110     }
1111 }
1112 
1113 
1114 dsc_private GSBOOL
1115 dsc_is_section(char *line)
1116 {
1117     if ( !((line[0]=='%') && (line[1]=='%')) )
1118     return FALSE;
1119     if (IS_DSC(line, "%%BeginPreview"))
1120     return TRUE;
1121     if (IS_DSC(line, "%%BeginDefaults"))
1122     return TRUE;
1123     if (IS_DSC(line, "%%BeginProlog"))
1124     return TRUE;
1125     if (IS_DSC(line, "%%BeginSetup"))
1126     return TRUE;
1127     if (IS_DSC(line, "%%Page:"))
1128     return TRUE;
1129     if (IS_DSC(line, "%%Trailer"))
1130     return TRUE;
1131     if (IS_DSC(line, "%%EOF"))
1132     return TRUE;
1133     return FALSE;
1134 }
1135 
1136 
1137 dsc_private GSDWORD
1138 dsc_get_dword(const unsigned char *buf)
1139 {
1140     GSDWORD dw;
1141     dw = (GSDWORD)buf[0];
1142     dw += ((GSDWORD)buf[1])<<8;
1143     dw += ((GSDWORD)buf[2])<<16;
1144     dw += ((GSDWORD)buf[3])<<24;
1145     return dw;
1146 }
1147 
1148 dsc_private GSWORD
1149 dsc_get_word(const unsigned char *buf)
1150 {
1151     GSWORD w;
1152     w = (GSWORD)buf[0];
1153     w |= (GSWORD)(buf[1]<<8);
1154     return w;
1155 }
1156 
1157 dsc_private int
1158 dsc_read_doseps(CDSC *dsc)
1159 {
1160     unsigned char *line = (unsigned char *)dsc->line;
1161     if ((dsc->doseps = (CDSCDOSEPS *)dsc_memalloc(dsc, sizeof(CDSCDOSEPS))) == NULL)
1162     return CDSC_ERROR;  /* no memory */
1163     
1164     dsc->doseps->ps_begin = dsc_get_dword(line+4);
1165     dsc->doseps->ps_length = dsc_get_dword(line+8);
1166     dsc->doseps->wmf_begin = dsc_get_dword(line+12);
1167     dsc->doseps->wmf_length = dsc_get_dword(line+16);
1168     dsc->doseps->tiff_begin = dsc_get_dword(line+20);
1169     dsc->doseps->tiff_length = dsc_get_dword(line+24);
1170     dsc->doseps->checksum = dsc_get_word(line+28);
1171     
1172     dsc->doseps_end = dsc->doseps->ps_begin + dsc->doseps->ps_length;
1173 
1174     /* move data_index backwards to byte after doseps header */
1175     dsc->data_index -= dsc->line_length - 30;
1176     /* we haven't read a line of PostScript code yet */
1177     dsc->line_count = 0;
1178     /* skip from current position to start of PostScript section */
1179     dsc->skip_bytes = dsc->doseps->ps_begin - 30;
1180 
1181     if (dsc->doseps->tiff_begin)
1182     dsc->preview = CDSC_TIFF;
1183     if (dsc->doseps->wmf_begin)
1184     dsc->preview = CDSC_WMF;
1185 
1186     return CDSC_OK;
1187 }
1188 
1189 
1190 
1191 dsc_private int 
1192 dsc_parse_pages(CDSC *dsc)
1193 {
1194     int ip, io; 
1195     unsigned int i;
1196     char *p;
1197     int n;
1198     if ((dsc->page_pages != 0) && (dsc->scan_section == scan_comments)) {
1199     int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, 
1200         dsc->line_length);
1201     switch (rc) {
1202         case CDSC_RESPONSE_OK:
1203         case CDSC_RESPONSE_CANCEL:
1204         return CDSC_OK; /* ignore duplicate comments in header */
1205         case CDSC_RESPONSE_IGNORE_ALL:
1206         return CDSC_NOTDSC;
1207     }
1208     }
1209     if ((dsc->page_pages != 0) && (dsc->scan_section == scan_trailer)) {
1210     int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, 
1211         dsc->line_length);
1212     switch (rc) {
1213         case CDSC_RESPONSE_OK:
1214         case CDSC_RESPONSE_CANCEL:
1215         break;      /* use duplicate comments in header */
1216         case CDSC_RESPONSE_IGNORE_ALL:
1217         return CDSC_NOTDSC;
1218     }
1219     }
1220 
1221     n = IS_DSC(dsc->line, "%%+") ? 3 : 8;
1222     while (IS_WHITE(dsc->line[n]))
1223     n++;
1224     p = dsc->line + n;
1225     if (COMPARE(p, "atend")) {
1226     int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, dsc->line_length);
1227     switch (rc) {
1228         case CDSC_RESPONSE_OK:
1229         /* assume (atend) */
1230         /* we should mark it as deferred */
1231         break;
1232         case CDSC_RESPONSE_CANCEL:
1233         /* ignore it */
1234         break;
1235         case CDSC_RESPONSE_IGNORE_ALL:
1236         return CDSC_NOTDSC;
1237     }
1238     }
1239     else if (COMPARE(p, "(atend)")) {
1240     /* do nothing */
1241     /* we should mark it as deferred */
1242     }
1243     else {
1244     ip = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
1245         if (i) {
1246         n+=i;
1247         dsc->page_pages = ip;
1248         io = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
1249         if (i) {
1250         /* DSC 2 uses extra integer to indicate page order */
1251         /* DSC 3 uses %%PageOrder: */
1252         if (dsc->page_order == CDSC_ORDER_UNKNOWN)
1253             switch (io) {
1254             case -1:
1255                 dsc->page_order = CDSC_DESCEND;
1256                 break;
1257             case 0:
1258                 dsc->page_order = CDSC_SPECIAL;
1259                 break;
1260             case 1:
1261                 dsc->page_order = CDSC_ASCEND;
1262                 break;
1263             }
1264         }
1265     }
1266     else {
1267         int rc = dsc_error(dsc, CDSC_MESSAGE_INCORRECT_USAGE, dsc->line, 
1268         dsc->line_length);
1269         switch (rc) {
1270         case CDSC_RESPONSE_OK:
1271         case CDSC_RESPONSE_CANCEL:
1272             /* ignore it */
1273             break;
1274         case CDSC_RESPONSE_IGNORE_ALL:
1275             return CDSC_NOTDSC;
1276         }
1277     }
1278     }
1279     return CDSC_OK;
1280 }
1281 
1282 dsc_private int 
1283 dsc_parse_bounding_box(CDSC *dsc, CDSCBBOX** pbbox, int offset)
1284 {
1285     unsigned int i, n;
1286     int llx, lly, urx, ury;
1287     float fllx, flly, furx, fury;
1288     char *p;
1289     /* Process first %%BoundingBox: in comments, and last in trailer */
1290     if ((*pbbox != NULL) && (dsc->scan_section == scan_comments)) {
1291     int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, 
1292         dsc->line_length);
1293     switch (rc) {
1294         case CDSC_RESPONSE_OK:
1295         case CDSC_RESPONSE_CANCEL:
1296         return CDSC_OK; /* ignore duplicate comments in header */
1297         case CDSC_RESPONSE_IGNORE_ALL:
1298         return CDSC_NOTDSC;
1299     }
1300     }
1301     if ((*pbbox != NULL) && (dsc->scan_section == scan_pages)) {
1302     int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, 
1303         dsc->line_length);
1304     switch (rc) {
1305         case CDSC_RESPONSE_OK:
1306         case CDSC_RESPONSE_CANCEL:
1307         return CDSC_OK; /* ignore duplicate comments in header */
1308         case CDSC_RESPONSE_IGNORE_ALL:
1309         return CDSC_NOTDSC;
1310     }
1311     }
1312     if ((*pbbox != NULL) && (dsc->scan_section == scan_trailer)) {
1313     int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, 
1314         dsc->line_length);
1315     switch (rc) {
1316         case CDSC_RESPONSE_OK:
1317         case CDSC_RESPONSE_CANCEL:
1318         break;      /* use duplicate comments in trailer */
1319         case CDSC_RESPONSE_IGNORE_ALL:
1320         return CDSC_NOTDSC;
1321     }
1322     }
1323     if (*pbbox != NULL) {
1324     dsc_memfree(dsc, *pbbox);
1325     *pbbox = NULL;
1326     }
1327 
1328     /* should only process first %%BoundingBox: */
1329 
1330     while (IS_WHITE(dsc->line[offset]))
1331     offset++;
1332     p = dsc->line + offset;
1333     
1334     if (COMPARE(p, "atend")) {
1335     int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, 
1336         dsc->line_length);
1337     switch (rc) {
1338         case CDSC_RESPONSE_OK:
1339         /* assume (atend) */
1340         /* we should mark it as deferred */
1341         break;
1342         case CDSC_RESPONSE_CANCEL:
1343         /* ignore it */
1344         break;
1345         case CDSC_RESPONSE_IGNORE_ALL:
1346         return CDSC_NOTDSC;
1347     }
1348     }
1349     else if (COMPARE(p, "(atend)")) {
1350     /* do nothing */
1351     /* we should mark it as deferred */
1352     }
1353     else {
1354         /* llx = */ lly = urx = ury = 0;
1355     n = offset;
1356     llx = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
1357     n += i;
1358     if (i)
1359         lly = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
1360     n += i;
1361     if (i)
1362         urx = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
1363     n += i;
1364     if (i)
1365         ury = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
1366     if (i) {
1367         *pbbox = (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX));
1368         if (*pbbox == NULL)
1369         return CDSC_ERROR;  /* no memory */
1370         (*pbbox)->llx = llx;
1371         (*pbbox)->lly = lly;
1372         (*pbbox)->urx = urx;
1373         (*pbbox)->ury = ury;
1374     }
1375     else {
1376         int rc = dsc_error(dsc, CDSC_MESSAGE_BBOX, dsc->line, 
1377         dsc->line_length);
1378         switch (rc) {
1379           case CDSC_RESPONSE_OK:
1380         /* fllx = */ flly = furx = fury = 0.0;
1381         n = offset;
1382         n += i;
1383         fllx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1384         n += i;
1385         if (i)
1386             flly = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1387         n += i;
1388         if (i)
1389             furx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1390         n += i;
1391         if (i)
1392             fury = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1393         if (i) {
1394             *pbbox = (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX));
1395                     if (*pbbox == NULL) {
1396                         return CDSC_ERROR;  /* no memory */
1397                     }
1398                     (*pbbox)->llx = (int)fllx;
1399                     (*pbbox)->lly = (int)flly;
1400                     (*pbbox)->urx = (int)(furx+0.999);
1401                     (*pbbox)->ury = (int)(fury+0.999);
1402                 }
1403         return CDSC_OK;
1404         case CDSC_RESPONSE_CANCEL:
1405         return CDSC_OK;
1406         case CDSC_RESPONSE_IGNORE_ALL:
1407         return CDSC_NOTDSC;
1408       }
1409     }
1410     }
1411     return CDSC_OK;
1412 }
1413 
1414 dsc_private int 
1415 dsc_parse_float_bounding_box(CDSC *dsc, CDSCFBBOX** pbbox, int offset)
1416 {
1417     unsigned int i, n;
1418     float fllx, flly, furx, fury;
1419     char *p;
1420     /* Process first %%HiResBoundingBox: or %%CropBox: in comments, 
1421      * and last in trailer.
1422      */
1423     if ((*pbbox != NULL) && (dsc->scan_section == scan_comments)) {
1424     int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, 
1425         dsc->line_length);
1426     switch (rc) {
1427         case CDSC_RESPONSE_OK:
1428         case CDSC_RESPONSE_CANCEL:
1429         return CDSC_OK; /* ignore duplicate comments in header */
1430         case CDSC_RESPONSE_IGNORE_ALL:
1431         return CDSC_NOTDSC;
1432     }
1433     }
1434     if ((*pbbox != NULL) && (dsc->scan_section == scan_pages)) {
1435     int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, 
1436         dsc->line_length);
1437     switch (rc) {
1438         case CDSC_RESPONSE_OK:
1439         case CDSC_RESPONSE_CANCEL:
1440         return CDSC_OK; /* ignore duplicate comments in header */
1441         case CDSC_RESPONSE_IGNORE_ALL:
1442         return CDSC_NOTDSC;
1443     }
1444     }
1445     if ((*pbbox != NULL) && (dsc->scan_section == scan_trailer)) {
1446     int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, 
1447         dsc->line_length);
1448     switch (rc) {
1449         case CDSC_RESPONSE_OK:
1450         case CDSC_RESPONSE_CANCEL:
1451         break;      /* use duplicate comments in trailer */
1452         case CDSC_RESPONSE_IGNORE_ALL:
1453         return CDSC_NOTDSC;
1454     }
1455     }
1456     if (*pbbox != NULL) {
1457     dsc_memfree(dsc, *pbbox);
1458     *pbbox = NULL;
1459     }
1460 
1461     /* should only process first %%BoundingBox: */
1462 
1463     while (IS_WHITE(dsc->line[offset]))
1464     offset++;
1465     p = dsc->line + offset;
1466     
1467     if (COMPARE(p, "atend")) {
1468     int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, 
1469         dsc->line_length);
1470     switch (rc) {
1471         case CDSC_RESPONSE_OK:
1472         /* assume (atend) */
1473         /* we should mark it as deferred */
1474         break;
1475         case CDSC_RESPONSE_CANCEL:
1476         /* ignore it */
1477         break;
1478         case CDSC_RESPONSE_IGNORE_ALL:
1479         return CDSC_NOTDSC;
1480     }
1481     }
1482     else if (COMPARE(p, "(atend)")) {
1483     /* do nothing */
1484     /* we should mark it as deferred */
1485     }
1486     else {
1487     /* fllx = */ flly = furx = fury = 0.0;
1488     n = offset;
1489     fllx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1490     n += i;
1491     if (i)
1492         flly = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1493     n += i;
1494     if (i)
1495         furx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1496     n += i;
1497     if (i)
1498         fury = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1499     if (i) {
1500         *pbbox = (CDSCFBBOX *)dsc_memalloc(dsc, sizeof(CDSCFBBOX));
1501         if (*pbbox == NULL)
1502         return CDSC_ERROR;  /* no memory */
1503         (*pbbox)->fllx = fllx;
1504         (*pbbox)->flly = flly;
1505         (*pbbox)->furx = furx;
1506         (*pbbox)->fury = fury;
1507     }
1508     }
1509     return CDSC_OK;
1510 }
1511 
1512 dsc_private int 
1513 dsc_parse_orientation(CDSC *dsc, unsigned int *porientation, int offset)
1514 {
1515     char *p;
1516     if ((dsc->page_orientation != CDSC_ORIENT_UNKNOWN) && 
1517     (dsc->scan_section == scan_comments)) {
1518     int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, 
1519         dsc->line_length);
1520     switch (rc) {
1521         case CDSC_RESPONSE_OK:
1522         case CDSC_RESPONSE_CANCEL:
1523         return CDSC_OK; /* ignore duplicate comments in header */
1524         case CDSC_RESPONSE_IGNORE_ALL:
1525         return CDSC_NOTDSC;
1526     }
1527     }
1528     if ((dsc->page_orientation != CDSC_ORIENT_UNKNOWN) && 
1529     (dsc->scan_section == scan_trailer)) {
1530     int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, 
1531         dsc->line_length);
1532     switch (rc) {
1533         case CDSC_RESPONSE_OK:
1534         case CDSC_RESPONSE_CANCEL:
1535         break;      /* use duplicate comments in header; */
1536         case CDSC_RESPONSE_IGNORE_ALL:
1537         return CDSC_NOTDSC;
1538     }
1539     }
1540     p = dsc->line + offset;
1541     while (IS_WHITE(*p))
1542     p++;
1543     if (COMPARE(p, "atend")) {
1544     int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, dsc->line_length);
1545     switch (rc) {
1546         case CDSC_RESPONSE_OK:
1547         /* assume (atend) */
1548         /* we should mark it as deferred */
1549         break;
1550         case CDSC_RESPONSE_CANCEL:
1551         /* ignore it */
1552         break;
1553         case CDSC_RESPONSE_IGNORE_ALL:
1554         return CDSC_NOTDSC;
1555     }
1556     }
1557     else if (COMPARE(p, "(atend)")) {
1558     /* do nothing */
1559     /* we should mark it as deferred */
1560     }
1561     else if (COMPARE(p, "Portrait")) {
1562     *porientation = CDSC_PORTRAIT;
1563     }
1564     else if (COMPARE(p, "Landscape")) {
1565     *porientation = CDSC_LANDSCAPE;
1566     }
1567     else {
1568     dsc_unknown(dsc);
1569     }
1570     return CDSC_OK;
1571 }
1572 
1573 dsc_private int 
1574 dsc_parse_order(CDSC *dsc)
1575 {
1576     char *p;
1577     if ((dsc->page_order != CDSC_ORDER_UNKNOWN) && 
1578     (dsc->scan_section == scan_comments)) {
1579     int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, 
1580         dsc->line_length);
1581     switch (rc) {
1582         case CDSC_RESPONSE_OK:
1583         case CDSC_RESPONSE_CANCEL:
1584         return CDSC_OK; /* ignore duplicate comments in header */
1585         case CDSC_RESPONSE_IGNORE_ALL:
1586         return CDSC_NOTDSC;
1587     }
1588     }
1589     if ((dsc->page_order != CDSC_ORDER_UNKNOWN) && 
1590     (dsc->scan_section == scan_trailer)) {
1591     int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, 
1592         dsc->line_length);
1593     switch (rc) {
1594         case CDSC_RESPONSE_OK:
1595         case CDSC_RESPONSE_CANCEL:
1596         break;      /* use duplicate comments in trailer */
1597         case CDSC_RESPONSE_IGNORE_ALL:
1598         return CDSC_NOTDSC;
1599     }
1600     }
1601 
1602     p = dsc->line + (IS_DSC(dsc->line, "%%+") ? 3 : 13);
1603     while (IS_WHITE(*p))
1604     p++;
1605     if (COMPARE(p, "atend")) {
1606     int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, 
1607         dsc->line_length);
1608     switch (rc) {
1609         case CDSC_RESPONSE_OK:
1610         /* assume (atend) */
1611         /* we should mark it as deferred */
1612         break;
1613         case CDSC_RESPONSE_CANCEL:
1614         /* ignore it */
1615         break;
1616         case CDSC_RESPONSE_IGNORE_ALL:
1617         return CDSC_NOTDSC;
1618     }
1619     }
1620     else if (COMPARE(p, "(atend)")) {
1621     /* do nothing */
1622     /* we should mark it as deferred */
1623     }
1624     else if (COMPARE(p, "Ascend")) {
1625     dsc->page_order = CDSC_ASCEND;
1626     }
1627     else if (COMPARE(p, "Descend")) {
1628     dsc->page_order = CDSC_DESCEND;
1629     }
1630     else if (COMPARE(p, "Special")) {
1631     dsc->page_order = CDSC_SPECIAL;
1632     }
1633     else {
1634     dsc_unknown(dsc);
1635     }
1636     return CDSC_OK;
1637 }
1638 
1639 
1640 dsc_private int 
1641 dsc_parse_media(CDSC *dsc, const CDSCMEDIA **page_media)
1642 {
1643     char media_name[MAXSTR];
1644     int n = IS_DSC(dsc->line, "%%+") ? 3 : 12; /* %%PageMedia: */
1645     unsigned int i;
1646 
1647     if (dsc_copy_string(media_name, sizeof(media_name)-1,
1648     dsc->line+n, dsc->line_length-n, NULL)) {
1649     for (i=0; i<dsc->media_count; i++) {
1650         if (dsc->media[i]->name && 
1651         (dsc_stricmp(media_name, dsc->media[i]->name) == 0)) {
1652         *page_media = dsc->media[i];
1653         return CDSC_OK;
1654         }
1655     }
1656     }
1657     dsc_unknown(dsc);
1658     
1659     return CDSC_OK;
1660 }
1661 
1662 
1663 dsc_private int 
1664 dsc_parse_document_media(CDSC *dsc)
1665 {
1666     unsigned int i, n;
1667     CDSCMEDIA lmedia;
1668     GSBOOL blank_line;
1669 
1670     if (IS_DSC(dsc->line, "%%DocumentMedia:"))
1671     n = 16;
1672     else if (IS_DSC(dsc->line, "%%+"))
1673     n = 3;
1674     else
1675     return CDSC_ERROR;  /* error */
1676 
1677     /* check for blank remainder of line */
1678     blank_line = TRUE;
1679     for (i=n; i<dsc->line_length; i++) {
1680     if (!IS_WHITE_OR_EOL(dsc->line[i])) {
1681         blank_line = FALSE;
1682         break;
1683     }
1684     }
1685 
1686     if (!blank_line) {
1687     char name[MAXSTR];
1688     char colour[MAXSTR];
1689     char type[MAXSTR];
1690     lmedia.name = lmedia.colour = lmedia.type = (char *)NULL;
1691     lmedia.width = lmedia.height = lmedia.weight = 0;
1692     lmedia.mediabox = (CDSCBBOX *)NULL;
1693     lmedia.name = dsc_copy_string(name, sizeof(name)-1,
1694         dsc->line+n, dsc->line_length-n, &i);
1695     n+=i;
1696     if (i)
1697         lmedia.width = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1698     n+=i;
1699     if (i)
1700         lmedia.height = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1701     n+=i;
1702     if (i)
1703         lmedia.weight = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1704     n+=i;
1705     if (i)
1706         lmedia.colour = dsc_copy_string(colour, sizeof(colour)-1,
1707         dsc->line+n, dsc->line_length-n, &i);
1708     n+=i;
1709     if (i)
1710         lmedia.type = dsc_copy_string(type, sizeof(type)-1,
1711         dsc->line+n, dsc->line_length-n, &i);
1712 
1713     if (i==0)
1714         dsc_unknown(dsc); /* we didn't get all fields */
1715     else {
1716         if (dsc_add_media(dsc, &lmedia))
1717         return CDSC_ERROR;  /* out of memory */
1718     }
1719     }
1720     return CDSC_OK;
1721 }
1722 
1723 /* viewing orientation is believed to be the first four elements of
1724  * a CTM matrix
1725  */
1726 dsc_private int 
1727 dsc_parse_viewing_orientation(CDSC *dsc, CDSCCTM **pctm)
1728 {
1729     CDSCCTM ctm;
1730     unsigned int i, n;
1731 
1732     if (*pctm != NULL) {
1733     dsc_memfree(dsc, *pctm);
1734     *pctm = NULL;
1735     }
1736 
1737     n = IS_DSC(dsc->line, "%%+") ? 3 : 21;  /* %%ViewingOrientation: */
1738     while (IS_WHITE(dsc->line[n]))
1739     n++;
1740 
1741     /* ctm.xx = */ ctm.xy = ctm.yx = ctm.yy = 0.0;
1742     ctm.xx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1743     n += i;
1744     if (i)
1745         ctm.xy = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1746     n += i;
1747     if (i)
1748         ctm.yx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1749     n += i;
1750     if (i)
1751         ctm.yy = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
1752     if (i==0) {
1753     dsc_unknown(dsc); /* we didn't get all fields */
1754     }
1755     else {
1756     *pctm = (CDSCCTM *)dsc_memalloc(dsc, sizeof(CDSCCTM));
1757     if (*pctm == NULL)
1758         return CDSC_ERROR;  /* no memory */
1759     **pctm = ctm;
1760     }
1761     return CDSC_OK;
1762 }
1763    
1764 
1765 /* This is called before dsc_read_line(), since we may
1766  * need to skip a binary header which contains a new line
1767  * character
1768  */
1769 dsc_private int 
1770 dsc_scan_type(CDSC *dsc)
1771 {
1772     unsigned char *p;
1773     unsigned char *line = (unsigned char *)(dsc->data + dsc->data_index);
1774     int length = dsc->data_length - dsc->data_index;
1775 
1776     /* Types that should be known:
1777      *   DSC
1778      *   EPSF
1779      *   PJL + any of above
1780      *   ^D + any of above
1781      *   DOS EPS
1782      *   PDF
1783      *   non-DSC
1784      */
1785 
1786     /* First process any non PostScript headers */
1787     /* At this stage we do not have a complete line */
1788 
1789     if (length == 0)
1790     return CDSC_NEEDMORE;
1791 
1792     if (dsc->skip_pjl) {
1793     /* skip until first PostScript comment */
1794     while (length >= 2) {
1795         while (length && !IS_EOL(line[0])) {
1796         /* skip until EOL character */
1797         line++;
1798         dsc->data_index++;
1799         length--;
1800         }
1801         while ((length >= 2) && IS_EOL(line[0]) && IS_EOL(line[1])) {
1802         /* skip until EOL followed by non-EOL */
1803         line++;
1804         dsc->data_index++;
1805         length--;
1806         }
1807         if (length < 2)
1808         return CDSC_NEEDMORE;
1809 
1810         if (IS_EOL(line[0]) && line[1]=='%') {
1811         line++;
1812         dsc->data_index++;
1813         length--;
1814         dsc->skip_pjl = FALSE;
1815         break;
1816         }
1817         else {
1818         /* line++; */
1819         dsc->data_index++;
1820         /* length--; */
1821         return CDSC_NEEDMORE;
1822         }
1823     }
1824     if (dsc->skip_pjl)
1825         return CDSC_NEEDMORE;
1826     }
1827 
1828     if (length == 0)
1829     return CDSC_NEEDMORE;
1830 
1831     if (line[0] == '\004') {
1832     line++;
1833     dsc->data_index++;
1834     length--;
1835     dsc->ctrld = TRUE;
1836     }
1837 
1838     if (line[0] == '\033') {
1839     /* possibly PJL */
1840     if (length < 9)
1841         return CDSC_NEEDMORE;
1842     if (COMPARE(line, "\033%-12345X")) {
1843         dsc->skip_pjl = TRUE;  /* skip until first PostScript comment */
1844         dsc->pjl = TRUE;
1845         dsc->data_index += 9;
1846         return dsc_scan_type(dsc);
1847     }
1848     }
1849 
1850     if ((line[0]==0xc5) && (length < 4))
1851     return CDSC_NEEDMORE;
1852     if ((line[0]==0xc5) && (line[1]==0xd0) && 
1853      (line[2]==0xd3) && (line[3]==0xc6) ) {
1854     /* id is "EPSF" with bit 7 set */
1855     /* read DOS EPS header, then ignore all bytes until the PS section */
1856     if (length < 30)
1857         return CDSC_NEEDMORE;
1858     dsc->line = (char *)line;
1859     if (dsc_read_doseps(dsc))
1860         return CDSC_ERROR;
1861     }
1862     else {
1863     if (length < 2)
1864         return CDSC_NEEDMORE;
1865     if ((line[0] == '%') && (line[1] == 'P')) {
1866         if (length < 5)
1867             return CDSC_NEEDMORE;
1868         if (COMPARE(line, "%PDF-")) {
1869         dsc->pdf = TRUE;
1870         dsc->scan_section = scan_comments;
1871         return CDSC_OK;
1872         }
1873     }
1874     }
1875 
1876     /* Finally process PostScript headers */
1877 
1878     if (dsc_read_line(dsc) <= 0)
1879     return CDSC_NEEDMORE;
1880     
1881     dsc->dsc_version = dsc_add_line(dsc, dsc->line, dsc->line_length);
1882     if (COMPARE(dsc->line, "%!PS-Adobe")) {
1883     dsc->dsc = TRUE;
1884     dsc->begincomments = DSC_START(dsc);
1885     if (dsc->dsc_version == NULL)
1886         return CDSC_ERROR;  /* no memory */
1887     p = (unsigned char *)dsc->line + 14;
1888     while (IS_WHITE(*p))
1889         p++;
1890     if (COMPARE(p, "EPSF-"))
1891         dsc->epsf = TRUE;
1892     dsc->scan_section = scan_comments;
1893     return CDSC_PSADOBE;
1894     }
1895     if (COMPARE(dsc->line, "%!")) {
1896     dsc->scan_section = scan_comments;
1897     return CDSC_NOTDSC;
1898     }
1899 
1900     dsc->scan_section = scan_comments;
1901     return CDSC_NOTDSC; /* unrecognised */
1902 }
1903 
1904 
1905 
1906 dsc_private int 
1907 dsc_scan_comments(CDSC *dsc)
1908 {
1909     /* Comments section ends at */
1910     /*  %%EndComments */
1911     /*  another section */
1912     /*  line that does not start with %% */
1913     /* Save a few important lines */
1914 
1915     char *line = dsc->line;
1916     GSBOOL continued = FALSE;
1917     dsc->id = CDSC_OK;
1918     if (IS_DSC(line, "%%EndComments")) {
1919     dsc->id = CDSC_ENDCOMMENTS;
1920     dsc->endcomments = DSC_END(dsc);
1921     dsc->scan_section = scan_pre_preview;
1922     return CDSC_OK;
1923     }
1924     else if (IS_DSC(line, "%%BeginComments")) {
1925     /* ignore because we are in this section */
1926     dsc->id = CDSC_BEGINCOMMENTS;
1927     }
1928     else if (dsc_is_section(line)) {
1929     dsc->endcomments = DSC_START(dsc);
1930     dsc->scan_section = scan_pre_preview;
1931     return CDSC_PROPAGATE;
1932     }
1933     else if (line[0] == '%' && IS_WHITE_OR_EOL(line[1])) {
1934     dsc->endcomments = DSC_START(dsc);
1935     dsc->scan_section = scan_pre_preview;
1936     return CDSC_PROPAGATE;
1937     }
1938     else if (line[0] != '%') {
1939     dsc->id = CDSC_OK;
1940     dsc->endcomments = DSC_START(dsc);
1941     dsc->scan_section = scan_pre_preview;
1942     return CDSC_PROPAGATE;
1943     }
1944     else if (IS_DSC(line, "%%Begin")) {
1945     dsc->endcomments = DSC_START(dsc);
1946     dsc->scan_section = scan_pre_preview;
1947     return CDSC_PROPAGATE;
1948     }
1949 
1950     /* Handle continuation lines.
1951      * To simply processing, we assume that contination lines 
1952      * will only occur if repeat parameters are allowed and that 
1953      * a complete set of these parameters appears on each line.  
1954      * This is more restrictive than the DSC specification, but
1955      * is valid for the DSC comments understood by this parser
1956      * for all documents that we have seen.
1957      */
1958     if (IS_DSC(line, "%%+")) {
1959     line = dsc->last_line;
1960     continued = TRUE;
1961     }
1962     else
1963     dsc_save_line(dsc);
1964 
1965     if (IS_DSC(line, "%%Pages:")) {
1966     dsc->id = CDSC_PAGES;
1967     if (dsc_parse_pages(dsc) != 0)
1968         return CDSC_ERROR;
1969     }
1970     else if (IS_DSC(line, "%%Creator:")) {
1971     dsc->id = CDSC_CREATOR;
1972     dsc->dsc_creator = dsc_add_line(dsc, dsc->line+10, dsc->line_length-10);
1973     if (dsc->dsc_creator==NULL)
1974         return CDSC_ERROR;
1975     }
1976     else if (IS_DSC(line, "%%CreationDate:")) {
1977     dsc->id = CDSC_CREATIONDATE;
1978     dsc->dsc_date = dsc_add_line(dsc, dsc->line+15, dsc->line_length-15);
1979     if (dsc->dsc_date==NULL)
1980         return CDSC_ERROR;
1981     }
1982     else if (IS_DSC(line, "%%Title:")) {
1983     dsc->id = CDSC_TITLE;
1984     dsc->dsc_title = dsc_add_line(dsc, dsc->line+8, dsc->line_length-8);
1985     if (dsc->dsc_title==NULL)
1986         return CDSC_ERROR;
1987     }
1988     else if (IS_DSC(line, "%%For:")) {
1989     dsc->id = CDSC_FOR;
1990     dsc->dsc_for = dsc_add_line(dsc, dsc->line+6, dsc->line_length-6);
1991     if (dsc->dsc_for==NULL)
1992         return CDSC_ERROR;
1993     }
1994     else if (IS_DSC(line, "%%LanguageLevel:")) {
1995     unsigned int n = continued ? 3 : 16;
1996     unsigned int i;
1997     int ll;
1998     dsc->id = CDSC_LANGUAGELEVEL;
1999     ll = dsc_get_int(dsc->line+n, dsc->line_length-n, &i);
2000     if (i) {
2001         if ( (ll==1) || (ll==2) || (ll==3) )
2002         dsc->language_level = ll;
2003         else {
2004         dsc_unknown(dsc);
2005         }
2006     }
2007     else 
2008         dsc_unknown(dsc);
2009     }
2010     else if (IS_DSC(line, "%%BoundingBox:")) {
2011     dsc->id = CDSC_BOUNDINGBOX;
2012     if (dsc_parse_bounding_box(dsc, &(dsc->bbox), continued ? 3 : 14))
2013         return CDSC_ERROR;
2014     }
2015     else if (IS_DSC(line, "%%HiResBoundingBox:")) {
2016     dsc->id = CDSC_HIRESBOUNDINGBOX;
2017     if (dsc_parse_float_bounding_box(dsc, &(dsc->hires_bbox), 
2018         continued ? 3 : 19))
2019         return CDSC_ERROR;
2020     }
2021     else if (IS_DSC(line, "%%CropBox:")) {
2022     dsc->id = CDSC_CROPBOX;
2023     if (dsc_parse_float_bounding_box(dsc, &(dsc->crop_box), 
2024         continued ? 3 : 10))
2025         return CDSC_ERROR;
2026     }
2027     else if (IS_DSC(line, "%%Orientation:")) {
2028     dsc->id = CDSC_ORIENTATION;
2029     if (dsc_parse_orientation(dsc, &(dsc->page_orientation), 
2030         continued ? 3 : 14))
2031         return CDSC_ERROR;
2032     }
2033     else if (IS_DSC(line, "%%PageOrder:")) {
2034     dsc->id = CDSC_PAGEORDER;
2035     if (dsc_parse_order(dsc))
2036         return CDSC_ERROR;
2037     }
2038     else if (IS_DSC(line, "%%DocumentMedia:")) {
2039     dsc->id = CDSC_DOCUMENTMEDIA;
2040     if (dsc_parse_document_media(dsc))
2041         return CDSC_ERROR;
2042     }
2043     else if (IS_DSC(line, "%%DocumentPaperSizes:")) {
2044     /* DSC 2.1 */
2045     unsigned int n = continued ? 3 : 21;
2046     unsigned int count = 0;
2047     unsigned int i = 1;
2048     char name[MAXSTR];
2049     char *p;
2050     dsc->id = CDSC_DOCUMENTPAPERSIZES;
2051     while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) {
2052         p = dsc_copy_string(name, sizeof(name)-1,
2053             dsc->line+n, dsc->line_length-n, &i);
2054         if (i && p) {
2055         const CDSCMEDIA *m = dsc_known_media;
2056         if (count >= dsc->media_count) {
2057             /* set some default values */
2058             CDSCMEDIA lmedia;
2059             lmedia.name = p;
2060             lmedia.width = 595.0;
2061             lmedia.height = 842.0;
2062             lmedia.weight = 80.0;
2063             lmedia.colour = NULL;
2064             lmedia.type = NULL;
2065             lmedia.mediabox = NULL;
2066             if (dsc_add_media(dsc, &lmedia))
2067             return CDSC_ERROR;
2068         }
2069         else
2070             dsc->media[count]->name = 
2071             dsc_alloc_string(dsc, p, strlen(p));
2072         /* find in list of known media */
2073         while (m && m->name) {
2074             if (dsc_stricmp(p, m->name)==0) {
2075             dsc->media[count]->width = m->width;
2076             dsc->media[count]->height = m->height;
2077             break;
2078             }
2079             m++;
2080         }
2081         }
2082         n+=i;
2083         count++;
2084     }
2085     }
2086     else if (IS_DSC(line, "%%DocumentPaperForms:")) {
2087     /* DSC 2.1 */
2088     unsigned int n = continued ? 3 : 21;
2089     unsigned int count = 0;
2090     unsigned int i = 1;
2091     char type[MAXSTR];
2092     char *p;
2093     dsc->id = CDSC_DOCUMENTPAPERFORMS;
2094     while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) {
2095         p = dsc_copy_string(type, sizeof(type)-1,
2096             dsc->line+n, dsc->line_length-n, &i);
2097         if (i && p) {
2098         if (count >= dsc->media_count) {
2099             /* set some default values */
2100             CDSCMEDIA lmedia;
2101             lmedia.name = NULL;
2102             lmedia.width = 595.0;
2103             lmedia.height = 842.0;
2104             lmedia.weight = 80.0;
2105             lmedia.colour = NULL;
2106             lmedia.type = p;
2107             lmedia.mediabox = NULL;
2108             if (dsc_add_media(dsc, &lmedia))
2109             return CDSC_ERROR;
2110         }
2111         else
2112             dsc->media[count]->type = 
2113             dsc_alloc_string(dsc, p, strlen(p));
2114         }
2115         n+=i;
2116         count++;
2117     }
2118     }
2119     else if (IS_DSC(line, "%%DocumentPaperColors:")) {
2120     /* DSC 2.1 */
2121     unsigned int n = continued ? 3 : 22;
2122     unsigned int count = 0;
2123     unsigned int i = 1;
2124     char colour[MAXSTR];
2125     char *p;
2126     dsc->id = CDSC_DOCUMENTPAPERCOLORS;
2127     while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) {
2128         p = dsc_copy_string(colour, sizeof(colour)-1, 
2129             dsc->line+n, dsc->line_length-n, &i);
2130         if (i && p) {
2131         if (count >= dsc->media_count) {
2132             /* set some default values */
2133             CDSCMEDIA lmedia;
2134             lmedia.name = NULL;
2135             lmedia.width = 595.0;
2136             lmedia.height = 842.0;
2137             lmedia.weight = 80.0;
2138             lmedia.colour = p;
2139             lmedia.type = NULL;
2140             lmedia.mediabox = NULL;
2141             if (dsc_add_media(dsc, &lmedia))
2142             return CDSC_ERROR;
2143         }
2144         else
2145             dsc->media[count]->colour = 
2146             dsc_alloc_string(dsc, p, strlen(p));
2147         }
2148         n+=i;
2149         count++;
2150     }
2151     }
2152     else if (IS_DSC(line, "%%DocumentPaperWeights:")) {
2153     /* DSC 2.1 */
2154     unsigned int n = continued ? 3 : 23;
2155     unsigned int count = 0;
2156     unsigned int i = 1;
2157     float w;
2158     dsc->id = CDSC_DOCUMENTPAPERWEIGHTS;
2159     while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) {
2160         w = dsc_get_real(dsc->line+n, dsc->line_length-n, &i);
2161         if (i) {
2162         if (count >= dsc->media_count) {
2163             /* set some default values */
2164             CDSCMEDIA lmedia;
2165             lmedia.name = NULL;
2166             lmedia.width = 595.0;
2167             lmedia.height = 842.0;
2168             lmedia.weight = w;
2169             lmedia.colour = NULL;
2170             lmedia.type = NULL;
2171             lmedia.mediabox = NULL;
2172             if (dsc_add_media(dsc, &lmedia))
2173             return CDSC_ERROR;
2174         }
2175         else
2176             dsc->media[count]->weight = w;
2177         }
2178         n+=i;
2179         count++;
2180     }
2181     }
2182     else if (IS_DSC(line, "%%DocumentData:")) {
2183     unsigned int n = continued ? 3 : 15;
2184     char *p = dsc->line + n;
2185         while (IS_WHITE(*p))
2186         p++;
2187     dsc->id = CDSC_DOCUMENTDATA;
2188     if (COMPARE(p, "Clean7Bit"))
2189         dsc->document_data = CDSC_CLEAN7BIT;
2190     else if (COMPARE(p, "Clean8Bit"))
2191         dsc->document_data = CDSC_CLEAN8BIT;
2192     else if (COMPARE(p, "Binary"))
2193         dsc->document_data = CDSC_BINARY;
2194     else
2195         dsc_unknown(dsc);
2196     }
2197     else if (IS_DSC(line, "%%Requirements:")) {
2198     dsc->id = CDSC_REQUIREMENTS;
2199     /* ignore */
2200     }
2201     else if (IS_DSC(line, "%%DocumentNeededFonts:")) {
2202     dsc->id = CDSC_DOCUMENTNEEDEDFONTS;
2203     /* ignore */
2204     }
2205     else if (IS_DSC(line, "%%DocumentSuppliedFonts:")) {
2206     dsc->id = CDSC_DOCUMENTSUPPLIEDFONTS;
2207     /* ignore */
2208     }
2209     else if (dsc->line[0] == '%' && IS_WHITE_OR_EOL(dsc->line[1])) {
2210     dsc->id = CDSC_OK;
2211     /* ignore */
2212     }
2213     else {
2214     dsc->id = CDSC_UNKNOWNDSC;
2215     dsc_unknown(dsc);
2216     }
2217 
2218     dsc->endcomments = DSC_END(dsc);
2219     return CDSC_OK;
2220 }
2221 
2222 
2223 dsc_private int 
2224 dsc_scan_preview(CDSC *dsc)
2225 {
2226     /* Preview section ends at */
2227     /*  %%EndPreview */
2228     /*  another section */
2229     /* Preview section must start with %%BeginPreview */
2230     char *line = dsc->line;
2231     dsc->id = CDSC_OK;
2232 
2233     if (dsc->scan_section == scan_pre_preview) {
2234     if (IS_BLANK(line))
2235         return CDSC_OK; /* ignore blank lines before preview */
2236     else if (IS_DSC(line, "%%BeginPreview")) {
2237         dsc->id = CDSC_BEGINPREVIEW;
2238         dsc->beginpreview = DSC_START(dsc);
2239         dsc->endpreview = DSC_END(dsc);
2240         dsc->scan_section = scan_preview;
2241         /* Don't mark the preview as EPSI if a DOS EPS header is present */
2242         if (dsc->preview == CDSC_NOPREVIEW)
2243         dsc->preview = CDSC_EPSI;
2244         return CDSC_OK;
2245     }
2246     else {
2247         dsc->scan_section = scan_pre_defaults;
2248         return CDSC_PROPAGATE;
2249     }
2250     }
2251 
2252     if (IS_DSC(line, "%%BeginPreview")) {
2253     /* ignore because we are in this section */
2254     }
2255     else if (dsc_is_section(line)) {
2256     dsc->endpreview = DSC_START(dsc);
2257     dsc->scan_section = scan_pre_defaults;
2258     return CDSC_PROPAGATE;
2259     }
2260     else if (IS_DSC(line, "%%EndPreview")) {
2261     dsc->id = CDSC_ENDPREVIEW;
2262     dsc->endpreview = DSC_END(dsc);
2263     dsc->scan_section = scan_pre_defaults;
2264     return CDSC_OK;
2265     }
2266     else if (line[0] == '%' && line[1] != '%') {
2267     /* Ordinary comments are OK */
2268     }
2269     else {
2270     dsc->id = CDSC_UNKNOWNDSC;
2271     /* DSC comments should not occur in preview */
2272     dsc_unknown(dsc);
2273     }
2274 
2275     dsc->endpreview = DSC_END(dsc);
2276     return CDSC_OK;
2277 }
2278 
2279 dsc_private int
2280 dsc_scan_defaults(CDSC *dsc)
2281 {
2282     /* Defaults section ends at */
2283     /*  %%EndDefaults */
2284     /*  another section */
2285     /* Defaults section must start with %%BeginDefaults */
2286     char *line = dsc->line;
2287     dsc->id = CDSC_OK;
2288 
2289     if (dsc->scan_section == scan_pre_defaults) {
2290     if (IS_BLANK(line))
2291         return CDSC_OK; /* ignore blank lines before defaults */
2292     else if (IS_DSC(line, "%%BeginDefaults")) {
2293         dsc->id = CDSC_BEGINDEFAULTS;
2294         dsc->begindefaults = DSC_START(dsc);
2295         dsc->enddefaults = DSC_END(dsc);
2296         dsc->scan_section = scan_defaults;
2297         return CDSC_OK;
2298     }
2299     else {
2300         dsc->scan_section = scan_pre_prolog;
2301         return CDSC_PROPAGATE;
2302     }
2303     }
2304 
2305     if (NOT_DSC_LINE(line)) {
2306     /* ignore */
2307     }
2308     else if (IS_DSC(line, "%%BeginPreview")) {
2309     /* ignore because we have already processed this section */
2310     }
2311     else if (IS_DSC(line, "%%BeginDefaults")) {
2312     /* ignore because we are in this section */
2313     }
2314     else if (dsc_is_section(line)) {
2315     dsc->enddefaults = DSC_START(dsc);
2316     dsc->scan_section = scan_pre_prolog;
2317     return CDSC_PROPAGATE;
2318     }
2319     else if (IS_DSC(line, "%%EndDefaults")) {
2320     dsc->id = CDSC_ENDDEFAULTS;
2321     dsc->enddefaults = DSC_END(dsc);
2322     dsc->scan_section = scan_pre_prolog;
2323     return CDSC_OK;
2324     }
2325     else if (IS_DSC(line, "%%PageMedia:")) {
2326     dsc->id = CDSC_PAGEMEDIA;
2327     dsc_parse_media(dsc, &dsc->page_media);
2328     }
2329     else if (IS_DSC(line, "%%PageOrientation:")) {
2330     dsc->id = CDSC_PAGEORIENTATION;
2331     /* This can override %%Orientation:  */
2332     if (dsc_parse_orientation(dsc, &(dsc->page_orientation), 18))
2333         return CDSC_ERROR;
2334     }
2335     else if (IS_DSC(line, "%%PageBoundingBox:")) {
2336     dsc->id = CDSC_PAGEBOUNDINGBOX;
2337     if (dsc_parse_bounding_box(dsc, &(dsc->page_bbox), 18))
2338         return CDSC_ERROR;
2339     }
2340     else if (IS_DSC(line, "%%ViewingOrientation:")) {
2341     dsc->id = CDSC_VIEWINGORIENTATION;
2342     if (dsc_parse_viewing_orientation(dsc, &dsc->viewing_orientation))
2343         return CDSC_ERROR;
2344     }
2345     else {
2346     dsc->id = CDSC_UNKNOWNDSC;
2347     /* All other DSC comments are unknown, but not an error */
2348     dsc_unknown(dsc);
2349     }
2350     dsc->enddefaults = DSC_END(dsc);
2351     return CDSC_OK;
2352 }
2353 
2354 /* CDSC_RESPONSE_OK and CDSC_RESPONSE_CANCEL mean ignore the 
2355  * mismatch (default) */
2356 dsc_private int
2357 dsc_check_match_prompt(CDSC *dsc, const char *str, int count)
2358 {
2359     if (count != 0) {
2360     char buf[MAXSTR+MAXSTR] = "";
2361     if (dsc->line_length < (unsigned int)(sizeof(buf)/2-1))  {
2362         strncpy(buf, dsc->line, dsc->line_length);
2363         buf[dsc->line_length] = '\0';
2364     }
2365     sprintf(buf+strlen(buf), "\n%%%%Begin%.40s: / %%%%End%.40s\n", str, str);
2366     return dsc_error(dsc, CDSC_MESSAGE_BEGIN_END, buf, strlen(buf));
2367     }
2368     return CDSC_RESPONSE_CANCEL;
2369 }
2370 
2371 dsc_private int
2372 dsc_check_match_type(CDSC *dsc, const char *str, int count)
2373 {
2374     if (dsc_check_match_prompt(dsc, str, count) == CDSC_RESPONSE_IGNORE_ALL)
2375     return CDSC_NOTDSC;
2376     return CDSC_OK;
2377 }
2378 
2379 /* complain if Begin/End blocks didn't match */
2380 /* return non-zero if we should ignore all DSC */
2381 dsc_private int
2382 dsc_check_match(CDSC *dsc)
2383 {
2384     int rc = 0;
2385     const char *font = "Font";
2386     const char *feature = "Feature";
2387     const char *resource = "Resource";
2388     const char *procset = "ProcSet";
2389 
2390     if (!rc)
2391     rc = dsc_check_match_type(dsc, font, dsc->begin_font_count);
2392     if (!rc)
2393     rc = dsc_check_match_type(dsc, feature, dsc->begin_feature_count);
2394     if (!rc)
2395     rc = dsc_check_match_type(dsc, resource, dsc->begin_resource_count);
2396     if (!rc)
2397     rc = dsc_check_match_type(dsc, procset, dsc->begin_procset_count);
2398 
2399     dsc->begin_font_count = 0;
2400     dsc->begin_feature_count = 0;
2401     dsc->begin_resource_count = 0;
2402     dsc->begin_procset_count = 0;
2403     return rc;
2404 }
2405 
2406 
2407 dsc_private int 
2408 dsc_scan_prolog(CDSC *dsc)
2409 {
2410     /* Prolog section ends at */
2411     /*  %%EndProlog */
2412     /*  another section */
2413     /* Prolog section may start with %%BeginProlog or non-dsc line */
2414     char *line = dsc->line;
2415     dsc->id = CDSC_OK;
2416 
2417     if (dsc->scan_section == scan_pre_prolog) {
2418         if (dsc_is_section(line) && (!IS_DSC(line, "%%BeginProlog"))) {
2419         dsc->scan_section = scan_pre_setup;
2420         return CDSC_PROPAGATE;
2421     }
2422     dsc->id = CDSC_BEGINPROLOG;
2423     dsc->beginprolog = DSC_START(dsc);
2424     dsc->endprolog = DSC_END(dsc);
2425     dsc->scan_section = scan_prolog;
2426     if (IS_DSC(line, "%%BeginProlog"))
2427         return CDSC_OK;
2428     }
2429    
2430     if (NOT_DSC_LINE(line)) {
2431     /* ignore */
2432     }
2433     else if (IS_DSC(line, "%%BeginPreview")) {
2434     /* ignore because we have already processed this section */
2435     }
2436     else if (IS_DSC(line, "%%BeginDefaults")) {
2437     /* ignore because we have already processed this section */
2438     }
2439     else if (IS_DSC(line, "%%BeginProlog")) {
2440     /* ignore because we are in this section */
2441     }
2442     else if (dsc_is_section(line)) {
2443     dsc->endprolog = DSC_START(dsc);
2444     dsc->scan_section = scan_pre_setup;
2445     if (dsc_check_match(dsc))
2446         return CDSC_NOTDSC;
2447     return CDSC_PROPAGATE;
2448     }
2449     else if (IS_DSC(line, "%%EndProlog")) {
2450     dsc->id = CDSC_ENDPROLOG;
2451     dsc->endprolog = DSC_END(dsc);
2452     dsc->scan_section = scan_pre_setup;
2453     if (dsc_check_match(dsc))
2454         return CDSC_NOTDSC;
2455     return CDSC_OK;
2456     }
2457     else if (IS_DSC(line, "%%BeginFont:")) {
2458     dsc->id = CDSC_BEGINFONT;
2459     /* ignore Begin/EndFont, apart form making sure */
2460     /* that they are matched. */
2461     dsc->begin_font_count++;
2462     }
2463     else if (IS_DSC(line, "%%EndFont")) {
2464     dsc->id = CDSC_ENDFONT;
2465     dsc->begin_font_count--;
2466     }
2467     else if (IS_DSC(line, "%%BeginFeature:")) {
2468     dsc->id = CDSC_BEGINFEATURE;
2469     /* ignore Begin/EndFeature, apart form making sure */
2470     /* that they are matched. */
2471     dsc->begin_feature_count++;
2472     }
2473     else if (IS_DSC(line, "%%EndFeature")) {
2474     dsc->id = CDSC_ENDFEATURE;
2475     dsc->begin_feature_count--;
2476     }
2477     else if (IS_DSC(line, "%%BeginResource:")) {
2478     dsc->id = CDSC_BEGINRESOURCE;
2479     /* ignore Begin/EndResource, apart form making sure */
2480     /* that they are matched. */
2481     dsc->begin_resource_count++;
2482     }
2483     else if (IS_DSC(line, "%%EndResource")) {
2484     dsc->id = CDSC_ENDRESOURCE;
2485     dsc->begin_resource_count--;
2486     }
2487     else if (IS_DSC(line, "%%BeginProcSet:")) {
2488     dsc->id = CDSC_BEGINPROCSET;
2489     /* ignore Begin/EndProcSet, apart form making sure */
2490     /* that they are matched. */
2491     dsc->begin_procset_count++;
2492     }
2493     else if (IS_DSC(line, "%%EndProcSet")) {
2494     dsc->id = CDSC_ENDPROCSET;
2495     dsc->begin_procset_count--;
2496     }
2497     else {
2498     /* All other DSC comments are unknown, but not an error */
2499     dsc->id = CDSC_UNKNOWNDSC;
2500     dsc_unknown(dsc);
2501     }
2502 
2503     dsc->endprolog = DSC_END(dsc);
2504     return CDSC_OK;
2505 }
2506 
2507 dsc_private int
2508 dsc_scan_setup(CDSC *dsc)
2509 {
2510     /* Setup section ends at */
2511     /*  %%EndSetup */
2512     /*  another section */
2513     /* Setup section must start with %%BeginSetup */
2514 
2515     char *line = dsc->line;
2516     dsc->id = CDSC_OK;
2517 
2518     if (dsc->scan_section == scan_pre_setup) {
2519     if (IS_BLANK(line))
2520         return CDSC_OK; /* ignore blank lines before setup */
2521     else if (IS_DSC(line, "%%BeginSetup")) {
2522         dsc->id = CDSC_BEGINSETUP;
2523         dsc->beginsetup = DSC_START(dsc);
2524         dsc->endsetup = DSC_END(dsc);
2525         dsc->scan_section = scan_setup;
2526         return CDSC_OK;
2527     }
2528     else {
2529         dsc->scan_section = scan_pre_pages;
2530         return CDSC_PROPAGATE;
2531     }
2532     }
2533 
2534     if (NOT_DSC_LINE(line)) {
2535     /* ignore */
2536     }
2537     else if (IS_DSC(line, "%%BeginPreview")) {
2538     /* ignore because we have already processed this section */
2539     }
2540     else if (IS_DSC(line, "%%BeginDefaults")) {
2541     /* ignore because we have already processed this section */
2542     }
2543     else if (IS_DSC(line, "%%BeginProlog")) {
2544     /* ignore because we have already processed this section */
2545     }
2546     else if (IS_DSC(line, "%%BeginSetup")) {
2547     /* ignore because we are in this section */
2548     }
2549     else if (dsc_is_section(line)) {
2550     dsc->endsetup = DSC_START(dsc);
2551     dsc->scan_section = scan_pre_pages;
2552     if (dsc_check_match(dsc))
2553         return CDSC_NOTDSC;
2554     return CDSC_PROPAGATE;
2555     }
2556     else if (IS_DSC(line, "%%EndSetup")) {
2557     dsc->id = CDSC_ENDSETUP;
2558     dsc->endsetup = DSC_END(dsc);
2559     dsc->scan_section = scan_pre_pages;
2560     if (dsc_check_match(dsc))
2561         return CDSC_NOTDSC;
2562     return CDSC_OK;
2563     }
2564     else if (IS_DSC(line, "%%BeginFeature:")) {
2565     dsc->id = CDSC_BEGINFEATURE;
2566     /* ignore Begin/EndFeature, apart form making sure */
2567     /* that they are matched. */
2568     dsc->begin_feature_count++;
2569     }
2570     else if (IS_DSC(line, "%%EndFeature")) {
2571     dsc->id = CDSC_ENDFEATURE;
2572     dsc->begin_feature_count--;
2573     }
2574     else if (IS_DSC(line, "%%Feature:")) {
2575     dsc->id = CDSC_FEATURE;
2576     /* ignore */
2577     }
2578     else if (IS_DSC(line, "%%BeginResource:")) {
2579     dsc->id = CDSC_BEGINRESOURCE;
2580     /* ignore Begin/EndResource, apart form making sure */
2581     /* that they are matched. */
2582     dsc->begin_resource_count++;
2583     }
2584     else if (IS_DSC(line, "%%EndResource")) {
2585     dsc->id = CDSC_ENDRESOURCE;
2586     dsc->begin_resource_count--;
2587     }
2588     else if (IS_DSC(line, "%%PaperColor:")) {
2589     dsc->id = CDSC_PAPERCOLOR;
2590     /* ignore */
2591     }
2592     else if (IS_DSC(line, "%%PaperForm:")) {
2593     dsc->id = CDSC_PAPERFORM;
2594     /* ignore */
2595     }
2596     else if (IS_DSC(line, "%%PaperWeight:")) {
2597     dsc->id = CDSC_PAPERWEIGHT;
2598     /* ignore */
2599     }
2600     else if (IS_DSC(line, "%%PaperSize:")) {
2601     /* DSC 2.1 */
2602         GSBOOL found_media = FALSE;
2603     int i;
2604     int n = 12;
2605     char buf[MAXSTR];
2606     buf[0] = '\0';
2607     dsc->id = CDSC_PAPERSIZE;
2608     dsc_copy_string(buf, sizeof(buf)-1, dsc->line+n, dsc->line_length-n, 
2609         NULL);
2610     for (i=0; i<(int)dsc->media_count; i++) {
2611         if (dsc->media[i] && dsc->media[i]->name && 
2612         (dsc_stricmp(buf, dsc->media[i]->name)==0)) {
2613         dsc->page_media = dsc->media[i];
2614         found_media = TRUE;
2615         break;
2616         }
2617     }
2618     if (!found_media) {
2619         /* It didn't match %%DocumentPaperSizes: */
2620         /* Try our known media */
2621         const CDSCMEDIA *m = dsc_known_media;
2622         while (m->name) {
2623         if (dsc_stricmp(buf, m->name)==0) {
2624             dsc->page_media = m;
2625             break;
2626         }
2627         m++;
2628         }
2629         if (m->name == NULL)
2630         dsc_unknown(dsc);
2631     }
2632     }
2633     else {
2634     /* All other DSC comments are unknown, but not an error */
2635     dsc->id = CDSC_UNKNOWNDSC;
2636     dsc_unknown(dsc);
2637     }
2638 
2639     dsc->endsetup = DSC_END(dsc);
2640     return CDSC_OK;
2641 }
2642 
2643 dsc_private int 
2644 dsc_scan_page(CDSC *dsc)
2645 {
2646     /* Page section ends at */
2647     /*  %%Page */
2648     /*  %%Trailer */
2649     /*  %%EOF */
2650     char *line = dsc->line;
2651     dsc->id = CDSC_OK;
2652 
2653     if (dsc->scan_section == scan_pre_pages) {
2654     if (IS_DSC(line, "%%Page:")) {
2655         dsc->scan_section = scan_pages;
2656         /* fall through */
2657     }
2658     else  {
2659         /* %%Page: didn't follow %%EndSetup
2660          * Keep reading until reach %%Page or %%Trailer
2661          * and add it to previous section.
2662          */
2663         unsigned long *last;
2664         if (dsc->endsetup != 0)
2665         last = &dsc->endsetup;
2666         else if (dsc->endprolog != 0)
2667         last = &dsc->endprolog;
2668         else if (dsc->enddefaults != 0)
2669         last = &dsc->enddefaults;
2670         else if (dsc->endpreview != 0)
2671         last = &dsc->endpreview;
2672         else if (dsc->endcomments != 0)
2673         last = &dsc->endcomments;
2674         else
2675         last = &dsc->begincomments;
2676         *last = DSC_START(dsc);
2677         if (IS_DSC(line, "%%Trailer") || IS_DSC(line, "%%EOF")) {
2678         dsc->scan_section = scan_pre_trailer;
2679         return CDSC_PROPAGATE;
2680         }
2681         return CDSC_OK;
2682     }
2683     }
2684 
2685     if (NOT_DSC_LINE(line)) {
2686     /* ignore */
2687     }
2688     else if (IS_DSC(line, "%%Page:")) {
2689     dsc->id = CDSC_PAGE;
2690     if (dsc->page_count) {
2691         dsc->page[dsc->page_count-1].end = DSC_START(dsc);
2692         if (dsc_check_match(dsc))
2693         return CDSC_NOTDSC;
2694     }
2695 
2696     if (dsc_parse_page(dsc) != 0)
2697         return CDSC_ERROR;
2698 
2699     return CDSC_OK;
2700     }
2701     else if (IS_DSC(line, "%%BeginPreview")) {
2702     /* ignore because we have already processed this section */
2703     }
2704     else if (IS_DSC(line, "%%BeginDefaults")) {
2705     /* ignore because we have already processed this section */
2706     }
2707     else if (IS_DSC(line, "%%BeginProlog")) {
2708     /* ignore because we have already processed this section */
2709     }
2710     else if (IS_DSC(line, "%%BeginSetup")) {
2711     /* ignore because we have already processed this section */
2712     }
2713     else if (dsc_is_section(line)) {
2714     if (IS_DSC(line, "%%Trailer")) {
2715         dsc->page[dsc->page_count-1].end = DSC_START(dsc);
2716         if (dsc->file_length) {
2717         if ((!dsc->doseps && 
2718             ((DSC_END(dsc) + 32768) < dsc->file_length)) ||
2719              ((dsc->doseps) && 
2720             ((DSC_END(dsc) + 32768) < dsc->doseps_end))) {
2721             int rc = dsc_error(dsc, CDSC_MESSAGE_EARLY_TRAILER, 
2722             dsc->line, dsc->line_length);
2723             switch (rc) {
2724             case CDSC_RESPONSE_OK:
2725                 /* ignore early trailer */
2726                 break;
2727             case CDSC_RESPONSE_CANCEL:
2728                 /* this is the trailer */
2729                 dsc->scan_section = scan_pre_trailer;
2730                 if (dsc_check_match(dsc))
2731                 return CDSC_NOTDSC;
2732                 return CDSC_PROPAGATE;
2733             case CDSC_RESPONSE_IGNORE_ALL:
2734                 return CDSC_NOTDSC;
2735             }
2736         }
2737         else {
2738             dsc->scan_section = scan_pre_trailer;
2739             if (dsc_check_match(dsc))
2740             return CDSC_NOTDSC;
2741             return CDSC_PROPAGATE;
2742         }
2743         }
2744         else {
2745         dsc->scan_section = scan_pre_trailer;
2746         if (dsc_check_match(dsc))
2747             return CDSC_NOTDSC;
2748         return CDSC_PROPAGATE;
2749         }
2750     }
2751     else if (IS_DSC(line, "%%EOF")) {
2752         dsc->page[dsc->page_count-1].end = DSC_START(dsc);
2753         if (dsc->file_length) {
2754         if ((DSC_END(dsc)+100 < dsc->file_length) ||
2755             (dsc->doseps && (DSC_END(dsc) + 100 < dsc->doseps_end))) {
2756             int rc = dsc_error(dsc, CDSC_MESSAGE_EARLY_EOF, 
2757             dsc->line, dsc->line_length);
2758             switch (rc) {
2759             case CDSC_RESPONSE_OK:
2760                 /* %%EOF is wrong, ignore it */
2761                 break;
2762             case CDSC_RESPONSE_CANCEL:
2763                 /* %%EOF is correct */
2764                 dsc->scan_section = scan_eof;
2765                 dsc->eof = TRUE;
2766                 if (dsc_check_match(dsc))
2767                 return CDSC_NOTDSC;
2768                 return CDSC_PROPAGATE;
2769             case CDSC_RESPONSE_IGNORE_ALL:
2770                 return CDSC_NOTDSC;
2771             }
2772         }
2773         }
2774         else {
2775         /* ignore it */
2776         if (dsc_check_match(dsc))
2777             return CDSC_NOTDSC;
2778         return CDSC_OK;
2779         }
2780     }
2781     else {
2782         /* Section comment, probably from a badly */
2783         /* encapsulated EPS file. */
2784         int rc = dsc_error(dsc, CDSC_MESSAGE_BAD_SECTION, 
2785             dsc->line, dsc->line_length);
2786         if (rc == CDSC_RESPONSE_IGNORE_ALL)
2787         return CDSC_NOTDSC;
2788     }
2789     }
2790     else if (IS_DSC(line, "%%PageTrailer")) {
2791     dsc->id = CDSC_PAGETRAILER;
2792     /* ignore */
2793     }
2794     else if (IS_DSC(line, "%%BeginPageSetup")) {
2795     dsc->id = CDSC_BEGINPAGESETUP;
2796     /* ignore */
2797     }
2798     else if (IS_DSC(line, "%%EndPageSetup")) {
2799     dsc->id = CDSC_ENDPAGESETUP;
2800     /* ignore */
2801     }
2802     else if (IS_DSC(line, "%%PageMedia:")) {
2803     dsc->id = CDSC_PAGEMEDIA;
2804     dsc_parse_media(dsc, &(dsc->page[dsc->page_count-1].media));
2805     }
2806     else if (IS_DSC(line, "%%PaperColor:")) {
2807     dsc->id = CDSC_PAPERCOLOR;
2808     /* ignore */
2809     }
2810     else if (IS_DSC(line, "%%PaperForm:")) {
2811     dsc->id = CDSC_PAPERFORM;
2812     /* ignore */
2813     }
2814     else if (IS_DSC(line, "%%PaperWeight:")) {
2815     dsc->id = CDSC_PAPERWEIGHT;
2816     /* ignore */
2817     }
2818     else if (IS_DSC(line, "%%PaperSize:")) {
2819     /* DSC 2.1 */
2820         GSBOOL found_media = FALSE;
2821     int i;
2822     int n = 12;
2823     char buf[MAXSTR];
2824     buf[0] = '\0';
2825     dsc_copy_string(buf, sizeof(buf)-1, dsc->line+n, 
2826         dsc->line_length-n, NULL);
2827     for (i=0; i<(int)dsc->media_count; i++) {
2828         if (dsc->media[i] && dsc->media[i]->name && 
2829         (dsc_stricmp(buf, dsc->media[i]->name)==0)) {
2830         dsc->page_media = dsc->media[i];
2831         found_media = TRUE;
2832         break;
2833         }
2834     }
2835     if (!found_media) {
2836         /* It didn't match %%DocumentPaperSizes: */
2837         /* Try our known media */
2838         const CDSCMEDIA *m = dsc_known_media;
2839         while (m->name) {
2840         if (dsc_stricmp(buf, m->name)==0) {
2841             dsc->page[dsc->page_count-1].media = m;
2842             break;
2843         }
2844         m++;
2845         }
2846         if (m->name == NULL)
2847         dsc_unknown(dsc);
2848     }
2849     }
2850     else if (IS_DSC(line, "%%PageOrientation:")) {
2851     dsc->id = CDSC_PAGEORIENTATION;
2852     if (dsc_parse_orientation(dsc, 
2853         &(dsc->page[dsc->page_count-1].orientation) ,18))
2854         return CDSC_NOTDSC;
2855     }
2856     else if (IS_DSC(line, "%%PageBoundingBox:")) {
2857     dsc->id = CDSC_PAGEBOUNDINGBOX;
2858     if (dsc_parse_bounding_box(dsc, &dsc->page[dsc->page_count-1].bbox, 18))
2859         return CDSC_NOTDSC;
2860     }
2861     else if (IS_DSC(line, "%%ViewingOrientation:")) {
2862     dsc->id = CDSC_VIEWINGORIENTATION;
2863     if (dsc_parse_viewing_orientation(dsc, 
2864         &dsc->page[dsc->page_count-1].viewing_orientation))
2865         return CDSC_ERROR;
2866     }
2867     else if (IS_DSC(line, "%%BeginFont:")) {
2868     dsc->id = CDSC_BEGINFONT;
2869     /* ignore Begin/EndFont, apart form making sure */
2870     /* that they are matched. */
2871     dsc->begin_font_count++;
2872     }
2873     else if (IS_DSC(line, "%%EndFont")) {
2874     dsc->id = CDSC_BEGINFONT;
2875     dsc->begin_font_count--;
2876     }
2877     else if (IS_DSC(line, "%%BeginFeature:")) {
2878     dsc->id = CDSC_BEGINFEATURE;
2879     /* ignore Begin/EndFeature, apart form making sure */
2880     /* that they are matched. */
2881     dsc->begin_feature_count++;
2882     }
2883     else if (IS_DSC(line, "%%EndFeature")) {
2884     dsc->id = CDSC_ENDFEATURE;
2885     dsc->begin_feature_count--;
2886     }
2887     else if (IS_DSC(line, "%%BeginResource:")) {
2888     dsc->id = CDSC_BEGINRESOURCE;
2889     /* ignore Begin/EndResource, apart form making sure */
2890     /* that they are matched. */
2891     dsc->begin_resource_count++;
2892     }
2893     else if (IS_DSC(line, "%%EndResource")) {
2894     dsc->id = CDSC_ENDRESOURCE;
2895     dsc->begin_resource_count--;
2896     }
2897     else if (IS_DSC(line, "%%BeginProcSet:")) {
2898     dsc->id = CDSC_BEGINPROCSET;
2899     /* ignore Begin/EndProcSet, apart form making sure */
2900     /* that they are matched. */
2901     dsc->begin_procset_count++;
2902     }
2903     else if (IS_DSC(line, "%%EndProcSet")) {
2904     dsc->id = CDSC_ENDPROCSET;
2905     dsc->begin_procset_count--;
2906     }
2907     else if (IS_DSC(line, "%%IncludeFont:")) {
2908     dsc->id = CDSC_INCLUDEFONT;
2909     /* ignore */
2910     }
2911     else {
2912     /* All other DSC comments are unknown, but not an error */
2913     dsc->id = CDSC_UNKNOWNDSC;
2914     dsc_unknown(dsc);
2915     }
2916 
2917     dsc->page[dsc->page_count-1].end = DSC_END(dsc);
2918     return CDSC_OK;
2919 }
2920 
2921 /* Valid Trailer comments are
2922  * %%Trailer
2923  * %%EOF
2924  * or the following deferred with (atend)
2925  * %%BoundingBox:
2926  * %%DocumentCustomColors:
2927  * %%DocumentFiles:
2928  * %%DocumentFonts:
2929  * %%DocumentNeededFiles:
2930  * %%DocumentNeededFonts:
2931  * %%DocumentNeededProcSets:
2932  * %%DocumentNeededResources:
2933  * %%DocumentProcSets:
2934  * %%DocumentProcessColors:
2935  * %%DocumentSuppliedFiles:
2936  * %%DocumentSuppliedFonts:
2937  * %%DocumentSuppliedProcSets: 
2938  * %%DocumentSuppliedResources: 
2939  * %%Orientation: 
2940  * %%Pages: 
2941  * %%PageOrder: 
2942  *
2943  * Our supported subset is
2944  * %%Trailer
2945  * %%EOF
2946  * %%BoundingBox:
2947  * %%Orientation: 
2948  * %%Pages: 
2949  * %%PageOrder: 
2950  * In addition to these, we support
2951  * %%DocumentMedia:
2952  * 
2953  * A %%PageTrailer can have the following:
2954  * %%PageBoundingBox: 
2955  * %%PageCustomColors: 
2956  * %%PageFiles: 
2957  * %%PageFonts: 
2958  * %%PageOrientation: 
2959  * %%PageProcessColors: 
2960  * %%PageResources: 
2961  */
2962 
2963 dsc_private int
2964 dsc_scan_trailer(CDSC *dsc)
2965 {
2966     /* Trailer section start at */
2967     /*  %%Trailer */
2968     /* and ends at */
2969     /*  %%EOF */
2970     char *line = dsc->line;
2971     GSBOOL continued = FALSE;
2972     dsc->id = CDSC_OK;
2973 
2974     if (dsc->scan_section == scan_pre_trailer) {
2975     if (IS_DSC(line, "%%Trailer")) {
2976         dsc->id = CDSC_TRAILER;
2977         dsc->begintrailer = DSC_START(dsc);
2978         dsc->endtrailer = DSC_END(dsc);
2979         dsc->scan_section = scan_trailer;
2980         return CDSC_OK;
2981     }
2982     else if (IS_DSC(line, "%%EOF")) {
2983         dsc->id = CDSC_EOF;
2984         dsc->begintrailer = DSC_START(dsc);
2985         dsc->endtrailer = DSC_END(dsc);
2986         dsc->scan_section = scan_trailer;
2987         /* Continue, in case we found %%EOF in an embedded document */
2988         return CDSC_OK;
2989     }
2990     else {
2991         /* %%Page: didn't follow %%EndSetup
2992          * Keep reading until reach %%Page or %%Trailer
2993          * and add it to setup section
2994          */
2995         /* append to previous section */
2996         if (dsc->beginsetup)
2997         dsc->endsetup = DSC_END(dsc);
2998         else if (dsc->beginprolog)
2999         dsc->endprolog = DSC_END(dsc);
3000         else {
3001         /* horribly confused */
3002         }
3003         return CDSC_OK;
3004     }
3005     }
3006 
3007     /* Handle continuation lines.
3008      * See comment above about our restrictive processing of 
3009      * continuation lines
3010      */
3011     if (IS_DSC(line, "%%+")) {
3012     line = dsc->last_line;
3013     continued = TRUE;
3014     }
3015     else
3016     dsc_save_line(dsc);
3017 
3018     if (NOT_DSC_LINE(line)) {
3019     /* ignore */
3020     }
3021     else if (IS_DSC(dsc->line, "%%EOF")) {
3022     /* Keep scanning, in case we have a false trailer */
3023     dsc->id = CDSC_EOF;
3024     }
3025     else if (IS_DSC(dsc->line, "%%Trailer")) {
3026     /* Cope with no pages with code after setup and before trailer. */
3027     /* Last trailer is the correct one. */
3028     dsc->id = CDSC_TRAILER;
3029     dsc->begintrailer = DSC_START(dsc);
3030     }
3031     else if (IS_DSC(line, "%%Pages:")) {
3032     dsc->id = CDSC_PAGES;
3033     if (dsc_parse_pages(dsc) != 0)
3034            return CDSC_ERROR;
3035     }
3036     else if (IS_DSC(line, "%%BoundingBox:")) {
3037     dsc->id = CDSC_BOUNDINGBOX;
3038     if (dsc_parse_bounding_box(dsc, &(dsc->bbox), continued ? 3 : 14))
3039         return CDSC_ERROR;
3040     }
3041     else if (IS_DSC(line, "%%HiResBoundingBox:")) {
3042     dsc->id = CDSC_HIRESBOUNDINGBOX;
3043     if (dsc_parse_float_bounding_box(dsc, &(dsc->hires_bbox), 
3044         continued ? 3 : 19))
3045         return CDSC_ERROR;
3046     }
3047     else if (IS_DSC(line, "%%CropBox:")) {
3048     dsc->id = CDSC_CROPBOX;
3049     if (dsc_parse_float_bounding_box(dsc, &(dsc->crop_box), 
3050         continued ? 3 : 10))
3051         return CDSC_ERROR;
3052     }
3053     else if (IS_DSC(line, "%%Orientation:")) {
3054     dsc->id = CDSC_ORIENTATION;
3055     if (dsc_parse_orientation(dsc, &(dsc->page_orientation), continued ? 3 : 14))
3056         return CDSC_ERROR;
3057     }
3058     else if (IS_DSC(line, "%%PageOrder:")) {
3059     dsc->id = CDSC_PAGEORDER;
3060     if (dsc_parse_order(dsc))
3061         return CDSC_ERROR;
3062     }
3063     else if (IS_DSC(line, "%%DocumentMedia:")) {
3064     dsc->id = CDSC_DOCUMENTMEDIA;
3065     if (dsc_parse_document_media(dsc))
3066         return CDSC_ERROR;
3067     }
3068     else if (IS_DSC(dsc->line, "%%Page:")) {
3069     /* This should not occur in the trailer, but we might see 
3070      * this if a document has been incorrectly embedded.
3071      */
3072     int rc = dsc_error(dsc, CDSC_MESSAGE_PAGE_IN_TRAILER, 
3073         dsc->line, dsc->line_length);
3074     switch (rc) {
3075         case CDSC_RESPONSE_OK:
3076         /* Assume that we are really in the previous */
3077         /* page, not the trailer */
3078         dsc->scan_section = scan_pre_pages;
3079         if (dsc->page_count)
3080             dsc->page[dsc->page_count-1].end = DSC_START(dsc);
3081         return CDSC_PROPAGATE;  /* try again */
3082         case CDSC_RESPONSE_CANCEL:
3083         /* ignore pages in trailer */
3084         break;
3085         case CDSC_RESPONSE_IGNORE_ALL:
3086         return CDSC_NOTDSC;
3087     }
3088     }
3089     else if (IS_DSC(line, "%%DocumentNeededFonts:")) {
3090     dsc->id = CDSC_DOCUMENTNEEDEDFONTS;
3091     /* ignore */
3092     }
3093     else if (IS_DSC(line, "%%DocumentSuppliedFonts:")) {
3094     dsc->id = CDSC_DOCUMENTSUPPLIEDFONTS;
3095     /* ignore */
3096     }
3097     else {
3098     /* All other DSC comments are unknown, but not an error */
3099     dsc->id = CDSC_UNKNOWNDSC;
3100     dsc_unknown(dsc);
3101     }
3102 
3103     dsc->endtrailer = DSC_END(dsc);
3104     return CDSC_OK;
3105 }
3106 
3107 
3108 dsc_private char *
3109 dsc_alloc_string(CDSC *dsc, const char *str, int len)
3110 {
3111     char *p;
3112     if (dsc->string_head == NULL) {
3113     dsc->string_head = (CDSCSTRING *)dsc_memalloc(dsc, sizeof(CDSCSTRING));
3114     if (dsc->string_head == NULL)
3115         return NULL;    /* no memory */
3116     dsc->string = dsc->string_head;
3117     dsc->string->next = NULL;
3118     dsc->string->data = (char *)dsc_memalloc(dsc, CDSC_STRING_CHUNK);
3119     if (dsc->string->data == NULL) {
3120         dsc_reset(dsc);
3121         return NULL;    /* no memory */
3122     }
3123     dsc->string->index = 0;
3124     dsc->string->length = CDSC_STRING_CHUNK;
3125     }
3126     if ( dsc->string->index + len + 1 > dsc->string->length) {
3127     /* allocate another string block */
3128     CDSCSTRING *newstring = (CDSCSTRING *)dsc_memalloc(dsc, sizeof(CDSCSTRING));
3129     if (newstring == NULL) {
3130         dsc_debug_print(dsc, "Out of memory\n");
3131         return NULL;
3132     }
3133         newstring->next = NULL;
3134     newstring->length = 0;
3135     newstring->index = 0;
3136     newstring->data = (char *)dsc_memalloc(dsc, CDSC_STRING_CHUNK);
3137     if (newstring->data == NULL) {
3138         dsc_memfree(dsc, newstring);
3139         dsc_debug_print(dsc, "Out of memory\n");
3140         return NULL;    /* no memory */
3141     }
3142     newstring->length = CDSC_STRING_CHUNK;
3143     dsc->string->next = newstring;
3144     dsc->string = newstring;
3145     }
3146     if ( dsc->string->index + len + 1 > dsc->string->length)
3147     return NULL;    /* failed */
3148     p = dsc->string->data + dsc->string->index;
3149     memcpy(p, str, len);
3150     *(p+len) = '\0';
3151     dsc->string->index += len + 1;
3152     return p;
3153 }
3154 
3155 /* store line, ignoring leading spaces */
3156 dsc_private char *
3157 dsc_add_line(CDSC *dsc, const char *line, unsigned int len)
3158 {
3159     char *newline;
3160     unsigned int i;
3161     while (len && (IS_WHITE(*line))) {
3162     len--;
3163     line++;
3164     }
3165     newline = dsc_alloc_string(dsc, line, len);
3166     if (newline == NULL)
3167     return NULL;
3168 
3169     for (i=0; i<len; i++) {
3170     if (newline[i] == '\r') {
3171         newline[i]='\0';
3172         break;
3173     }
3174     if (newline[i] == '\n') {
3175         newline[i]='\0';
3176         break;
3177     }
3178     }
3179     return newline;
3180 }
3181 
3182 
3183 /* Copy string on line to new allocated string str */
3184 /* String is always null terminated */
3185 /* String is no longer than len */
3186 /* Return pointer to string  */
3187 /* Store number of used characters from line */
3188 /* Don't copy enclosing () */
3189 dsc_private char *
3190 dsc_copy_string(char *str, unsigned int slen, char *line, 
3191     unsigned int len, unsigned int *offset)
3192 {
3193     int quoted = FALSE;
3194     int instring=0;
3195     unsigned int newlength = 0;
3196     unsigned int i = 0;
3197     unsigned char ch;
3198     if (len > slen)
3199     len = slen-1;
3200     while ( (i<len) && IS_WHITE(line[i]))
3201     i++;    /* skip leading spaces */
3202     if (line[i]=='(') {
3203     quoted = TRUE;
3204     instring++;
3205     i++; /* don't copy outside () */
3206     }
3207     while (i < len) {
3208     str[newlength] = ch = line[i];
3209     i++;
3210     if (quoted) {
3211         if (ch == '(')
3212             instring++;
3213         if (ch == ')')
3214             instring--;
3215         if (instring==0)
3216             break;
3217     }
3218     else if (ch == ' ')
3219         break;
3220 
3221     if (ch == '\r')
3222         break;
3223     if (ch == '\n')
3224         break;
3225     else if ( (ch == '\\') && (i+1 < len) ) {
3226         ch = line[i];
3227         if ((ch >= '0') && (ch <= '9')) {
3228         /* octal coded character */
3229         int j = 3;
3230         ch = 0;
3231         while (j && (i < len) && line[i]>='0' && line[i]<='7') {
3232             ch = (unsigned char)((ch<<3) + (line[i]-'0'));
3233             i++;
3234             j--;
3235         }
3236         str[newlength] = ch;
3237         }
3238         else if (ch == '(') {
3239         str[newlength] = ch;
3240         i++;
3241         }
3242         else if (ch == ')') {
3243         str[newlength] = ch;
3244         i++;
3245         }
3246         else if (ch == 'b') {
3247         str[newlength] = '\b';
3248         i++;
3249         }
3250         else if (ch == 'f') {
3251         str[newlength] = '\b';
3252         i++;
3253         }
3254         else if (ch == 'n') {
3255         str[newlength] = '\n';
3256         i++;
3257         }
3258         else if (ch == 'r') {
3259         str[newlength] = '\r';
3260         i++;
3261         }
3262         else if (ch == 't') {
3263         str[newlength] = '\t';
3264         i++;
3265         }
3266         else if (ch == '\\') {
3267         str[newlength] = '\\';
3268         i++;
3269         }
3270     }
3271     newlength++;
3272     }
3273     str[newlength] = '\0';
3274     if (offset != (unsigned int *)NULL)
3275         *offset = i;
3276     return str;
3277 }
3278 
3279 dsc_private int 
3280 dsc_get_int(const char *line, unsigned int len, unsigned int *offset)
3281 {
3282     char newline[MAXSTR];
3283     int newlength = 0;
3284     unsigned int i = 0;
3285     unsigned char ch;
3286 
3287     len = min(len, sizeof(newline)-1);
3288     while ((i<len) && IS_WHITE(line[i]))
3289     i++;    /* skip leading spaces */
3290     while (i < len) {
3291     newline[newlength] = ch = line[i];
3292     if (!(isdigit(ch) || (ch=='-') || (ch=='+')))
3293         break;  /* not part of an integer number */
3294     i++;
3295     newlength++;
3296     }
3297     while ((i<len) && IS_WHITE(line[i]))
3298     i++;    /* skip trailing spaces */
3299     newline[newlength] = '\0';
3300     if (offset != (unsigned int *)NULL)
3301         *offset = i;
3302     return atoi(newline);
3303 }
3304 
3305 dsc_private float 
3306 dsc_get_real(const char *line, unsigned int len, unsigned int *offset)
3307 {
3308     char newline[MAXSTR];
3309     int newlength = 0;
3310     unsigned int i = 0;
3311     unsigned char ch;
3312 
3313     len = min(len, sizeof(newline)-1);
3314     while ((i<len) && IS_WHITE(line[i]))
3315     i++;    /* skip leading spaces */
3316     while (i < len) {
3317     newline[newlength] = ch = line[i];
3318     if (!(isdigit(ch) || (ch=='.') || (ch=='-') || (ch=='+') 
3319         || (ch=='e') || (ch=='E')))
3320         break;  /* not part of a real number */
3321     i++;
3322     newlength++;
3323     }
3324     while ((i<len) && IS_WHITE(line[i]))
3325     i++;    /* skip trailing spaces */
3326 
3327     newline[newlength] = '\0';
3328 
3329     if (offset != (unsigned int *)NULL)
3330         *offset = i;
3331     return (float)atof(newline);
3332 }
3333 
3334 dsc_private int
3335 dsc_stricmp(const char *s, const char *t)
3336 {
3337     while (toupper(*s) == toupper(*t)) {
3338     if (*s == '\0')
3339         return 0;
3340     s++;
3341     t++; 
3342     }
3343     return (toupper(*s) - toupper(*t));
3344 }
3345 
3346 
3347 dsc_private int
3348 dsc_parse_page(CDSC *dsc)
3349 {
3350     char *p;
3351     unsigned int i;
3352     char page_label[MAXSTR];
3353     char *pl;
3354     int page_ordinal;
3355     int page_number;
3356 
3357     p = dsc->line + 7;
3358     pl = dsc_copy_string(page_label, sizeof(page_label)-1, p, dsc->line_length-7, &i);
3359     if (pl == NULL)
3360     return CDSC_ERROR;
3361     p += i;
3362     page_ordinal = atoi(p);
3363 
3364     if ( (page_ordinal == 0) || (strlen(page_label) == 0) ||
3365        (dsc->page_count && 
3366         (page_ordinal != dsc->page[dsc->page_count-1].ordinal+1)) ) {
3367     int rc = dsc_error(dsc, CDSC_MESSAGE_PAGE_ORDINAL, dsc->line, 
3368         dsc->line_length);
3369     switch (rc) {
3370         case CDSC_RESPONSE_OK:
3371         /* ignore this page */
3372         return CDSC_OK;
3373         case CDSC_RESPONSE_CANCEL:
3374         /* accept the page */
3375         break;
3376         case CDSC_RESPONSE_IGNORE_ALL:
3377         return CDSC_NOTDSC;
3378     }
3379     }
3380 
3381     page_number = dsc->page_count;
3382     dsc_add_page(dsc, page_ordinal, page_label);
3383     dsc->page[page_number].begin = DSC_START(dsc);
3384     dsc->page[page_number].end = DSC_START(dsc);
3385 
3386     if (dsc->page[page_number].label == NULL)
3387     return CDSC_ERROR;  /* no memory */
3388     
3389     return CDSC_OK;
3390 }
3391 
3392 
3393 
3394 /* DSC error reporting */
3395 
3396 void 
3397 dsc_debug_print(CDSC *dsc, const char *str)
3398 {
3399     if (dsc->debug_print_fn)
3400     dsc->debug_print_fn(dsc->caller_data, str);
3401 }
3402 
3403 
3404 /* Display a message about a problem with the DSC comments.
3405  * 
3406  * explanation = an index to to a multiline explanation in dsc_message[]
3407  * line = pointer to the offending DSC line (if any)
3408  * return code = 
3409  *   CDSC_RESPONSE_OK          DSC was wrong, make a guess about what 
3410  *                             was really meant.
3411  *   CDSC_RESPONSE_CANCEL      Assume DSC was correct, ignore if it 
3412  *                             is misplaced.
3413  *   CDSC_RESPONSE_IGNORE_ALL  Ignore all DSC.
3414  */
3415 /* Silent operation.  Don't display errors. */
3416 dsc_private int 
3417 dsc_error(CDSC *dsc, unsigned int explanation, 
3418     char *line, unsigned int line_len)
3419 {
3420     /* if error function provided, use it */
3421     if (dsc->dsc_error_fn)
3422     return dsc->dsc_error_fn(dsc->caller_data, dsc, 
3423         explanation, line, line_len);
3424 
3425     /* treat DSC as being correct */
3426     return CDSC_RESPONSE_CANCEL;
3427 }
3428 
3429 
3430 // vim:sw=4:sts=4:ts=8:noet