]> git.ipfire.org Git - thirdparty/cups.git/blame - pdftops/PDFDoc.cxx
Merge changes from CUPS 1.4svn-r7199.
[thirdparty/cups.git] / pdftops / PDFDoc.cxx
CommitLineData
ef416fc2 1//========================================================================
2//
3// PDFDoc.cc
4//
5// Copyright 1996-2003 Glyph & Cog, LLC
6//
7//========================================================================
8
9#include <config.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#ifdef WIN32
20# include <windows.h>
21#endif
22#include "GString.h"
23#include "config.h"
24#include "GlobalParams.h"
25#include "Page.h"
26#include "Catalog.h"
27#include "Stream.h"
28#include "XRef.h"
29#include "Link.h"
30#include "OutputDev.h"
31#include "Error.h"
32#include "ErrorCodes.h"
33#include "Lexer.h"
34#include "Parser.h"
35#include "SecurityHandler.h"
36#ifndef DISABLE_OUTLINE
37#include "Outline.h"
38#endif
39#include "PDFDoc.h"
40
41//------------------------------------------------------------------------
42
43#define headerSearchSize 1024 // read this many bytes at beginning of
44 // file to look for '%PDF'
45
46//------------------------------------------------------------------------
47// PDFDoc
48//------------------------------------------------------------------------
49
50PDFDoc::PDFDoc(GString *fileNameA, GString *ownerPassword,
51 GString *userPassword, void *guiDataA) {
52 Object obj;
53 GString *fileName1, *fileName2;
54
55 ok = gFalse;
56 errCode = errNone;
57
58 guiData = guiDataA;
59
60 file = NULL;
61 str = NULL;
62 xref = NULL;
63 catalog = NULL;
64 links = NULL;
65#ifndef DISABLE_OUTLINE
66 outline = NULL;
67#endif
68
69 fileName = fileNameA;
70 fileName1 = fileName;
71
72
73 // try to open file
74 fileName2 = NULL;
75#ifdef VMS
76 if (!(file = fopen(fileName1->getCString(), "rb", "ctx=stm"))) {
77 error(-1, "Couldn't open file '%s'", fileName1->getCString());
78 errCode = errOpenFile;
79 return;
80 }
81#else
82 if (!(file = fopen(fileName1->getCString(), "rb"))) {
83 fileName2 = fileName->copy();
84 fileName2->lowerCase();
85 if (!(file = fopen(fileName2->getCString(), "rb"))) {
86 fileName2->upperCase();
87 if (!(file = fopen(fileName2->getCString(), "rb"))) {
88 error(-1, "Couldn't open file '%s'", fileName->getCString());
89 delete fileName2;
90 errCode = errOpenFile;
91 return;
92 }
93 }
94 delete fileName2;
95 }
96#endif
97
98 // create stream
99 obj.initNull();
100 str = new FileStream(file, 0, gFalse, 0, &obj);
101
102 ok = setup(ownerPassword, userPassword);
103}
104
105#ifdef WIN32
106PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword,
107 GString *userPassword, void *guiDataA) {
108 OSVERSIONINFO version;
109 wchar_t fileName2[_MAX_PATH + 1];
110 Object obj;
111 int i;
112
113 ok = gFalse;
114 errCode = errNone;
115
116 guiData = guiDataA;
117
118 file = NULL;
119 str = NULL;
120 xref = NULL;
121 catalog = NULL;
122 links = NULL;
123#ifndef DISABLE_OUTLINE
124 outline = NULL;
125#endif
126
127 //~ file name should be stored in Unicode (?)
128 fileName = new GString();
129 for (i = 0; i < fileNameLen; ++i) {
130 fileName->append((char)fileNameA[i]);
131 }
132
133 // zero-terminate the file name string
134 for (i = 0; i < fileNameLen && i < _MAX_PATH; ++i) {
135 fileName2[i] = fileNameA[i];
136 }
137 fileName2[i] = 0;
138
139 // try to open file
140 // NB: _wfopen is only available in NT
141 version.dwOSVersionInfoSize = sizeof(version);
142 GetVersionEx(&version);
143 if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
144 file = _wfopen(fileName2, L"rb");
145 } else {
146 file = fopen(fileName->getCString(), "rb");
147 }
148 if (!file) {
149 error(-1, "Couldn't open file '%s'", fileName->getCString());
150 errCode = errOpenFile;
151 return;
152 }
153
154 // create stream
155 obj.initNull();
156 str = new FileStream(file, 0, gFalse, 0, &obj);
157
158 ok = setup(ownerPassword, userPassword);
159}
160#endif
161
162PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword,
163 GString *userPassword, void *guiDataA) {
164 ok = gFalse;
165 errCode = errNone;
166 guiData = guiDataA;
167 fileName = NULL;
168 file = NULL;
169 str = strA;
170 xref = NULL;
171 catalog = NULL;
172 links = NULL;
173#ifndef DISABLE_OUTLINE
174 outline = NULL;
175#endif
176 ok = setup(ownerPassword, userPassword);
177}
178
179GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) {
180 str->reset();
181
182 // check header
183 checkHeader();
184
185 // read xref table
186 xref = new XRef(str);
187 if (!xref->isOk()) {
188 error(-1, "Couldn't read xref table");
189 errCode = xref->getErrorCode();
190 return gFalse;
191 }
192
193 // check for encryption
194 if (!checkEncryption(ownerPassword, userPassword)) {
195 errCode = errEncrypted;
196 return gFalse;
197 }
198
199 // read catalog
200 catalog = new Catalog(xref);
201 if (!catalog->isOk()) {
202 error(-1, "Couldn't read page catalog");
203 errCode = errBadCatalog;
204 return gFalse;
205 }
206
207#ifndef DISABLE_OUTLINE
208 // read outline
209 outline = new Outline(catalog->getOutline(), xref);
210#endif
211
212 // done
213 return gTrue;
214}
215
216PDFDoc::~PDFDoc() {
217#ifndef DISABLE_OUTLINE
218 if (outline) {
219 delete outline;
220 }
221#endif
222 if (catalog) {
223 delete catalog;
224 }
225 if (xref) {
226 delete xref;
227 }
228 if (str) {
229 delete str;
230 }
231 if (file) {
232 fclose(file);
233 }
234 if (fileName) {
235 delete fileName;
236 }
237 if (links) {
238 delete links;
239 }
240}
241
242// Check for a PDF header on this stream. Skip past some garbage
243// if necessary.
244void PDFDoc::checkHeader() {
245 char hdrBuf[headerSearchSize+1];
246 char *p;
247 int i;
248
249 pdfVersion = 0;
250 for (i = 0; i < headerSearchSize; ++i) {
251 hdrBuf[i] = str->getChar();
252 }
253 hdrBuf[headerSearchSize] = '\0';
254 for (i = 0; i < headerSearchSize - 5; ++i) {
255 if (!strncmp(&hdrBuf[i], "%PDF-", 5)) {
256 break;
257 }
258 }
259 if (i >= headerSearchSize - 5) {
260 error(-1, "May not be a PDF file (continuing anyway)");
261 return;
262 }
263 str->moveStart(i);
264 if (!(p = strtok(&hdrBuf[i+5], " \t\n\r"))) {
265 error(-1, "May not be a PDF file (continuing anyway)");
266 return;
267 }
268 pdfVersion = atof(p);
269 if (!(hdrBuf[i+5] >= '0' && hdrBuf[i+5] <= '9') ||
270 pdfVersion > supportedPDFVersionNum + 0.0001) {
271 error(-1, "PDF version %s -- xpdf supports version %s"
272 " (continuing anyway)", p, supportedPDFVersionStr);
273 }
274}
275
276GBool PDFDoc::checkEncryption(GString *ownerPassword, GString *userPassword) {
277 Object encrypt;
278 GBool encrypted;
279 SecurityHandler *secHdlr;
280 GBool ret;
281
282 xref->getTrailerDict()->dictLookup("Encrypt", &encrypt);
283 if ((encrypted = encrypt.isDict())) {
284 if ((secHdlr = SecurityHandler::make(this, &encrypt))) {
285 if (secHdlr->checkEncryption(ownerPassword, userPassword)) {
286 // authorization succeeded
287 xref->setEncryption(secHdlr->getPermissionFlags(),
288 secHdlr->getOwnerPasswordOk(),
289 secHdlr->getFileKey(),
290 secHdlr->getFileKeyLength(),
291 secHdlr->getEncVersion());
292 ret = gTrue;
293 } else {
294 // authorization failed
295 ret = gFalse;
296 }
297 delete secHdlr;
298 } else {
299 // couldn't find the matching security handler
300 ret = gFalse;
301 }
302 } else {
303 // document is not encrypted
304 ret = gTrue;
305 }
306 encrypt.free();
307 return ret;
308}
309
310void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI,
311 int rotate, GBool useMediaBox, GBool crop,
312 GBool doLinks,
313 GBool (*abortCheckCbk)(void *data),
314 void *abortCheckCbkData) {
315 Page *p;
316
317 if (globalParams->getPrintCommands()) {
318 printf("***** page %d *****\n", page);
319 }
320 p = catalog->getPage(page);
321 if (doLinks) {
322 if (links) {
323 delete links;
324 }
325 getLinks(p);
326 p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, links, catalog,
327 abortCheckCbk, abortCheckCbkData);
328 } else {
329 p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, NULL, catalog,
330 abortCheckCbk, abortCheckCbkData);
331 }
332}
333
334void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage,
335 double hDPI, double vDPI, int rotate,
336 GBool useMediaBox, GBool crop, GBool doLinks,
337 GBool (*abortCheckCbk)(void *data),
338 void *abortCheckCbkData) {
339 int page;
340
341 for (page = firstPage; page <= lastPage; ++page) {
342 displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, doLinks,
343 abortCheckCbk, abortCheckCbkData);
344 }
345}
346
347void PDFDoc::displayPageSlice(OutputDev *out, int page,
348 double hDPI, double vDPI, int rotate,
349 GBool useMediaBox, GBool crop, GBool doLinks,
350 int sliceX, int sliceY, int sliceW, int sliceH,
351 GBool (*abortCheckCbk)(void *data),
352 void *abortCheckCbkData) {
353 Page *p;
354
355 p = catalog->getPage(page);
356 if (doLinks) {
357 if (links) {
358 delete links;
359 }
360 getLinks(p);
361 p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop,
362 sliceX, sliceY, sliceW, sliceH,
363 links, catalog, abortCheckCbk, abortCheckCbkData);
364 } else {
365 p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop,
366 sliceX, sliceY, sliceW, sliceH,
367 NULL, catalog, abortCheckCbk, abortCheckCbkData);
368 }
369}
370
371Links *PDFDoc::takeLinks() {
372 Links *ret;
373
374 ret = links;
375 links = NULL;
376 return ret;
377}
378
379GBool PDFDoc::isLinearized() {
380 Parser *parser;
381 Object obj1, obj2, obj3, obj4, obj5;
382 GBool lin;
383
384 lin = gFalse;
385 obj1.initNull();
386 parser = new Parser(xref,
387 new Lexer(xref,
388 str->makeSubStream(str->getStart(), gFalse, 0, &obj1)));
389 parser->getObj(&obj1);
390 parser->getObj(&obj2);
391 parser->getObj(&obj3);
392 parser->getObj(&obj4);
393 if (obj1.isInt() && obj2.isInt() && obj3.isCmd("obj") &&
394 obj4.isDict()) {
395 obj4.dictLookup("Linearized", &obj5);
396 if (obj5.isNum() && obj5.getNum() > 0) {
397 lin = gTrue;
398 }
399 obj5.free();
400 }
401 obj4.free();
402 obj3.free();
403 obj2.free();
404 obj1.free();
405 delete parser;
406 return lin;
407}
408
409GBool PDFDoc::saveAs(GString *name) {
410 FILE *f;
411 int c;
412
413 if (!(f = fopen(name->getCString(), "wb"))) {
414 error(-1, "Couldn't open file '%s'", name->getCString());
415 return gFalse;
416 }
417 str->reset();
418 while ((c = str->getChar()) != EOF) {
419 fputc(c, f);
420 }
421 str->close();
422 fclose(f);
423 return gTrue;
424}
425
426void PDFDoc::getLinks(Page *page) {
427 Object obj;
428
429 links = new Links(page->getAnnots(&obj), catalog->getBaseURI());
430 obj.free();
431}