"Fossies" - the Fresh Open Source Software Archive

Member "epstool-3.08/src/dscparse.c" (10 Jun 2005, 124488 Bytes) of package /linux/misc/old/ghost/ghostgum/epstool-3.08-os2.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

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