source: trunk/poppler/mypoppler/poppler/PDFDoc.cc @ 2

Last change on this file since 2 was 2, checked in by Eugene Romanenko, 15 years ago

First import

File size: 11.3 KB
Line 
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 <locale.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <stddef.h>
19#include <string.h>
20#ifdef WIN32
21#  include <windows.h>
22#endif
23#include "goo/GooString.h"
24#include "poppler-config.h"
25#include "GlobalParams.h"
26#include "Page.h"
27#include "Catalog.h"
28#include "Stream.h"
29#include "XRef.h"
30#include "Link.h"
31#include "OutputDev.h"
32#include "Error.h"
33#include "ErrorCodes.h"
34#include "Lexer.h"
35#include "Parser.h"
36#include "SecurityHandler.h"
37#ifndef DISABLE_OUTLINE
38#include "Outline.h"
39#endif
40#include "PDFDoc.h"
41#include "UGooString.h"
42
43//------------------------------------------------------------------------
44
45#define headerSearchSize 1024   // read this many bytes at beginning of
46                                //   file to look for '%PDF'
47
48//------------------------------------------------------------------------
49// PDFDoc
50//------------------------------------------------------------------------
51
52PDFDoc::PDFDoc(GooString *fileNameA, GooString *ownerPassword,
53               GooString *userPassword, void *guiDataA) {
54  Object obj;
55  GooString *fileName1, *fileName2;
56
57  ok = gFalse;
58  errCode = errNone;
59
60  guiData = guiDataA;
61
62  file = NULL;
63  str = NULL;
64  xref = NULL;
65  catalog = NULL;
66  links = NULL;
67#ifndef DISABLE_OUTLINE
68  outline = NULL;
69#endif
70
71  fileName = fileNameA;
72  fileName1 = fileName;
73
74
75  // try to open file
76  fileName2 = NULL;
77#ifdef VMS
78  if (!(file = fopen(fileName1->getCString(), "rb", "ctx=stm"))) {
79    error(-1, "Couldn't open file '%s'", fileName1->getCString());
80    errCode = errOpenFile;
81    return;
82  }
83#else
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());
91        delete fileName2;
92        errCode = errOpenFile;
93        return;
94      }
95    }
96    delete fileName2;
97  }
98#endif
99
100  // create stream
101  obj.initNull();
102  str = new FileStream(file, 0, gFalse, 0, &obj);
103
104  ok = setup(ownerPassword, userPassword);
105}
106
107#ifdef WIN32
108PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GooString *ownerPassword,
109               GooString *userPassword, void *guiDataA) {
110  OSVERSIONINFO version;
111  wchar_t fileName2[_MAX_PATH + 1];
112  Object obj;
113  int i;
114
115  ok = gFalse;
116  errCode = errNone;
117
118  guiData = guiDataA;
119
120  file = NULL;
121  str = NULL;
122  xref = NULL;
123  catalog = NULL;
124  links = NULL;
125#ifndef DISABLE_OUTLINE
126  outline = NULL;
127#endif
128
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]);
133  }
134
135  // zero-terminate the file name string
136  for (i = 0; i < fileNameLen && i < _MAX_PATH; ++i) {
137    fileName2[i] = fileNameA[i];
138  }
139  fileName2[i] = 0;
140
141  // try to open file
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");
147  } else {
148    file = fopen(fileName->getCString(), "rb");
149  }
150  if (!file) {
151    error(-1, "Couldn't open file '%s'", fileName->getCString());
152    errCode = errOpenFile;
153    return;
154  }
155
156  // create stream
157  obj.initNull();
158  str = new FileStream(file, 0, gFalse, 0, &obj);
159
160  ok = setup(ownerPassword, userPassword);
161}
162#endif
163
164PDFDoc::PDFDoc(BaseStream *strA, GooString *ownerPassword,
165               GooString *userPassword, void *guiDataA) {
166  ok = gFalse;
167  errCode = errNone;
168  guiData = guiDataA;
169  fileName = NULL;
170  file = NULL;
171  str = strA;
172  xref = NULL;
173  catalog = NULL;
174  links = NULL;
175#ifndef DISABLE_OUTLINE
176  outline = NULL;
177#endif
178  ok = setup(ownerPassword, userPassword);
179}
180
181GBool PDFDoc::setup(GooString *ownerPassword, GooString *userPassword) {
182  str->reset();
183
184  // check footer
185  if (!checkFooter()) return gFalse;
186 
187  // check header
188  checkHeader();
189
190  // read xref table
191  xref = new XRef(str);
192  if (!xref->isOk()) {
193    error(-1, "Couldn't read xref table");
194    errCode = xref->getErrorCode();
195    return gFalse;
196  }
197
198  // check for encryption
199  if (!checkEncryption(ownerPassword, userPassword)) {
200    errCode = errEncrypted;
201    return gFalse;
202  }
203
204  // read catalog
205  catalog = new Catalog(xref);
206  if (!catalog->isOk()) {
207    error(-1, "Couldn't read page catalog");
208    errCode = errBadCatalog;
209    return gFalse;
210  }
211
212#ifndef DISABLE_OUTLINE
213  // read outline
214  outline = new Outline(catalog->getOutline(), xref);
215#endif
216
217  // done
218  return gTrue;
219}
220
221PDFDoc::~PDFDoc() {
222#ifndef DISABLE_OUTLINE
223  if (outline) {
224    delete outline;
225  }
226#endif
227  if (catalog) {
228    delete catalog;
229  }
230  if (xref) {
231    delete xref;
232  }
233  if (str) {
234    delete str;
235  }
236  if (file) {
237    fclose(file);
238  }
239  if (fileName) {
240    delete fileName;
241  }
242  if (links) {
243    delete links;
244  }
245}
246
247
248// Check for a %%EOF at the end of this stream
249GBool 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);
254  int i, ch;
255  for (i = 0; i < 1024; i++)
256  {
257    ch = str->getChar();
258    if (ch == EOF)
259      break;
260    eof[i] = ch;
261  }
262  eof[i] = '\0';
263
264  bool found = false;
265  for (i = i - 5; i >= 0; i--) {
266    if (strncmp (&eof[i], "%%EOF", 5) == 0) {
267      found = true;
268      break;
269    }
270  }
271  if (!found)
272  {
273    error(-1, "Document has not the mandatory ending %%EOF");
274    errCode = errDamaged;
275    delete[] eof;
276    return gFalse;
277  }
278  delete[] eof;
279  str->setPos(pos);
280  return gTrue;
281}
282 
283// Check for a PDF header on this stream.  Skip past some garbage
284// if necessary.
285void PDFDoc::checkHeader() {
286  char hdrBuf[headerSearchSize+1];
287  char *p;
288  int i;
289
290  pdfVersion = 0;
291  for (i = 0; i < headerSearchSize; ++i) {
292    hdrBuf[i] = str->getChar();
293  }
294  hdrBuf[headerSearchSize] = '\0';
295  for (i = 0; i < headerSearchSize - 5; ++i) {
296    if (!strncmp(&hdrBuf[i], "%PDF-", 5)) {
297      break;
298    }
299  }
300  if (i >= headerSearchSize - 5) {
301    error(-1, "May not be a PDF file (continuing anyway)");
302    return;
303  }
304  str->moveStart(i);
305  if (!(p = strtok(&hdrBuf[i+5], " \t\n\r"))) {
306    error(-1, "May not be a PDF file (continuing anyway)");
307    return;
308  }
309  {
310    char *theLocale = setlocale(LC_NUMERIC, "C");
311    pdfVersion = atof(p);
312    setlocale(LC_NUMERIC, theLocale);
313  }
314  // We don't do the version check. Don't add it back in.
315}
316
317GBool PDFDoc::checkEncryption(GooString *ownerPassword, GooString *userPassword) {
318  Object encrypt;
319  GBool encrypted;
320  SecurityHandler *secHdlr;
321  GBool ret;
322
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());
334        ret = gTrue;
335      } else {
336        // authorization failed
337        ret = gFalse;
338      }
339      delete secHdlr;
340    } else {
341      // couldn't find the matching security handler
342      ret = gFalse;
343    }
344  } else {
345    // document is not encrypted
346    ret = gTrue;
347  }
348  encrypt.free();
349  return ret;
350}
351
352void 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) {
358  Page *p;
359
360  if (globalParams->getPrintCommands()) {
361    printf("***** page %d *****\n", page);
362  }
363  p = catalog->getPage(page);
364  if (doLinks) {
365    if (links) {
366      delete links;
367    }
368    getLinks(p);
369    p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, links, catalog,
370               abortCheckCbk, abortCheckCbkData,
371               annotDisplayDecideCbk, annotDisplayDecideCbkData);
372  } else {
373    p->display(out, hDPI, vDPI, rotate, useMediaBox, crop, NULL, catalog,
374               abortCheckCbk, abortCheckCbkData,
375               annotDisplayDecideCbk, annotDisplayDecideCbkData);
376  }
377}
378
379void 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) {
386  int page;
387
388  for (page = firstPage; page <= lastPage; ++page) {
389    displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, doLinks,
390                abortCheckCbk, abortCheckCbkData,
391                annotDisplayDecideCbk, annotDisplayDecideCbkData);
392  }
393}
394
395void 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) {
403  Page *p;
404
405  p = catalog->getPage(page);
406  if (doLinks)
407  {
408    if (links) {
409      delete links;
410    }
411    getLinks(p);
412    p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop,
413                  sliceX, sliceY, sliceW, sliceH,
414                  links, catalog,
415                  abortCheckCbk, abortCheckCbkData,
416                  annotDisplayDecideCbk, annotDisplayDecideCbkData);
417  } else {
418    p->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop,
419                  sliceX, sliceY, sliceW, sliceH,
420                  NULL, catalog,
421                  abortCheckCbk, abortCheckCbkData,
422                  annotDisplayDecideCbk, annotDisplayDecideCbkData);
423  } 
424}
425
426Links *PDFDoc::takeLinks() {
427  Links *ret;
428
429  ret = links;
430  links = NULL;
431  return ret;
432}
433
434GBool PDFDoc::isLinearized() {
435  Parser *parser;
436  Object obj1, obj2, obj3, obj4, obj5;
437  GBool lin;
438
439  lin = gFalse;
440  obj1.initNull();
441  parser = new Parser(xref,
442             new Lexer(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") &&
449      obj4.isDict()) {
450    obj4.dictLookup("Linearized", &obj5);
451    if (obj5.isNum() && obj5.getNum() > 0) {
452      lin = gTrue;
453    }
454    obj5.free();
455  }
456  obj4.free();
457  obj3.free();
458  obj2.free();
459  obj1.free();
460  delete parser;
461  return lin;
462}
463
464GBool PDFDoc::saveAs(GooString *name) {
465  FILE *f;
466  int c;
467
468  if (!(f = fopen(name->getCString(), "wb"))) {
469    error(-1, "Couldn't open file '%s'", name->getCString());
470    return gFalse;
471  }
472  str->reset();
473  while ((c = str->getChar()) != EOF) {
474    fputc(c, f);
475  }
476  str->close();
477  fclose(f);
478  return gTrue;
479}
480
481void PDFDoc::getLinks(Page *page) {
482  Object obj;
483
484  links = new Links(page->getAnnots(&obj), catalog->getBaseURI());
485  obj.free();
486}
Note: See TracBrowser for help on using the repository browser.