1 //========================================================================
5 // Copyright 1996-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
23 #include "goo/GooString.h"
24 #include "poppler-config.h"
25 #include "GlobalParams.h"
31 #include "OutputDev.h"
33 #include "ErrorCodes.h"
36 #include "SecurityHandler.h"
37 #ifndef DISABLE_OUTLINE
41 #include "UGooString.h"
43 //------------------------------------------------------------------------
45 #define headerSearchSize 1024 // read this many bytes at beginning of
46 // file to look for '%PDF'
48 //------------------------------------------------------------------------
50 //------------------------------------------------------------------------
52 PDFDoc::PDFDoc(GooString
*fileNameA
, GooString
*ownerPassword
,
53 GooString
*userPassword
, void *guiDataA
) {
55 GooString
*fileName1
, *fileName2
;
67 #ifndef DISABLE_OUTLINE
78 if (!(file
= fopen(fileName1
->getCString(), "rb", "ctx=stm"))) {
79 error(-1, "Couldn't open file '%s'", fileName1
->getCString());
80 errCode
= errOpenFile
;
84 if (!(file
= fopen(fileName1
->getCString(), "rb"))) {
85 fileName2
= fileName
->copy();
86 fileName2
->lowerCase();
87 if (!(file
= fopen(fileName2
->getCString(), "rb"))) {
88 fileName2
->upperCase();
89 if (!(file
= fopen(fileName2
->getCString(), "rb"))) {
90 error(-1, "Couldn't open file '%s'", fileName
->getCString());
92 errCode
= errOpenFile
;
102 str
= new FileStream(file
, 0, gFalse
, 0, &obj
);
104 ok
= setup(ownerPassword
, userPassword
);
108 PDFDoc::PDFDoc(wchar_t *fileNameA
, int fileNameLen
, GooString
*ownerPassword
,
109 GooString
*userPassword
, void *guiDataA
) {
110 OSVERSIONINFO version
;
111 wchar_t fileName2
[_MAX_PATH
+ 1];
125 #ifndef DISABLE_OUTLINE
129 //~ file name should be stored in Unicode (?)
130 fileName
= new GooString();
131 for (i
= 0; i
< fileNameLen
; ++i
) {
132 fileName
->append((char)fileNameA
[i
]);
135 // zero-terminate the file name string
136 for (i
= 0; i
< fileNameLen
&& i
< _MAX_PATH
; ++i
) {
137 fileName2
[i
] = fileNameA
[i
];
142 // NB: _wfopen is only available in NT
143 version
.dwOSVersionInfoSize
= sizeof(version
);
144 GetVersionEx(&version
);
145 if (version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
146 file
= _wfopen(fileName2
, L
"rb");
148 file
= fopen(fileName
->getCString(), "rb");
151 error(-1, "Couldn't open file '%s'", fileName
->getCString());
152 errCode
= errOpenFile
;
158 str
= new FileStream(file
, 0, gFalse
, 0, &obj
);
160 ok
= setup(ownerPassword
, userPassword
);
164 PDFDoc::PDFDoc(BaseStream
*strA
, GooString
*ownerPassword
,
165 GooString
*userPassword
, void *guiDataA
) {
175 #ifndef DISABLE_OUTLINE
178 ok
= setup(ownerPassword
, userPassword
);
181 GBool
PDFDoc::setup(GooString
*ownerPassword
, GooString
*userPassword
) {
185 if (!checkFooter()) return gFalse
;
191 xref
= new XRef(str
);
193 error(-1, "Couldn't read xref table");
194 errCode
= xref
->getErrorCode();
198 // check for encryption
199 if (!checkEncryption(ownerPassword
, userPassword
)) {
200 errCode
= errEncrypted
;
205 catalog
= new Catalog(xref
);
206 if (!catalog
->isOk()) {
207 error(-1, "Couldn't read page catalog");
208 errCode
= errBadCatalog
;
212 #ifndef DISABLE_OUTLINE
214 outline
= new Outline(catalog
->getOutline(), xref
);
222 #ifndef DISABLE_OUTLINE
248 // Check for a %%EOF at the end of this stream
249 GBool
PDFDoc::checkFooter() {
250 // we look in the last 1024 chars because Adobe does the same
251 char *eof
= new char[1025];
252 int pos
= str
->getPos();
253 str
->setPos(1024, -1);
255 for (i
= 0; i
< 1024; i
++)
265 for (i
= i
- 5; i
>= 0; i
--) {
266 if (strncmp (&eof
[i
], "%%EOF", 5) == 0) {
273 error(-1, "Document has not the mandatory ending %%EOF");
274 errCode
= errDamaged
;
283 // Check for a PDF header on this stream. Skip past some garbage
285 void PDFDoc::checkHeader() {
286 char hdrBuf
[headerSearchSize
+1];
291 for (i
= 0; i
< headerSearchSize
; ++i
) {
292 hdrBuf
[i
] = str
->getChar();
294 hdrBuf
[headerSearchSize
] = '\0';
295 for (i
= 0; i
< headerSearchSize
- 5; ++i
) {
296 if (!strncmp(&hdrBuf
[i
], "%PDF-", 5)) {
300 if (i
>= headerSearchSize
- 5) {
301 error(-1, "May not be a PDF file (continuing anyway)");
305 if (!(p
= strtok(&hdrBuf
[i
+5], " \t\n\r"))) {
306 error(-1, "May not be a PDF file (continuing anyway)");
310 char *theLocale
= setlocale(LC_NUMERIC
, "C");
311 pdfVersion
= atof(p
);
312 setlocale(LC_NUMERIC
, theLocale
);
314 // We don't do the version check. Don't add it back in.
317 GBool
PDFDoc::checkEncryption(GooString
*ownerPassword
, GooString
*userPassword
) {
320 SecurityHandler
*secHdlr
;
323 xref
->getTrailerDict()->dictLookup("Encrypt", &encrypt
);
324 if ((encrypted
= encrypt
.isDict())) {
325 if ((secHdlr
= SecurityHandler::make(this, &encrypt
))) {
326 if (secHdlr
->checkEncryption(ownerPassword
, userPassword
)) {
327 // authorization succeeded
328 xref
->setEncryption(secHdlr
->getPermissionFlags(),
329 secHdlr
->getOwnerPasswordOk(),
330 secHdlr
->getFileKey(),
331 secHdlr
->getFileKeyLength(),
332 secHdlr
->getEncVersion(),
333 secHdlr
->getEncRevision());
336 // authorization failed
341 // couldn't find the matching security handler
345 // document is not encrypted
352 void PDFDoc::displayPage(OutputDev
*out
, int page
, double hDPI
, double vDPI
,
353 int rotate
, GBool useMediaBox
, GBool crop
, GBool doLinks
,
354 GBool (*abortCheckCbk
)(void *data
),
355 void *abortCheckCbkData
,
356 GBool (*annotDisplayDecideCbk
)(Annot
*annot
, void *user_data
),
357 void *annotDisplayDecideCbkData
) {
360 if (globalParams
->getPrintCommands()) {
361 printf("***** page %d *****\n", page
);
363 p
= catalog
->getPage(page
);
369 p
->display(out
, hDPI
, vDPI
, rotate
, useMediaBox
, crop
, links
, catalog
,
370 abortCheckCbk
, abortCheckCbkData
,
371 annotDisplayDecideCbk
, annotDisplayDecideCbkData
);
373 p
->display(out
, hDPI
, vDPI
, rotate
, useMediaBox
, crop
, NULL
, catalog
,
374 abortCheckCbk
, abortCheckCbkData
,
375 annotDisplayDecideCbk
, annotDisplayDecideCbkData
);
379 void PDFDoc::displayPages(OutputDev
*out
, int firstPage
, int lastPage
,
380 double hDPI
, double vDPI
, int rotate
, GBool useMediaBox
,
381 GBool crop
, GBool doLinks
,
382 GBool (*abortCheckCbk
)(void *data
),
383 void *abortCheckCbkData
,
384 GBool (*annotDisplayDecideCbk
)(Annot
*annot
, void *user_data
),
385 void *annotDisplayDecideCbkData
) {
388 for (page
= firstPage
; page
<= lastPage
; ++page
) {
389 displayPage(out
, page
, hDPI
, vDPI
, rotate
, useMediaBox
, crop
, doLinks
,
390 abortCheckCbk
, abortCheckCbkData
,
391 annotDisplayDecideCbk
, annotDisplayDecideCbkData
);
395 void PDFDoc::displayPageSlice(OutputDev
*out
, int page
,
396 double hDPI
, double vDPI
,
397 int rotate
, GBool useMediaBox
, GBool crop
, GBool doLinks
,
398 int sliceX
, int sliceY
, int sliceW
, int sliceH
,
399 GBool (*abortCheckCbk
)(void *data
),
400 void *abortCheckCbkData
,
401 GBool (*annotDisplayDecideCbk
)(Annot
*annot
, void *user_data
),
402 void *annotDisplayDecideCbkData
) {
405 p
= catalog
->getPage(page
);
412 p
->displaySlice(out
, hDPI
, vDPI
, rotate
, useMediaBox
, crop
,
413 sliceX
, sliceY
, sliceW
, sliceH
,
415 abortCheckCbk
, abortCheckCbkData
,
416 annotDisplayDecideCbk
, annotDisplayDecideCbkData
);
418 p
->displaySlice(out
, hDPI
, vDPI
, rotate
, useMediaBox
, crop
,
419 sliceX
, sliceY
, sliceW
, sliceH
,
421 abortCheckCbk
, abortCheckCbkData
,
422 annotDisplayDecideCbk
, annotDisplayDecideCbkData
);
426 Links
*PDFDoc::takeLinks() {
434 GBool
PDFDoc::isLinearized() {
436 Object obj1
, obj2
, obj3
, obj4
, obj5
;
441 parser
= new Parser(xref
,
443 str
->makeSubStream(str
->getStart(), gFalse
, 0, &obj1
)));
444 parser
->getObj(&obj1
);
445 parser
->getObj(&obj2
);
446 parser
->getObj(&obj3
);
447 parser
->getObj(&obj4
);
448 if (obj1
.isInt() && obj2
.isInt() && obj3
.isCmd("obj") &&
450 obj4
.dictLookup("Linearized", &obj5
);
451 if (obj5
.isNum() && obj5
.getNum() > 0) {
464 GBool
PDFDoc::saveAs(GooString
*name
) {
468 if (!(f
= fopen(name
->getCString(), "wb"))) {
469 error(-1, "Couldn't open file '%s'", name
->getCString());
473 while ((c
= str
->getChar()) != EOF
) {
481 void PDFDoc::getLinks(Page
*page
) {
484 links
= new Links(page
->getAnnots(&obj
), catalog
->getBaseURI());