w32tex
About: TeX Live provides a comprehensive TeX system including all the major TeX-related programs, macro packages, and fonts that are free software. Windows sources.
  Fossies Dox: w32tex-src.tar.xz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

PDFDoc.cc
Go to the documentation of this file.
1 //========================================================================
2 //
3 // PDFDoc.cc
4 //
5 // Copyright 1996-2003 Glyph & Cog, LLC
6 //
7 //========================================================================
8 
9 //========================================================================
10 //
11 // Modified under the Poppler project - http://poppler.freedesktop.org
12 //
13 // All changes made under the Poppler project to this file are licensed
14 // under GPL version 2 or later
15 //
16 // Copyright (C) 2005, 2006, 2008 Brad Hards <bradh@frogmouth.net>
17 // Copyright (C) 2005, 2007-2009, 2011-2020 Albert Astals Cid <aacid@kde.org>
18 // Copyright (C) 2008 Julien Rebetez <julienr@svn.gnome.org>
19 // Copyright (C) 2008, 2010 Pino Toscano <pino@kde.org>
20 // Copyright (C) 2008, 2010, 2011 Carlos Garcia Campos <carlosgc@gnome.org>
21 // Copyright (C) 2009 Eric Toombs <ewtoombs@uwaterloo.ca>
22 // Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net>
23 // Copyright (C) 2009, 2011 Axel Struebing <axel.struebing@freenet.de>
24 // Copyright (C) 2010-2012, 2014 Hib Eris <hib@hiberis.nl>
25 // Copyright (C) 2010 Jakub Wilk <jwilk@jwilk.net>
26 // Copyright (C) 2010 Ilya Gorenbein <igorenbein@finjan.com>
27 // Copyright (C) 2010 Srinivas Adicherla <srinivas.adicherla@geodesic.com>
28 // Copyright (C) 2010 Philip Lorenz <lorenzph+freedesktop@gmail.com>
29 // Copyright (C) 2011-2016 Thomas Freitag <Thomas.Freitag@alfa.de>
30 // Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it>
31 // Copyright (C) 2013, 2014, 2017 Adrian Johnson <ajohnson@redneon.com>
32 // Copyright (C) 2013, 2018 Adam Reichold <adamreichold@myopera.com>
33 // Copyright (C) 2014 Bogdan Cristea <cristeab@gmail.com>
34 // Copyright (C) 2015 Li Junling <lijunling@sina.com>
35 // Copyright (C) 2015 André Guerreiro <aguerreiro1985@gmail.com>
36 // Copyright (C) 2015 André Esser <bepandre@hotmail.com>
37 // Copyright (C) 2016, 2020 Jakub Alba <jakubalba@gmail.com>
38 // Copyright (C) 2017 Jean Ghali <jghali@libertysurf.fr>
39 // Copyright (C) 2017 Fredrik Fornwall <fredrik@fornwall.net>
40 // Copyright (C) 2018 Ben Timby <btimby@gmail.com>
41 // Copyright (C) 2018 Evangelos Foutras <evangelos@foutrelis.com>
42 // Copyright (C) 2018 Klarälvdalens Datakonsult AB, a KDAB Group company, <info@kdab.com>. Work sponsored by the LiMux project of the city of Munich
43 // Copyright (C) 2018 Evangelos Rigas <erigas@rnd2.org>
44 // Copyright (C) 2018 Philipp Knechtges <philipp-dev@knechtges.com>
45 // Copyright (C) 2019 Christian Persch <chpe@src.gnome.org>
46 // Copyright (C) 2020 Nelson Benítez León <nbenitezl@gmail.com>
47 // Copyright (C) 2020 Thorsten Behrens <Thorsten.Behrens@CIB.de>
48 // Copyright (C) 2020 Adam Sampson <ats@offog.org>
49 // Copyright (C) 2021 Oliver Sander <oliver.sander@tu-dresden.de>
50 //
51 // To see a description of the changes please see the Changelog file that
52 // came with your tarball or type make ChangeLog if you are building from git
53 //
54 //========================================================================
55 
56 #include <config.h>
57 #include <poppler-config.h>
58 
59 #include <cctype>
60 #include <clocale>
61 #include <cstdio>
62 #include <cerrno>
63 #include <climits>
64 #include <cstdlib>
65 #include <cstddef>
66 #include <cstring>
67 #include <ctime>
68 #include <regex>
69 #include <sys/stat.h>
70 #include "goo/glibc.h"
71 #include "goo/gstrtod.h"
72 #include "goo/GooString.h"
73 #include "goo/gfile.h"
74 #include "poppler-config.h"
75 #include "GlobalParams.h"
76 #include "Page.h"
77 #include "Catalog.h"
78 #include "Stream.h"
79 #include "XRef.h"
80 #include "Linearization.h"
81 #include "Link.h"
82 #include "OutputDev.h"
83 #include "Error.h"
84 #include "ErrorCodes.h"
85 #include "Lexer.h"
86 #include "Parser.h"
87 #include "SecurityHandler.h"
88 #include "Decrypt.h"
89 #include "Outline.h"
90 #include "PDFDoc.h"
91 #include "Hints.h"
92 #include "UTF.h"
93 #include "JSInfo.h"
94 
95 //------------------------------------------------------------------------
96 
97 #define headerSearchSize \
98  1024 // read this many bytes at beginning of
99  // file to look for '%PDF'
100 #define pdfIdLength 32 // PDF Document IDs (PermanentId, UpdateId) length
101 
102 #define linearizationSearchSize \
103  1024 // read this many bytes at beginning of
104  // file to look for linearization
105  // dictionary
106 
107 #define xrefSearchSize \
108  1024 // read this many bytes at end of file
109  // to look for 'startxref'
110 
111 //------------------------------------------------------------------------
112 // PDFDoc
113 //------------------------------------------------------------------------
114 
115 #define pdfdocLocker() std::unique_lock<std::recursive_mutex> locker(mutex)
116 
118 {
119  ok = false;
120  errCode = errNone;
121  fileName = nullptr;
122  file = nullptr;
123  str = nullptr;
124  xref = nullptr;
125  linearization = nullptr;
126  catalog = nullptr;
127  hints = nullptr;
128  outline = nullptr;
129  startXRefPos = -1;
130  secHdlr = nullptr;
131  pageCache = nullptr;
132 }
133 
135 {
136  init();
137 }
138 
139 PDFDoc::PDFDoc(const GooString *fileNameA, const GooString *ownerPassword, const GooString *userPassword, void *guiDataA)
140 {
141 #ifdef _WIN32
142  int n, i;
143 #endif
144 
145  init();
146 
147  fileName = fileNameA;
148  guiData = guiDataA;
149 #ifdef _WIN32
150  n = fileName->getLength();
151  fileNameU = (wchar_t *)gmallocn(n + 1, sizeof(wchar_t));
152  for (i = 0; i < n; ++i) {
153  fileNameU[i] = (wchar_t)(fileName->getChar(i) & 0xff);
154  }
155  fileNameU[n] = L'\0';
156 #endif
157 
158  // try to open file
159 #ifdef _WIN32
160  wchar_t *wFileName = (wchar_t *)utf8ToUtf16(fileName->c_str());
161  file = GooFile::open(wFileName);
162  gfree(wFileName);
163 #else
165 #endif
166  if (file == nullptr) {
167  // fopen() has failed.
168  // Keep a copy of the errno returned by fopen so that it can be
169  // referred to later.
170  fopenErrno = errno;
171  error(errIO, -1, "Couldn't open file '{0:t}': {1:s}.", fileName, strerror(errno));
173  return;
174  }
175 
176  // create stream
177  str = new FileStream(file, 0, false, file->size(), Object(objNull));
178 
180 }
181 
182 #ifdef _WIN32
183 PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GooString *ownerPassword, GooString *userPassword, void *guiDataA)
184 {
185  OSVERSIONINFO version;
186  int i;
187 
188  init();
189 
190  guiData = guiDataA;
191 
192  // save both Unicode and 8-bit copies of the file name
193  GooString *fileNameG = new GooString();
194  fileNameU = (wchar_t *)gmallocn(fileNameLen + 1, sizeof(wchar_t));
195  for (i = 0; i < fileNameLen; ++i) {
196  fileNameG->append((char)fileNameA[i]);
197  fileNameU[i] = fileNameA[i];
198  }
199  fileName = fileNameG;
200  fileNameU[fileNameLen] = L'\0';
201 
202  // try to open file
203  // NB: _wfopen is only available in NT
204  version.dwOSVersionInfoSize = sizeof(version);
205  GetVersionEx(&version);
206  if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) {
207  file = GooFile::open(fileNameU);
208  } else {
210  }
211  if (!file) {
212  error(errIO, -1, "Couldn't open file '{0:t}'", fileName);
214  return;
215  }
216 
217  // create stream
218  str = new FileStream(file, 0, false, file->size(), Object(objNull));
219 
221 }
222 #endif
223 
225 {
226 #ifdef _WIN32
227  int n, i;
228 #endif
229 
230  init();
231  guiData = guiDataA;
232  if (strA->getFileName()) {
233  fileName = strA->getFileName()->copy();
234 #ifdef _WIN32
235  n = fileName->getLength();
236  fileNameU = (wchar_t *)gmallocn(n + 1, sizeof(wchar_t));
237  for (i = 0; i < n; ++i) {
238  fileNameU[i] = (wchar_t)(fileName->getChar(i) & 0xff);
239  }
240  fileNameU[n] = L'\0';
241 #endif
242  } else {
243  fileName = nullptr;
244 #ifdef _WIN32
245  fileNameU = NULL;
246 #endif
247  }
248  str = strA;
250 }
251 
253 {
254  pdfdocLocker();
255 
256  if (str->getLength() <= 0) {
257  error(errSyntaxError, -1, "Document stream is empty");
259  return false;
260  }
261 
262  str->setPos(0, -1);
263  if (str->getPos() < 0) {
264  error(errSyntaxError, -1, "Document base stream is not seekable");
265  errCode = errFileIO;
266  return false;
267  }
268 
269  str->reset();
270 
271  // check footer
272  // Adobe does not seem to enforce %%EOF, so we do the same
273  // if (!checkFooter()) return false;
274 
275  // check header
276  checkHeader();
277 
278  bool wasReconstructed = false;
279 
280  // read xref table
281  xref = new XRef(str, getStartXRef(), getMainXRefEntriesOffset(), &wasReconstructed);
282  if (!xref->isOk()) {
283  if (wasReconstructed) {
284  delete xref;
285  startXRefPos = -1;
286  xref = new XRef(str, getStartXRef(true), getMainXRefEntriesOffset(true), &wasReconstructed);
287  }
288  if (!xref->isOk()) {
289  error(errSyntaxError, -1, "Couldn't read xref table");
291  return false;
292  }
293  }
294 
295  // check for encryption
298  return false;
299  }
300 
301  // read catalog
302  catalog = new Catalog(this);
303  if (catalog && !catalog->isOk()) {
304  if (!wasReconstructed) {
305  // try one more time to construct the Catalog, maybe the problem is damaged XRef
306  delete catalog;
307  delete xref;
308  xref = new XRef(str, 0, 0, nullptr, true);
309  catalog = new Catalog(this);
310  }
311 
312  if (catalog && !catalog->isOk()) {
313  error(errSyntaxError, -1, "Couldn't read page catalog");
315  return false;
316  }
317  }
318 
319  // Extract PDF Subtype information
321 
322  // done
323  return true;
324 }
325 
327 {
328  if (pageCache) {
329  for (int i = 0; i < getNumPages(); i++) {
330  if (pageCache[i]) {
331  delete pageCache[i];
332  }
333  }
334  gfree(pageCache);
335  }
336  delete secHdlr;
337  if (outline) {
338  delete outline;
339  }
340  if (catalog) {
341  delete catalog;
342  }
343  if (xref) {
344  delete xref;
345  }
346  if (hints) {
347  delete hints;
348  }
349  if (linearization) {
350  delete linearization;
351  }
352  if (str) {
353  delete str;
354  }
355  if (file) {
356  delete file;
357  }
358  if (fileName) {
359  delete fileName;
360  }
361 #ifdef _WIN32
362  if (fileNameU) {
363  gfree(fileNameU);
364  }
365 #endif
366 }
367 
368 // Check for a %%EOF at the end of this stream
370 {
371  // we look in the last 1024 chars because Adobe does the same
372  char *eof = new char[1025];
373  Goffset pos = str->getPos();
374  str->setPos(1024, -1);
375  int i, ch;
376  for (i = 0; i < 1024; i++) {
377  ch = str->getChar();
378  if (ch == EOF)
379  break;
380  eof[i] = ch;
381  }
382  eof[i] = '\0';
383 
384  bool found = false;
385  for (i = i - 5; i >= 0; i--) {
386  if (strncmp(&eof[i], "%%EOF", 5) == 0) {
387  found = true;
388  break;
389  }
390  }
391  if (!found) {
392  error(errSyntaxError, -1, "Document has not the mandatory ending %%EOF");
394  delete[] eof;
395  return false;
396  }
397  delete[] eof;
398  str->setPos(pos);
399  return true;
400 }
401 
402 // Check for a PDF header on this stream. Skip past some garbage
403 // if necessary.
404 void PDFDoc::checkHeader()
405 {
406  char hdrBuf[headerSearchSize + 1];
407  char *p;
408  char *tokptr;
409  int i;
410  int bytesRead;
411 
412  pdfMajorVersion = 0;
413  pdfMinorVersion = 0;
414 
415  // read up to headerSearchSize bytes from the beginning of the document
416  for (i = 0; i < headerSearchSize; ++i) {
417  const int c = str->getChar();
418  if (c == EOF)
419  break;
420  hdrBuf[i] = c;
421  }
422  bytesRead = i;
423  hdrBuf[bytesRead] = '\0';
424 
425  // find the start of the PDF header if it exists and parse the version
426  bool headerFound = false;
427  for (i = 0; i < bytesRead - 5; ++i) {
428  if (!strncmp(&hdrBuf[i], "%PDF-", 5)) {
429  headerFound = true;
430  break;
431  }
432  }
433  if (!headerFound) {
434  error(errSyntaxWarning, -1, "May not be a PDF file (continuing anyway)");
435  return;
436  }
437  str->moveStart(i);
438  if (!(p = strtok_r(&hdrBuf[i + 5], " \t\n\r", &tokptr))) {
439  error(errSyntaxWarning, -1, "May not be a PDF file (continuing anyway)");
440  return;
441  }
442  sscanf(p, "%d.%d", &pdfMajorVersion, &pdfMinorVersion);
443  // We don't do the version check. Don't add it back in.
444 }
445 
447 {
448  bool encrypted;
449  bool ret;
450 
451  Object encrypt = xref->getTrailerDict()->dictLookup("Encrypt");
452  if ((encrypted = encrypt.isDict())) {
453  if ((secHdlr = SecurityHandler::make(this, &encrypt))) {
454  if (secHdlr->isUnencrypted()) {
455  // no encryption
456  ret = true;
458  // authorization succeeded
460  ret = true;
461  } else {
462  // authorization failed
463  ret = false;
464  }
465  } else {
466  // couldn't find the matching security handler
467  ret = false;
468  }
469  } else {
470  // document is not encrypted
471  ret = true;
472  }
473  return ret;
474 }
475 
477 {
478  const std::regex regex("PDF/(?:A|X|VT|E|UA)-([[:digit:]])(?:[[:alpha:]]{1,2})?:?([[:digit:]]{4})?");
479  std::smatch match;
480  const std::string &pdfsubver = pdfSubtypeVersion->toStr();
481  PDFSubtypePart subtypePart = subtypePartNone;
482 
483  if (std::regex_search(pdfsubver, match, regex)) {
484  int date = 0;
485  const int part = std::stoi(match.str(1));
486 
487  if (match[2].matched) {
488  date = std::stoi(match.str(2));
489  }
490 
491  switch (subtype) {
492  case subtypePDFX:
493  switch (part) {
494  case 1:
495  switch (date) {
496  case 2001:
497  default:
498  subtypePart = subtypePart1;
499  break;
500  case 2003:
501  subtypePart = subtypePart4;
502  break;
503  }
504  break;
505  case 2:
506  subtypePart = subtypePart5;
507  break;
508  case 3:
509  switch (date) {
510  case 2002:
511  default:
512  subtypePart = subtypePart3;
513  break;
514  case 2003:
515  subtypePart = subtypePart6;
516  break;
517  }
518  break;
519  case 4:
520  subtypePart = subtypePart7;
521  break;
522  case 5:
523  subtypePart = subtypePart8;
524  break;
525  }
526  break;
527  default:
528  subtypePart = (PDFSubtypePart)part;
529  break;
530  }
531  }
532 
533  return subtypePart;
534 }
535 
537 {
538  const std::regex regex("PDF/(?:A|X|VT|E|UA)-[[:digit:]]([[:alpha:]]+)");
539  std::smatch match;
540  const std::string &pdfsubver = pdfSubtypeVersion->toStr();
542 
543  // match contains the PDF conformance (A, B, G, N, P, PG or U)
544  if (std::regex_search(pdfsubver, match, regex)) {
545  GooString *conf = new GooString(match.str(1));
546  // Convert to lowercase as the conformance may appear in both cases
547  conf->lowerCase();
548  if (conf->cmp("a") == 0) {
549  pdfConf = subtypeConfA;
550  } else if (conf->cmp("b") == 0) {
551  pdfConf = subtypeConfB;
552  } else if (conf->cmp("g") == 0) {
553  pdfConf = subtypeConfG;
554  } else if (conf->cmp("n") == 0) {
555  pdfConf = subtypeConfN;
556  } else if (conf->cmp("p") == 0) {
557  pdfConf = subtypeConfP;
558  } else if (conf->cmp("pg") == 0) {
559  pdfConf = subtypeConfPG;
560  } else if (conf->cmp("u") == 0) {
561  pdfConf = subtypeConfU;
562  } else {
563  pdfConf = subtypeConfNone;
564  }
565  delete conf;
566  }
567 
568  return pdfConf;
569 }
570 
572 {
576 
577  GooString *pdfSubtypeVersion = nullptr;
578  // Find PDF InfoDict subtype key if any
579  if ((pdfSubtypeVersion = getDocInfoStringEntry("GTS_PDFA1Version"))) {
581  } else if ((pdfSubtypeVersion = getDocInfoStringEntry("GTS_PDFEVersion"))) {
583  } else if ((pdfSubtypeVersion = getDocInfoStringEntry("GTS_PDFUAVersion"))) {
585  } else if ((pdfSubtypeVersion = getDocInfoStringEntry("GTS_PDFVTVersion"))) {
587  } else if ((pdfSubtypeVersion = getDocInfoStringEntry("GTS_PDFXVersion"))) {
589  } else {
593  return;
594  }
595 
596  // Extract part from version string
597  pdfPart = pdfPartFromString(pdfSubtype, pdfSubtypeVersion);
598 
599  // Extract conformance from version string
600  pdfConformance = pdfConformanceFromString(pdfSubtypeVersion);
601 
602  delete pdfSubtypeVersion;
603 }
604 
605 static void addSignatureFieldsToVector(FormField *ff, std::vector<FormFieldSignature *> &res)
606 {
607  if (ff->getNumChildren() == 0) {
608  if (ff->getType() == formSignature) {
609  res.push_back(static_cast<FormFieldSignature *>(ff));
610  }
611  } else {
612  for (int i = 0; i < ff->getNumChildren(); ++i) {
615  }
616  }
617 }
618 
619 std::vector<FormFieldSignature *> PDFDoc::getSignatureFields()
620 {
621  std::vector<FormFieldSignature *> res;
622 
623  const Form *f = catalog->getForm();
624  if (!f)
625  return res;
626 
627  const int nRootFields = f->getNumFields();
628  for (int i = 0; i < nRootFields; ++i) {
629  FormField *ff = f->getRootField(i);
631  }
632  return res;
633 }
634 
635 void PDFDoc::displayPage(OutputDev *out, int page, double hDPI, double vDPI, int rotate, bool useMediaBox, bool crop, bool printing, bool (*abortCheckCbk)(void *data), void *abortCheckCbkData,
636  bool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), void *annotDisplayDecideCbkData, bool copyXRef)
637 {
639  printf("***** page %d *****\n", page);
640  }
641 
642  if (getPage(page))
643  getPage(page)->display(out, hDPI, vDPI, rotate, useMediaBox, crop, printing, abortCheckCbk, abortCheckCbkData, annotDisplayDecideCbk, annotDisplayDecideCbkData, copyXRef);
644 }
645 
646 void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage, double hDPI, double vDPI, int rotate, bool useMediaBox, bool crop, bool printing, bool (*abortCheckCbk)(void *data), void *abortCheckCbkData,
647  bool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), void *annotDisplayDecideCbkData)
648 {
649  int page;
650 
651  for (page = firstPage; page <= lastPage; ++page) {
652  displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, printing, abortCheckCbk, abortCheckCbkData, annotDisplayDecideCbk, annotDisplayDecideCbkData);
653  }
654 }
655 
656 void PDFDoc::displayPageSlice(OutputDev *out, int page, double hDPI, double vDPI, int rotate, bool useMediaBox, bool crop, bool printing, int sliceX, int sliceY, int sliceW, int sliceH, bool (*abortCheckCbk)(void *data),
657  void *abortCheckCbkData, bool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), void *annotDisplayDecideCbkData, bool copyXRef)
658 {
659  if (getPage(page))
660  getPage(page)->displaySlice(out, hDPI, vDPI, rotate, useMediaBox, crop, sliceX, sliceY, sliceW, sliceH, printing, abortCheckCbk, abortCheckCbkData, annotDisplayDecideCbk, annotDisplayDecideCbkData, copyXRef);
661 }
662 
664 {
665  Page *p = getPage(page);
666  if (!p) {
667  return new Links(nullptr);
668  }
669  return p->getLinks();
670 }
671 
673 {
674  if (getPage(page))
676 }
677 
679 {
680  if (!linearization) {
682  linearizationState = 0;
683  }
684  return linearization;
685 }
686 
688 {
689  if (linearization == nullptr)
690  return false;
691  if (linearizationState == 1)
692  return true;
693  if (linearizationState == 2)
694  return false;
695  if (!hints) {
697  }
698  if (!hints->isOk()) {
699  linearizationState = 2;
700  return false;
701  }
702  for (int page = 1; page <= linearization->getNumPages(); page++) {
703  Ref pageRef;
704 
705  pageRef.num = hints->getPageObjectNum(page);
706  if (!pageRef.num) {
707  linearizationState = 2;
708  return false;
709  }
710 
711  // check for bogus ref - this can happen in corrupted PDF files
712  if (pageRef.num < 0 || pageRef.num >= xref->getNumObjects()) {
713  linearizationState = 2;
714  return false;
715  }
716 
717  pageRef.gen = xref->getEntry(pageRef.num)->gen;
718  Object obj = xref->fetch(pageRef);
719  if (!obj.isDict("Page")) {
720  linearizationState = 2;
721  return false;
722  }
723  }
724  linearizationState = 1;
725  return true;
726 }
727 
728 bool PDFDoc::isLinearized(bool tryingToReconstruct)
729 {
730  if ((str->getLength()) && (getLinearization()->getLength() == str->getLength()))
731  return true;
732  else {
733  if (tryingToReconstruct)
734  return getLinearization()->getLength() > 0;
735  else
736  return false;
737  }
738 }
739 
741 {
742  bool removeEntry = !value || value->getLength() == 0 || value->hasJustUnicodeMarker();
743  if (removeEntry) {
744  delete value;
745  }
746 
747  Object infoObj = getDocInfo();
748  if (infoObj.isNull() && removeEntry) {
749  // No info dictionary, so no entry to remove.
750  return;
751  }
752 
753  Ref infoObjRef;
754  infoObj = xref->createDocInfoIfNeeded(&infoObjRef);
755  if (removeEntry) {
756  infoObj.dictSet(key, Object(objNull));
757  } else {
758  infoObj.dictSet(key, Object(value));
759  }
760 
761  if (infoObj.dictGetLength() == 0) {
762  // Info dictionary is empty. Remove it altogether.
763  removeDocInfo();
764  } else {
765  xref->setModifiedObject(&infoObj, infoObjRef);
766  }
767 }
768 
770 {
771  Object infoObj = getDocInfo();
772  if (!infoObj.isDict()) {
773  return nullptr;
774  }
775 
776  Object entryObj = infoObj.dictLookup(key);
777 
778  GooString *result;
779 
780  if (entryObj.isString()) {
781  result = entryObj.takeString();
782  } else {
783  result = nullptr;
784  }
785 
786  return result;
787 }
788 
789 static bool get_id(const GooString *encodedidstring, GooString *id)
790 {
791  const char *encodedid = encodedidstring->c_str();
792  char pdfid[pdfIdLength + 1];
793  int n;
794 
795  if (encodedidstring->getLength() != pdfIdLength / 2)
796  return false;
797 
798  n = sprintf(pdfid, "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", encodedid[0] & 0xff, encodedid[1] & 0xff, encodedid[2] & 0xff, encodedid[3] & 0xff, encodedid[4] & 0xff, encodedid[5] & 0xff, encodedid[6] & 0xff,
799  encodedid[7] & 0xff, encodedid[8] & 0xff, encodedid[9] & 0xff, encodedid[10] & 0xff, encodedid[11] & 0xff, encodedid[12] & 0xff, encodedid[13] & 0xff, encodedid[14] & 0xff, encodedid[15] & 0xff);
800  if (n != pdfIdLength)
801  return false;
802 
803  id->Set(pdfid, pdfIdLength);
804  return true;
805 }
806 
807 bool PDFDoc::getID(GooString *permanent_id, GooString *update_id) const
808 {
809  Object obj = xref->getTrailerDict()->dictLookup("ID");
810 
811  if (obj.isArray() && obj.arrayGetLength() == 2) {
812  if (permanent_id) {
813  Object obj2 = obj.arrayGet(0);
814  if (obj2.isString()) {
815  if (!get_id(obj2.getString(), permanent_id)) {
816  return false;
817  }
818  } else {
819  error(errSyntaxError, -1, "Invalid permanent ID");
820  return false;
821  }
822  }
823 
824  if (update_id) {
825  Object obj2 = obj.arrayGet(1);
826  if (obj2.isString()) {
827  if (!get_id(obj2.getString(), update_id)) {
828  return false;
829  }
830  } else {
831  error(errSyntaxError, -1, "Invalid update ID");
832  return false;
833  }
834  }
835 
836  return true;
837  }
838 
839  return false;
840 }
841 
843 {
844  if (!hints && isLinearized()) {
846  }
847 
848  return hints;
849 }
850 
851 int PDFDoc::savePageAs(const GooString *name, int pageNo)
852 {
853  FILE *f;
854  OutStream *outStr;
855  XRef *yRef, *countRef;
856 
857  if (file && file->modificationTimeChangedSinceOpen())
859 
860  int rootNum = getXRef()->getNumObjects() + 1;
861 
862  // Make sure that special flags are set, because we are going to read
863  // all objects, including Unencrypted ones.
865 
866  unsigned char *fileKey;
867  CryptAlgorithm encAlgorithm;
868  int keyLength;
869  xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength);
870 
871  if (pageNo < 1 || pageNo > getNumPages() || !getCatalog()->getPage(pageNo)) {
872  error(errInternal, -1, "Illegal pageNo: {0:d}({1:d})", pageNo, getNumPages());
873  return errOpenFile;
874  }
875  const PDFRectangle *cropBox = nullptr;
876  if (getCatalog()->getPage(pageNo)->isCropped()) {
877  cropBox = getCatalog()->getPage(pageNo)->getCropBox();
878  }
879  replacePageDict(pageNo, getCatalog()->getPage(pageNo)->getRotate(), getCatalog()->getPage(pageNo)->getMediaBox(), cropBox);
880  Ref *refPage = getCatalog()->getPageRef(pageNo);
881  Object page = getXRef()->fetch(*refPage);
882 
883  if (!(f = openFile(name->c_str(), "wb"))) {
884  error(errIO, -1, "Couldn't open file '{0:t}'", name);
885  return errOpenFile;
886  }
887  outStr = new FileOutStream(f, 0);
888 
889  yRef = new XRef(getXRef()->getTrailerDict());
890 
891  if (secHdlr != nullptr && !secHdlr->isUnencrypted()) {
892  yRef->setEncryption(secHdlr->getPermissionFlags(), secHdlr->getOwnerPasswordOk(), fileKey, keyLength, secHdlr->getEncVersion(), secHdlr->getEncRevision(), encAlgorithm);
893  }
894  countRef = new XRef();
895  Object *trailerObj = getXRef()->getTrailerDict();
896  if (trailerObj->isDict()) {
897  markPageObjects(trailerObj->getDict(), yRef, countRef, 0, refPage->num, rootNum + 2);
898  }
899  yRef->add(0, 65535, 0, false);
901 
902  // get and mark info dict
903  Object infoObj = getXRef()->getDocInfo();
904  if (infoObj.isDict()) {
905  Dict *infoDict = infoObj.getDict();
906  markPageObjects(infoDict, yRef, countRef, 0, refPage->num, rootNum + 2);
907  if (trailerObj->isDict()) {
908  Dict *trailerDict = trailerObj->getDict();
909  const Object &ref = trailerDict->lookupNF("Info");
910  if (ref.isRef()) {
911  yRef->add(ref.getRef(), 0, true);
912  if (getXRef()->getEntry(ref.getRef().num)->type == xrefEntryCompressed) {
913  yRef->getEntry(ref.getRef().num)->type = xrefEntryCompressed;
914  }
915  }
916  }
917  }
918 
919  // get and mark output intents etc.
920  Object catObj = getXRef()->getCatalog();
921  Dict *catDict = catObj.getDict();
922  Object pagesObj = catDict->lookup("Pages");
923  Object afObj = catDict->lookupNF("AcroForm").copy();
924  if (!afObj.isNull()) {
925  markAcroForm(&afObj, yRef, countRef, 0, refPage->num, rootNum + 2);
926  }
927  Dict *pagesDict = pagesObj.getDict();
928  Object resourcesObj = pagesDict->lookup("Resources");
929  if (resourcesObj.isDict())
930  markPageObjects(resourcesObj.getDict(), yRef, countRef, 0, refPage->num, rootNum + 2);
931  markPageObjects(catDict, yRef, countRef, 0, refPage->num, rootNum + 2);
932 
933  Dict *pageDict = page.getDict();
934  if (resourcesObj.isNull() && !pageDict->hasKey("Resources")) {
935  Object *resourceDictObject = getCatalog()->getPage(pageNo)->getResourceDictObject();
936  if (resourceDictObject->isDict()) {
937  resourcesObj = resourceDictObject->copy();
938  markPageObjects(resourcesObj.getDict(), yRef, countRef, 0, refPage->num, rootNum + 2);
939  }
940  }
941  markPageObjects(pageDict, yRef, countRef, 0, refPage->num, rootNum + 2);
942  Object annotsObj = pageDict->lookupNF("Annots").copy();
943  if (!annotsObj.isNull()) {
944  markAnnotations(&annotsObj, yRef, countRef, 0, refPage->num, rootNum + 2);
945  }
946  yRef->markUnencrypted();
947  writePageObjects(outStr, yRef, 0);
948 
949  yRef->add(rootNum, 0, outStr->getPos(), true);
950  outStr->printf("%d 0 obj\n", rootNum);
951  outStr->printf("<< /Type /Catalog /Pages %d 0 R", rootNum + 1);
952  for (int j = 0; j < catDict->getLength(); j++) {
953  const char *key = catDict->getKey(j);
954  if (strcmp(key, "Type") != 0 && strcmp(key, "Catalog") != 0 && strcmp(key, "Pages") != 0) {
955  if (j > 0)
956  outStr->printf(" ");
957  Object value = catDict->getValNF(j).copy();
958  outStr->printf("/%s ", key);
959  writeObject(&value, outStr, getXRef(), 0, nullptr, cryptRC4, 0, 0, 0);
960  }
961  }
962  outStr->printf(">>\nendobj\n");
963 
964  yRef->add(rootNum + 1, 0, outStr->getPos(), true);
965  outStr->printf("%d 0 obj\n", rootNum + 1);
966  outStr->printf("<< /Type /Pages /Kids [ %d 0 R ] /Count 1 ", rootNum + 2);
967  if (resourcesObj.isDict()) {
968  outStr->printf("/Resources ");
969  writeObject(&resourcesObj, outStr, getXRef(), 0, nullptr, cryptRC4, 0, 0, 0);
970  }
971  outStr->printf(">>\n");
972  outStr->printf("endobj\n");
973 
974  yRef->add(rootNum + 2, 0, outStr->getPos(), true);
975  outStr->printf("%d 0 obj\n", rootNum + 2);
976  outStr->printf("<< ");
977  for (int n = 0; n < pageDict->getLength(); n++) {
978  if (n > 0)
979  outStr->printf(" ");
980  const char *key = pageDict->getKey(n);
981  Object value = pageDict->getValNF(n).copy();
982  if (strcmp(key, "Parent") == 0) {
983  outStr->printf("/Parent %d 0 R", rootNum + 1);
984  } else {
985  outStr->printf("/%s ", key);
986  writeObject(&value, outStr, getXRef(), 0, nullptr, cryptRC4, 0, 0, 0);
987  }
988  }
989  outStr->printf(" >>\nendobj\n");
990 
991  Goffset uxrefOffset = outStr->getPos();
992  Ref ref;
993  ref.num = rootNum;
994  ref.gen = 0;
995  Object trailerDict = createTrailerDict(rootNum + 3, false, 0, &ref, getXRef(), name->c_str(), uxrefOffset);
996  writeXRefTableTrailer(std::move(trailerDict), yRef, false /* do not write unnecessary entries */, uxrefOffset, outStr, getXRef());
997 
998  outStr->close();
999  fclose(f);
1000  delete yRef;
1001  delete countRef;
1002  delete outStr;
1003 
1004  return errNone;
1005 }
1006 
1008 {
1009  FILE *f;
1010  OutStream *outStr;
1011  int res;
1012 
1013  if (!(f = openFile(name->c_str(), "wb"))) {
1014  error(errIO, -1, "Couldn't open file '{0:t}'", name);
1015  return errOpenFile;
1016  }
1017  outStr = new FileOutStream(f, 0);
1018  res = saveAs(outStr, mode);
1019  delete outStr;
1020  fclose(f);
1021  return res;
1022 }
1023 
1025 {
1026  if (file && file->modificationTimeChangedSinceOpen())
1027  return errFileChangedSinceOpen;
1028 
1029  if (!xref->isModified() && mode == writeStandard) {
1030  // simply copy the original file
1031  saveWithoutChangesAs(outStr);
1032  } else if (mode == writeForceRewrite) {
1033  saveCompleteRewrite(outStr);
1034  } else {
1035  saveIncrementalUpdate(outStr);
1036  }
1037 
1038  return errNone;
1039 }
1040 
1042 {
1043  FILE *f;
1044  OutStream *outStr;
1045  int res;
1046 
1047  if (!(f = openFile(name->c_str(), "wb"))) {
1048  error(errIO, -1, "Couldn't open file '{0:t}'", name);
1049  return errOpenFile;
1050  }
1051 
1052  outStr = new FileOutStream(f, 0);
1053  res = saveWithoutChangesAs(outStr);
1054  delete outStr;
1055 
1056  fclose(f);
1057 
1058  return res;
1059 }
1060 
1062 {
1063  int c;
1064 
1065  if (file && file->modificationTimeChangedSinceOpen())
1066  return errFileChangedSinceOpen;
1067 
1068  BaseStream *copyStr = str->copy();
1069  copyStr->reset();
1070  while ((c = copyStr->getChar()) != EOF) {
1071  outStr->put(c);
1072  }
1073  copyStr->close();
1074  delete copyStr;
1075 
1076  return errNone;
1077 }
1078 
1080 {
1081  XRef *uxref;
1082  int c;
1083  // copy the original file
1084  BaseStream *copyStr = str->copy();
1085  copyStr->reset();
1086  while ((c = copyStr->getChar()) != EOF) {
1087  outStr->put(c);
1088  }
1089  copyStr->close();
1090  delete copyStr;
1091 
1092  unsigned char *fileKey;
1093  CryptAlgorithm encAlgorithm;
1094  int keyLength;
1095  xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength);
1096 
1097  uxref = new XRef();
1098  uxref->add(0, 65535, 0, false);
1099  xref->lock();
1100  for (int i = 0; i < xref->getNumObjects(); i++) {
1101  if ((xref->getEntry(i)->type == xrefEntryFree) && (xref->getEntry(i)->gen == 0)) // we skip the irrelevant free objects
1102  continue;
1103 
1104  if (xref->getEntry(i)->getFlag(XRefEntry::Updated)) { // we have an updated object
1105  Ref ref;
1106  ref.num = i;
1107  ref.gen = xref->getEntry(i)->type == xrefEntryCompressed ? 0 : xref->getEntry(i)->gen;
1108  if (xref->getEntry(i)->type != xrefEntryFree) {
1109  Object obj1 = xref->fetch(ref, 1 /* recursion */);
1110  Goffset offset = writeObjectHeader(&ref, outStr);
1111  writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref);
1112  writeObjectFooter(outStr);
1113  uxref->add(ref, offset, true);
1114  } else {
1115  uxref->add(ref, 0, false);
1116  }
1117  }
1118  }
1119  xref->unlock();
1120  // because of "uxref->add(0, 65535, 0, false);" uxref->getNumObjects() will
1121  // always be >= 1; if it is 1, it means there is nothing to update
1122  if (uxref->getNumObjects() == 1) {
1123  delete uxref;
1124  return;
1125  }
1126 
1127  Goffset uxrefOffset = outStr->getPos();
1128  int numobjects = xref->getNumObjects();
1129  const char *fileNameA = fileName ? fileName->c_str() : nullptr;
1130  Ref rootRef, uxrefStreamRef;
1131  rootRef.num = getXRef()->getRootNum();
1132  rootRef.gen = getXRef()->getRootGen();
1133 
1134  // Output a xref stream if there is a xref stream already
1135  bool xRefStream = xref->isXRefStream();
1136 
1137  if (xRefStream) {
1138  // Append an entry for the xref stream itself
1139  uxrefStreamRef.num = numobjects++;
1140  uxrefStreamRef.gen = 0;
1141  uxref->add(uxrefStreamRef, uxrefOffset, true);
1142  }
1143 
1144  Object trailerDict = createTrailerDict(numobjects, true, getStartXRef(), &rootRef, getXRef(), fileNameA, uxrefOffset);
1145  if (xRefStream) {
1146  writeXRefStreamTrailer(std::move(trailerDict), uxref, &uxrefStreamRef, uxrefOffset, outStr, getXRef());
1147  } else {
1148  writeXRefTableTrailer(std::move(trailerDict), uxref, false, uxrefOffset, outStr, getXRef());
1149  }
1150 
1151  delete uxref;
1152 }
1153 
1155 {
1156  // Make sure that special flags are set, because we are going to read
1157  // all objects, including Unencrypted ones.
1159 
1160  unsigned char *fileKey;
1161  CryptAlgorithm encAlgorithm;
1162  int keyLength;
1163  xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength);
1164 
1166  XRef *uxref = new XRef();
1167  uxref->add(0, 65535, 0, false);
1168  xref->lock();
1169  for (int i = 0; i < xref->getNumObjects(); i++) {
1170  Ref ref;
1172  if (type == xrefEntryFree) {
1173  ref.num = i;
1174  ref.gen = xref->getEntry(i)->gen;
1175  /* the XRef class adds a lot of irrelevant free entries, we only want the significant one
1176  and we don't want the one with num=0 because it has already been added (gen = 65535)*/
1177  if (ref.gen > 0 && ref.num > 0)
1178  uxref->add(ref, 0, false);
1179  } else if (xref->getEntry(i)->getFlag(XRefEntry::DontRewrite)) {
1180  // This entry must not be written, put a free entry instead (with incremented gen)
1181  ref.num = i;
1182  ref.gen = xref->getEntry(i)->gen + 1;
1183  uxref->add(ref, 0, false);
1184  } else if (type == xrefEntryUncompressed) {
1185  ref.num = i;
1186  ref.gen = xref->getEntry(i)->gen;
1187  Object obj1 = xref->fetch(ref, 1 /* recursion */);
1188  Goffset offset = writeObjectHeader(&ref, outStr);
1189  // Write unencrypted objects in unencrypted form
1191  writeObject(&obj1, outStr, nullptr, cryptRC4, 0, 0, 0);
1192  } else {
1193  writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref);
1194  }
1195  writeObjectFooter(outStr);
1196  uxref->add(ref, offset, true);
1197  } else if (type == xrefEntryCompressed) {
1198  ref.num = i;
1199  ref.gen = 0; // compressed entries have gen == 0
1200  Object obj1 = xref->fetch(ref, 1 /* recursion */);
1201  Goffset offset = writeObjectHeader(&ref, outStr);
1202  writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref);
1203  writeObjectFooter(outStr);
1204  uxref->add(ref, offset, true);
1205  }
1206  }
1207  xref->unlock();
1208  Goffset uxrefOffset = outStr->getPos();
1209  writeXRefTableTrailer(uxrefOffset, uxref, true /* write all entries */, uxref->getNumObjects(), outStr, false /* complete rewrite */);
1210  delete uxref;
1211 }
1212 
1213 void PDFDoc::writeDictionnary(Dict *dict, OutStream *outStr, XRef *xRef, unsigned int numOffset, unsigned char *fileKey, CryptAlgorithm encAlgorithm, int keyLength, Ref ref, std::set<Dict *> *alreadyWrittenDicts)
1214 {
1215  bool deleteSet = false;
1216  if (!alreadyWrittenDicts) {
1217  alreadyWrittenDicts = new std::set<Dict *>;
1218  deleteSet = true;
1219  }
1220 
1221  if (alreadyWrittenDicts->find(dict) != alreadyWrittenDicts->end()) {
1222  error(errSyntaxWarning, -1, "PDFDoc::writeDictionnary: Found recursive dicts");
1223  if (deleteSet)
1224  delete alreadyWrittenDicts;
1225  return;
1226  } else {
1227  alreadyWrittenDicts->insert(dict);
1228  }
1229 
1230  outStr->printf("<<");
1231  for (int i = 0; i < dict->getLength(); i++) {
1232  GooString keyName(dict->getKey(i));
1233  GooString *keyNameToPrint = keyName.sanitizedName(false /* non ps mode */);
1234  outStr->printf("/%s ", keyNameToPrint->c_str());
1235  delete keyNameToPrint;
1236  Object obj1 = dict->getValNF(i).copy();
1237  writeObject(&obj1, outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, ref, alreadyWrittenDicts);
1238  }
1239  outStr->printf(">> ");
1240 
1241  if (deleteSet) {
1242  delete alreadyWrittenDicts;
1243  }
1244 }
1245 
1247 {
1248  outStr->printf("stream\r\n");
1249  str->reset();
1250  for (int c = str->getChar(); c != EOF; c = str->getChar()) {
1251  outStr->printf("%c", c);
1252  }
1253  outStr->printf("\r\nendstream\r\n");
1254 }
1255 
1257 {
1258  Object obj1 = str->getDict()->lookup("Length");
1259  if (!obj1.isInt() && !obj1.isInt64()) {
1260  error(errSyntaxError, -1, "PDFDoc::writeRawStream, no Length in stream dict");
1261  return;
1262  }
1263 
1264  Goffset length;
1265  if (obj1.isInt())
1266  length = obj1.getInt();
1267  else
1268  length = obj1.getInt64();
1269 
1270  outStr->printf("stream\r\n");
1271  str->unfilteredReset();
1272  for (Goffset i = 0; i < length; i++) {
1273  int c = str->getUnfilteredChar();
1274  if (unlikely(c == EOF)) {
1275  error(errSyntaxError, -1, "PDFDoc::writeRawStream: EOF reading stream");
1276  break;
1277  }
1278  outStr->printf("%c", c);
1279  }
1280  str->reset();
1281  outStr->printf("\r\nendstream\r\n");
1282 }
1283 
1284 void PDFDoc::writeString(const GooString *s, OutStream *outStr, const unsigned char *fileKey, CryptAlgorithm encAlgorithm, int keyLength, Ref ref)
1285 {
1286  // Encrypt string if encryption is enabled
1287  GooString *sEnc = nullptr;
1288  if (fileKey) {
1289  EncryptStream *enc = new EncryptStream(new MemStream(s->c_str(), 0, s->getLength(), Object(objNull)), fileKey, encAlgorithm, keyLength, ref);
1290  sEnc = new GooString();
1291  int c;
1292  enc->reset();
1293  while ((c = enc->getChar()) != EOF) {
1294  sEnc->append((char)c);
1295  }
1296 
1297  delete enc;
1298  s = sEnc;
1299  }
1300 
1301  // Write data
1302  if (s->hasUnicodeMarker()) {
1303  // unicode string don't necessary end with \0
1304  const char *c = s->c_str();
1305  outStr->printf("(");
1306  for (int i = 0; i < s->getLength(); i++) {
1307  char unescaped = *(c + i) & 0x000000ff;
1308  // escape if needed
1309  if (unescaped == '(' || unescaped == ')' || unescaped == '\\')
1310  outStr->printf("%c", '\\');
1311  outStr->printf("%c", unescaped);
1312  }
1313  outStr->printf(") ");
1314  } else {
1315  const char *c = s->c_str();
1316  outStr->printf("(");
1317  for (int i = 0; i < s->getLength(); i++) {
1318  char unescaped = *(c + i) & 0x000000ff;
1319  // escape if needed
1320  if (unescaped == '\r')
1321  outStr->printf("\\r");
1322  else if (unescaped == '\n')
1323  outStr->printf("\\n");
1324  else {
1325  if (unescaped == '(' || unescaped == ')' || unescaped == '\\') {
1326  outStr->printf("%c", '\\');
1327  }
1328  outStr->printf("%c", unescaped);
1329  }
1330  }
1331  outStr->printf(") ");
1332  }
1333 
1334  delete sEnc;
1335 }
1336 
1338 {
1339  Goffset offset = outStr->getPos();
1340  outStr->printf("%i %i obj\r\n", ref->num, ref->gen);
1341  return offset;
1342 }
1343 
1344 void PDFDoc::writeObject(Object *obj, OutStream *outStr, XRef *xRef, unsigned int numOffset, unsigned char *fileKey, CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen, std::set<Dict *> *alreadyWrittenDicts)
1345 {
1346  writeObject(obj, outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, { objNum, objGen }, alreadyWrittenDicts);
1347 }
1348 
1349 void PDFDoc::writeObject(Object *obj, OutStream *outStr, XRef *xRef, unsigned int numOffset, unsigned char *fileKey, CryptAlgorithm encAlgorithm, int keyLength, Ref ref, std::set<Dict *> *alreadyWrittenDicts)
1350 {
1351  Array *array;
1352 
1353  switch (obj->getType()) {
1354  case objBool:
1355  outStr->printf("%s ", obj->getBool() ? "true" : "false");
1356  break;
1357  case objInt:
1358  outStr->printf("%i ", obj->getInt());
1359  break;
1360  case objInt64:
1361  outStr->printf("%lli ", obj->getInt64());
1362  break;
1363  case objReal: {
1364  GooString s;
1365  s.appendf("{0:.10g}", obj->getReal());
1366  outStr->printf("%s ", s.c_str());
1367  break;
1368  }
1369  case objString:
1370  writeString(obj->getString(), outStr, fileKey, encAlgorithm, keyLength, ref);
1371  break;
1372  case objHexString: {
1373  const GooString *s = obj->getHexString();
1374  outStr->printf("<");
1375  for (int i = 0; i < s->getLength(); i++) {
1376  outStr->printf("%02x", s->getChar(i) & 0xff);
1377  }
1378  outStr->printf("> ");
1379  break;
1380  }
1381  case objName: {
1382  GooString name(obj->getName());
1383  GooString *nameToPrint = name.sanitizedName(false /* non ps mode */);
1384  outStr->printf("/%s ", nameToPrint->c_str());
1385  delete nameToPrint;
1386  break;
1387  }
1388  case objNull:
1389  outStr->printf("null ");
1390  break;
1391  case objArray:
1392  array = obj->getArray();
1393  outStr->printf("[");
1394  for (int i = 0; i < array->getLength(); i++) {
1395  Object obj1 = array->getNF(i).copy();
1396  writeObject(&obj1, outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, ref);
1397  }
1398  outStr->printf("] ");
1399  break;
1400  case objDict:
1401  writeDictionnary(obj->getDict(), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, ref, alreadyWrittenDicts);
1402  break;
1403  case objStream: {
1404  // We can't modify stream with the current implementation (no write functions in Stream API)
1405  // => the only type of streams which that have been modified are internal streams (=strWeird)
1406  Stream *stream = obj->getStream();
1407  if (stream->getKind() == strWeird || stream->getKind() == strCrypt) {
1408  // we write the stream unencoded => TODO: write stream encoder
1409 
1410  // Encrypt stream
1411  EncryptStream *encStream = nullptr;
1412  bool removeFilter = true;
1413  if (stream->getKind() == strWeird && fileKey) {
1414  Object filter = stream->getDict()->lookup("Filter");
1415  if (!filter.isName("Crypt")) {
1416  if (filter.isArray()) {
1417  for (int i = 0; i < filter.arrayGetLength(); i++) {
1418  Object filterEle = filter.arrayGet(i);
1419  if (filterEle.isName("Crypt")) {
1420  removeFilter = false;
1421  break;
1422  }
1423  }
1424  if (removeFilter) {
1425  encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, ref);
1426  encStream->setAutoDelete(false);
1427  stream = encStream;
1428  }
1429  } else {
1430  encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, ref);
1431  encStream->setAutoDelete(false);
1432  stream = encStream;
1433  }
1434  } else {
1435  removeFilter = false;
1436  }
1437  } else if (fileKey != nullptr) { // Encrypt stream
1438  encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, ref);
1439  encStream->setAutoDelete(false);
1440  stream = encStream;
1441  }
1442 
1443  stream->reset();
1444  // recalculate stream length
1445  Goffset tmp = 0;
1446  for (int c = stream->getChar(); c != EOF; c = stream->getChar()) {
1447  tmp++;
1448  }
1449  stream->getDict()->set("Length", Object(tmp));
1450 
1451  // Remove Stream encoding
1452  if (removeFilter) {
1453  stream->getDict()->remove("Filter");
1454  }
1455  stream->getDict()->remove("DecodeParms");
1456 
1457  writeDictionnary(stream->getDict(), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, ref, alreadyWrittenDicts);
1458  writeStream(stream, outStr);
1459  delete encStream;
1460  } else if (fileKey != nullptr && stream->getKind() == strFile && static_cast<FileStream *>(stream)->getNeedsEncryptionOnSave()) {
1461  EncryptStream *encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, ref);
1462  encStream->setAutoDelete(false);
1463  writeDictionnary(encStream->getDict(), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, ref, alreadyWrittenDicts);
1464  writeStream(encStream, outStr);
1465  delete encStream;
1466  } else {
1467  // raw stream copy
1468  FilterStream *fs = dynamic_cast<FilterStream *>(stream);
1469  if (fs) {
1470  BaseStream *bs = fs->getBaseStream();
1471  if (bs) {
1472  Goffset streamEnd;
1473  if (xRef->getStreamEnd(bs->getStart(), &streamEnd)) {
1474  Goffset val = streamEnd - bs->getStart();
1475  stream->getDict()->set("Length", Object(val));
1476  }
1477  }
1478  }
1479  writeDictionnary(stream->getDict(), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, ref, alreadyWrittenDicts);
1480  writeRawStream(stream, outStr);
1481  }
1482  break;
1483  }
1484  case objRef:
1485  outStr->printf("%i %i R ", obj->getRef().num + numOffset, obj->getRef().gen);
1486  break;
1487  case objCmd:
1488  outStr->printf("%s\n", obj->getCmd());
1489  break;
1490  case objError:
1491  outStr->printf("error\r\n");
1492  break;
1493  case objEOF:
1494  outStr->printf("eof\r\n");
1495  break;
1496  case objNone:
1497  outStr->printf("none\r\n");
1498  break;
1499  default:
1500  error(errUnimplemented, -1, "Unhandled objType : {0:d}, please report a bug with a testcase\r\n", obj->getType());
1501  break;
1502  }
1503 }
1504 
1506 {
1507  outStr->printf("\r\nendobj\r\n");
1508 }
1509 
1510 Object PDFDoc::createTrailerDict(int uxrefSize, bool incrUpdate, Goffset startxRef, Ref *root, XRef *xRef, const char *fileName, Goffset fileSize)
1511 {
1512  Dict *trailerDict = new Dict(xRef);
1513  trailerDict->set("Size", Object(uxrefSize));
1514 
1515  // build a new ID, as recommended in the reference, uses:
1516  // - current time
1517  // - file name
1518  // - file size
1519  // - values of entry in information dictionnary
1521  char buffer[256];
1522  sprintf(buffer, "%i", (int)time(nullptr));
1523  message.append(buffer);
1524 
1525  if (fileName)
1526  message.append(fileName);
1527 
1528  sprintf(buffer, "%lli", (long long)fileSize);
1529  message.append(buffer);
1530 
1531  // info dict -- only use text string
1532  if (!xRef->getTrailerDict()->isNone()) {
1533  Object docInfo = xRef->getDocInfo();
1534  if (docInfo.isDict()) {
1535  for (int i = 0; i < docInfo.getDict()->getLength(); i++) {
1536  Object obj2 = docInfo.getDict()->getVal(i);
1537  if (obj2.isString()) {
1538  message.append(obj2.getString());
1539  }
1540  }
1541  }
1542  }
1543 
1544  bool hasEncrypt = false;
1545  if (!xRef->getTrailerDict()->isNone()) {
1546  Object obj2 = xRef->getTrailerDict()->dictLookupNF("Encrypt").copy();
1547  if (!obj2.isNull()) {
1548  trailerDict->set("Encrypt", std::move(obj2));
1549  hasEncrypt = true;
1550  }
1551  }
1552 
1553  // calculate md5 digest
1554  unsigned char digest[16];
1555  md5((unsigned char *)message.c_str(), message.getLength(), digest);
1556 
1557  // create ID array
1558  // In case of encrypted files, the ID must not be changed because it's used to calculate the key
1559  if (incrUpdate || hasEncrypt) {
1560  // only update the second part of the array
1561  Object obj4 = xRef->getTrailerDict()->getDict()->lookup("ID");
1562  if (!obj4.isArray()) {
1563  error(errSyntaxWarning, -1, "PDFDoc::createTrailerDict original file's ID entry isn't an array. Trying to continue");
1564  } else {
1565  Array *array = new Array(xRef);
1566  // Get the first part of the ID
1567  array->add(obj4.arrayGet(0));
1568  array->add(Object(new GooString((const char *)digest, 16)));
1569  trailerDict->set("ID", Object(array));
1570  }
1571  } else {
1572  // new file => same values for the two identifiers
1573  Array *array = new Array(xRef);
1574  array->add(Object(new GooString((const char *)digest, 16)));
1575  array->add(Object(new GooString((const char *)digest, 16)));
1576  trailerDict->set("ID", Object(array));
1577  }
1578 
1579  trailerDict->set("Root", Object(*root));
1580 
1581  if (incrUpdate) {
1582  trailerDict->set("Prev", Object(startxRef));
1583  }
1584 
1585  if (!xRef->getTrailerDict()->isNone()) {
1586  Object obj5 = xRef->getDocInfoNF();
1587  if (!obj5.isNull()) {
1588  trailerDict->set("Info", std::move(obj5));
1589  }
1590  }
1591 
1592  return Object(trailerDict);
1593 }
1594 
1595 void PDFDoc::writeXRefTableTrailer(Object &&trailerDict, XRef *uxref, bool writeAllEntries, Goffset uxrefOffset, OutStream *outStr, XRef *xRef)
1596 {
1597  uxref->writeTableToFile(outStr, writeAllEntries);
1598  outStr->printf("trailer\r\n");
1599  writeDictionnary(trailerDict.getDict(), outStr, xRef, 0, nullptr, cryptRC4, 0, { 0, 0 }, nullptr);
1600  outStr->printf("\r\nstartxref\r\n");
1601  outStr->printf("%lli\r\n", uxrefOffset);
1602  outStr->printf("%%%%EOF\r\n");
1603 }
1604 
1605 void PDFDoc::writeXRefStreamTrailer(Object &&trailerDict, XRef *uxref, Ref *uxrefStreamRef, Goffset uxrefOffset, OutStream *outStr, XRef *xRef)
1606 {
1607  GooString stmData;
1608 
1609  // Fill stmData and some trailerDict fields
1610  uxref->writeStreamToBuffer(&stmData, trailerDict.getDict(), xRef);
1611 
1612  // Create XRef stream object and write it
1613  MemStream *mStream = new MemStream(stmData.c_str(), 0, stmData.getLength(), std::move(trailerDict));
1614  writeObjectHeader(uxrefStreamRef, outStr);
1615  Object obj1(static_cast<Stream *>(mStream));
1616  writeObject(&obj1, outStr, xRef, 0, nullptr, cryptRC4, 0, 0, 0);
1617  writeObjectFooter(outStr);
1618 
1619  outStr->printf("startxref\r\n");
1620  outStr->printf("%lli\r\n", uxrefOffset);
1621  outStr->printf("%%%%EOF\r\n");
1622 }
1623 
1624 void PDFDoc::writeXRefTableTrailer(Goffset uxrefOffset, XRef *uxref, bool writeAllEntries, int uxrefSize, OutStream *outStr, bool incrUpdate)
1625 {
1626  const char *fileNameA = fileName ? fileName->c_str() : nullptr;
1627  // file size (doesn't include the trailer)
1628  unsigned int fileSize = 0;
1629  int c;
1630  str->reset();
1631  while ((c = str->getChar()) != EOF) {
1632  fileSize++;
1633  }
1634  str->close();
1635  Ref ref;
1636  ref.num = getXRef()->getRootNum();
1637  ref.gen = getXRef()->getRootGen();
1638  Object trailerDict = createTrailerDict(uxrefSize, incrUpdate, getStartXRef(), &ref, getXRef(), fileNameA, fileSize);
1639  writeXRefTableTrailer(std::move(trailerDict), uxref, writeAllEntries, uxrefOffset, outStr, getXRef());
1640 }
1641 
1642 void PDFDoc::writeHeader(OutStream *outStr, int major, int minor)
1643 {
1644  outStr->printf("%%PDF-%d.%d\n", major, minor);
1645  outStr->printf("%%%c%c%c%c\n", 0xE2, 0xE3, 0xCF, 0xD3);
1646 }
1647 
1648 void PDFDoc::markDictionnary(Dict *dict, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum, std::set<Dict *> *alreadyMarkedDicts)
1649 {
1650  bool deleteSet = false;
1651  if (!alreadyMarkedDicts) {
1652  alreadyMarkedDicts = new std::set<Dict *>;
1653  deleteSet = true;
1654  }
1655 
1656  if (alreadyMarkedDicts->find(dict) != alreadyMarkedDicts->end()) {
1657  error(errSyntaxWarning, -1, "PDFDoc::markDictionnary: Found recursive dicts");
1658  if (deleteSet)
1659  delete alreadyMarkedDicts;
1660  return;
1661  } else {
1662  alreadyMarkedDicts->insert(dict);
1663  }
1664 
1665  for (int i = 0; i < dict->getLength(); i++) {
1666  const char *key = dict->getKey(i);
1667  if (strcmp(key, "Annots") != 0) {
1668  Object obj1 = dict->getValNF(i).copy();
1669  markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts);
1670  } else {
1671  Object annotsObj = dict->getValNF(i).copy();
1672  if (!annotsObj.isNull()) {
1673  markAnnotations(&annotsObj, xRef, countRef, 0, oldRefNum, newRefNum, alreadyMarkedDicts);
1674  }
1675  }
1676  }
1677 
1678  if (deleteSet) {
1679  delete alreadyMarkedDicts;
1680  }
1681 }
1682 
1683 void PDFDoc::markObject(Object *obj, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum, std::set<Dict *> *alreadyMarkedDicts)
1684 {
1685  Array *array;
1686 
1687  switch (obj->getType()) {
1688  case objArray:
1689  array = obj->getArray();
1690  for (int i = 0; i < array->getLength(); i++) {
1691  Object obj1 = array->getNF(i).copy();
1692  markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts);
1693  }
1694  break;
1695  case objDict:
1696  markDictionnary(obj->getDict(), xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts);
1697  break;
1698  case objStream: {
1699  Stream *stream = obj->getStream();
1700  markDictionnary(stream->getDict(), xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts);
1701  } break;
1702  case objRef: {
1703  if (obj->getRef().num + (int)numOffset >= xRef->getNumObjects() || xRef->getEntry(obj->getRef().num + numOffset)->type == xrefEntryFree) {
1704  if (getXRef()->getEntry(obj->getRef().num)->type == xrefEntryFree) {
1705  return; // already marked as free => should be replaced
1706  }
1707  xRef->add(obj->getRef().num + numOffset, obj->getRef().gen, 0, true);
1708  if (getXRef()->getEntry(obj->getRef().num)->type == xrefEntryCompressed) {
1709  xRef->getEntry(obj->getRef().num + numOffset)->type = xrefEntryCompressed;
1710  }
1711  }
1712  if (obj->getRef().num + (int)numOffset >= countRef->getNumObjects() || countRef->getEntry(obj->getRef().num + numOffset)->type == xrefEntryFree) {
1713  countRef->add(obj->getRef().num + numOffset, 1, 0, true);
1714  } else {
1715  XRefEntry *entry = countRef->getEntry(obj->getRef().num + numOffset);
1716  entry->gen++;
1717  if (entry->gen > 9)
1718  break;
1719  }
1720  Object obj1 = getXRef()->fetch(obj->getRef());
1721  markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum);
1722  } break;
1723  default:
1724  break;
1725  }
1726 }
1727 
1728 void PDFDoc::replacePageDict(int pageNo, int rotate, const PDFRectangle *mediaBox, const PDFRectangle *cropBox)
1729 {
1730  Ref *refPage = getCatalog()->getPageRef(pageNo);
1731  Object page = getXRef()->fetch(*refPage);
1732  Dict *pageDict = page.getDict();
1733  pageDict->remove("MediaBoxssdf");
1734  pageDict->remove("MediaBox");
1735  pageDict->remove("CropBox");
1736  pageDict->remove("ArtBox");
1737  pageDict->remove("BleedBox");
1738  pageDict->remove("TrimBox");
1739  pageDict->remove("Rotate");
1740  Array *mediaBoxArray = new Array(getXRef());
1741  mediaBoxArray->add(Object(mediaBox->x1));
1742  mediaBoxArray->add(Object(mediaBox->y1));
1743  mediaBoxArray->add(Object(mediaBox->x2));
1744  mediaBoxArray->add(Object(mediaBox->y2));
1745  Object mediaBoxObject(mediaBoxArray);
1746  Object trimBoxObject = mediaBoxObject.copy();
1747  pageDict->add("MediaBox", std::move(mediaBoxObject));
1748  if (cropBox != nullptr) {
1749  Array *cropBoxArray = new Array(getXRef());
1750  cropBoxArray->add(Object(cropBox->x1));
1751  cropBoxArray->add(Object(cropBox->y1));
1752  cropBoxArray->add(Object(cropBox->x2));
1753  cropBoxArray->add(Object(cropBox->y2));
1754  Object cropBoxObject(cropBoxArray);
1755  trimBoxObject = cropBoxObject.copy();
1756  pageDict->add("CropBox", std::move(cropBoxObject));
1757  }
1758  pageDict->add("TrimBox", std::move(trimBoxObject));
1759  pageDict->add("Rotate", Object(rotate));
1760  getXRef()->setModifiedObject(&page, *refPage);
1761 }
1762 
1763 void PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum, std::set<Dict *> *alreadyMarkedDicts)
1764 {
1765  pageDict->remove("OpenAction");
1766  pageDict->remove("Outlines");
1767  pageDict->remove("StructTreeRoot");
1768 
1769  for (int n = 0; n < pageDict->getLength(); n++) {
1770  const char *key = pageDict->getKey(n);
1771  Object value = pageDict->getValNF(n).copy();
1772  if (strcmp(key, "Parent") != 0 && strcmp(key, "Pages") != 0 && strcmp(key, "AcroForm") != 0 && strcmp(key, "Annots") != 0 && strcmp(key, "P") != 0 && strcmp(key, "Root") != 0) {
1773  markObject(&value, xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts);
1774  }
1775  }
1776 }
1777 
1778 bool PDFDoc::markAnnotations(Object *annotsObj, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldPageNum, int newPageNum, std::set<Dict *> *alreadyMarkedDicts)
1779 {
1780  bool modified = false;
1781  Object annots = annotsObj->fetch(getXRef());
1782  if (annots.isArray()) {
1783  Array *array = annots.getArray();
1784  for (int i = array->getLength() - 1; i >= 0; i--) {
1785  Object obj1 = array->get(i);
1786  if (obj1.isDict()) {
1787  Dict *dict = obj1.getDict();
1788  Object type = dict->lookup("Type");
1789  if (type.isName() && strcmp(type.getName(), "Annot") == 0) {
1790  const Object &obj2 = dict->lookupNF("P");
1791  if (obj2.isRef()) {
1792  if (obj2.getRef().num == oldPageNum) {
1793  const Object &obj3 = array->getNF(i);
1794  if (obj3.isRef()) {
1795  Ref r;
1796  r.num = newPageNum;
1797  r.gen = 0;
1798  dict->set("P", Object(r));
1799  getXRef()->setModifiedObject(&obj1, obj3.getRef());
1800  }
1801  } else if (obj2.getRef().num == newPageNum) {
1802  continue;
1803  } else {
1804  Object page = getXRef()->fetch(obj2.getRef());
1805  if (page.isDict()) {
1806  Dict *pageDict = page.getDict();
1807  Object pagetype = pageDict->lookup("Type");
1808  if (!pagetype.isName() || strcmp(pagetype.getName(), "Page") != 0) {
1809  continue;
1810  }
1811  }
1812  array->remove(i);
1813  modified = true;
1814  continue;
1815  }
1816  }
1817  }
1818  markPageObjects(dict, xRef, countRef, numOffset, oldPageNum, newPageNum, alreadyMarkedDicts);
1819  }
1820  obj1 = array->getNF(i).copy();
1821  if (obj1.isRef()) {
1822  if (obj1.getRef().num + (int)numOffset >= xRef->getNumObjects() || xRef->getEntry(obj1.getRef().num + numOffset)->type == xrefEntryFree) {
1823  if (getXRef()->getEntry(obj1.getRef().num)->type == xrefEntryFree) {
1824  continue; // already marked as free => should be replaced
1825  }
1826  xRef->add(obj1.getRef().num + numOffset, obj1.getRef().gen, 0, true);
1827  if (getXRef()->getEntry(obj1.getRef().num)->type == xrefEntryCompressed) {
1828  xRef->getEntry(obj1.getRef().num + numOffset)->type = xrefEntryCompressed;
1829  }
1830  }
1831  if (obj1.getRef().num + (int)numOffset >= countRef->getNumObjects() || countRef->getEntry(obj1.getRef().num + numOffset)->type == xrefEntryFree) {
1832  countRef->add(obj1.getRef().num + numOffset, 1, 0, true);
1833  } else {
1834  XRefEntry *entry = countRef->getEntry(obj1.getRef().num + numOffset);
1835  entry->gen++;
1836  }
1837  }
1838  }
1839  }
1840  if (annotsObj->isRef()) {
1841  if (annotsObj->getRef().num + (int)numOffset >= xRef->getNumObjects() || xRef->getEntry(annotsObj->getRef().num + numOffset)->type == xrefEntryFree) {
1842  if (getXRef()->getEntry(annotsObj->getRef().num)->type == xrefEntryFree) {
1843  return modified; // already marked as free => should be replaced
1844  }
1845  xRef->add(annotsObj->getRef().num + numOffset, annotsObj->getRef().gen, 0, true);
1846  if (getXRef()->getEntry(annotsObj->getRef().num)->type == xrefEntryCompressed) {
1847  xRef->getEntry(annotsObj->getRef().num + numOffset)->type = xrefEntryCompressed;
1848  }
1849  }
1850  if (annotsObj->getRef().num + (int)numOffset >= countRef->getNumObjects() || countRef->getEntry(annotsObj->getRef().num + numOffset)->type == xrefEntryFree) {
1851  countRef->add(annotsObj->getRef().num + numOffset, 1, 0, true);
1852  } else {
1853  XRefEntry *entry = countRef->getEntry(annotsObj->getRef().num + numOffset);
1854  entry->gen++;
1855  }
1856  getXRef()->setModifiedObject(&annots, annotsObj->getRef());
1857  }
1858  return modified;
1859 }
1860 
1861 void PDFDoc::markAcroForm(Object *afObj, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum)
1862 {
1863  bool modified = false;
1864  Object acroform = afObj->fetch(getXRef());
1865  if (acroform.isDict()) {
1866  Dict *dict = acroform.getDict();
1867  for (int i = 0; i < dict->getLength(); i++) {
1868  if (strcmp(dict->getKey(i), "Fields") == 0) {
1869  Object fields = dict->getValNF(i).copy();
1870  modified = markAnnotations(&fields, xRef, countRef, numOffset, oldRefNum, newRefNum);
1871  } else {
1872  Object obj = dict->getValNF(i).copy();
1873  markObject(&obj, xRef, countRef, numOffset, oldRefNum, newRefNum);
1874  }
1875  }
1876  }
1877  if (afObj->isRef()) {
1878  if (afObj->getRef().num + (int)numOffset >= xRef->getNumObjects() || xRef->getEntry(afObj->getRef().num + numOffset)->type == xrefEntryFree) {
1879  if (getXRef()->getEntry(afObj->getRef().num)->type == xrefEntryFree) {
1880  return; // already marked as free => should be replaced
1881  }
1882  xRef->add(afObj->getRef().num + numOffset, afObj->getRef().gen, 0, true);
1883  if (getXRef()->getEntry(afObj->getRef().num)->type == xrefEntryCompressed) {
1884  xRef->getEntry(afObj->getRef().num + numOffset)->type = xrefEntryCompressed;
1885  }
1886  }
1887  if (afObj->getRef().num + (int)numOffset >= countRef->getNumObjects() || countRef->getEntry(afObj->getRef().num + numOffset)->type == xrefEntryFree) {
1888  countRef->add(afObj->getRef().num + numOffset, 1, 0, true);
1889  } else {
1890  XRefEntry *entry = countRef->getEntry(afObj->getRef().num + numOffset);
1891  entry->gen++;
1892  }
1893  if (modified) {
1894  getXRef()->setModifiedObject(&acroform, afObj->getRef());
1895  }
1896  }
1897  return;
1898 }
1899 
1900 unsigned int PDFDoc::writePageObjects(OutStream *outStr, XRef *xRef, unsigned int numOffset, bool combine)
1901 {
1902  unsigned int objectsCount = 0; // count the number of objects in the XRef(s)
1903  unsigned char *fileKey;
1904  CryptAlgorithm encAlgorithm;
1905  int keyLength;
1906  xRef->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength);
1907 
1908  for (int n = numOffset; n < xRef->getNumObjects(); n++) {
1909  if (xRef->getEntry(n)->type != xrefEntryFree) {
1910  Ref ref;
1911  ref.num = n;
1912  ref.gen = xRef->getEntry(n)->gen;
1913  objectsCount++;
1914  Object obj = getXRef()->fetch(ref.num - numOffset, ref.gen);
1915  Goffset offset = writeObjectHeader(&ref, outStr);
1916  if (combine) {
1917  writeObject(&obj, outStr, getXRef(), numOffset, nullptr, cryptRC4, 0, 0, 0);
1918  } else if (xRef->getEntry(n)->getFlag(XRefEntry::Unencrypted)) {
1919  writeObject(&obj, outStr, nullptr, cryptRC4, 0, 0, 0);
1920  } else {
1921  writeObject(&obj, outStr, fileKey, encAlgorithm, keyLength, ref);
1922  }
1923  writeObjectFooter(outStr);
1924  xRef->add(ref, offset, true);
1925  }
1926  }
1927  return objectsCount;
1928 }
1929 
1931 {
1932  if (!outline) {
1933  pdfdocLocker();
1934  // read outline
1935  outline = new Outline(catalog->getOutline(), xref);
1936  }
1937 
1938  return outline;
1939 }
1940 
1941 std::unique_ptr<PDFDoc> PDFDoc::ErrorPDFDoc(int errorCode, const GooString *fileNameA)
1942 {
1943  // We cannot call std::make_unique here because the PDFDoc constructor is private
1944  PDFDoc *doc = new PDFDoc();
1945  doc->errCode = errorCode;
1946  doc->fileName = fileNameA;
1947 
1948  return std::unique_ptr<PDFDoc>(doc);
1949 }
1950 
1951 long long PDFDoc::strToLongLong(const char *s)
1952 {
1953  long long x, d;
1954  const char *p;
1955 
1956  x = 0;
1957  for (p = s; *p && isdigit(*p & 0xff); ++p) {
1958  d = *p - '0';
1959  if (x > (LLONG_MAX - d) / 10) {
1960  break;
1961  }
1962  x = 10 * x + d;
1963  }
1964  return x;
1965 }
1966 
1967 // Read the 'startxref' position.
1968 Goffset PDFDoc::getStartXRef(bool tryingToReconstruct)
1969 {
1970  if (startXRefPos == -1) {
1971 
1972  if (isLinearized(tryingToReconstruct)) {
1973  char buf[linearizationSearchSize + 1];
1974  int c, n, i;
1975 
1976  str->setPos(0);
1977  for (n = 0; n < linearizationSearchSize; ++n) {
1978  if ((c = str->getChar()) == EOF) {
1979  break;
1980  }
1981  buf[n] = c;
1982  }
1983  buf[n] = '\0';
1984 
1985  // find end of first obj (linearization dictionary)
1986  startXRefPos = 0;
1987  for (i = 0; i < n; i++) {
1988  if (!strncmp("endobj", &buf[i], 6)) {
1989  i += 6;
1990  // skip whitespace
1991  while (buf[i] && Lexer::isSpace(buf[i]))
1992  ++i;
1993  startXRefPos = i;
1994  break;
1995  }
1996  }
1997  } else {
1998  char buf[xrefSearchSize + 1];
1999  const char *p;
2000  int c, n, i;
2001 
2002  // read last xrefSearchSize bytes
2003  int segnum = 0;
2004  int maxXRefSearch = 24576;
2005  if (str->getLength() < maxXRefSearch)
2006  maxXRefSearch = str->getLength();
2007  for (; (xrefSearchSize - 16) * segnum < maxXRefSearch; segnum++) {
2008  str->setPos((xrefSearchSize - 16) * segnum + xrefSearchSize, -1);
2009  for (n = 0; n < xrefSearchSize; ++n) {
2010  if ((c = str->getChar()) == EOF) {
2011  break;
2012  }
2013  buf[n] = c;
2014  }
2015  buf[n] = '\0';
2016 
2017  // find startxref
2018  for (i = n - 9; i >= 0; --i) {
2019  if (!strncmp(&buf[i], "startxref", 9)) {
2020  break;
2021  }
2022  }
2023  if (i < 0) {
2024  startXRefPos = 0;
2025  } else {
2026  for (p = &buf[i + 9]; isspace(*p); ++p)
2027  ;
2029  break;
2030  }
2031  }
2032  }
2033  }
2034 
2035  return startXRefPos;
2036 }
2037 
2039 {
2040  unsigned int mainXRefEntriesOffset = 0;
2041 
2042  if (isLinearized(tryingToReconstruct)) {
2043  mainXRefEntriesOffset = getLinearization()->getMainXRefEntriesOffset();
2044  }
2045 
2046  return mainXRefEntriesOffset;
2047 }
2048 
2049 int PDFDoc::getNumPages()
2050 {
2051  if (isLinearized()) {
2052  int n;
2053  if ((n = getLinearization()->getNumPages())) {
2054  return n;
2055  }
2056  }
2057 
2058  return catalog->getNumPages();
2059 }
2060 
2062 {
2063  Ref pageRef;
2064 
2065  pageRef.num = getHints()->getPageObjectNum(page);
2066  if (!pageRef.num) {
2067  error(errSyntaxWarning, -1, "Failed to get object num from hint tables for page {0:d}", page);
2068  return nullptr;
2069  }
2070 
2071  // check for bogus ref - this can happen in corrupted PDF files
2072  if (pageRef.num < 0 || pageRef.num >= xref->getNumObjects()) {
2073  error(errSyntaxWarning, -1, "Invalid object num ({0:d}) for page {1:d}", pageRef.num, page);
2074  return nullptr;
2075  }
2076 
2077  pageRef.gen = xref->getEntry(pageRef.num)->gen;
2078  Object obj = xref->fetch(pageRef);
2079  if (!obj.isDict("Page")) {
2080  error(errSyntaxWarning, -1, "Object ({0:d} {1:d}) is not a pageDict", pageRef.num, pageRef.gen);
2081  return nullptr;
2082  }
2083  Dict *pageDict = obj.getDict();
2084 
2085  return new Page(this, page, std::move(obj), pageRef, new PageAttrs(nullptr, pageDict), catalog->getForm());
2086 }
2087 
2089 {
2090  if ((page < 1) || page > getNumPages())
2091  return nullptr;
2092 
2093  if (isLinearized() && checkLinearization()) {
2094  pdfdocLocker();
2095  if (!pageCache) {
2096  pageCache = (Page **)gmallocn(getNumPages(), sizeof(Page *));
2097  for (int i = 0; i < getNumPages(); i++) {
2098  pageCache[i] = nullptr;
2099  }
2100  }
2101  if (!pageCache[page - 1]) {
2102  pageCache[page - 1] = parsePage(page);
2103  }
2104  if (pageCache[page - 1]) {
2105  return pageCache[page - 1];
2106  } else {
2107  error(errSyntaxWarning, -1, "Failed parsing page {0:d} using hint tables", page);
2108  }
2109  }
2110 
2111  return catalog->getPage(page);
2112 }
2113 
2115 {
2116  JSInfo jsInfo(this);
2117  jsInfo.scanJS(getNumPages(), true);
2118  return jsInfo.containsJS();
2119 }
#define message
Definition: aptex-macros.h:418
#define match
Definition: aptex-macros.h:359
#define type(a)
Definition: aptex-macros.h:171
#define name
#define subtype(a)
Definition: aptex-macros.h:172
#define mode
Definition: aptex-macros.h:510
Definition: Annot.h:80
Definition: Array.h:29
void add(Object *elem)
Definition: Array.cc:41
void setAutoDelete(bool val)
Definition: Decrypt.cc:378
virtual Goffset getLength()
Definition: Stream.h:337
virtual BaseStream * copy()=0
virtual GString * getFileName()
Definition: Stream.h:173
virtual GFileOffset getStart()=0
virtual Dict * getDict()
Definition: Stream.h:172
virtual void setPos(GFileOffset pos, int dir=0)=0
virtual void moveStart(int delta)=0
AcroForm * getForm()
Definition: Catalog.h:91
Ref * getPageRef(int i)
Definition: Catalog.cc:316
Object * getOutline()
Definition: Catalog.h:87
Page * getPage(int i)
Definition: Catalog.cc:300
int getNumPages()
Definition: Catalog.h:53
GBool isOk()
Definition: Catalog.h:50
Definition: Dict.h:29
char * getKey(int i)
Definition: Dict.cc:135
void add(char *key, Object *val)
Definition: Dict.cc:56
int getLength()
Definition: Dict.h:48
Object * lookupNF(const char *key, Object *obj)
Definition: Dict.cc:129
void remove(const char *key)
Definition: Dict.cc:128
Object * getVal(int i, Object *obj)
Definition: Dict.cc:139
Object * lookup(const char *key, Object *obj, int recursion=0)
Definition: Dict.cc:122
void set(const char *key, Object &&val)
Definition: Dict.cc:142
Object * getValNF(int i, Object *obj)
Definition: Dict.cc:143
bool hasKey(const char *key) const
Definition: Dict.cc:233
void reset() override
Definition: Decrypt.cc:404
bool getNeedsEncryptionOnSave() const
Definition: Stream.h:539
virtual BaseStream * getBaseStream()
Definition: Stream.h:198
virtual Dict * getDict()
Definition: Stream.h:200
FormField * getChildren(int i) const
Definition: Form.h:364
int getNumChildren() const
Definition: Form.h:363
FormFieldType getType() const
Definition: Form.h:341
Definition: Form.h:640
GString * copy()
Definition: GString.h:42
char getChar(int i)
Definition: GString.h:86
int getLength()
Definition: GString.h:80
GBool getPrintCommands()
static GooFile * open(const GooString *fileName)
Definition: gfile.cc:403
const std::string & toStr() const
Definition: GooString.h:72
GooString * sanitizedName(bool psmode) const
Definition: GooString.cc:623
int getLength() const
Definition: GooString.h:142
GooString * append(char c)
Definition: GooString.h:161
Definition: Hints.h:30
int getPageObjectNum(int page)
Definition: Hints.cc:503
Definition: JSInfo.h:31
bool containsJS()
Definition: JSInfo.cc:241
void scanJS(int nPages)
Definition: JSInfo.cc:89
static GBool isSpace(int c)
Definition: Lexer.cc:553
unsigned int getLength() const
unsigned int getMainXRefEntriesOffset() const
int getNumPages() const
Definition: Object.h:84
Ref getRef()
Definition: Object.h:163
GBool isDict()
Definition: Object.h:137
Object * dictLookup(const char *key, Object *obj, int recursion=0)
Definition: Object.h:266
bool isInt64() const
Definition: Object.h:358
double getReal()
Definition: Object.h:156
Stream * getStream()
Definition: Object.h:162
char * getCmd()
Definition: Object.h:166
Array * getArray()
Definition: Object.h:160
GBool isName()
Definition: Object.h:134
GBool isRef()
Definition: Object.h:139
GBool getBool()
Definition: Object.h:154
Object * copy(Object *obj)
Definition: Object.cc:80
Object * fetch(XRef *xref, Object *obj, int recursion=0)
Definition: Object.cc:114
int dictGetLength()
Definition: Object.h:254
char * getName()
Definition: Object.h:159
int getInt()
Definition: Object.h:155
GBool isNone()
Definition: Object.h:143
GBool isInt()
Definition: Object.h:130
ObjType getType()
Definition: Object.h:128
int arrayGetLength()
Definition: Object.h:236
GBool isArray()
Definition: Object.h:136
GBool isString()
Definition: Object.h:133
const GooString * getHexString() const
Definition: Object.h:418
GString * getString()
Definition: Object.h:158
Dict * getDict()
Definition: Object.h:161
Object * dictLookupNF(const char *key, Object *obj)
Definition: Object.h:269
long long getInt64() const
Definition: Object.h:469
void dictSet(const char *key, Object &&val)
Definition: Object.h:595
GBool isNull()
Definition: Object.h:135
GooString * takeString()
Definition: Object.h:412
Object * arrayGet(int i, Object *obj, int recursion=0)
Definition: Object.h:242
virtual void put(char c)=0
virtual Goffset getPos()=0
virtual void close()=0
virtual void printf(const char *format,...)=0
Definition: PDFDoc.h:38
Goffset startXRefPos
Definition: PDFDoc.h:389
SecurityHandler * secHdlr
Definition: PDFDoc.h:377
void checkHeader()
Definition: PDFDoc.cc:375
void displayPageSlice(OutputDev *out, int page, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, GBool printing, int sliceX, int sliceY, int sliceW, int sliceH, GBool(*abortCheckCbk)(void *data)=NULL, void *abortCheckCbkData=NULL)
Definition: PDFDoc.cc:471
void markAcroForm(Object *afObj, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum)
Definition: PDFDoc.cc:1861
BaseStream * str
Definition: PDFDoc.h:210
PDFSubtypeConformance pdfConformance
Definition: PDFDoc.h:370
int saveWithoutChangesAs(const GooString *name)
Definition: PDFDoc.cc:1041
static void writeXRefStreamTrailer(Object &&trailerDict, XRef *uxref, Ref *uxrefStreamRef, Goffset uxrefOffset, OutStream *outStr, XRef *xRef)
Definition: PDFDoc.cc:1605
std::vector< FormFieldSignature * > getSignatureFields()
Definition: PDFDoc.cc:619
static Object createTrailerDict(int uxrefSize, bool incrUpdate, Goffset startxRef, Ref *root, XRef *xRef, const char *fileName, Goffset fileSize)
Definition: PDFDoc.cc:1510
int getNumPages()
Definition: PDFDoc.h:93
void displayPages(OutputDev *out, int firstPage, int lastPage, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, GBool printing, GBool(*abortCheckCbk)(void *data)=NULL, void *abortCheckCbkData=NULL)
Definition: PDFDoc.cc:457
long long strToLongLong(const char *s)
Definition: PDFDoc.cc:1951
GBool isLinearized()
Definition: PDFDoc.cc:533
GBool checkEncryption(GString *ownerPassword, GString *userPassword)
Definition: PDFDoc.cc:406
void init()
Definition: PDFDoc.cc:117
Catalog * catalog
Definition: PDFDoc.h:214
PDFSubtypePart pdfPart
Definition: PDFDoc.h:369
static std::unique_ptr< PDFDoc > ErrorPDFDoc(int errorCode, const GooString *fileNameA=nullptr)
Definition: PDFDoc.cc:1941
int getPDFMajorVersion() const
Definition: PDFDoc.h:280
static Goffset writeObjectHeader(Ref *ref, OutStream *outStr)
Definition: PDFDoc.cc:1337
bool getID(GooString *permanent_id, GooString *update_id) const
Definition: PDFDoc.cc:807
void processLinks(OutputDev *out, int page)
Definition: PDFDoc.cc:488
static void writeStream(Stream *str, OutStream *outStr)
Definition: PDFDoc.cc:1246
int linearizationState
Definition: PDFDoc.h:375
bool hasJavascript()
Definition: PDFDoc.cc:2114
int fopenErrno
Definition: PDFDoc.h:387
Linearization * getLinearization()
Definition: PDFDoc.cc:678
int savePageAs(const GooString *name, int pageNo)
Definition: PDFDoc.cc:851
int getPDFMinorVersion() const
Definition: PDFDoc.h:281
PDFSubtype pdfSubtype
Definition: PDFDoc.h:368
void removeDocInfo()
Definition: PDFDoc.h:242
GooString * getDocInfoStringEntry(const char *key)
Definition: PDFDoc.cc:769
void markDictionnary(Dict *dict, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum, std::set< Dict * > *alreadyMarkedDicts)
Definition: PDFDoc.cc:1648
Links * getLinks(int page)
Definition: PDFDoc.cc:484
void setDocInfoStringEntry(const char *key, GooString *value)
Definition: PDFDoc.cc:740
Page * getPage(int page)
Definition: PDFDoc.cc:2088
Linearization * linearization
Definition: PDFDoc.h:371
bool markAnnotations(Object *annots, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldPageNum, int newPageNum, std::set< Dict * > *alreadyMarkedDicts=nullptr)
Definition: PDFDoc.cc:1778
int errCode
Definition: PDFDoc.h:221
static void writeXRefTableTrailer(Object &&trailerDict, XRef *uxref, bool writeAllEntries, Goffset uxrefOffset, OutStream *outStr, XRef *xRef)
Definition: PDFDoc.cc:1595
Goffset getStartXRef(bool tryingToReconstruct=false)
Definition: PDFDoc.cc:1968
static void writeRawStream(Stream *str, OutStream *outStr)
Definition: PDFDoc.cc:1256
Hints * getHints()
Definition: PDFDoc.cc:842
void saveCompleteRewrite(OutStream *outStr)
Definition: PDFDoc.cc:1154
GBool saveAs(GString *name)
Definition: PDFDoc.cc:564
XRef * getXRef()
Definition: PDFDoc.h:72
Page ** pageCache
Definition: PDFDoc.h:381
void displayPage(OutputDev *out, int page, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, GBool printing, GBool(*abortCheckCbk)(void *data)=NULL, void *abortCheckCbkData=NULL)
Definition: PDFDoc.cc:444
Goffset getMainXRefEntriesOffset(bool tryingToReconstruct=false)
Definition: PDFDoc.cc:2038
static void writeDictionnary(Dict *dict, OutStream *outStr, XRef *xRef, unsigned int numOffset, unsigned char *fileKey, CryptAlgorithm encAlgorithm, int keyLength, Ref ref, std::set< Dict * > *alreadyWrittenDicts)
Definition: PDFDoc.cc:1213
Hints * hints
Definition: PDFDoc.h:379
void saveIncrementalUpdate(OutStream *outStr)
Definition: PDFDoc.cc:1079
bool checkFooter()
Definition: PDFDoc.cc:369
static void writeString(const GooString *s, OutStream *outStr, const unsigned char *fileKey, CryptAlgorithm encAlgorithm, int keyLength, Ref ref)
Definition: PDFDoc.cc:1284
GBool ok
Definition: PDFDoc.h:220
GString * fileName
Definition: PDFDoc.h:205
unsigned int writePageObjects(OutStream *outStr, XRef *xRef, unsigned int numOffset, bool combine=false)
Definition: PDFDoc.cc:1900
void extractPDFSubtype()
Definition: PDFDoc.cc:571
FILE * file
Definition: PDFDoc.h:209
bool checkLinearization()
Definition: PDFDoc.cc:687
Outline * outline
Definition: PDFDoc.h:216
Catalog * getCatalog()
Definition: PDFDoc.h:75
~PDFDoc()
Definition: PDFDoc.cc:342
PDFDoc()
Definition: PDFDoc.cc:134
void markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum, std::set< Dict * > *alreadyMarkedDicts=nullptr)
Definition: PDFDoc.cc:1763
Object getDocInfo()
Definition: PDFDoc.h:238
GBool setup(GString *ownerPassword, GString *userPassword)
Definition: PDFDoc.cc:273
void markObject(Object *obj, XRef *xRef, XRef *countRef, unsigned int numOffset, int oldRefNum, int newRefNum, std::set< Dict * > *alreadyMarkedDicts=nullptr)
Definition: PDFDoc.cc:1683
int pdfMajorVersion
Definition: PDFDoc.h:366
Outline * getOutline()
Definition: PDFDoc.h:142
XRef * xref
Definition: PDFDoc.h:213
void * guiData
Definition: PDFDoc.h:365
int pdfMinorVersion
Definition: PDFDoc.h:367
static void writeHeader(OutStream *outStr, int major, int minor)
Definition: PDFDoc.cc:1642
static void writeObject(Object *obj, OutStream *outStr, XRef *xref, unsigned int numOffset, unsigned char *fileKey, CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen, std::set< Dict * > *alreadyWrittenDicts=nullptr)
Definition: PDFDoc.cc:1344
void replacePageDict(int pageNo, int rotate, const PDFRectangle *mediaBox, const PDFRectangle *cropBox)
Definition: PDFDoc.cc:1728
Page * parsePage(int page)
Definition: PDFDoc.cc:2061
static void writeObjectFooter(OutStream *outStr)
Definition: PDFDoc.cc:1505
double x2
Definition: Page.h:30
double y2
Definition: Page.h:30
double x1
Definition: Page.h:30
double y1
Definition: Page.h:30
Definition: Page.h:43
Definition: Page.h:112
void displaySlice(OutputDev *out, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, int sliceX, int sliceY, int sliceW, int sliceH, GBool printing, GBool(*abortCheckCbk)(void *data)=NULL, void *abortCheckCbkData=NULL)
Definition: Page.cc:327
Object * getResourceDictObject()
Definition: Page.cc:335
void processLinks(OutputDev *out)
Definition: Page.cc:477
PDFRectangle * getCropBox()
Definition: Page.h:132
void display(OutputDev *out, double hDPI, double vDPI, int rotate, GBool useMediaBox, GBool crop, GBool printing, GBool(*abortCheckCbk)(void *data)=NULL, void *abortCheckCbkData=NULL)
Definition: Page.cc:317
virtual int getEncRevision() const =0
virtual GBool getOwnerPasswordOk()=0
virtual CryptAlgorithm getEncAlgorithm()=0
static SecurityHandler * make(PDFDoc *docA, Object *encryptDictA)
GBool checkEncryption(GString *ownerPassword, GString *userPassword)
virtual GBool isUnencrypted()
virtual int getFileKeyLength()=0
virtual int getPermissionFlags()=0
virtual Guchar * getFileKey()=0
virtual int getEncVersion()=0
Definition: Stream.h:67
virtual void unfilteredReset()=0
virtual void reset()=0
virtual GFileOffset getPos()=0
virtual int getChar()=0
virtual int getUnfilteredChar()=0
virtual void close()
Definition: Stream.cc:64
Definition: XRef.h:58
void writeStreamToBuffer(GooString *stmBuf, Dict *xrefDict, XRef *xref)
Definition: XRef.cc:1552
void add(int num, int gen, Goffset offs, bool used)
Definition: XRef.cc:1349
XRefEntry * getEntry(int i)
Definition: XRef.h:124
Object * fetch(int num, int gen, Object *obj, int recursion=0)
Definition: XRef.cc:1155
int getNumObjects()
Definition: XRef.h:102
bool isModified() const
Definition: XRef.h:197
void markUnencrypted()
Definition: XRef.cc:1786
void unlock()
Definition: XRef.cc:1254
void setEncryption(int permFlagsA, GBool ownerPasswordOkA, Guchar *fileKeyA, int keyLengthA, int encVersionA, CryptAlgorithm encAlgorithmA)
Definition: XRef.cc:1105
void scanSpecialFlags()
Definition: XRef.cc:1747
Object * getDocInfo(Object *obj)
Definition: XRef.cc:1359
GBool isOk()
Definition: XRef.h:68
void writeTableToFile(OutStream *outStr, bool writeAllEntries)
Definition: XRef.cc:1505
Object createDocInfoIfNeeded(Ref *ref)
Definition: XRef.cc:1270
int getRootGen()
Definition: XRef.h:112
GBool getStreamEnd(GFileOffset streamStart, GFileOffset *streamEnd)
Definition: XRef.cc:1368
int getErrorCode()
Definition: XRef.h:71
void setModifiedObject(const Object *o, Ref r)
Definition: XRef.cc:1379
int getRootNum()
Definition: XRef.h:111
Object * getCatalog(Object *obj)
Definition: XRef.h:92
Object * getDocInfoNF(Object *obj)
Definition: XRef.cc:1364
bool isXRefStream() const
Definition: XRef.h:118
void lock()
Definition: XRef.cc:1249
void getEncryptionParameters(unsigned char **fileKeyA, CryptAlgorithm *encAlgorithmA, int *keyLengthA)
Definition: XRef.cc:1022
Object * getTrailerDict()
Definition: XRef.h:125
#define n
Definition: t4ht.c:1290
static void date(UDate when, const UChar *tz, UDateFormatStyle style, const char *format, const char *locale, UErrorCode *status)
Definition: date.c:253
#define gfree(p)
Definition: dt2dv.c:326
int strcmp()
Definition: coll.cpp:143
int sscanf()
int printf()
#define error(a)
Definition: dviinfo.c:48
struct rect data
Definition: dvipdfm.c:64
struct _FileStream FileStream
Definition: filestrm.h:32
struct move_struct move
mpz_t * f
Definition: gen-fib.c:34
#define s
Definition: afcover.h:80
void * gmallocn(int nObjs, int objSize)
Definition: gmem.cc:204
#define c(n)
Definition: gpos-common.c:150
#define d(n)
Definition: gpos-common.c:151
FILE * out
Definition: hbf2gf.c:286
static int32_t fileSize(FILE *f)
Definition: icuswap.cpp:61
#define unlikely(x)
Definition: jbig2arith.cc:116
struct child * children
Definition: job.c:229
#define NULL
Definition: ftobjs.h:61
small capitals from c petite p
Definition: afcover.h:72
small capitals from c petite p scientific i
Definition: afcover.h:80
#define EOF
Definition: afmparse.c:59
png_uint_32 md5[4]
Definition: png.c:2248
FILE * openFile(const char *path, const char *mode)
Definition: gfile.cc:612
#define errDamaged
Definition: ErrorCodes.h:18
#define errNone
Definition: ErrorCodes.h:12
#define errEncrypted
Definition: ErrorCodes.h:21
#define errOpenFile
Definition: ErrorCodes.h:14
#define errBadCatalog
Definition: ErrorCodes.h:16
#define errFileIO
Definition: ErrorCodes.h:34
@ errSyntaxError
Definition: Error.h:25
@ errSyntaxWarning
Definition: Error.h:23
@ errUnimplemented
Definition: Error.h:32
@ errInternal
Definition: Error.h:34
@ errIO
Definition: Error.h:30
GlobalParams * globalParams
@ objCmd
Definition: Object.h:62
@ objBool
Definition: Object.h:48
@ objNone
Definition: Object.h:65
@ objNull
Definition: Object.h:53
@ objArray
Definition: Object.h:56
@ objString
Definition: Object.h:51
@ objDict
Definition: Object.h:57
@ objStream
Definition: Object.h:58
@ objError
Definition: Object.h:63
@ objRef
Definition: Object.h:59
@ objInt
Definition: Object.h:49
@ objReal
Definition: Object.h:50
@ objName
Definition: Object.h:52
@ objEOF
Definition: Object.h:64
CryptAlgorithm
Definition: Stream.h:57
@ cryptRC4
Definition: Stream.h:58
@ strFile
Definition: Stream.h:33
@ strWeird
Definition: Stream.h:43
XRefEntryType
Definition: XRef.h:35
@ xrefEntryFree
Definition: XRef.h:36
@ xrefEntryUncompressed
Definition: XRef.h:37
@ xrefEntryCompressed
Definition: XRef.h:38
static char ownerPassword[33]
Definition: pdfdetach.cc:28
static char userPassword[33]
Definition: pdfdetach.cc:29
static PDFDoc * doc
Definition: pdffonts.cc:89
static int lastPage
Definition: pdffonts.cc:52
static int firstPage
Definition: pdffonts.cc:51
int errno
#define buf
int major
Definition: pdfcolor.c:526
int minor
Definition: pdfcolor.c:527
pdf_obj * entry
Definition: pdfdoc.c:64
#define fclose
Definition: debug.h:100
static int ret
Definition: convert.c:72
FILE * enc
Definition: encoding.c:64
static char * strerror(int errnum)
Definition: error.c:56
#define string
Definition: ctangleboot.c:111
#define length(c)
Definition: ctangleboot.c:65
#define root
Definition: ctangleboot.c:69
boolean eof(FILE *file)
Definition: eofeoln.c:11
int strncmp()
#define LLONG_MAX
Definition: config.h:179
#define sprintf
Definition: snprintf.c:44
#define isdigit(c)
Definition: snprintf.c:177
int getLength(char *s)
Definition: lengths.c:99
struct array Array
const int * pos
Definition: combiners.h:905
Definition: conf.py:1
float x
Definition: cordic.py:15
def ref(x)
Definition: pdf-org.py:104
#define version
Definition: nup.c:10
union value value
Definition: obx.h:44
static bool printing
Definition: pdftocairo.cc:235
#define res(length)
Definition: picttoppm.c:287
static int filter
Definition: pnmtopng.c:113
char * strtok_r(char *s, const char *delim, char **save_ptr)
@ formSignature
Definition: Form.h:59
int utf8ToUtf16(const char *utf8, uint16_t *utf16, int maxUtf16, int maxUtf8)
Definition: UTF.cc:608
int r
Definition: ppmqvga.c:68
static int offset
Definition: ppmtogif.c:642
time_t time()
struct stream_s stream
Definition: pts_fax.h:93
long long Goffset
Definition: gfile.h:76
#define errFileChangedSinceOpen
Definition: ErrorCodes.h:52
@ objInt64
Definition: Object.h:154
@ objHexString
Definition: Object.h:155
static PDFSubtypeConformance pdfConformanceFromString(GooString *pdfSubtypeVersion)
Definition: PDFDoc.cc:536
#define pdfIdLength
Definition: PDFDoc.cc:100
#define xrefSearchSize
Definition: PDFDoc.cc:107
static void addSignatureFieldsToVector(FormField *ff, std::vector< FormFieldSignature * > &res)
Definition: PDFDoc.cc:605
#define pdfdocLocker()
Definition: PDFDoc.cc:115
static PDFSubtypePart pdfPartFromString(PDFSubtype subtype, GooString *pdfSubtypeVersion)
Definition: PDFDoc.cc:476
static bool get_id(const GooString *encodedidstring, GooString *id)
Definition: PDFDoc.cc:789
#define linearizationSearchSize
Definition: PDFDoc.cc:102
#define headerSearchSize
Definition: PDFDoc.cc:97
PDFSubtypeConformance
Definition: PDFDoc.h:104
@ subtypeConfNull
Definition: PDFDoc.h:105
@ subtypeConfG
Definition: PDFDoc.h:108
@ subtypeConfNone
Definition: PDFDoc.h:113
@ subtypeConfB
Definition: PDFDoc.h:107
@ subtypeConfA
Definition: PDFDoc.h:106
@ subtypeConfP
Definition: PDFDoc.h:110
@ subtypeConfU
Definition: PDFDoc.h:112
@ subtypeConfPG
Definition: PDFDoc.h:111
@ subtypeConfN
Definition: PDFDoc.h:109
PDFWriteMode
Definition: PDFDoc.h:72
@ writeStandard
Definition: PDFDoc.h:73
@ writeForceRewrite
Definition: PDFDoc.h:74
PDFSubtype
Definition: PDFDoc.h:79
@ subtypeNone
Definition: PDFDoc.h:86
@ subtypePDFE
Definition: PDFDoc.h:82
@ subtypeNull
Definition: PDFDoc.h:80
@ subtypePDFX
Definition: PDFDoc.h:85
@ subtypePDFVT
Definition: PDFDoc.h:84
@ subtypePDFA
Definition: PDFDoc.h:81
@ subtypePDFUA
Definition: PDFDoc.h:83
PDFSubtypePart
Definition: PDFDoc.h:90
@ subtypePart1
Definition: PDFDoc.h:92
@ subtypePart7
Definition: PDFDoc.h:98
@ subtypePart5
Definition: PDFDoc.h:96
@ subtypePart6
Definition: PDFDoc.h:97
@ subtypePart4
Definition: PDFDoc.h:95
@ subtypePartNull
Definition: PDFDoc.h:91
@ subtypePart3
Definition: PDFDoc.h:94
@ subtypePart8
Definition: PDFDoc.h:99
@ subtypePartNone
Definition: PDFDoc.h:100
@ strCrypt
Definition: Stream.h:71
static bool combine(Unicode base, Unicode add, Unicode *out)
static auto annotDisplayDecideCbk
Definition: pdftoppm.cc:278
struct hints Hints
#define isspace(ch)
Definition: utype.h:87
static void digest(const WORD32 *m, WORD32 *d)
Definition: md5.c:89
#define rotate(D, num)
Definition: md5.c:38
#define str(s)
Definition: sh6.c:399
#define wchar_t
Definition: stddef.in.h:81
Definition: Object.h:37
int gen
Definition: Object.h:39
int num
Definition: Object.h:38
Definition: XRef.h:41
@ Updated
Definition: XRef.h:70
@ DontRewrite
Definition: XRef.h:75
@ Unencrypted
Definition: XRef.h:74
bool getFlag(Flag flag) const
Definition: XRef.h:78
int gen
Definition: XRef.h:43
XRefEntryType type
Definition: XRef.h:44
Definition: utils.c:300
Definition: filedef.h:30
Definition: edgelist.h:31
Definition: mendex.h:14
Definition: sh2.c:920
Definition: strexpr.c:21
#define FILE
Definition: t1stdio.h:34
ch
Definition: t4ht.c:1443
int j
Definition: t4ht.c:1589
#define key
Definition: tex2xindy.c:753
found
Definition: tex4ht.c:5000
page
Definition: tex4ht.c:3916
@ L
Definition: ubidiimp.h:45
const char * fileName
Definition: ugrep.cpp:52
Definition: obx.h:51
@ part
Definition: preamble.c:52
#define errorCode
Definition: xmlparse.c:601