filters

PDFDoc.cpp
1//========================================================================
2//
3// PDFDoc.cpp
4//
5// Copyright 1996-2002 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 "xpdf_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
46PDFDoc::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
99PDFDoc::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
115GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) {
116 // check header
117 checkHeader();
118
119 // read xref table
120 xref = new XRef(str, ownerPassword, userPassword);
121 if (!xref->isOk()) {
122 error(-1, "Couldn't read xref table");
123 errCode = xref->getErrorCode();
124 return gFalse;
125 }
126
127 // read catalog
128 catalog = new Catalog(xref);
129 if (!catalog->isOk()) {
130 error(-1, "Couldn't read page catalog");
131 errCode = errBadCatalog;
132 return gFalse;
133 }
134
135#ifndef DISABLE_OUTLINE
136 // read outline
137 outline = new Outline(catalog->getOutline(), xref);
138#endif
139
140 // done
141 return gTrue;
142}
143
144PDFDoc::~PDFDoc() {
145#ifndef DISABLE_OUTLINE
146 delete outline;
147#endif
148 delete catalog;
149 delete xref;
150 delete str;
151 if (file) {
152 fclose(file);
153 }
154 delete fileName;
155 delete links;
156}
157
158// Check for a PDF header on this stream. Skip past some garbage
159// if necessary.
160void PDFDoc::checkHeader() {
161 char hdrBuf[headerSearchSize+1];
162 char *p;
163 int i;
164
165 pdfVersion = 0;
166 for (i = 0; i < headerSearchSize; ++i) {
167 hdrBuf[i] = str->getChar();
168 }
169 hdrBuf[headerSearchSize] = '\0';
170 for (i = 0; i < headerSearchSize - 5; ++i) {
171 if (!strncmp(&hdrBuf[i], "%PDF-", 5)) {
172 break;
173 }
174 }
175 if (i >= headerSearchSize - 5) {
176 error(-1, "May not be a PDF file (continuing anyway)");
177 return;
178 }
179 str->moveStart(i);
180 p = strtok(&hdrBuf[i+5], " \t\n\r");
181 pdfVersion = atof(p);
182 if (!(hdrBuf[i+5] >= '0' && hdrBuf[i+5] <= '9') ||
183 pdfVersion > supportedPDFVersionNum + 0.0001) {
184 error(-1, "PDF version %s -- xpdf supports version %s"
185 " (continuing anyway)", p, supportedPDFVersionStr);
186 }
187}
188
189void PDFDoc::displayPage(OutputDev *out, int page, double zoom,
190 int rotate, GBool doLinks,
191 GBool (*abortCheckCbk)(void *data),
192 void *abortCheckCbkData) {
193 Page *p;
194
195 if (globalParams->getPrintCommands()) {
196 printf("***** page %d *****\n", page);
197 }
198 p = catalog->getPage(page);
199 if (doLinks) {
200 if (links) {
201 delete links;
202 }
203 getLinks(p);
204 p->display(out, zoom, rotate, links, catalog,
205 abortCheckCbk, abortCheckCbkData);
206 } else {
207 p->display(out, zoom, rotate, NULL, catalog,
208 abortCheckCbk, abortCheckCbkData);
209 }
210}
211
212void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage,
213 int zoom, int rotate, GBool doLinks,
214 GBool (*abortCheckCbk)(void *data),
215 void *abortCheckCbkData) {
216 int page;
217
218 for (page = firstPage; page <= lastPage; ++page) {
219 displayPage(out, page, zoom, rotate, doLinks,
220 abortCheckCbk, abortCheckCbkData);
221 }
222}
223
224void PDFDoc::displayPageSlice(OutputDev *out, int page, double zoom,
225 int rotate, int sliceX, int sliceY,
226 int sliceW, int sliceH,
227 GBool (*abortCheckCbk)(void *data),
228 void *abortCheckCbkData) {
229 Page *p;
230
231 p = catalog->getPage(page);
232 p->displaySlice(out, zoom, rotate, sliceX, sliceY, sliceW, sliceH,
233 NULL, catalog, abortCheckCbk, abortCheckCbkData);
234}
235
236GBool PDFDoc::isLinearized() {
237 Parser *parser;
238 Object obj1, obj2, obj3, obj4, obj5;
239 GBool lin;
240
241 lin = gFalse;
242 obj1.initNull();
243 parser = new Parser(xref,
244 new Lexer(xref,
245 str->makeSubStream(str->getStart(), gFalse, 0, &obj1)));
246 parser->getObj(&obj1);
247 parser->getObj(&obj2);
248 parser->getObj(&obj3);
249 parser->getObj(&obj4);
250 if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") &&
251 obj4.isDict()) {
252 obj4.dictLookup("Linearized", &obj5);
253 if (obj5.isNum() && obj5.getNum() > 0) {
254 lin = gTrue;
255 }
256 obj5.free();
257 }
258 obj4.free();
259 obj3.free();
260 obj2.free();
261 obj1.free();
262 delete parser;
263 return lin;
264}
265
266GBool PDFDoc::saveAs(GString *name) {
267 FILE *f;
268 int c;
269
270 if (!(f = fopen(name->getCString(), "wb"))) {
271 error(-1, "Couldn't open file '%s'", name->getCString());
272 return gFalse;
273 }
274 str->reset();
275 while ((c = str->getChar()) != EOF) {
276 fputc(c, f);
277 }
278 str->close();
279 fclose(f);
280 return gTrue;
281}
282
283void PDFDoc::getLinks(Page *page) {
284 Object obj;
285
286 links = new Links(page->getAnnots(&obj), catalog->getBaseURI());
287 obj.free();
288}