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;
65 #ifndef DISABLE_OUTLINE
76 if (!(file = fopen(fileName1->getCString(), "rb", "ctx=stm"))) {
77 error(-1, "Couldn't open file '%s'", fileName1->getCString());
78 errCode = errOpenFile;
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());
90 errCode = errOpenFile;
100 str = new FileStream(file, 0, gFalse, 0, &obj);
102 ok = setup(ownerPassword, userPassword);
106 PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GString *ownerPassword,
107 GString *userPassword, void *guiDataA) {
108 OSVERSIONINFO version;
109 wchar_t fileName2[_MAX_PATH + 1];
123 #ifndef DISABLE_OUTLINE
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]);
133 // zero-terminate the file name string
134 for (i = 0; i < fileNameLen && i < _MAX_PATH; ++i) {
135 fileName2[i] = fileNameA[i];
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");
146 file = fopen(fileName->getCString(), "rb");
149 error(-1, "Couldn't open file '%s'", fileName->getCString());
150 errCode = errOpenFile;
156 str = new FileStream(file, 0, gFalse, 0, &obj);
158 ok = setup(ownerPassword, userPassword);
162 PDFDoc::PDFDoc(BaseStream *strA, GString *ownerPassword,
163 GString *userPassword, void *guiDataA) {
173 #ifndef DISABLE_OUTLINE
176 ok = setup(ownerPassword, userPassword);
179 GBool PDFDoc::setup(GString *ownerPassword, GString *userPassword) {
186 xref = new XRef(str);
188 error(-1, "Couldn't read xref table");
189 errCode = xref->getErrorCode();
193 // check for encryption
194 if (!checkEncryption(ownerPassword, userPassword)) {
195 errCode = errEncrypted;
200 catalog = new Catalog(xref);
201 if (!catalog->isOk()) {
202 error(-1, "Couldn't read page catalog");
203 errCode = errBadCatalog;
207 #ifndef DISABLE_OUTLINE
209 outline = new Outline(catalog->getOutline(), xref);
217 #ifndef DISABLE_OUTLINE
242 // Check for a PDF header on this stream. Skip past some garbage
244 void PDFDoc::checkHeader() {
245 char hdrBuf[headerSearchSize+1];
250 for (i = 0; i < headerSearchSize; ++i) {
251 hdrBuf[i] = str->getChar();
253 hdrBuf[headerSearchSize] = '\0';
254 for (i = 0; i < headerSearchSize - 5; ++i) {
255 if (!strncmp(&hdrBuf[i], "%PDF-", 5)) {
259 if (i >= headerSearchSize - 5) {
260 error(-1, "May not be a PDF file (continuing anyway)");
264 if (!(p = strtok(&hdrBuf[i+5], " \t\n\r"))) {
265 error(-1, "May not be a PDF file (continuing anyway)");
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);
276 GBool PDFDoc::checkEncryption(GString *ownerPassword, GString *userPassword) {
279 SecurityHandler *secHdlr;
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());
294 // authorization failed
299 // couldn't find the matching security handler
303 // document is not encrypted
310 void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI,
311 int rotate, GBool useMediaBox, GBool crop,
313 GBool (*abortCheckCbk)(void *data),
314 void *abortCheckCbkData) {
317 if (globalParams->getPrintCommands()) {
318 printf("***** page %d *****\n", page);
320 p = catalog->getPage(page);
326 p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, links, catalog,
327 abortCheckCbk, abortCheckCbkData);
329 p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, NULL, catalog,
330 abortCheckCbk, abortCheckCbkData);
334 void 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) {
341 for (page = firstPage; page <= lastPage; ++page) {
342 displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, doLinks,
343 abortCheckCbk, abortCheckCbkData);
347 void 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) {
355 p = catalog->getPage(page);
361 p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop,
362 sliceX, sliceY, sliceW, sliceH,
363 links, catalog, abortCheckCbk, abortCheckCbkData);
365 p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop,
366 sliceX, sliceY, sliceW, sliceH,
367 NULL, catalog, abortCheckCbk, abortCheckCbkData);
371 Links *PDFDoc::takeLinks() {
379 GBool PDFDoc::isLinearized() {
381 Object obj1, obj2, obj3, obj4, obj5;
386 parser = new Parser(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") &&
395 obj4.dictLookup("Linearized", &obj5);
396 if (obj5.isNum() && obj5.getNum() > 0) {
409 GBool PDFDoc::saveAs(GString *name) {
413 if (!(f = fopen(name->getCString(), "wb"))) {
414 error(-1, "Couldn't open file '%s'", name->getCString());
418 while ((c = str->getChar()) != EOF) {
426 void PDFDoc::getLinks(Page *page) {
429 links = new Links(page->getAnnots(&obj), catalog->getBaseURI());