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>
56 #include <X11/Xos.h> /* #includes the appropriate <string.h> */
58 #include "gsdefaults.h"
64 /* length calculates string length at compile time */
65 /* can only be used with character constants */
66 #define length(a) (sizeof(a)-1)
67 #define iscomment(a, b) (strncmp(a, b, length(b)) == 0)
68 #define DSCcomment(a) (a[0] == '%' && a[1] == '%')
70 /* list of standard paper sizes from Adobe's PPD. */
72 /*--------------------------------------------------*/
73 /* Declarations for ps_io_*() routines. */
75 typedef struct FileDataStruct_ *FileData;
77 typedef struct FileDataStruct_ {
78 FILE *file; /* file */
79 int file_desc; /* file descriptor corresponding to file */
80 int filepos; /* file position corresponding to the start of the line */
81 char *buf; /* buffer */
82 int buf_size; /* size of buffer */
83 int buf_end; /* last char in buffer given as offset to buf */
84 int line_begin; /* start of the line given as offset to buf */
85 int line_end; /* end of the line given as offset to buf */
86 int line_len; /* length of line, i.e. (line_end-line_begin) */
87 char line_termchar; /* char exchanged for a '\0' at end of line */
88 int status; /* 0 = okay, 1 = failed */
91 static FileData ps_io_init (FILE *file);
92 static void ps_io_exit (FileData data);
93 static char *ps_io_fgetchars (FileData data, int offset);
95 static char *skipped_line = "% ps_io_fgetchars: skipped line";
96 static char *empty_string = "";
98 static char *readline (FileData fd, char **lineP, long *positionP, unsigned int *line_lenP);
99 static char *gettextline(char *line);
100 static char *get_next_text(char *line, char **next_char);
101 static int blank(char *line);
104 pages_new(struct page *pages, int current, int maxpages)
106 struct page *oldpages = pages;
108 pages = g_new0(struct page, maxpages);
110 pages = g_renew(struct page, oldpages, maxpages);
111 for(; current < maxpages; current++) {
112 memset(&(pages[current]), 0x00, sizeof(struct page));
113 pages[current].orientation = GTK_GS_ORIENTATION_NONE;
119 * psscan -- scan the PostScript file for document structuring comments.
121 * This scanner is designed to retrieve the information necessary for
122 * the ghostview previewer. It will scan files that conform to any
123 * version (1.0, 2.0, 2.1, or 3.0) of the document structuring conventions.
124 * It does not really care which version of comments the file contains.
125 * (The comments are largely upward compatible.) It will scan a number
126 * of non-conforming documents. (You could have part of the document
127 * conform to V2.0 and the rest conform to V3.0. It would be similar
128 * to the DC-2 1/2+, it would look funny but it can still fly.)
130 * This routine returns a pointer to the document structure.
131 * The structure contains the information relevant to previewing.
132 * These include EPSF flag (to tell if the file is a encapsulated figure),
133 * Page Size (for the Page Size), Bounding Box (to minimize backing
134 * pixmap size or determine window size for encapsulated PostScript),
135 * Orientation of Paper (for default transformation matrix), and
136 * Page Order. The Title, Creator, and CreationDate are also retrieved to
137 * help identify the document.
139 * The following comments are examined:
142 * Must start with %!PS-Adobe-. Version numbers ignored.
143 * Also allowed to be just %!PS, many files seem to have that.
145 * %!PS-Adobe-* [EPSF-*]
146 * %%BoundingBox: <int> <int> <int> <int>|(atend)
147 * %%Creator: <textline>
148 * %%CreationDate: <textline>
149 * %%Orientation: Portrait|Landscape|(atend)
150 * %%Pages: <uint> [<int>]|(atend)
151 * %%PageOrder: Ascend|Descend|Special|(atend)
152 * %%Title: <textline>
153 * %%DocumentMedia: <text> <real> <real> <real> <text> <text>
154 * %%DocumentPaperSizes: <text>
157 * Note: Either the 3.0 or 2.0 syntax for %%Pages is accepted.
158 * Also either the 2.0 %%DocumentPaperSizes or the 3.0
159 * %%DocumentMedia comments are accepted as well.
161 * The header section ends either explicitly with %%EndComments or
162 * implicitly with any line that does not begin with %X where X is
163 * a not whitespace character.
165 * If the file is encapsulated PostScript the optional Preview section
171 * This section explicitly begins and ends with the above comments.
173 * Next the Defaults section for version 3 page defaults:
176 * %%PageBoundingBox: <int> <int> <int> <int>
177 * %%PageOrientation: Portrait|Landscape
178 * %%PageMedia: <text>
181 * This section explicitly begins and ends with the above comments.
183 * The prolog section either explicitly starts with %%BeginProlog or
184 * implicitly with any nonblank line.
189 * The Prolog should end with %%EndProlog, however the proglog implicitly
190 * ends when %%BeginSetup, %%Page, %%Trailer or %%EOF are encountered.
192 * The Setup section is where the version 2 page defaults are found.
193 * This section either explicitly begins with %%BeginSetup or implicitly
194 * with any nonblank line after the Prolog.
197 * %%PageBoundingBox: <int> <int> <int> <int>
198 * %%PageOrientation: Portrait|Landscape
199 * %%PaperSize: <text>
202 * The Setup should end with %%EndSetup, however the setup implicitly
203 * ends when %%Page, %%Trailer or %%EOF are encountered.
205 * Next each page starts explicitly with %%Page and ends implicitly with
206 * %%Page or %%Trailer or %%EOF. The following comments are recognized:
208 * %%Page: <text> <uint>
209 * %%PageBoundingBox: <int> <int> <int> <int>|(atend)
210 * %%PageOrientation: Portrait|Landscape
211 * %%PageMedia: <text>
212 * %%PaperSize: <text>
214 * The tralier section start explicitly with %%Trailer and end with %%EOF.
215 * The following comment are examined with the proper (atend) notation
216 * was used in the header:
219 * %%BoundingBox: <int> <int> <int> <int>|(atend)
220 * %%Orientation: Portrait|Landscape|(atend)
221 * %%Pages: <uint> [<int>]|(atend)
222 * %%PageOrder: Ascend|Descend|Special|(atend)
226 * + A DC-3 received severe damage to one of its wings. The wing was a total
227 * loss. There was no replacement readily available, so the mechanic
228 * installed a wing from a DC-2.
234 psscan(FILE * file, int respect_eof, const gchar * fname)
236 struct document *doc;
238 int pages_set = NONE;
239 int page_order_set = NONE;
240 int orientation_set = NONE;
241 int page_bb_set = NONE;
242 int page_size_set = NONE;
243 int preread; /* flag which tells the readline isn't needed */
245 unsigned int maxpages = 0;
246 unsigned int nextpage = 1; /* Next expected page */
247 unsigned int thispage;
248 int ignore = 0; /* whether to ignore page ordinals */
251 char text[PSLINELENGTH]; /* Temporary storage for text */
252 long position; /* Position of the current line */
253 long beginsection; /* Position of the beginning of the section */
254 unsigned int line_len; /* Length of the current line */
255 unsigned int section_len; /* Place to accumulate the section length */
256 char *next_char; /* 1st char after text returned by get_next_text() */
259 GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes();
267 fd = ps_io_init(file);
268 if (!readline(fd, &line, &position, &line_len)) {
269 fprintf(stderr, "Warning: empty file.\n");
274 /* HP printer job language data follows. Some printer drivers add pjl
275 * commands to switch a pjl printer to postscript mode. If no PS header
276 * follows, this seems to be a real pjl file. */
277 if(iscomment(line, "\033%-12345X@PJL")) {
278 /* read until first DSC comment */
279 while(readline(fd, &line, &position, &line_len)
280 && (line[0] != '%')) ;
282 g_print("psscan error: input files seems to be a PJL file.\n");
288 /* Header comments */
290 /* Header should start with "%!PS-Adobe-", but some programms omit
291 * parts of this or add a ^D at the beginning. */
292 if(iscomment(line, "%!PS") || iscomment(line, "\004%!PS")) {
293 doc = g_new0(struct document, 1);
294 doc->default_page_orientation = GTK_GS_ORIENTATION_NONE;
295 doc->orientation = GTK_GS_ORIENTATION_NONE;
297 /* ignore possible leading ^D */
298 if(*line == '\004') {
303 /* Jake Hamby patch 18/3/98 */
306 sscanf(line, "%*s %256s", text);
307 /*doc->epsf = iscomment(text, "EPSF-"); */
308 doc->epsf = iscomment(text, "EPSF"); /* Hamby - This line changed */
309 doc->beginheader = position;
310 section_len = line_len;
313 /* There are postscript documents that do not have
314 %PS at the beginning, usually unstructured. We should GS decide
315 For instance, the tech reports at this university:
317 http://svrc.it.uq.edu.au/Bibliography/svrc-tr.html?94-45
319 add ugly PostScript before the actual document.
322 able to display them correctly as unstructured PS.
324 In a way, this makes sense, a program PostScript does not need
325 the !PS at the beginning.
327 doc = g_new0(struct document, 1);
328 doc->default_page_orientation = GTK_GS_ORIENTATION_NONE;
329 doc->orientation = GTK_GS_ORIENTATION_NONE;
335 while(preread || readline(fd, &line, &position, &line_len)) {
337 section_len += line_len;
340 iscomment(line + 1, "%EndComments") ||
341 line[1] == ' ' || line[1] == '\t' || line[1] == '\n' ||
345 else if(line[1] != '%') {
348 else if(doc->title == NULL && iscomment(line + 2, "Title:")) {
349 doc->title = gettextline(line + length("%%Title:"));
351 else if(doc->date == NULL && iscomment(line + 2, "CreationDate:")) {
352 doc->date = gettextline(line + length("%%CreationDate:"));
354 else if(doc->creator == NULL && iscomment(line + 2, "Creator:")) {
355 doc->creator = gettextline(line + length("%%Creator:"));
357 else if(bb_set == NONE && iscomment(line + 2, "BoundingBox:")) {
358 sscanf(line + length("%%BoundingBox:"), "%256s", text);
359 if(strcmp(text, "(atend)") == 0) {
363 if(sscanf(line + length("%%BoundingBox:"), "%d %d %d %d",
364 &(doc->boundingbox[LLX]),
365 &(doc->boundingbox[LLY]),
366 &(doc->boundingbox[URX]), &(doc->boundingbox[URY])) == 4)
369 float fllx, flly, furx, fury;
370 if(sscanf(line + length("%%BoundingBox:"), "%f %f %f %f",
371 &fllx, &flly, &furx, &fury) == 4) {
373 doc->boundingbox[LLX] = fllx;
374 doc->boundingbox[LLY] = flly;
375 doc->boundingbox[URX] = furx;
376 doc->boundingbox[URY] = fury;
377 if(fllx < doc->boundingbox[LLX])
378 doc->boundingbox[LLX]--;
379 if(flly < doc->boundingbox[LLY])
380 doc->boundingbox[LLY]--;
381 if(furx > doc->boundingbox[URX])
382 doc->boundingbox[URX]++;
383 if(fury > doc->boundingbox[URY])
384 doc->boundingbox[URY]++;
389 else if(orientation_set == NONE && iscomment(line + 2, "Orientation:")) {
390 sscanf(line + length("%%Orientation:"), "%256s", text);
391 if(strcmp(text, "(atend)") == 0) {
392 orientation_set = ATEND;
394 else if(strcmp(text, "Portrait") == 0) {
395 doc->orientation = GTK_GS_ORIENTATION_PORTRAIT;
398 else if(strcmp(text, "Landscape") == 0) {
399 doc->orientation = GTK_GS_ORIENTATION_LANDSCAPE;
402 else if(strcmp(text, "Seascape") == 0) {
403 doc->orientation = GTK_GS_ORIENTATION_SEASCAPE;
407 else if(page_order_set == NONE && iscomment(line + 2, "PageOrder:")) {
408 sscanf(line + length("%%PageOrder:"), "%256s", text);
409 if(strcmp(text, "(atend)") == 0) {
410 page_order_set = ATEND;
412 else if(strcmp(text, "Ascend") == 0) {
413 doc->pageorder = ASCEND;
416 else if(strcmp(text, "Descend") == 0) {
417 doc->pageorder = DESCEND;
420 else if(strcmp(text, "Special") == 0) {
421 doc->pageorder = SPECIAL;
425 else if(pages_set == NONE && iscomment(line + 2, "Pages:")) {
426 sscanf(line + length("%%Pages:"), "%256s", text);
427 if(strcmp(text, "(atend)") == 0) {
431 switch (sscanf(line + length("%%Pages:"), "%d %d", &maxpages, &i)) {
433 if(page_order_set == NONE) {
435 doc->pageorder = DESCEND;
439 doc->pageorder = SPECIAL;
443 doc->pageorder = ASCEND;
449 doc->pages = pages_new(NULL, 0, maxpages);
453 else if(doc->numsizes == NONE && iscomment(line + 2, "DocumentMedia:")) {
455 doc->size = g_new0(GtkGSPaperSize, 1);
457 get_next_text(line + length("%%DocumentMedia:"), &next_char);
458 if(doc->size[0].name != NULL) {
459 if(sscanf(next_char, "%f %f", &w, &h) == 2) {
460 doc->size[0].width = w + 0.5;
461 doc->size[0].height = h + 0.5;
463 if(doc->size[0].width != 0 && doc->size[0].height != 0)
466 g_free(doc->size[0].name);
469 while(readline(fd, &line, &position, &line_len) &&
470 DSCcomment(line) && iscomment(line + 2, "+")) {
471 section_len += line_len;
472 doc->size = g_renew(GtkGSPaperSize, doc->size, doc->numsizes + 1);
473 doc->size[doc->numsizes].name =
474 get_next_text(line + length("%%+"), &next_char);
475 if(doc->size[doc->numsizes].name != NULL) {
476 if(sscanf(next_char, "%f %f", &w, &h) == 2) {
477 doc->size[doc->numsizes].width = w + 0.5;
478 doc->size[doc->numsizes].height = h + 0.5;
480 if(doc->size[doc->numsizes].width != 0 &&
481 doc->size[doc->numsizes].height != 0)
484 g_free(doc->size[doc->numsizes].name);
487 section_len += line_len;
488 if(doc->numsizes != 0)
489 doc->default_page_size = doc->size;
491 else if(doc->numsizes == NONE && iscomment(line + 2, "DocumentPaperSizes:")) {
493 doc->size = g_new0(GtkGSPaperSize, 1);
495 get_next_text(line + length("%%DocumentPaperSizes:"), &next_char);
496 if(doc->size[0].name != NULL) {
497 doc->size[0].width = 0;
498 doc->size[0].height = 0;
499 for(dmp = papersizes; dmp->name != NULL; dmp++) {
500 /* Note: Paper size comment uses down cased paper size
501 * name. Case insensitive compares are only used for
502 * PaperSize comments.
504 if(strcasecmp(doc->size[0].name, dmp->name) == 0) {
505 g_free(doc->size[0].name);
506 doc->size[0].name = g_strdup(dmp->name);
507 doc->size[0].width = dmp->width;
508 doc->size[0].height = dmp->height;
512 if(doc->size[0].width != 0 && doc->size[0].height != 0)
515 g_free(doc->size[0].name);
517 while((cp = get_next_text(next_char, &next_char))) {
518 doc->size = g_renew(GtkGSPaperSize, doc->size, doc->numsizes + 1);
519 doc->size[doc->numsizes].name = cp;
520 doc->size[doc->numsizes].width = 0;
521 doc->size[doc->numsizes].height = 0;
522 for(dmp = papersizes; dmp->name != NULL; dmp++) {
523 /* Note: Paper size comment uses down cased paper size
524 * name. Case insensitive compares are only used for
525 * PaperSize comments.
527 if(strcasecmp(doc->size[doc->numsizes].name, dmp->name) == 0) {
528 g_free(doc->size[doc->numsizes].name);
529 doc->size[doc->numsizes].name = g_strdup(dmp->name);
530 doc->size[doc->numsizes].name = dmp->name;
531 doc->size[doc->numsizes].width = dmp->width;
532 doc->size[doc->numsizes].height = dmp->height;
536 if(doc->size[doc->numsizes].width != 0 &&
537 doc->size[doc->numsizes].height != 0)
540 g_free(doc->size[doc->numsizes].name);
543 while(readline(fd, &line, &position, &line_len) &&
544 DSCcomment(line) && iscomment(line + 2, "+")) {
545 section_len += line_len;
546 next_char = line + length("%%+");
547 while((cp = get_next_text(next_char, &next_char))) {
548 doc->size = g_renew(GtkGSPaperSize, doc->size, doc->numsizes + 1);
549 doc->size[doc->numsizes].name = cp;
550 doc->size[doc->numsizes].width = 0;
551 doc->size[doc->numsizes].height = 0;
552 for(dmp = papersizes; dmp->name != NULL; dmp++) {
553 /* Note: Paper size comment uses down cased paper size
554 * name. Case insensitive compares are only used for
555 * PaperSize comments.
557 if(strcasecmp(doc->size[doc->numsizes].name, dmp->name) == 0) {
558 doc->size[doc->numsizes].width = dmp->width;
559 doc->size[doc->numsizes].height = dmp->height;
563 if(doc->size[doc->numsizes].width != 0 &&
564 doc->size[doc->numsizes].height != 0)
567 g_free(doc->size[doc->numsizes].name);
570 section_len += line_len;
571 if(doc->numsizes != 0)
572 doc->default_page_size = doc->size;
576 if(DSCcomment(line) && iscomment(line + 2, "EndComments")) {
577 readline(fd, &line, &position, &line_len);
578 section_len += line_len;
580 doc->endheader = position;
581 doc->lenheader = section_len - line_len;
583 /* Optional Preview comments for encapsulated PostScript files */
585 beginsection = position;
586 section_len = line_len;
587 while(blank(line) && readline(fd, &line, &position, &line_len)) {
588 section_len += line_len;
591 if(doc->epsf && DSCcomment(line) && iscomment(line + 2, "BeginPreview")) {
592 doc->beginpreview = beginsection;
594 while(readline(fd, &line, &position, &line_len) &&
595 !(DSCcomment(line) && iscomment(line + 2, "EndPreview"))) {
596 section_len += line_len;
598 section_len += line_len;
599 readline(fd, &line, &position, &line_len);
600 section_len += line_len;
601 doc->endpreview = position;
602 doc->lenpreview = section_len - line_len;
605 /* Page Defaults for Version 3.0 files */
607 if(beginsection == 0) {
608 beginsection = position;
609 section_len = line_len;
611 while(blank(line) && readline(fd, &line, &position, &line_len)) {
612 section_len += line_len;
615 if(DSCcomment(line) && iscomment(line + 2, "BeginDefaults")) {
616 doc->begindefaults = beginsection;
618 while(readline(fd, &line, &position, &line_len) &&
619 !(DSCcomment(line) && iscomment(line + 2, "EndDefaults"))) {
620 section_len += line_len;
621 if(!DSCcomment(line)) {
624 else if(doc->default_page_orientation == GTK_GS_ORIENTATION_NONE &&
625 iscomment(line + 2, "PageOrientation:")) {
626 sscanf(line + length("%%PageOrientation:"), "%256s", text);
627 if(strcmp(text, "Portrait") == 0) {
628 doc->default_page_orientation = GTK_GS_ORIENTATION_PORTRAIT;
630 else if(strcmp(text, "Landscape") == 0) {
631 doc->default_page_orientation = GTK_GS_ORIENTATION_LANDSCAPE;
633 else if(strcmp(text, "Seascape") == 0) {
634 doc->default_page_orientation = GTK_GS_ORIENTATION_SEASCAPE;
637 else if(page_size_set == NONE && iscomment(line + 2, "PageMedia:")) {
638 cp = get_next_text(line + length("%%PageMedia:"), NULL);
639 for(dmp = doc->size, i = 0; i < doc->numsizes; i++, dmp++) {
640 if(strcmp(cp, dmp->name) == 0) {
641 doc->default_page_size = dmp;
648 else if(page_bb_set == NONE && iscomment(line + 2, "PageBoundingBox:")) {
649 if(sscanf(line + length("%%PageBoundingBox:"), "%d %d %d %d",
650 &(doc->default_page_boundingbox[LLX]),
651 &(doc->default_page_boundingbox[LLY]),
652 &(doc->default_page_boundingbox[URX]),
653 &(doc->default_page_boundingbox[URY])) == 4)
656 float fllx, flly, furx, fury;
658 (line + length("%%PageBoundingBox:"), "%f %f %f %f",
659 &fllx, &flly, &furx, &fury) == 4) {
661 doc->default_page_boundingbox[LLX] = fllx;
662 doc->default_page_boundingbox[LLY] = flly;
663 doc->default_page_boundingbox[URX] = furx;
664 doc->default_page_boundingbox[URY] = fury;
665 if(fllx < doc->default_page_boundingbox[LLX])
666 doc->default_page_boundingbox[LLX]--;
667 if(flly < doc->default_page_boundingbox[LLY])
668 doc->default_page_boundingbox[LLY]--;
669 if(furx > doc->default_page_boundingbox[URX])
670 doc->default_page_boundingbox[URX]++;
671 if(fury > doc->default_page_boundingbox[URY])
672 doc->default_page_boundingbox[URY]++;
677 section_len += line_len;
678 readline(fd, &line, &position, &line_len);
679 section_len += line_len;
680 doc->enddefaults = position;
681 doc->lendefaults = section_len - line_len;
684 /* Document Prolog */
686 if(beginsection == 0) {
687 beginsection = position;
688 section_len = line_len;
690 while(blank(line) && readline(fd, &line, &position, &line_len)) {
691 section_len += line_len;
694 if(!(DSCcomment(line) &&
695 (iscomment(line + 2, "BeginSetup") ||
696 iscomment(line + 2, "Page:") ||
697 iscomment(line + 2, "Trailer") || iscomment(line + 2, "EOF")))) {
698 doc->beginprolog = beginsection;
703 readline(fd, &line, &position, &line_len)) &&
704 !(DSCcomment(line) &&
705 (iscomment(line + 2, "EndProlog") ||
706 iscomment(line + 2, "BeginSetup") ||
707 iscomment(line + 2, "Page:") ||
708 iscomment(line + 2, "Trailer") || iscomment(line + 2, "EOF")))) {
710 section_len += line_len;
713 section_len += line_len;
714 if(DSCcomment(line) && iscomment(line + 2, "EndProlog")) {
715 readline(fd, &line, &position, &line_len);
716 section_len += line_len;
718 doc->endprolog = position;
719 doc->lenprolog = section_len - line_len;
722 /* Document Setup, Page Defaults found here for Version 2 files */
724 if(beginsection == 0) {
725 beginsection = position;
726 section_len = line_len;
728 while(blank(line) && readline(fd, &line, &position, &line_len)) {
729 section_len += line_len;
732 if(!(DSCcomment(line) &&
733 (iscomment(line + 2, "Page:") ||
734 iscomment(line + 2, "Trailer") ||
735 (respect_eof && iscomment(line + 2, "EOF"))))) {
736 doc->beginsetup = beginsection;
740 readline(fd, &line, &position, &line_len)) &&
741 !(DSCcomment(line) &&
742 (iscomment(line + 2, "EndSetup") ||
743 iscomment(line + 2, "Page:") ||
744 iscomment(line + 2, "Trailer") ||
745 (respect_eof && iscomment(line + 2, "EOF"))))) {
747 section_len += line_len;
749 if(!DSCcomment(line)) {
752 else if(doc->default_page_orientation == GTK_GS_ORIENTATION_NONE &&
753 iscomment(line + 2, "PageOrientation:")) {
754 sscanf(line + length("%%PageOrientation:"), "%256s", text);
755 if(strcmp(text, "Portrait") == 0) {
756 doc->default_page_orientation = GTK_GS_ORIENTATION_PORTRAIT;
758 else if(strcmp(text, "Landscape") == 0) {
759 doc->default_page_orientation = GTK_GS_ORIENTATION_LANDSCAPE;
761 else if(strcmp(text, "Seascape") == 0) {
762 doc->default_page_orientation = GTK_GS_ORIENTATION_SEASCAPE;
765 else if(page_size_set == NONE && iscomment(line + 2, "PaperSize:")) {
766 cp = get_next_text(line + length("%%PaperSize:"), NULL);
767 for(dmp = doc->size, i = 0; i < doc->numsizes; i++, dmp++) {
768 /* Note: Paper size comment uses down cased paper size
769 * name. Case insensitive compares are only used for
770 * PaperSize comments.
772 if(strcasecmp(cp, dmp->name) == 0) {
773 doc->default_page_size = dmp;
780 else if(page_bb_set == NONE && iscomment(line + 2, "PageBoundingBox:")) {
781 if(sscanf(line + length("%%PageBoundingBox:"), "%d %d %d %d",
782 &(doc->default_page_boundingbox[LLX]),
783 &(doc->default_page_boundingbox[LLY]),
784 &(doc->default_page_boundingbox[URX]),
785 &(doc->default_page_boundingbox[URY])) == 4)
788 float fllx, flly, furx, fury;
790 (line + length("%%PageBoundingBox:"), "%f %f %f %f",
791 &fllx, &flly, &furx, &fury) == 4) {
793 doc->default_page_boundingbox[LLX] = fllx;
794 doc->default_page_boundingbox[LLY] = flly;
795 doc->default_page_boundingbox[URX] = furx;
796 doc->default_page_boundingbox[URY] = fury;
797 if(fllx < doc->default_page_boundingbox[LLX])
798 doc->default_page_boundingbox[LLX]--;
799 if(flly < doc->default_page_boundingbox[LLY])
800 doc->default_page_boundingbox[LLY]--;
801 if(furx > doc->default_page_boundingbox[URX])
802 doc->default_page_boundingbox[URX]++;
803 if(fury > doc->default_page_boundingbox[URY])
804 doc->default_page_boundingbox[URY]++;
809 section_len += line_len;
810 if(DSCcomment(line) && iscomment(line + 2, "EndSetup")) {
811 readline(fd, &line, &position, &line_len);
812 section_len += line_len;
814 doc->endsetup = position;
815 doc->lensetup = section_len - line_len;
818 /* HACK: Mozilla 1.8 Workaround.
820 It seems that Mozilla 1.8 generates important postscript code
821 after the '%%EndProlog' and before the first page comment '%%Page: x y'.
822 See comment below also.
825 if(doc->beginprolog && !doc->beginsetup) {
826 doc->lenprolog += section_len - line_len;
827 doc->endprolog = position;
830 /* HACK: Windows NT Workaround
832 Mark Pfeifer (pfeiferm%ppddev@comet.cmis.abbott.com) noticed
833 about problems when viewing Windows NT 3.51 generated postscript
834 files with gv. He found that the relevant postscript files
835 show important postscript code after the '%%EndSetup' and before
836 the first page comment '%%Page: x y'.
838 if(doc->beginsetup) {
839 while(!(DSCcomment(line) &&
840 (iscomment(line + 2, "EndSetup") ||
841 (iscomment(line + 2, "Page:") ||
842 iscomment(line + 2, "Trailer") ||
843 (respect_eof && iscomment(line + 2, "EOF"))))) &&
844 (readline(fd, &line, &position, &line_len))) {
845 section_len += line_len;
846 doc->lensetup = section_len - line_len;
847 doc->endsetup = position;
851 /* Individual Pages */
853 if(beginsection == 0) {
854 beginsection = position;
855 section_len = line_len;
857 while(blank(line) && readline(fd, &line, &position, &line_len)) {
858 section_len += line_len;
863 while(DSCcomment(line) && iscomment(line + 2, "Page:")) {
866 doc->pages = pages_new(NULL, 0, maxpages);
868 label = get_next_text(line + length("%%Page:"), &next_char);
869 if(sscanf(next_char, "%d", &thispage) != 1)
872 ignore = thispage != 1;
874 if(!ignore && thispage != nextpage) {
880 if(doc->numpages == maxpages) {
882 doc->pages = pages_new(doc->pages, maxpages - 1, maxpages);
885 doc->pages[doc->numpages].label = label;
887 doc->pages[doc->numpages].begin = beginsection;
891 doc->pages[doc->numpages].begin = position;
892 section_len = line_len;
895 while(readline(fd, &line, &position, &line_len) &&
896 !(DSCcomment(line) &&
897 (iscomment(line + 2, "Page:") ||
898 iscomment(line + 2, "Trailer") ||
899 (respect_eof && iscomment(line + 2, "EOF"))))) {
900 section_len += line_len;
901 if(!DSCcomment(line)) {
904 else if(doc->pages[doc->numpages].orientation == NONE &&
905 iscomment(line + 2, "PageOrientation:")) {
906 sscanf(line + length("%%PageOrientation:"), "%256s", text);
907 if(strcmp(text, "Portrait") == 0) {
908 doc->pages[doc->numpages].orientation = GTK_GS_ORIENTATION_PORTRAIT;
910 else if(strcmp(text, "Landscape") == 0) {
911 doc->pages[doc->numpages].orientation = GTK_GS_ORIENTATION_LANDSCAPE;
913 else if(strcmp(text, "Seascape") == 0) {
914 doc->pages[doc->numpages].orientation = GTK_GS_ORIENTATION_SEASCAPE;
917 else if(doc->pages[doc->numpages].size == NULL &&
918 iscomment(line + 2, "PageMedia:")) {
919 cp = get_next_text(line + length("%%PageMedia:"), NULL);
920 for(dmp = doc->size, i = 0; i < doc->numsizes; i++, dmp++) {
921 if(strcmp(cp, dmp->name) == 0) {
922 doc->pages[doc->numpages].size = dmp;
928 else if(doc->pages[doc->numpages].size == NULL &&
929 iscomment(line + 2, "PaperSize:")) {
930 cp = get_next_text(line + length("%%PaperSize:"), NULL);
931 for(dmp = doc->size, i = 0; i < doc->numsizes; i++, dmp++) {
932 /* Note: Paper size comment uses down cased paper size
933 * name. Case insensitive compares are only used for
934 * PaperSize comments.
936 if(strcasecmp(cp, dmp->name) == 0) {
937 doc->pages[doc->numpages].size = dmp;
943 else if((page_bb_set == NONE || page_bb_set == ATEND) &&
944 iscomment(line + 2, "PageBoundingBox:")) {
945 sscanf(line + length("%%PageBoundingBox:"), "%256s", text);
946 if(strcmp(text, "(atend)") == 0) {
951 (line + length("%%PageBoundingBox:"), "%d %d %d %d",
952 &(doc->pages[doc->numpages].boundingbox[LLX]),
953 &(doc->pages[doc->numpages].boundingbox[LLY]),
954 &(doc->pages[doc->numpages].boundingbox[URX]),
955 &(doc->pages[doc->numpages].boundingbox[URY])) == 4) {
956 if(page_bb_set == NONE)
960 float fllx, flly, furx, fury;
961 if(sscanf(line + length("%%PageBoundingBox:"),
962 "%f %f %f %f", &fllx, &flly, &furx, &fury) == 4) {
963 if(page_bb_set == NONE)
965 doc->pages[doc->numpages].boundingbox[LLX] = fllx;
966 doc->pages[doc->numpages].boundingbox[LLY] = flly;
967 doc->pages[doc->numpages].boundingbox[URX] = furx;
968 doc->pages[doc->numpages].boundingbox[URY] = fury;
969 if(fllx < doc->pages[doc->numpages].boundingbox[LLX])
970 doc->pages[doc->numpages].boundingbox[LLX]--;
971 if(flly < doc->pages[doc->numpages].boundingbox[LLY])
972 doc->pages[doc->numpages].boundingbox[LLY]--;
973 if(furx > doc->pages[doc->numpages].boundingbox[URX])
974 doc->pages[doc->numpages].boundingbox[URX]++;
975 if(fury > doc->pages[doc->numpages].boundingbox[URY])
976 doc->pages[doc->numpages].boundingbox[URY]++;
982 section_len += line_len;
983 doc->pages[doc->numpages].end = position;
984 doc->pages[doc->numpages].len = section_len - line_len;
988 /* Document Trailer */
991 doc->begintrailer = beginsection;
995 doc->begintrailer = position;
996 section_len = line_len;
1001 readline(fd, &line, &position, &line_len)) &&
1002 !(respect_eof && DSCcomment(line) && iscomment(line + 2, "EOF"))) {
1004 section_len += line_len;
1006 if(!DSCcomment(line)) {
1009 else if(iscomment(line + 2, "Page:")) {
1010 g_free(get_next_text(line + length("%%Page:"), &next_char));
1011 if(sscanf(next_char, "%d", &thispage) != 1)
1013 if(!ignore && thispage == nextpage) {
1014 if(doc->numpages > 0) {
1015 doc->pages[doc->numpages - 1].end = position;
1016 doc->pages[doc->numpages - 1].len += section_len - line_len;
1020 doc->endsetup = position;
1021 doc->endsetup += section_len - line_len;
1023 else if(doc->endprolog) {
1024 doc->endprolog = position;
1025 doc->endprolog += section_len - line_len;
1031 else if(!respect_eof && iscomment(line + 2, "Trailer")) {
1032 /* What we thought was the start of the trailer was really */
1033 /* the trailer of an EPS on the page. */
1034 /* Set the end of the page to this trailer and keep scanning. */
1035 if(doc->numpages > 0) {
1036 doc->pages[doc->numpages - 1].end = position;
1037 doc->pages[doc->numpages - 1].len += section_len - line_len;
1039 doc->begintrailer = position;
1040 section_len = line_len;
1042 else if(bb_set == ATEND && iscomment(line + 2, "BoundingBox:")) {
1043 if(sscanf(line + length("%%BoundingBox:"), "%d %d %d %d",
1044 &(doc->boundingbox[LLX]),
1045 &(doc->boundingbox[LLY]),
1046 &(doc->boundingbox[URX]), &(doc->boundingbox[URY])) != 4) {
1047 float fllx, flly, furx, fury;
1048 if(sscanf(line + length("%%BoundingBox:"), "%f %f %f %f",
1049 &fllx, &flly, &furx, &fury) == 4) {
1050 doc->boundingbox[LLX] = fllx;
1051 doc->boundingbox[LLY] = flly;
1052 doc->boundingbox[URX] = furx;
1053 doc->boundingbox[URY] = fury;
1054 if(fllx < doc->boundingbox[LLX])
1055 doc->boundingbox[LLX]--;
1056 if(flly < doc->boundingbox[LLY])
1057 doc->boundingbox[LLY]--;
1058 if(furx > doc->boundingbox[URX])
1059 doc->boundingbox[URX]++;
1060 if(fury > doc->boundingbox[URY])
1061 doc->boundingbox[URY]++;
1065 else if(orientation_set == ATEND && iscomment(line + 2, "Orientation:")) {
1066 sscanf(line + length("%%Orientation:"), "%256s", text);
1067 if(strcmp(text, "Portrait") == 0) {
1068 doc->orientation = GTK_GS_ORIENTATION_PORTRAIT;
1070 else if(strcmp(text, "Landscape") == 0) {
1071 doc->orientation = GTK_GS_ORIENTATION_LANDSCAPE;
1073 else if(strcmp(text, "Seascape") == 0) {
1074 doc->orientation = GTK_GS_ORIENTATION_SEASCAPE;
1077 else if(page_order_set == ATEND && iscomment(line + 2, "PageOrder:")) {
1078 sscanf(line + length("%%PageOrder:"), "%256s", text);
1079 if(strcmp(text, "Ascend") == 0) {
1080 doc->pageorder = ASCEND;
1082 else if(strcmp(text, "Descend") == 0) {
1083 doc->pageorder = DESCEND;
1085 else if(strcmp(text, "Special") == 0) {
1086 doc->pageorder = SPECIAL;
1089 else if(pages_set == ATEND && iscomment(line + 2, "Pages:")) {
1090 if(sscanf(line + length("%%Pages:"), "%*u %d", &i) == 1) {
1091 if(page_order_set == NONE) {
1093 doc->pageorder = DESCEND;
1095 doc->pageorder = SPECIAL;
1097 doc->pageorder = ASCEND;
1102 section_len += line_len;
1103 if(DSCcomment(line) && iscomment(line + 2, "EOF")) {
1104 readline(fd, &line, &position, &line_len);
1105 section_len += line_len;
1107 doc->endtrailer = position;
1108 doc->lentrailer = section_len - line_len;
1111 section_len = line_len;
1113 while(preread || readline(line, sizeof line, file, &position, &line_len)) {
1115 section_len += line_len;
1117 if(DSCcomment(line) && iscomment(line + 2, "Page:")) {
1118 g_free(get_next_text(line + length("%%Page:"), &next_char));
1119 if(sscanf(next_char, "%d", &thispage) != 1)
1121 if(!ignore && thispage == nextpage) {
1122 if(doc->numpages > 0) {
1123 doc->pages[doc->numpages - 1].end = position;
1124 doc->pages[doc->numpages - 1].len += doc->lentrailer +
1125 section_len - line_len;
1129 doc->endsetup = position;
1130 doc->endsetup += doc->lentrailer + section_len - line_len;
1132 else if(doc->endprolog) {
1133 doc->endprolog = position;
1134 doc->endprolog += doc->lentrailer + section_len - line_len;
1147 * psfree -- free dynamic storage associated with document structure.
1152 struct document *doc;
1158 printf("This document exists\n");
1160 for(i = 0; i < doc->numpages; i++) {
1161 if(doc->pages[i].label)
1162 g_free(doc->pages[i].label);
1164 for(i = 0; i < doc->numsizes; i++) {
1165 if(doc->size[i].name)
1166 g_free(doc->size[i].name);
1173 g_free(doc->creator);
1183 * gettextine -- skip over white space and return the rest of the line.
1184 * If the text begins with '(' return the text string
1185 * using get_next_text().
1189 gettextline(char *line)
1193 while(*line && (*line == ' ' || *line == '\t'))
1196 return get_next_text(line, NULL);
1199 if(strlen(line) == 0)
1202 cp = g_strdup(line);
1204 /* Remove end of line */
1205 if(cp[strlen(line) - 2] == '\r' && cp[strlen(line) - 1] == '\n')
1206 /* Handle DOS \r\n */
1207 cp[strlen(line) - 2] = '\0';
1208 else if(cp[strlen(line) - 1] == '\n' || cp[strlen(line) - 1] == '\r')
1209 /* Handle mac and unix */
1210 cp[strlen(line) - 1] = '\0';
1217 * get_next_text -- return the next text string on the line.
1218 * return NULL if nothing is present.
1222 get_next_text(line, next_char)
1226 char text[PSLINELENGTH]; /* Temporary storage for text */
1230 while(*line && (*line == ' ' || *line == '\t'))
1237 while(*line && !(*line == ')' && level == 0)
1238 && (cp - text) < PSLINELENGTH - 1) {
1240 if(*(line + 1) == 'n') {
1244 else if(*(line + 1) == 'r') {
1248 else if(*(line + 1) == 't') {
1252 else if(*(line + 1) == 'b') {
1256 else if(*(line + 1) == 'f') {
1260 else if(*(line + 1) == '\\') {
1264 else if(*(line + 1) == '(') {
1268 else if(*(line + 1) == ')') {
1272 else if(*(line + 1) >= '0' && *(line + 1) <= '9') {
1273 if(*(line + 2) >= '0' && *(line + 2) <= '9') {
1274 if(*(line + 3) >= '0' && *(line + 3) <= '9') {
1276 ((*(line + 1) - '0') * 8 + *(line + 2) -
1277 '0') * 8 + *(line + 3) - '0';
1281 *cp++ = (*(line + 1) - '0') * 8 + *(line + 2) - '0';
1286 *cp++ = *(line + 1) - '0';
1295 else if(*line == '(') {
1299 else if(*line == ')') {
1309 while(*line && !(*line == ' ' || *line == '\t' || *line == '\n')
1310 && (cp - text) < PSLINELENGTH - 1)
1316 if(!quoted && strlen(text) == 0)
1318 return g_strdup(text);
1322 * pscopy -- copy lines of Postscript from a section of one file
1324 * Automatically switch to binary copying whenever
1325 * %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
1326 * comments are encountered.
1330 pscopy(from, to, begin, end)
1333 long begin; /* set negative to avoid initial seek */
1336 char line[PSLINELENGTH]; /* 255 characters + 1 newline + 1 NULL */
1337 char text[PSLINELENGTH]; /* Temporary storage for text */
1343 fseek(from, begin, SEEK_SET);
1344 while(ftell(from) < end) {
1345 fgets(line, sizeof line, from);
1346 gtk_gs_doc_sink_write(to, line, strlen(line));
1348 if(!(DSCcomment(line) && iscomment(line + 2, "Begin"))) {
1351 else if(iscomment(line + 7, "Data:")) {
1353 if(sscanf(line + length("%%BeginData:"), "%d %*s %256s", &num, text) >= 1) {
1354 if(strcmp(text, "Lines") == 0) {
1355 for(i = 0; i < num; i++) {
1356 fgets(line, sizeof(line), from);
1357 gtk_gs_doc_sink_write(to, line, strlen(line));
1361 while(num > BUFSIZ) {
1362 fread(buf, sizeof(char), BUFSIZ, from);
1363 gtk_gs_doc_sink_write(to, buf, BUFSIZ);
1366 fread(buf, sizeof(char), num, from);
1367 gtk_gs_doc_sink_write(to, buf, num);
1371 else if(iscomment(line + 7, "Binary:")) {
1372 if(sscanf(line + length("%%BeginBinary:"), "%d", &num) == 1) {
1373 while(num > BUFSIZ) {
1374 fread(buf, sizeof(char), BUFSIZ, from);
1375 gtk_gs_doc_sink_write(to, buf, BUFSIZ);
1378 fread(buf, sizeof(char), num, from);
1379 gtk_gs_doc_sink_write(to, buf, num);
1386 * pscopyuntil -- copy lines of Postscript from a section of one file
1387 * to another file until a particular comment is reached.
1388 * Automatically switch to binary copying whenever
1389 * %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
1390 * comments are encountered.
1394 pscopyuntil(FILE * from, GtkGSDocSink * to, long begin, long end,
1395 const char *comment)
1397 char line[PSLINELENGTH]; /* 255 characters + 1 newline + 1 NULL */
1398 char text[PSLINELENGTH]; /* Temporary storage for text */
1405 comment_length = strlen(comment);
1409 fseek(from, begin, SEEK_SET);
1411 while(ftell(from) < end && !feof(from)) {
1412 fgets(line, sizeof line, from);
1414 /* iscomment cannot be used here,
1415 * because comment_length is not known at compile time. */
1416 if(comment != NULL && strncmp(line, comment, comment_length) == 0) {
1417 return g_strdup(line);
1419 gtk_gs_doc_sink_write(to, line, strlen(line));
1420 if(!(DSCcomment(line) && iscomment(line + 2, "Begin"))) {
1423 else if(iscomment(line + 7, "Data:")) {
1425 if(sscanf(line + length("%%BeginData:"), "%d %*s %256s", &num, text) >= 1) {
1426 if(strcmp(text, "Lines") == 0) {
1427 for(i = 0; i < num; i++) {
1428 fgets(line, sizeof line, from);
1429 gtk_gs_doc_sink_write(to, line, strlen(line));
1433 while(num > BUFSIZ) {
1434 fread(buf, sizeof(char), BUFSIZ, from);
1435 gtk_gs_doc_sink_write(to, buf, BUFSIZ);
1438 fread(buf, sizeof(char), num, from);
1439 gtk_gs_doc_sink_write(to, buf, num);
1443 else if(iscomment(line + 7, "Binary:")) {
1444 if(sscanf(line + length("%%BeginBinary:"), "%d", &num) == 1) {
1445 while(num > BUFSIZ) {
1446 fread(buf, sizeof(char), BUFSIZ, from);
1447 gtk_gs_doc_sink_write(to, buf, BUFSIZ);
1450 fread(buf, sizeof(char), num, from);
1451 gtk_gs_doc_sink_write(to, buf, num);
1459 * blank -- determine whether the line contains nothing but whitespace.
1467 while(*cp == ' ' || *cp == '\t')
1469 return *cp == '\n' || (*cp == '%' && (line[0] != '%' || line[1] != '%'));
1472 /*##########################################################*/
1474 /* Copy the headers, marked pages, and trailer to fp */
1475 /*##########################################################*/
1478 pscopydoc(GtkGSDocSink * dest,
1479 char *src_filename, struct document *d, gint * pagelist)
1482 char text[PSLINELENGTH];
1484 gboolean pages_written = FALSE;
1485 gboolean pages_atend = FALSE;
1491 src_file = fopen(src_filename, "r");
1494 for(i = 0; i < d->numpages; i++) {
1499 here = d->beginheader;
1501 while((comment = pscopyuntil(src_file, dest, here, d->endheader, "%%Pages:"))) {
1502 here = ftell(src_file);
1503 if(pages_written || pages_atend) {
1507 sscanf(comment + length("%%Pages:"), "%256s", text);
1508 if(strcmp(text, "(atend)") == 0) {
1509 gtk_gs_doc_sink_write(dest, comment, strlen(comment));
1513 switch (sscanf(comment + length("%%Pages:"), "%*d %d", &i)) {
1515 gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d %d\n", pages, i);
1518 gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d\n", pages);
1521 pages_written = TRUE;
1525 pscopyuntil(src_file, dest, d->beginpreview, d->endpreview, NULL);
1526 pscopyuntil(src_file, dest, d->begindefaults, d->enddefaults, NULL);
1527 pscopyuntil(src_file, dest, d->beginprolog, d->endprolog, NULL);
1528 pscopyuntil(src_file, dest, d->beginsetup, d->endsetup, NULL);
1530 for(i = 0; i < d->numpages; i++) {
1531 if(d->pageorder == DESCEND)
1532 j = (d->numpages - 1) - i;
1537 comment = pscopyuntil(src_file, dest,
1538 d->pages[i].begin, d->pages[i].end, "%%Page:");
1539 gtk_gs_doc_sink_printf(dest, "%%%%Page: %s %d\n",
1540 d->pages[i].label, page++);
1542 pscopyuntil(src_file, dest, -1, d->pages[i].end, NULL);
1546 here = d->begintrailer;
1547 while((comment = pscopyuntil(src_file, dest, here, d->endtrailer,
1549 here = ftell(src_file);
1554 switch (sscanf(comment + length("%%Pages:"), "%*d %d", &i)) {
1556 gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d %d\n", pages, i);
1559 gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d\n", pages);
1562 pages_written = TRUE;
1569 /*----------------------------------------------------------*/
1571 /*----------------------------------------------------------*/
1573 #define FD_FILE (fd->file)
1574 #define FD_FILE_DESC (fd->file_desc)
1575 #define FD_FILEPOS (fd->filepos)
1576 #define FD_LINE_BEGIN (fd->line_begin)
1577 #define FD_LINE_END (fd->line_end)
1578 #define FD_LINE_LEN (fd->line_len)
1579 #define FD_LINE_TERMCHAR (fd->line_termchar)
1580 #define FD_BUF (fd->buf)
1581 #define FD_BUF_END (fd->buf_end)
1582 #define FD_BUF_SIZE (fd->buf_size)
1583 #define FD_STATUS (fd->status)
1585 #define FD_STATUS_OKAY 0
1586 #define FD_STATUS_BUFTOOLARGE 1
1587 #define FD_STATUS_NOMORECHARS 2
1589 #define LINE_CHUNK_SIZE 4096
1590 #define MAX_PS_IO_FGETCHARS_BUF_SIZE 57344
1591 #define BREAK_PS_IO_FGETCHARS_BUF_SIZE 49152
1593 static FileData ps_io_init(file)
1597 size_t size = sizeof(FileDataStruct);
1599 fd = (FileData) g_malloc(size);
1600 memset((void*) fd ,0,(size_t)size);
1604 FD_FILE_DESC = fileno(file);
1605 FD_FILEPOS = ftell(file);
1606 FD_BUF_SIZE = (2*LINE_CHUNK_SIZE)+1;
1607 FD_BUF = g_malloc(FD_BUF_SIZE);
1612 /*----------------------------------------------------------*/
1614 /*----------------------------------------------------------*/
1624 /*----------------------------------------------------------*/
1626 /*----------------------------------------------------------*/
1629 ps_io_fseek(fd,offset)
1634 status=fseek(FD_FILE,(long)offset,SEEK_SET);
1635 FD_BUF_END = FD_LINE_BEGIN = FD_LINE_END = FD_LINE_LEN = 0;
1636 FD_FILEPOS = offset;
1637 FD_STATUS = FD_STATUS_OKAY;
1641 /*----------------------------------------------------------*/
1643 /*----------------------------------------------------------*/
1652 /*----------------------------------------------------------*/
1653 /* ps_io_fgetchars */
1654 /*----------------------------------------------------------*/
1656 #ifdef USE_MEMMOVE_CODE
1657 static void ps_memmove (d, s, l)
1662 if (s < d) for (s += l, d += l; l; --l) *--d = *--s;
1663 else if (s != d) for (; l; --l) *d++ = *s++;
1666 # define ps_memmove memmove
1669 static char * ps_io_fgetchars(fd,num)
1673 char *eol=NULL,*tmp;
1674 size_t size_of_char = sizeof(char);
1676 if (FD_STATUS != FD_STATUS_OKAY) {
1680 FD_BUF[FD_LINE_END] = FD_LINE_TERMCHAR; /* restoring char previously exchanged against '\0' */
1681 FD_LINE_BEGIN = FD_LINE_END;
1684 if (num<0) { /* reading whole line */
1685 if (FD_BUF_END-FD_LINE_END) {
1686 /* strpbrk is faster but fails on lines with embedded NULLs
1687 eol = strpbrk(FD_BUF+FD_LINE_END,"\n\r");
1689 tmp = FD_BUF + FD_BUF_END;
1690 eol = FD_BUF + FD_LINE_END;
1691 while (eol < tmp && *eol != '\n' && *eol != '\r') eol++;
1692 if (eol >= tmp) eol = NULL;
1694 if (*eol=='\r' && *(eol+1)=='\n') eol += 2;
1699 } else { /* reading specified num of chars */
1700 if (FD_BUF_END >= FD_LINE_BEGIN+num) {
1701 eol = FD_BUF+FD_LINE_BEGIN+num;
1706 if (FD_BUF_END - FD_LINE_BEGIN > BREAK_PS_IO_FGETCHARS_BUF_SIZE) {
1707 eol = FD_BUF + FD_BUF_END - 1;
1711 while (FD_BUF_SIZE < FD_BUF_END+LINE_CHUNK_SIZE+1) {
1712 if (FD_BUF_SIZE > MAX_PS_IO_FGETCHARS_BUF_SIZE) {
1713 /* we should never get here, since the line is broken
1714 artificially after BREAK_PS_IO_FGETCHARS_BUF_SIZE bytes. */
1715 fprintf(stderr, "gv: ps_io_fgetchars: Fatal Error: buffer became too large.\n");
1718 if (FD_LINE_BEGIN) {
1719 ps_memmove((void*)FD_BUF,(void*)(FD_BUF+FD_LINE_BEGIN),
1720 ((size_t)(FD_BUF_END-FD_LINE_BEGIN+1))*size_of_char);
1721 FD_BUF_END -= FD_LINE_BEGIN;
1724 FD_BUF_SIZE = FD_BUF_SIZE+LINE_CHUNK_SIZE+1;
1725 FD_BUF = g_realloc(FD_BUF,FD_BUF_SIZE);
1729 FD_LINE_END = FD_BUF_END;
1731 /* different existing VMS file formats require that we use read here ###jp###,10/12/96 */
1732 if (num<0) FD_BUF_END += read(FD_FILE_DESC,FD_BUF+FD_BUF_END,LINE_CHUNK_SIZE);
1733 else FD_BUF_END += fread(FD_BUF+FD_BUF_END,size_of_char,LINE_CHUNK_SIZE,FD_FILE);
1735 /* read() seems to fail sometimes (? ? ?) so we always use fread ###jp###,07/31/96*/
1736 FD_BUF_END += fread(FD_BUF+FD_BUF_END,size_of_char,LINE_CHUNK_SIZE,FD_FILE);
1739 FD_BUF[FD_BUF_END] = '\0';
1740 if (FD_BUF_END-FD_LINE_END == 0) {
1741 FD_STATUS = FD_STATUS_NOMORECHARS;
1747 FD_LINE_END = eol - FD_BUF;
1748 FD_LINE_LEN = FD_LINE_END - FD_LINE_BEGIN;
1749 FD_LINE_TERMCHAR = FD_BUF[FD_LINE_END];
1750 FD_BUF[FD_LINE_END] = '\0';
1751 #ifdef USE_FTELL_FOR_FILEPOS
1752 if (FD_LINE_END==FD_BUF_END) {
1754 For VMS we cannot assume that the record is FD_LINE_LEN bytes long
1755 on the disk. For stream_lf and stream_cr that is true, but not for
1756 other formats, since VAXC/DECC converts the formatting into a single \n.
1757 eg. variable format files have a 2-byte length and padding to an even
1758 number of characters. So, we use ftell for each record.
1759 This still will not work if we need to fseek to a \n or \r inside a
1760 variable record (ftell always returns the start of the record in this
1762 (Tim Adye, adye@v2.rl.ac.uk)
1764 FD_FILEPOS = ftell(FD_FILE);
1766 #endif /* USE_FTELL_FOR_FILEPOS */
1767 FD_FILEPOS += FD_LINE_LEN;
1769 return(FD_BUF+FD_LINE_BEGIN);
1772 /*----------------------------------------------------------*/
1775 Read the next line in the postscript file.
1776 Automatically skip over data (as indicated by
1777 %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
1779 Also, skip over included documents (as indicated by
1780 %%BeginDocument/%%EndDocument comments.)
1782 /*----------------------------------------------------------*/
1784 static char *readline (fd, lineP, positionP, line_lenP)
1788 unsigned int *line_lenP;
1790 unsigned int nbytes=0;
1794 if (positionP) *positionP = FD_FILEPOS;
1795 line = ps_io_fgetchars(fd,-1);
1798 *lineP = empty_string;
1802 *line_lenP = FD_LINE_LEN;
1804 #define IS_COMMENT(comment) \
1805 (DSCcomment(line) && iscomment(line+2,(comment)))
1806 #define IS_BEGIN(comment) \
1807 (iscomment(line+7,(comment)))
1808 #define SKIP_WHILE(cond) \
1809 while (readline(fd, &line, NULL, &nbytes) && (cond)) *line_lenP += nbytes;\
1811 #define SKIP_UNTIL_1(comment) { \
1812 SKIP_WHILE((!IS_COMMENT(comment))) \
1814 #define SKIP_UNTIL_2(comment1,comment2) { \
1815 SKIP_WHILE((!IS_COMMENT(comment1) && !IS_COMMENT(comment2)))\
1818 if (!IS_COMMENT("Begin")) {} /* Do nothing */
1819 else if IS_BEGIN("Document:") SKIP_UNTIL_1("EndDocument")
1820 else if IS_BEGIN("Feature:") SKIP_UNTIL_1("EndFeature")
1821 #ifdef USE_ACROREAD_WORKAROUND
1822 else if IS_BEGIN("File") SKIP_UNTIL_2("EndFile","EOF")
1824 else if IS_BEGIN("File") SKIP_UNTIL_1("EndFile")
1826 else if IS_BEGIN("Font") SKIP_UNTIL_1("EndFont")
1827 else if IS_BEGIN("ProcSet") SKIP_UNTIL_1("EndProcSet")
1828 else if IS_BEGIN("Resource") SKIP_UNTIL_1("EndResource")
1829 else if IS_BEGIN("Data:") {
1832 if (FD_LINE_LEN > 100) FD_BUF[100] = '\0';
1834 if (sscanf(line+length("%%BeginData:"), "%d %*s %s", &num, text) >= 1) {
1835 if (strcmp(text, "Lines") == 0) {
1837 line = ps_io_fgetchars(fd,-1);
1838 if (line) *line_lenP += FD_LINE_LEN;
1842 int read_chunk_size = LINE_CHUNK_SIZE;
1844 if (num <= LINE_CHUNK_SIZE) read_chunk_size=num;
1845 line = ps_io_fgetchars(fd,read_chunk_size);
1846 if (line) *line_lenP += FD_LINE_LEN;
1847 num -= read_chunk_size;
1851 SKIP_UNTIL_1("EndData")
1853 else if IS_BEGIN("Binary:") {
1855 if (sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
1856 int read_chunk_size = LINE_CHUNK_SIZE;
1858 if (num <= LINE_CHUNK_SIZE) read_chunk_size=num;
1859 line = ps_io_fgetchars(fd,read_chunk_size);
1860 if (line) *line_lenP += FD_LINE_LEN;
1861 num -= read_chunk_size;
1863 SKIP_UNTIL_1("EndBinary")
1868 *line_lenP += nbytes;
1869 *lineP = skipped_line;
1871 *lineP = FD_BUF+FD_LINE_BEGIN;
1874 return(FD_BUF+FD_LINE_BEGIN);
1877 #define DEFAULT_PAGE_SIZE 1
1880 psgetpagebox (const struct document *doc, int page, int *urx, int *ury, int *llx, int *lly)
1886 GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes ();
1887 int new_pagesize = -1;
1889 if (new_pagesize == -1) {
1890 new_pagesize = DEFAULT_PAGE_SIZE;
1892 /* If we have a document:
1893 * We use -- the page size (if specified)
1894 * or the doc. size (if specified)
1895 * or the page bbox (if specified)
1896 * or the bounding box
1898 if ((page >= 0) && (doc->numpages > page) &&
1899 (doc->pages) && (doc->pages[page].size)) {
1900 new_pagesize = doc->pages[page].size - doc->size;
1901 } else if (doc->default_page_size != NULL) {
1902 new_pagesize = doc->default_page_size - doc->size;
1903 } else if ((page >= 0) &&
1904 (doc->numpages > page) &&
1906 (doc->pages[page].boundingbox[URX] >
1907 doc->pages[page].boundingbox[LLX]) &&
1908 (doc->pages[page].boundingbox[URY] >
1909 doc->pages[page].boundingbox[LLY])) {
1911 } else if ((doc->boundingbox[URX] > doc->boundingbox[LLX]) &&
1912 (doc->boundingbox[URY] > doc->boundingbox[LLY])) {
1918 /* Compute bounding box */
1919 if (doc && (doc->epsf || new_pagesize == -1)) { /* epsf or bbox */
1922 (doc->pages[page].boundingbox[URX] >
1923 doc->pages[page].boundingbox[LLX]) &&
1924 (doc->pages[page].boundingbox[URY] >
1925 doc->pages[page].boundingbox[LLY])) {
1927 new_llx = doc->pages[page].boundingbox[LLX];
1928 new_lly = doc->pages[page].boundingbox[LLY];
1929 new_urx = doc->pages[page].boundingbox[URX];
1930 new_ury = doc->pages[page].boundingbox[URY];
1931 } else if ((doc->boundingbox[URX] > doc->boundingbox[LLX]) &&
1932 (doc->boundingbox[URY] > doc->boundingbox[LLY])) {
1934 new_llx = doc->boundingbox[LLX];
1935 new_lly = doc->boundingbox[LLY];
1936 new_urx = doc->boundingbox[URX];
1937 new_ury = doc->boundingbox[URY];
1940 if (new_pagesize < 0)
1941 new_pagesize = DEFAULT_PAGE_SIZE;
1942 new_llx = new_lly = 0;
1943 if (doc && doc->size &&
1944 (new_pagesize < doc->numsizes)) {
1945 new_urx = doc->size[new_pagesize].width;
1946 new_ury = doc->size[new_pagesize].height;
1948 new_urx = papersizes[new_pagesize].width;
1949 new_ury = papersizes[new_pagesize].height;
1953 if (new_urx <= new_llx)
1954 new_urx = papersizes[12].width;
1955 if (new_ury <= new_lly)
1956 new_ury = papersizes[12].height;