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