Initial revision
[swftools.git] / pdf2swf / xpdf / PDFDoc.cc
1 //========================================================================
2 //
3 // PDFDoc.cc
4 //
5 // Copyright 1996 Derek B. Noonburg
6 //
7 //========================================================================
8
9 #ifdef __GNUC__
10 #pragma implementation
11 #endif
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <stddef.h>
16 #include <string.h>
17 #include "GString.h"
18 #include "config.h"
19 #include "Page.h"
20 #include "Catalog.h"
21 #include "Stream.h"
22 #include "XRef.h"
23 #include "Link.h"
24 #include "OutputDev.h"
25 #include "Params.h"
26 #include "Error.h"
27 #include "Lexer.h"
28 #include "Parser.h"
29 #include "PDFDoc.h"
30
31 //------------------------------------------------------------------------
32
33 #define headerSearchSize 1024   // read this many bytes at beginning of
34                                 //   file to look for '%PDF'
35
36 //------------------------------------------------------------------------
37 // PDFDoc
38 //------------------------------------------------------------------------
39
40 PDFDoc::PDFDoc(GString *fileName1, GString *userPassword) {
41   Object obj;
42   GString *fileName2;
43
44   ok = gFalse;
45
46   file = NULL;
47   str = NULL;
48   xref = NULL;
49   catalog = NULL;
50   links = NULL;
51
52   // try to open file
53   fileName = fileName1;
54   fileName2 = NULL;
55 #ifdef VMS
56   if (!(file = fopen(fileName->getCString(), "rb", "ctx=stm"))) {
57     error(-1, "Couldn't open file '%s'", fileName->getCString());
58     return;
59   }
60 #else
61   if (!(file = fopen(fileName->getCString(), "rb"))) {
62     fileName2 = fileName->copy();
63     fileName2->lowerCase();
64     if (!(file = fopen(fileName2->getCString(), "rb"))) {
65       fileName2->upperCase();
66       if (!(file = fopen(fileName2->getCString(), "rb"))) {
67         error(-1, "Couldn't open file '%s'", fileName->getCString());
68         delete fileName2;
69         return;
70       }
71     }
72     delete fileName2;
73   }
74 #endif
75
76   // create stream
77   obj.initNull();
78   str = new FileStream(file, 0, -1, &obj);
79
80   ok = setup(userPassword);
81 }
82
83 PDFDoc::PDFDoc(BaseStream *str, GString *userPassword) {
84   ok = gFalse;
85   fileName = NULL;
86   file = NULL;
87   this->str = str;
88   xref = NULL;
89   catalog = NULL;
90   links = NULL;
91   ok = setup(userPassword);
92 }
93
94 GBool PDFDoc::setup(GString *userPassword) {
95   Object catObj;
96
97   // check header
98   checkHeader();
99
100   // read xref table
101   xref = new XRef(str, userPassword);
102   if (!xref->isOk()) {
103     error(-1, "Couldn't read xref table");
104     return gFalse;
105   }
106
107   // read catalog
108   catalog = new Catalog(xref->getCatalog(&catObj));
109   catObj.free();
110   if (!catalog->isOk()) {
111     error(-1, "Couldn't read page catalog");
112     return gFalse;
113   }
114
115   // done
116   return gTrue;
117 }
118
119 PDFDoc::~PDFDoc() {
120   if (catalog) {
121     delete catalog;
122   }
123   if (xref) {
124     delete xref;
125   }
126   if (str) {
127     delete str;
128   }
129   if (file) {
130     fclose(file);
131   }
132   if (fileName) {
133     delete fileName;
134   }
135   if (links) {
136     delete links;
137   }
138 }
139
140 // Check for a PDF header on this stream.  Skip past some garbage
141 // if necessary.
142 void PDFDoc::checkHeader() {
143   char hdrBuf[headerSearchSize+1];
144   char *p;
145   int i;
146
147   pdfVersion = 0;
148   for (i = 0; i < headerSearchSize; ++i) {
149     hdrBuf[i] = str->getChar();
150   }
151   hdrBuf[headerSearchSize] = '\0';
152   for (i = 0; i < headerSearchSize - 5; ++i) {
153     if (!strncmp(&hdrBuf[i], "%PDF-", 5)) {
154       break;
155     }
156   }
157   if (i >= headerSearchSize - 5) {
158     error(-1, "May not be a PDF file (continuing anyway)");
159     return;
160   }
161   str->moveStart(i);
162   p = strtok(&hdrBuf[i+5], " \t\n\r");
163   pdfVersion = atof(p);
164   if (!(hdrBuf[i+5] >= '0' && hdrBuf[i+5] <= '9') ||
165       pdfVersion > supportedPDFVersionNum + 0.0001) {
166     error(-1, "PDF version %s -- xpdf supports version %s"
167           " (continuing anyway)", p, supportedPDFVersionStr);
168   }
169 }
170
171 void PDFDoc::displayPage(OutputDev *out, int page, double zoom,
172                          int rotate, GBool doLinks) {
173   Page *p;
174
175   if (printCommands) {
176     printf("***** page %d *****\n", page);
177   }
178   p = catalog->getPage(page);
179   if (doLinks) {
180     if (links) {
181       delete links;
182     }
183     getLinks(p);
184     p->display(out, zoom, rotate, links, catalog);
185   } else {
186     p->display(out, zoom, rotate, NULL, catalog);
187   }
188 }
189
190 void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage,
191                           int zoom, int rotate, GBool doLinks) {
192   int page;
193
194   for (page = firstPage; page <= lastPage; ++page) {
195     displayPage(out, page, zoom, rotate, doLinks);
196   }
197 }
198
199 GBool PDFDoc::isLinearized() {
200   Parser *parser;
201   Object obj1, obj2, obj3, obj4, obj5;
202   GBool lin;
203
204   lin = gFalse;
205   obj1.initNull();
206   parser = new Parser(new Lexer(str->makeSubStream(str->getStart(),
207                                                    -1, &obj1)));
208   parser->getObj(&obj1);
209   parser->getObj(&obj2);
210   parser->getObj(&obj3);
211   parser->getObj(&obj4);
212   if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") &&
213       obj4.isDict()) {
214     obj4.dictLookup("Linearized", &obj5);
215     if (obj5.isNum() && obj5.getNum() > 0) {
216       lin = gTrue;
217     }
218     obj5.free();
219   }
220   obj4.free();
221   obj3.free();
222   obj2.free();
223   obj1.free();
224   delete parser;
225   return lin;
226 }
227
228 GBool PDFDoc::saveAs(GString *name) {
229   FILE *f;
230   int c;
231
232   if (!(f = fopen(name->getCString(), "wb"))) {
233     error(-1, "Couldn't open file '%s'", name->getCString());
234     return gFalse;
235   }
236   str->reset();
237   while ((c = str->getChar()) != EOF) {
238     fputc(c, f);
239   }
240   str->close();
241   fclose(f);
242   return gTrue;
243 }
244
245 void PDFDoc::getLinks(Page *page) {
246   Object obj;
247
248   links = new Links(page->getAnnots(&obj), catalog->getBaseURI());
249   obj.free();
250 }
251