1 //========================================================================
5 // Copyright 1996-2003 Glyph & Cog, LLC
7 //========================================================================
11 #ifdef USE_GCC_PRAGMAS
12 #pragma implementation
24 #include "GlobalParams.h"
30 #include "OutputDev.h"
32 #include "ErrorCodes.h"
35 #include "SecurityHandler.h"
36 #ifndef DISABLE_OUTLINE
41 //------------------------------------------------------------------------
43 #define headerSearchSize 1024 // read this many bytes at beginning of
44 // file to look for '%PDF'
46 //------------------------------------------------------------------------
48 //------------------------------------------------------------------------
50 PDFDoc::PDFDoc(GString
*fileNameA
, GString
*ownerPassword
,
51 GString
*userPassword
, void *guiDataA
) {
53 GString
*fileName1
, *fileName2
;
64 #ifndef DISABLE_OUTLINE
75 if (!(file
= fopen(fileName1
->getCString(), "rb", "ctx=stm"))) {
76 error(-1, "Couldn't open file '%s'", fileName1
->getCString());
77 errCode
= errOpenFile
;
81 if (!(file
= fopen(fileName1
->getCString(), "rb"))) {
82 fileName2
= fileName
->copy();
83 fileName2
->lowerCase();
84 if (!(file
= fopen(fileName2
->getCString(), "rb"))) {
85 fileName2
->upperCase();
86 if (!(file
= fopen(fileName2
->getCString(), "rb"))) {
87 error(-1, "Couldn't open file '%s'", fileName
->getCString());
89 errCode
= errOpenFile
;
99 str
= new FileStream(file
, 0, gFalse
, 0, &obj
);
101 ok
= setup(ownerPassword
, userPassword
);
105 PDFDoc::PDFDoc(wchar_t *fileNameA
, int fileNameLen
, GString
*ownerPassword
,
106 GString
*userPassword
, void *guiDataA
) {
107 OSVERSIONINFO version
;
108 wchar_t fileName2
[_MAX_PATH
+ 1];
121 #ifndef DISABLE_OUTLINE
125 //~ file name should be stored in Unicode (?)
126 fileName
= new GString();
127 for (i
= 0; i
< fileNameLen
; ++i
) {
128 fileName
->append((char)fileNameA
[i
]);
131 // zero-terminate the file name string
132 for (i
= 0; i
< fileNameLen
&& i
< _MAX_PATH
; ++i
) {
133 fileName2
[i
] = fileNameA
[i
];
138 // NB: _wfopen is only available in NT
139 version
.dwOSVersionInfoSize
= sizeof(version
);
140 GetVersionEx(&version
);
141 if (version
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
142 file
= _wfopen(fileName2
, L
"rb");
144 file
= fopen(fileName
->getCString(), "rb");
147 error(-1, "Couldn't open file '%s'", fileName
->getCString());
148 errCode
= errOpenFile
;
154 str
= new FileStream(file
, 0, gFalse
, 0, &obj
);
156 ok
= setup(ownerPassword
, userPassword
);
160 PDFDoc::PDFDoc(BaseStream
*strA
, GString
*ownerPassword
,
161 GString
*userPassword
, void *guiDataA
) {
165 if (strA
->getFileName()) {
166 fileName
= strA
->getFileName()->copy();
174 #ifndef DISABLE_OUTLINE
177 ok
= setup(ownerPassword
, userPassword
);
180 GBool
PDFDoc::setup(GString
*ownerPassword
, GString
*userPassword
) {
187 xref
= new XRef(str
);
189 error(-1, "Couldn't read xref table");
190 errCode
= xref
->getErrorCode();
194 // check for encryption
195 if (!checkEncryption(ownerPassword
, userPassword
)) {
196 errCode
= errEncrypted
;
201 catalog
= new Catalog(xref
);
202 if (!catalog
->isOk()) {
203 error(-1, "Couldn't read page catalog");
204 errCode
= errBadCatalog
;
208 #ifndef DISABLE_OUTLINE
210 outline
= new Outline(catalog
->getOutline(), xref
);
218 #ifndef DISABLE_OUTLINE
240 // Check for a PDF header on this stream. Skip past some garbage
242 void PDFDoc::checkHeader() {
243 char hdrBuf
[headerSearchSize
+1];
248 for (i
= 0; i
< headerSearchSize
; ++i
) {
249 hdrBuf
[i
] = str
->getChar();
251 hdrBuf
[headerSearchSize
] = '\0';
252 for (i
= 0; i
< headerSearchSize
- 5; ++i
) {
253 if (!strncmp(&hdrBuf
[i
], "%PDF-", 5)) {
257 if (i
>= headerSearchSize
- 5) {
258 error(-1, "May not be a PDF file (continuing anyway)");
262 if (!(p
= strtok(&hdrBuf
[i
+5], " \t\n\r"))) {
263 error(-1, "May not be a PDF file (continuing anyway)");
266 pdfVersion
= atof(p
);
267 if (!(hdrBuf
[i
+5] >= '0' && hdrBuf
[i
+5] <= '9') ||
268 pdfVersion
> supportedPDFVersionNum
+ 0.0001) {
269 error(-1, "PDF version %s -- xpdf supports version %s"
270 " (continuing anyway)", p
, supportedPDFVersionStr
);
274 GBool
PDFDoc::checkEncryption(GString
*ownerPassword
, GString
*userPassword
) {
277 SecurityHandler
*secHdlr
;
280 xref
->getTrailerDict()->dictLookup("Encrypt", &encrypt
);
281 if ((encrypted
= encrypt
.isDict())) {
282 if ((secHdlr
= SecurityHandler::make(this, &encrypt
))) {
283 if (secHdlr
->checkEncryption(ownerPassword
, userPassword
)) {
284 // authorization succeeded
285 xref
->setEncryption(secHdlr
->getPermissionFlags(),
286 secHdlr
->getOwnerPasswordOk(),
287 secHdlr
->getFileKey(),
288 secHdlr
->getFileKeyLength(),
289 secHdlr
->getEncVersion(),
290 secHdlr
->getEncAlgorithm());
293 // authorization failed
298 // couldn't find the matching security handler
302 // document is not encrypted
309 void PDFDoc::displayPage(OutputDev
*out
, int page
,
310 double hDPI
, double vDPI
, int rotate
,
311 GBool useMediaBox
, GBool crop
, GBool printing
,
312 GBool (*abortCheckCbk
)(void *data
),
313 void *abortCheckCbkData
) {
314 if (globalParams
->getPrintCommands()) {
315 printf("***** page %d *****\n", page
);
317 catalog
->getPage(page
)->display(out
, hDPI
, vDPI
,
318 rotate
, useMediaBox
, crop
, printing
, catalog
,
319 abortCheckCbk
, abortCheckCbkData
);
322 void PDFDoc::displayPages(OutputDev
*out
, int firstPage
, int lastPage
,
323 double hDPI
, double vDPI
, int rotate
,
324 GBool useMediaBox
, GBool crop
, GBool printing
,
325 GBool (*abortCheckCbk
)(void *data
),
326 void *abortCheckCbkData
) {
329 for (page
= firstPage
; page
<= lastPage
; ++page
) {
330 displayPage(out
, page
, hDPI
, vDPI
, rotate
, useMediaBox
, crop
, printing
,
331 abortCheckCbk
, abortCheckCbkData
);
335 void PDFDoc::displayPageSlice(OutputDev
*out
, int page
,
336 double hDPI
, double vDPI
, int rotate
,
337 GBool useMediaBox
, GBool crop
, GBool printing
,
338 int sliceX
, int sliceY
, int sliceW
, int sliceH
,
339 GBool (*abortCheckCbk
)(void *data
),
340 void *abortCheckCbkData
) {
341 catalog
->getPage(page
)->displaySlice(out
, hDPI
, vDPI
,
342 rotate
, useMediaBox
, crop
,
343 sliceX
, sliceY
, sliceW
, sliceH
,
345 abortCheckCbk
, abortCheckCbkData
);
348 Links
*PDFDoc::getLinks(int page
) {
349 return catalog
->getPage(page
)->getLinks(catalog
);
352 void PDFDoc::processLinks(OutputDev
*out
, int page
) {
353 catalog
->getPage(page
)->processLinks(out
, catalog
);
356 GBool
PDFDoc::isLinearized() {
358 xObject obj1
, obj2
, obj3
, obj4
, obj5
;
363 parser
= new Parser(xref
,
365 str
->makeSubStream(str
->getStart(), gFalse
, 0, &obj1
)),
367 parser
->getObj(&obj1
);
368 parser
->getObj(&obj2
);
369 parser
->getObj(&obj3
);
370 parser
->getObj(&obj4
);
371 if (obj1
.isInt() && obj2
.isInt() && obj3
.isCmd("obj") &&
373 obj4
.dictLookup("Linearized", &obj5
);
374 if (obj5
.isNum() && obj5
.getNum() > 0) {
387 GBool
PDFDoc::saveAs(GString
*name
) {
391 if (!(f
= fopen(name
->getCString(), "wb"))) {
392 error(-1, "Couldn't open file '%s'", name
->getCString());
396 while ((c
= str
->getChar()) != EOF
) {