]> www.fi.muni.cz Git - evince.git/blob - backend/ps/ps.c
Updated Spanish translation
[evince.git] / backend / ps / ps.c
1 /*
2  * ps.c -- Postscript scanning and copying routines.
3  * Copyright (C) 1992, 1998  Timothy O. Theisen
4  *
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.
9  *
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.
14  *
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.
18  *
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
24  */
25
26 /* 18/3/98 Jake Hamby patch */
27
28 /*
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/
35  */
36
37 /* GV by        Johannes Plass
38  *                      Department of Physics
39  *                      Johannes Gutenberg University
40  *                      Mainz, Germany
41  *              
42  *                      <plass@thep.physik.uni-mainz.de>
43  */
44
45 /* end of patch */
46
47 #include <config.h>
48 #include <stdlib.h>
49 #include <stdio.h>
50 #ifndef SEEK_SET
51 #   define SEEK_SET 0
52 #endif
53 #ifndef BUFSIZ
54 #   define BUFSIZ 1024
55 #endif
56 #include <ctype.h>
57 #include <X11/Xos.h>            /* #includes the appropriate <string.h> */
58 #include "gstypes.h"
59 #include "gsdefaults.h"
60 #include "ps.h"
61 #include "gsio.h"
62
63 #include <glib.h>
64
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] == '%')
70
71     /* list of standard paper sizes from Adobe's PPD. */
72
73 /*--------------------------------------------------*/
74 /* Declarations for ps_io_*() routines. */
75
76 typedef struct FileDataStruct_ *FileData;
77
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 */
90 } FileDataStruct;
91
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);
95
96 static char    *skipped_line = "% ps_io_fgetchars: skipped line";
97 static char    *empty_string = "";
98
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);
103
104 static struct page *
105 pages_new(struct page *pages, int current, int maxpages)
106 {
107   struct page *oldpages = pages;
108   if(!oldpages)
109     pages = g_new0(struct page, maxpages);
110   else
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;
115   }
116   return pages;
117 }
118
119 /*
120  *      psscan -- scan the PostScript file for document structuring comments.
121  *
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.)
130  *
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.
139  *
140  *      The following comments are examined:
141  *
142  *      Header section: 
143  *      Must start with %!PS-Adobe-.  Version numbers ignored.
144  *      Also allowed to be just %!PS, many files seem to have that.
145  *
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>
156  *      %%EndComments
157  *
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.
161  *
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.
165  *
166  *      If the file is encapsulated PostScript the optional Preview section
167  *      is next:
168  *
169  *      %%BeginPreview
170  *      %%EndPreview
171  *
172  *      This section explicitly begins and ends with the above comments.
173  *
174  *      Next the Defaults section for version 3 page defaults:
175  *
176  *      %%BeginDefaults
177  *      %%PageBoundingBox: <int> <int> <int> <int>
178  *      %%PageOrientation: Portrait|Landscape
179  *      %%PageMedia: <text>
180  *      %%EndDefaults
181  *
182  *      This section explicitly begins and ends with the above comments.
183  *
184  *      The prolog section either explicitly starts with %%BeginProlog or
185  *      implicitly with any nonblank line.
186  *
187  *      %%BeginProlog
188  *      %%EndProlog
189  *
190  *      The Prolog should end with %%EndProlog, however the proglog implicitly
191  *      ends when %%BeginSetup, %%Page, %%Trailer or %%EOF are encountered.
192  *
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.
196  *
197  *      %%BeginSetup
198  *      %%PageBoundingBox: <int> <int> <int> <int>
199  *      %%PageOrientation: Portrait|Landscape
200  *      %%PaperSize: <text>
201  *      %%EndSetup
202  *
203  *      The Setup should end with %%EndSetup, however the setup implicitly
204  *      ends when %%Page, %%Trailer or %%EOF are encountered.
205  *
206  *      Next each page starts explicitly with %%Page and ends implicitly with
207  *      %%Page or %%Trailer or %%EOF.  The following comments are recognized:
208  *
209  *      %%Page: <text> <uint>
210  *      %%PageBoundingBox: <int> <int> <int> <int>|(atend)
211  *      %%PageOrientation: Portrait|Landscape
212  *      %%PageMedia: <text>
213  *      %%PaperSize: <text>
214  *
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:
218  *
219  *      %%Trailer
220  *      %%BoundingBox: <int> <int> <int> <int>|(atend)
221  *      %%Orientation: Portrait|Landscape|(atend)
222  *      %%Pages: <uint> [<int>]|(atend)
223  *      %%PageOrder: Ascend|Descend|Special|(atend)
224  *      %%EOF
225  *
226  *
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.
230  */
231
232 #include <glib.h>
233
234 struct document *
235 psscan(FILE * file, int respect_eof, const gchar * fname)
236 {
237   struct document *doc;
238   int bb_set = NONE;
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 */
245   int i;
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 */
250   char *label;
251   char *line;
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() */
258   char *cp;
259   GtkGSPaperSize *dmp;
260   GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes();
261   FileData fd;
262
263   if(!file)
264     return NULL;
265
266   rewind(file);
267
268   fd = ps_io_init(file);
269   if (!readline(fd, &line, &position, &line_len)) {
270     fprintf(stderr, "Warning: empty file.\n");
271     ps_io_exit(fd);
272     return(NULL);
273   }
274
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] != '%')) ;
282     if(line[0] != '%') {
283       g_print("psscan error: input files seems to be a PJL file.\n");
284       ps_io_exit(fd);
285       return (NULL);
286     }
287   }
288
289   /* Header comments */
290
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;
297
298     /* ignore possible leading ^D */
299     if(*line == '\004') {
300       position++;
301       line_len--;
302     }
303
304 /* Jake Hamby patch 18/3/98 */
305
306     text[0] = '\0';
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;
312   }
313   else {
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:
317
318        http://svrc.it.uq.edu.au/Bibliography/svrc-tr.html?94-45
319
320        add ugly PostScript before the actual document. 
321
322        GS and gv is
323        able to display them correctly as unstructured PS.
324
325        In a way, this makes sense, a program PostScript does not need
326        the !PS at the beginning.
327      */
328     doc = g_new0(struct document, 1);
329     doc->default_page_orientation = GTK_GS_ORIENTATION_NONE;
330     doc->orientation = GTK_GS_ORIENTATION_NONE;
331     ps_io_exit(fd);
332     return (doc);
333   }
334
335   preread = 0;
336   while(preread || readline(fd, &line, &position, &line_len)) {
337     if(!preread)
338       section_len += line_len;
339     preread = 0;
340     if(line[0] != '%' ||
341        iscomment(line + 1, "%EndComments") ||
342        line[1] == ' ' || line[1] == '\t' || line[1] == '\n' ||
343        !isprint(line[1])) {
344       break;
345     }
346     else if(line[1] != '%') {
347       /* Do nothing */
348     }
349     else if(doc->title == NULL && iscomment(line + 2, "Title:")) {
350       doc->title = gettextline(line + length("%%Title:"));
351     }
352     else if(doc->date == NULL && iscomment(line + 2, "CreationDate:")) {
353       doc->date = gettextline(line + length("%%CreationDate:"));
354     }
355     else if(doc->creator == NULL && iscomment(line + 2, "Creator:")) {
356       doc->creator = gettextline(line + length("%%Creator:"));
357     }
358     else if(bb_set == NONE && iscomment(line + 2, "BoundingBox:")) {
359       sscanf(line + length("%%BoundingBox:"), "%256s", text);
360       if(strcmp(text, "(atend)") == 0) {
361         bb_set = ATEND;
362       }
363       else {
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)
368           bb_set = 1;
369         else {
370           float fllx, flly, furx, fury;
371           if(sscanf(line + length("%%BoundingBox:"), "%f %f %f %f",
372                     &fllx, &flly, &furx, &fury) == 4) {
373             bb_set = 1;
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]++;
386           }
387         }
388       }
389     }
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;
394       }
395       else if(strcmp(text, "Portrait") == 0) {
396         doc->orientation = GTK_GS_ORIENTATION_PORTRAIT;
397         orientation_set = 1;
398       }
399       else if(strcmp(text, "Landscape") == 0) {
400         doc->orientation = GTK_GS_ORIENTATION_LANDSCAPE;
401         orientation_set = 1;
402       }
403       else if(strcmp(text, "Seascape") == 0) {
404         doc->orientation = GTK_GS_ORIENTATION_SEASCAPE;
405         orientation_set = 1;
406       }
407     }
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;
412       }
413       else if(strcmp(text, "Ascend") == 0) {
414         doc->pageorder = ASCEND;
415         page_order_set = 1;
416       }
417       else if(strcmp(text, "Descend") == 0) {
418         doc->pageorder = DESCEND;
419         page_order_set = 1;
420       }
421       else if(strcmp(text, "Special") == 0) {
422         doc->pageorder = SPECIAL;
423         page_order_set = 1;
424       }
425     }
426     else if(pages_set == NONE && iscomment(line + 2, "Pages:")) {
427       sscanf(line + length("%%Pages:"), "%256s", text);
428       if(strcmp(text, "(atend)") == 0) {
429         pages_set = ATEND;
430       }
431       else {
432         switch (sscanf(line + length("%%Pages:"), "%d %d", &maxpages, &i)) {
433         case 2:
434           if(page_order_set == NONE) {
435             if(i == -1) {
436               doc->pageorder = DESCEND;
437               page_order_set = 1;
438             }
439             else if(i == 0) {
440               doc->pageorder = SPECIAL;
441               page_order_set = 1;
442             }
443             else if(i == 1) {
444               doc->pageorder = ASCEND;
445               page_order_set = 1;
446             }
447           }
448         case 1:
449           if(maxpages > 0)
450             doc->pages = pages_new(NULL, 0, maxpages);
451         }
452       }
453     }
454     else if(doc->numsizes == NONE && iscomment(line + 2, "DocumentMedia:")) {
455       float w, h;
456       doc->size = g_new0(GtkGSPaperSize, 1);
457       doc->size[0].name =
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;
463         }
464         if(doc->size[0].width != 0 && doc->size[0].height != 0)
465           doc->numsizes = 1;
466         else
467           g_free(doc->size[0].name);
468       }
469       preread = 1;
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;
480           }
481           if(doc->size[doc->numsizes].width != 0 &&
482              doc->size[doc->numsizes].height != 0)
483             doc->numsizes++;
484           else
485             g_free(doc->size[doc->numsizes].name);
486         }
487       }
488       section_len += line_len;
489       if(doc->numsizes != 0)
490         doc->default_page_size = doc->size;
491     }
492     else if(doc->numsizes == NONE && iscomment(line + 2, "DocumentPaperSizes:")) {
493
494       doc->size = g_new0(GtkGSPaperSize, 1);
495       doc->size[0].name =
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.
504            */
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;
510             break;
511           }
512         }
513         if(doc->size[0].width != 0 && doc->size[0].height != 0)
514           doc->numsizes = 1;
515         else
516           g_free(doc->size[0].name);
517       }
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.
527            */
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;
534             break;
535           }
536         }
537         if(doc->size[doc->numsizes].width != 0 &&
538            doc->size[doc->numsizes].height != 0)
539           doc->numsizes++;
540         else
541           g_free(doc->size[doc->numsizes].name);
542       }
543       preread = 1;
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.
557              */
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;
561               break;
562             }
563           }
564           if(doc->size[doc->numsizes].width != 0 &&
565              doc->size[doc->numsizes].height != 0)
566             doc->numsizes++;
567           else
568             g_free(doc->size[doc->numsizes].name);
569         }
570       }
571       section_len += line_len;
572       if(doc->numsizes != 0)
573         doc->default_page_size = doc->size;
574     }
575   }
576
577   if(DSCcomment(line) && iscomment(line + 2, "EndComments")) {
578     readline(fd, &line, &position, &line_len);
579     section_len += line_len;
580   }
581   doc->endheader = position;
582   doc->lenheader = section_len - line_len;
583
584   /* Optional Preview comments for encapsulated PostScript files */
585
586   beginsection = position;
587   section_len = line_len;
588   while(blank(line) && readline(fd, &line, &position, &line_len)) {
589     section_len += line_len;
590   }
591
592   if(doc->epsf && DSCcomment(line) && iscomment(line + 2, "BeginPreview")) {
593     doc->beginpreview = beginsection;
594     beginsection = 0;
595     while(readline(fd, &line, &position, &line_len) &&
596           !(DSCcomment(line) && iscomment(line + 2, "EndPreview"))) {
597       section_len += line_len;
598     }
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;
604   }
605
606   /* Page Defaults for Version 3.0 files */
607
608   if(beginsection == 0) {
609     beginsection = position;
610     section_len = line_len;
611   }
612   while(blank(line) && readline(fd, &line, &position, &line_len)) {
613     section_len += line_len;
614   }
615
616   if(DSCcomment(line) && iscomment(line + 2, "BeginDefaults")) {
617     doc->begindefaults = beginsection;
618     beginsection = 0;
619     while(readline(fd, &line, &position, &line_len) &&
620           !(DSCcomment(line) && iscomment(line + 2, "EndDefaults"))) {
621       section_len += line_len;
622       if(!DSCcomment(line)) {
623         /* Do nothing */
624       }
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;
630         }
631         else if(strcmp(text, "Landscape") == 0) {
632           doc->default_page_orientation = GTK_GS_ORIENTATION_LANDSCAPE;
633         }
634         else if(strcmp(text, "Seascape") == 0) {
635           doc->default_page_orientation = GTK_GS_ORIENTATION_SEASCAPE;
636         }
637       }
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;
643             page_size_set = 1;
644             break;
645           }
646         }
647         g_free(cp);
648       }
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)
655           page_bb_set = 1;
656         else {
657           float fllx, flly, furx, fury;
658           if(sscanf
659              (line + length("%%PageBoundingBox:"), "%f %f %f %f",
660               &fllx, &flly, &furx, &fury) == 4) {
661             page_bb_set = 1;
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]++;
674           }
675         }
676       }
677     }
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;
683   }
684
685   /* Document Prolog */
686
687   if(beginsection == 0) {
688     beginsection = position;
689     section_len = line_len;
690   }
691   while(blank(line) && readline(fd, &line, &position, &line_len)) {
692     section_len += line_len;
693   }
694
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;
700     beginsection = 0;
701     preread = 1;
702
703     while((preread ||
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")))) {
710       if(!preread)
711         section_len += line_len;
712       preread = 0;
713     }
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;
718     }
719     doc->endprolog = position;
720     doc->lenprolog = section_len - line_len;
721   }
722
723   /* Document Setup,  Page Defaults found here for Version 2 files */
724
725   if(beginsection == 0) {
726     beginsection = position;
727     section_len = line_len;
728   }
729   while(blank(line) && readline(fd, &line, &position, &line_len)) {
730     section_len += line_len;
731   }
732
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;
738     beginsection = 0;
739     preread = 1;
740     while((preread ||
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"))))) {
747       if(!preread)
748         section_len += line_len;
749       preread = 0;
750       if(!DSCcomment(line)) {
751         /* Do nothing */
752       }
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;
758         }
759         else if(strcmp(text, "Landscape") == 0) {
760           doc->default_page_orientation = GTK_GS_ORIENTATION_LANDSCAPE;
761         }
762         else if(strcmp(text, "Seascape") == 0) {
763           doc->default_page_orientation = GTK_GS_ORIENTATION_SEASCAPE;
764         }
765       }
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.
772            */
773           if(strcasecmp(cp, dmp->name) == 0) {
774             doc->default_page_size = dmp;
775             page_size_set = 1;
776             break;
777           }
778         }
779         g_free(cp);
780       }
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)
787           page_bb_set = 1;
788         else {
789           float fllx, flly, furx, fury;
790           if(sscanf
791              (line + length("%%PageBoundingBox:"), "%f %f %f %f",
792               &fllx, &flly, &furx, &fury) == 4) {
793             page_bb_set = 1;
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]++;
806           }
807         }
808       }
809     }
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;
814     }
815     doc->endsetup = position;
816     doc->lensetup = section_len - line_len;
817   }
818
819   /* HACK: Mozilla 1.8 Workaround.
820   
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.
824    */
825    
826   if(doc->beginprolog && !doc->beginsetup) {
827       doc->lenprolog += section_len - line_len;
828       doc->endprolog = position;
829   }
830   
831   /* HACK: Windows NT Workaround
832
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'.
838    */
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;
849     }
850   }
851
852   /* Individual Pages */
853
854   if(beginsection == 0) {
855     beginsection = position;
856     section_len = line_len;
857   }
858   while(blank(line) && readline(fd, &line, &position, &line_len)) {
859     section_len += line_len;
860   }
861
862
863 newpage:
864   while(DSCcomment(line) && iscomment(line + 2, "Page:")) {
865     if(maxpages == 0) {
866       maxpages = 1;
867       doc->pages = pages_new(NULL, 0, maxpages);
868     }
869     label = get_next_text(line + length("%%Page:"), &next_char);
870     if(sscanf(next_char, "%d", &thispage) != 1)
871       thispage = 0;
872     if(nextpage == 1) {
873       ignore = thispage != 1;
874     }
875     if(!ignore && thispage != nextpage) {
876       g_free(label);
877       doc->numpages--;
878       goto continuepage;
879     }
880     nextpage++;
881     if(doc->numpages == maxpages) {
882       maxpages++;
883       doc->pages = pages_new(doc->pages, maxpages - 1, maxpages);
884     }
885     page_bb_set = NONE;
886     doc->pages[doc->numpages].label = label;
887     if(beginsection) {
888       doc->pages[doc->numpages].begin = beginsection;
889       beginsection = 0;
890     }
891     else {
892       doc->pages[doc->numpages].begin = position;
893       section_len = line_len;
894     }
895   continuepage:
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)) {
903         /* Do nothing */
904       }
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;
910         }
911         else if(strcmp(text, "Landscape") == 0) {
912           doc->pages[doc->numpages].orientation = GTK_GS_ORIENTATION_LANDSCAPE;
913         }
914         else if(strcmp(text, "Seascape") == 0) {
915           doc->pages[doc->numpages].orientation = GTK_GS_ORIENTATION_SEASCAPE;
916         }
917       }
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;
924             break;
925           }
926         }
927         g_free(cp);
928       }
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.
936            */
937           if(strcasecmp(cp, dmp->name) == 0) {
938             doc->pages[doc->numpages].size = dmp;
939             break;
940           }
941         }
942         g_free(cp);
943       }
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) {
948           page_bb_set = ATEND;
949         }
950         else {
951           if(sscanf
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)
958               page_bb_set = 1;
959           }
960           else {
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)
965                 page_bb_set = 1;
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]++;
978             }
979           }
980         }
981       }
982     }
983     section_len += line_len;
984     doc->pages[doc->numpages].end = position;
985     doc->pages[doc->numpages].len = section_len - line_len;
986     doc->numpages++;
987   }
988
989   /* Document Trailer */
990
991   if(beginsection) {
992     doc->begintrailer = beginsection;
993     beginsection = 0;
994   }
995   else {
996     doc->begintrailer = position;
997     section_len = line_len;
998   }
999
1000   preread = 1;
1001   while((preread ||
1002          readline(fd, &line, &position, &line_len)) &&
1003         !(respect_eof && DSCcomment(line) && iscomment(line + 2, "EOF"))) {
1004     if(!preread)
1005       section_len += line_len;
1006     preread = 0;
1007     if(!DSCcomment(line)) {
1008       /* Do nothing */
1009     }
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)
1013         thispage = 0;
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;
1018         }
1019         else {
1020           if(doc->endsetup) {
1021             doc->endsetup = position;
1022             doc->endsetup += section_len - line_len;
1023           }
1024           else if(doc->endprolog) {
1025             doc->endprolog = position;
1026             doc->endprolog += section_len - line_len;
1027           }
1028         }
1029         goto newpage;
1030       }
1031     }
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;
1039       }
1040       doc->begintrailer = position;
1041       section_len = line_len;
1042     }
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]++;
1063         }
1064       }
1065     }
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;
1070       }
1071       else if(strcmp(text, "Landscape") == 0) {
1072         doc->orientation = GTK_GS_ORIENTATION_LANDSCAPE;
1073       }
1074       else if(strcmp(text, "Seascape") == 0) {
1075         doc->orientation = GTK_GS_ORIENTATION_SEASCAPE;
1076       }
1077     }
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;
1082       }
1083       else if(strcmp(text, "Descend") == 0) {
1084         doc->pageorder = DESCEND;
1085       }
1086       else if(strcmp(text, "Special") == 0) {
1087         doc->pageorder = SPECIAL;
1088       }
1089     }
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) {
1093           if(i == -1)
1094             doc->pageorder = DESCEND;
1095           else if(i == 0)
1096             doc->pageorder = SPECIAL;
1097           else if(i == 1)
1098             doc->pageorder = ASCEND;
1099         }
1100       }
1101     }
1102   }
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;
1107   }
1108   doc->endtrailer = position;
1109   doc->lentrailer = section_len - line_len;
1110
1111 #if 0
1112   section_len = line_len;
1113   preread = 1;
1114   while(preread || readline(line, sizeof line, file, &position, &line_len)) {
1115     if(!preread)
1116       section_len += line_len;
1117     preread = 0;
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)
1121         thispage = 0;
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;
1127         }
1128         else {
1129           if(doc->endsetup) {
1130             doc->endsetup = position;
1131             doc->endsetup += doc->lentrailer + section_len - line_len;
1132           }
1133           else if(doc->endprolog) {
1134             doc->endprolog = position;
1135             doc->endprolog += doc->lentrailer + section_len - line_len;
1136           }
1137         }
1138         goto newpage;
1139       }
1140     }
1141   }
1142 #endif
1143   ps_io_exit(fd);
1144   return doc;
1145 }
1146
1147 /*
1148  *      psfree -- free dynamic storage associated with document structure.
1149  */
1150
1151 void
1152 psfree(doc)
1153      struct document *doc;
1154 {
1155   int i;
1156
1157   if(doc) {
1158     /*
1159        printf("This document exists\n");
1160      */
1161     for(i = 0; i < doc->numpages; i++) {
1162       if(doc->pages[i].label)
1163         g_free(doc->pages[i].label);
1164     }
1165     for(i = 0; i < doc->numsizes; i++) {
1166       if(doc->size[i].name)
1167         g_free(doc->size[i].name);
1168     }
1169     if(doc->title)
1170       g_free(doc->title);
1171     if(doc->date)
1172       g_free(doc->date);
1173     if(doc->creator)
1174       g_free(doc->creator);
1175     if(doc->pages)
1176       g_free(doc->pages);
1177     if(doc->size)
1178       g_free(doc->size);
1179     g_free(doc);
1180   }
1181 }
1182
1183 /*
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().
1187  */
1188
1189 static char *
1190 gettextline(char *line)
1191 {
1192   char *cp;
1193
1194   while(*line && (*line == ' ' || *line == '\t'))
1195     line++;
1196   if(*line == '(') {
1197     return get_next_text(line, NULL);
1198   }
1199   else {
1200     if(strlen(line) == 0)
1201       return NULL;
1202
1203     cp = g_strdup(line);
1204
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';
1212
1213     return cp;
1214   }
1215 }
1216
1217 /*
1218  *      get_next_text -- return the next text string on the line.
1219  *                 return NULL if nothing is present.
1220  */
1221
1222 static char *
1223 get_next_text(line, next_char)
1224      char *line;
1225      char **next_char;
1226 {
1227   char text[PSLINELENGTH];      /* Temporary storage for text */
1228   char *cp;
1229   int quoted = 0;
1230
1231   while(*line && (*line == ' ' || *line == '\t'))
1232     line++;
1233   cp = text;
1234   if(*line == '(') {
1235     int level = 0;
1236     quoted = 1;
1237     line++;
1238     while(*line && !(*line == ')' && level == 0)
1239           && (cp - text) < PSLINELENGTH - 1) {
1240       if(*line == '\\') {
1241         if(*(line + 1) == 'n') {
1242           *cp++ = '\n';
1243           line += 2;
1244         }
1245         else if(*(line + 1) == 'r') {
1246           *cp++ = '\r';
1247           line += 2;
1248         }
1249         else if(*(line + 1) == 't') {
1250           *cp++ = '\t';
1251           line += 2;
1252         }
1253         else if(*(line + 1) == 'b') {
1254           *cp++ = '\b';
1255           line += 2;
1256         }
1257         else if(*(line + 1) == 'f') {
1258           *cp++ = '\f';
1259           line += 2;
1260         }
1261         else if(*(line + 1) == '\\') {
1262           *cp++ = '\\';
1263           line += 2;
1264         }
1265         else if(*(line + 1) == '(') {
1266           *cp++ = '(';
1267           line += 2;
1268         }
1269         else if(*(line + 1) == ')') {
1270           *cp++ = ')';
1271           line += 2;
1272         }
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') {
1276               *cp++ =
1277                 ((*(line + 1) - '0') * 8 + *(line + 2) -
1278                  '0') * 8 + *(line + 3) - '0';
1279               line += 4;
1280             }
1281             else {
1282               *cp++ = (*(line + 1) - '0') * 8 + *(line + 2) - '0';
1283               line += 3;
1284             }
1285           }
1286           else {
1287             *cp++ = *(line + 1) - '0';
1288             line += 2;
1289           }
1290         }
1291         else {
1292           line++;
1293           *cp++ = *line++;
1294         }
1295       }
1296       else if(*line == '(') {
1297         level++;
1298         *cp++ = *line++;
1299       }
1300       else if(*line == ')') {
1301         level--;
1302         *cp++ = *line++;
1303       }
1304       else {
1305         *cp++ = *line++;
1306       }
1307     }
1308   }
1309   else {
1310     while(*line && !(*line == ' ' || *line == '\t' || *line == '\n')
1311           && (cp - text) < PSLINELENGTH - 1)
1312       *cp++ = *line++;
1313   }
1314   *cp = '\0';
1315   if(next_char)
1316     *next_char = line;
1317   if(!quoted && strlen(text) == 0)
1318     return NULL;
1319   return g_strdup(text);
1320 }
1321
1322 /*
1323  *      pscopy -- copy lines of Postscript from a section of one file
1324  *                to another file.
1325  *                Automatically switch to binary copying whenever
1326  *                %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
1327  *                comments are encountered.
1328  */
1329
1330 void
1331 pscopy(from, to, begin, end)
1332      FILE *from;
1333      GtkGSDocSink *to;
1334      long begin;                /* set negative to avoid initial seek */
1335      long end;
1336 {
1337   char line[PSLINELENGTH];      /* 255 characters + 1 newline + 1 NULL */
1338   char text[PSLINELENGTH];      /* Temporary storage for text */
1339   unsigned int num;
1340   int i;
1341   char buf[BUFSIZ];
1342
1343   if(begin >= 0)
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));
1348
1349     if(!(DSCcomment(line) && iscomment(line + 2, "Begin"))) {
1350       /* Do nothing */
1351     }
1352     else if(iscomment(line + 7, "Data:")) {
1353       text[0] = '\0';
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));
1359           }
1360         }
1361         else {
1362           while(num > BUFSIZ) {
1363             fread(buf, sizeof(char), BUFSIZ, from);
1364             gtk_gs_doc_sink_write(to, buf, BUFSIZ);
1365             num -= BUFSIZ;
1366           }
1367           fread(buf, sizeof(char), num, from);
1368           gtk_gs_doc_sink_write(to, buf, num);
1369         }
1370       }
1371     }
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);
1377           num -= BUFSIZ;
1378         }
1379         fread(buf, sizeof(char), num, from);
1380         gtk_gs_doc_sink_write(to, buf, num);
1381       }
1382     }
1383   }
1384 }
1385
1386 /*
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.
1392  */
1393
1394 char *
1395 pscopyuntil(FILE * from, GtkGSDocSink * to, long begin, long end,
1396             const char *comment)
1397 {
1398   char line[PSLINELENGTH];      /* 255 characters + 1 newline + 1 NULL */
1399   char text[PSLINELENGTH];      /* Temporary storage for text */
1400   unsigned int num;
1401   int comment_length;
1402   int i;
1403   char buf[BUFSIZ];
1404
1405   if(comment != NULL)
1406     comment_length = strlen(comment);
1407   else
1408     comment_length = 0;
1409   if(begin >= 0)
1410     fseek(from, begin, SEEK_SET);
1411
1412   while(ftell(from) < end && !feof(from)) {
1413     fgets(line, sizeof line, from);
1414
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);
1419     }
1420     gtk_gs_doc_sink_write(to, line, strlen(line));
1421     if(!(DSCcomment(line) && iscomment(line + 2, "Begin"))) {
1422       /* Do nothing */
1423     }
1424     else if(iscomment(line + 7, "Data:")) {
1425       text[0] = '\0';
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));
1431           }
1432         }
1433         else {
1434           while(num > BUFSIZ) {
1435             fread(buf, sizeof(char), BUFSIZ, from);
1436             gtk_gs_doc_sink_write(to, buf, BUFSIZ);
1437             num -= BUFSIZ;
1438           }
1439           fread(buf, sizeof(char), num, from);
1440           gtk_gs_doc_sink_write(to, buf, num);
1441         }
1442       }
1443     }
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);
1449           num -= BUFSIZ;
1450         }
1451         fread(buf, sizeof(char), num, from);
1452         gtk_gs_doc_sink_write(to, buf, num);
1453       }
1454     }
1455   }
1456   return NULL;
1457 }
1458
1459 /*
1460  *      blank -- determine whether the line contains nothing but whitespace.
1461  */
1462
1463 static int
1464 blank(char *line)
1465 {
1466   char *cp = line;
1467
1468   while(*cp == ' ' || *cp == '\t')
1469     cp++;
1470   return *cp == '\n' || (*cp == '%' && (line[0] != '%' || line[1] != '%'));
1471 }
1472
1473 /*##########################################################*/
1474 /* pscopydoc */
1475 /* Copy the headers, marked pages, and trailer to fp */
1476 /*##########################################################*/
1477
1478 void
1479 pscopydoc(GtkGSDocSink * dest,
1480           char *src_filename, struct document *d, gint * pagelist)
1481 {
1482   FILE *src_file;
1483   char text[PSLINELENGTH];
1484   char *comment;
1485   gboolean pages_written = FALSE;
1486   gboolean pages_atend = FALSE;
1487   int pages;
1488   int page = 1;
1489   int i, j;
1490   int here;
1491
1492   src_file = fopen(src_filename, "r");
1493   i = 0;
1494   pages = 0;
1495   for(i = 0; i < d->numpages; i++) {
1496     if(pagelist[i])
1497       pages++;
1498   }
1499
1500   here = d->beginheader;
1501
1502   while((comment = pscopyuntil(src_file, dest, here, d->endheader, "%%Pages:"))) {
1503     here = ftell(src_file);
1504     if(pages_written || pages_atend) {
1505       g_free(comment);
1506       continue;
1507     }
1508     sscanf(comment + length("%%Pages:"), "%256s", text);
1509     if(strcmp(text, "(atend)") == 0) {
1510       gtk_gs_doc_sink_write(dest, comment, strlen(comment));
1511       pages_atend = TRUE;
1512     }
1513     else {
1514       switch (sscanf(comment + length("%%Pages:"), "%*d %d", &i)) {
1515       case 1:
1516         gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d %d\n", pages, i);
1517         break;
1518       default:
1519         gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d\n", pages);
1520         break;
1521       }
1522       pages_written = TRUE;
1523     }
1524     g_free(comment);
1525   }
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);
1530
1531   for(i = 0; i < d->numpages; i++) {
1532     if(d->pageorder == DESCEND)
1533       j = (d->numpages - 1) - i;
1534     else
1535       j = i;
1536     j = i;
1537     if(pagelist[j]) {
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++);
1542       g_free(comment);
1543       pscopyuntil(src_file, dest, -1, d->pages[i].end, NULL);
1544     }
1545   }
1546
1547   here = d->begintrailer;
1548   while((comment = pscopyuntil(src_file, dest, here, d->endtrailer,
1549                                "%%Pages:"))) {
1550     here = ftell(src_file);
1551     if(pages_written) {
1552       g_free(comment);
1553       continue;
1554     }
1555     switch (sscanf(comment + length("%%Pages:"), "%*d %d", &i)) {
1556     case 1:
1557       gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d %d\n", pages, i);
1558       break;
1559     default:
1560       gtk_gs_doc_sink_printf(dest, "%%%%Pages: %d\n", pages);
1561       break;
1562     }
1563     pages_written = TRUE;
1564     g_free(comment);
1565   }
1566
1567   fclose(src_file);
1568 }
1569
1570 /*----------------------------------------------------------*/
1571 /* ps_io_init */
1572 /*----------------------------------------------------------*/
1573
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)
1585
1586 #define FD_STATUS_OKAY        0
1587 #define FD_STATUS_BUFTOOLARGE 1
1588 #define FD_STATUS_NOMORECHARS 2
1589
1590 #define LINE_CHUNK_SIZE     4096
1591 #define MAX_PS_IO_FGETCHARS_BUF_SIZE 57344
1592 #define BREAK_PS_IO_FGETCHARS_BUF_SIZE 49152
1593
1594 static FileData ps_io_init(file)
1595    FILE *file;
1596 {
1597    FileData fd;
1598    size_t size = sizeof(FileDataStruct);
1599
1600    fd = (FileData) g_malloc(size);
1601    memset((void*) fd ,0,(size_t)size);
1602
1603    rewind(file);
1604    FD_FILE      = file;
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);
1609    FD_BUF[0]    = '\0';
1610    return(fd);
1611 }
1612
1613 /*----------------------------------------------------------*/
1614 /* ps_io_exit */
1615 /*----------------------------------------------------------*/
1616
1617 static void
1618 ps_io_exit(fd)
1619    FileData fd;
1620 {
1621    g_free(FD_BUF);
1622    g_free(fd);
1623 }
1624
1625 /*----------------------------------------------------------*/
1626 /* ps_io_fseek */
1627 /*----------------------------------------------------------*/
1628
1629 /*static int
1630 ps_io_fseek(fd,offset)
1631    FileData fd;
1632    int offset;
1633 {
1634    int status;
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;
1639    return(status);
1640 }*/
1641
1642 /*----------------------------------------------------------*/
1643 /* ps_io_ftell */
1644 /*----------------------------------------------------------*/
1645
1646 /*static int
1647 ps_io_ftell(fd)
1648    FileData fd;
1649 {
1650    return(FD_FILEPOS);
1651 }*/
1652
1653 /*----------------------------------------------------------*/
1654 /* ps_io_fgetchars */
1655 /*----------------------------------------------------------*/
1656
1657 #ifdef USE_MEMMOVE_CODE
1658 static void ps_memmove (d, s, l)
1659   char *d;
1660   const char *s;
1661   unsigned l;
1662 {
1663   if (s < d) for (s += l, d += l; l; --l) *--d = *--s;
1664   else if (s != d) for (; l; --l)         *d++ = *s++;
1665 }
1666 #else
1667 #   define ps_memmove memmove
1668 #endif
1669
1670 static char * ps_io_fgetchars(fd,num)
1671    FileData fd;
1672    int num;
1673 {
1674    char *eol=NULL,*tmp;
1675    size_t size_of_char = sizeof(char);
1676
1677    if (FD_STATUS != FD_STATUS_OKAY) {
1678       return(NULL);
1679    }
1680
1681    FD_BUF[FD_LINE_END] = FD_LINE_TERMCHAR; /* restoring char previously exchanged against '\0' */
1682    FD_LINE_BEGIN       = FD_LINE_END;
1683
1684    do {
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");
1689             */
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;
1694             if (eol) {
1695                if (*eol=='\r' && *(eol+1)=='\n') eol += 2;
1696                else eol++;
1697                break;
1698             }
1699          }
1700       } else { /* reading specified num of chars */
1701          if (FD_BUF_END >= FD_LINE_BEGIN+num) {
1702             eol = FD_BUF+FD_LINE_BEGIN+num;
1703             break;
1704          }
1705       }
1706
1707       if (FD_BUF_END - FD_LINE_BEGIN > BREAK_PS_IO_FGETCHARS_BUF_SIZE) {
1708         eol = FD_BUF + FD_BUF_END - 1;
1709         break;
1710       }
1711
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");
1717             exit(-1);
1718          }
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; 
1723             FD_LINE_BEGIN  = 0;
1724          } else {
1725             FD_BUF_SIZE    = FD_BUF_SIZE+LINE_CHUNK_SIZE+1;
1726             FD_BUF         = g_realloc(FD_BUF,FD_BUF_SIZE);
1727          }
1728       }
1729
1730       FD_LINE_END = FD_BUF_END;
1731 #ifdef VMS
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);
1735 #else
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);
1738 #endif
1739
1740       FD_BUF[FD_BUF_END] = '\0';
1741       if (FD_BUF_END-FD_LINE_END == 0) {
1742          FD_STATUS = FD_STATUS_NOMORECHARS;
1743          return(NULL);
1744       }
1745    }
1746    while (1);
1747
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) {
1754       /*
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
1762       case).
1763       (Tim Adye, adye@v2.rl.ac.uk)
1764       */
1765       FD_FILEPOS         = ftell(FD_FILE);
1766    } else
1767 #endif /* USE_FTELL_FOR_FILEPOS */
1768       FD_FILEPOS        += FD_LINE_LEN;
1769
1770    return(FD_BUF+FD_LINE_BEGIN);
1771 }
1772
1773 /*----------------------------------------------------------*/
1774 /*
1775    readline()
1776    Read the next line in the postscript file.
1777    Automatically skip over data (as indicated by
1778    %%BeginBinary/%%EndBinary or %%BeginData/%%EndData
1779    comments.)
1780    Also, skip over included documents (as indicated by
1781    %%BeginDocument/%%EndDocument comments.)
1782 */
1783 /*----------------------------------------------------------*/
1784
1785 static char *readline (fd, lineP, positionP, line_lenP)
1786    FileData fd;
1787    char **lineP;
1788    long *positionP;
1789    unsigned int *line_lenP;
1790 {
1791    unsigned int nbytes=0;
1792    int skipped=0;
1793    char *line;
1794
1795    if (positionP) *positionP = FD_FILEPOS;
1796    line = ps_io_fgetchars(fd,-1);
1797    if (!line) {
1798       *line_lenP = 0;
1799       *lineP     = empty_string;
1800       return(NULL); 
1801    }
1802
1803    *line_lenP = FD_LINE_LEN;
1804
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;\
1811            skipped=1;
1812 #define SKIP_UNTIL_1(comment) {                         \
1813            SKIP_WHILE((!IS_COMMENT(comment)))           \
1814         }
1815 #define SKIP_UNTIL_2(comment1,comment2) {               \
1816            SKIP_WHILE((!IS_COMMENT(comment1) && !IS_COMMENT(comment2)))\
1817         }
1818
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")
1824 #else
1825    else if IS_BEGIN("File")       SKIP_UNTIL_1("EndFile")
1826 #endif
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:")      {
1831       int  num;
1832       char text[101];
1833       if (FD_LINE_LEN > 100) FD_BUF[100] = '\0';
1834       text[0] = '\0';
1835       if (sscanf(line+length("%%BeginData:"), "%d %*s %s", &num, text) >= 1) {
1836          if (strcmp(text, "Lines") == 0) {
1837             while (num) {
1838                line = ps_io_fgetchars(fd,-1);
1839                if (line) *line_lenP += FD_LINE_LEN;
1840                num--;
1841             }
1842          } else {
1843             int read_chunk_size = LINE_CHUNK_SIZE;
1844             while (num>0) {
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;
1849             }
1850          }
1851       }
1852       SKIP_UNTIL_1("EndData")
1853    }
1854    else if IS_BEGIN("Binary:") {
1855       int  num;
1856       if (sscanf(line+length("%%BeginBinary:"), "%d", &num) == 1) {
1857          int read_chunk_size = LINE_CHUNK_SIZE;
1858          while (num>0) {
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;
1863          }
1864          SKIP_UNTIL_1("EndBinary")
1865       }
1866    }
1867
1868    if (skipped) {
1869       *line_lenP += nbytes;
1870       *lineP = skipped_line;      
1871    } else {
1872       *lineP = FD_BUF+FD_LINE_BEGIN;
1873    }
1874
1875    return(FD_BUF+FD_LINE_BEGIN);
1876 }
1877
1878 #define DEFAULT_PAGE_SIZE 1
1879
1880 void
1881 psgetpagebox (const struct document *doc, int page, int *urx, int *ury, int *llx, int *lly)
1882 {
1883    gint new_llx = 0;
1884    gint new_lly = 0;
1885    gint new_urx = 0;
1886    gint new_ury = 0;
1887    GtkGSPaperSize *papersizes = gtk_gs_defaults_get_paper_sizes ();
1888    int new_pagesize = -1;
1889
1890    if (new_pagesize == -1) {
1891       new_pagesize = DEFAULT_PAGE_SIZE;
1892       if (doc) {
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 
1898           */
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) &&
1906                     (doc->pages) &&
1907                     (doc->pages[page].boundingbox[URX] >
1908                      doc->pages[page].boundingbox[LLX]) &&
1909                     (doc->pages[page].boundingbox[URY] >
1910                      doc->pages[page].boundingbox[LLY])) {
1911             new_pagesize = -1;
1912          } else if ((doc->boundingbox[URX] > doc->boundingbox[LLX]) &&
1913                     (doc->boundingbox[URY] > doc->boundingbox[LLY])) {
1914             new_pagesize = -1;
1915          }
1916       }
1917    }
1918
1919    /* Compute bounding box */
1920    if (doc && (doc->epsf || new_pagesize == -1)) {    /* epsf or bbox */
1921       if ((page >= 0) &&
1922           (doc->pages) &&
1923           (doc->pages[page].boundingbox[URX] >
1924            doc->pages[page].boundingbox[LLX]) &&
1925           (doc->pages[page].boundingbox[URY] >
1926            doc->pages[page].boundingbox[LLY])) {
1927          /* use page bbox */
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])) {
1934          /* use doc bbox */
1935          new_llx = doc->boundingbox[LLX];
1936          new_lly = doc->boundingbox[LLY];
1937          new_urx = doc->boundingbox[URX];
1938          new_ury = doc->boundingbox[URY];
1939       }
1940    } else {
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;
1948       } else {
1949         new_urx = papersizes[new_pagesize].width;
1950         new_ury = papersizes[new_pagesize].height;
1951       }
1952    }
1953
1954    if (new_urx <= new_llx)
1955       new_urx = papersizes[12].width;
1956    if (new_ury <= new_lly)
1957       new_ury = papersizes[12].height;
1958
1959    *urx = new_urx;
1960    *ury = new_ury;
1961    *llx = new_llx;
1962    *lly = new_lly;
1963 }