This is epsfreader.m in view mode; [Download] [Up]
/* * (a) (C) 1990 by Adobe Systems Incorporated. All rights reserved. * * (b) If this Sample Code is distributed as part of the Display PostScript * System Software Development Kit from Adobe Systems Incorporated, * then this copy is designated as Development Software and its use is * subject to the terms of the License Agreement attached to such Kit. * * (c) If this Sample Code is distributed independently, then the following * terms apply: * * (d) This file may be freely copied and redistributed as long as: * 1) Parts (a), (d), (e) and (f) continue to be included in the file, * 2) If the file has been modified in any way, a notice of such * modification is conspicuously indicated. * * (e) PostScript, Display PostScript, and Adobe are registered trademarks of * Adobe Systems Incorporated. * * (f) THE INFORMATION BELOW IS FURNISHED AS IS, IS SUBJECT TO * CHANGE WITHOUT NOTICE, AND SHOULD NOT BE CONSTRUED * AS A COMMITMENT BY ADOBE SYSTEMS INCORPORATED. * ADOBE SYSTEMS INCORPORATED ASSUMES NO RESPONSIBILITY * OR LIABILITY FOR ANY ERRORS OR INACCURACIES, MAKES NO * WARRANTY OF ANY KIND (EXPRESS, IMPLIED OR STATUTORY) * WITH RESPECT TO THIS INFORMATION, AND EXPRESSLY * DISCLAIMS ANY AND ALL WARRANTIES OF MERCHANTABILITY, * FITNESS FOR PARTICULAR PURPOSES AND NONINFRINGEMENT * OF THIRD PARTY RIGHTS. */ /* * epsfparser.m * * ReadEpsf() is the procedure to invoke for parsing. It takes a pointer * to a structure as an argument. This structure contains the pointer to * the data as well as the locations to place the results of the parsing. * This parser grabs the bounding box and the fonts. Other parsers * can add to this general structure to do more sophisticated parsing * such as page breakout and such. * * Version: 2.0 * Author: Ken Fromm * History: * 03-19-91 Added this comment. */ #import "epsfstruct.h" #import <appkit/nextstd.h> #import <objc/hashtable.h> #import <objc/List.h> #import <objc/Storage.h> #import <strings.h> static int processToField(EpsfStruct *epsf); static int processToLineEnd(EpsfStruct *epsf); static int processBBox(EpsfStruct *epsf); static int processIncludeFile(EpsfStruct *epsf); static int processToEndDocument(EpsfStruct *epsf); static int processDocumentResource(EpsfStruct *epsf); static int processPageCount(EpsfStruct *epsf); /* * These static CommentHandle arrays are organized * into different groups according to the level of the * parsing. The general comments handle the top most * level of parsing. The document comments handle * the parsing of an included document. * * This setup allows the same general flow to handle the * parsing of each group. When a comment is reached * that indicates another level of parsing should be * performed, the tables for that level is passed to the * processToComment procedure. * * Others group could be added (not necessarily for * Epsf inclusion but for print management parsing). One * example is a page comment group. This group would * parse the page comments breaking out the location * of the individual pages as well as fonts, colors, paper * sizes, etc. * */ typedef struct { char *comment; int (*proc) (EpsfStruct *epsf); } CommentHandle; /***** General comments *****/ static CommentHandle generalComments [ ] = { {"%%BoundingBox:", processBBox}, {"%%BeginDocument", processToEndDocument}, {"%%Document", processDocumentResource}, {"%%Pages:", processPageCount} }; /***** Document comments *****/ static CommentHandle documentIncludeComments [ ] = { {"%%BeginDocument", processToEndDocument}, {"%%IncludeFile", processIncludeFile} }; /***** Document comments *****/ static CommentHandle documentEndComments [ ] = { {"%%EndDocument", processToLineEnd} }; /* * These static arrays are used to recognize the types of resources. * For starters there are at present 5 types of resources - fonts, files, * procsets, patterns and forms. Within each type, there are 3 states - * present, needed and supplied. The present state is the union of the * needed and supplied. The needed means the resource is not included * with the document. The supplied means the resource is included with * the document. */ typedef struct { char *comment; int key; } ResourceHandle; /***** Resource comments *****/ static ResourceHandle resourceStates [ ] = { {"Needed", RES_NEEDED}, {"Supplied", RES_SUPPLIED} }; static ResourceHandle resourceTypeMain [ ] = { {"Fonts", RES_FONTS}, {"Files", RES_FILES}, {"ProcSets", RES_PROCSETS}, {"Patterns", RES_PATTERNS}, {"Forms", RES_FORMS}, {"Resources", RES_RESOURCES}, }; static ResourceHandle resourceTypeSub [ ] = { {"fonts", RES_FONTS}, {"files", RES_FILES}, {"procsets", RES_PROCSETS}, {"patterns", RES_PATTERNS}, {"forms", RES_FORMS} }; /* * This is the workhorse of the parser. It takes a general structure * and some pointers to CommentHandle arrays and processes * the data until the one of the comments in the endTable has * been reached or the data runs out. Any matches to the * processTable comments processes the comment without * returning. (Any match to the endTable returns after processing.) * * If endLength is 0 then we will only process until the next line that * is not a comment. */ static int processToComment(EpsfStruct *epsf, CommentHandle endTable[ ], int endLength, CommentHandle processTable[ ], int processLength) { int i, j; while (epsf->data < epsf->enddata) { if (strncmp(epsf->data, "%", 1) == 0) { for (j = 0; j < endLength; j++) { if (strncmp(epsf->data, endTable[j].comment, strlen(endTable[j].comment)) == 0) { return endTable[j].proc(epsf); } } for (i = 0; i < processLength; i++) { if (strncmp(epsf->data, processTable[i].comment, strlen(processTable[i].comment)) == 0) { processTable[i].proc(epsf); break; } } if (i == processLength) processToLineEnd(epsf); } else { /* If endLength == 0 then process until the next non-comment. */ if (endLength == 0) return EPSF_OK; else processToLineEnd(epsf); } } return EPSF_OK; } static int CheckEpsf(EpsfStruct *epsf) { int rc = EPSF_INVALIDPS; if (strncmp(epsf->data, "%!PS-Adobe-", 11) == 0) { processToField(epsf); if (strncmp(epsf->data, "EPSF-", 5) == 0) { processToLineEnd(epsf); rc = EPSF_OK; } } return rc; } void CheckEpsfBinaryHeader(char **data, int *len) { EpsfBinaryHeader *header; char *newdata; int newlen; /* * If a binary header file is encountered then just skip * to the PostScript section of the file. Update the * data and len arguments to reflect this change. */ header = (EpsfBinaryHeader *) *data; if (header->idbytes == EPSF_BINARYID) { newdata = *data + header->ps_start; newlen = header->ps_length; if (newdata >= *data && newdata + newlen <= *data + *len) { *data = newdata; *len = newlen; } } } /* * This is the routine invoked for parsing. It validates the file * as a proper EPSF file (by checking for the %!PS-Adobe or * for the binary header id) and then parses the file. */ int ReadEpsf(EpsfStruct *epsf) { int rc = EPSF_OK; if (epsf && epsf->filedata && *epsf->filedata) { CheckEpsfBinaryHeader(&epsf->filedata, &epsf->filelen); epsf->data = epsf->filedata; epsf->enddata = epsf->filedata + epsf->filelen; if (epsf->data < epsf->enddata && !CheckEpsf(epsf)) { bzero(epsf->bbox, sizeof(epsf->bbox)); bzero(&epsf->resources, sizeof(epsf->resources)); bzero(&epsf->inclusions, sizeof(epsf->inclusions)); while (epsf->data < epsf->enddata && !rc) { rc = processToComment(epsf, generalComments, sizeof(generalComments)/sizeof(CommentHandle), NULL, 0); } /* Check for a valid bounding box. */ if (!rc && epsf->bbox[0] == 0 && epsf->bbox[1] == 0 && epsf->bbox[2] == 0 && epsf->bbox[3] == 0) rc = EPSF_INVALIDBBOX; } else rc = EPSF_INVALIDPS; } else rc = EPSF_INVALIDPS; return rc; } static int processToNonSpace(EpsfStruct *epsf) { while (epsf->data < epsf->enddata && *epsf->data == ' ') epsf->data++; return EPSF_OK; } static int processToField(EpsfStruct *epsf) { while (epsf->data < epsf->enddata && *epsf->data != ':' && *epsf->data != ' ') epsf->data++; if (epsf->data < epsf->enddata && *epsf->data == ':') epsf->data++; processToNonSpace(epsf); return EPSF_OK; } static int processToLineEnd(EpsfStruct *epsf) { while (epsf->data < epsf->enddata && *epsf->data != '\n') epsf->data++; if (epsf->data < epsf->enddata) epsf->data++; return EPSF_OK; } static int processBBox(EpsfStruct *epsf) { int rc = EPSF_OK; processToField(epsf); if (epsf->data < epsf->enddata && strncmp(epsf->data, "(atend)", 7) != 0) if ((sscanf(epsf->data, "%f %f %f %f", &epsf->bbox[0], &epsf->bbox[1], &epsf->bbox[2], &epsf->bbox[3]) != 4) || epsf->bbox[2] <= epsf->bbox[0] || epsf->bbox[3] <= epsf->bbox[1]) rc = EPSF_INVALIDBBOX; processToLineEnd(epsf); return rc; } static int processIncludeFile(EpsfStruct *epsf) { int rc = EPSF_OK; char name[EPSF_MAXLINE]; Inclusion inclusion; bzero(&inclusion, sizeof(inclusion)); inclusion.offset = epsf->data - epsf->filedata; processToField(epsf); if (epsf->data < epsf->enddata) { if (sscanf(epsf->data, "%s", name)) inclusion.filename = NXUniqueString(name); processToLineEnd(epsf); inclusion.len = (epsf->data - epsf->filedata) - inclusion.offset; if (inclusion.filename) { if (!epsf->inclusions) epsf->inclusions= [Storage newCount:0 elementSize:sizeof(Inclusion) description:InclusionDescription]; [epsf->inclusions addElement:&inclusion]; } } else rc = EPSF_INVALIDDOCUMENT; return rc; } static int processToEndDocument(EpsfStruct *epsf) { processToLineEnd(epsf); processToComment(epsf, documentEndComments, sizeof(documentEndComments)/sizeof(CommentHandle), documentIncludeComments, sizeof(documentIncludeComments)/sizeof(CommentHandle)); if (epsf->data >= epsf->enddata) return EPSF_INVALIDDOCUMENT; else return EPSF_OK; } /* Checks the page count. If greater than 1, an error is returned. */ /* Eps files should be single page documents only. */ static int processPageCount(EpsfStruct *epsf) { int rc = EPSF_OK; int pagetotal = 0; processToField(epsf); if (epsf->data < epsf->enddata && strncmp(epsf->data, "(atend)", 7) != 0) if (sscanf(epsf->data, "%d", &pagetotal)) if (pagetotal > 1) rc = EPSF_INVALIDPAGECOUNT; processToLineEnd(epsf); return rc; } static int checkResource(EpsfStruct *epsf, ResourceHandle table[ ], int length) { int i; for (i = 0; i < length; i++) { if (epsf->data < epsf->enddata && strncmp(epsf->data, table[i].comment, strlen(table[i].comment)) == 0) { epsf->data += strlen(table[i].comment); return table[i].key; } } return -1; } static int processResourceLine(EpsfStruct *epsf, int type, int state) { int i; char name[EPSF_MAXLINE], temp[40]; if (!epsf->resources[type].states[state]) epsf->resources[type].states[state] = [List new]; processToNonSpace(epsf); while (epsf->data < epsf->enddata && *epsf->data != '\n') { sscanf(epsf->data, "%s", name); epsf->data += strlen(name); processToNonSpace(epsf); if (type == RES_PROCSETS) { for (i = 0; i < 2 && epsf->data < epsf->enddata && *epsf->data != '\n'; i++) { if (sscanf(epsf->data, "%s", temp)) { strcat(name, " "); strcat(name, temp); epsf->data += strlen(temp); processToNonSpace(epsf); } } } [epsf->resources[type].states[state] addObjectIfAbsent:(id) NXUniqueString(name)]; } return EPSF_OK; } static int processResources(EpsfStruct *epsf, int xtype, int state) { int done = FALSE, type; type = xtype; processToField(epsf); if (epsf->data < epsf->enddata && strncmp(epsf->data, "(atend)", 7) != 0) { while (epsf->data < epsf->enddata && !done ) { processToNonSpace(epsf); if (*epsf->data == '\n') { epsf->data++; if (epsf->data < epsf->enddata && strncmp(epsf->data, "%%+", 3) == 0) epsf->data += 3; else done = TRUE; } else { if (xtype == RES_RESOURCES) type = checkResource(epsf, resourceTypeSub, sizeof(resourceTypeSub)/sizeof(ResourceHandle)); if (type >= RES_FONTS && type <= RES_FORMS) processResourceLine(epsf, type, state); else while (epsf->data < epsf->enddata && *epsf->data != '\n') epsf->data++; } } } else processToLineEnd(epsf); return EPSF_OK; } static int processDocumentResource(EpsfStruct *epsf) { int state, type; epsf->data += 10; if (epsf->data < epsf->enddata) { state = checkResource(epsf, resourceStates, sizeof(resourceStates)/sizeof(ResourceHandle)); state = MAX(RES_PRESENT, state); type = checkResource(epsf, resourceTypeMain, sizeof(resourceTypeMain)/sizeof(ResourceHandle)); if (type >= 0) processResources(epsf, type, state); } return EPSF_OK; } static char *getResource(int key, ResourceHandle table[ ], int length) { int i; for (i = 0; i < length; i++) if (table[i].key == key) return table[i].comment; return NULL; } void GetDocumentComment(char *comment, int type, int state) { char *subOne, *subTwo; strcpy(comment, "%%%%Document"); subOne = getResource(state, resourceStates, sizeof(resourceStates)/sizeof(ResourceHandle)); if (subOne) strcat(comment, subOne); subTwo = getResource(type, resourceTypeMain, sizeof(resourceTypeMain)/sizeof(ResourceHandle)); if (subTwo) strcat(comment, subTwo); strcat(comment, ": "); } const char *GetTypeComment(int type) { return getResource(type, resourceTypeMain, sizeof(resourceTypeMain)/sizeof(ResourceHandle)); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.