/* Copyright (C) 2000-2003, Ghostgum Software Pty Ltd. All rights reserved. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA, 02111-1307. */ /*$Id: dscparse.c,v 1.7.2.1.2.2 2003/01/28 11:44:44 ghostgum Exp $ */ /* * This is a DSC parser, based on the DSC 3.0 spec, * with a few DSC 2.1 additions for page size. * * Current limitations: * %%+ may be used after any comment in the comment or trailer, * but is currently only supported by * %%DocumentMedia * * DSC 2.1 additions (discontinued in DSC 3.0): * %%DocumentPaperColors: * %%DocumentPaperForms: * %%DocumentPaperSizes: * %%DocumentPaperWeights: * %%PaperColor: (ignored) * %%PaperForm: (ignored) * %%PaperSize: * %%PaperWeight: (ignored) * * Other additions for defaults or page section % %%ViewingOrientation: xx xy yx yy */ #include /* for sprintf(), not file I/O */ #include #include #include #define MAXSTR 256 #include "dscparse.h" /* Macros for comparing string literals * For maximum speed, the length of the second macro argument is * computed at compile time. * THE SECOND MACRO ARGUMENT MUST BE A STRING LITERAL. */ #define COMPARE(p,str) (strncmp((const char *)(p), (str), sizeof(str)-1)==0) #define IS_DSC(line, str) (COMPARE((line), (str))) /* Macros for comparing the first one or two characters */ #define IS_WHITE(ch) (((ch)==' ') || ((ch)=='\t')) #define IS_EOL(ch) (((ch)=='\r') || ((ch)=='\n')) #define IS_WHITE_OR_EOL(ch) (IS_WHITE(ch) || IS_EOL(ch)) #define IS_BLANK(str) (IS_EOL(str[0])) #define NOT_DSC_LINE(str) (((str)[0]!='%') || ((str)[1]!='%')) /* Macros for document offset to start and end of line */ #define DSC_START(dsc) ((dsc)->data_offset + (dsc)->data_index - (dsc)->line_length) #define DSC_END(dsc) ((dsc)->data_offset + (dsc)->data_index) /* dsc_scan_SECTION() functions return one of * CDSC_ERROR, CDSC_OK, CDSC_NOTDSC * or one of the following */ /* The line should be passed on to the next section parser. */ #define CDSC_PROPAGATE 10 /* If document is DOS EPS and we haven't read 30 bytes, ask for more. */ #define CDSC_NEEDMORE 11 /* local prototypes */ dsc_private void * dsc_memalloc(CDSC *dsc, size_t size); dsc_private void dsc_memfree(CDSC*dsc, void *ptr); dsc_private CDSC * dsc_init2(CDSC *dsc); dsc_private void dsc_reset(CDSC *dsc); dsc_private void dsc_section_join(DSC_OFFSET begin, DSC_OFFSET *pend, DSC_OFFSET **pplast); dsc_private int dsc_read_line(CDSC *dsc); dsc_private int dsc_read_doseps(CDSC *dsc); dsc_private char * dsc_alloc_string(CDSC *dsc, const char *str, int len); dsc_private char * dsc_add_line(CDSC *dsc, const char *line, unsigned int len); dsc_private char * dsc_copy_string(char *str, unsigned int slen, char *line, unsigned int len, unsigned int *offset); dsc_private GSDWORD dsc_get_dword(const unsigned char *buf); dsc_private GSWORD dsc_get_word(const unsigned char *buf); dsc_private int dsc_get_int(const char *line, unsigned int len, unsigned int *offset); dsc_private float dsc_get_real(const char *line, unsigned int len, unsigned int *offset); dsc_private void dsc_unknown(CDSC *dsc); dsc_private GSBOOL dsc_is_section(char *line); dsc_private int dsc_parse_pages(CDSC *dsc); dsc_private int dsc_parse_bounding_box(CDSC *dsc, CDSCBBOX** pbbox, int offset); dsc_private int dsc_parse_float_bounding_box(CDSC *dsc, CDSCFBBOX** pfbbox, int offset); dsc_private int dsc_parse_orientation(CDSC *dsc, unsigned int *porientation, int offset); dsc_private int dsc_parse_order(CDSC *dsc); dsc_private int dsc_parse_media(CDSC *dsc, const CDSCMEDIA **page_media); dsc_private int dsc_parse_document_media(CDSC *dsc); dsc_private int dsc_parse_viewing_orientation(CDSC *dsc, CDSCCTM **pctm); dsc_private int dsc_parse_page(CDSC *dsc); dsc_private void dsc_save_line(CDSC *dsc); dsc_private int dsc_scan_type(CDSC *dsc); dsc_private int dsc_scan_comments(CDSC *dsc); dsc_private int dsc_scan_preview(CDSC *dsc); dsc_private int dsc_scan_defaults(CDSC *dsc); dsc_private int dsc_scan_prolog(CDSC *dsc); dsc_private int dsc_scan_setup(CDSC *dsc); dsc_private int dsc_scan_page(CDSC *dsc); dsc_private int dsc_scan_trailer(CDSC *dsc); dsc_private int dsc_error(CDSC *dsc, unsigned int explanation, char *line, unsigned int line_len); dsc_private int dsc_dcs2_fixup(CDSC *dsc); dsc_private int dsc_parse_platefile(CDSC *dsc); dsc_private int dsc_parse_dcs1plate(CDSC *dsc); dsc_private CDSCCOLOUR * dsc_find_colour(CDSC *dsc, const char *colourname); dsc_private int dsc_parse_process_colours(CDSC *dsc); dsc_private int dsc_parse_custom_colours(CDSC *dsc); dsc_private int dsc_parse_cmyk_custom_colour(CDSC *dsc); dsc_private int dsc_parse_rgb_custom_colour(CDSC *dsc); /* DSC error reporting */ dsc_private const int dsc_severity[] = { CDSC_ERROR_WARN, /* CDSC_MESSAGE_BBOX */ CDSC_ERROR_WARN, /* CDSC_MESSAGE_EARLY_TRAILER */ CDSC_ERROR_WARN, /* CDSC_MESSAGE_EARLY_EOF */ CDSC_ERROR_ERROR, /* CDSC_MESSAGE_PAGE_IN_TRAILER */ CDSC_ERROR_ERROR, /* CDSC_MESSAGE_PAGE_ORDINAL */ CDSC_ERROR_ERROR, /* CDSC_MESSAGE_PAGES_WRONG */ CDSC_ERROR_ERROR, /* CDSC_MESSAGE_EPS_NO_BBOX */ CDSC_ERROR_ERROR, /* CDSC_MESSAGE_EPS_PAGES */ CDSC_ERROR_WARN, /* CDSC_MESSAGE_NO_MEDIA */ CDSC_ERROR_WARN, /* CDSC_MESSAGE_ATEND */ CDSC_ERROR_INFORM, /* CDSC_MESSAGE_DUP_COMMENT */ CDSC_ERROR_INFORM, /* CDSC_MESSAGE_DUP_TRAILER */ CDSC_ERROR_WARN, /* CDSC_MESSAGE_BEGIN_END */ CDSC_ERROR_INFORM, /* CDSC_MESSAGE_BAD_SECTION */ CDSC_ERROR_INFORM, /* CDSC_MESSAGE_LONG_LINE */ CDSC_ERROR_WARN, /* CDSC_MESSAGE_INCORRECT_USAGE */ 0 }; #define DSC_MAX_ERROR ((sizeof(dsc_severity) / sizeof(int))-2) const CDSCMEDIA dsc_known_media[CDSC_KNOWN_MEDIA] = { /* These sizes taken from Ghostscript gs_statd.ps */ {"11x17", 792, 1224, 0, NULL, NULL}, {"A3", 842, 1190, 0, NULL, NULL}, {"A4", 595, 842, 0, NULL, NULL}, {"A5", 421, 595, 0, NULL, NULL}, {"B4", 709, 1002, 0, NULL, NULL}, /* ISO, but not Adobe standard */ {"B5", 501, 709, 0, NULL, NULL}, /* ISO, but not Adobe standard */ {"Ledger", 1224, 792, 0, NULL, NULL}, {"Legal", 612, 1008, 0, NULL, NULL}, {"Letter", 612, 792, 0, NULL, NULL}, {"Note", 612, 792, 0, NULL, NULL}, {NULL, 0, 0, 0, NULL, NULL} }; /* parser state */ enum CDSC_SCAN_SECTION { scan_none = 0, scan_comments = 1, scan_pre_preview = 2, scan_preview = 3, scan_pre_defaults = 4, scan_defaults = 5, scan_pre_prolog = 6, scan_prolog = 7, scan_pre_setup = 8, scan_setup = 9, scan_pre_pages = 10, scan_pages = 11, scan_pre_trailer = 12, scan_trailer = 13, scan_eof = 14 }; static const char * const dsc_scan_section_name[15] = { "Type", "Comments", "pre-Preview", "Preview", "pre-Defaults", "Defaults", "pre-Prolog", "Prolog", "pre-Setup", "Setup", "pre-Page", "Page", "pre-Trailer", "Trailer", "EOF" }; /******************************************************************/ /* Public functions */ /******************************************************************/ /* constructor */ CDSC * dsc_init(void *caller_data) { CDSC *dsc = (CDSC *)malloc(sizeof(CDSC)); if (dsc == NULL) return NULL; memset(dsc, 0, sizeof(CDSC)); dsc->caller_data = caller_data; dsc->ref_count = 0; dsc_ref(dsc); return dsc_init2(dsc); } /* constructor, with caller supplied memalloc */ CDSC * dsc_init_with_alloc( void *caller_data, void *(*memalloc)(size_t size, void *closure_data), void (*memfree)(void *ptr, void *closure_data), void *closure_data) { CDSC *dsc = (CDSC *)memalloc(sizeof(CDSC), closure_data); if (dsc == NULL) return NULL; memset(dsc, 0, sizeof(CDSC)); dsc->caller_data = caller_data; dsc->memalloc = memalloc; dsc->memfree = memfree; dsc->mem_closure_data = closure_data; dsc->ref_count = 0; dsc_ref(dsc); return dsc_init2(dsc); } /* destructor */ void dsc_free(CDSC *dsc) { if (dsc == NULL) return; dsc_reset(dsc); dsc_memfree(dsc, dsc); } CDSC * dsc_new(void *caller_data) { return dsc_init(caller_data); } int dsc_ref(CDSC *dsc) { return ++(dsc->ref_count); } int dsc_unref(CDSC *dsc) { if (dsc->ref_count <= 0) return -1; dsc->ref_count--; if (dsc->ref_count == 0) { dsc_free(dsc); return 0; } return dsc->ref_count; } /* Tell DSC parser how long document will be, to allow ignoring * of early %%Trailer and %%EOF. This is optional. */ void dsc_set_length(CDSC *dsc, DSC_OFFSET len) { dsc->file_length = len; } /* Process a buffer containing DSC comments and PostScript */ /* Return value is < 0 for error, >=0 for OK. * CDSC_ERROR * CDSC_OK * CDSC_NOTDSC (DSC will be ignored) * other values indicate the last DSC comment read */ int dsc_scan_data(CDSC *dsc, const char *data, int length) { int bytes_read; int code = 0; if (dsc == NULL) return CDSC_ERROR; if (dsc->id == CDSC_NOTDSC) return CDSC_NOTDSC; dsc->id = CDSC_OK; if (dsc->eof) return CDSC_OK; /* ignore */ if (length == 0) { /* EOF, so process what remains */ dsc->eof = TRUE; } do { if (dsc->id == CDSC_NOTDSC) break; if (length != 0) { /* move existing data if needed */ if (dsc->data_length > CDSC_DATA_LENGTH/2) { memmove(dsc->data, dsc->data + dsc->data_index, dsc->data_length - dsc->data_index); dsc->data_offset += dsc->data_index; dsc->data_length -= dsc->data_index; dsc->data_index = 0; } /* append to buffer */ bytes_read = min(length, (int)(CDSC_DATA_LENGTH - dsc->data_length)); memcpy(dsc->data + dsc->data_length, data, bytes_read); dsc->data_length += bytes_read; data += bytes_read; length -= bytes_read; } if (dsc->scan_section == scan_none) { code = dsc_scan_type(dsc); if (code == CDSC_NEEDMORE) { /* need more characters before we can identify type */ code = CDSC_OK; break; } dsc->id = code; } if (code == CDSC_NOTDSC) { dsc->id = CDSC_NOTDSC; break; } while ((code = dsc_read_line(dsc)) > 0) { if (dsc->id == CDSC_NOTDSC) break; if (dsc->file_length && (dsc->data_offset + dsc->data_index > dsc->file_length)) { /* have read past end of where we need to parse. */ return CDSC_OK; /* ignore */ } if (dsc->doseps_end && (dsc->data_offset + dsc->data_index > dsc->doseps_end)) { /* have read past end of DOS EPS PostScript section */ return CDSC_OK; /* ignore */ } if (dsc->eof) return CDSC_OK; if (dsc->skip_document) continue; /* embedded document */ if (dsc->skip_lines) continue; /* embedded lines */ if (IS_DSC(dsc->line, "%%BeginData:")) continue; if (IS_DSC(dsc->line, "%%BeginBinary:")) continue; if (IS_DSC(dsc->line, "%%EndDocument")) continue; if (IS_DSC(dsc->line, "%%EndData")) continue; if (IS_DSC(dsc->line, "%%EndBinary")) continue; do { switch (dsc->scan_section) { case scan_comments: code = dsc_scan_comments(dsc); break; case scan_pre_preview: case scan_preview: code = dsc_scan_preview(dsc); break; case scan_pre_defaults: case scan_defaults: code = dsc_scan_defaults(dsc); break; case scan_pre_prolog: case scan_prolog: code = dsc_scan_prolog(dsc); break; case scan_pre_setup: case scan_setup: code = dsc_scan_setup(dsc); break; case scan_pre_pages: case scan_pages: code = dsc_scan_page(dsc); break; case scan_pre_trailer: case scan_trailer: code = dsc_scan_trailer(dsc); break; case scan_eof: code = CDSC_OK; break; default: /* invalid state */ code = CDSC_ERROR; } /* repeat if line is start of next section */ } while (code == CDSC_PROPAGATE); /* if DOS EPS header not complete, ask for more */ if (code == CDSC_NEEDMORE) { code = CDSC_OK; break; } if (code == CDSC_NOTDSC) { dsc->id = CDSC_NOTDSC; break; } } } while (length != 0); return (code < 0) ? code : dsc->id; } /* Tidy up from incorrect DSC comments */ int dsc_fixup(CDSC *dsc) { unsigned int i; char buf[32]; DSC_OFFSET *last; if (dsc->id == CDSC_NOTDSC) return 0; /* flush last partial line */ dsc_scan_data(dsc, NULL, 0); /* Fix DSC error: EOF before end of %%BeginData */ if (dsc->eof && (dsc->skip_lines || dsc->skip_bytes || dsc->skip_document)) { switch (dsc->scan_section) { case scan_comments: dsc->endcomments = DSC_END(dsc); break; case scan_preview: dsc->endpreview = DSC_END(dsc); break; case scan_defaults: dsc->enddefaults = DSC_END(dsc); break; case scan_prolog: dsc->endprolog = DSC_END(dsc); break; case scan_setup: dsc->endsetup = DSC_END(dsc); break; case scan_pages: if (dsc->page_count) dsc->page[dsc->page_count-1].end = DSC_END(dsc); break; case scan_trailer: case scan_eof: dsc->endtrailer = DSC_END(dsc); break; } } /* Fix DSC error: code between %%EndSetup and %%Page */ if (dsc->page_count && (dsc->page[0].begin != dsc->endsetup) && (dsc->endsetup != dsc->beginsetup)) { dsc->endsetup = dsc->page[0].begin; dsc_debug_print(dsc, "Warning: code included between setup and first page\n"); } /* Last page contained a false trailer, */ /* so extend last page to start of trailer */ if (dsc->page_count && (dsc->begintrailer != 0) && (dsc->page[dsc->page_count-1].end != dsc->begintrailer)) { dsc_debug_print(dsc, "Ignoring earlier misplaced trailer\n"); dsc_debug_print(dsc, "and extending last page to start of trailer\n"); dsc->page[dsc->page_count-1].end = dsc->begintrailer; } /* * Join up all sections. * There might be extra code between them, or we might have * missed including the \n which followed \r. */ last = &dsc->endcomments; dsc_section_join(dsc->beginpreview, &dsc->endpreview, &last); dsc_section_join(dsc->begindefaults, &dsc->enddefaults, &last); dsc_section_join(dsc->beginprolog, &dsc->endprolog, &last); dsc_section_join(dsc->beginsetup, &dsc->endsetup, &last); for (i=0; ipage_count; i++) dsc_section_join(dsc->page[i].begin, &dsc->page[i].end, &last); if (dsc->begintrailer) *last = dsc->begintrailer; if ((dsc->page_pages == 0) && (dsc->page_count == 1)) { /* don't flag an error if %%Pages absent but one %%Page found */ /* adjust incorrect page count */ dsc->page_pages = dsc->page_count; } /* Warnings and Errors that we can now identify */ if ((dsc->page_count != dsc->page_pages)) { int rc = dsc_error(dsc, CDSC_MESSAGE_PAGES_WRONG, NULL, 0); switch (rc) { case CDSC_RESPONSE_OK: /* adjust incorrect page count */ dsc->page_pages = dsc->page_count; break; case CDSC_RESPONSE_CANCEL: break;; case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } if (dsc->epsf && (dsc->bbox == (CDSCBBOX *)NULL)) { /* EPS files MUST include a BoundingBox */ int rc = dsc_error(dsc, CDSC_MESSAGE_EPS_NO_BBOX, NULL, 0); switch (rc) { case CDSC_RESPONSE_OK: /* Assume that it is EPS */ break; case CDSC_RESPONSE_CANCEL: /* Is NOT an EPS file */ dsc->epsf = FALSE; case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } if (dsc->epsf && ((dsc->page_count > 1) || (dsc->page_pages > 1))) { int rc = dsc_error(dsc, CDSC_MESSAGE_EPS_PAGES, NULL, 0); switch (rc) { case CDSC_RESPONSE_OK: /* Is an EPS file */ break; case CDSC_RESPONSE_CANCEL: /* Is NOT an EPS file */ dsc->epsf = FALSE; break; case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } /* convert single file DSC 2.0 into multiple pages */ dsc_dcs2_fixup(dsc); if ((dsc->media_count == 1) && (dsc->page_media == NULL)) { /* if one only media was specified, and default page media */ /* was not specified, assume that default is the only media. */ dsc->page_media = dsc->media[0]; } if ((dsc->media_count != 0) && (dsc->page_media == NULL)) { int rc = dsc_error(dsc, CDSC_MESSAGE_NO_MEDIA, NULL, 0); switch (rc) { case CDSC_RESPONSE_OK: /* default media is first listed */ dsc->page_media = dsc->media[0]; break; case CDSC_RESPONSE_CANCEL: /* No default media */ break; case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } /* make sure all pages have a label */ for (i=0; ipage_count; i++) { if (strlen(dsc->page[i].label) == 0) { sprintf(buf, "%d", i+1); if ((dsc->page[i].label = dsc_alloc_string(dsc, buf, (int)strlen(buf))) == (char *)NULL) return CDSC_ERROR; /* no memory */ } } return CDSC_OK; } /* Install a function to be used for displaying messages about * DSC errors and warnings, and to request advice from user. * Installing an error function is optional. */ void dsc_set_error_function(CDSC *dsc, int (*fn)(void *caller_data, CDSC *dsc, unsigned int explanation, const char *line, unsigned int line_len)) { dsc->dsc_error_fn = fn; } /* Install a function for printing debug messages */ /* This is optional */ void dsc_set_debug_function(CDSC *dsc, void (*debug_fn)(void *caller_data, const char *str)) { dsc->debug_print_fn = debug_fn; } /* Doesn't need to be public for PostScript documents */ /* Made public so GSview can add pages when processing PDF files */ int dsc_add_page(CDSC *dsc, int ordinal, char *label) { dsc->page[dsc->page_count].ordinal = ordinal; dsc->page[dsc->page_count].label = dsc_alloc_string(dsc, label, (int)strlen(label)+1); dsc->page[dsc->page_count].begin = 0; dsc->page[dsc->page_count].end = 0; dsc->page[dsc->page_count].orientation = CDSC_ORIENT_UNKNOWN; dsc->page[dsc->page_count].media = NULL; dsc->page[dsc->page_count].bbox = NULL; dsc->page[dsc->page_count].viewing_orientation = NULL; dsc->page[dsc->page_count].crop_box = NULL; dsc->page_count++; if (dsc->page_count >= dsc->page_chunk_length) { CDSCPAGE *new_page = (CDSCPAGE *)dsc_memalloc(dsc, (CDSC_PAGE_CHUNK+dsc->page_count) * sizeof(CDSCPAGE)); if (new_page == NULL) return CDSC_ERROR; /* out of memory */ memcpy(new_page, dsc->page, dsc->page_count * sizeof(CDSCPAGE)); dsc_memfree(dsc, dsc->page); dsc->page= new_page; dsc->page_chunk_length = CDSC_PAGE_CHUNK+dsc->page_count; } return CDSC_OK; } /* Doesn't need to be public for PostScript documents */ /* Made public so GSview can store PDF MediaBox */ int dsc_add_media(CDSC *dsc, CDSCMEDIA *media) { CDSCMEDIA **newmedia_array; CDSCMEDIA *newmedia; /* extend media array */ newmedia_array = (CDSCMEDIA **)dsc_memalloc(dsc, (dsc->media_count + 1) * sizeof(CDSCMEDIA *)); if (newmedia_array == NULL) return CDSC_ERROR; /* out of memory */ if (dsc->media != NULL) { memcpy(newmedia_array, dsc->media, dsc->media_count * sizeof(CDSCMEDIA *)); dsc_memfree(dsc, dsc->media); } dsc->media = newmedia_array; /* allocate new media */ newmedia = dsc->media[dsc->media_count] = (CDSCMEDIA *)dsc_memalloc(dsc, sizeof(CDSCMEDIA)); if (newmedia == NULL) return CDSC_ERROR; /* out of memory */ newmedia->name = NULL; newmedia->width = 595.0; newmedia->height = 842.0; newmedia->weight = 80.0; newmedia->colour = NULL; newmedia->type = NULL; newmedia->mediabox = NULL; dsc->media_count++; if (media->name) { newmedia->name = dsc_alloc_string(dsc, media->name, (int)strlen(media->name)); if (newmedia->name == NULL) return CDSC_ERROR; /* no memory */ } newmedia->width = media->width; newmedia->height = media->height; newmedia->weight = media->weight; if (media->colour) { newmedia->colour = dsc_alloc_string(dsc, media->colour, (int)strlen(media->colour)); if (newmedia->colour == NULL) return CDSC_ERROR; /* no memory */ } if (media->type) { newmedia->type = dsc_alloc_string(dsc, media->type, (int)strlen(media->type)); if (newmedia->type == NULL) return CDSC_ERROR; /* no memory */ } newmedia->mediabox = NULL; if (media->mediabox) { newmedia->mediabox = (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX)); if (newmedia->mediabox == NULL) return CDSC_ERROR; /* no memory */ *newmedia->mediabox = *media->mediabox; } return CDSC_OK; } /* Doesn't need to be public for PostScript documents */ /* Made public so GSview can store PDF CropBox */ int dsc_set_page_bbox(CDSC *dsc, unsigned int page_number, int llx, int lly, int urx, int ury) { CDSCBBOX *bbox; if (page_number >= dsc->page_count) return CDSC_ERROR; bbox = dsc->page[page_number].bbox; if (bbox == NULL) dsc->page[page_number].bbox = bbox = (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX)); if (bbox == NULL) return CDSC_ERROR; bbox->llx = llx; bbox->lly = lly; bbox->urx = urx; bbox->ury = ury; return CDSC_OK; } /******************************************************************/ /* Private functions below here. */ /******************************************************************/ dsc_private void * dsc_memalloc(CDSC *dsc, size_t size) { if (dsc->memalloc) return dsc->memalloc(size, dsc->mem_closure_data); return malloc(size); } dsc_private void dsc_memfree(CDSC*dsc, void *ptr) { if (dsc->memfree) dsc->memfree(ptr, dsc->mem_closure_data); else free(ptr); } /* private constructor */ dsc_private CDSC * dsc_init2(CDSC *dsc) { dsc_reset(dsc); dsc->string_head = (CDSCSTRING *)dsc_memalloc(dsc, sizeof(CDSCSTRING)); if (dsc->string_head == NULL) { dsc_free(dsc); return NULL; /* no memory */ } dsc->string = dsc->string_head; dsc->string->next = NULL; dsc->string->data = (char *)dsc_memalloc(dsc, CDSC_STRING_CHUNK); if (dsc->string->data == NULL) { dsc_free(dsc); return NULL; /* no memory */ } dsc->string->index = 0; dsc->string->length = CDSC_STRING_CHUNK; dsc->page = (CDSCPAGE *)dsc_memalloc(dsc, CDSC_PAGE_CHUNK * sizeof(CDSCPAGE)); if (dsc->page == NULL) { dsc_free(dsc); return NULL; /* no memory */ } dsc->page_chunk_length = CDSC_PAGE_CHUNK; dsc->page_count = 0; dsc->line = NULL; dsc->data_length = 0; dsc->data_index = dsc->data_length; return dsc; } dsc_private void dsc_reset(CDSC *dsc) { unsigned int i; /* Clear public members */ dsc->dsc = FALSE; dsc->ctrld = FALSE; dsc->pjl = FALSE; dsc->epsf = FALSE; dsc->pdf = FALSE; dsc->epsf = FALSE; dsc->preview = CDSC_NOPREVIEW; dsc->dsc_version = NULL; /* stored in dsc->string */ dsc->language_level = 0; dsc->document_data = CDSC_DATA_UNKNOWN; dsc->begincomments = 0; dsc->endcomments = 0; dsc->beginpreview = 0; dsc->endpreview = 0; dsc->begindefaults = 0; dsc->enddefaults = 0; dsc->beginprolog = 0; dsc->endprolog = 0; dsc->beginsetup = 0; dsc->endsetup = 0; dsc->begintrailer = 0; dsc->endtrailer = 0; for (i=0; ipage_count; i++) { /* page media is pointer to an element of media or dsc_known_media */ /* do not free it. */ if (dsc->page[i].bbox) dsc_memfree(dsc, dsc->page[i].bbox); if (dsc->page[i].viewing_orientation) dsc_memfree(dsc, dsc->page[i].viewing_orientation); if (dsc->page[i].crop_box) dsc_memfree(dsc, dsc->page[i].crop_box); } if (dsc->page) dsc_memfree(dsc, dsc->page); dsc->page = NULL; dsc->page_count = 0; dsc->page_pages = 0; dsc->page_order = CDSC_ORDER_UNKNOWN; dsc->page_orientation = CDSC_ORIENT_UNKNOWN; if (dsc->viewing_orientation) dsc_memfree(dsc, dsc->viewing_orientation); dsc->viewing_orientation = NULL; if (dsc->media) { for (i=0; imedia_count; i++) { if (dsc->media[i]) { if (dsc->media[i]->mediabox) dsc_memfree(dsc, dsc->media[i]->mediabox); dsc_memfree(dsc, dsc->media[i]); } } dsc_memfree(dsc, dsc->media); } dsc->media_count = 0; dsc->media = NULL; /* page_media is pointer to an element of media or dsc_known_media */ /* do not free it. */ dsc->page_media = NULL; if (dsc->bbox) dsc_memfree(dsc, dsc->bbox); dsc->bbox = NULL; if (dsc->page_bbox) dsc_memfree(dsc, dsc->page_bbox); dsc->page_bbox = NULL; if (dsc->doseps) dsc_memfree(dsc, dsc->doseps); dsc->doseps = NULL; dsc->dsc_title = NULL; dsc->dsc_creator = NULL; dsc->dsc_date = NULL; dsc->dsc_for = NULL; dsc->max_error = DSC_MAX_ERROR; dsc->severity = dsc_severity; /* Clear private members */ /* Don't touch dsc->caller_data */ dsc->id = CDSC_OK; dsc->scan_section = scan_none; dsc->doseps_end = 0; dsc->page_chunk_length = 0; dsc->file_length = 0; dsc->skip_document = 0; dsc->skip_bytes = 0; dsc->skip_lines = 0; dsc->skip_pjl = 0; dsc->begin_font_count = 0; dsc->begin_feature_count = 0; dsc->begin_resource_count = 0; dsc->begin_procset_count = 0; dsc->data_length = 0; dsc->data_index = 0; dsc->data_offset = 0; dsc->eof = 0; dsc->line = 0; dsc->line_length = 0; dsc->eol = 0; dsc->last_cr = FALSE; dsc->line_count = 1; dsc->long_line = FALSE; memset(dsc->last_line, 0, sizeof(dsc->last_line)); dsc->string = dsc->string_head; while (dsc->string != (CDSCSTRING *)NULL) { if (dsc->string->data) dsc_memfree(dsc, dsc->string->data); dsc->string_head = dsc->string; dsc->string = dsc->string->next; dsc_memfree(dsc, dsc->string_head); } dsc->string_head = NULL; dsc->string = NULL; /* don't touch caller functions */ /* public data */ if (dsc->hires_bbox) dsc_memfree(dsc, dsc->hires_bbox); dsc->hires_bbox = NULL; if (dsc->crop_box) dsc_memfree(dsc, dsc->crop_box); dsc->crop_box = NULL; if (dsc->dcs2) { CDCS2 *this_dcs, *next_dcs; this_dcs = dsc->dcs2; while (this_dcs) { next_dcs = this_dcs->next; /* strings have already been freed */ dsc_memfree(dsc, this_dcs); this_dcs = next_dcs; } dsc->dcs2 = NULL; } if (dsc->colours) { CDSCCOLOUR *this_colour, *next_colour; this_colour = dsc->colours; while (this_colour) { next_colour = this_colour->next; /* strings have already been freed */ dsc_memfree(dsc, this_colour); this_colour = next_colour; } dsc->colours = NULL; } } /* * Join up all sections. * There might be extra code between them, or we might have * missed including the \n which followed \r. * begin is the start of this section * pend is a pointer to the end of this section * pplast is a pointer to a pointer of the end of the previous section */ dsc_private void dsc_section_join(DSC_OFFSET begin, DSC_OFFSET *pend, DSC_OFFSET **pplast) { if (begin) **pplast = begin; if (*pend > begin) *pplast = pend; } /* return value is 0 if no line available, or length of line */ dsc_private int dsc_read_line(CDSC *dsc) { char *p, *last; dsc->line = NULL; if (dsc->eof) { /* return all that remains, even if line incomplete */ dsc->line = dsc->data + dsc->data_index; dsc->line_length = dsc->data_length - dsc->data_index; dsc->data_index = dsc->data_length; return dsc->line_length; } if (dsc->file_length && (dsc->data_offset + dsc->data_index >= dsc->file_length)) { /* Have read past where we need to parse. */ /* Ignore all that remains. */ dsc->line = dsc->data + dsc->data_index; dsc->line_length = dsc->data_length - dsc->data_index; dsc->data_index = dsc->data_length; return dsc->line_length; } if (dsc->doseps_end && (dsc->data_offset + dsc->data_index >= dsc->doseps_end)) { /* Have read past end of DOS EPS PostScript section. */ /* Ignore all that remains. */ dsc->line = dsc->data + dsc->data_index; dsc->line_length = dsc->data_length - dsc->data_index; dsc->data_index = dsc->data_length; return dsc->line_length; } /* ignore embedded bytes */ if (dsc->skip_bytes) { int cnt = min(dsc->skip_bytes, (int)(dsc->data_length - dsc->data_index)); dsc->skip_bytes -= cnt; dsc->data_index += cnt; if (dsc->skip_bytes != 0) return 0; } do { dsc->line = dsc->data + dsc->data_index; last = dsc->data + dsc->data_length; if (dsc->data_index == dsc->data_length) { dsc->line_length = 0; return 0; } if (dsc->eol) { /* if previous line was complete, increment line count */ dsc->line_count++; if (dsc->skip_lines) dsc->skip_lines--; } /* skip over \n which followed \r */ if (dsc->last_cr && dsc->line[0] == '\n') { dsc->data_index++; dsc->line++; } dsc->last_cr = FALSE; /* look for EOL */ dsc->eol = FALSE; for (p = dsc->line; p < last; p++) { if (*p == '\r') { p++; if ((plast_cr = TRUE; /* we might need to skip \n */ dsc->eol = TRUE; /* dsc->line is a complete line */ break; } if (*p == '\n') { p++; dsc->eol = TRUE; /* dsc->line is a complete line */ break; } if (*p == '\032') { /* MS-DOS Ctrl+Z */ dsc->eol = TRUE; } } if (dsc->eol == FALSE) { /* we haven't got a complete line yet */ if (dsc->data_length - dsc->data_index < sizeof(dsc->data)/2) { /* buffer is less than half full, ask for some more */ dsc->line_length = 0; return 0; } } dsc->data_index += dsc->line_length = (int)(p - dsc->line); } while (dsc->skip_lines && dsc->line_length); if (dsc->line_length == 0) return 0; if ((dsc->line[0]=='%') && (dsc->line[1]=='%')) { /* handle recursive %%BeginDocument */ if ((dsc->skip_document) && dsc->line_length && COMPARE(dsc->line, "%%EndDocument")) { dsc->skip_document--; } /* handle embedded lines or binary data */ if (COMPARE(dsc->line, "%%BeginData:")) { /* %%BeginData: [ [ ] ] * ::= (Lines or physical bytes) * ::= Hex | Binary | ASCII (Type of data) * ::= Bytes | Lines (Read in bytes or lines) */ char begindata[MAXSTR+1]; int cnt; const char *numberof, *bytesorlines; cnt = dsc->line_length; if (dsc->line_length > sizeof(begindata)-1) cnt = sizeof(begindata)-1; memcpy(begindata, dsc->line, cnt); begindata[cnt] = '\0'; numberof = strtok(begindata+12, " \r\n"); strtok(NULL, " \r\n"); /* dump type */ bytesorlines = strtok(NULL, " \r\n"); if (bytesorlines == NULL) bytesorlines = "Bytes"; if ( (numberof == NULL) || (bytesorlines == NULL) ) { /* invalid usage of %%BeginData */ /* ignore that we ever saw it */ int rc = dsc_error(dsc, CDSC_MESSAGE_INCORRECT_USAGE, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: case CDSC_RESPONSE_CANCEL: break; case CDSC_RESPONSE_IGNORE_ALL: return 0; } } else { cnt = atoi(numberof); if (cnt) { if (bytesorlines && (dsc_stricmp(bytesorlines, "Lines")==0)) { /* skip cnt lines */ if (dsc->skip_lines == 0) { /* we are not already skipping lines */ dsc->skip_lines = cnt+1; } } else { /* byte count doesn't includes \n or \r\n */ /* or \r of %%BeginData: */ /* skip cnt bytes */ if (dsc->skip_bytes == 0) { /* we are not already skipping lines */ dsc->skip_bytes = cnt; } } } } } else if (COMPARE(dsc->line, "%%BeginBinary:")) { /* byte count doesn't includes \n or \r\n or \r of %%BeginBinary:*/ int cnt = dsc_get_int(dsc->line + 14, dsc->line_length - 14, NULL); if (dsc->skip_bytes == 0) { /* we are not already skipping lines */ dsc->skip_bytes = cnt; } } } if ((dsc->line[0]=='%') && (dsc->line[1]=='%') && COMPARE(dsc->line, "%%BeginDocument:") ) { /* Skip over embedded document, recursively */ dsc->skip_document++; } if (!dsc->long_line && (dsc->line_length > DSC_LINE_LENGTH)) { dsc_error(dsc, CDSC_MESSAGE_LONG_LINE, dsc->line, dsc->line_length); dsc->long_line = TRUE; } return dsc->line_length; } /* Save last DSC line, for use with %%+ */ dsc_private void dsc_save_line(CDSC *dsc) { int len = min(sizeof(dsc->last_line), dsc->line_length); memcpy(dsc->last_line, dsc->line, len); } /* display unknown DSC line */ dsc_private void dsc_unknown(CDSC *dsc) { if (dsc->debug_print_fn) { char line[DSC_LINE_LENGTH]; unsigned int length = min(DSC_LINE_LENGTH-1, dsc->line_length); sprintf(line, "Unknown in %s section at line %d:\n ", dsc_scan_section_name[dsc->scan_section], dsc->line_count); dsc_debug_print(dsc, line); strncpy(line, dsc->line, length); line[length] = '\0'; dsc_debug_print(dsc, line); dsc_debug_print(dsc, "\n"); } } dsc_private GSBOOL dsc_is_section(char *line) { if ( !((line[0]=='%') && (line[1]=='%')) ) return FALSE; if (IS_DSC(line, "%%BeginPreview")) return TRUE; if (IS_DSC(line, "%%BeginDefaults")) return TRUE; if (IS_DSC(line, "%%BeginProlog")) return TRUE; if (IS_DSC(line, "%%BeginSetup")) return TRUE; if (IS_DSC(line, "%%Page:")) return TRUE; if (IS_DSC(line, "%%Trailer")) return TRUE; if (IS_DSC(line, "%%EOF")) return TRUE; return FALSE; } dsc_private GSDWORD dsc_get_dword(const unsigned char *buf) { GSDWORD dw; dw = (GSDWORD)buf[0]; dw += ((GSDWORD)buf[1])<<8; dw += ((GSDWORD)buf[2])<<16; dw += ((GSDWORD)buf[3])<<24; return dw; } dsc_private GSWORD dsc_get_word(const unsigned char *buf) { GSWORD w; w = (GSWORD)buf[0]; w |= (GSWORD)(buf[1]<<8); return w; } dsc_private int dsc_read_doseps(CDSC *dsc) { unsigned char *line = (unsigned char *)dsc->line; if ((dsc->doseps = (CDSCDOSEPS *)dsc_memalloc(dsc, sizeof(CDSCDOSEPS))) == NULL) return CDSC_ERROR; /* no memory */ dsc->doseps->ps_begin = dsc_get_dword(line+4); dsc->doseps->ps_length = dsc_get_dword(line+8); dsc->doseps->wmf_begin = dsc_get_dword(line+12); dsc->doseps->wmf_length = dsc_get_dword(line+16); dsc->doseps->tiff_begin = dsc_get_dword(line+20); dsc->doseps->tiff_length = dsc_get_dword(line+24); dsc->doseps->checksum = dsc_get_word(line+28); if (dsc->file_length && (dsc->doseps->ps_begin + dsc->doseps->ps_length > dsc->file_length)) { /* Error in DOS EPS header. * Some files have been seen with a fixed large value as * the length of the PostScript section. * Correct for these erroneous files. */ dsc->doseps->ps_length = (GSDWORD)(dsc->file_length - dsc->doseps->ps_begin); } dsc->doseps_end = dsc->doseps->ps_begin + dsc->doseps->ps_length; /* move data_index backwards to byte after doseps header */ dsc->data_index -= dsc->line_length - 30; /* we haven't read a line of PostScript code yet */ dsc->line_count = 0; /* skip from current position to start of PostScript section */ dsc->skip_bytes = dsc->doseps->ps_begin - 30; if (dsc->doseps->tiff_begin) dsc->preview = CDSC_TIFF; if (dsc->doseps->wmf_begin) dsc->preview = CDSC_WMF; return CDSC_OK; } dsc_private int dsc_parse_pages(CDSC *dsc) { int ip, io; unsigned int i; char *p; int n; if ((dsc->page_pages != 0) && (dsc->scan_section == scan_comments)) { int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: case CDSC_RESPONSE_CANCEL: return CDSC_OK; /* ignore duplicate comments in header */ case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } if ((dsc->page_pages != 0) && (dsc->scan_section == scan_trailer)) { int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: case CDSC_RESPONSE_CANCEL: break; /* use duplicate comments in header */ case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } n = IS_DSC(dsc->line, "%%+") ? 3 : 8; while (IS_WHITE(dsc->line[n])) n++; p = dsc->line + n; if (COMPARE(p, "atend")) { int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: /* assume (atend) */ /* we should mark it as deferred */ break; case CDSC_RESPONSE_CANCEL: /* ignore it */ break; case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } else if (COMPARE(p, "(atend)")) { /* do nothing */ /* we should mark it as deferred */ } else { ip = dsc_get_int(dsc->line+n, dsc->line_length-n, &i); if (i) { n+=i; dsc->page_pages = ip; io = dsc_get_int(dsc->line+n, dsc->line_length-n, &i); if (i) { /* DSC 2 uses extra integer to indicate page order */ /* DSC 3 uses %%PageOrder: */ if (dsc->page_order == CDSC_ORDER_UNKNOWN) switch (io) { case -1: dsc->page_order = CDSC_DESCEND; break; case 0: dsc->page_order = CDSC_SPECIAL; break; case 1: dsc->page_order = CDSC_ASCEND; break; } } } else { int rc = dsc_error(dsc, CDSC_MESSAGE_INCORRECT_USAGE, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: case CDSC_RESPONSE_CANCEL: /* ignore it */ break; case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } } return CDSC_OK; } dsc_private int dsc_parse_bounding_box(CDSC *dsc, CDSCBBOX** pbbox, int offset) { unsigned int i, n; int llx, lly, urx, ury; float fllx, flly, furx, fury; char *p; /* Process first %%BoundingBox: in comments, and last in trailer */ if ((*pbbox != NULL) && (dsc->scan_section == scan_comments)) { int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: case CDSC_RESPONSE_CANCEL: return CDSC_OK; /* ignore duplicate comments in header */ case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } if ((*pbbox != NULL) && (dsc->scan_section == scan_pages)) { int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: case CDSC_RESPONSE_CANCEL: return CDSC_OK; /* ignore duplicate comments in header */ case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } if ((*pbbox != NULL) && (dsc->scan_section == scan_trailer)) { int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: case CDSC_RESPONSE_CANCEL: break; /* use duplicate comments in trailer */ case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } if (*pbbox != NULL) { dsc_memfree(dsc, *pbbox); *pbbox = NULL; } /* should only process first %%BoundingBox: */ while (IS_WHITE(dsc->line[offset])) offset++; p = dsc->line + offset; if (COMPARE(p, "atend")) { int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: /* assume (atend) */ /* we should mark it as deferred */ break; case CDSC_RESPONSE_CANCEL: /* ignore it */ break; case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } else if (COMPARE(p, "(atend)")) { /* do nothing */ /* we should mark it as deferred */ } else { /* llx = */ lly = urx = ury = 0; n = offset; llx = dsc_get_int(dsc->line+n, dsc->line_length-n, &i); n += i; if (i) lly = dsc_get_int(dsc->line+n, dsc->line_length-n, &i); n += i; if (i) urx = dsc_get_int(dsc->line+n, dsc->line_length-n, &i); n += i; if (i) ury = dsc_get_int(dsc->line+n, dsc->line_length-n, &i); if (i) { *pbbox = (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX)); if (*pbbox == NULL) return CDSC_ERROR; /* no memory */ (*pbbox)->llx = llx; (*pbbox)->lly = lly; (*pbbox)->urx = urx; (*pbbox)->ury = ury; } else { int rc = dsc_error(dsc, CDSC_MESSAGE_BBOX, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: /* fllx = */ flly = furx = fury = 0.0; n = offset; n += i; fllx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); n += i; if (i) flly = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); n += i; if (i) furx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); n += i; if (i) fury = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); if (i) { *pbbox = (CDSCBBOX *)dsc_memalloc(dsc, sizeof(CDSCBBOX)); if (*pbbox == NULL) return CDSC_ERROR; /* no memory */ (*pbbox)->llx = (int)fllx; (*pbbox)->lly = (int)flly; (*pbbox)->urx = (int)(furx+0.999); (*pbbox)->ury = (int)(fury+0.999); } return CDSC_OK; case CDSC_RESPONSE_CANCEL: return CDSC_OK; case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } } return CDSC_OK; } dsc_private int dsc_parse_float_bounding_box(CDSC *dsc, CDSCFBBOX** pbbox, int offset) { unsigned int i, n; float fllx, flly, furx, fury; char *p; /* Process first %%HiResBoundingBox: or %%CropBox: in comments, * and last in trailer. */ if ((*pbbox != NULL) && (dsc->scan_section == scan_comments)) { int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: case CDSC_RESPONSE_CANCEL: return CDSC_OK; /* ignore duplicate comments in header */ case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } if ((*pbbox != NULL) && (dsc->scan_section == scan_pages)) { int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: case CDSC_RESPONSE_CANCEL: return CDSC_OK; /* ignore duplicate comments in header */ case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } if ((*pbbox != NULL) && (dsc->scan_section == scan_trailer)) { int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: case CDSC_RESPONSE_CANCEL: break; /* use duplicate comments in trailer */ case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } if (*pbbox != NULL) { dsc_memfree(dsc, *pbbox); *pbbox = NULL; } /* should only process first %%BoundingBox: */ while (IS_WHITE(dsc->line[offset])) offset++; p = dsc->line + offset; if (COMPARE(p, "atend")) { int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: /* assume (atend) */ /* we should mark it as deferred */ break; case CDSC_RESPONSE_CANCEL: /* ignore it */ break; case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } else if (COMPARE(p, "(atend)")) { /* do nothing */ /* we should mark it as deferred */ } else { /* fllx = */ flly = furx = fury = 0.0; n = offset; fllx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); n += i; if (i) flly = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); n += i; if (i) furx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); n += i; if (i) fury = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); if (i) { *pbbox = (CDSCFBBOX *)dsc_memalloc(dsc, sizeof(CDSCFBBOX)); if (*pbbox == NULL) return CDSC_ERROR; /* no memory */ (*pbbox)->fllx = fllx; (*pbbox)->flly = flly; (*pbbox)->furx = furx; (*pbbox)->fury = fury; } } return CDSC_OK; } dsc_private int dsc_parse_orientation(CDSC *dsc, unsigned int *porientation, int offset) { char *p; if ((dsc->page_orientation != CDSC_ORIENT_UNKNOWN) && (dsc->scan_section == scan_comments)) { int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: case CDSC_RESPONSE_CANCEL: return CDSC_OK; /* ignore duplicate comments in header */ case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } if ((dsc->page_orientation != CDSC_ORIENT_UNKNOWN) && (dsc->scan_section == scan_trailer)) { int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: case CDSC_RESPONSE_CANCEL: break; /* use duplicate comments in header; */ case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } p = dsc->line + offset; while (IS_WHITE(*p)) p++; if (COMPARE(p, "atend")) { int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: /* assume (atend) */ /* we should mark it as deferred */ break; case CDSC_RESPONSE_CANCEL: /* ignore it */ break; case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } else if (COMPARE(p, "(atend)")) { /* do nothing */ /* we should mark it as deferred */ } else if (COMPARE(p, "Portrait")) { *porientation = CDSC_PORTRAIT; } else if (COMPARE(p, "Landscape")) { *porientation = CDSC_LANDSCAPE; } else { dsc_unknown(dsc); } return CDSC_OK; } dsc_private int dsc_parse_order(CDSC *dsc) { char *p; if ((dsc->page_order != CDSC_ORDER_UNKNOWN) && (dsc->scan_section == scan_comments)) { int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_COMMENT, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: case CDSC_RESPONSE_CANCEL: return CDSC_OK; /* ignore duplicate comments in header */ case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } if ((dsc->page_order != CDSC_ORDER_UNKNOWN) && (dsc->scan_section == scan_trailer)) { int rc = dsc_error(dsc, CDSC_MESSAGE_DUP_TRAILER, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: case CDSC_RESPONSE_CANCEL: break; /* use duplicate comments in trailer */ case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } p = dsc->line + (IS_DSC(dsc->line, "%%+") ? 3 : 13); while (IS_WHITE(*p)) p++; if (COMPARE(p, "atend")) { int rc = dsc_error(dsc, CDSC_MESSAGE_ATEND, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: /* assume (atend) */ /* we should mark it as deferred */ break; case CDSC_RESPONSE_CANCEL: /* ignore it */ break; case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } else if (COMPARE(p, "(atend)")) { /* do nothing */ /* we should mark it as deferred */ } else if (COMPARE(p, "Ascend")) { dsc->page_order = CDSC_ASCEND; } else if (COMPARE(p, "Descend")) { dsc->page_order = CDSC_DESCEND; } else if (COMPARE(p, "Special")) { dsc->page_order = CDSC_SPECIAL; } else { dsc_unknown(dsc); } return CDSC_OK; } dsc_private int dsc_parse_media(CDSC *dsc, const CDSCMEDIA **page_media) { char media_name[MAXSTR]; int n = IS_DSC(dsc->line, "%%+") ? 3 : 12; /* %%PageMedia: */ unsigned int i; if (dsc_copy_string(media_name, sizeof(media_name)-1, dsc->line+n, dsc->line_length-n, NULL)) { for (i=0; imedia_count; i++) { if (dsc->media[i]->name && (dsc_stricmp(media_name, dsc->media[i]->name) == 0)) { *page_media = dsc->media[i]; return CDSC_OK; } } } dsc_unknown(dsc); return CDSC_OK; } dsc_private int dsc_parse_document_media(CDSC *dsc) { unsigned int i, n; CDSCMEDIA lmedia; GSBOOL blank_line; if (IS_DSC(dsc->line, "%%DocumentMedia:")) n = 16; else if (IS_DSC(dsc->line, "%%+")) n = 3; else return CDSC_ERROR; /* error */ /* check for blank remainder of line */ blank_line = TRUE; for (i=n; iline_length; i++) { if (!IS_WHITE_OR_EOL(dsc->line[i])) { blank_line = FALSE; break; } } if (!blank_line) { char name[MAXSTR]; char colour[MAXSTR]; char type[MAXSTR]; lmedia.name = lmedia.colour = lmedia.type = (char *)NULL; lmedia.width = lmedia.height = lmedia.weight = 0; lmedia.mediabox = (CDSCBBOX *)NULL; lmedia.name = dsc_copy_string(name, sizeof(name), dsc->line+n, dsc->line_length-n, &i); n+=i; if (i) lmedia.width = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); n+=i; if (i) lmedia.height = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); n+=i; if (i) lmedia.weight = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); n+=i; if (i) lmedia.colour = dsc_copy_string(colour, sizeof(colour), dsc->line+n, dsc->line_length-n, &i); n+=i; if (i) lmedia.type = dsc_copy_string(type, sizeof(type), dsc->line+n, dsc->line_length-n, &i); if (i==0) dsc_unknown(dsc); /* we didn't get all fields */ else { if (dsc_add_media(dsc, &lmedia)) return CDSC_ERROR; /* out of memory */ } } return CDSC_OK; } /* viewing orientation is believed to be the first four elements of * a CTM matrix */ dsc_private int dsc_parse_viewing_orientation(CDSC *dsc, CDSCCTM **pctm) { CDSCCTM ctm; unsigned int i, n; if (*pctm != NULL) { dsc_memfree(dsc, *pctm); *pctm = NULL; } n = IS_DSC(dsc->line, "%%+") ? 3 : 21; /* %%ViewingOrientation: */ while (IS_WHITE(dsc->line[n])) n++; /* ctm.xx = */ ctm.xy = ctm.yx = ctm.yy = 0.0; ctm.xx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); n += i; if (i) ctm.xy = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); n += i; if (i) ctm.yx = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); n += i; if (i) ctm.yy = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); if (i==0) { dsc_unknown(dsc); /* we didn't get all fields */ } else { *pctm = (CDSCCTM *)dsc_memalloc(dsc, sizeof(CDSCCTM)); if (*pctm == NULL) return CDSC_ERROR; /* no memory */ **pctm = ctm; } return CDSC_OK; } /* This is called before dsc_read_line(), since we may * need to skip a binary header which contains a new line * character */ dsc_private int dsc_scan_type(CDSC *dsc) { unsigned char *p; unsigned char *line = (unsigned char *)(dsc->data + dsc->data_index); int length = dsc->data_length - dsc->data_index; /* Types that should be known: * DSC * EPSF * PJL + any of above * ^D + any of above * DOS EPS * PDF * non-DSC */ /* First process any non PostScript headers */ /* At this stage we do not have a complete line */ if (length == 0) return CDSC_NEEDMORE; /* If we have already found a DOS EPS header, */ /* ignore all until the PostScript section */ if (dsc->skip_bytes) { int cnt = min(dsc->skip_bytes, (int)(dsc->data_length - dsc->data_index)); dsc->skip_bytes -= cnt; dsc->data_index += cnt; length -= cnt; line += cnt; if (dsc->skip_bytes != 0) return CDSC_NEEDMORE; } if (dsc->skip_pjl) { /* skip until first PostScript comment */ while (length >= 2) { while (length && !IS_EOL(line[0])) { /* skip until EOL character */ line++; dsc->data_index++; length--; } while ((length >= 2) && IS_EOL(line[0]) && IS_EOL(line[1])) { /* skip until EOL followed by non-EOL */ line++; dsc->data_index++; length--; } if (length < 2) return CDSC_NEEDMORE; if (IS_EOL(line[0]) && line[1]=='%') { line++; dsc->data_index++; length--; dsc->skip_pjl = FALSE; break; } else { line++; dsc->data_index++; length--; } } if (dsc->skip_pjl) return CDSC_NEEDMORE; } if (length == 0) return CDSC_NEEDMORE; if (line[0] == '\004') { line++; dsc->data_index++; length--; dsc->ctrld = TRUE; } if (line[0] == '\033') { /* possibly PJL */ if (length < 9) return CDSC_NEEDMORE; if (COMPARE(line, "\033%-12345X")) { dsc->skip_pjl = TRUE; /* skip until first PostScript comment */ dsc->pjl = TRUE; dsc->data_index += 9; return dsc_scan_type(dsc); } } if ((line[0]==0xc5) && (length < 4)) return CDSC_NEEDMORE; if ((line[0]==0xc5) && (line[1]==0xd0) && (line[2]==0xd3) && (line[3]==0xc6) ) { /* id is "EPSF" with bit 7 set */ /* read DOS EPS header, then ignore all bytes until the PS section */ if (length < 30) return CDSC_NEEDMORE; dsc->line = (char *)line; if (dsc_read_doseps(dsc)) return CDSC_ERROR; } else { if (length < 2) return CDSC_NEEDMORE; if ((line[0] == '%') && (line[1] == 'P')) { if (length < 5) return CDSC_NEEDMORE; if (COMPARE(line, "%PDF-")) { dsc->pdf = TRUE; dsc->scan_section = scan_comments; return CDSC_OK; } } } /* Finally process PostScript headers */ if (dsc_read_line(dsc) <= 0) return CDSC_NEEDMORE; dsc->dsc_version = dsc_add_line(dsc, dsc->line, dsc->line_length); if (COMPARE(dsc->line, "%!PS-Adobe")) { dsc->dsc = TRUE; dsc->begincomments = DSC_START(dsc); if (dsc->dsc_version == NULL) return CDSC_ERROR; /* no memory */ p = (unsigned char *)dsc->line + 14; while (IS_WHITE(*p)) p++; if (COMPARE(p, "EPSF-")) dsc->epsf = TRUE; dsc->scan_section = scan_comments; return CDSC_PSADOBE; } if (COMPARE(dsc->line, "%!")) { dsc->scan_section = scan_comments; return CDSC_NOTDSC; } dsc->scan_section = scan_comments; return CDSC_NOTDSC; /* unrecognised */ } dsc_private int dsc_scan_comments(CDSC *dsc) { /* Comments section ends at */ /* %%EndComments */ /* another section */ /* line that does not start with %% */ /* Save a few important lines */ char *line = dsc->line; GSBOOL continued = FALSE; dsc->id = CDSC_OK; if (IS_DSC(line, "%%EndComments")) { dsc->id = CDSC_ENDCOMMENTS; dsc->endcomments = DSC_END(dsc); dsc->scan_section = scan_pre_preview; return CDSC_OK; } else if (IS_DSC(line, "%%BeginComments")) { /* ignore because we are in this section */ dsc->id = CDSC_BEGINCOMMENTS; } else if (dsc_is_section(line)) { dsc->endcomments = DSC_START(dsc); dsc->scan_section = scan_pre_preview; return CDSC_PROPAGATE; } else if (line[0] == '%' && IS_WHITE_OR_EOL(line[1])) { dsc->endcomments = DSC_START(dsc); dsc->scan_section = scan_pre_preview; return CDSC_PROPAGATE; } else if (line[0] != '%') { dsc->id = CDSC_OK; dsc->endcomments = DSC_START(dsc); dsc->scan_section = scan_pre_preview; return CDSC_PROPAGATE; } else if (IS_DSC(line, "%%Begin")) { dsc->endcomments = DSC_START(dsc); dsc->scan_section = scan_pre_preview; return CDSC_PROPAGATE; } /* Handle continuation lines. * To simply processing, we assume that contination lines * will only occur if repeat parameters are allowed and that * a complete set of these parameters appears on each line. * This is more restrictive than the DSC specification, but * is valid for the DSC comments understood by this parser * for all documents that we have seen. */ if (IS_DSC(line, "%%+")) { line = dsc->last_line; continued = TRUE; } else dsc_save_line(dsc); if (IS_DSC(line, "%%Pages:")) { dsc->id = CDSC_PAGES; if (dsc_parse_pages(dsc) != 0) return CDSC_ERROR; } else if (IS_DSC(line, "%%Creator:")) { dsc->id = CDSC_CREATOR; dsc->dsc_creator = dsc_add_line(dsc, dsc->line+10, dsc->line_length-10); if (dsc->dsc_creator==NULL) return CDSC_ERROR; } else if (IS_DSC(line, "%%CreationDate:")) { dsc->id = CDSC_CREATIONDATE; dsc->dsc_date = dsc_add_line(dsc, dsc->line+15, dsc->line_length-15); if (dsc->dsc_date==NULL) return CDSC_ERROR; } else if (IS_DSC(line, "%%Title:")) { dsc->id = CDSC_TITLE; dsc->dsc_title = dsc_add_line(dsc, dsc->line+8, dsc->line_length-8); if (dsc->dsc_title==NULL) return CDSC_ERROR; } else if (IS_DSC(line, "%%For:")) { dsc->id = CDSC_FOR; dsc->dsc_for = dsc_add_line(dsc, dsc->line+6, dsc->line_length-6); if (dsc->dsc_for==NULL) return CDSC_ERROR; } else if (IS_DSC(line, "%%LanguageLevel:")) { unsigned int n = continued ? 3 : 16; unsigned int i; int ll; dsc->id = CDSC_LANGUAGELEVEL; ll = dsc_get_int(dsc->line+n, dsc->line_length-n, &i); if (i) { if ( (ll==1) || (ll==2) || (ll==3) ) dsc->language_level = ll; else { dsc_unknown(dsc); } } else dsc_unknown(dsc); } else if (IS_DSC(line, "%%BoundingBox:")) { dsc->id = CDSC_BOUNDINGBOX; if (dsc_parse_bounding_box(dsc, &(dsc->bbox), continued ? 3 : 14)) return CDSC_ERROR; } else if (IS_DSC(line, "%%HiResBoundingBox:")) { dsc->id = CDSC_HIRESBOUNDINGBOX; if (dsc_parse_float_bounding_box(dsc, &(dsc->hires_bbox), continued ? 3 : 19)) return CDSC_ERROR; } else if (IS_DSC(line, "%%CropBox:")) { dsc->id = CDSC_CROPBOX; if (dsc_parse_float_bounding_box(dsc, &(dsc->crop_box), continued ? 3 : 10)) return CDSC_ERROR; } else if (IS_DSC(line, "%%Orientation:")) { dsc->id = CDSC_ORIENTATION; if (dsc_parse_orientation(dsc, &(dsc->page_orientation), continued ? 3 : 14)) return CDSC_ERROR; } else if (IS_DSC(line, "%%PageOrder:")) { dsc->id = CDSC_PAGEORDER; if (dsc_parse_order(dsc)) return CDSC_ERROR; } else if (IS_DSC(line, "%%DocumentMedia:")) { dsc->id = CDSC_DOCUMENTMEDIA; if (dsc_parse_document_media(dsc)) return CDSC_ERROR; } else if (IS_DSC(line, "%%DocumentPaperSizes:")) { /* DSC 2.1 */ unsigned int n = continued ? 3 : 21; unsigned int count = 0; unsigned int i = 1; char name[MAXSTR]; char *p; dsc->id = CDSC_DOCUMENTPAPERSIZES; while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) { p = dsc_copy_string(name, sizeof(name)-1, dsc->line+n, dsc->line_length-n, &i); if (i && p) { const CDSCMEDIA *m = dsc_known_media; if (count >= dsc->media_count) { /* set some default values */ CDSCMEDIA lmedia; lmedia.name = p; lmedia.width = 595.0; lmedia.height = 842.0; lmedia.weight = 80.0; lmedia.colour = NULL; lmedia.type = NULL; lmedia.mediabox = NULL; if (dsc_add_media(dsc, &lmedia)) return CDSC_ERROR; } else dsc->media[count]->name = dsc_alloc_string(dsc, p, (int)strlen(p)); /* find in list of known media */ while (m && m->name) { if (dsc_stricmp(p, m->name)==0) { dsc->media[count]->width = m->width; dsc->media[count]->height = m->height; break; } m++; } } n+=i; count++; } } else if (IS_DSC(line, "%%DocumentPaperForms:")) { /* DSC 2.1 */ unsigned int n = continued ? 3 : 21; unsigned int count = 0; unsigned int i = 1; char type[MAXSTR]; char *p; dsc->id = CDSC_DOCUMENTPAPERFORMS; while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) { p = dsc_copy_string(type, sizeof(type)-1, dsc->line+n, dsc->line_length-n, &i); if (i && p) { if (count >= dsc->media_count) { /* set some default values */ CDSCMEDIA lmedia; lmedia.name = NULL; lmedia.width = 595.0; lmedia.height = 842.0; lmedia.weight = 80.0; lmedia.colour = NULL; lmedia.type = p; lmedia.mediabox = NULL; if (dsc_add_media(dsc, &lmedia)) return CDSC_ERROR; } else dsc->media[count]->type = dsc_alloc_string(dsc, p, (int)strlen(p)); } n+=i; count++; } } else if (IS_DSC(line, "%%DocumentPaperColors:")) { /* DSC 2.1 */ unsigned int n = continued ? 3 : 22; unsigned int count = 0; unsigned int i = 1; char colour[MAXSTR]; char *p; dsc->id = CDSC_DOCUMENTPAPERCOLORS; while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) { p = dsc_copy_string(colour, sizeof(colour)-1, dsc->line+n, dsc->line_length-n, &i); if (i && p) { if (count >= dsc->media_count) { /* set some default values */ CDSCMEDIA lmedia; lmedia.name = NULL; lmedia.width = 595.0; lmedia.height = 842.0; lmedia.weight = 80.0; lmedia.colour = p; lmedia.type = NULL; lmedia.mediabox = NULL; if (dsc_add_media(dsc, &lmedia)) return CDSC_ERROR; } else dsc->media[count]->colour = dsc_alloc_string(dsc, p, (int)strlen(p)); } n+=i; count++; } } else if (IS_DSC(line, "%%DocumentPaperWeights:")) { /* DSC 2.1 */ unsigned int n = continued ? 3 : 23; unsigned int count = 0; unsigned int i = 1; float w; dsc->id = CDSC_DOCUMENTPAPERWEIGHTS; while (i && (dsc->line[n]!='\r') && (dsc->line[n]!='\n')) { w = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); if (i) { if (count >= dsc->media_count) { /* set some default values */ CDSCMEDIA lmedia; lmedia.name = NULL; lmedia.width = 595.0; lmedia.height = 842.0; lmedia.weight = w; lmedia.colour = NULL; lmedia.type = NULL; lmedia.mediabox = NULL; if (dsc_add_media(dsc, &lmedia)) return CDSC_ERROR; } else dsc->media[count]->weight = w; } n+=i; count++; } } else if (IS_DSC(line, "%%DocumentData:")) { unsigned int n = continued ? 3 : 15; char *p = dsc->line + n; while (IS_WHITE(*p)) p++; dsc->id = CDSC_DOCUMENTDATA; if (COMPARE(p, "Clean7Bit")) dsc->document_data = CDSC_CLEAN7BIT; else if (COMPARE(p, "Clean8Bit")) dsc->document_data = CDSC_CLEAN8BIT; else if (COMPARE(p, "Binary")) dsc->document_data = CDSC_BINARY; else dsc_unknown(dsc); } else if (IS_DSC(line, "%%Requirements:")) { dsc->id = CDSC_REQUIREMENTS; /* ignore */ } else if (IS_DSC(line, "%%DocumentNeededFonts:")) { dsc->id = CDSC_DOCUMENTNEEDEDFONTS; /* ignore */ } else if (IS_DSC(line, "%%DocumentSuppliedFonts:")) { dsc->id = CDSC_DOCUMENTSUPPLIEDFONTS; /* ignore */ } else if (IS_DSC(line, "%%PlateFile:")) { dsc->id = CDSC_PLATEFILE; if (dsc_parse_platefile(dsc) != CDSC_OK) dsc->id = CDSC_UNKNOWNDSC; } else if (IS_DSC(line, "%%CyanPlate:") || IS_DSC(line, "%%MagentaPlate:") || IS_DSC(line, "%%YellowPlate:") || IS_DSC(line, "%%BlackPlate:")) { dsc->id = CDSC_PLATEFILE; if (dsc_parse_dcs1plate(dsc) != CDSC_OK) dsc->id = CDSC_UNKNOWNDSC; } else if (IS_DSC(line, "%%DocumentProcessColors:")) { dsc->id = CDSC_DOCUMENTPROCESSCOLORS; if (dsc_parse_process_colours(dsc) != CDSC_OK) dsc->id = CDSC_UNKNOWNDSC; } else if (IS_DSC(line, "%%DocumentCustomColors:")) { dsc->id = CDSC_DOCUMENTCUSTOMCOLORS; if (dsc_parse_custom_colours(dsc) != CDSC_OK) dsc->id = CDSC_UNKNOWNDSC; } else if (IS_DSC(line, "%%CMYKCustomColor:")) { dsc->id = CDSC_CMYKCUSTOMCOLOR; if (dsc_parse_cmyk_custom_colour(dsc) != CDSC_OK) dsc->id = CDSC_UNKNOWNDSC; } else if (IS_DSC(line, "%%RGBCustomColor:")) { dsc->id = CDSC_RGBCUSTOMCOLOR; if (dsc_parse_rgb_custom_colour(dsc) != CDSC_OK) dsc->id = CDSC_UNKNOWNDSC; } else if (dsc->line[0] == '%' && IS_WHITE_OR_EOL(dsc->line[1])) { dsc->id = CDSC_OK; /* ignore */ } else { dsc->id = CDSC_UNKNOWNDSC; dsc_unknown(dsc); } dsc->endcomments = DSC_END(dsc); return CDSC_OK; } dsc_private int dsc_scan_preview(CDSC *dsc) { /* Preview section ends at */ /* %%EndPreview */ /* another section */ /* Preview section must start with %%BeginPreview */ char *line = dsc->line; dsc->id = CDSC_OK; if (dsc->scan_section == scan_pre_preview) { if (IS_BLANK(line)) return CDSC_OK; /* ignore blank lines before preview */ else if (IS_DSC(line, "%%BeginPreview")) { dsc->id = CDSC_BEGINPREVIEW; dsc->beginpreview = DSC_START(dsc); dsc->endpreview = DSC_END(dsc); dsc->scan_section = scan_preview; /* Don't mark the preview as EPSI if a DOS EPS header is present */ if (dsc->preview == CDSC_NOPREVIEW) dsc->preview = CDSC_EPSI; return CDSC_OK; } else { dsc->scan_section = scan_pre_defaults; return CDSC_PROPAGATE; } } if (IS_DSC(line, "%%BeginPreview")) { /* ignore because we are in this section */ } else if (dsc_is_section(line)) { dsc->endpreview = DSC_START(dsc); dsc->scan_section = scan_pre_defaults; return CDSC_PROPAGATE; } else if (IS_DSC(line, "%%EndPreview")) { dsc->id = CDSC_ENDPREVIEW; dsc->endpreview = DSC_END(dsc); dsc->scan_section = scan_pre_defaults; return CDSC_OK; } else if (line[0] == '%' && line[1] != '%') { /* Ordinary comments are OK */ } else { dsc->id = CDSC_UNKNOWNDSC; /* DSC comments should not occur in preview */ dsc_unknown(dsc); } dsc->endpreview = DSC_END(dsc); return CDSC_OK; } dsc_private int dsc_scan_defaults(CDSC *dsc) { /* Defaults section ends at */ /* %%EndDefaults */ /* another section */ /* Defaults section must start with %%BeginDefaults */ char *line = dsc->line; dsc->id = CDSC_OK; if (dsc->scan_section == scan_pre_defaults) { if (IS_BLANK(line)) return CDSC_OK; /* ignore blank lines before defaults */ else if (IS_DSC(line, "%%BeginDefaults")) { dsc->id = CDSC_BEGINDEFAULTS; dsc->begindefaults = DSC_START(dsc); dsc->enddefaults = DSC_END(dsc); dsc->scan_section = scan_defaults; return CDSC_OK; } else { dsc->scan_section = scan_pre_prolog; return CDSC_PROPAGATE; } } if (NOT_DSC_LINE(line)) { /* ignore */ } else if (IS_DSC(line, "%%BeginPreview")) { /* ignore because we have already processed this section */ } else if (IS_DSC(line, "%%BeginDefaults")) { /* ignore because we are in this section */ } else if (dsc_is_section(line)) { dsc->enddefaults = DSC_START(dsc); dsc->scan_section = scan_pre_prolog; return CDSC_PROPAGATE; } else if (IS_DSC(line, "%%EndDefaults")) { dsc->id = CDSC_ENDDEFAULTS; dsc->enddefaults = DSC_END(dsc); dsc->scan_section = scan_pre_prolog; return CDSC_OK; } else if (IS_DSC(line, "%%PageMedia:")) { dsc->id = CDSC_PAGEMEDIA; dsc_parse_media(dsc, &dsc->page_media); } else if (IS_DSC(line, "%%PageOrientation:")) { dsc->id = CDSC_PAGEORIENTATION; /* This can override %%Orientation: */ if (dsc_parse_orientation(dsc, &(dsc->page_orientation), 18)) return CDSC_ERROR; } else if (IS_DSC(line, "%%PageBoundingBox:")) { dsc->id = CDSC_PAGEBOUNDINGBOX; if (dsc_parse_bounding_box(dsc, &(dsc->page_bbox), 18)) return CDSC_ERROR; } else if (IS_DSC(line, "%%ViewingOrientation:")) { dsc->id = CDSC_VIEWINGORIENTATION; if (dsc_parse_viewing_orientation(dsc, &dsc->viewing_orientation)) return CDSC_ERROR; } else if (IS_DSC(line, "%%PageCropBox:")) { dsc->id = CDSC_PAGECROPBOX; if (dsc_parse_float_bounding_box(dsc, &dsc->crop_box, 14)) return CDSC_ERROR; } else { dsc->id = CDSC_UNKNOWNDSC; /* All other DSC comments are unknown, but not an error */ dsc_unknown(dsc); } dsc->enddefaults = DSC_END(dsc); return CDSC_OK; } /* CDSC_RESPONSE_OK and CDSC_RESPONSE_CANCEL mean ignore the * mismatch (default) */ dsc_private int dsc_check_match_prompt(CDSC *dsc, const char *str, int count) { if (count != 0) { char buf[MAXSTR+MAXSTR]; if (dsc->line_length < (unsigned int)(sizeof(buf)/2-1)) { strncpy(buf, dsc->line, dsc->line_length); buf[dsc->line_length] = '\0'; } sprintf(buf+strlen(buf), "\n%%%%Begin%.40s: / %%%%End%.40s\n", str, str); return dsc_error(dsc, CDSC_MESSAGE_BEGIN_END, buf, (int)strlen(buf)); } return CDSC_RESPONSE_CANCEL; } dsc_private int dsc_check_match_type(CDSC *dsc, const char *str, int count) { if (dsc_check_match_prompt(dsc, str, count) == CDSC_RESPONSE_IGNORE_ALL) return CDSC_NOTDSC; return CDSC_OK; } /* complain if Begin/End blocks didn't match */ /* return non-zero if we should ignore all DSC */ dsc_private int dsc_check_match(CDSC *dsc) { int rc = 0; const char *font = "Font"; const char *feature = "Feature"; const char *resource = "Resource"; const char *procset = "ProcSet"; if (!rc) rc = dsc_check_match_type(dsc, font, dsc->begin_font_count); if (!rc) rc = dsc_check_match_type(dsc, feature, dsc->begin_feature_count); if (!rc) rc = dsc_check_match_type(dsc, resource, dsc->begin_resource_count); if (!rc) rc = dsc_check_match_type(dsc, procset, dsc->begin_procset_count); dsc->begin_font_count = 0; dsc->begin_feature_count = 0; dsc->begin_resource_count = 0; dsc->begin_procset_count = 0; return rc; } dsc_private int dsc_scan_prolog(CDSC *dsc) { /* Prolog section ends at */ /* %%EndProlog */ /* another section */ /* Prolog section may start with %%BeginProlog or non-dsc line */ char *line = dsc->line; dsc->id = CDSC_OK; if (dsc->scan_section == scan_pre_prolog) { if (dsc_is_section(line) && (!IS_DSC(line, "%%BeginProlog"))) { dsc->scan_section = scan_pre_setup; return CDSC_PROPAGATE; } dsc->id = CDSC_BEGINPROLOG; dsc->beginprolog = DSC_START(dsc); dsc->endprolog = DSC_END(dsc); dsc->scan_section = scan_prolog; if (IS_DSC(line, "%%BeginProlog")) return CDSC_OK; } if (NOT_DSC_LINE(line)) { /* ignore */ } else if (IS_DSC(line, "%%BeginPreview")) { /* ignore because we have already processed this section */ } else if (IS_DSC(line, "%%BeginDefaults")) { /* ignore because we have already processed this section */ } else if (IS_DSC(line, "%%BeginProlog")) { /* ignore because we are in this section */ } else if (dsc_is_section(line)) { dsc->endprolog = DSC_START(dsc); dsc->scan_section = scan_pre_setup; if (dsc_check_match(dsc)) return CDSC_NOTDSC; return CDSC_PROPAGATE; } else if (IS_DSC(line, "%%EndProlog")) { dsc->id = CDSC_ENDPROLOG; dsc->endprolog = DSC_END(dsc); dsc->scan_section = scan_pre_setup; if (dsc_check_match(dsc)) return CDSC_NOTDSC; return CDSC_OK; } else if (IS_DSC(line, "%%BeginFont:")) { dsc->id = CDSC_BEGINFONT; /* ignore Begin/EndFont, apart form making sure */ /* that they are matched. */ dsc->begin_font_count++; } else if (IS_DSC(line, "%%EndFont")) { dsc->id = CDSC_ENDFONT; dsc->begin_font_count--; } else if (IS_DSC(line, "%%BeginFeature:")) { dsc->id = CDSC_BEGINFEATURE; /* ignore Begin/EndFeature, apart form making sure */ /* that they are matched. */ dsc->begin_feature_count++; } else if (IS_DSC(line, "%%EndFeature")) { dsc->id = CDSC_ENDFEATURE; dsc->begin_feature_count--; } else if (IS_DSC(line, "%%BeginResource:")) { dsc->id = CDSC_BEGINRESOURCE; /* ignore Begin/EndResource, apart form making sure */ /* that they are matched. */ dsc->begin_resource_count++; } else if (IS_DSC(line, "%%EndResource")) { dsc->id = CDSC_ENDRESOURCE; dsc->begin_resource_count--; } else if (IS_DSC(line, "%%BeginProcSet:")) { dsc->id = CDSC_BEGINPROCSET; /* ignore Begin/EndProcSet, apart form making sure */ /* that they are matched. */ dsc->begin_procset_count++; } else if (IS_DSC(line, "%%EndProcSet")) { dsc->id = CDSC_ENDPROCSET; dsc->begin_procset_count--; } else { /* All other DSC comments are unknown, but not an error */ dsc->id = CDSC_UNKNOWNDSC; dsc_unknown(dsc); } dsc->endprolog = DSC_END(dsc); return CDSC_OK; } dsc_private int dsc_scan_setup(CDSC *dsc) { /* Setup section ends at */ /* %%EndSetup */ /* another section */ /* Setup section must start with %%BeginSetup */ char *line = dsc->line; dsc->id = CDSC_OK; if (dsc->scan_section == scan_pre_setup) { if (IS_BLANK(line)) return CDSC_OK; /* ignore blank lines before setup */ else if (IS_DSC(line, "%%BeginSetup")) { dsc->id = CDSC_BEGINSETUP; dsc->beginsetup = DSC_START(dsc); dsc->endsetup = DSC_END(dsc); dsc->scan_section = scan_setup; return CDSC_OK; } else { dsc->scan_section = scan_pre_pages; return CDSC_PROPAGATE; } } if (NOT_DSC_LINE(line)) { /* ignore */ } else if (IS_DSC(line, "%%BeginPreview")) { /* ignore because we have already processed this section */ } else if (IS_DSC(line, "%%BeginDefaults")) { /* ignore because we have already processed this section */ } else if (IS_DSC(line, "%%BeginProlog")) { /* ignore because we have already processed this section */ } else if (IS_DSC(line, "%%BeginSetup")) { /* ignore because we are in this section */ } else if (dsc_is_section(line)) { dsc->endsetup = DSC_START(dsc); dsc->scan_section = scan_pre_pages; if (dsc_check_match(dsc)) return CDSC_NOTDSC; return CDSC_PROPAGATE; } else if (IS_DSC(line, "%%EndSetup")) { dsc->id = CDSC_ENDSETUP; dsc->endsetup = DSC_END(dsc); dsc->scan_section = scan_pre_pages; if (dsc_check_match(dsc)) return CDSC_NOTDSC; return CDSC_OK; } else if (IS_DSC(line, "%%BeginFeature:")) { dsc->id = CDSC_BEGINFEATURE; /* ignore Begin/EndFeature, apart form making sure */ /* that they are matched. */ dsc->begin_feature_count++; } else if (IS_DSC(line, "%%EndFeature")) { dsc->id = CDSC_ENDFEATURE; dsc->begin_feature_count--; } else if (IS_DSC(line, "%%Feature:")) { dsc->id = CDSC_FEATURE; /* ignore */ } else if (IS_DSC(line, "%%BeginResource:")) { dsc->id = CDSC_BEGINRESOURCE; /* ignore Begin/EndResource, apart form making sure */ /* that they are matched. */ dsc->begin_resource_count++; } else if (IS_DSC(line, "%%EndResource")) { dsc->id = CDSC_ENDRESOURCE; dsc->begin_resource_count--; } else if (IS_DSC(line, "%%PaperColor:")) { dsc->id = CDSC_PAPERCOLOR; /* ignore */ } else if (IS_DSC(line, "%%PaperForm:")) { dsc->id = CDSC_PAPERFORM; /* ignore */ } else if (IS_DSC(line, "%%PaperWeight:")) { dsc->id = CDSC_PAPERWEIGHT; /* ignore */ } else if (IS_DSC(line, "%%PaperSize:")) { /* DSC 2.1 */ GSBOOL found_media = FALSE; int i; int n = 12; char buf[MAXSTR]; buf[0] = '\0'; dsc->id = CDSC_PAPERSIZE; dsc_copy_string(buf, sizeof(buf)-1, dsc->line+n, dsc->line_length-n, NULL); for (i=0; i<(int)dsc->media_count; i++) { if (dsc->media[i] && dsc->media[i]->name && (dsc_stricmp(buf, dsc->media[i]->name)==0)) { dsc->page_media = dsc->media[i]; found_media = TRUE; break; } } if (!found_media) { /* It didn't match %%DocumentPaperSizes: */ /* Try our known media */ const CDSCMEDIA *m = dsc_known_media; while (m->name) { if (dsc_stricmp(buf, m->name)==0) { dsc->page_media = m; break; } m++; } if (m->name == NULL) dsc_unknown(dsc); } } else { /* All other DSC comments are unknown, but not an error */ dsc->id = CDSC_UNKNOWNDSC; dsc_unknown(dsc); } dsc->endsetup = DSC_END(dsc); return CDSC_OK; } dsc_private int dsc_scan_page(CDSC *dsc) { /* Page section ends at */ /* %%Page */ /* %%Trailer */ /* %%EOF */ char *line = dsc->line; dsc->id = CDSC_OK; if (dsc->scan_section == scan_pre_pages) { if (IS_DSC(line, "%%Page:")) { dsc->scan_section = scan_pages; /* fall through */ } else { /* %%Page: didn't follow %%EndSetup * Keep reading until reach %%Page or %%Trailer * and add it to previous section. */ DSC_OFFSET *last; if (dsc->endsetup != 0) last = &dsc->endsetup; else if (dsc->endprolog != 0) last = &dsc->endprolog; else if (dsc->enddefaults != 0) last = &dsc->enddefaults; else if (dsc->endpreview != 0) last = &dsc->endpreview; else if (dsc->endcomments != 0) last = &dsc->endcomments; else last = &dsc->begincomments; *last = DSC_START(dsc); if (IS_DSC(line, "%%Trailer") || IS_DSC(line, "%%EOF")) { dsc->scan_section = scan_pre_trailer; return CDSC_PROPAGATE; } *last = DSC_END(dsc); return CDSC_OK; } } if (NOT_DSC_LINE(line)) { /* ignore */ } else if (IS_DSC(line, "%%Page:")) { int code; dsc->id = CDSC_PAGE; if (dsc->page_count) { dsc->page[dsc->page_count-1].end = DSC_START(dsc); if (dsc_check_match(dsc)) return CDSC_NOTDSC; } if ( (code = dsc_parse_page(dsc)) != CDSC_OK) return code; if (dsc->page_count == 0) dsc->scan_section = scan_pre_pages; } else if (IS_DSC(line, "%%BeginPreview")) { /* ignore because we have already processed this section */ } else if (IS_DSC(line, "%%BeginDefaults")) { /* ignore because we have already processed this section */ } else if (IS_DSC(line, "%%BeginProlog")) { /* ignore because we have already processed this section */ } else if (IS_DSC(line, "%%BeginSetup")) { /* ignore because we have already processed this section */ } else if (dsc_is_section(line)) { if (IS_DSC(line, "%%Trailer")) { if (dsc->page_count) dsc->page[dsc->page_count-1].end = DSC_START(dsc); if (dsc->file_length) { if ((!dsc->doseps && ((DSC_END(dsc) + 32768) < dsc->file_length)) || ((dsc->doseps) && ((DSC_END(dsc) + 32768) < dsc->doseps_end))) { int rc = dsc_error(dsc, CDSC_MESSAGE_EARLY_TRAILER, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: /* ignore early trailer */ break; case CDSC_RESPONSE_CANCEL: /* this is the trailer */ dsc->scan_section = scan_pre_trailer; if (dsc_check_match(dsc)) return CDSC_NOTDSC; return CDSC_PROPAGATE; case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } else { dsc->scan_section = scan_pre_trailer; if (dsc_check_match(dsc)) return CDSC_NOTDSC; return CDSC_PROPAGATE; } } else { dsc->scan_section = scan_pre_trailer; if (dsc_check_match(dsc)) return CDSC_NOTDSC; return CDSC_PROPAGATE; } } else if (IS_DSC(line, "%%EOF")) { if (dsc->page_count) dsc->page[dsc->page_count-1].end = DSC_START(dsc); if (dsc->file_length) { if ((DSC_END(dsc)+100 < dsc->file_length) || (dsc->doseps && (DSC_END(dsc) + 100 < dsc->doseps_end))) { int rc = dsc_error(dsc, CDSC_MESSAGE_EARLY_EOF, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: /* %%EOF is wrong, ignore it */ break; case CDSC_RESPONSE_CANCEL: /* %%EOF is correct */ dsc->scan_section = scan_eof; dsc->eof = TRUE; if (dsc_check_match(dsc)) return CDSC_NOTDSC; return CDSC_PROPAGATE; case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } } else { /* ignore it */ if (dsc_check_match(dsc)) return CDSC_NOTDSC; return CDSC_OK; } } else { /* Section comment, probably from a badly */ /* encapsulated EPS file. */ int rc = dsc_error(dsc, CDSC_MESSAGE_BAD_SECTION, dsc->line, dsc->line_length); if (rc == CDSC_RESPONSE_IGNORE_ALL) return CDSC_NOTDSC; } } else if (IS_DSC(line, "%%PageTrailer")) { dsc->id = CDSC_PAGETRAILER; /* ignore */ } else if (IS_DSC(line, "%%BeginPageSetup")) { dsc->id = CDSC_BEGINPAGESETUP; /* ignore */ } else if (IS_DSC(line, "%%EndPageSetup")) { dsc->id = CDSC_ENDPAGESETUP; /* ignore */ } else if (IS_DSC(line, "%%PageMedia:")) { dsc->id = CDSC_PAGEMEDIA; if (dsc->page_count) dsc_parse_media(dsc, &(dsc->page[dsc->page_count-1].media)); } else if (IS_DSC(line, "%%PaperColor:")) { dsc->id = CDSC_PAPERCOLOR; /* ignore */ } else if (IS_DSC(line, "%%PaperForm:")) { dsc->id = CDSC_PAPERFORM; /* ignore */ } else if (IS_DSC(line, "%%PaperWeight:")) { dsc->id = CDSC_PAPERWEIGHT; /* ignore */ } else if (IS_DSC(line, "%%PaperSize:")) { /* DSC 2.1 */ GSBOOL found_media = FALSE; int i; int n = 12; char buf[MAXSTR]; buf[0] = '\0'; dsc_copy_string(buf, sizeof(buf)-1, dsc->line+n, dsc->line_length-n, NULL); for (i=0; i<(int)dsc->media_count; i++) { if (dsc->media[i] && dsc->media[i]->name && (dsc_stricmp(buf, dsc->media[i]->name)==0)) { if (dsc->page_count) dsc->page[dsc->page_count-1].media = dsc->media[i]; found_media = TRUE; break; } } if (!found_media) { /* It didn't match %%DocumentPaperSizes: */ /* Try our known media */ const CDSCMEDIA *m = dsc_known_media; while (m->name) { if (dsc_stricmp(buf, m->name)==0) { if (dsc->page_count) dsc->page[dsc->page_count-1].media = m; break; } m++; } if (m->name == NULL) dsc_unknown(dsc); } } else if (IS_DSC(line, "%%PageOrientation:")) { if (dsc->page_count) { dsc->id = CDSC_PAGEORIENTATION; if (dsc_parse_orientation(dsc, &(dsc->page[dsc->page_count-1].orientation) ,18)) return CDSC_NOTDSC; } } else if (IS_DSC(line, "%%PageBoundingBox:")) { if (dsc->page_count) { dsc->id = CDSC_PAGEBOUNDINGBOX; if (dsc_parse_bounding_box(dsc, &dsc->page[dsc->page_count-1].bbox, 18)) return CDSC_NOTDSC; } } else if (IS_DSC(line, "%%ViewingOrientation:")) { if (dsc->page_count) { dsc->id = CDSC_VIEWINGORIENTATION; if (dsc_parse_viewing_orientation(dsc, &dsc->page[dsc->page_count-1].viewing_orientation)) return CDSC_ERROR; } } else if (IS_DSC(line, "%%PageCropBox:")) { if (dsc->page_count) { dsc->id = CDSC_PAGECROPBOX; if (dsc_parse_float_bounding_box(dsc, &(dsc->page[dsc->page_count-1].crop_box), 14)) return CDSC_ERROR; } } else if (IS_DSC(line, "%%BeginFont:")) { dsc->id = CDSC_BEGINFONT; /* ignore Begin/EndFont, apart form making sure */ /* that they are matched. */ dsc->begin_font_count++; } else if (IS_DSC(line, "%%EndFont")) { dsc->id = CDSC_BEGINFONT; dsc->begin_font_count--; } else if (IS_DSC(line, "%%BeginFeature:")) { dsc->id = CDSC_BEGINFEATURE; /* ignore Begin/EndFeature, apart form making sure */ /* that they are matched. */ dsc->begin_feature_count++; } else if (IS_DSC(line, "%%EndFeature")) { dsc->id = CDSC_ENDFEATURE; dsc->begin_feature_count--; } else if (IS_DSC(line, "%%BeginResource:")) { dsc->id = CDSC_BEGINRESOURCE; /* ignore Begin/EndResource, apart form making sure */ /* that they are matched. */ dsc->begin_resource_count++; } else if (IS_DSC(line, "%%EndResource")) { dsc->id = CDSC_ENDRESOURCE; dsc->begin_resource_count--; } else if (IS_DSC(line, "%%BeginProcSet:")) { dsc->id = CDSC_BEGINPROCSET; /* ignore Begin/EndProcSet, apart form making sure */ /* that they are matched. */ dsc->begin_procset_count++; } else if (IS_DSC(line, "%%EndProcSet")) { dsc->id = CDSC_ENDPROCSET; dsc->begin_procset_count--; } else if (IS_DSC(line, "%%IncludeFont:")) { dsc->id = CDSC_INCLUDEFONT; /* ignore */ } else { /* All other DSC comments are unknown, but not an error */ dsc->id = CDSC_UNKNOWNDSC; dsc_unknown(dsc); } if (dsc->page_count) dsc->page[dsc->page_count-1].end = DSC_END(dsc); return CDSC_OK; } /* Valid Trailer comments are * %%Trailer * %%EOF * or the following deferred with (atend) * %%BoundingBox: * %%DocumentCustomColors: * %%DocumentFiles: * %%DocumentFonts: * %%DocumentNeededFiles: * %%DocumentNeededFonts: * %%DocumentNeededProcSets: * %%DocumentNeededResources: * %%DocumentProcSets: * %%DocumentProcessColors: * %%DocumentSuppliedFiles: * %%DocumentSuppliedFonts: * %%DocumentSuppliedProcSets: * %%DocumentSuppliedResources: * %%Orientation: * %%Pages: * %%PageOrder: * * Our supported subset is * %%Trailer * %%EOF * %%BoundingBox: * %%Orientation: * %%Pages: * %%PageOrder: * In addition to these, we support * %%DocumentMedia: * * A %%PageTrailer can have the following: * %%PageBoundingBox: * %%PageCustomColors: * %%PageFiles: * %%PageFonts: * %%PageOrientation: * %%PageProcessColors: * %%PageResources: */ dsc_private int dsc_scan_trailer(CDSC *dsc) { /* Trailer section start at */ /* %%Trailer */ /* and ends at */ /* %%EOF */ char *line = dsc->line; GSBOOL continued = FALSE; dsc->id = CDSC_OK; if (dsc->scan_section == scan_pre_trailer) { if (IS_DSC(line, "%%Trailer")) { dsc->id = CDSC_TRAILER; dsc->begintrailer = DSC_START(dsc); dsc->endtrailer = DSC_END(dsc); dsc->scan_section = scan_trailer; return CDSC_OK; } else if (IS_DSC(line, "%%EOF")) { dsc->id = CDSC_EOF; dsc->begintrailer = DSC_START(dsc); dsc->endtrailer = DSC_END(dsc); dsc->scan_section = scan_trailer; /* Continue, in case we found %%EOF in an embedded document */ return CDSC_OK; } else { /* %%Page: didn't follow %%EndSetup * Keep reading until reach %%Page or %%Trailer * and add it to setup section */ /* append to previous section */ if (dsc->beginsetup) dsc->endsetup = DSC_END(dsc); else if (dsc->beginprolog) dsc->endprolog = DSC_END(dsc); else { /* horribly confused */ } return CDSC_OK; } } /* Handle continuation lines. * See comment above about our restrictive processing of * continuation lines */ if (IS_DSC(line, "%%+")) { line = dsc->last_line; continued = TRUE; } else dsc_save_line(dsc); if (NOT_DSC_LINE(line)) { /* ignore */ } else if (IS_DSC(dsc->line, "%%EOF")) { /* Keep scanning, in case we have a false trailer */ dsc->id = CDSC_EOF; } else if (IS_DSC(dsc->line, "%%Trailer")) { /* Cope with no pages with code after setup and before trailer. */ /* Last trailer is the correct one. */ dsc->id = CDSC_TRAILER; dsc->begintrailer = DSC_START(dsc); } else if (IS_DSC(line, "%%Pages:")) { dsc->id = CDSC_PAGES; if (dsc_parse_pages(dsc) != 0) return CDSC_ERROR; } else if (IS_DSC(line, "%%BoundingBox:")) { dsc->id = CDSC_BOUNDINGBOX; if (dsc_parse_bounding_box(dsc, &(dsc->bbox), continued ? 3 : 14)) return CDSC_ERROR; } else if (IS_DSC(line, "%%HiResBoundingBox:")) { dsc->id = CDSC_HIRESBOUNDINGBOX; if (dsc_parse_float_bounding_box(dsc, &(dsc->hires_bbox), continued ? 3 : 19)) return CDSC_ERROR; } else if (IS_DSC(line, "%%CropBox:")) { dsc->id = CDSC_CROPBOX; if (dsc_parse_float_bounding_box(dsc, &(dsc->crop_box), continued ? 3 : 10)) return CDSC_ERROR; } else if (IS_DSC(line, "%%Orientation:")) { dsc->id = CDSC_ORIENTATION; if (dsc_parse_orientation(dsc, &(dsc->page_orientation), continued ? 3 : 14)) return CDSC_ERROR; } else if (IS_DSC(line, "%%PageOrder:")) { dsc->id = CDSC_PAGEORDER; if (dsc_parse_order(dsc)) return CDSC_ERROR; } else if (IS_DSC(line, "%%DocumentMedia:")) { dsc->id = CDSC_DOCUMENTMEDIA; if (dsc_parse_document_media(dsc)) return CDSC_ERROR; } else if (IS_DSC(dsc->line, "%%Page:")) { /* This should not occur in the trailer, but we might see * this if a document has been incorrectly embedded. */ int rc = dsc_error(dsc, CDSC_MESSAGE_PAGE_IN_TRAILER, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: /* Assume that we are really in the previous */ /* page, not the trailer */ dsc->scan_section = scan_pre_pages; if (dsc->page_count) dsc->page[dsc->page_count-1].end = DSC_START(dsc); return CDSC_PROPAGATE; /* try again */ case CDSC_RESPONSE_CANCEL: /* ignore pages in trailer */ break; case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } else if (IS_DSC(line, "%%DocumentNeededFonts:")) { dsc->id = CDSC_DOCUMENTNEEDEDFONTS; /* ignore */ } else if (IS_DSC(line, "%%DocumentSuppliedFonts:")) { dsc->id = CDSC_DOCUMENTSUPPLIEDFONTS; /* ignore */ } else { /* All other DSC comments are unknown, but not an error */ dsc->id = CDSC_UNKNOWNDSC; dsc_unknown(dsc); } dsc->endtrailer = DSC_END(dsc); return CDSC_OK; } dsc_private char * dsc_alloc_string(CDSC *dsc, const char *str, int len) { char *p; if (dsc->string_head == NULL) { dsc->string_head = (CDSCSTRING *)dsc_memalloc(dsc, sizeof(CDSCSTRING)); if (dsc->string_head == NULL) return NULL; /* no memory */ dsc->string = dsc->string_head; dsc->string->next = NULL; dsc->string->data = (char *)dsc_memalloc(dsc, CDSC_STRING_CHUNK); if (dsc->string->data == NULL) { dsc_reset(dsc); return NULL; /* no memory */ } dsc->string->index = 0; dsc->string->length = CDSC_STRING_CHUNK; } if ( dsc->string->index + len + 1 > dsc->string->length) { /* allocate another string block */ CDSCSTRING *newstring = (CDSCSTRING *)dsc_memalloc(dsc, sizeof(CDSCSTRING)); if (newstring == NULL) { dsc_debug_print(dsc, "Out of memory\n"); return NULL; } newstring->next = NULL; newstring->length = 0; newstring->index = 0; newstring->data = (char *)dsc_memalloc(dsc, CDSC_STRING_CHUNK); if (newstring->data == NULL) { dsc_memfree(dsc, newstring); dsc_debug_print(dsc, "Out of memory\n"); return NULL; /* no memory */ } newstring->length = CDSC_STRING_CHUNK; dsc->string->next = newstring; dsc->string = newstring; } if ( dsc->string->index + len + 1 > dsc->string->length) return NULL; /* failed */ p = dsc->string->data + dsc->string->index; memcpy(p, str, len); *(p+len) = '\0'; dsc->string->index += len + 1; return p; } /* store line, ignoring leading spaces */ dsc_private char * dsc_add_line(CDSC *dsc, const char *line, unsigned int len) { char *newline; unsigned int i; while (len && (IS_WHITE(*line))) { len--; line++; } newline = dsc_alloc_string(dsc, line, len); if (newline == NULL) return NULL; for (i=0; i slen) len = slen-1; while ( (i= '0') && (ch <= '9')) { /* octal coded character */ int j = 3; ch = 0; while (j && (i < len) && line[i]>='0' && line[i]<='7') { ch = (unsigned char)((ch<<3) + (line[i]-'0')); i++; j--; } str[newlength] = ch; } else if (ch == '(') { str[newlength] = ch; i++; } else if (ch == ')') { str[newlength] = ch; i++; } else if (ch == 'b') { str[newlength] = '\b'; i++; } else if (ch == 'f') { str[newlength] = '\b'; i++; } else if (ch == 'n') { str[newlength] = '\n'; i++; } else if (ch == 'r') { str[newlength] = '\r'; i++; } else if (ch == 't') { str[newlength] = '\t'; i++; } else if (ch == '\\') { str[newlength] = '\\'; i++; } } newlength++; } str[newlength] = '\0'; if (offset != (unsigned int *)NULL) *offset = i; return str; } dsc_private int dsc_get_int(const char *line, unsigned int len, unsigned int *offset) { char newline[MAXSTR]; int newlength = 0; unsigned int i = 0; unsigned char ch; len = min(len, sizeof(newline)-1); while ((iline + 7; pl = dsc_copy_string(page_label, sizeof(page_label), p, dsc->line_length-7, &i); if (pl == NULL) return CDSC_ERROR; p += i; if (dsc->line_length - 7 - i == 0) { /* Ordinal missing, or parentheses not matched in label */ /* Try to find ordinal at end of line */ while (i > 0) { if (!IS_WHITE_OR_EOL(p[-1])) break; p--; i--; } while (i > 0) { if (!isdigit(p[-1])) break; p--; i--; } } page_ordinal = dsc_get_int(p, dsc->line_length - 7 - i, NULL); if ( (page_ordinal == 0) || (strlen(page_label) == 0) || (dsc->page_count && (page_ordinal != dsc->page[dsc->page_count-1].ordinal+1)) ) { int rc = dsc_error(dsc, CDSC_MESSAGE_PAGE_ORDINAL, dsc->line, dsc->line_length); switch (rc) { case CDSC_RESPONSE_OK: /* ignore this page */ return CDSC_OK; case CDSC_RESPONSE_CANCEL: /* accept the page */ break; case CDSC_RESPONSE_IGNORE_ALL: return CDSC_NOTDSC; } } page_number = dsc->page_count; dsc_add_page(dsc, page_ordinal, page_label); dsc->page[page_number].begin = DSC_START(dsc); dsc->page[page_number].end = DSC_START(dsc); if (dsc->page[page_number].label == NULL) return CDSC_ERROR; /* no memory */ return CDSC_OK; } /* DSC error reporting */ void dsc_debug_print(CDSC *dsc, const char *str) { if (dsc->debug_print_fn) dsc->debug_print_fn(dsc->caller_data, str); } /* Display a message about a problem with the DSC comments. * * explanation = an index to to a multiline explanation in dsc_message[] * line = pointer to the offending DSC line (if any) * return code = * CDSC_RESPONSE_OK DSC was wrong, make a guess about what * was really meant. * CDSC_RESPONSE_CANCEL Assume DSC was correct, ignore if it * is misplaced. * CDSC_RESPONSE_IGNORE_ALL Ignore all DSC. */ /* Silent operation. Don't display errors. */ dsc_private int dsc_error(CDSC *dsc, unsigned int explanation, char *line, unsigned int line_len) { /* if error function provided, use it */ if (dsc->dsc_error_fn) return dsc->dsc_error_fn(dsc->caller_data, dsc, explanation, line, line_len); /* treat DSC as being correct */ return CDSC_RESPONSE_CANCEL; } /* Fixup if DCS 2.0 was used */ dsc_private int dsc_dcs2_fixup(CDSC *dsc) { char composite[] = "Composite"; /* If DCS 2.0 single file format found, expose the separations * as multiple pages. Treat the initial EPS file as a single * page without comments, prolog or trailer. */ if (dsc->dcs2) { int code = CDSC_OK; int page_number; DSC_OFFSET *pbegin; DSC_OFFSET *pend; DSC_OFFSET end; CDCS2 *pdcs = dsc->dcs2; /* Now treat the initial EPS file as a single page without * headers or trailer, so page extraction will fetch the * the correct separation. */ if (dsc->page_count == 0) code = dsc_add_page(dsc, 1, composite); else if (dsc->page_count == 1) dsc->page[0].label = dsc_alloc_string(dsc, composite, (int)strlen(composite)+1); if (code != CDSC_OK) return code; page_number = dsc->page_count - 1; pbegin = &dsc->page[page_number].begin; pend = &dsc->page[page_number].end; if (*pbegin == *pend) { /* no page, so force it to conform to the following sections */ *pbegin = 999999999; *pend = 0; } if (dsc->begincomments != dsc->endcomments) { *pbegin = min(dsc->begincomments, *pbegin); dsc->begincomments = 0; *pend = max(dsc->endcomments, *pend); dsc->endcomments = 0; } if (dsc->beginpreview != dsc->endpreview) { *pbegin = min(dsc->beginpreview, *pbegin); dsc->beginpreview = 0; *pend = max(dsc->endpreview, *pend); dsc->endpreview = 0; } if (dsc->begindefaults != dsc->enddefaults) { *pbegin = min(dsc->begindefaults, *pbegin); dsc->begindefaults = 0; *pend = max(dsc->enddefaults, *pend); dsc->enddefaults = 0; } if (dsc->beginprolog != dsc->endprolog) { *pbegin = min(dsc->beginprolog, *pbegin); dsc->beginprolog = 0; *pend = max(dsc->endprolog, *pend); dsc->endprolog = 0; } if (dsc->beginsetup != dsc->endsetup) { *pbegin = min(dsc->beginsetup, *pbegin); dsc->beginsetup = 0; *pend = max(dsc->endsetup, *pend); dsc->endsetup = 0; } if (dsc->begintrailer != dsc->endtrailer) { *pbegin = min(dsc->begintrailer, *pbegin); dsc->begintrailer = 0; *pend = max(dsc->endtrailer, *pend); dsc->endtrailer = 0; } if (*pbegin == 999999999) *pbegin = *pend; end = 0; /* end of composite is start of first separation */ while (pdcs) { page_number = dsc->page_count; if ((pdcs->begin) && (pdcs->colourname != NULL)) { /* Single file DCS 2.0 */ code = dsc_add_page(dsc, page_number+1, pdcs->colourname); if (code) return code; dsc->page[page_number].begin = pdcs->begin; dsc->page[page_number].end = pdcs->end; if (end != 0) end = min(end, pdcs->begin); else end = pdcs->begin; /* first separation */ } else { /* Multiple file DCS 2.0 */ if ((pdcs->location != NULL) && (pdcs->filetype != NULL) && (pdcs->colourname != NULL) && (dsc_stricmp(pdcs->location, "Local") == 0) && ((dsc_stricmp(pdcs->filetype, "EPS") == 0) || (dsc_stricmp(pdcs->filetype, "EPSF") == 0))) { code = dsc_add_page(dsc, page_number+1, pdcs->colourname); if (code) return code; dsc->page[page_number].begin = 0; dsc->page[page_number].end = 0; } } pdcs = pdcs->next; } /* end of composite is start of first separation */ if (end != 0) *pend = end; } return 0; } dsc_private int dsc_parse_platefile(CDSC *dsc) { unsigned int i, n; CDCS2 dcs2; CDCS2 *pdcs2; char colourname[MAXSTR]; char filetype[MAXSTR]; char location[MAXSTR]; char *filename = NULL; int filename_length = 0; GSBOOL blank_line; GSBOOL single = FALSE; if (IS_DSC(dsc->line, "%%PlateFile:")) n = 12; else if (IS_DSC(dsc->line, "%%+")) n = 3; else return CDSC_ERROR; /* error */ memset(&dcs2, 0, sizeof(dcs2)); memset(&colourname, 0, sizeof(colourname)); memset(&filetype, 0, sizeof(filetype)); memset(&location, 0, sizeof(location)); memset(&filename, 0, sizeof(filename)); /* check for blank remainder of line */ blank_line = TRUE; for (i=n; iline_length; i++) { if (!IS_WHITE_OR_EOL(dsc->line[i])) { blank_line = FALSE; break; } } if (!blank_line) { dsc_copy_string(colourname, sizeof(colourname), dsc->line+n, dsc->line_length-n, &i); n+=i; if (i) dsc_copy_string(filetype, sizeof(filetype), dsc->line+n, dsc->line_length-n, &i); n+=i; while (IS_WHITE_OR_EOL(dsc->line[n])) n++; if (dsc->line[n] == '#') { /* single file DCS 2.0 */ single = TRUE; n++; if (i) dcs2.begin= dsc_get_int(dsc->line+n, dsc->line_length-n, &i); n+=i; if (i) dcs2.end= dcs2.begin + dsc_get_int(dsc->line+n, dsc->line_length-n, &i); } else { /* multiple file DCS 2.0 */ if (i) dsc_copy_string(location, sizeof(location), dsc->line+n, dsc->line_length-n, &i); n+=i; if (i) { filename = dsc->line+n; filename_length = dsc->line_length-n; } } if (i==0) dsc_unknown(dsc); /* we didn't get all fields */ else { /* Allocate strings */ if (strlen(colourname)) dcs2.colourname = dsc_alloc_string(dsc, colourname, (int)strlen(colourname)); if (strlen(filetype)) dcs2.filetype = dsc_alloc_string(dsc, filetype, (int)strlen(filetype)); if (strlen(location)) dcs2.location = dsc_alloc_string(dsc, location, (int)strlen(location)); if (filename) dcs2.filename = dsc_add_line(dsc, filename, filename_length); /* Prevent parser from reading separations */ if (single) dsc->file_length = min(dsc->file_length, dcs2.begin); /* Allocate it */ pdcs2 = (CDCS2 *)dsc_memalloc(dsc, sizeof(CDCS2)); if (pdcs2 == NULL) return CDSC_ERROR; /* out of memory */ memcpy(pdcs2, &dcs2, sizeof(CDCS2)); /* Then add to list of separations */ if (dsc->dcs2 == NULL) dsc->dcs2 = pdcs2; else { CDCS2 *this_dcs2 = dsc->dcs2; while (this_dcs2->next) this_dcs2 = this_dcs2->next; this_dcs2->next = pdcs2; } } } return CDSC_OK; } /* Parse a DCS 1.0 plate comment, storing like a multi file DSC 2.0 */ dsc_private int dsc_parse_dcs1plate(CDSC *dsc) { unsigned int i, n = 0; CDCS2 dcs2; CDCS2 *pdcs2; const char *colourname; char filename[MAXSTR]; GSBOOL blank_line; GSBOOL continued = FALSE; char *line = dsc->line; memset(&dcs2, 0, sizeof(dcs2)); memset(&filename, 0, sizeof(filename)); if (IS_DSC(line, "%%+")) { n = 3; line = dsc->last_line; continued = TRUE; } if (IS_DSC(line, "%%CyanPlate:")) { colourname = "Cyan"; if (!continued) n = 12; } else if (IS_DSC(line, "%%MagentaPlate:")) { colourname = "Magenta"; if (!continued) n = 15; } else if (IS_DSC(line, "%%YellowPlate:")) { colourname = "Yellow"; if (!continued) n = 14; } else if (IS_DSC(line, "%%BlackPlate:")) { colourname = "Black"; if (!continued) n = 13; } else return CDSC_ERROR; /* error */ /* check for blank remainder of line */ blank_line = TRUE; for (i=n; iline_length; i++) { if (!IS_WHITE_OR_EOL(dsc->line[i])) { blank_line = FALSE; break; } } if (!blank_line) { dsc_copy_string(filename, sizeof(filename), dsc->line+n, dsc->line_length-n, &i); if (i==0) dsc_unknown(dsc); /* we didn't get all fields */ else { /* Allocate strings */ dcs2.colourname = dsc_alloc_string(dsc, colourname, (int)strlen(colourname)); dcs2.filetype = dsc_alloc_string(dsc, "EPS", 3); dcs2.location = dsc_alloc_string(dsc, "Local", 5); if (strlen(filename)) dcs2.filename = dsc_alloc_string(dsc, filename, (int)strlen(filename)); /* Allocate it */ pdcs2 = (CDCS2 *)dsc_memalloc(dsc, sizeof(CDCS2)); if (pdcs2 == NULL) return CDSC_ERROR; /* out of memory */ memcpy(pdcs2, &dcs2, sizeof(CDCS2)); /* Then add to list of separations */ if (dsc->dcs2 == NULL) dsc->dcs2 = pdcs2; else { CDCS2 *this_dcs2 = dsc->dcs2; while (this_dcs2->next) this_dcs2 = this_dcs2->next; this_dcs2->next = pdcs2; } } } return CDSC_OK; } /* Find the filename which corresponds to this separation. * Used with multiple file DCS 2.0. * Returns NULL if there is no filename, or not DCS 2.0, * or single file DCS 2.0. * Caller will need to obtain the filesize from the file. */ const char * dsc_find_platefile(CDSC *dsc, int page) { CDCS2 *pdcs = dsc->dcs2; int i = 1; while (pdcs) { if (pdcs->begin != pdcs->end) return NULL; /* Single file DCS 2.0 */ if (pdcs->location && pdcs->filetype && pdcs->colourname && (dsc_stricmp(pdcs->location, "Local") == 0) && ((dsc_stricmp(pdcs->filetype, "EPS") == 0) || (dsc_stricmp(pdcs->filetype, "EPSF") == 0))) { if (i == page) return pdcs->filename; i++; } pdcs = pdcs->next; } return NULL; } dsc_private CDSCCOLOUR * dsc_find_colour(CDSC *dsc, const char *colourname) { CDSCCOLOUR *colour = dsc->colours; while (colour) { if (colour->name && (dsc_stricmp(colour->name, colourname)==0)) return colour; colour = colour->next; } return 0; } dsc_private int dsc_parse_process_colours(CDSC *dsc) { unsigned int i, n; CDSCCOLOUR *pcolour; char colourname[MAXSTR]; GSBOOL blank_line; if (IS_DSC(dsc->line, "%%DocumentProcessColors:")) n = 24; else if (IS_DSC(dsc->line, "%%+")) n = 3; else return CDSC_ERROR; /* error */ memset(&colourname, 0, sizeof(colourname)); /* check for blank remainder of line */ blank_line = TRUE; for (i=n; iline_length; i++) { if (!IS_WHITE_OR_EOL(dsc->line[i])) { blank_line = FALSE; break; } } if (!blank_line) { do { dsc_copy_string(colourname, sizeof(colourname), dsc->line+n, dsc->line_length-n, &i); n+=i; if (i && strlen(colourname)) { if ((pcolour = dsc_find_colour(dsc, colourname)) == NULL) { pcolour = (CDSCCOLOUR *)malloc(sizeof(CDSCCOLOUR)); if (pcolour == NULL) return CDSC_ERROR; /* out of memory */ memset(pcolour, 0, sizeof(CDSCCOLOUR)); pcolour->custom = CDSC_CUSTOM_COLOUR_UNKNOWN; pcolour->name = dsc_alloc_string(dsc, colourname, (int)strlen(colourname)); if (dsc->colours == NULL) dsc->colours = pcolour; else { CDSCCOLOUR *this_colour = dsc->colours; while (this_colour->next) this_colour = this_colour->next; this_colour->next = pcolour; } } pcolour->type = CDSC_COLOUR_PROCESS; } } while (i != 0); } return CDSC_OK; } dsc_private int dsc_parse_custom_colours(CDSC *dsc) { unsigned int i, n; CDSCCOLOUR *pcolour; char colourname[MAXSTR]; GSBOOL blank_line; if (IS_DSC(dsc->line, "%%DocumentCustomColors:")) n = 23; else if (IS_DSC(dsc->line, "%%+")) n = 3; else return CDSC_ERROR; /* error */ memset(&colourname, 0, sizeof(colourname)); /* check for blank remainder of line */ blank_line = TRUE; for (i=n; iline_length; i++) { if (!IS_WHITE_OR_EOL(dsc->line[i])) { blank_line = FALSE; break; } } if (!blank_line) { do { dsc_copy_string(colourname, sizeof(colourname), dsc->line+n, dsc->line_length-n, &i); n+=i; if (i && strlen(colourname)) { if ((pcolour = dsc_find_colour(dsc, colourname)) == NULL) { pcolour = (CDSCCOLOUR *)malloc(sizeof(CDSCCOLOUR)); if (pcolour == NULL) return CDSC_ERROR; /* out of memory */ memset(pcolour, 0, sizeof(CDSCCOLOUR)); pcolour->name = dsc_alloc_string(dsc, colourname, (int)strlen(colourname)); pcolour->custom = CDSC_CUSTOM_COLOUR_UNKNOWN; if (dsc->colours == NULL) dsc->colours = pcolour; else { CDSCCOLOUR *this_colour = dsc->colours; while (this_colour->next) this_colour = this_colour->next; this_colour->next = pcolour; } } pcolour->type = CDSC_COLOUR_CUSTOM; } } while (i != 0); } return CDSC_OK; } dsc_private int dsc_parse_cmyk_custom_colour(CDSC *dsc) { unsigned int i, n; CDSCCOLOUR *pcolour; char colourname[MAXSTR]; float cyan, magenta, yellow, black; GSBOOL blank_line; if (IS_DSC(dsc->line, "%%CMYKCustomColor:")) n = 18; else if (IS_DSC(dsc->line, "%%+")) n = 3; else return CDSC_ERROR; /* error */ memset(&colourname, 0, sizeof(colourname)); /* check for blank remainder of line */ do { blank_line = TRUE; for (i=n; iline_length; i++) { if (!IS_WHITE_OR_EOL(dsc->line[i])) { blank_line = FALSE; break; } } if (blank_line) break; else { cyan = magenta = yellow = black = 0.0; cyan = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); n += i; if (i) magenta = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); n += i; if (i) yellow = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); n += i; if (i) black = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); n += i; if (i) dsc_copy_string(colourname, sizeof(colourname), dsc->line+n, dsc->line_length-n, &i); n+=i; if (i && strlen(colourname)) { if ((pcolour = dsc_find_colour(dsc, colourname)) == NULL) { pcolour = (CDSCCOLOUR *)malloc(sizeof(CDSCCOLOUR)); if (pcolour == NULL) return CDSC_ERROR; /* out of memory */ memset(pcolour, 0, sizeof(CDSCCOLOUR)); pcolour->name = dsc_alloc_string(dsc, colourname, (int)strlen(colourname)); pcolour->type = CDSC_COLOUR_UNKNOWN; if (dsc->colours == NULL) dsc->colours = pcolour; else { CDSCCOLOUR *this_colour = dsc->colours; while (this_colour->next) this_colour = this_colour->next; this_colour->next = pcolour; } } pcolour->custom = CDSC_CUSTOM_COLOUR_CMYK; pcolour->cyan = cyan; pcolour->magenta = magenta; pcolour->yellow = yellow; pcolour->black = black; } } } while (i != 0); return CDSC_OK; } dsc_private int dsc_parse_rgb_custom_colour(CDSC *dsc) { unsigned int i, n; CDSCCOLOUR *pcolour; char colourname[MAXSTR]; float red, green, blue; GSBOOL blank_line; if (IS_DSC(dsc->line, "%%RGBCustomColor:")) n = 17; else if (IS_DSC(dsc->line, "%%+")) n = 3; else return CDSC_ERROR; /* error */ memset(&colourname, 0, sizeof(colourname)); /* check for blank remainder of line */ do { blank_line = TRUE; for (i=n; iline_length; i++) { if (!IS_WHITE_OR_EOL(dsc->line[i])) { blank_line = FALSE; break; } } if (blank_line) break; else { red = green = blue = 0.0; red = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); n += i; if (i) green = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); n += i; if (i) blue = dsc_get_real(dsc->line+n, dsc->line_length-n, &i); n += i; if (i) dsc_copy_string(colourname, sizeof(colourname), dsc->line+n, dsc->line_length-n, &i); n+=i; if (i && strlen(colourname)) { if ((pcolour = dsc_find_colour(dsc, colourname)) == NULL) { pcolour = (CDSCCOLOUR *)malloc(sizeof(CDSCCOLOUR)); if (pcolour == NULL) return CDSC_ERROR; /* out of memory */ memset(pcolour, 0, sizeof(CDSCCOLOUR)); pcolour->name = dsc_alloc_string(dsc, colourname, (int)strlen(colourname)); pcolour->type = CDSC_COLOUR_UNKNOWN; if (dsc->colours == NULL) dsc->colours = pcolour; else { CDSCCOLOUR *this_colour = dsc->colours; while (this_colour->next) this_colour = this_colour->next; this_colour->next = pcolour; } } pcolour->custom = CDSC_CUSTOM_COLOUR_RGB; pcolour->red = red; pcolour->green = green; pcolour->blue = blue; } } } while (i != 0); return CDSC_OK; }