2 * ps.c -- Postscript scanning and copying routines.
3 * Copyright (C) 1992, 1998 Timothy O. Theisen
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 * Author: Tim Theisen Systems Programmer
20 * Internet: tim@cs.wisc.edu Department of Computer Sciences
21 * UUCP: uwvax!tim University of Wisconsin-Madison
22 * Phone: (608)262-0438 1210 West Dayton Street
23 * FAX: (608)262-9777 Madison, WI 53706
26 /* 18/3/98 Jake Hamby patch */
29 * 98/03/17: Jake Hamby (jehamby@lightside.com):
30 * Added support for compressed/gzipped Postscript and PDF files.
31 * Compressed files are gunzipped to a temporary file, and PDF files are
32 * scanned by calling Ghostscript to generate a fake DSC file.
33 * This is based on code from GV 3.5.8, which is available at:
34 * http://wwwthep.physik.uni-mainz.de/~plass/gv/
37 /* GV by Johannes Plass
38 * Department of Physics
39 * Johannes Gutenberg University
42 * <plass@thep.physik.uni-mainz.de>
57 #include <X11/Xos.h> /* #includes the appropriate <string.h> */
59 #include "gsdefaults.h"
65 /* length calculates string length at compile time */
66 /* can only be used with character constants */
67 #define length(a) (sizeof(a)-1)
68 #define iscomment(a, b) (strncmp(a, b, length(b)) == 0)
69 #define DSCcomment(a) (a[0] == '%' && a[1] == '%')
71 /* list of standard paper sizes from Adobe's PPD. */
73 /*--------------------------------------------------*/
74 /* Declarations for ps_io_*() routines. */
76 typedef struct FileDataStruct_ *FileData;
78 typedef struct FileDataStruct_ {
79 FILE *file; /* file */
80 int file_desc; /* file descriptor corresponding to file */
81 int filepos; /* file position corresponding to the start of the line */
82 char *buf; /* buffer */
83 int buf_size; /* size of buffer */
84 int buf_end; /* last char in buffer given as offset to buf */
85 int line_begin; /* start of the line given as offset to buf */
86 int line_end; /* end of the line given as offset to buf */
87 int line_len; /* length of line, i.e. (line_end-line_begin) */
88 char line_termchar; /* char exchanged for a '\0' at end of line */
89 int status; /* 0 = okay, 1 = failed */
92 static FileData ps_io_init (FILE *file);
93 static void ps_io_exit (FileData data);
94 static char *ps_io_fgetchars (FileData data, int offset);
96 static char *skipped_line = "% ps_io_fgetchars: skipped line";
97 static char *empty_string = "";
99 static char *readline (FileData fd, char **lineP, long *positionP, unsigned int *line_lenP);
100 static char *gettextline(char *line);
101 static char *get_next_text(char *line, char **next_char);
102 static int blank(char *line);
105 pages_new(struct page *pages, int current, int maxpages)
107 struct page *oldpages = pages;
109 pages = g_new0(struct page, maxpages);
111 pages = g_renew(struct page, oldpages, maxpages);
112 for(; current < maxpages; current++) {
113 memset(&(pages[current]), 0x00, sizeof(struct page));
114 pages[current].orientation = GTK_GS_ORIENTATION_NONE;
120 * psscan -- scan the PostScript file for document structuring comments.
122 * This scanner is designed to retrieve the information necessary for
123 * the ghostview previewer. It will scan files that conform to any
124 * version (1.0, 2.0, 2.1, or 3.0) of the document structuring conventions.
125 * It does not really care which version of comments the file contains.
126 * (The comments are largely upward compatible.) It will scan a number
127 * of non-conforming documents. (You could have part of the document
128 * conform to V2.0 and the rest conform to V3.0. It would be similar
129 * to the DC-2 1/2+, it would look funny but it can still fly.)
131 * This routine returns a pointer to the document structure.
132 * The structure contains the information relevant to previewing.
133 * These include EPSF flag (to tell if the file is a encapsulated figure),
134 * Page Size (for the Page Size), Bounding Box (to minimize backing
135 * pixmap size or determine window size for encapsulated PostScript),
136 * Orientation of Paper (for default transformation matrix), and
137 * Page Order. The Title, Creator, and CreationDate are also retrieved to
138 * help identify the document.
140 * The following comments are examined:
143 * Must start with %!PS-Adobe-. Version numbers ignored.
144 * Also allowed to be just %!PS, many files seem to have that.
146 * %!PS-Adobe-* [EPSF-*]
147 * %%BoundingBox: <int> <int> <int> <int>|(atend)
148 * %%Creator: <textline>
149 * %%CreationDate: <textline>
150 * %%Orientation: Portrait|Landscape|(atend)
151 * %%Pages: <uint> [<int>]|(atend)
152 * %%PageOrder: Ascend|Descend|Special|(atend)
153 * %%Title: <textline>
154 * %%DocumentMedia: <text> <real> <real> <real> <text> <text>
155 * %%DocumentPaperSizes: <text>
158 * Note: Either the 3.0 or 2.0 syntax for %%Pages is accepted.
159 * Also either the 2.0 %%DocumentPaperSizes or the 3.0
160 * %%DocumentMedia comments are accepted as well.
162 * The header section ends either explicitly with %%EndComments or
163 * implicitly with any line that does not begin with %X where X is
164 * a not whitespace character.
166 * If the file is encapsulated PostScript the optional Preview section
172 * This section explicitly begins and ends with the above comments.
174 * Next the Defaults section for version 3 page defaults:
177 * %%PageBoundingBox: <int> <int> <int> <int>
178 * %%PageOrientation: Portrait|Landscape
179 * %%PageMedia: <text>
182 * This section explicitly begins and ends with the above comments.
184 * The prolog section either explicitly starts with %%BeginProlog or
185 * implicitly with any nonblank line.
190 * The Prolog should end with %%EndProlog, however the proglog implicitly
191 * ends when %%BeginSetup, %%Page, %%Trailer or %%EOF are encountered.
193 * The Setup section is where the version 2 page defaults are found.
194 * This section either explicitly begins with %%BeginSetup or implicitly
195 * with any nonblank line after the Prolog.
198 * %%PageBoundingBox: <int> <int> <int> <int>
199 * %%PageOrientation: Portrait|Landscape
200 * %%PaperSize: <text>
203 * The Setup should end with %%EndSetup, however the setup implicitly
204 * ends when %%Page, %%Trailer or %%EOF are encountered.
206 * Next each page starts explicitly with %%Page and ends implicitly with
207 * %%Page or %%Trailer or %%EOF. The following comments are recognized:
209 * %%Page: <text> <uint>
210 * %%PageBoundingBox: <int> <int> <int> <int>|(atend)
211 * %%PageOrientation: Portrait|Landscape
212 * %%PageMedia: <text>
213 * %%PaperSize: <text>
215 * The tralier section start explicitly with %%Trailer and end with %%EOF.
216 * The following comment are examined with the proper (atend) notation
217 * was used in the header:
220 * %%BoundingBox: <int> <int> <int> <int>|(atend)
221 * %%Orientation: Portrait|Landscape|(atend)
222 * %%Pages: <uint> [<int>]|(atend)
223 * %%PageOrder: Ascend|Descend|Special|(atend)
227 * + A DC-3 received severe damage to one of its wings. The wing was a total
228 * loss. There was no replacement readily available, so the mechanic
229 * installed a wing from a DC-2.
235 psscan(FILE * file, int respect_eof, const gchar * fname)
237 struct document *doc;
239 int pages_set = NONE;
240 int page_order_set = NONE;
241 int orientation_set = NONE;
242 int page_bb_set = NONE;
243 int page_size_set = NONE;
244 int preread; /* flag which tells the readline isn't needed */
246 unsigned int maxpages = 0;
247 unsigned int nextpage = 1; /* Next expected page */
248 unsigned int thispage;
249 int ignore = 0; /* whether to ignore page ordinals */
252 char text[PSLINELENGTH]; /* Temporary storage for text */
253 long position; /* Position of the current line */
254 long beginsection; /* Position of the beginning of the section */
255 unsigned int line_len; /* Length of the current line */
256 unsigned int section_len; /* Place to accumulate the section length */
257 char *next_char; /* 1st char after text returned by get_next_text() */
260 GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes();
268 fd = ps_io_init(file);
269 if (!readline(fd, &line, &position, &line_len)) {
270 fprintf(stderr, "Warning: empty file.\n");
275 /* HP printer job language data follows. Some printer drivers add pjl
276 * commands to switch a pjl printer to postscript mode. If no PS header
277 * follows, this seems to be a real pjl file. */
278 if(iscomment(line, "\033%-12345X@PJL")) {
279 /* read until first DSC comment */
280 while(readline(fd, &line, &position, &line_len)
281 && (line[0] != '%')) ;
283 g_print("psscan error: input files seems to be a PJL file.\n");
289 /* Header comments */
291 /* Header should start with "%!PS-Adobe-", but some programms omit
292 * parts of this or add a ^D at the beginning. */
293 if(iscomment(line, "%!PS") || iscomment(line, "\004%!PS")) {
294 doc = g_new0(struct document, 1);
295 doc->default_page_orientation = GTK_GS_ORIENTATION_NONE;
296 doc->orientation = GTK_GS_ORIENTATION_NONE;
298 /* ignore possible leading ^D */
299 if(*line == '\004') {
304 /* Jake Hamby patch 18/3/98 */
307 sscanf(line, "%*s %256s", text);
308 /*doc->epsf = iscomment(text, "EPSF-"); */
309 doc->epsf = iscomment(text, "EPSF"); /* Hamby - This line changed */
310 doc->beginheader = position;
311 section_len = line_len;
314 /* There are postscript documents that do not have
315 %PS at the beginning, usually unstructured. We should GS decide
316 For instance, the tech reports at this university:
318 http://svrc.it.uq.edu.au/Bibliography/svrc-tr.html?94-45
320 add ugly PostScript before the actual document.
323 able to display them correctly as unstructured PS.
325 In a way, this makes sense, a program PostScript does not need
326 the !PS at the beginning.
328 doc = g_new0(struct document, 1);
329 doc->default_page_orientation = GTK_GS_ORIENTATION_NONE;
330 doc->orientation = GTK_GS_ORIENTATION_NONE;
336 while(preread || readline(fd, &line, &position, &line_len)) {
338 section_len += line_len;
341 iscomment(line + 1, "%EndComments") ||
342 line[1] == ' ' || line[1] == '\t' || line[1] == '\n' ||
346 else if(line[1] != '%') {
349 else if(doc->title == NULL && iscomment(line + 2, "Title:")) {
350 doc->title = gettextline(line + length("%%Title:"));
352 else if(doc->date == NULL && iscomment(line + 2, "CreationDate:")) {
353 doc->date = gettextline(line + length("%%CreationDate:"));
355 else if(doc->creator == NULL && iscomment(line + 2, "Creator:")) {
356 doc->creator = gettextline(line + length("%%Creator:"));
358 else if(bb_set == NONE && iscomment(line + 2, "BoundingBox:")) {
359 sscanf(line + length("%%BoundingBox:"), "%256s", text);
360 if(strcmp(text, "(atend)") == 0) {
364 if(sscanf(line + length("%%BoundingBox:"), "%d %d %d %d",
365 &(doc->boundingbox[LLX]),
366 &(doc->boundingbox[LLY]),
367 &(doc->boundingbox[URX]), &(doc->boundingbox[URY])) == 4)
370 float fllx, flly, furx, fury;
371 if(sscanf(line + length("%%BoundingBox:"), "%f %f %f %f",
372 &fllx, &flly, &furx, &fury) == 4) {
374 doc->boundingbox[LLX] = fllx;
375 doc->boundingbox[LLY] = flly;
376 doc->boundingbox[URX] = furx;
377 doc->boundingbox[URY] = fury;
378 if(fllx < doc->boundingbox[LLX])
379 doc->boundingbox[LLX]--;
380 if(flly < doc->boundingbox[LLY])
381 doc->boundingbox[LLY]--;
382 if(furx > doc->boundingbox[URX])
383 doc->boundingbox[URX]++;
384 if(fury > doc->boundingbox[URY])
385 doc->boundingbox[URY]++;
390 else if(orientation_set == NONE && iscomment(line + 2, "Orientation:")) {
391 sscanf(line + length("%%Orientation:"), "%256s", text);
392 if(strcmp(text, "(atend)") == 0) {
393 orientation_set = ATEND;
395 else if(strcmp(text, "Portrait") == 0) {
396 doc->orientation = GTK_GS_ORIENTATION_PORTRAIT;
399 else if(strcmp(text, "Landscape") == 0) {
400 doc->orientation = GTK_GS_ORIENTATION_LANDSCAPE;
403 else if(strcmp(text, "Seascape") == 0) {
404 doc->orientation = GTK_GS_ORIENTATION_SEASCAPE;
408 else if(page_order_set == NONE && iscomment(line + 2, "PageOrder:")) {
409 sscanf(line + length("%%PageOrder:"), "%256s", text);
410 if(strcmp(text, "(atend)") == 0) {
411 page_order_set = ATEND;
413 else if(strcmp(text, "Ascend") == 0) {
414 doc->pageorder = ASCEND;
417 else if(strcmp(text, "Descend") == 0) {
418 doc->pageorder = DESCEND;
421 else if(strcmp(text, "Special") == 0) {
422 doc->pageorder = SPECIAL;
426 else if(pages_set == NONE && iscomment(line + 2, "Pages:")) {
427 sscanf(line + length("%%Pages:"), "%256s", text);
428 if(strcmp(text, "(atend)") == 0) {
432 switch (sscanf(line + length("%%Pages:"), "%d %d", &maxpages, &i)) {
434 if(page_order_set == NONE) {
436 doc->pageorder = DESCEND;
440 doc->pageorder = SPECIAL;
444 doc->pageorder = ASCEND;
450 doc->pages = pages_new(NULL, 0, maxpages);
454 else if(doc->numsizes == NONE && iscomment(line + 2, "DocumentMedia:")) {
456 doc->size = g_new0(GtkGSPaperSize, 1);
458 get_next_text(line + length("%%DocumentMedia:"), &next_char);
459 if(doc->size[0].name != NULL) {
460 if(sscanf(next_char, "%f %f", &w, &h) == 2) {
461 doc->size[0].width = w + 0.5;
462 doc->size[0].height = h + 0.5;
464 if(doc->size[0].width != 0 && doc->size[0].height != 0)
467 g_free(doc->size[0].name);
470 while(readline(fd, &line, &position, &line_len) &&
471 DSCcomment(line) && iscomment(line + 2, "+")) {
472 section_len += line_len;
473 doc->size = g_renew(GtkGSPaperSize, doc->size, doc->numsizes + 1);
474 doc->size[doc->numsizes].name =
475 get_next_text(line + length("%%+"), &next_char);
476 if(doc->size[doc->numsizes].name != NULL) {
477 if(sscanf(next_char, "%f %f", &w, &h) == 2) {
478 doc->size[doc->numsizes].width = w + 0.5;
479 doc->size[doc->numsizes].height = h + 0.5;
481 if(doc->size[doc->numsizes].width != 0 &&
482 doc->size[doc->numsizes].height != 0)
485 g_free(doc->size[doc->numsizes].name);
488 section_len += line_len;
489 if(doc->numsizes != 0)
490 doc->default_page_size = doc->size;
492 else if(doc->numsizes == NONE && iscomment(line + 2, "DocumentPaperSizes:")) {
494 doc->size = g_new0(GtkGSPaperSize, 1);
496 get_next_text(line + length("%%DocumentPaperSizes:"), &next_char);
497 if(doc->size[0].name != NULL) {
498 doc->size[0].width = 0;
499 doc->size[0].height = 0;
500 for(dmp = papersizes; dmp->name != NULL; dmp++) {
501 /* Note: Paper size comment uses down cased paper size
502 * name. Case insensitive compares are only used for
503 * PaperSize comments.
505 if(strcasecmp(doc->size[0].name, dmp->name) == 0) {
506 g_free(doc->size[0].name);
507 doc->size[0].name = g_strdup(dmp->name);
508 doc->size[0].width = dmp->width;
509 doc->size[0].height = dmp->height;
513 if(doc->size[0].width != 0 && doc->size[0].height != 0)
516 g_free(doc->size[0].name);
518 while((cp = get_next_text(next_char, &next_char))) {
519 doc->size = g_renew(GtkGSPaperSize, doc->size, doc->numsizes + 1);
520 doc->size[doc->numsizes].name = cp;
521 doc->size[doc->numsizes].width = 0;
522 doc->size[doc->numsizes].height = 0;
523 for(dmp = papersizes; dmp->name != NULL; dmp++) {
524 /* Note: Paper size comment uses down cased paper size
525 * name. Case insensitive compares are only used for
526 * PaperSize comments.
528 if(strcasecmp(doc->size[doc->numsizes].name, dmp->name) == 0) {
529 g_free(doc->size[doc->numsizes].name);
530 doc->size[doc->numsizes].name = g_strdup(dmp->name);
531 doc->size[doc->numsizes].name = dmp->name;
532 doc->size[doc->numsizes].width = dmp->width;
533 doc->size[doc->numsizes].height = dmp->height;
537 if(doc->size[doc->numsizes].width != 0 &&
538 doc->size[doc->numsizes].height != 0)
541 g_free(doc->size[doc->numsizes].name);
544 while(readline(fd, &line, &position, &line_len) &&
545 DSCcomment(line) && iscomment(line + 2, "+")) {
546 section_len += line_len;
547 next_char = line + length("%%+");
548 while((cp = get_next_text(next_char, &next_char))) {
549 doc->size = g_renew(GtkGSPaperSize, doc->size, doc->numsizes + 1);
550 doc->size[doc->numsizes].name = cp;
551 doc->size[doc->numsizes].width = 0;
552 doc->size[doc->numsizes].height = 0;
553 for(dmp = papersizes; dmp->name != NULL; dmp++) {
554 /* Note: Paper size comment uses down cased paper size
555 * name. Case insensitive compares are only used for
556 * PaperSize comments.
558 if(strcasecmp(doc->size[doc->numsizes].name, dmp->name) == 0) {
559 doc->size[doc->numsizes].width = dmp->width;
560 doc->size[doc->numsizes].height = dmp->height;
564 if(doc->size[doc->numsizes].width != 0 &&
565 doc->size[doc->numsizes].height != 0)
568 g_free(doc->size[doc->numsizes].name);
571 section_len += line_len;
572 if(doc->numsizes != 0)
573 doc->default_page_size = doc->size;
577 if(DSCcomment(line) && iscomment(line + 2, "EndComments")) {
578 readline(fd, &line, &position, &line_len);
579 section_len += line_len;
581 doc->endheader = position;
582 doc->lenheader = section_len - line_len;
584 /* Optional Preview comments for encapsulated PostScript files */
586 beginsection = position;
587 section_len = line_len;
588 while(blank(line) && readline(fd, &line, &position, &line_len)) {
589 section_len += line_len;
592 if(doc->epsf && DSCcomment(line) && iscomment(line + 2, "BeginPreview")) {
593 doc->beginpreview = beginsection;
595 while(readline(fd, &line, &position, &line_len) &&
596 !(DSCcomment(line) && iscomment(line + 2, "EndPreview"))) {
597 section_len += line_len;
599 section_len += line_len;
600 readline(fd, &line, &position, &line_len);
601 section_len += line_len;
602 doc->endpreview = position;
603 doc->lenpreview = section_len - line_len;
606 /* Page Defaults for Version 3.0 files */
608 if(beginsection == 0) {
609 beginsection = position;
610 section_len = line_len;
612 while(blank(line) && readline(fd, &line, &position, &line_len)) {
613 section_len += line_len;
616 if(DSCcomment(line) && iscomment(line + 2, "BeginDefaults")) {
617 doc->begindefaults = beginsection;
619 while(readline(fd, &line, &position, &line_len) &&
620 !(DSCcomment(line) && iscomment(line + 2, "EndDefaults"))) {
621 section_len += line_len;
622 if(!DSCcomment(line)) {
625 else if(doc->default_page_orientation == GTK_GS_ORIENTATION_NONE &&
626 iscomment(line + 2, "PageOrientation:")) {
627 sscanf(line + length("%%PageOrientation:"), "%256s", text);
628 if(strcmp(text, "Portrait") == 0) {
629 doc->default_page_orientation = GTK_GS_ORIENTATION_PORTRAIT;
631 else if(strcmp(text, "Landscape") == 0) {
632 doc->default_page_orientation = GTK_GS_ORIENTATION_LANDSCAPE;
634 else if(strcmp(text, "Seascape") == 0) {
635 doc->default_page_orientation = GTK_GS_ORIENTATION_SEASCAPE;
638 else if(page_size_set == NONE && iscomment(line + 2, "PageMedia:")) {
639 cp = get_next_text(line + length("%%PageMedia:"), NULL);
640 for(dmp = doc->size, i = 0; i < doc->numsizes; i++, dmp++) {
641 if(strcmp(cp, dmp->name) == 0) {
642 doc->default_page_size = dmp;
649 else if(page_bb_set == NONE && iscomment(line + 2, "PageBoundingBox:")) {
650 if(sscanf(line + length("%%PageBoundingBox:"), "%d %d %d %d",
651 &(doc->default_page_boundingbox[LLX]),
652 &(doc->default_page_boundingbox[LLY]),
653 &(doc->default_page_boundingbox[URX]),
654 &(doc->default_page_boundingbox[URY])) == 4)
657 float fllx, flly, furx, fury;
659 (line + length("%%PageBoundingBox:"), "%f %f %f %f",
660 &fllx, &flly, &furx, &fury) == 4) {
662 doc->default_page_boundingbox[LLX] = fllx;
663 doc->default_page_boundingbox[LLY] = flly;
664 doc->default_page_boundingbox[URX] = furx;
665 doc->default_page_boundingbox[URY] = fury;
666 if(fllx < doc->default_page_boundingbox[LLX])
667 doc->default_page_boundingbox[LLX]--;
668 if(flly < doc->default_page_boundingbox[LLY])
669 doc->default_page_boundingbox[LLY]--;
670 if(furx > doc->default_page_boundingbox[URX])
671 doc->default_page_boundingbox[URX]++;
672 if(fury > doc->default_page_boundingbox[URY])
673 doc->default_page_boundingbox[URY]++;
678 section_len += line_len;
679 readline(fd, &line, &position, &line_len);
680 section_len += line_len;
681 doc->enddefaults = position;
682 doc->lendefaults = section_len - line_len;
685 /* Document Prolog */
687 if(beginsection == 0) {
688 beginsection = position;
689 section_len = line_len;
691 while(blank(line) && readline(fd, &line, &position, &line_len)) {
692 section_len += line_len;
695 if(!(DSCcomment(line) &&
696 (iscomment(line + 2, "BeginSetup") ||
697 iscomment(line + 2, "Page:") ||
698 iscomment(line + 2, "Trailer") || iscomment(line + 2, "EOF")))) {
699 doc->beginprolog = beginsection;
704 readline(fd, &line, &position, &line_len)) &&
705 !(DSCcomment(line) &&
706 (iscomment(line + 2, "EndProlog") ||
707 iscomment(line + 2, "BeginSetup") ||
708 iscomment(line + 2, "Page:") ||
709 iscomment(line + 2, "Trailer") || iscomment(line + 2, "EOF")))) {
711 section_len += line_len;
714 section_len += line_len;
715 if(DSCcomment(line) && iscomment(line + 2, "EndProlog")) {
716 readline(fd, &line, &position, &line_len);
717 section_len += line_len;
719 doc->endprolog = position;
720 doc->lenprolog = section_len - line_len;
723 /* Document Setup, Page Defaults found here for Version 2 files */
725 if(beginsection == 0) {
726 beginsection = position;
727 section_len = line_len;
729 while(blank(line) && readline(fd, &line, &position, &line_len)) {
730 section_len += line_len;
733 if(!(DSCcomment(line) &&
734 (iscomment(line + 2, "Page:") ||
735 iscomment(line + 2, "Trailer") ||
736 (respect_eof && iscomment(line + 2, "EOF"))))) {
737 doc->beginsetup = beginsection;
741 readline(fd, &line, &position, &line_len)) &&
742 !(DSCcomment(line) &&
743 (iscomment(line + 2, "EndSetup") ||
744 iscomment(line + 2, "Page:") ||
745 iscomment(line + 2, "Trailer") ||
746 (respect_eof && iscomment(line + 2, "EOF"))))) {
748 section_len += line_len;
750 if(!DSCcomment(line)) {
753 else if(doc->default_page_orientation == GTK_GS_ORIENTATION_NONE &&
754 iscomment(line + 2, "PageOrientation:")) {
755 sscanf(line + length("%%PageOrientation:"), "%256s", text);
756 if(strcmp(text, "Portrait") == 0) {
757 doc->default_page_orientation = GTK_GS_ORIENTATION_PORTRAIT;
759 else if(strcmp(text, "Landscape") == 0) {
760 doc->default_page_orientation = GTK_GS_ORIENTATION_LANDSCAPE;
762 else if(strcmp(text, "Seascape") == 0) {
763 doc->default_page_orientation = GTK_GS_ORIENTATION_SEASCAPE;
766 else if(page_size_set == NONE && iscomment(line + 2, "PaperSize:")) {
767 cp = get_next_text(line + length("%%PaperSize:"), NULL);
768 for(dmp = doc->size, i = 0; i < doc->numsizes; i++, dmp++) {
769 /* Note: Paper size comment uses down cased paper size
770 * name. Case insensitive compares are only used for
771 * PaperSize comments.
773 if(strcasecmp(cp, dmp->name) == 0) {
774 doc->default_page_size = dmp;
781 else if(page_bb_set == NONE && iscomment(line + 2, "PageBoundingBox:")) {
782 if(sscanf(line + length("%%PageBoundingBox:"), "%d %d %d %d",
783 &(doc->default_page_boundingbox[LLX]),
784 &(doc->default_page_boundingbox[LLY]),
785 &(doc->default_page_boundingbox[URX]),
786 &(doc->default_page_boundingbox[URY])) == 4)
789 float fllx, flly, furx, fury;
791 (line + length("%%PageBoundingBox:"), "%f %f %f %f",
792 &fllx, &flly, &furx, &fury) == 4) {
794 doc->default_page_boundingbox[LLX] = fllx;
795 doc->default_page_boundingbox[LLY] = flly;
796 doc->default_page_boundingbox[URX] = furx;
797 doc->default_page_boundingbox[URY] = fury;
798 if(fllx < doc->default_page_boundingbox[LLX])
799 doc->default_page_boundingbox[LLX]--;
800 if(flly < doc->default_page_boundingbox[LLY])
801 doc->default_page_boundingbox[LLY]--;
802 if(furx > doc->default_page_boundingbox[URX])
803 doc->default_page_boundingbox[URX]++;
804 if(fury > doc->default_page_boundingbox[URY])
805 doc->default_page_boundingbox[URY]++;
810 section_len += line_len;
811 if(DSCcomment(line) && iscomment(line + 2, "EndSetup")) {
812 readline(fd, &line, &position, &line_len);
813 section_len += line_len;
815 doc->endsetup = position;
816 doc->lensetup = section_len - line_len;
819 /* HACK: Mozilla 1.8 Workaround.
821 It seems that Mozilla 1.8 generates important postscript code
822 after the '%%EndProlog' and before the first page comment '%%Page: x y'.
823 See comment below also.
826 if(doc->beginprolog && !doc->beginsetup) {
827 doc->lenprolog += section_len - line_len;
828 doc->endprolog = position;
831 /* HACK: Windows NT Workaround
833 Mark Pfeifer (pfeiferm%ppddev@comet.cmis.abbott.com) noticed
834 about problems when viewing Windows NT 3.51 generated postscript
835 files with gv. He found that the relevant postscript files
836 show important postscript code after the '%%EndSetup' and before
837 the first page comment '%%Page: x y'.
839 if(doc->beginsetup) {
840 while(!(DSCcomment(line) &&
841 (iscomment(line + 2, "EndSetup") ||
842 (iscomment(line + 2, "Page:") ||
843 iscomment(line + 2, "Trailer") ||
844 (respect_eof && iscomment(line + 2, "EOF"))))) &&
845 (readline(fd, &line, &position, &line_len))) {
846 section_len += line_len;
847 doc->lensetup = section_len - line_len;
848 doc->endsetup = position;
852 /* Individual Pages */
854 if(beginsection == 0) {
855 beginsection = position;
856 section_len = line_len;
858 while(blank(line) && readline(fd, &line, &position, &line_len)) {
859 section_len += line_len;
864 while(DSCcomment(line) && iscomment(line + 2, "Page:")) {
867 doc->pages = pages_new(NULL, 0, maxpages);
869 label = get_next_text(line + length("%%Page:"), &next_char);
870 if(sscanf(next_char, "%d", &thispage) != 1)
873 ignore = thispage != 1;
875 if(!ignore && thispage != nextpage) {
881 if(doc->numpages == maxpages) {
883 doc->pages = pages_new(doc->pages, maxpages - 1, maxpages);
886 doc->pages[doc->numpages].label = label;
888 doc->pages[doc->numpages].begin = beginsection;
892 doc->pages[doc->numpages].begin = position;
893 section_len = line_len;
896 while(readline(fd, &line, &position, &line_len) &&
897 !(DSCcomment(line) &&
898 (iscomment(line + 2, "Page:") ||
899 iscomment(line + 2, "Trailer") ||
900 (respect_eof && iscomment(line + 2, "EOF"))))) {
901 section_len += line_len;
902 if(!DSCcomment(line)) {
905 else if(doc->pages[doc->numpages].orientation == NONE &&
906 iscomment(line + 2, "PageOrientation:")) {
907 sscanf(line + length("%%PageOrientation:"), "%256s", text);
908 if(strcmp(text, "Portrait") == 0) {
909 doc->pages[doc->numpages].orientation = GTK_GS_ORIENTATION_PORTRAIT;
911 else if(strcmp(text, "Landscape") == 0) {
912 doc->pages[doc->numpages].orientation = GTK_GS_ORIENTATION_LANDSCAPE;
914 else if(strcmp(text, "Seascape") == 0) {
915 doc->pages[doc->numpages].orientation = GTK_GS_ORIENTATION_SEASCAPE;
918 else if(doc->pages[doc->numpages].size == NULL &&
919 iscomment(line + 2, "PageMedia:")) {
920 cp = get_next_text(line + length("%%PageMedia:"), NULL);
921 for(dmp = doc->size, i = 0; i < doc->numsizes; i++, dmp++) {
922 if(strcmp(cp, dmp->name) == 0) {
923 doc->pages[doc->numpages].size = dmp;
929 else if(doc->pages[doc->numpages].size == NULL &&
930 iscomment(line + 2, "PaperSize:")) {
931 cp = get_next_text(line + length("%%PaperSize:"), NULL);
932 for(dmp = doc->size, i = 0; i < doc->numsizes; i++, dmp++) {
933 /* Note: Paper size comment uses down cased paper size
934 * name. Case insensitive compares are only used for
935 * PaperSize comments.
937 if(strcasecmp(cp, dmp->name) == 0) {
938 doc->pages[doc->numpages].size = dmp;
944 else if((page_bb_set == NONE || page_bb_set == ATEND) &&
945 iscomment(line + 2, "PageBoundingBox:")) {
946 sscanf(line + length("%%PageBoundingBox:"), "%256s", text);
947 if(strcmp(text, "(atend)") == 0) {
952 (line + length("%%PageBoundingBox:"), "%d %d %d %d",
953 &(doc->pages[doc->numpages].boundingbox[LLX]),
954 &(doc->pages[doc->numpages].boundingbox[LLY]),
955 &(doc->pages[doc->numpages].boundingbox[URX]),
956 &(doc->pages[doc->numpages].boundingbox[URY])) == 4) {
957 if(page_bb_set == NONE)
961 float fllx, flly, furx, fury;
962 if(sscanf(line + length("%%PageBoundingBox:"),
963 "%f %f %f %f", &fllx, &flly, &furx, &fury) == 4) {
964 if(page_bb_set == NONE)
966 doc->pages[doc->numpages].boundingbox[LLX] = fllx;
967 doc->pages[doc->numpages].boundingbox[LLY] = flly;
968 doc->pages[doc->numpages].boundingbox[URX] = furx;
969 doc->pages[doc->numpages].boundingbox[URY] = fury;
970 if(fllx < doc->pages[doc->numpages].boundingbox[LLX])
971 doc->pages[doc->numpages].boundingbox[LLX]--;
972 if(flly < doc->pages[doc->numpages].boundingbox[LLY])
973 doc->pages[doc->numpages].boundingbox[LLY]--;
974 if(furx > doc->pages[doc->numpages].boundingbox[URX])
975 doc->pages[doc->numpages].boundingbox[URX]++;
976 if(fury > doc->pages[doc->numpages].boundingbox[URY])
977 doc->pages[doc->numpages].boundingbox[URY]++;
983 section_len += line_len;
984 doc->pages[doc->numpages].end = position;
985 doc->pages[doc->numpages].len = section_len - line_len;
989 /* Document Trailer */
992 doc->begintrailer = beginsection;
996 doc->begintrailer = position;
997 section_len = line_len;
1002 readline(fd, &line, &position, &line_len)) &&
1003 !(respect_eof && DSCcomment(line) && iscomment(line + 2, "EOF"))) {
1005 section_len += line_len;
1007 if(!DSCcomment(line)) {
1010 else if(iscomment(line + 2, "Page:")) {
1011 g_free(get_next_text(line + length("%%Page:"), &next_char));
1012 if(sscanf(next_char, "%d", &thispage) != 1)
1014 if(!ignore && thispage == nextpage) {
1015 if(doc->numpages > 0) {
1016 doc->pages[doc->numpages - 1].end = position;
1017 doc->pages[doc->numpages - 1].len += section_len - line_len;
1021 doc->endsetup = position;
1022 doc->endsetup += section_len - line_len;
1024 else if(doc->endprolog) {
1025 doc->endprolog = position;
1026 doc->endprolog += section_len - line_len;
1032 else if(!respect_eof && iscomment(line + 2, "Trailer")) {
1033 /* What we thought was the start of the trailer was really */
1034 /* the trailer of an EPS on the page. */
1035 /* Set the end of the page to this trailer and keep scanning. */
1036 if(doc->numpages > 0) {
1037 doc->pages[doc->numpages - 1].end = position;
1038 doc->pages[doc->numpages - 1].len += section_len - line_len;
1040 doc->begintrailer = position;
1041 section_len = line_len;
1043 else if(bb_set == ATEND && iscomment(line + 2, "BoundingBox:")) {
1044 if(sscanf(line + length("%%BoundingBox:"), "%d %d %d %d",
1045 &(doc->boundingbox[LLX]),
1046 &(doc->boundingbox[LLY]),
1047 &(doc->boundingbox[URX]), &(doc->boundingbox[URY])) != 4) {
1048 float fllx, flly, furx, fury;
1049 if(sscanf(line + length("%%BoundingBox:"), "%f %f %f %f",
1050 &fllx, &flly, &furx, &fury) == 4) {
1051 doc->boundingbox[LLX] = fllx;
1052 doc->boundingbox[LLY] = flly;
1053 doc->boundingbox[URX] = furx;
1054 doc->boundingbox[URY] = fury;
1055 if(fllx < doc->boundingbox[LLX])
1056 doc->boundingbox[LLX]--;
1057 if(flly < doc->boundingbox[LLY])
1058 doc->boundingbox[LLY]--;
1059 if(furx > doc->boundingbox[URX])
1060 doc->boundingbox[URX]++;
1061 if(fury > doc->boundingbox[URY])
1062 doc->boundingbox[URY]++;
1066 else if(orientation_set == ATEND && iscomment(line + 2, "Orientation:")) {
1067 sscanf(line + length("%%Orientation:"), "%256s", text);
1068 if(strcmp(text, "Portrait") == 0) {
1069 doc->orientation = GTK_GS_ORIENTATION_PORTRAIT;
1071 else if(strcmp(text, "Landscape") == 0) {
1072 doc->orientation = GTK_GS_ORIENTATION_LANDSCAPE;
1074 else if(strcmp(text, "Seascape") == 0) {
1075 doc->orientation = GTK_GS_ORIENTATION_SEASCAPE;
1078 else if(page_order_set == ATEND && iscomment(line + 2, "PageOrder:")) {
1079 sscanf(line + length("%%PageOrder:"), "%256s", text);
1080 if(strcmp(text, "Ascend") == 0) {
1081 doc->pageorder = ASCEND;
1083 else if(strcmp(text, "Descend") == 0) {
1084 doc->pageorder = DESCEND;
1086 else if(strcmp(text, "Special") == 0) {
1087 doc->pageorder = SPECIAL;
1090 else if(pages_set == ATEND && iscomment(line + 2, "Pages:")) {
1091 if(sscanf(line + length("%%Pages:"), "%*u %d", &i) == 1) {
1092 if(page_order_set == NONE) {
1094 doc->pageorder = DESCEND;
1096 doc->pageorder = SPECIAL;
1098 doc->pageorder = ASCEND;
1103 section_len += line_len;
1104 if(DSCcomment(line) && iscomment(line + 2, "EOF")) {
1105 readline(fd, &line, &position, &line_len);
1106 section_len += line_len;
1108 doc->endtrailer = position;
1109 doc->lentrailer = section_len - line_len;
1112 section_len = line_len;
1114 while(preread || readline(line, sizeof line, file, &position, &line_len)) {
1116 section_len += line_len;
1118 if(DSCcomment(line) && iscomment(line + 2, "Page:")) {
1119 g_free(get_next_text(line + length("%%Page:"), &next_char));
1120 if(sscanf(next_char, "%d", &thispage) != 1)
1122 if(!ignore && thispage == nextpage) {
1123 if(doc->numpages > 0) {
1124 doc->pages[doc->numpages - 1].end = position;
1125 doc->pages[doc->numpages - 1].len += doc->lentrailer +
1126 section_len - line_len;
1130 doc->endsetup = position;
1131 doc->endsetup += doc->lentrailer + section_len - line_len;
1133 else if(doc->endprolog) {
1134 doc->endprolog = position;
1135 doc->endprolog += doc->lentrailer + section_len - line_len;
1148 * psfree -- free dynamic storage associated with document structure.
1153 struct document *doc;
1159 printf("This document exists\n");
1161 for(i = 0; i < doc->numpages; i++) {
1162 if(doc->pages[i].label)
1163 g_free(doc->pages[i].label);
1165 for(i = 0; i < doc->numsizes; i++) {
1166 if(doc->size[i].name)
1167 g_free(doc->size[i].name);
1174 g_free(doc->creator);
1184 * gettextine -- skip over white space and return the rest of the line.
1185 * If the text begins with '(' return the text string
1186 * using get_next_text().
1190 gettextline(char *line)
1194 while(*line && (*line == ' ' || *line == '\t'))
1197 return get_next_text(line, NULL);
1200 if(strlen(line) == 0)
1203 cp = g_strdup(line);
1205 /* Remove end of line */
1206 if(cp[strlen(line) - 2] == '\r' && cp[strlen(line) - 1] == '\n')
1207 /* Handle DOS \r\n */
1208 cp[strlen(line) - 2] = '\0';
1209 else if(cp[strlen(line) - 1] == '\n' || cp[strlen(line) - 1] == '\r')
1210 /* Handle mac and unix */
1211 cp[strlen(line) - 1] = '\0';
1218 * get_next_text -- return the next text string on the line.
1219 * return NULL if nothing is present.
1223 get_next_text(line, next_char)
1227 char text[PSLINELENGTH]; /* Temporary storage for text */
1231 while(*line && (*line == ' ' || *line == '\t'))
1238 while(*line && !(*line == ')' && level == 0)
1239 && (cp - text) < PSLINELENGTH - 1) {
1241 if(*(line + 1) == 'n') {
1245 else if(*(line + 1) == 'r') {
1249 else if(*(line + 1) == 't') {
1253 else if(*(line + 1) == 'b') {
1257 else if(*(line + 1) == 'f') {
1261 else if(*(line + 1) == '\\') {
1265 else if(*(line + 1) == '(') {
1269 else if(*(line + 1) == ')') {
1273 else if(*(line + 1) >= '0' && *(line + 1) <= '9') {
1274 if(*(line + 2) >= '0' && *(line + 2) <= '9') {
1275 if(*(line + 3) >= '0' && *(line + 3) <= '9') {
1277 ((*(line + 1) - '0') * 8 + *(line + 2) -
1278 '0') * 8 + *(line + 3) - '0';
1282 *cp++ = (*(line + 1) - '0') * 8 + *(line + 2) - '0';
1287 *cp++ = *(line + 1) - '0';
1296 else if(*line == '(') {
1300 else if(*line == ')') {
1310 while(*line && !(*line == ' ' || *line == '\t' || *line == '\n')
1311 && (cp - text) < PSLINELENGTH - 1)
1317 if(!quoted && strlen(text) == 0)
1319 return g_strdup(text);
1323 * pscopy -- copy lines of Postscript from a section of one file
1325 * Automatically switch to binary copying whenever
1326 * %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
1327 * comments are encountered.
1331 pscopy(from, to, begin, end)
1334 long begin; /* set negative to avoid initial seek */
1337 char line[PSLINELENGTH]; /* 255 characters + 1 newline + 1 NULL */
1338 char text[PSLINELENGTH]; /* Temporary storage for text */
1344 fseek(from, begin, SEEK_SET);
1345 while(ftell(from) < end) {
1346 fgets(line, sizeof line, from);
1347 gtk_gs_doc_sink_write(to, line, strlen(line));
1349 if(!(DSCcomment(line) && iscomment(line + 2, "Begin"))) {
1352 else if(iscomment(line + 7, "Data:")) {
1354 if(sscanf(line + length("%%BeginData:"), "%d %*s %256s", &num, text) >= 1) {
1355 if(strcmp(text, "Lines") == 0) {
1356 for(i = 0; i < num; i++) {
1357 fgets(line, sizeof(line), from);
1358 gtk_gs_doc_sink_write(to, line, strlen(line));
1362 while(num > BUFSIZ) {
1363 fread(buf, sizeof(char), BUFSIZ, from);
1364 gtk_gs_doc_sink_write(to, buf, BUFSIZ);
1367 fread(buf, sizeof(char), num, from);
1368 gtk_gs_doc_sink_write(to, buf, num);
1372 else if(iscomment(line + 7, "Binary:")) {
1373 if(sscanf(line + length("%%BeginBinary:"), "%d", &num) == 1) {
1374 while(num > BUFSIZ) {
1375 fread(buf, sizeof(char), BUFSIZ, from);
1376 gtk_gs_doc_sink_write(to, buf, BUFSIZ);
1379 fread(buf, sizeof(char), num, from);
1380 gtk_gs_doc_sink_write(to, buf, num);
1387 * pscopyuntil -- copy lines of Postscript from a section of one file
1388 * to another file until a particular comment is reached.
1389 * Automatically switch to binary copying whenever
1390 * %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
1391 * comments are encountered.
1395 pscopyuntil(FILE * from, GtkGSDocSink * to, long begin, long end,
1396 const char *comment)
1398 char line[PSLINELENGTH]; /* 255 characters + 1 newline + 1 NULL */
1399 char text[PSLINELENGTH]; /* Temporary storage for text */
1406 comment_length = strlen(comment);
1410 fseek(from, begin, SEEK_SET);
1412 while(ftell(from) < end && !feof(from)) {
1413 fgets(line, sizeof line, from);
1415 /* iscomment cannot be used here,
1416 * because comment_length is not known at compile time. */
1417 if(comment != NULL && strncmp(line, comment, comment_length) == 0) {
1418 return g_strdup(line);
1420 gtk_gs_doc_sink_write(to, line, strlen(line));
1421 if(!(DSCcomment(line) && iscomment(line + 2, "Begin"))) {
1424 else if(iscomment(line + 7, "Data:")) {
1426 if(sscanf(line + length("%%BeginData:"), "%d %*s %256s", &num, text) >= 1) {
1427 if(strcmp(text, "Lines") == 0) {
1428 for(i = 0; i < num; i++) {
1429 fgets(line, sizeof line, from);
1430 gtk_gs_doc_sink_write(to, line, strlen(line));
1434 while(num > BUFSIZ) {
1435 fread(buf, sizeof(char), BUFSIZ, from);
1436 gtk_gs_doc_sink_write(to, buf, BUFSIZ);
1439 fread(buf, sizeof(char), num, from);
1440 gtk_gs_doc_sink_write(to, buf, num);
1444 else if(iscomment(line + 7, "Binary:")) {
1445 if(sscanf(line + length("%%BeginBinary:"), "%d", &num) == 1) {
1446 while(num > BUFSIZ) {
1447 fread(buf, sizeof(char), BUFSIZ, from);
1448 gtk_gs_doc_sink_write(to, buf, BUFSIZ);
1451 fread(buf, sizeof(char), num, from);
1452 gtk_gs_doc_sink_write(to, buf, num);
1460 * blank -- determine whether the line contains nothing but whitespace.
1468 while(*cp == ' ' || *cp == '\t')
1470 return *cp == '\n' || (*cp == '%' && (line[0] != '%' || line[1] != '%'));
1473 /*##########################################################*/
1475 /* Copy the headers, marked pages, and trailer to fp */
1476 /*##########################################################*/
1479 pscopydoc(GtkGSDocSink * dest,
1480 char *src_filename, struct document *d, gint * pagelist)
1483 char text[PSLINELENGTH];
1485 gboolean pages_written = FALSE;
1486 gboolean pages_atend = FALSE;
1492 src_file = fopen(src_filename, "r");
1495 for(i = 0; i < d->numpages; i++) {
1500 here = d->beginheader;
1502 while((comment = pscopyuntil(src_file, dest, here, d->endheader, "%%Pages:"))) {
1503 here = ftell(src_file);
1504 if(pages_written || pages_atend) {
1508 sscanf(comment + length("%%Pages:"), "%256s", text);
1509 if(strcmp(text, "(atend)") == 0) {
1510 gtk_gs_doc_sink_write(dest, comment, strlen(comment));
1514 switch (sscanf(comment + length("%%Pages:"), "%*d %d", &i)) {
1516 gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d %d\n", pages, i);
1519 gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d\n", pages);
1522 pages_written = TRUE;
1526 pscopyuntil(src_file, dest, d->beginpreview, d->endpreview, NULL);
1527 pscopyuntil(src_file, dest, d->begindefaults, d->enddefaults, NULL);
1528 pscopyuntil(src_file, dest, d->beginprolog, d->endprolog, NULL);
1529 pscopyuntil(src_file, dest, d->beginsetup, d->endsetup, NULL);
1531 for(i = 0; i < d->numpages; i++) {
1532 if(d->pageorder == DESCEND)
1533 j = (d->numpages - 1) - i;
1538 comment = pscopyuntil(src_file, dest,
1539 d->pages[i].begin, d->pages[i].end, "%%Page:");
1540 gtk_gs_doc_sink_printf(dest, "%%%%Page: %s %d\n",
1541 d->pages[i].label, page++);
1543 pscopyuntil(src_file, dest, -1, d->pages[i].end, NULL);
1547 here = d->begintrailer;
1548 while((comment = pscopyuntil(src_file, dest, here, d->endtrailer,
1550 here = ftell(src_file);
1555 switch (sscanf(comment + length("%%Pages:"), "%*d %d", &i)) {
1557 gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d %d\n", pages, i);
1560 gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d\n", pages);
1563 pages_written = TRUE;
1570 /*----------------------------------------------------------*/
1572 /*----------------------------------------------------------*/
1574 #define FD_FILE (fd->file)
1575 #define FD_FILE_DESC (fd->file_desc)
1576 #define FD_FILEPOS (fd->filepos)
1577 #define FD_LINE_BEGIN (fd->line_begin)
1578 #define FD_LINE_END (fd->line_end)
1579 #define FD_LINE_LEN (fd->line_len)
1580 #define FD_LINE_TERMCHAR (fd->line_termchar)
1581 #define FD_BUF (fd->buf)
1582 #define FD_BUF_END (fd->buf_end)
1583 #define FD_BUF_SIZE (fd->buf_size)
1584 #define FD_STATUS (fd->status)
1586 #define FD_STATUS_OKAY 0
1587 #define FD_STATUS_BUFTOOLARGE 1
1588 #define FD_STATUS_NOMORECHARS 2
1590 #define LINE_CHUNK_SIZE 4096
1591 #define MAX_PS_IO_FGETCHARS_BUF_SIZE 57344
1592 #define BREAK_PS_IO_FGETCHARS_BUF_SIZE 49152
1594 static FileData ps_io_init(file)
1598 size_t size = sizeof(FileDataStruct);
1600 fd = (FileData) g_malloc(size);
1601 memset((void*) fd ,0,(size_t)size);
1605 FD_FILE_DESC = fileno(file);
1606 FD_FILEPOS = ftell(file);
1607 FD_BUF_SIZE = (2*LINE_CHUNK_SIZE)+1;
1608 FD_BUF = g_malloc(FD_BUF_SIZE);
1613 /*----------------------------------------------------------*/
1615 /*----------------------------------------------------------*/
1625 /*----------------------------------------------------------*/
1627 /*----------------------------------------------------------*/
1630 ps_io_fseek(fd,offset)
1635 status=fseek(FD_FILE,(long)offset,SEEK_SET);
1636 FD_BUF_END = FD_LINE_BEGIN = FD_LINE_END = FD_LINE_LEN = 0;
1637 FD_FILEPOS = offset;
1638 FD_STATUS = FD_STATUS_OKAY;
1642 /*----------------------------------------------------------*/
1644 /*----------------------------------------------------------*/
1653 /*----------------------------------------------------------*/
1654 /* ps_io_fgetchars */
1655 /*----------------------------------------------------------*/
1657 #ifdef USE_MEMMOVE_CODE
1658 static void ps_memmove (d, s, l)
1663 if (s < d) for (s += l, d += l; l; --l) *--d = *--s;
1664 else if (s != d) for (; l; --l) *d++ = *s++;
1667 # define ps_memmove memmove
1670 static char * ps_io_fgetchars(fd,num)
1674 char *eol=NULL,*tmp;
1675 size_t size_of_char = sizeof(char);
1677 if (FD_STATUS != FD_STATUS_OKAY) {
1681 FD_BUF[FD_LINE_END] = FD_LINE_TERMCHAR; /* restoring char previously exchanged against '\0' */
1682 FD_LINE_BEGIN = FD_LINE_END;
1685 if (num<0) { /* reading whole line */
1686 if (FD_BUF_END-FD_LINE_END) {
1687 /* strpbrk is faster but fails on lines with embedded NULLs
1688 eol = strpbrk(FD_BUF+FD_LINE_END,"\n\r");
1690 tmp = FD_BUF + FD_BUF_END;
1691 eol = FD_BUF + FD_LINE_END;
1692 while (eol < tmp && *eol != '\n' && *eol != '\r') eol++;
1693 if (eol >= tmp) eol = NULL;
1695 if (*eol=='\r' && *(eol+1)=='\n') eol += 2;
1700 } else { /* reading specified num of chars */
1701 if (FD_BUF_END >= FD_LINE_BEGIN+num) {
1702 eol = FD_BUF+FD_LINE_BEGIN+num;
1707 if (FD_BUF_END - FD_LINE_BEGIN > BREAK_PS_IO_FGETCHARS_BUF_SIZE) {
1708 eol = FD_BUF + FD_BUF_END - 1;
1712 while (FD_BUF_SIZE < FD_BUF_END+LINE_CHUNK_SIZE+1) {
1713 if (FD_BUF_SIZE > MAX_PS_IO_FGETCHARS_BUF_SIZE) {
1714 /* we should never get here, since the line is broken
1715 artificially after BREAK_PS_IO_FGETCHARS_BUF_SIZE bytes. */
1716 fprintf(stderr, "gv: ps_io_fgetchars: Fatal Error: buffer became too large.\n");
1719 if (FD_LINE_BEGIN) {
1720 ps_memmove((void*)FD_BUF,(void*)(FD_BUF+FD_LINE_BEGIN),
1721 ((size_t)(FD_BUF_END-FD_LINE_BEGIN+1))*size_of_char);
1722 FD_BUF_END -= FD_LINE_BEGIN;
1725 FD_BUF_SIZE = FD_BUF_SIZE+LINE_CHUNK_SIZE+1;
1726 FD_BUF = g_realloc(FD_BUF,FD_BUF_SIZE);
1730 FD_LINE_END = FD_BUF_END;
1732 /* different existing VMS file formats require that we use read here ###jp###,10/12/96 */
1733 if (num<0) FD_BUF_END += read(FD_FILE_DESC,FD_BUF+FD_BUF_END,LINE_CHUNK_SIZE);
1734 else FD_BUF_END += fread(FD_BUF+FD_BUF_END,size_of_char,LINE_CHUNK_SIZE,FD_FILE);
1736 /* read() seems to fail sometimes (? ? ?) so we always use fread ###jp###,07/31/96*/
1737 FD_BUF_END += fread(FD_BUF+FD_BUF_END,size_of_char,LINE_CHUNK_SIZE,FD_FILE);
1740 FD_BUF[FD_BUF_END] = '\0';
1741 if (FD_BUF_END-FD_LINE_END == 0) {
1742 FD_STATUS = FD_STATUS_NOMORECHARS;
1748 FD_LINE_END = eol - FD_BUF;
1749 FD_LINE_LEN = FD_LINE_END - FD_LINE_BEGIN;
1750 FD_LINE_TERMCHAR = FD_BUF[FD_LINE_END];
1751 FD_BUF[FD_LINE_END] = '\0';
1752 #ifdef USE_FTELL_FOR_FILEPOS
1753 if (FD_LINE_END==FD_BUF_END) {
1755 For VMS we cannot assume that the record is FD_LINE_LEN bytes long
1756 on the disk. For stream_lf and stream_cr that is true, but not for
1757 other formats, since VAXC/DECC converts the formatting into a single \n.
1758 eg. variable format files have a 2-byte length and padding to an even
1759 number of characters. So, we use ftell for each record.
1760 This still will not work if we need to fseek to a \n or \r inside a
1761 variable record (ftell always returns the start of the record in this
1763 (Tim Adye, adye@v2.rl.ac.uk)
1765 FD_FILEPOS = ftell(FD_FILE);
1767 #endif /* USE_FTELL_FOR_FILEPOS */
1768 FD_FILEPOS += FD_LINE_LEN;
1770 return(FD_BUF+FD_LINE_BEGIN);
1773 /*----------------------------------------------------------*/
1776 Read the next line in the postscript file.
1777 Automatically skip over data (as indicated by
1778 %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
1780 Also, skip over included documents (as indicated by
1781 %%BeginDocument/%%EndDocument comments.)
1783 /*----------------------------------------------------------*/
1785 static char *readline (fd, lineP, positionP, line_lenP)
1789 unsigned int *line_lenP;
1791 unsigned int nbytes=0;
1795 if (positionP) *positionP = FD_FILEPOS;
1796 line = ps_io_fgetchars(fd,-1);
1799 *lineP = empty_string;
1803 *line_lenP = FD_LINE_LEN;
1805 #define IS_COMMENT(comment) \
1806 (DSCcomment(line) && iscomment(line+2,(comment)))
1807 #define IS_BEGIN(comment) \
1808 (iscomment(line+7,(comment)))
1809 #define SKIP_WHILE(cond) \
1810 while (readline(fd, &line, NULL, &nbytes) && (cond)) *line_lenP += nbytes;\
1812 #define SKIP_UNTIL_1(comment) { \
1813 SKIP_WHILE((!IS_COMMENT(comment))) \
1815 #define SKIP_UNTIL_2(comment1,comment2) { \
1816 SKIP_WHILE((!IS_COMMENT(comment1) && !IS_COMMENT(comment2)))\
1819 if (!IS_COMMENT("Begin")) {} /* Do nothing */
1820 else if IS_BEGIN("Document:") SKIP_UNTIL_1("EndDocument")
1821 else if IS_BEGIN("Feature:") SKIP_UNTIL_1("EndFeature")
1822 #ifdef USE_ACROREAD_WORKAROUND
1823 else if IS_BEGIN("File") SKIP_UNTIL_2("EndFile","EOF")
1825 else if IS_BEGIN("File") SKIP_UNTIL_1("EndFile")
1827 else if IS_BEGIN("Font") SKIP_UNTIL_1("EndFont")
1828 else if IS_BEGIN("ProcSet") SKIP_UNTIL_1("EndProcSet")
1829 else if IS_BEGIN("Resource") SKIP_UNTIL_1("EndResource")
1830 else if IS_BEGIN("Data:") {
1833 if (FD_LINE_LEN > 100) FD_BUF[100] = '\0';
1835 if (sscanf(line+length("%%BeginData:"), "%d %*s %s", &num, text) >= 1) {
1836 if (strcmp(text, "Lines") == 0) {
1838 line = ps_io_fgetchars(fd,-1);
1839 if (line) *line_lenP += FD_LINE_LEN;
1843 int read_chunk_size = LINE_CHUNK_SIZE;
1845 if (num <= LINE_CHUNK_SIZE) read_chunk_size=num;
1846 line = ps_io_fgetchars(fd,read_chunk_size);
1847 if (line) *line_lenP += FD_LINE_LEN;
1848 num -= read_chunk_size;
1852 SKIP_UNTIL_1("EndData")
1854 else if IS_BEGIN("Binary:") {
1856 if (sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
1857 int read_chunk_size = LINE_CHUNK_SIZE;
1859 if (num <= LINE_CHUNK_SIZE) read_chunk_size=num;
1860 line = ps_io_fgetchars(fd,read_chunk_size);
1861 if (line) *line_lenP += FD_LINE_LEN;
1862 num -= read_chunk_size;
1864 SKIP_UNTIL_1("EndBinary")
1869 *line_lenP += nbytes;
1870 *lineP = skipped_line;
1872 *lineP = FD_BUF+FD_LINE_BEGIN;
1875 return(FD_BUF+FD_LINE_BEGIN);
1878 #define DEFAULT_PAGE_SIZE 1
1881 psgetpagebox (const struct document *doc, int page, int *urx, int *ury, int *llx, int *lly)
1887 GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes ();
1888 int new_pagesize = -1;
1890 if (new_pagesize == -1) {
1891 new_pagesize = DEFAULT_PAGE_SIZE;
1893 /* If we have a document:
1894 * We use -- the page size (if specified)
1895 * or the doc. size (if specified)
1896 * or the page bbox (if specified)
1897 * or the bounding box
1899 if ((page >= 0) && (doc->numpages > page) &&
1900 (doc->pages) && (doc->pages[page].size)) {
1901 new_pagesize = doc->pages[page].size - doc->size;
1902 } else if (doc->default_page_size != NULL) {
1903 new_pagesize = doc->default_page_size - doc->size;
1904 } else if ((page >= 0) &&
1905 (doc->numpages > page) &&
1907 (doc->pages[page].boundingbox[URX] >
1908 doc->pages[page].boundingbox[LLX]) &&
1909 (doc->pages[page].boundingbox[URY] >
1910 doc->pages[page].boundingbox[LLY])) {
1912 } else if ((doc->boundingbox[URX] > doc->boundingbox[LLX]) &&
1913 (doc->boundingbox[URY] > doc->boundingbox[LLY])) {
1919 /* Compute bounding box */
1920 if (doc && (doc->epsf || new_pagesize == -1)) { /* epsf or bbox */
1923 (doc->pages[page].boundingbox[URX] >
1924 doc->pages[page].boundingbox[LLX]) &&
1925 (doc->pages[page].boundingbox[URY] >
1926 doc->pages[page].boundingbox[LLY])) {
1928 new_llx = doc->pages[page].boundingbox[LLX];
1929 new_lly = doc->pages[page].boundingbox[LLY];
1930 new_urx = doc->pages[page].boundingbox[URX];
1931 new_ury = doc->pages[page].boundingbox[URY];
1932 } else if ((doc->boundingbox[URX] > doc->boundingbox[LLX]) &&
1933 (doc->boundingbox[URY] > doc->boundingbox[LLY])) {
1935 new_llx = doc->boundingbox[LLX];
1936 new_lly = doc->boundingbox[LLY];
1937 new_urx = doc->boundingbox[URX];
1938 new_ury = doc->boundingbox[URY];
1941 if (new_pagesize < 0)
1942 new_pagesize = DEFAULT_PAGE_SIZE;
1943 new_llx = new_lly = 0;
1944 if (doc && doc->size &&
1945 (new_pagesize < doc->numsizes)) {
1946 new_urx = doc->size[new_pagesize].width;
1947 new_ury = doc->size[new_pagesize].height;
1949 new_urx = papersizes[new_pagesize].width;
1950 new_ury = papersizes[new_pagesize].height;
1954 if (new_urx <= new_llx)
1955 new_urx = papersizes[12].width;
1956 if (new_ury <= new_lly)
1957 new_ury = papersizes[12].height;