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