From e3ec3d8e589335cca076d620cc98741cf1c73f98 Mon Sep 17 00:00:00 2001 From: Luigi Scarso <luigi.scarso@gmail.com> Date: Mon, 15 Jan 2018 14:13:47 +0000 Subject: [PATCH] delete missed files --- .../poppler/poppler-src/poppler/Lexer.cc.orig | 641 ------ .../poppler/poppler-src/poppler/Object.h.orig | 416 ---- .../poppler/poppler-src/poppler/Object.h~ | 416 ---- .../poppler-src/poppler/PDFDoc.cc.orig | 1985 ----------------- .../poppler/poppler-src/poppler/PDFDoc.cc~ | 1985 ----------------- 5 files changed, 5443 deletions(-) delete mode 100644 source/libs/poppler/poppler-src/poppler/Lexer.cc.orig delete mode 100644 source/libs/poppler/poppler-src/poppler/Object.h.orig delete mode 100644 source/libs/poppler/poppler-src/poppler/Object.h~ delete mode 100644 source/libs/poppler/poppler-src/poppler/PDFDoc.cc.orig delete mode 100644 source/libs/poppler/poppler-src/poppler/PDFDoc.cc~ diff --git a/source/libs/poppler/poppler-src/poppler/Lexer.cc.orig b/source/libs/poppler/poppler-src/poppler/Lexer.cc.orig deleted file mode 100644 index d2329b536..000000000 --- a/source/libs/poppler/poppler-src/poppler/Lexer.cc.orig +++ /dev/null @@ -1,641 +0,0 @@ -//======================================================================== -// -// Lexer.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -//======================================================================== -// -// Modified under the Poppler project - http://poppler.freedesktop.org -// -// All changes made under the Poppler project to this file are licensed -// under GPL version 2 or later -// -// Copyright (C) 2006-2010, 2012-2014, 2017 Albert Astals Cid <aacid@kde.org> -// Copyright (C) 2006 Krzysztof Kowalczyk <kkowalczyk@gmail.com> -// Copyright (C) 2010 Carlos Garcia Campos <carlosgc@gnome.org> -// Copyright (C) 2012, 2013 Adrian Johnson <ajohnson@redneon.com> -// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de> -// -// To see a description of the changes please see the Changelog file that -// came with your tarball or type make ChangeLog if you are building from git -// -//======================================================================== - -#include <config.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <limits.h> -#include <ctype.h> -#include "Lexer.h" -#include "Error.h" -#include "XRef.h" - -//------------------------------------------------------------------------ - -// A '1' in this array means the character is white space. A '1' or -// '2' means the character ends a name or command. -static const char specialChars[256] = { - 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, // 0x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1x - 1, 0, 0, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0, 0, 0, 2, // 2x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, // 3x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 5x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 2, 0, 0, // 7x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9x - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ax - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // bx - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // cx - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // dx - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // ex - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 // fx -}; - -static const int IntegerSafeLimit = (INT_MAX - 9) / 10; -static const long long LongLongSafeLimit = (LLONG_MAX - 9) / 10; - -//------------------------------------------------------------------------ -// Lexer -//------------------------------------------------------------------------ - -Lexer::Lexer(XRef *xrefA, Stream *str) { - lookCharLastValueCached = LOOK_VALUE_NOT_CACHED; - xref = xrefA; - - curStr = Object(str); - streams = new Array(xref); - streams->add(curStr.copy()); - strPtr = 0; - freeArray = gTrue; - curStr.streamReset(); -} - -Lexer::Lexer(XRef *xrefA, Object *obj) { - lookCharLastValueCached = LOOK_VALUE_NOT_CACHED; - xref = xrefA; - - if (obj->isStream()) { - Object obj2; - streams = new Array(xref); - freeArray = gTrue; - streams->add(obj->copy()); - } else { - streams = obj->getArray(); - freeArray = gFalse; - } - strPtr = 0; - if (streams->getLength() > 0) { - curStr = streams->get(strPtr); - curStr.streamReset(); - } -} - -Lexer::~Lexer() { - if (!curStr.isNone()) { - curStr.streamClose(); - } - if (freeArray) { - delete streams; - } -} - -int Lexer::getChar(GBool comesFromLook) { - int c; - - if (LOOK_VALUE_NOT_CACHED != lookCharLastValueCached) { - c = lookCharLastValueCached; - lookCharLastValueCached = LOOK_VALUE_NOT_CACHED; - return c; - } - - c = EOF; - while (!curStr.isNone() && (c = curStr.streamGetChar()) == EOF) { - if (comesFromLook == gTrue) { - return EOF; - } else { - curStr.streamClose(); - curStr = Object(); - ++strPtr; - if (strPtr < streams->getLength()) { - curStr = streams->get(strPtr); - curStr.streamReset(); - } - } - } - return c; -} - -int Lexer::lookChar() { - - if (LOOK_VALUE_NOT_CACHED != lookCharLastValueCached) { - return lookCharLastValueCached; - } - lookCharLastValueCached = getChar(gTrue); - if (lookCharLastValueCached == EOF) { - lookCharLastValueCached = LOOK_VALUE_NOT_CACHED; - return EOF; - } else { - return lookCharLastValueCached; - } -} - -Object Lexer::getObj(int objNum) { - char *p; - int c, c2; - GBool comment, neg, done, overflownInteger, overflownLongLong; - int numParen; - int xi; - long long xll = 0; - double xf = 0, scale; - GooString *s; - int n, m; - - // skip whitespace and comments - comment = gFalse; - while (1) { - if ((c = getChar()) == EOF) { - return Object(objEOF); - } - if (comment) { - if (c == '\r' || c == '\n') - comment = gFalse; - } else if (c == '%') { - comment = gTrue; - } else if (specialChars[c] != 1) { - break; - } - } - - // start reading token - switch (c) { - - // number - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case '+': case '-': case '.': - overflownInteger = gFalse; - overflownLongLong = gFalse; - neg = gFalse; - xi = 0; - if (c == '-') { - neg = gTrue; - } else if (c == '.') { - goto doReal; - } else if (c != '+') { - xi = c - '0'; - } - while (1) { - c = lookChar(); - if (isdigit(c)) { - getChar(); - if (unlikely(overflownLongLong)) { - xf = xf * 10.0 + (c - '0'); - } else if (unlikely (overflownInteger)) { - if (unlikely(xll > LongLongSafeLimit) && - (xll > (LLONG_MAX - (c - '0')) / 10.0)) { - overflownLongLong = gTrue; - xf = xll * 10.0 + (c - '0'); - } else { - xll = xll * 10 + (c - '0'); - } - } else { - if (unlikely(xi > IntegerSafeLimit) && - (xi > (INT_MAX - (c - '0')) / 10.0)) { - overflownInteger = gTrue; - xll = xi * 10LL + (c - '0'); - } else { - xi = xi * 10 + (c - '0'); - } - } - } else if (c == '.') { - getChar(); - goto doReal; - } else { - break; - } - } - if (neg) { - xi = -xi; - xll = -xll; - xf = -xf; - } - if (unlikely(overflownInteger)) { - if (overflownLongLong) { - return Object(xf); - } else { - if (unlikely(xll == INT_MIN)) { - return Object(static_cast<int>(INT_MIN)); - } else { - return Object(xll); - } - } - } else { - return Object(xi); - } - break; - doReal: - if (likely(!overflownInteger)) { - xf = xi; - } else if (!overflownLongLong) { - xf = xll; - } - scale = 0.1; - while (1) { - c = lookChar(); - if (c == '-') { - // ignore minus signs in the middle of numbers to match - // Adobe's behavior - error(errSyntaxWarning, getPos(), "Badly formatted number"); - getChar(); - continue; - } - if (!isdigit(c)) { - break; - } - getChar(); - xf = xf + scale * (c - '0'); - scale *= 0.1; - } - if (neg) { - xf = -xf; - } - return Object(xf); - break; - - // string - case '(': - p = tokBuf; - n = 0; - numParen = 1; - done = gFalse; - s = NULL; - do { - c2 = EOF; - switch (c = getChar()) { - - case EOF: -#if 0 - // This breaks some PDF files, e.g., ones from Photoshop. - case '\r': - case '\n': -#endif - error(errSyntaxError, getPos(), "Unterminated string"); - done = gTrue; - break; - - case '(': - ++numParen; - c2 = c; - break; - - case ')': - if (--numParen == 0) { - done = gTrue; - } else { - c2 = c; - } - break; - - case '\\': - switch (c = getChar()) { - case 'n': - c2 = '\n'; - break; - case 'r': - c2 = '\r'; - break; - case 't': - c2 = '\t'; - break; - case 'b': - c2 = '\b'; - break; - case 'f': - c2 = '\f'; - break; - case '\\': - case '(': - case ')': - c2 = c; - break; - case '0': case '1': case '2': case '3': - case '4': case '5': case '6': case '7': - c2 = c - '0'; - c = lookChar(); - if (c >= '0' && c <= '7') { - getChar(); - c2 = (c2 << 3) + (c - '0'); - c = lookChar(); - if (c >= '0' && c <= '7') { - getChar(); - c2 = (c2 << 3) + (c - '0'); - } - } - break; - case '\r': - c = lookChar(); - if (c == '\n') { - getChar(); - } - break; - case '\n': - break; - case EOF: - error(errSyntaxError, getPos(), "Unterminated string"); - done = gTrue; - break; - default: - c2 = c; - break; - } - break; - - default: - c2 = c; - break; - } - - if (c2 != EOF) { - if (n == tokBufSize) { - if (!s) - s = new GooString(tokBuf, tokBufSize); - else - s->append(tokBuf, tokBufSize); - p = tokBuf; - n = 0; - - // we are growing see if the document is not malformed and we are growing too much - if (objNum > 0 && xref != NULL) - { - int newObjNum = xref->getNumEntry(curStr.streamGetPos()); - if (newObjNum != objNum) - { - error(errSyntaxError, getPos(), "Unterminated string"); - done = gTrue; - delete s; - n = -2; - } - } - } - *p++ = (char)c2; - ++n; - } - } while (!done); - if (n >= 0) { - if (!s) - s = new GooString(tokBuf, n); - else - s->append(tokBuf, n); - return Object(s); - } else { - return Object(objEOF); - } - break; - - // name - case '/': - p = tokBuf; - n = 0; - s = NULL; - while ((c = lookChar()) != EOF && !specialChars[c]) { - getChar(); - if (c == '#') { - c2 = lookChar(); - if (c2 >= '0' && c2 <= '9') { - c = c2 - '0'; - } else if (c2 >= 'A' && c2 <= 'F') { - c = c2 - 'A' + 10; - } else if (c2 >= 'a' && c2 <= 'f') { - c = c2 - 'a' + 10; - } else { - goto notEscChar; - } - getChar(); - c <<= 4; - c2 = getChar(); - if (c2 >= '0' && c2 <= '9') { - c += c2 - '0'; - } else if (c2 >= 'A' && c2 <= 'F') { - c += c2 - 'A' + 10; - } else if (c2 >= 'a' && c2 <= 'f') { - c += c2 - 'a' + 10; - } else { - error(errSyntaxError, getPos(), "Illegal digit in hex char in name"); - } - } - notEscChar: - // the PDF spec claims that names are limited to 127 chars, but - // Distiller 8 will produce longer names, and Acrobat 8 will - // accept longer names - ++n; - if (n < tokBufSize) { - *p++ = c; - } else if (n == tokBufSize) { - error(errSyntaxError, getPos(), "Warning: name token is longer than what the specification says it can be"); - *p = c; - s = new GooString(tokBuf, n); - } else { - s->append((char)c); - } - } - if (n < tokBufSize) { - *p = '\0'; - return Object(objName, tokBuf); - } else { - Object obj(objName, s->getCString()); - delete s; - return obj; - } - break; - - // array punctuation - case '[': - case ']': - tokBuf[0] = c; - tokBuf[1] = '\0'; - return Object(objCmd, tokBuf); - break; - - // hex string or dict punctuation - case '<': - c = lookChar(); - - // dict punctuation - if (c == '<') { - getChar(); - tokBuf[0] = tokBuf[1] = '<'; - tokBuf[2] = '\0'; - return Object(objCmd, tokBuf); - - // hex string - } else { - p = tokBuf; - m = n = 0; - c2 = 0; - s = NULL; - while (1) { - c = getChar(); - if (c == '>') { - break; - } else if (c == EOF) { - error(errSyntaxError, getPos(), "Unterminated hex string"); - break; - } else if (specialChars[c] != 1) { - c2 = c2 << 4; - if (c >= '0' && c <= '9') - c2 += c - '0'; - else if (c >= 'A' && c <= 'F') - c2 += c - 'A' + 10; - else if (c >= 'a' && c <= 'f') - c2 += c - 'a' + 10; - else - error(errSyntaxError, getPos(), "Illegal character <{0:02x}> in hex string", c); - if (++m == 2) { - if (n == tokBufSize) { - if (!s) - s = new GooString(tokBuf, tokBufSize); - else - s->append(tokBuf, tokBufSize); - p = tokBuf; - n = 0; - } - *p++ = (char)c2; - ++n; - c2 = 0; - m = 0; - } - } - } - if (!s) - s = new GooString(tokBuf, n); - else - s->append(tokBuf, n); - if (m == 1) - s->append((char)(c2 << 4)); - return Object(s); - } - break; - - // dict punctuation - case '>': - c = lookChar(); - if (c == '>') { - getChar(); - tokBuf[0] = tokBuf[1] = '>'; - tokBuf[2] = '\0'; - return Object(objCmd, tokBuf); - } else { - error(errSyntaxError, getPos(), "Illegal character '>'"); - return Object(objError); - } - break; - - // error - case ')': - case '{': - case '}': - error(errSyntaxError, getPos(), "Illegal character '{0:c}'", c); - return Object(objError); - break; - - // command - default: - p = tokBuf; - *p++ = c; - n = 1; - while ((c = lookChar()) != EOF && !specialChars[c]) { - getChar(); - if (++n == tokBufSize) { - error(errSyntaxError, getPos(), "Command token too long"); - break; - } - *p++ = c; - } - *p = '\0'; - if (tokBuf[0] == 't' && !strcmp(tokBuf, "true")) { - return Object(gTrue); - } else if (tokBuf[0] == 'f' && !strcmp(tokBuf, "false")) { - return Object(gFalse); - } else if (tokBuf[0] == 'n' && !strcmp(tokBuf, "null")) { - return Object(objNull); - } else { - return Object(objCmd, tokBuf); - } - break; - } - - return Object(); -} - -Object Lexer::getObj(const char *cmdA, int objNum) { - char *p; - int c; - GBool comment; - int n; - - // skip whitespace and comments - comment = gFalse; - const char *cmd1 = tokBuf; - *tokBuf = 0; - while (strcmp(cmdA, cmd1) && (objNum < 0 || (xref && xref->getNumEntry(getPos()) == objNum))) { - while (1) { - if ((c = getChar()) == EOF) { - return Object(objEOF); - } - if (comment) { - if (c == '\r' || c == '\n') { - comment = gFalse; - } - } else if (c == '%') { - comment = gTrue; - } else if (specialChars[c] != 1) { - break; - } - } - p = tokBuf; - *p++ = c; - n = 1; - while ((c = lookChar()) != EOF && specialChars[c] == 0) { - getChar(); - if (++n == tokBufSize) { - break; - } - *p++ = c; - } - *p = '\0'; - } - - return Object(objCmd, tokBuf); -} - -void Lexer::skipToNextLine() { - int c; - - while (1) { - c = getChar(); - if (c == EOF || c == '\n') { - return; - } - if (c == '\r') { - if ((c = lookChar()) == '\n') { - getChar(); - } - return; - } - } -} - -GBool Lexer::isSpace(int c) { - return c >= 0 && c <= 0xff && specialChars[c] == 1; -} diff --git a/source/libs/poppler/poppler-src/poppler/Object.h.orig b/source/libs/poppler/poppler-src/poppler/Object.h.orig deleted file mode 100644 index f2ca20d15..000000000 --- a/source/libs/poppler/poppler-src/poppler/Object.h.orig +++ /dev/null @@ -1,416 +0,0 @@ -//======================================================================== -// -// Object.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -//======================================================================== -// -// Modified under the Poppler project - http://poppler.freedesktop.org -// -// All changes made under the Poppler project to this file are licensed -// under GPL version 2 or later -// -// Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org> -// Copyright (C) 2008 Kees Cook <kees@outflux.net> -// Copyright (C) 2008, 2010, 2017 Albert Astals Cid <aacid@kde.org> -// Copyright (C) 2009 Jakub Wilk <jwilk@jwilk.net> -// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it> -// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de> -// Copyright (C) 2013, 2017 Adrian Johnson <ajohnson@redneon.com> -// Copyright (C) 2013 Adrian Perez de Castro <aperez@igalia.com> -// Copyright (C) 2016 Jakub Alba <jakubalba@gmail.com> -// -// To see a description of the changes please see the Changelog file that -// came with your tarball or type make ChangeLog if you are building from git -// -//======================================================================== - -#ifndef OBJECT_H -#define OBJECT_H - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include <set> -#include <stdio.h> -#include <string.h> -#include <limits.h> -#include "goo/gtypes.h" -#include "goo/gmem.h" -#include "goo/GooString.h" -#include "goo/GooLikely.h" -#include "Error.h" - -#define OBJECT_TYPE_CHECK(wanted_type) \ - if (unlikely(type != wanted_type)) { \ - error(errInternal, 0, "Call to Object where the object was type {0:d}, " \ - "not the expected type {1:d}", type, wanted_type); \ - abort(); \ - } - -#define OBJECT_2TYPES_CHECK(wanted_type1, wanted_type2) \ - if (unlikely(type != wanted_type1) && unlikely(type != wanted_type2)) { \ - error(errInternal, 0, "Call to Object where the object was type {0:d}, " \ - "not the expected type {1:d} or {2:d}", type, wanted_type1, wanted_type2); \ - abort(); \ - } - -#define OBJECT_3TYPES_CHECK(wanted_type1, wanted_type2, wanted_type3) \ - if (unlikely(type != wanted_type1) && unlikely(type != wanted_type2) && unlikely(type != wanted_type3)) { \ - error(errInternal, 0, "Call to Object where the object was type {0:d}, " \ - "not the expected type {1:d}, {2:d} or {3:d}", type, wanted_type1, wanted_type2, wanted_type3); \ - abort(); \ - } - -#define CHECK_NOT_DEAD \ - if (unlikely(type == objDead)) { \ - error(errInternal, 0, "Call to dead object"); \ - abort(); \ - } - -class XRef; -class Array; -class Dict; -class Stream; - -//------------------------------------------------------------------------ -// Ref -//------------------------------------------------------------------------ - -struct Ref { - int num; // object number - int gen; // generation number -}; - -//------------------------------------------------------------------------ -// object types -//------------------------------------------------------------------------ - -enum ObjType { - // simple objects - objBool, // boolean - objInt, // integer - objReal, // real - objString, // string - objName, // name - objNull, // null - - // complex objects - objArray, // array - objDict, // dictionary - objStream, // stream - objRef, // indirect reference - - // special objects - objCmd, // command name - objError, // error return from Lexer - objEOF, // end of file return from Lexer - objNone, // uninitialized object - - // poppler-only objects - objInt64, // integer with at least 64-bits - objDead // and object after shallowCopy -}; - -#define numObjTypes 16 // total number of object types - -//------------------------------------------------------------------------ -// Object -//------------------------------------------------------------------------ - -#ifdef DEBUG_MEM -#define initObj(t) free(); zeroUnion(); ++numAlloc[type = t] -#else -#define initObj(t) free(); zeroUnion(); type = t -#endif - -#ifdef DEBUG_MEM -#define constructObj(t) ++numAlloc[type = t] -#else -#define constructObj(t) type = t -#endif - -class Object { -public: - // clear the anonymous union as best we can -- clear at least a pointer - void zeroUnion() { this->cString = NULL; } - - // Default constructor. - Object(): - type(objNone) { zeroUnion(); } - ~Object(); - - explicit Object(GBool boolnA) - { constructObj(objBool); booln = boolnA; } - explicit Object(int intgA) - { constructObj(objInt); intg = intgA; } - explicit Object(ObjType typeA) - { constructObj(typeA); } - explicit Object(double realA) - { constructObj(objReal); real = realA; } - explicit Object(GooString *stringA) - { constructObj(objString); string = stringA; } - Object(ObjType typeA, const char *stringA) - { constructObj(typeA); cString = copyString(stringA); } - explicit Object(long long int64gA) - { constructObj(objInt64); int64g = int64gA; } - explicit Object(Array *arrayA) - { constructObj(objArray); array = arrayA; } - explicit Object(Dict *dictA) - { constructObj(objDict); dict = dictA; } - explicit Object(Stream *streamA) - { constructObj(objStream); stream = streamA; } - Object(int numA, int genA) - { constructObj(objRef); ref.num = numA; ref.gen = genA; } - template<typename T> Object(T) = delete; - - Object(Object&& other); - Object& operator=(Object&& other); - - Object &operator=(const Object &other) = delete; - Object(const Object &other) = delete; - - // Set object to null. - void setToNull() { initObj(objNull); } - - // Copy this to obj - Object copy() const; - - // If object is a Ref, fetch and return the referenced object. - // Otherwise, return a copy of the object. - Object fetch(XRef *xref, int recursion = 0) const; - - // Type checking. - ObjType getType() const { CHECK_NOT_DEAD; return type; } - GBool isBool() const { CHECK_NOT_DEAD; return type == objBool; } - GBool isInt() const { CHECK_NOT_DEAD; return type == objInt; } - GBool isReal() const { CHECK_NOT_DEAD; return type == objReal; } - GBool isNum() const { CHECK_NOT_DEAD; return type == objInt || type == objReal || type == objInt64; } - GBool isString() const { CHECK_NOT_DEAD; return type == objString; } - GBool isName() const { CHECK_NOT_DEAD; return type == objName; } - GBool isNull() const { CHECK_NOT_DEAD; return type == objNull; } - GBool isArray() const { CHECK_NOT_DEAD; return type == objArray; } - GBool isDict() const { CHECK_NOT_DEAD; return type == objDict; } - GBool isStream() const { CHECK_NOT_DEAD; return type == objStream; } - GBool isRef() const { CHECK_NOT_DEAD; return type == objRef; } - GBool isCmd() const { CHECK_NOT_DEAD; return type == objCmd; } - GBool isError() const { CHECK_NOT_DEAD; return type == objError; } - GBool isEOF() const { CHECK_NOT_DEAD; return type == objEOF; } - GBool isNone() const { CHECK_NOT_DEAD; return type == objNone; } - GBool isInt64() const { CHECK_NOT_DEAD; return type == objInt64; } - GBool isIntOrInt64() const { CHECK_NOT_DEAD; return type == objInt || type == objInt64; } - - // Special type checking. - GBool isName(const char *nameA) const - { return type == objName && !strcmp(cString, nameA); } - GBool isDict(const char *dictType) const; - GBool isStream(char *dictType) const; - GBool isCmd(const char *cmdA) const - { return type == objCmd && !strcmp(cString, cmdA); } - - // Accessors. - GBool getBool() const { OBJECT_TYPE_CHECK(objBool); return booln; } - int getInt() const { OBJECT_TYPE_CHECK(objInt); return intg; } - double getReal() const { OBJECT_TYPE_CHECK(objReal); return real; } - - // Note: integers larger than 2^53 can not be exactly represented by a double. - // Where the exact value of integers up to 2^63 is required, use isInt64()/getInt64(). - double getNum() const { OBJECT_3TYPES_CHECK(objInt, objInt64, objReal); - return type == objInt ? (double)intg : type == objInt64 ? (double)int64g : real; } - double getNum(bool *ok) const { - if (unlikely(type != objInt && type != objInt64 && type != objReal)) { - *ok = false; - return 0.; - } - return type == objInt ? (double)intg : type == objInt64 ? (double)int64g : real; - } - GooString *getString() const { OBJECT_TYPE_CHECK(objString); return string; } - // After takeString() the only method that should be called for the object is free() - // because the object it's not expected to have a NULL string. - GooString *takeString() { - OBJECT_TYPE_CHECK(objString); GooString *s = string; string = NULL; return s; } - char *getName() const { OBJECT_TYPE_CHECK(objName); return cString; } - Array *getArray() const { OBJECT_TYPE_CHECK(objArray); return array; } - Dict *getDict() const { OBJECT_TYPE_CHECK(objDict); return dict; } - Stream *getStream() const { OBJECT_TYPE_CHECK(objStream); return stream; } - Ref getRef() const { OBJECT_TYPE_CHECK(objRef); return ref; } - int getRefNum() const { OBJECT_TYPE_CHECK(objRef); return ref.num; } - int getRefGen() const { OBJECT_TYPE_CHECK(objRef); return ref.gen; } - char *getCmd() const { OBJECT_TYPE_CHECK(objCmd); return cString; } - long long getInt64() const { OBJECT_TYPE_CHECK(objInt64); return int64g; } - long long getIntOrInt64() const { OBJECT_2TYPES_CHECK(objInt, objInt64); - return type == objInt ? intg : int64g; } - - // Array accessors. - int arrayGetLength() const; - void arrayAdd(Object &&elem); - void arrayRemove(int i); - Object arrayGet(int i, int recursion) const; - Object arrayGetNF(int i) const; - - // Dict accessors. - int dictGetLength() const; - void dictAdd(char *key, Object &&val); - void dictSet(const char *key, Object &&val); - void dictRemove(const char *key); - GBool dictIs(const char *dictType) const; - Object dictLookup(const char *key, int recursion = 0) const; - Object dictLookupNF(const char *key) const; - char *dictGetKey(int i) const; - Object dictGetVal(int i) const; - Object dictGetValNF(int i) const; - - // Stream accessors. - GBool streamIs(char *dictType) const; - void streamReset(); - void streamClose(); - int streamGetChar() const; - int streamGetChars(int nChars, Guchar *buffer) const; - int streamLookChar() const; - char *streamGetLine(char *buf, int size) const; - Goffset streamGetPos() const; - void streamSetPos(Goffset pos, int dir = 0); - Dict *streamGetDict() const; - - // Output. - const char *getTypeName() const; - void print(FILE *f = stdout) const; - - // Memory testing. - static void memCheck(FILE *f); - -private: - friend class Array; // Needs free and initNullAfterMalloc - friend class Dict; // Needs free and initNullAfterMalloc - friend class XRef; // Needs free and initNullAfterMalloc - - // Free object contents. - void free(); - - // Only use if are mallocing Objects - void initNullAfterMalloc() { constructObj(objNull); } - - ObjType type; // object type - union { // value for each type: - GBool booln; // boolean - int intg; // integer - long long int64g; // 64-bit integer - double real; // real - GooString *string; // string - char *cString; // name or command, depending on objType - Array *array; // array - Dict *dict; // dictionary - Stream *stream; // stream - Ref ref; // indirect reference - }; - -#ifdef DEBUG_MEM - static int // number of each type of object - numAlloc[numObjTypes]; // currently allocated -#endif -}; - -//------------------------------------------------------------------------ -// Array accessors. -//------------------------------------------------------------------------ - -#include "Array.h" - -inline int Object::arrayGetLength() const - { OBJECT_TYPE_CHECK(objArray); return array->getLength(); } - -inline void Object::arrayAdd(Object &&elem) - { OBJECT_TYPE_CHECK(objArray); array->add(std::move(elem)); } - -inline void Object::arrayRemove(int i) - { OBJECT_TYPE_CHECK(objArray); array->remove(i); } - -inline Object Object::arrayGet(int i, int recursion = 0) const - { OBJECT_TYPE_CHECK(objArray); return array->get(i, recursion); } - -inline Object Object::arrayGetNF(int i) const - { OBJECT_TYPE_CHECK(objArray); return array->getNF(i); } - -//------------------------------------------------------------------------ -// Dict accessors. -//------------------------------------------------------------------------ - -#include "Dict.h" - -inline int Object::dictGetLength() const - { OBJECT_TYPE_CHECK(objDict); return dict->getLength(); } - -inline void Object::dictAdd(char *key, Object &&val) - { OBJECT_TYPE_CHECK(objDict); dict->add(key, std::move(val)); } - -inline void Object::dictSet(const char *key, Object &&val) - { OBJECT_TYPE_CHECK(objDict); dict->set(key, std::move(val)); } - -inline void Object::dictRemove(const char *key) - { OBJECT_TYPE_CHECK(objDict); dict->remove(key); } - -inline GBool Object::dictIs(const char *dictType) const - { OBJECT_TYPE_CHECK(objDict); return dict->is(dictType); } - -inline GBool Object::isDict(const char *dictType) const - { return type == objDict && dictIs(dictType); } - -inline Object Object::dictLookup(const char *key, int recursion) const - { OBJECT_TYPE_CHECK(objDict); return dict->lookup(key, recursion); } - -inline Object Object::dictLookupNF(const char *key) const - { OBJECT_TYPE_CHECK(objDict); return dict->lookupNF(key); } - -inline char *Object::dictGetKey(int i) const - { OBJECT_TYPE_CHECK(objDict); return dict->getKey(i); } - -inline Object Object::dictGetVal(int i) const - { OBJECT_TYPE_CHECK(objDict); return dict->getVal(i); } - -inline Object Object::dictGetValNF(int i) const - { OBJECT_TYPE_CHECK(objDict); return dict->getValNF(i); } - -//------------------------------------------------------------------------ -// Stream accessors. -//------------------------------------------------------------------------ - -#include "Stream.h" - -inline GBool Object::streamIs(char *dictType) const - { OBJECT_TYPE_CHECK(objStream); return stream->getDict()->is(dictType); } - -inline GBool Object::isStream(char *dictType) const - { return type == objStream && streamIs(dictType); } - -inline void Object::streamReset() - { OBJECT_TYPE_CHECK(objStream); stream->reset(); } - -inline void Object::streamClose() - { OBJECT_TYPE_CHECK(objStream); stream->close(); } - -inline int Object::streamGetChar() const - { OBJECT_TYPE_CHECK(objStream); return stream->getChar(); } - -inline int Object::streamGetChars(int nChars, Guchar *buffer) const - { OBJECT_TYPE_CHECK(objStream); return stream->doGetChars(nChars, buffer); } - -inline int Object::streamLookChar() const - { OBJECT_TYPE_CHECK(objStream); return stream->lookChar(); } - -inline char *Object::streamGetLine(char *buf, int size) const - { OBJECT_TYPE_CHECK(objStream); return stream->getLine(buf, size); } - -inline Goffset Object::streamGetPos() const - { OBJECT_TYPE_CHECK(objStream); return stream->getPos(); } - -inline void Object::streamSetPos(Goffset pos, int dir) - { OBJECT_TYPE_CHECK(objStream); stream->setPos(pos, dir); } - -inline Dict *Object::streamGetDict() const - { OBJECT_TYPE_CHECK(objStream); return stream->getDict(); } - -#endif diff --git a/source/libs/poppler/poppler-src/poppler/Object.h~ b/source/libs/poppler/poppler-src/poppler/Object.h~ deleted file mode 100644 index f2ca20d15..000000000 --- a/source/libs/poppler/poppler-src/poppler/Object.h~ +++ /dev/null @@ -1,416 +0,0 @@ -//======================================================================== -// -// Object.h -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -//======================================================================== -// -// Modified under the Poppler project - http://poppler.freedesktop.org -// -// All changes made under the Poppler project to this file are licensed -// under GPL version 2 or later -// -// Copyright (C) 2007 Julien Rebetez <julienr@svn.gnome.org> -// Copyright (C) 2008 Kees Cook <kees@outflux.net> -// Copyright (C) 2008, 2010, 2017 Albert Astals Cid <aacid@kde.org> -// Copyright (C) 2009 Jakub Wilk <jwilk@jwilk.net> -// Copyright (C) 2012 Fabio D'Urso <fabiodurso@hotmail.it> -// Copyright (C) 2013 Thomas Freitag <Thomas.Freitag@alfa.de> -// Copyright (C) 2013, 2017 Adrian Johnson <ajohnson@redneon.com> -// Copyright (C) 2013 Adrian Perez de Castro <aperez@igalia.com> -// Copyright (C) 2016 Jakub Alba <jakubalba@gmail.com> -// -// To see a description of the changes please see the Changelog file that -// came with your tarball or type make ChangeLog if you are building from git -// -//======================================================================== - -#ifndef OBJECT_H -#define OBJECT_H - -#ifdef USE_GCC_PRAGMAS -#pragma interface -#endif - -#include <set> -#include <stdio.h> -#include <string.h> -#include <limits.h> -#include "goo/gtypes.h" -#include "goo/gmem.h" -#include "goo/GooString.h" -#include "goo/GooLikely.h" -#include "Error.h" - -#define OBJECT_TYPE_CHECK(wanted_type) \ - if (unlikely(type != wanted_type)) { \ - error(errInternal, 0, "Call to Object where the object was type {0:d}, " \ - "not the expected type {1:d}", type, wanted_type); \ - abort(); \ - } - -#define OBJECT_2TYPES_CHECK(wanted_type1, wanted_type2) \ - if (unlikely(type != wanted_type1) && unlikely(type != wanted_type2)) { \ - error(errInternal, 0, "Call to Object where the object was type {0:d}, " \ - "not the expected type {1:d} or {2:d}", type, wanted_type1, wanted_type2); \ - abort(); \ - } - -#define OBJECT_3TYPES_CHECK(wanted_type1, wanted_type2, wanted_type3) \ - if (unlikely(type != wanted_type1) && unlikely(type != wanted_type2) && unlikely(type != wanted_type3)) { \ - error(errInternal, 0, "Call to Object where the object was type {0:d}, " \ - "not the expected type {1:d}, {2:d} or {3:d}", type, wanted_type1, wanted_type2, wanted_type3); \ - abort(); \ - } - -#define CHECK_NOT_DEAD \ - if (unlikely(type == objDead)) { \ - error(errInternal, 0, "Call to dead object"); \ - abort(); \ - } - -class XRef; -class Array; -class Dict; -class Stream; - -//------------------------------------------------------------------------ -// Ref -//------------------------------------------------------------------------ - -struct Ref { - int num; // object number - int gen; // generation number -}; - -//------------------------------------------------------------------------ -// object types -//------------------------------------------------------------------------ - -enum ObjType { - // simple objects - objBool, // boolean - objInt, // integer - objReal, // real - objString, // string - objName, // name - objNull, // null - - // complex objects - objArray, // array - objDict, // dictionary - objStream, // stream - objRef, // indirect reference - - // special objects - objCmd, // command name - objError, // error return from Lexer - objEOF, // end of file return from Lexer - objNone, // uninitialized object - - // poppler-only objects - objInt64, // integer with at least 64-bits - objDead // and object after shallowCopy -}; - -#define numObjTypes 16 // total number of object types - -//------------------------------------------------------------------------ -// Object -//------------------------------------------------------------------------ - -#ifdef DEBUG_MEM -#define initObj(t) free(); zeroUnion(); ++numAlloc[type = t] -#else -#define initObj(t) free(); zeroUnion(); type = t -#endif - -#ifdef DEBUG_MEM -#define constructObj(t) ++numAlloc[type = t] -#else -#define constructObj(t) type = t -#endif - -class Object { -public: - // clear the anonymous union as best we can -- clear at least a pointer - void zeroUnion() { this->cString = NULL; } - - // Default constructor. - Object(): - type(objNone) { zeroUnion(); } - ~Object(); - - explicit Object(GBool boolnA) - { constructObj(objBool); booln = boolnA; } - explicit Object(int intgA) - { constructObj(objInt); intg = intgA; } - explicit Object(ObjType typeA) - { constructObj(typeA); } - explicit Object(double realA) - { constructObj(objReal); real = realA; } - explicit Object(GooString *stringA) - { constructObj(objString); string = stringA; } - Object(ObjType typeA, const char *stringA) - { constructObj(typeA); cString = copyString(stringA); } - explicit Object(long long int64gA) - { constructObj(objInt64); int64g = int64gA; } - explicit Object(Array *arrayA) - { constructObj(objArray); array = arrayA; } - explicit Object(Dict *dictA) - { constructObj(objDict); dict = dictA; } - explicit Object(Stream *streamA) - { constructObj(objStream); stream = streamA; } - Object(int numA, int genA) - { constructObj(objRef); ref.num = numA; ref.gen = genA; } - template<typename T> Object(T) = delete; - - Object(Object&& other); - Object& operator=(Object&& other); - - Object &operator=(const Object &other) = delete; - Object(const Object &other) = delete; - - // Set object to null. - void setToNull() { initObj(objNull); } - - // Copy this to obj - Object copy() const; - - // If object is a Ref, fetch and return the referenced object. - // Otherwise, return a copy of the object. - Object fetch(XRef *xref, int recursion = 0) const; - - // Type checking. - ObjType getType() const { CHECK_NOT_DEAD; return type; } - GBool isBool() const { CHECK_NOT_DEAD; return type == objBool; } - GBool isInt() const { CHECK_NOT_DEAD; return type == objInt; } - GBool isReal() const { CHECK_NOT_DEAD; return type == objReal; } - GBool isNum() const { CHECK_NOT_DEAD; return type == objInt || type == objReal || type == objInt64; } - GBool isString() const { CHECK_NOT_DEAD; return type == objString; } - GBool isName() const { CHECK_NOT_DEAD; return type == objName; } - GBool isNull() const { CHECK_NOT_DEAD; return type == objNull; } - GBool isArray() const { CHECK_NOT_DEAD; return type == objArray; } - GBool isDict() const { CHECK_NOT_DEAD; return type == objDict; } - GBool isStream() const { CHECK_NOT_DEAD; return type == objStream; } - GBool isRef() const { CHECK_NOT_DEAD; return type == objRef; } - GBool isCmd() const { CHECK_NOT_DEAD; return type == objCmd; } - GBool isError() const { CHECK_NOT_DEAD; return type == objError; } - GBool isEOF() const { CHECK_NOT_DEAD; return type == objEOF; } - GBool isNone() const { CHECK_NOT_DEAD; return type == objNone; } - GBool isInt64() const { CHECK_NOT_DEAD; return type == objInt64; } - GBool isIntOrInt64() const { CHECK_NOT_DEAD; return type == objInt || type == objInt64; } - - // Special type checking. - GBool isName(const char *nameA) const - { return type == objName && !strcmp(cString, nameA); } - GBool isDict(const char *dictType) const; - GBool isStream(char *dictType) const; - GBool isCmd(const char *cmdA) const - { return type == objCmd && !strcmp(cString, cmdA); } - - // Accessors. - GBool getBool() const { OBJECT_TYPE_CHECK(objBool); return booln; } - int getInt() const { OBJECT_TYPE_CHECK(objInt); return intg; } - double getReal() const { OBJECT_TYPE_CHECK(objReal); return real; } - - // Note: integers larger than 2^53 can not be exactly represented by a double. - // Where the exact value of integers up to 2^63 is required, use isInt64()/getInt64(). - double getNum() const { OBJECT_3TYPES_CHECK(objInt, objInt64, objReal); - return type == objInt ? (double)intg : type == objInt64 ? (double)int64g : real; } - double getNum(bool *ok) const { - if (unlikely(type != objInt && type != objInt64 && type != objReal)) { - *ok = false; - return 0.; - } - return type == objInt ? (double)intg : type == objInt64 ? (double)int64g : real; - } - GooString *getString() const { OBJECT_TYPE_CHECK(objString); return string; } - // After takeString() the only method that should be called for the object is free() - // because the object it's not expected to have a NULL string. - GooString *takeString() { - OBJECT_TYPE_CHECK(objString); GooString *s = string; string = NULL; return s; } - char *getName() const { OBJECT_TYPE_CHECK(objName); return cString; } - Array *getArray() const { OBJECT_TYPE_CHECK(objArray); return array; } - Dict *getDict() const { OBJECT_TYPE_CHECK(objDict); return dict; } - Stream *getStream() const { OBJECT_TYPE_CHECK(objStream); return stream; } - Ref getRef() const { OBJECT_TYPE_CHECK(objRef); return ref; } - int getRefNum() const { OBJECT_TYPE_CHECK(objRef); return ref.num; } - int getRefGen() const { OBJECT_TYPE_CHECK(objRef); return ref.gen; } - char *getCmd() const { OBJECT_TYPE_CHECK(objCmd); return cString; } - long long getInt64() const { OBJECT_TYPE_CHECK(objInt64); return int64g; } - long long getIntOrInt64() const { OBJECT_2TYPES_CHECK(objInt, objInt64); - return type == objInt ? intg : int64g; } - - // Array accessors. - int arrayGetLength() const; - void arrayAdd(Object &&elem); - void arrayRemove(int i); - Object arrayGet(int i, int recursion) const; - Object arrayGetNF(int i) const; - - // Dict accessors. - int dictGetLength() const; - void dictAdd(char *key, Object &&val); - void dictSet(const char *key, Object &&val); - void dictRemove(const char *key); - GBool dictIs(const char *dictType) const; - Object dictLookup(const char *key, int recursion = 0) const; - Object dictLookupNF(const char *key) const; - char *dictGetKey(int i) const; - Object dictGetVal(int i) const; - Object dictGetValNF(int i) const; - - // Stream accessors. - GBool streamIs(char *dictType) const; - void streamReset(); - void streamClose(); - int streamGetChar() const; - int streamGetChars(int nChars, Guchar *buffer) const; - int streamLookChar() const; - char *streamGetLine(char *buf, int size) const; - Goffset streamGetPos() const; - void streamSetPos(Goffset pos, int dir = 0); - Dict *streamGetDict() const; - - // Output. - const char *getTypeName() const; - void print(FILE *f = stdout) const; - - // Memory testing. - static void memCheck(FILE *f); - -private: - friend class Array; // Needs free and initNullAfterMalloc - friend class Dict; // Needs free and initNullAfterMalloc - friend class XRef; // Needs free and initNullAfterMalloc - - // Free object contents. - void free(); - - // Only use if are mallocing Objects - void initNullAfterMalloc() { constructObj(objNull); } - - ObjType type; // object type - union { // value for each type: - GBool booln; // boolean - int intg; // integer - long long int64g; // 64-bit integer - double real; // real - GooString *string; // string - char *cString; // name or command, depending on objType - Array *array; // array - Dict *dict; // dictionary - Stream *stream; // stream - Ref ref; // indirect reference - }; - -#ifdef DEBUG_MEM - static int // number of each type of object - numAlloc[numObjTypes]; // currently allocated -#endif -}; - -//------------------------------------------------------------------------ -// Array accessors. -//------------------------------------------------------------------------ - -#include "Array.h" - -inline int Object::arrayGetLength() const - { OBJECT_TYPE_CHECK(objArray); return array->getLength(); } - -inline void Object::arrayAdd(Object &&elem) - { OBJECT_TYPE_CHECK(objArray); array->add(std::move(elem)); } - -inline void Object::arrayRemove(int i) - { OBJECT_TYPE_CHECK(objArray); array->remove(i); } - -inline Object Object::arrayGet(int i, int recursion = 0) const - { OBJECT_TYPE_CHECK(objArray); return array->get(i, recursion); } - -inline Object Object::arrayGetNF(int i) const - { OBJECT_TYPE_CHECK(objArray); return array->getNF(i); } - -//------------------------------------------------------------------------ -// Dict accessors. -//------------------------------------------------------------------------ - -#include "Dict.h" - -inline int Object::dictGetLength() const - { OBJECT_TYPE_CHECK(objDict); return dict->getLength(); } - -inline void Object::dictAdd(char *key, Object &&val) - { OBJECT_TYPE_CHECK(objDict); dict->add(key, std::move(val)); } - -inline void Object::dictSet(const char *key, Object &&val) - { OBJECT_TYPE_CHECK(objDict); dict->set(key, std::move(val)); } - -inline void Object::dictRemove(const char *key) - { OBJECT_TYPE_CHECK(objDict); dict->remove(key); } - -inline GBool Object::dictIs(const char *dictType) const - { OBJECT_TYPE_CHECK(objDict); return dict->is(dictType); } - -inline GBool Object::isDict(const char *dictType) const - { return type == objDict && dictIs(dictType); } - -inline Object Object::dictLookup(const char *key, int recursion) const - { OBJECT_TYPE_CHECK(objDict); return dict->lookup(key, recursion); } - -inline Object Object::dictLookupNF(const char *key) const - { OBJECT_TYPE_CHECK(objDict); return dict->lookupNF(key); } - -inline char *Object::dictGetKey(int i) const - { OBJECT_TYPE_CHECK(objDict); return dict->getKey(i); } - -inline Object Object::dictGetVal(int i) const - { OBJECT_TYPE_CHECK(objDict); return dict->getVal(i); } - -inline Object Object::dictGetValNF(int i) const - { OBJECT_TYPE_CHECK(objDict); return dict->getValNF(i); } - -//------------------------------------------------------------------------ -// Stream accessors. -//------------------------------------------------------------------------ - -#include "Stream.h" - -inline GBool Object::streamIs(char *dictType) const - { OBJECT_TYPE_CHECK(objStream); return stream->getDict()->is(dictType); } - -inline GBool Object::isStream(char *dictType) const - { return type == objStream && streamIs(dictType); } - -inline void Object::streamReset() - { OBJECT_TYPE_CHECK(objStream); stream->reset(); } - -inline void Object::streamClose() - { OBJECT_TYPE_CHECK(objStream); stream->close(); } - -inline int Object::streamGetChar() const - { OBJECT_TYPE_CHECK(objStream); return stream->getChar(); } - -inline int Object::streamGetChars(int nChars, Guchar *buffer) const - { OBJECT_TYPE_CHECK(objStream); return stream->doGetChars(nChars, buffer); } - -inline int Object::streamLookChar() const - { OBJECT_TYPE_CHECK(objStream); return stream->lookChar(); } - -inline char *Object::streamGetLine(char *buf, int size) const - { OBJECT_TYPE_CHECK(objStream); return stream->getLine(buf, size); } - -inline Goffset Object::streamGetPos() const - { OBJECT_TYPE_CHECK(objStream); return stream->getPos(); } - -inline void Object::streamSetPos(Goffset pos, int dir) - { OBJECT_TYPE_CHECK(objStream); stream->setPos(pos, dir); } - -inline Dict *Object::streamGetDict() const - { OBJECT_TYPE_CHECK(objStream); return stream->getDict(); } - -#endif diff --git a/source/libs/poppler/poppler-src/poppler/PDFDoc.cc.orig b/source/libs/poppler/poppler-src/poppler/PDFDoc.cc.orig deleted file mode 100644 index 90f039d8e..000000000 --- a/source/libs/poppler/poppler-src/poppler/PDFDoc.cc.orig +++ /dev/null @@ -1,1985 +0,0 @@ -//======================================================================== -// -// PDFDoc.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -//======================================================================== -// -// Modified under the Poppler project - http://poppler.freedesktop.org -// -// All changes made under the Poppler project to this file are licensed -// under GPL version 2 or later -// -// Copyright (C) 2005, 2006, 2008 Brad Hards <bradh@frogmouth.net> -// Copyright (C) 2005, 2007-2009, 2011-2017 Albert Astals Cid <aacid@kde.org> -// Copyright (C) 2008 Julien Rebetez <julienr@svn.gnome.org> -// Copyright (C) 2008, 2010 Pino Toscano <pino@kde.org> -// Copyright (C) 2008, 2010, 2011 Carlos Garcia Campos <carlosgc@gnome.org> -// Copyright (C) 2009 Eric Toombs <ewtoombs@uwaterloo.ca> -// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net> -// Copyright (C) 2009, 2011 Axel Struebing <axel.struebing@freenet.de> -// Copyright (C) 2010-2012, 2014 Hib Eris <hib@hiberis.nl> -// Copyright (C) 2010 Jakub Wilk <jwilk@jwilk.net> -// Copyright (C) 2010 Ilya Gorenbein <igorenbein@finjan.com> -// Copyright (C) 2010 Srinivas Adicherla <srinivas.adicherla@geodesic.com> -// Copyright (C) 2010 Philip Lorenz <lorenzph+freedesktop@gmail.com> -// Copyright (C) 2011-2016 Thomas Freitag <Thomas.Freitag@alfa.de> -// Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it> -// Copyright (C) 2013, 2014, 2017 Adrian Johnson <ajohnson@redneon.com> -// Copyright (C) 2013 Adam Reichold <adamreichold@myopera.com> -// Copyright (C) 2014 Bogdan Cristea <cristeab@gmail.com> -// Copyright (C) 2015 Li Junling <lijunling@sina.com> -// Copyright (C) 2015 André Guerreiro <aguerreiro1985@gmail.com> -// Copyright (C) 2015 André Esser <bepandre@hotmail.com> -// Copyright (C) 2016 Jakub Alba <jakubalba@gmail.com> -// Copyright (C) 2017 Jean Ghali <jghali@libertysurf.fr> -// -// To see a description of the changes please see the Changelog file that -// came with your tarball or type make ChangeLog if you are building from git -// -//======================================================================== - -#include <config.h> -#include <poppler-config.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include <ctype.h> -#include <locale.h> -#include <stdio.h> -#include <errno.h> -#include <limits.h> -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <time.h> -#include <sys/stat.h> -#include "goo/glibc.h" -#include "goo/gstrtod.h" -#include "goo/GooString.h" -#include "goo/gfile.h" -#include "poppler-config.h" -#include "GlobalParams.h" -#include "Page.h" -#include "Catalog.h" -#include "Stream.h" -#include "XRef.h" -#include "Linearization.h" -#include "Link.h" -#include "OutputDev.h" -#include "Error.h" -#include "ErrorCodes.h" -#include "Lexer.h" -#include "Parser.h" -#include "SecurityHandler.h" -#include "Decrypt.h" -#ifndef DISABLE_OUTLINE -#include "Outline.h" -#endif -#include "PDFDoc.h" -#include "Hints.h" -#include "UTF.h" - -#ifdef MULTITHREADED -# define pdfdocLocker() MutexLocker locker(&mutex) -#else -# define pdfdocLocker() -#endif - -//------------------------------------------------------------------------ - -#define headerSearchSize 1024 // read this many bytes at beginning of - // file to look for '%PDF' -#define pdfIdLength 32 // PDF Document IDs (PermanentId, UpdateId) length - -#define linearizationSearchSize 1024 // read this many bytes at beginning of - // file to look for linearization - // dictionary - -#define xrefSearchSize 1024 // read this many bytes at end of file - // to look for 'startxref' - -//------------------------------------------------------------------------ -// PDFDoc -//------------------------------------------------------------------------ - -void PDFDoc::init() -{ -#ifdef MULTITHREADED - gInitMutex(&mutex); -#endif - ok = gFalse; - errCode = errNone; - fileName = NULL; - file = NULL; - str = NULL; - xref = NULL; - linearization = NULL; - catalog = NULL; - hints = NULL; -#ifndef DISABLE_OUTLINE - outline = NULL; -#endif - startXRefPos = -1; - secHdlr = NULL; - pageCache = NULL; -} - -PDFDoc::PDFDoc() -{ - init(); -} - -PDFDoc::PDFDoc(GooString *fileNameA, GooString *ownerPassword, - GooString *userPassword, void *guiDataA) { -#ifdef _WIN32 - int n, i; -#endif - - init(); - - fileName = fileNameA; - guiData = guiDataA; -#ifdef _WIN32 - n = fileName->getLength(); - fileNameU = (wchar_t *)gmallocn(n + 1, sizeof(wchar_t)); - for (i = 0; i < n; ++i) { - fileNameU[i] = (wchar_t)(fileName->getChar(i) & 0xff); - } - fileNameU[n] = L'\0'; -#endif - - // try to open file -#ifdef _WIN32 - wchar_t *wFileName = (wchar_t*)utf8ToUtf16(fileName->getCString()); - file = GooFile::open(wFileName); - gfree(wFileName); -#else - file = GooFile::open(fileName); -#endif - if (file == NULL) { - // fopen() has failed. - // Keep a copy of the errno returned by fopen so that it can be - // referred to later. - fopenErrno = errno; - error(errIO, -1, "Couldn't open file '{0:t}': {1:s}.", fileName, strerror(errno)); - errCode = errOpenFile; - return; - } - - // create stream - str = new FileStream(file, 0, gFalse, file->size(), Object(objNull)); - - ok = setup(ownerPassword, userPassword); -} - -#ifdef _WIN32 -PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GooString *ownerPassword, - GooString *userPassword, void *guiDataA) { - OSVERSIONINFO version; - int i; - - init(); - - guiData = guiDataA; - - // save both Unicode and 8-bit copies of the file name - fileName = new GooString(); - fileNameU = (wchar_t *)gmallocn(fileNameLen + 1, sizeof(wchar_t)); - for (i = 0; i < fileNameLen; ++i) { - fileName->append((char)fileNameA[i]); - fileNameU[i] = fileNameA[i]; - } - fileNameU[fileNameLen] = L'\0'; - - // try to open file - // NB: _wfopen is only available in NT - version.dwOSVersionInfoSize = sizeof(version); - GetVersionEx(&version); - if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { - file = GooFile::open(fileNameU); - } else { - file = GooFile::open(fileName); - } - if (!file) { - error(errIO, -1, "Couldn't open file '{0:t}'", fileName); - errCode = errOpenFile; - return; - } - - // create stream - str = new FileStream(file, 0, gFalse, file->size(), Object(objNull)); - - ok = setup(ownerPassword, userPassword); -} -#endif - -PDFDoc::PDFDoc(BaseStream *strA, GooString *ownerPassword, - GooString *userPassword, void *guiDataA) { -#ifdef _WIN32 - int n, i; -#endif - - init(); - guiData = guiDataA; - if (strA->getFileName()) { - fileName = strA->getFileName()->copy(); -#ifdef _WIN32 - n = fileName->getLength(); - fileNameU = (wchar_t *)gmallocn(n + 1, sizeof(wchar_t)); - for (i = 0; i < n; ++i) { - fileNameU[i] = (wchar_t)(fileName->getChar(i) & 0xff); - } - fileNameU[n] = L'\0'; -#endif - } else { - fileName = NULL; -#ifdef _WIN32 - fileNameU = NULL; -#endif - } - str = strA; - ok = setup(ownerPassword, userPassword); -} - -GBool PDFDoc::setup(GooString *ownerPassword, GooString *userPassword) { - pdfdocLocker(); - str->setPos(0, -1); - if (str->getPos() < 0) - { - error(errSyntaxError, -1, "Document base stream is not seekable"); - return gFalse; - } - - str->reset(); - - // check footer - // Adobe does not seem to enforce %%EOF, so we do the same -// if (!checkFooter()) return gFalse; - - // check header - checkHeader(); - - GBool wasReconstructed = false; - - // read xref table - xref = new XRef(str, getStartXRef(), getMainXRefEntriesOffset(), &wasReconstructed); - if (!xref->isOk()) { - if (wasReconstructed) { - delete xref; - startXRefPos = -1; - xref = new XRef(str, getStartXRef(gTrue), getMainXRefEntriesOffset(gTrue), &wasReconstructed); - } - if (!xref->isOk()) { - error(errSyntaxError, -1, "Couldn't read xref table"); - errCode = xref->getErrorCode(); - return gFalse; - } - } - - // check for encryption - if (!checkEncryption(ownerPassword, userPassword)) { - errCode = errEncrypted; - return gFalse; - } - - // read catalog - catalog = new Catalog(this); - if (catalog && !catalog->isOk()) { - if (!wasReconstructed) - { - // try one more time to contruct the Catalog, maybe the problem is damaged XRef - delete catalog; - delete xref; - xref = new XRef(str, 0, 0, NULL, true); - catalog = new Catalog(this); - } - - if (catalog && !catalog->isOk()) { - error(errSyntaxError, -1, "Couldn't read page catalog"); - errCode = errBadCatalog; - return gFalse; - } - } - - // done - return gTrue; -} - -PDFDoc::~PDFDoc() { - if (pageCache) { - for (int i = 0; i < getNumPages(); i++) { - if (pageCache[i]) { - delete pageCache[i]; - } - } - gfree(pageCache); - } - delete secHdlr; -#ifndef DISABLE_OUTLINE - if (outline) { - delete outline; - } -#endif - if (catalog) { - delete catalog; - } - if (xref) { - delete xref; - } - if (hints) { - delete hints; - } - if (linearization) { - delete linearization; - } - if (str) { - delete str; - } - if (file) { - delete file; - } - if (fileName) { - delete fileName; - } -#ifdef _WIN32 - if (fileNameU) { - gfree(fileNameU); - } -#endif -#ifdef MULTITHREADED - gDestroyMutex(&mutex); -#endif -} - - -// Check for a %%EOF at the end of this stream -GBool PDFDoc::checkFooter() { - // we look in the last 1024 chars because Adobe does the same - char *eof = new char[1025]; - Goffset pos = str->getPos(); - str->setPos(1024, -1); - int i, ch; - for (i = 0; i < 1024; i++) - { - ch = str->getChar(); - if (ch == EOF) - break; - eof[i] = ch; - } - eof[i] = '\0'; - - bool found = false; - for (i = i - 5; i >= 0; i--) { - if (strncmp (&eof[i], "%%EOF", 5) == 0) { - found = true; - break; - } - } - if (!found) - { - error(errSyntaxError, -1, "Document has not the mandatory ending %%EOF"); - errCode = errDamaged; - delete[] eof; - return gFalse; - } - delete[] eof; - str->setPos(pos); - return gTrue; -} - -// Check for a PDF header on this stream. Skip past some garbage -// if necessary. -void PDFDoc::checkHeader() { - char hdrBuf[headerSearchSize+1]; - char *p; - char *tokptr; - int i; - - pdfMajorVersion = 0; - pdfMinorVersion = 0; - for (i = 0; i < headerSearchSize; ++i) { - hdrBuf[i] = str->getChar(); - } - hdrBuf[headerSearchSize] = '\0'; - for (i = 0; i < headerSearchSize - 5; ++i) { - if (!strncmp(&hdrBuf[i], "%PDF-", 5)) { - break; - } - } - if (i >= headerSearchSize - 5) { - error(errSyntaxWarning, -1, "May not be a PDF file (continuing anyway)"); - return; - } - str->moveStart(i); - if (!(p = strtok_r(&hdrBuf[i+5], " \t\n\r", &tokptr))) { - error(errSyntaxWarning, -1, "May not be a PDF file (continuing anyway)"); - return; - } - sscanf(p, "%d.%d", &pdfMajorVersion, &pdfMinorVersion); - // We don't do the version check. Don't add it back in. -} - -GBool PDFDoc::checkEncryption(GooString *ownerPassword, GooString *userPassword) { - GBool encrypted; - GBool ret; - - Object encrypt = xref->getTrailerDict()->dictLookup("Encrypt"); - if ((encrypted = encrypt.isDict())) { - if ((secHdlr = SecurityHandler::make(this, &encrypt))) { - if (secHdlr->isUnencrypted()) { - // no encryption - ret = gTrue; - } else if (secHdlr->checkEncryption(ownerPassword, userPassword)) { - // authorization succeeded - xref->setEncryption(secHdlr->getPermissionFlags(), - secHdlr->getOwnerPasswordOk(), - secHdlr->getFileKey(), - secHdlr->getFileKeyLength(), - secHdlr->getEncVersion(), - secHdlr->getEncRevision(), - secHdlr->getEncAlgorithm()); - ret = gTrue; - } else { - // authorization failed - ret = gFalse; - } - } else { - // couldn't find the matching security handler - ret = gFalse; - } - } else { - // document is not encrypted - ret = gTrue; - } - return ret; -} - -std::vector<FormWidgetSignature*> PDFDoc::getSignatureWidgets() -{ - int num_pages = getNumPages(); - FormPageWidgets *page_widgets = NULL; - std::vector<FormWidgetSignature*> widget_vector; - - for (int i = 1; i <= num_pages; i++) { - Page *p = getCatalog()->getPage(i); - if (p) { - page_widgets = p->getFormWidgets(); - for (int j = 0; page_widgets != NULL && j < page_widgets->getNumWidgets(); j++) { - if (page_widgets->getWidget(j)->getType() == formSignature) { - widget_vector.push_back(static_cast<FormWidgetSignature*>(page_widgets->getWidget(j))); - } - } - delete page_widgets; - } - } - return widget_vector; -} - -void PDFDoc::displayPage(OutputDev *out, int page, - double hDPI, double vDPI, int rotate, - GBool useMediaBox, GBool crop, GBool printing, - GBool (*abortCheckCbk)(void *data), - void *abortCheckCbkData, - GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), - void *annotDisplayDecideCbkData, GBool copyXRef) { - if (globalParams->getPrintCommands()) { - printf("***** page %d *****\n", page); - } - - if (getPage(page)) - getPage(page)->display(out, hDPI, vDPI, - rotate, useMediaBox, crop, printing, - abortCheckCbk, abortCheckCbkData, - annotDisplayDecideCbk, annotDisplayDecideCbkData, copyXRef); - -} - -void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage, - double hDPI, double vDPI, int rotate, - GBool useMediaBox, GBool crop, GBool printing, - GBool (*abortCheckCbk)(void *data), - void *abortCheckCbkData, - GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), - void *annotDisplayDecideCbkData) { - int page; - - for (page = firstPage; page <= lastPage; ++page) { - displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, printing, - abortCheckCbk, abortCheckCbkData, - annotDisplayDecideCbk, annotDisplayDecideCbkData); - } -} - -void PDFDoc::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), - void *abortCheckCbkData, - GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), - void *annotDisplayDecideCbkData, GBool copyXRef) { - if (getPage(page)) - getPage(page)->displaySlice(out, hDPI, vDPI, - rotate, useMediaBox, crop, - sliceX, sliceY, sliceW, sliceH, - printing, - abortCheckCbk, abortCheckCbkData, - annotDisplayDecideCbk, annotDisplayDecideCbkData, copyXRef); -} - -Links *PDFDoc::getLinks(int page) { - Page *p = getPage(page); - if (!p) { - return new Links (NULL); - } - return p->getLinks(); -} - -void PDFDoc::processLinks(OutputDev *out, int page) { - if (getPage(page)) - getPage(page)->processLinks(out); -} - -Linearization *PDFDoc::getLinearization() -{ - if (!linearization) { - linearization = new Linearization(str); - linearizationState = 0; - } - return linearization; -} - -GBool PDFDoc::checkLinearization() { - if (linearization == NULL) - return gFalse; - if (linearizationState == 1) - return gTrue; - if (linearizationState == 2) - return gFalse; - if (!hints) { - hints = new Hints(str, linearization, getXRef(), secHdlr); - } - if (!hints->isOk()) { - linearizationState = 2; - return gFalse; - } - for (int page = 1; page <= linearization->getNumPages(); page++) { - Ref pageRef; - - pageRef.num = hints->getPageObjectNum(page); - if (!pageRef.num) { - linearizationState = 2; - return gFalse; - } - - // check for bogus ref - this can happen in corrupted PDF files - if (pageRef.num < 0 || pageRef.num >= xref->getNumObjects()) { - linearizationState = 2; - return gFalse; - } - - pageRef.gen = xref->getEntry(pageRef.num)->gen; - Object obj = xref->fetch(pageRef.num, pageRef.gen); - if (!obj.isDict("Page")) { - linearizationState = 2; - return gFalse; - } - } - linearizationState = 1; - return gTrue; -} - -GBool PDFDoc::isLinearized(GBool tryingToReconstruct) { - if ((str->getLength()) && - (getLinearization()->getLength() == str->getLength())) - return gTrue; - else { - if (tryingToReconstruct) - return getLinearization()->getLength() > 0; - else - return gFalse; - } -} - -void PDFDoc::setDocInfoModified(Object *infoObj) -{ - Object infoObjRef = getDocInfoNF(); - xref->setModifiedObject(infoObj, infoObjRef.getRef()); -} - -void PDFDoc::setDocInfoStringEntry(const char *key, GooString *value) -{ - GBool removeEntry = !value || value->getLength() == 0 || value->hasJustUnicodeMarker(); - if (removeEntry) { - delete value; - } - - Object infoObj = getDocInfo(); - if (infoObj.isNull() && removeEntry) { - // No info dictionary, so no entry to remove. - return; - } - - infoObj = createDocInfoIfNoneExists(); - if (removeEntry) { - infoObj.dictSet(key, Object(objNull)); - } else { - infoObj.dictSet(key, Object(value)); - } - - - if (infoObj.dictGetLength() == 0) { - // Info dictionary is empty. Remove it altogether. - removeDocInfo(); - } else { - setDocInfoModified(&infoObj); - } -} - -GooString *PDFDoc::getDocInfoStringEntry(const char *key) { - Object infoObj = getDocInfo(); - if (!infoObj.isDict()) { - return NULL; - } - - Object entryObj = infoObj.dictLookup(key); - - GooString *result; - - if (entryObj.isString()) { - result = entryObj.takeString(); - } else { - result = NULL; - } - - return result; -} - -static GBool -get_id (GooString *encodedidstring, GooString *id) { - const char *encodedid = encodedidstring->getCString(); - char pdfid[pdfIdLength + 1]; - int n; - - if (encodedidstring->getLength() != pdfIdLength / 2) - return gFalse; - - 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, 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); - if (n != pdfIdLength) - return gFalse; - - id->Set(pdfid, pdfIdLength); - return gTrue; -} - -GBool PDFDoc::getID(GooString *permanent_id, GooString *update_id) { - Object obj = xref->getTrailerDict()->dictLookup ("ID"); - - if (obj.isArray() && obj.arrayGetLength() == 2) { - if (permanent_id) { - Object obj2 = obj.arrayGet(0); - if (obj2.isString()) { - if (!get_id (obj2.getString(), permanent_id)) { - return gFalse; - } - } else { - error(errSyntaxError, -1, "Invalid permanent ID"); - return gFalse; - } - } - - if (update_id) { - Object obj2 = obj.arrayGet(1); - if (obj2.isString()) { - if (!get_id (obj2.getString(), update_id)) { - return gFalse; - } - } else { - error(errSyntaxError, -1, "Invalid update ID"); - return gFalse; - } - } - - return gTrue; - } - - return gFalse; -} - -Hints *PDFDoc::getHints() -{ - if (!hints && isLinearized()) { - hints = new Hints(str, getLinearization(), getXRef(), secHdlr); - } - - return hints; -} - -int PDFDoc::savePageAs(GooString *name, int pageNo) -{ - FILE *f; - OutStream *outStr; - XRef *yRef, *countRef; - int rootNum = getXRef()->getNumObjects() + 1; - - // Make sure that special flags are set, because we are going to read - // all objects, including Unencrypted ones. - xref->scanSpecialFlags(); - - Guchar *fileKey; - CryptAlgorithm encAlgorithm; - int keyLength; - xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength); - - if (pageNo < 1 || pageNo > getNumPages() || !getCatalog()->getPage(pageNo)) { - error(errInternal, -1, "Illegal pageNo: {0:d}({1:d})", pageNo, getNumPages() ); - return errOpenFile; - } - PDFRectangle *cropBox = NULL; - if (getCatalog()->getPage(pageNo)->isCropped()) { - cropBox = getCatalog()->getPage(pageNo)->getCropBox(); - } - replacePageDict(pageNo, - getCatalog()->getPage(pageNo)->getRotate(), - getCatalog()->getPage(pageNo)->getMediaBox(), - cropBox); - Ref *refPage = getCatalog()->getPageRef(pageNo); - Object page = getXRef()->fetch(refPage->num, refPage->gen); - - if (!(f = fopen(name->getCString(), "wb"))) { - error(errIO, -1, "Couldn't open file '{0:t}'", name); - return errOpenFile; - } - outStr = new FileOutStream(f,0); - - yRef = new XRef(getXRef()->getTrailerDict()); - - if (secHdlr != NULL && !secHdlr->isUnencrypted()) { - yRef->setEncryption(secHdlr->getPermissionFlags(), - secHdlr->getOwnerPasswordOk(), fileKey, keyLength, secHdlr->getEncVersion(), secHdlr->getEncRevision(), encAlgorithm); - } - countRef = new XRef(); - Object *trailerObj = getXRef()->getTrailerDict(); - if (trailerObj->isDict()) { - markPageObjects(trailerObj->getDict(), yRef, countRef, 0, refPage->num, rootNum + 2); - } - yRef->add(0, 65535, 0, gFalse); - writeHeader(outStr, getPDFMajorVersion(), getPDFMinorVersion()); - - // get and mark info dict - Object infoObj = getXRef()->getDocInfo(); - if (infoObj.isDict()) { - Dict *infoDict = infoObj.getDict(); - markPageObjects(infoDict, yRef, countRef, 0, refPage->num, rootNum + 2); - if (trailerObj->isDict()) { - Dict *trailerDict = trailerObj->getDict(); - Object ref = trailerDict->lookupNF("Info"); - if (ref.isRef()) { - yRef->add(ref.getRef().num, ref.getRef().gen, 0, gTrue); - if (getXRef()->getEntry(ref.getRef().num)->type == xrefEntryCompressed) { - yRef->getEntry(ref.getRef().num)->type = xrefEntryCompressed; - } - } - } - } - - // get and mark output intents etc. - Object catObj = getXRef()->getCatalog(); - Dict *catDict = catObj.getDict(); - Object pagesObj = catDict->lookup("Pages"); - Object afObj = catDict->lookupNF("AcroForm"); - if (!afObj.isNull()) { - markAcroForm(&afObj, yRef, countRef, 0, refPage->num, rootNum + 2); - } - Dict *pagesDict = pagesObj.getDict(); - Object resourcesObj = pagesDict->lookup("Resources"); - if (resourcesObj.isDict()) - markPageObjects(resourcesObj.getDict(), yRef, countRef, 0, refPage->num, rootNum + 2); - markPageObjects(catDict, yRef, countRef, 0, refPage->num, rootNum + 2); - - Dict *pageDict = page.getDict(); - if (resourcesObj.isNull() && !pageDict->hasKey("Resources")) { - Object *resourceDictObject = getCatalog()->getPage(pageNo)->getResourceDictObject(); - if (resourceDictObject->isDict()) { - resourcesObj = resourceDictObject->copy(); - markPageObjects(resourcesObj.getDict(), yRef, countRef, 0, refPage->num, rootNum + 2); - } - } - markPageObjects(pageDict, yRef, countRef, 0, refPage->num, rootNum + 2); - Object annotsObj = pageDict->lookupNF("Annots"); - if (!annotsObj.isNull()) { - markAnnotations(&annotsObj, yRef, countRef, 0, refPage->num, rootNum + 2); - } - yRef->markUnencrypted(); - writePageObjects(outStr, yRef, 0); - - yRef->add(rootNum,0,outStr->getPos(),gTrue); - outStr->printf("%d 0 obj\n", rootNum); - outStr->printf("<< /Type /Catalog /Pages %d 0 R", rootNum + 1); - for (int j = 0; j < catDict->getLength(); j++) { - const char *key = catDict->getKey(j); - if (strcmp(key, "Type") != 0 && - strcmp(key, "Catalog") != 0 && - strcmp(key, "Pages") != 0) - { - if (j > 0) outStr->printf(" "); - Object value = catDict->getValNF(j); - outStr->printf("/%s ", key); - writeObject(&value, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0); - } - } - outStr->printf(">>\nendobj\n"); - - yRef->add(rootNum + 1,0,outStr->getPos(),gTrue); - outStr->printf("%d 0 obj\n", rootNum + 1); - outStr->printf("<< /Type /Pages /Kids [ %d 0 R ] /Count 1 ", rootNum + 2); - if (resourcesObj.isDict()) { - outStr->printf("/Resources "); - writeObject(&resourcesObj, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0); - } - outStr->printf(">>\n"); - outStr->printf("endobj\n"); - - yRef->add(rootNum + 2,0,outStr->getPos(),gTrue); - outStr->printf("%d 0 obj\n", rootNum + 2); - outStr->printf("<< "); - for (int n = 0; n < pageDict->getLength(); n++) { - if (n > 0) outStr->printf(" "); - const char *key = pageDict->getKey(n); - Object value = pageDict->getValNF(n); - if (strcmp(key, "Parent") == 0) { - outStr->printf("/Parent %d 0 R", rootNum + 1); - } else { - outStr->printf("/%s ", key); - writeObject(&value, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0); - } - } - outStr->printf(" >>\nendobj\n"); - - Goffset uxrefOffset = outStr->getPos(); - Ref ref; - ref.num = rootNum; - ref.gen = 0; - Object trailerDict = createTrailerDict(rootNum + 3, gFalse, 0, &ref, getXRef(), - name->getCString(), uxrefOffset); - writeXRefTableTrailer(std::move(trailerDict), yRef, gFalse /* do not write unnecessary entries */, - uxrefOffset, outStr, getXRef()); - - outStr->close(); - fclose(f); - delete yRef; - delete countRef; - delete outStr; - - return errNone; -} - -int PDFDoc::saveAs(GooString *name, PDFWriteMode mode) { - FILE *f; - OutStream *outStr; - int res; - - if (!(f = fopen(name->getCString(), "wb"))) { - error(errIO, -1, "Couldn't open file '{0:t}'", name); - return errOpenFile; - } - outStr = new FileOutStream(f,0); - res = saveAs(outStr, mode); - delete outStr; - fclose(f); - return res; -} - -int PDFDoc::saveAs(OutStream *outStr, PDFWriteMode mode) { - if (!xref->isModified() && mode == writeStandard) { - // simply copy the original file - saveWithoutChangesAs (outStr); - } else if (mode == writeForceRewrite) { - saveCompleteRewrite(outStr); - } else { - saveIncrementalUpdate(outStr); - } - - return errNone; -} - -int PDFDoc::saveWithoutChangesAs(GooString *name) { - FILE *f; - OutStream *outStr; - int res; - - if (!(f = fopen(name->getCString(), "wb"))) { - error(errIO, -1, "Couldn't open file '{0:t}'", name); - return errOpenFile; - } - - outStr = new FileOutStream(f,0); - res = saveWithoutChangesAs(outStr); - delete outStr; - - fclose(f); - - return res; -} - -int PDFDoc::saveWithoutChangesAs(OutStream *outStr) { - int c; - - BaseStream *copyStr = str->copy(); - copyStr->reset(); - while ((c = copyStr->getChar()) != EOF) { - outStr->put(c); - } - copyStr->close(); - delete copyStr; - - return errNone; -} - -void PDFDoc::saveIncrementalUpdate (OutStream* outStr) -{ - XRef *uxref; - int c; - //copy the original file - BaseStream *copyStr = str->copy(); - copyStr->reset(); - while ((c = copyStr->getChar()) != EOF) { - outStr->put(c); - } - copyStr->close(); - delete copyStr; - - Guchar *fileKey; - CryptAlgorithm encAlgorithm; - int keyLength; - xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength); - - uxref = new XRef(); - uxref->add(0, 65535, 0, gFalse); - xref->lock(); - for(int i=0; i<xref->getNumObjects(); i++) { - if ((xref->getEntry(i)->type == xrefEntryFree) && - (xref->getEntry(i)->gen == 0)) //we skip the irrelevant free objects - continue; - - if (xref->getEntry(i)->getFlag(XRefEntry::Updated)) { //we have an updated object - Ref ref; - ref.num = i; - ref.gen = xref->getEntry(i)->type == xrefEntryCompressed ? 0 : xref->getEntry(i)->gen; - if (xref->getEntry(i)->type != xrefEntryFree) { - Object obj1 = xref->fetch(ref.num, ref.gen, 1); - Goffset offset = writeObjectHeader(&ref, outStr); - writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen); - writeObjectFooter(outStr); - uxref->add(ref.num, ref.gen, offset, gTrue); - } else { - uxref->add(ref.num, ref.gen, 0, gFalse); - } - } - } - xref->unlock(); - // because of "uxref->add(0, 65535, 0, gFalse);" uxref->getNumObjects() will - // always be >= 1; if it is 1, it means there is nothing to update - if (uxref->getNumObjects() == 1) { - delete uxref; - return; - } - - Goffset uxrefOffset = outStr->getPos(); - int numobjects = xref->getNumObjects(); - const char *fileNameA = fileName ? fileName->getCString() : NULL; - Ref rootRef, uxrefStreamRef; - rootRef.num = getXRef()->getRootNum(); - rootRef.gen = getXRef()->getRootGen(); - - // Output a xref stream if there is a xref stream already - GBool xRefStream = xref->isXRefStream(); - - if (xRefStream) { - // Append an entry for the xref stream itself - uxrefStreamRef.num = numobjects++; - uxrefStreamRef.gen = 0; - uxref->add(uxrefStreamRef.num, uxrefStreamRef.gen, uxrefOffset, gTrue); - } - - Object trailerDict = createTrailerDict(numobjects, gTrue, getStartXRef(), &rootRef, getXRef(), fileNameA, uxrefOffset); - if (xRefStream) { - writeXRefStreamTrailer(std::move(trailerDict), uxref, &uxrefStreamRef, uxrefOffset, outStr, getXRef()); - } else { - writeXRefTableTrailer(std::move(trailerDict), uxref, gFalse, uxrefOffset, outStr, getXRef()); - } - - delete uxref; -} - -void PDFDoc::saveCompleteRewrite (OutStream* outStr) -{ - // Make sure that special flags are set, because we are going to read - // all objects, including Unencrypted ones. - xref->scanSpecialFlags(); - - Guchar *fileKey; - CryptAlgorithm encAlgorithm; - int keyLength; - xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength); - - outStr->printf("%%PDF-%d.%d\r\n",pdfMajorVersion,pdfMinorVersion); - XRef *uxref = new XRef(); - uxref->add(0, 65535, 0, gFalse); - xref->lock(); - for(int i=0; i<xref->getNumObjects(); i++) { - Ref ref; - XRefEntryType type = xref->getEntry(i)->type; - if (type == xrefEntryFree) { - ref.num = i; - ref.gen = xref->getEntry(i)->gen; - /* the XRef class adds a lot of irrelevant free entries, we only want the significant one - and we don't want the one with num=0 because it has already been added (gen = 65535)*/ - if (ref.gen > 0 && ref.num > 0) - uxref->add(ref.num, ref.gen, 0, gFalse); - } else if (xref->getEntry(i)->getFlag(XRefEntry::DontRewrite)) { - // This entry must not be written, put a free entry instead (with incremented gen) - ref.num = i; - ref.gen = xref->getEntry(i)->gen + 1; - uxref->add(ref.num, ref.gen, 0, gFalse); - } else if (type == xrefEntryUncompressed){ - ref.num = i; - ref.gen = xref->getEntry(i)->gen; - Object obj1 = xref->fetch(ref.num, ref.gen, 1); - Goffset offset = writeObjectHeader(&ref, outStr); - // Write unencrypted objects in unencrypted form - if (xref->getEntry(i)->getFlag(XRefEntry::Unencrypted)) { - writeObject(&obj1, outStr, NULL, cryptRC4, 0, 0, 0); - } else { - writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen); - } - writeObjectFooter(outStr); - uxref->add(ref.num, ref.gen, offset, gTrue); - } else if (type == xrefEntryCompressed) { - ref.num = i; - ref.gen = 0; //compressed entries have gen == 0 - Object obj1 = xref->fetch(ref.num, ref.gen, 1); - Goffset offset = writeObjectHeader(&ref, outStr); - writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen); - writeObjectFooter(outStr); - uxref->add(ref.num, ref.gen, offset, gTrue); - } - } - xref->unlock(); - Goffset uxrefOffset = outStr->getPos(); - writeXRefTableTrailer(uxrefOffset, uxref, gTrue /* write all entries */, - uxref->getNumObjects(), outStr, gFalse /* complete rewrite */); - delete uxref; -} - -void PDFDoc::writeDictionnary (Dict* dict, OutStream* outStr, XRef *xRef, Guint numOffset, Guchar *fileKey, - CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen, std::set<Dict*> *alreadyWrittenDicts) -{ - bool deleteSet = false; - if (!alreadyWrittenDicts) { - alreadyWrittenDicts = new std::set<Dict*>; - deleteSet = true; - } - - if (alreadyWrittenDicts->find(dict) != alreadyWrittenDicts->end()) { - error(errSyntaxWarning, -1, "PDFDoc::writeDictionnary: Found recursive dicts"); - if (deleteSet) delete alreadyWrittenDicts; - return; - } else { - alreadyWrittenDicts->insert(dict); - } - - outStr->printf("<<"); - for (int i=0; i<dict->getLength(); i++) { - GooString keyName(dict->getKey(i)); - GooString *keyNameToPrint = keyName.sanitizedName(gFalse /* non ps mode */); - outStr->printf("/%s ", keyNameToPrint->getCString()); - delete keyNameToPrint; - Object obj1 = dict->getValNF(i); - writeObject(&obj1, outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen, alreadyWrittenDicts); - } - outStr->printf(">> "); - - if (deleteSet) { - delete alreadyWrittenDicts; - } -} - -void PDFDoc::writeStream (Stream* str, OutStream* outStr) -{ - outStr->printf("stream\r\n"); - str->reset(); - for (int c=str->getChar(); c!= EOF; c=str->getChar()) { - outStr->printf("%c", c); - } - outStr->printf("\r\nendstream\r\n"); -} - -void PDFDoc::writeRawStream (Stream* str, OutStream* outStr) -{ - Object obj1 = str->getDict()->lookup("Length"); - if (!obj1.isInt() && !obj1.isInt64()) { - error (errSyntaxError, -1, "PDFDoc::writeRawStream, no Length in stream dict"); - return; - } - - Goffset length; - if (obj1.isInt()) - length = obj1.getInt(); - else - length = obj1.getInt64(); - - outStr->printf("stream\r\n"); - str->unfilteredReset(); - for (Goffset i = 0; i < length; i++) { - int c = str->getUnfilteredChar(); - if (unlikely(c == EOF)) { - error (errSyntaxError, -1, "PDFDoc::writeRawStream: EOF reading stream"); - break; - } - outStr->printf("%c", c); - } - str->reset(); - outStr->printf("\r\nendstream\r\n"); -} - -void PDFDoc::writeString (GooString* s, OutStream* outStr, Guchar *fileKey, - CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen) -{ - // Encrypt string if encryption is enabled - GooString *sEnc = NULL; - if (fileKey) { - EncryptStream *enc = new EncryptStream(new MemStream(s->getCString(), 0, s->getLength(), Object(objNull)), - fileKey, encAlgorithm, keyLength, objNum, objGen); - sEnc = new GooString(); - int c; - enc->reset(); - while ((c = enc->getChar()) != EOF) { - sEnc->append((char)c); - } - - delete enc; - s = sEnc; - } - - // Write data - if (s->hasUnicodeMarker()) { - //unicode string don't necessary end with \0 - const char* c = s->getCString(); - outStr->printf("("); - for(int i=0; i<s->getLength(); i++) { - char unescaped = *(c+i)&0x000000ff; - //escape if needed - if (unescaped == '(' || unescaped == ')' || unescaped == '\\') - outStr->printf("%c", '\\'); - outStr->printf("%c", unescaped); - } - outStr->printf(") "); - } else { - const char* c = s->getCString(); - outStr->printf("("); - for(int i=0; i<s->getLength(); i++) { - char unescaped = *(c+i)&0x000000ff; - //escape if needed - if (unescaped == '\r') - outStr->printf("\\r"); - else if (unescaped == '\n') - outStr->printf("\\n"); - else { - if (unescaped == '(' || unescaped == ')' || unescaped == '\\') { - outStr->printf("%c", '\\'); - } - outStr->printf("%c", unescaped); - } - } - outStr->printf(") "); - } - - delete sEnc; -} - -Goffset PDFDoc::writeObjectHeader (Ref *ref, OutStream* outStr) -{ - Goffset offset = outStr->getPos(); - outStr->printf("%i %i obj ", ref->num, ref->gen); - return offset; -} - -void PDFDoc::writeObject (Object* obj, OutStream* outStr, XRef *xRef, Guint numOffset, Guchar *fileKey, - CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen, std::set<Dict*> *alreadyWrittenDicts) -{ - Array *array; - - switch (obj->getType()) { - case objBool: - outStr->printf("%s ", obj->getBool()?"true":"false"); - break; - case objInt: - outStr->printf("%i ", obj->getInt()); - break; - case objInt64: - outStr->printf("%lli ", obj->getInt64()); - break; - case objReal: - { - GooString s; - s.appendf("{0:.10g}", obj->getReal()); - outStr->printf("%s ", s.getCString()); - break; - } - case objString: - writeString(obj->getString(), outStr, fileKey, encAlgorithm, keyLength, objNum, objGen); - break; - case objName: - { - GooString name(obj->getName()); - GooString *nameToPrint = name.sanitizedName(gFalse /* non ps mode */); - outStr->printf("/%s ", nameToPrint->getCString()); - delete nameToPrint; - break; - } - case objNull: - outStr->printf( "null "); - break; - case objArray: - array = obj->getArray(); - outStr->printf("["); - for (int i=0; i<array->getLength(); i++) { - Object obj1 = array->getNF(i); - writeObject(&obj1, outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen); - } - outStr->printf("] "); - break; - case objDict: - writeDictionnary (obj->getDict(), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen, alreadyWrittenDicts); - break; - case objStream: - { - //We can't modify stream with the current implementation (no write functions in Stream API) - // => the only type of streams which that have been modified are internal streams (=strWeird) - Stream *stream = obj->getStream(); - if (stream->getKind() == strWeird || stream->getKind() == strCrypt) { - //we write the stream unencoded => TODO: write stream encoder - - // Encrypt stream - EncryptStream *encStream = NULL; - GBool removeFilter = gTrue; - if (stream->getKind() == strWeird && fileKey) { - Object filter = stream->getDict()->lookup("Filter"); - if (!filter.isName("Crypt")) { - if (filter.isArray()) { - for (int i = 0; i < filter.arrayGetLength(); i++) { - Object filterEle = filter.arrayGet(i); - if (filterEle.isName("Crypt")) { - removeFilter = gFalse; - break; - } - } - if (removeFilter) { - encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, objNum, objGen); - encStream->setAutoDelete(gFalse); - stream = encStream; - } - } else { - encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, objNum, objGen); - encStream->setAutoDelete(gFalse); - stream = encStream; - } - } else { - removeFilter = gFalse; - } - } else if (fileKey != NULL) { // Encrypt stream - encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, objNum, objGen); - encStream->setAutoDelete(gFalse); - stream = encStream; - } - - stream->reset(); - //recalculate stream length - Goffset tmp = 0; - for (int c=stream->getChar(); c!=EOF; c=stream->getChar()) { - tmp++; - } - stream->getDict()->set("Length", Object(tmp)); - - //Remove Stream encoding - if (removeFilter) { - stream->getDict()->remove("Filter"); - } - stream->getDict()->remove("DecodeParms"); - - writeDictionnary (stream->getDict(),outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen, alreadyWrittenDicts); - writeStream (stream,outStr); - delete encStream; - } else { - //raw stream copy - FilterStream *fs = dynamic_cast<FilterStream*>(stream); - if (fs) { - BaseStream *bs = fs->getBaseStream(); - if (bs) { - Goffset streamEnd; - if (xRef->getStreamEnd(bs->getStart(), &streamEnd)) { - Goffset val = streamEnd - bs->getStart(); - stream->getDict()->set("Length", Object(val)); - } - } - } - writeDictionnary (stream->getDict(), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen, alreadyWrittenDicts); - writeRawStream (stream, outStr); - } - break; - } - case objRef: - outStr->printf("%i %i R ", obj->getRef().num + numOffset, obj->getRef().gen); - break; - case objCmd: - outStr->printf("%s\n", obj->getCmd()); - break; - case objError: - outStr->printf("error\r\n"); - break; - case objEOF: - outStr->printf("eof\r\n"); - break; - case objNone: - outStr->printf("none\r\n"); - break; - default: - error(errUnimplemented, -1,"Unhandled objType : {0:d}, please report a bug with a testcase\r\n", obj->getType()); - break; - } -} - -void PDFDoc::writeObjectFooter (OutStream* outStr) -{ - outStr->printf("endobj\r\n"); -} - -Object PDFDoc::createTrailerDict(int uxrefSize, GBool incrUpdate, Goffset startxRef, - Ref *root, XRef *xRef, const char *fileName, Goffset fileSize) -{ - Dict *trailerDict = new Dict(xRef); - trailerDict->set("Size", Object(uxrefSize)); - - //build a new ID, as recommended in the reference, uses: - // - current time - // - file name - // - file size - // - values of entry in information dictionnary - GooString message; - char buffer[256]; - sprintf(buffer, "%i", (int)time(NULL)); - message.append(buffer); - - if (fileName) - message.append(fileName); - - sprintf(buffer, "%lli", (long long)fileSize); - message.append(buffer); - - //info dict -- only use text string - if (!xRef->getTrailerDict()->isNone()) { - Object docInfo = xRef->getDocInfo(); - if (docInfo.isDict()) { - for(int i=0; i<docInfo.getDict()->getLength(); i++) { - Object obj2 = docInfo.getDict()->getVal(i); - if (obj2.isString()) { - message.append(obj2.getString()); - } - } - } - } - - GBool hasEncrypt = gFalse; - if (!xRef->getTrailerDict()->isNone()) { - Object obj2 = xRef->getTrailerDict()->dictLookupNF("Encrypt"); - if (!obj2.isNull()) { - trailerDict->set("Encrypt", std::move(obj2)); - hasEncrypt = gTrue; - } - } - - //calculate md5 digest - Guchar digest[16]; - md5((Guchar*)message.getCString(), message.getLength(), digest); - - //create ID array - // In case of encrypted files, the ID must not be changed because it's used to calculate the key - if (incrUpdate || hasEncrypt) { - //only update the second part of the array - Object obj4 = xRef->getTrailerDict()->getDict()->lookup("ID"); - if (!obj4.isArray()) { - error(errSyntaxWarning, -1, "PDFDoc::createTrailerDict original file's ID entry isn't an array. Trying to continue"); - } else { - Array *array = new Array(xRef); - //Get the first part of the ID - array->add(obj4.arrayGet(0)); - array->add(Object(new GooString((const char*)digest, 16))); - trailerDict->set("ID", Object(array)); - } - } else { - //new file => same values for the two identifiers - Array *array = new Array(xRef); - array->add(Object(new GooString((const char*)digest, 16))); - array->add(Object(new GooString((const char*)digest, 16))); - trailerDict->set("ID", Object(array)); - } - - trailerDict->set("Root", Object(root->num, root->gen)); - - if (incrUpdate) { - trailerDict->set("Prev", Object(startxRef)); - } - - if (!xRef->getTrailerDict()->isNone()) { - Object obj5 = xRef->getDocInfoNF(); - if (!obj5.isNull()) { - trailerDict->set("Info", std::move(obj5)); - } - } - - return Object(trailerDict); -} - -void PDFDoc::writeXRefTableTrailer(Object &&trailerDict, XRef *uxref, GBool writeAllEntries, Goffset uxrefOffset, OutStream* outStr, XRef *xRef) -{ - uxref->writeTableToFile( outStr, writeAllEntries ); - outStr->printf( "trailer\r\n"); - writeDictionnary(trailerDict.getDict(), outStr, xRef, 0, NULL, cryptRC4, 0, 0, 0, nullptr); - outStr->printf( "\r\nstartxref\r\n"); - outStr->printf( "%lli\r\n", uxrefOffset); - outStr->printf( "%%%%EOF\r\n"); -} - -void PDFDoc::writeXRefStreamTrailer (Object &&trailerDict, XRef *uxref, Ref *uxrefStreamRef, Goffset uxrefOffset, OutStream* outStr, XRef *xRef) -{ - GooString stmData; - - // Fill stmData and some trailerDict fields - uxref->writeStreamToBuffer(&stmData, trailerDict.getDict(), xRef); - - // Create XRef stream object and write it - MemStream *mStream = new MemStream( stmData.getCString(), 0, stmData.getLength(), std::move(trailerDict) ); - writeObjectHeader(uxrefStreamRef, outStr); - Object obj1(static_cast<Stream*>(mStream)); - writeObject(&obj1, outStr, xRef, 0, NULL, cryptRC4, 0, 0, 0); - writeObjectFooter(outStr); - - outStr->printf( "startxref\r\n"); - outStr->printf( "%lli\r\n", uxrefOffset); - outStr->printf( "%%%%EOF\r\n"); -} - -void PDFDoc::writeXRefTableTrailer(Goffset uxrefOffset, XRef *uxref, GBool writeAllEntries, - int uxrefSize, OutStream* outStr, GBool incrUpdate) -{ - const char *fileNameA = fileName ? fileName->getCString() : NULL; - // file size (doesn't include the trailer) - unsigned int fileSize = 0; - int c; - str->reset(); - while ((c = str->getChar()) != EOF) { - fileSize++; - } - str->close(); - Ref ref; - ref.num = getXRef()->getRootNum(); - ref.gen = getXRef()->getRootGen(); - Object trailerDict = createTrailerDict(uxrefSize, incrUpdate, getStartXRef(), &ref, - getXRef(), fileNameA, fileSize); - writeXRefTableTrailer(std::move(trailerDict), uxref, writeAllEntries, uxrefOffset, outStr, getXRef()); -} - -void PDFDoc::writeHeader(OutStream *outStr, int major, int minor) -{ - outStr->printf("%%PDF-%d.%d\n", major, minor); - outStr->printf("%%\xE2\xE3\xCF\xD3\n"); -} - -void PDFDoc::markDictionnary (Dict* dict, XRef * xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum, std::set<Dict*> *alreadyMarkedDicts) -{ - bool deleteSet = false; - if (!alreadyMarkedDicts) { - alreadyMarkedDicts = new std::set<Dict*>; - deleteSet = true; - } - - if (alreadyMarkedDicts->find(dict) != alreadyMarkedDicts->end()) { - error(errSyntaxWarning, -1, "PDFDoc::markDictionnary: Found recursive dicts"); - if (deleteSet) delete alreadyMarkedDicts; - return; - } else { - alreadyMarkedDicts->insert(dict); - } - - Object obj1; - for (int i=0; i<dict->getLength(); i++) { - const char *key = dict->getKey(i); - if (strcmp(key, "Annots") != 0) { - Object obj1 = dict->getValNF(i); - markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); - } else { - Object annotsObj = dict->getValNF(i); - if (!annotsObj.isNull()) { - markAnnotations(&annotsObj, xRef, countRef, 0, oldRefNum, newRefNum, alreadyMarkedDicts); - } - } - } - - if (deleteSet) { - delete alreadyMarkedDicts; - } -} - -void PDFDoc::markObject (Object* obj, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum, std::set<Dict*> *alreadyMarkedDicts) -{ - Array *array; - - switch (obj->getType()) { - case objArray: - array = obj->getArray(); - for (int i=0; i<array->getLength(); i++) { - Object obj1 = array->getNF(i); - markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum); - } - break; - case objDict: - markDictionnary (obj->getDict(), xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); - break; - case objStream: - { - Stream *stream = obj->getStream(); - markDictionnary (stream->getDict(), xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); - } - break; - case objRef: - { - if (obj->getRef().num + (int) numOffset >= xRef->getNumObjects() || xRef->getEntry(obj->getRef().num + numOffset)->type == xrefEntryFree) { - if (getXRef()->getEntry(obj->getRef().num)->type == xrefEntryFree) { - return; // already marked as free => should be replaced - } - xRef->add(obj->getRef().num + numOffset, obj->getRef().gen, 0, gTrue); - if (getXRef()->getEntry(obj->getRef().num)->type == xrefEntryCompressed) { - xRef->getEntry(obj->getRef().num + numOffset)->type = xrefEntryCompressed; - } - } - if (obj->getRef().num + (int) numOffset >= countRef->getNumObjects() || - countRef->getEntry(obj->getRef().num + numOffset)->type == xrefEntryFree) - { - countRef->add(obj->getRef().num + numOffset, 1, 0, gTrue); - } else { - XRefEntry *entry = countRef->getEntry(obj->getRef().num + numOffset); - entry->gen++; - if (entry->gen > 9) - break; - } - Object obj1 = getXRef()->fetch(obj->getRef().num, obj->getRef().gen); - markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum); - } - break; - default: - break; - } -} - -void PDFDoc::replacePageDict(int pageNo, int rotate, - PDFRectangle *mediaBox, - PDFRectangle *cropBox) -{ - Ref *refPage = getCatalog()->getPageRef(pageNo); - Object page = getXRef()->fetch(refPage->num, refPage->gen); - Dict *pageDict = page.getDict(); - pageDict->remove("MediaBoxssdf"); - pageDict->remove("MediaBox"); - pageDict->remove("CropBox"); - pageDict->remove("ArtBox"); - pageDict->remove("BleedBox"); - pageDict->remove("TrimBox"); - pageDict->remove("Rotate"); - Array *mediaBoxArray = new Array(getXRef()); - mediaBoxArray->add(Object(mediaBox->x1)); - mediaBoxArray->add(Object(mediaBox->y1)); - mediaBoxArray->add(Object(mediaBox->x2)); - mediaBoxArray->add(Object(mediaBox->y2)); - Object mediaBoxObject(mediaBoxArray); - Object trimBoxObject = mediaBoxObject.copy(); - pageDict->add(copyString("MediaBox"), std::move(mediaBoxObject)); - if (cropBox != NULL) { - Array *cropBoxArray = new Array(getXRef()); - cropBoxArray->add(Object(cropBox->x1)); - cropBoxArray->add(Object(cropBox->y1)); - cropBoxArray->add(Object(cropBox->x2)); - cropBoxArray->add(Object(cropBox->y2)); - Object cropBoxObject(cropBoxArray); - trimBoxObject = cropBoxObject.copy(); - pageDict->add(copyString("CropBox"), std::move(cropBoxObject)); - } - pageDict->add(copyString("TrimBox"), std::move(trimBoxObject)); - pageDict->add(copyString("Rotate"), Object(rotate)); - getXRef()->setModifiedObject(&page, *refPage); -} - -void PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum, std::set<Dict*> *alreadyMarkedDicts) -{ - pageDict->remove("OpenAction"); - pageDict->remove("Outlines"); - pageDict->remove("StructTreeRoot"); - - for (int n = 0; n < pageDict->getLength(); n++) { - const char *key = pageDict->getKey(n); - Object value = pageDict->getValNF(n); - 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) { - markObject(&value, xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); - } - } -} - -GBool PDFDoc::markAnnotations(Object *annotsObj, XRef *xRef, XRef *countRef, Guint numOffset, int oldPageNum, int newPageNum, std::set<Dict*> *alreadyMarkedDicts) { - GBool modified = gFalse; - Object annots = annotsObj->fetch(getXRef()); - if (annots.isArray()) { - Array *array = annots.getArray(); - for (int i=array->getLength() - 1; i >= 0; i--) { - Object obj1 = array->get(i); - if (obj1.isDict()) { - Dict *dict = obj1.getDict(); - Object type = dict->lookup("Type"); - if (type.isName() && strcmp(type.getName(), "Annot") == 0) { - Object obj2 = dict->lookupNF("P"); - if (obj2.isRef()) { - if (obj2.getRef().num == oldPageNum) { - Object obj3 = array->getNF(i); - if (obj3.isRef()) { - dict->set("P", Object(newPageNum, 0)); - getXRef()->setModifiedObject(&obj1, obj3.getRef()); - } - } else if (obj2.getRef().num == newPageNum) { - continue; - } else { - Object page = getXRef()->fetch(obj2.getRef().num, obj2.getRef().gen); - if (page.isDict()) { - Dict *dict = page.getDict(); - Object pagetype = dict->lookup("Type"); - if (!pagetype.isName() || strcmp(pagetype.getName(), "Page") != 0) { - continue; - } - } - array->remove(i); - modified = gTrue; - continue; - } - } - } - markPageObjects(dict, xRef, countRef, numOffset, oldPageNum, newPageNum, alreadyMarkedDicts); - } - obj1 = array->getNF(i); - if (obj1.isRef()) { - if (obj1.getRef().num + (int) numOffset >= xRef->getNumObjects() || xRef->getEntry(obj1.getRef().num + numOffset)->type == xrefEntryFree) { - if (getXRef()->getEntry(obj1.getRef().num)->type == xrefEntryFree) { - continue; // already marked as free => should be replaced - } - xRef->add(obj1.getRef().num + numOffset, obj1.getRef().gen, 0, gTrue); - if (getXRef()->getEntry(obj1.getRef().num)->type == xrefEntryCompressed) { - xRef->getEntry(obj1.getRef().num + numOffset)->type = xrefEntryCompressed; - } - } - if (obj1.getRef().num + (int) numOffset >= countRef->getNumObjects() || - countRef->getEntry(obj1.getRef().num + numOffset)->type == xrefEntryFree) - { - countRef->add(obj1.getRef().num + numOffset, 1, 0, gTrue); - } else { - XRefEntry *entry = countRef->getEntry(obj1.getRef().num + numOffset); - entry->gen++; - } - } - } - } - if (annotsObj->isRef()) { - if (annotsObj->getRef().num + (int) numOffset >= xRef->getNumObjects() || xRef->getEntry(annotsObj->getRef().num + numOffset)->type == xrefEntryFree) { - if (getXRef()->getEntry(annotsObj->getRef().num)->type == xrefEntryFree) { - return modified; // already marked as free => should be replaced - } - xRef->add(annotsObj->getRef().num + numOffset, annotsObj->getRef().gen, 0, gTrue); - if (getXRef()->getEntry(annotsObj->getRef().num)->type == xrefEntryCompressed) { - xRef->getEntry(annotsObj->getRef().num + numOffset)->type = xrefEntryCompressed; - } - } - if (annotsObj->getRef().num + (int) numOffset >= countRef->getNumObjects() || - countRef->getEntry(annotsObj->getRef().num + numOffset)->type == xrefEntryFree) - { - countRef->add(annotsObj->getRef().num + numOffset, 1, 0, gTrue); - } else { - XRefEntry *entry = countRef->getEntry(annotsObj->getRef().num + numOffset); - entry->gen++; - } - getXRef()->setModifiedObject(&annots, annotsObj->getRef()); - } - return modified; -} - -void PDFDoc::markAcroForm(Object *afObj, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum) { - GBool modified = gFalse; - Object acroform = afObj->fetch(getXRef()); - if (acroform.isDict()) { - Dict *dict = acroform.getDict(); - for (int i=0; i < dict->getLength(); i++) { - if (strcmp(dict->getKey(i), "Fields") == 0) { - Object fields = dict->getValNF(i); - modified = markAnnotations(&fields, xRef, countRef, numOffset, oldRefNum, newRefNum); - } else { - Object obj = dict->getValNF(i); - markObject(&obj, xRef, countRef, numOffset, oldRefNum, newRefNum); - } - } - } - if (afObj->isRef()) { - if (afObj->getRef().num + (int) numOffset >= xRef->getNumObjects() || xRef->getEntry(afObj->getRef().num + numOffset)->type == xrefEntryFree) { - if (getXRef()->getEntry(afObj->getRef().num)->type == xrefEntryFree) { - return; // already marked as free => should be replaced - } - xRef->add(afObj->getRef().num + numOffset, afObj->getRef().gen, 0, gTrue); - if (getXRef()->getEntry(afObj->getRef().num)->type == xrefEntryCompressed) { - xRef->getEntry(afObj->getRef().num + numOffset)->type = xrefEntryCompressed; - } - } - if (afObj->getRef().num + (int) numOffset >= countRef->getNumObjects() || - countRef->getEntry(afObj->getRef().num + numOffset)->type == xrefEntryFree) - { - countRef->add(afObj->getRef().num + numOffset, 1, 0, gTrue); - } else { - XRefEntry *entry = countRef->getEntry(afObj->getRef().num + numOffset); - entry->gen++; - } - if (modified){ - getXRef()->setModifiedObject(&acroform, afObj->getRef()); - } - } - return; -} - -Guint PDFDoc::writePageObjects(OutStream *outStr, XRef *xRef, Guint numOffset, GBool combine) -{ - Guint objectsCount = 0; //count the number of objects in the XRef(s) - Guchar *fileKey; - CryptAlgorithm encAlgorithm; - int keyLength; - xRef->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength); - - for (int n = numOffset; n < xRef->getNumObjects(); n++) { - if (xRef->getEntry(n)->type != xrefEntryFree) { - Ref ref; - ref.num = n; - ref.gen = xRef->getEntry(n)->gen; - objectsCount++; - Object obj = getXRef()->fetch(ref.num - numOffset, ref.gen); - Goffset offset = writeObjectHeader(&ref, outStr); - if (combine) { - writeObject(&obj, outStr, getXRef(), numOffset, NULL, cryptRC4, 0, 0, 0); - } else if (xRef->getEntry(n)->getFlag(XRefEntry::Unencrypted)) { - writeObject(&obj, outStr, NULL, cryptRC4, 0, 0, 0); - } else { - writeObject(&obj, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen); - } - writeObjectFooter(outStr); - xRef->add(ref.num, ref.gen, offset, gTrue); - } - } - return objectsCount; -} - -#ifndef DISABLE_OUTLINE -Outline *PDFDoc::getOutline() -{ - if (!outline) { - pdfdocLocker(); - // read outline - outline = new Outline(catalog->getOutline(), xref); - } - - return outline; -} -#endif - -PDFDoc *PDFDoc::ErrorPDFDoc(int errorCode, GooString *fileNameA) -{ - PDFDoc *doc = new PDFDoc(); - doc->errCode = errorCode; - doc->fileName = fileNameA; - - return doc; -} - -long long PDFDoc::strToLongLong(char *s) { - long long x, d; - char *p; - - x = 0; - for (p = s; *p && isdigit(*p & 0xff); ++p) { - d = *p - '0'; - if (x > (LLONG_MAX - d) / 10) { - break; - } - x = 10 * x + d; - } - return x; -} - -// Read the 'startxref' position. -Goffset PDFDoc::getStartXRef(GBool tryingToReconstruct) -{ - if (startXRefPos == -1) { - - if (isLinearized(tryingToReconstruct)) { - char buf[linearizationSearchSize+1]; - int c, n, i; - - str->setPos(0); - for (n = 0; n < linearizationSearchSize; ++n) { - if ((c = str->getChar()) == EOF) { - break; - } - buf[n] = c; - } - buf[n] = '\0'; - - // find end of first obj (linearization dictionary) - startXRefPos = 0; - for (i = 0; i < n; i++) { - if (!strncmp("endobj", &buf[i], 6)) { - i += 6; - //skip whitespace - while (buf[i] && Lexer::isSpace(buf[i])) ++i; - startXRefPos = i; - break; - } - } - } else { - char buf[xrefSearchSize+1]; - char *p; - int c, n, i; - - // read last xrefSearchSize bytes - int segnum = 0; - int maxXRefSearch = 24576; - if (str->getLength() < maxXRefSearch) maxXRefSearch = str->getLength(); - for (; (xrefSearchSize - 16) * segnum < maxXRefSearch; segnum++) { - str->setPos((xrefSearchSize - 16) * segnum + xrefSearchSize, -1); - for (n = 0; n < xrefSearchSize; ++n) { - if ((c = str->getChar()) == EOF) { - break; - } - buf[n] = c; - } - buf[n] = '\0'; - - // find startxref - for (i = n - 9; i >= 0; --i) { - if (!strncmp(&buf[i], "startxref", 9)) { - break; - } - } - if (i < 0) { - startXRefPos = 0; - } else { - for (p = &buf[i + 9]; isspace(*p); ++p); - startXRefPos = strToLongLong(p); - break; - } - } - } - - } - - return startXRefPos; -} - -Goffset PDFDoc::getMainXRefEntriesOffset(GBool tryingToReconstruct) -{ - Guint mainXRefEntriesOffset = 0; - - if (isLinearized(tryingToReconstruct)) { - mainXRefEntriesOffset = getLinearization()->getMainXRefEntriesOffset(); - } - - return mainXRefEntriesOffset; -} - -int PDFDoc::getNumPages() -{ - if (isLinearized()) { - int n; - if ((n = getLinearization()->getNumPages())) { - return n; - } - } - - return catalog->getNumPages(); -} - -Page *PDFDoc::parsePage(int page) -{ - Ref pageRef; - - pageRef.num = getHints()->getPageObjectNum(page); - if (!pageRef.num) { - error(errSyntaxWarning, -1, "Failed to get object num from hint tables for page {0:d}", page); - return NULL; - } - - // check for bogus ref - this can happen in corrupted PDF files - if (pageRef.num < 0 || pageRef.num >= xref->getNumObjects()) { - error(errSyntaxWarning, -1, "Invalid object num ({0:d}) for page {1:d}", pageRef.num, page); - return NULL; - } - - pageRef.gen = xref->getEntry(pageRef.num)->gen; - Object obj = xref->fetch(pageRef.num, pageRef.gen); - if (!obj.isDict("Page")) { - error(errSyntaxWarning, -1, "Object ({0:d} {1:d}) is not a pageDict", pageRef.num, pageRef.gen); - return NULL; - } - Dict *pageDict = obj.getDict(); - - return new Page(this, page, &obj, pageRef, - new PageAttrs(NULL, pageDict), catalog->getForm()); -} - -Page *PDFDoc::getPage(int page) -{ - if ((page < 1) || page > getNumPages()) return NULL; - - if (isLinearized() && checkLinearization()) { - pdfdocLocker(); - if (!pageCache) { - pageCache = (Page **) gmallocn(getNumPages(), sizeof(Page *)); - for (int i = 0; i < getNumPages(); i++) { - pageCache[i] = NULL; - } - } - if (!pageCache[page-1]) { - pageCache[page-1] = parsePage(page); - } - if (pageCache[page-1]) { - return pageCache[page-1]; - } else { - error(errSyntaxWarning, -1, "Failed parsing page {0:d} using hint tables", page); - } - } - - return catalog->getPage(page); -} diff --git a/source/libs/poppler/poppler-src/poppler/PDFDoc.cc~ b/source/libs/poppler/poppler-src/poppler/PDFDoc.cc~ deleted file mode 100644 index 90f039d8e..000000000 --- a/source/libs/poppler/poppler-src/poppler/PDFDoc.cc~ +++ /dev/null @@ -1,1985 +0,0 @@ -//======================================================================== -// -// PDFDoc.cc -// -// Copyright 1996-2003 Glyph & Cog, LLC -// -//======================================================================== - -//======================================================================== -// -// Modified under the Poppler project - http://poppler.freedesktop.org -// -// All changes made under the Poppler project to this file are licensed -// under GPL version 2 or later -// -// Copyright (C) 2005, 2006, 2008 Brad Hards <bradh@frogmouth.net> -// Copyright (C) 2005, 2007-2009, 2011-2017 Albert Astals Cid <aacid@kde.org> -// Copyright (C) 2008 Julien Rebetez <julienr@svn.gnome.org> -// Copyright (C) 2008, 2010 Pino Toscano <pino@kde.org> -// Copyright (C) 2008, 2010, 2011 Carlos Garcia Campos <carlosgc@gnome.org> -// Copyright (C) 2009 Eric Toombs <ewtoombs@uwaterloo.ca> -// Copyright (C) 2009 Kovid Goyal <kovid@kovidgoyal.net> -// Copyright (C) 2009, 2011 Axel Struebing <axel.struebing@freenet.de> -// Copyright (C) 2010-2012, 2014 Hib Eris <hib@hiberis.nl> -// Copyright (C) 2010 Jakub Wilk <jwilk@jwilk.net> -// Copyright (C) 2010 Ilya Gorenbein <igorenbein@finjan.com> -// Copyright (C) 2010 Srinivas Adicherla <srinivas.adicherla@geodesic.com> -// Copyright (C) 2010 Philip Lorenz <lorenzph+freedesktop@gmail.com> -// Copyright (C) 2011-2016 Thomas Freitag <Thomas.Freitag@alfa.de> -// Copyright (C) 2012, 2013 Fabio D'Urso <fabiodurso@hotmail.it> -// Copyright (C) 2013, 2014, 2017 Adrian Johnson <ajohnson@redneon.com> -// Copyright (C) 2013 Adam Reichold <adamreichold@myopera.com> -// Copyright (C) 2014 Bogdan Cristea <cristeab@gmail.com> -// Copyright (C) 2015 Li Junling <lijunling@sina.com> -// Copyright (C) 2015 André Guerreiro <aguerreiro1985@gmail.com> -// Copyright (C) 2015 André Esser <bepandre@hotmail.com> -// Copyright (C) 2016 Jakub Alba <jakubalba@gmail.com> -// Copyright (C) 2017 Jean Ghali <jghali@libertysurf.fr> -// -// To see a description of the changes please see the Changelog file that -// came with your tarball or type make ChangeLog if you are building from git -// -//======================================================================== - -#include <config.h> -#include <poppler-config.h> - -#ifdef USE_GCC_PRAGMAS -#pragma implementation -#endif - -#include <ctype.h> -#include <locale.h> -#include <stdio.h> -#include <errno.h> -#include <limits.h> -#include <stdlib.h> -#include <stddef.h> -#include <string.h> -#include <time.h> -#include <sys/stat.h> -#include "goo/glibc.h" -#include "goo/gstrtod.h" -#include "goo/GooString.h" -#include "goo/gfile.h" -#include "poppler-config.h" -#include "GlobalParams.h" -#include "Page.h" -#include "Catalog.h" -#include "Stream.h" -#include "XRef.h" -#include "Linearization.h" -#include "Link.h" -#include "OutputDev.h" -#include "Error.h" -#include "ErrorCodes.h" -#include "Lexer.h" -#include "Parser.h" -#include "SecurityHandler.h" -#include "Decrypt.h" -#ifndef DISABLE_OUTLINE -#include "Outline.h" -#endif -#include "PDFDoc.h" -#include "Hints.h" -#include "UTF.h" - -#ifdef MULTITHREADED -# define pdfdocLocker() MutexLocker locker(&mutex) -#else -# define pdfdocLocker() -#endif - -//------------------------------------------------------------------------ - -#define headerSearchSize 1024 // read this many bytes at beginning of - // file to look for '%PDF' -#define pdfIdLength 32 // PDF Document IDs (PermanentId, UpdateId) length - -#define linearizationSearchSize 1024 // read this many bytes at beginning of - // file to look for linearization - // dictionary - -#define xrefSearchSize 1024 // read this many bytes at end of file - // to look for 'startxref' - -//------------------------------------------------------------------------ -// PDFDoc -//------------------------------------------------------------------------ - -void PDFDoc::init() -{ -#ifdef MULTITHREADED - gInitMutex(&mutex); -#endif - ok = gFalse; - errCode = errNone; - fileName = NULL; - file = NULL; - str = NULL; - xref = NULL; - linearization = NULL; - catalog = NULL; - hints = NULL; -#ifndef DISABLE_OUTLINE - outline = NULL; -#endif - startXRefPos = -1; - secHdlr = NULL; - pageCache = NULL; -} - -PDFDoc::PDFDoc() -{ - init(); -} - -PDFDoc::PDFDoc(GooString *fileNameA, GooString *ownerPassword, - GooString *userPassword, void *guiDataA) { -#ifdef _WIN32 - int n, i; -#endif - - init(); - - fileName = fileNameA; - guiData = guiDataA; -#ifdef _WIN32 - n = fileName->getLength(); - fileNameU = (wchar_t *)gmallocn(n + 1, sizeof(wchar_t)); - for (i = 0; i < n; ++i) { - fileNameU[i] = (wchar_t)(fileName->getChar(i) & 0xff); - } - fileNameU[n] = L'\0'; -#endif - - // try to open file -#ifdef _WIN32 - wchar_t *wFileName = (wchar_t*)utf8ToUtf16(fileName->getCString()); - file = GooFile::open(wFileName); - gfree(wFileName); -#else - file = GooFile::open(fileName); -#endif - if (file == NULL) { - // fopen() has failed. - // Keep a copy of the errno returned by fopen so that it can be - // referred to later. - fopenErrno = errno; - error(errIO, -1, "Couldn't open file '{0:t}': {1:s}.", fileName, strerror(errno)); - errCode = errOpenFile; - return; - } - - // create stream - str = new FileStream(file, 0, gFalse, file->size(), Object(objNull)); - - ok = setup(ownerPassword, userPassword); -} - -#ifdef _WIN32 -PDFDoc::PDFDoc(wchar_t *fileNameA, int fileNameLen, GooString *ownerPassword, - GooString *userPassword, void *guiDataA) { - OSVERSIONINFO version; - int i; - - init(); - - guiData = guiDataA; - - // save both Unicode and 8-bit copies of the file name - fileName = new GooString(); - fileNameU = (wchar_t *)gmallocn(fileNameLen + 1, sizeof(wchar_t)); - for (i = 0; i < fileNameLen; ++i) { - fileName->append((char)fileNameA[i]); - fileNameU[i] = fileNameA[i]; - } - fileNameU[fileNameLen] = L'\0'; - - // try to open file - // NB: _wfopen is only available in NT - version.dwOSVersionInfoSize = sizeof(version); - GetVersionEx(&version); - if (version.dwPlatformId == VER_PLATFORM_WIN32_NT) { - file = GooFile::open(fileNameU); - } else { - file = GooFile::open(fileName); - } - if (!file) { - error(errIO, -1, "Couldn't open file '{0:t}'", fileName); - errCode = errOpenFile; - return; - } - - // create stream - str = new FileStream(file, 0, gFalse, file->size(), Object(objNull)); - - ok = setup(ownerPassword, userPassword); -} -#endif - -PDFDoc::PDFDoc(BaseStream *strA, GooString *ownerPassword, - GooString *userPassword, void *guiDataA) { -#ifdef _WIN32 - int n, i; -#endif - - init(); - guiData = guiDataA; - if (strA->getFileName()) { - fileName = strA->getFileName()->copy(); -#ifdef _WIN32 - n = fileName->getLength(); - fileNameU = (wchar_t *)gmallocn(n + 1, sizeof(wchar_t)); - for (i = 0; i < n; ++i) { - fileNameU[i] = (wchar_t)(fileName->getChar(i) & 0xff); - } - fileNameU[n] = L'\0'; -#endif - } else { - fileName = NULL; -#ifdef _WIN32 - fileNameU = NULL; -#endif - } - str = strA; - ok = setup(ownerPassword, userPassword); -} - -GBool PDFDoc::setup(GooString *ownerPassword, GooString *userPassword) { - pdfdocLocker(); - str->setPos(0, -1); - if (str->getPos() < 0) - { - error(errSyntaxError, -1, "Document base stream is not seekable"); - return gFalse; - } - - str->reset(); - - // check footer - // Adobe does not seem to enforce %%EOF, so we do the same -// if (!checkFooter()) return gFalse; - - // check header - checkHeader(); - - GBool wasReconstructed = false; - - // read xref table - xref = new XRef(str, getStartXRef(), getMainXRefEntriesOffset(), &wasReconstructed); - if (!xref->isOk()) { - if (wasReconstructed) { - delete xref; - startXRefPos = -1; - xref = new XRef(str, getStartXRef(gTrue), getMainXRefEntriesOffset(gTrue), &wasReconstructed); - } - if (!xref->isOk()) { - error(errSyntaxError, -1, "Couldn't read xref table"); - errCode = xref->getErrorCode(); - return gFalse; - } - } - - // check for encryption - if (!checkEncryption(ownerPassword, userPassword)) { - errCode = errEncrypted; - return gFalse; - } - - // read catalog - catalog = new Catalog(this); - if (catalog && !catalog->isOk()) { - if (!wasReconstructed) - { - // try one more time to contruct the Catalog, maybe the problem is damaged XRef - delete catalog; - delete xref; - xref = new XRef(str, 0, 0, NULL, true); - catalog = new Catalog(this); - } - - if (catalog && !catalog->isOk()) { - error(errSyntaxError, -1, "Couldn't read page catalog"); - errCode = errBadCatalog; - return gFalse; - } - } - - // done - return gTrue; -} - -PDFDoc::~PDFDoc() { - if (pageCache) { - for (int i = 0; i < getNumPages(); i++) { - if (pageCache[i]) { - delete pageCache[i]; - } - } - gfree(pageCache); - } - delete secHdlr; -#ifndef DISABLE_OUTLINE - if (outline) { - delete outline; - } -#endif - if (catalog) { - delete catalog; - } - if (xref) { - delete xref; - } - if (hints) { - delete hints; - } - if (linearization) { - delete linearization; - } - if (str) { - delete str; - } - if (file) { - delete file; - } - if (fileName) { - delete fileName; - } -#ifdef _WIN32 - if (fileNameU) { - gfree(fileNameU); - } -#endif -#ifdef MULTITHREADED - gDestroyMutex(&mutex); -#endif -} - - -// Check for a %%EOF at the end of this stream -GBool PDFDoc::checkFooter() { - // we look in the last 1024 chars because Adobe does the same - char *eof = new char[1025]; - Goffset pos = str->getPos(); - str->setPos(1024, -1); - int i, ch; - for (i = 0; i < 1024; i++) - { - ch = str->getChar(); - if (ch == EOF) - break; - eof[i] = ch; - } - eof[i] = '\0'; - - bool found = false; - for (i = i - 5; i >= 0; i--) { - if (strncmp (&eof[i], "%%EOF", 5) == 0) { - found = true; - break; - } - } - if (!found) - { - error(errSyntaxError, -1, "Document has not the mandatory ending %%EOF"); - errCode = errDamaged; - delete[] eof; - return gFalse; - } - delete[] eof; - str->setPos(pos); - return gTrue; -} - -// Check for a PDF header on this stream. Skip past some garbage -// if necessary. -void PDFDoc::checkHeader() { - char hdrBuf[headerSearchSize+1]; - char *p; - char *tokptr; - int i; - - pdfMajorVersion = 0; - pdfMinorVersion = 0; - for (i = 0; i < headerSearchSize; ++i) { - hdrBuf[i] = str->getChar(); - } - hdrBuf[headerSearchSize] = '\0'; - for (i = 0; i < headerSearchSize - 5; ++i) { - if (!strncmp(&hdrBuf[i], "%PDF-", 5)) { - break; - } - } - if (i >= headerSearchSize - 5) { - error(errSyntaxWarning, -1, "May not be a PDF file (continuing anyway)"); - return; - } - str->moveStart(i); - if (!(p = strtok_r(&hdrBuf[i+5], " \t\n\r", &tokptr))) { - error(errSyntaxWarning, -1, "May not be a PDF file (continuing anyway)"); - return; - } - sscanf(p, "%d.%d", &pdfMajorVersion, &pdfMinorVersion); - // We don't do the version check. Don't add it back in. -} - -GBool PDFDoc::checkEncryption(GooString *ownerPassword, GooString *userPassword) { - GBool encrypted; - GBool ret; - - Object encrypt = xref->getTrailerDict()->dictLookup("Encrypt"); - if ((encrypted = encrypt.isDict())) { - if ((secHdlr = SecurityHandler::make(this, &encrypt))) { - if (secHdlr->isUnencrypted()) { - // no encryption - ret = gTrue; - } else if (secHdlr->checkEncryption(ownerPassword, userPassword)) { - // authorization succeeded - xref->setEncryption(secHdlr->getPermissionFlags(), - secHdlr->getOwnerPasswordOk(), - secHdlr->getFileKey(), - secHdlr->getFileKeyLength(), - secHdlr->getEncVersion(), - secHdlr->getEncRevision(), - secHdlr->getEncAlgorithm()); - ret = gTrue; - } else { - // authorization failed - ret = gFalse; - } - } else { - // couldn't find the matching security handler - ret = gFalse; - } - } else { - // document is not encrypted - ret = gTrue; - } - return ret; -} - -std::vector<FormWidgetSignature*> PDFDoc::getSignatureWidgets() -{ - int num_pages = getNumPages(); - FormPageWidgets *page_widgets = NULL; - std::vector<FormWidgetSignature*> widget_vector; - - for (int i = 1; i <= num_pages; i++) { - Page *p = getCatalog()->getPage(i); - if (p) { - page_widgets = p->getFormWidgets(); - for (int j = 0; page_widgets != NULL && j < page_widgets->getNumWidgets(); j++) { - if (page_widgets->getWidget(j)->getType() == formSignature) { - widget_vector.push_back(static_cast<FormWidgetSignature*>(page_widgets->getWidget(j))); - } - } - delete page_widgets; - } - } - return widget_vector; -} - -void PDFDoc::displayPage(OutputDev *out, int page, - double hDPI, double vDPI, int rotate, - GBool useMediaBox, GBool crop, GBool printing, - GBool (*abortCheckCbk)(void *data), - void *abortCheckCbkData, - GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), - void *annotDisplayDecideCbkData, GBool copyXRef) { - if (globalParams->getPrintCommands()) { - printf("***** page %d *****\n", page); - } - - if (getPage(page)) - getPage(page)->display(out, hDPI, vDPI, - rotate, useMediaBox, crop, printing, - abortCheckCbk, abortCheckCbkData, - annotDisplayDecideCbk, annotDisplayDecideCbkData, copyXRef); - -} - -void PDFDoc::displayPages(OutputDev *out, int firstPage, int lastPage, - double hDPI, double vDPI, int rotate, - GBool useMediaBox, GBool crop, GBool printing, - GBool (*abortCheckCbk)(void *data), - void *abortCheckCbkData, - GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), - void *annotDisplayDecideCbkData) { - int page; - - for (page = firstPage; page <= lastPage; ++page) { - displayPage(out, page, hDPI, vDPI, rotate, useMediaBox, crop, printing, - abortCheckCbk, abortCheckCbkData, - annotDisplayDecideCbk, annotDisplayDecideCbkData); - } -} - -void PDFDoc::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), - void *abortCheckCbkData, - GBool (*annotDisplayDecideCbk)(Annot *annot, void *user_data), - void *annotDisplayDecideCbkData, GBool copyXRef) { - if (getPage(page)) - getPage(page)->displaySlice(out, hDPI, vDPI, - rotate, useMediaBox, crop, - sliceX, sliceY, sliceW, sliceH, - printing, - abortCheckCbk, abortCheckCbkData, - annotDisplayDecideCbk, annotDisplayDecideCbkData, copyXRef); -} - -Links *PDFDoc::getLinks(int page) { - Page *p = getPage(page); - if (!p) { - return new Links (NULL); - } - return p->getLinks(); -} - -void PDFDoc::processLinks(OutputDev *out, int page) { - if (getPage(page)) - getPage(page)->processLinks(out); -} - -Linearization *PDFDoc::getLinearization() -{ - if (!linearization) { - linearization = new Linearization(str); - linearizationState = 0; - } - return linearization; -} - -GBool PDFDoc::checkLinearization() { - if (linearization == NULL) - return gFalse; - if (linearizationState == 1) - return gTrue; - if (linearizationState == 2) - return gFalse; - if (!hints) { - hints = new Hints(str, linearization, getXRef(), secHdlr); - } - if (!hints->isOk()) { - linearizationState = 2; - return gFalse; - } - for (int page = 1; page <= linearization->getNumPages(); page++) { - Ref pageRef; - - pageRef.num = hints->getPageObjectNum(page); - if (!pageRef.num) { - linearizationState = 2; - return gFalse; - } - - // check for bogus ref - this can happen in corrupted PDF files - if (pageRef.num < 0 || pageRef.num >= xref->getNumObjects()) { - linearizationState = 2; - return gFalse; - } - - pageRef.gen = xref->getEntry(pageRef.num)->gen; - Object obj = xref->fetch(pageRef.num, pageRef.gen); - if (!obj.isDict("Page")) { - linearizationState = 2; - return gFalse; - } - } - linearizationState = 1; - return gTrue; -} - -GBool PDFDoc::isLinearized(GBool tryingToReconstruct) { - if ((str->getLength()) && - (getLinearization()->getLength() == str->getLength())) - return gTrue; - else { - if (tryingToReconstruct) - return getLinearization()->getLength() > 0; - else - return gFalse; - } -} - -void PDFDoc::setDocInfoModified(Object *infoObj) -{ - Object infoObjRef = getDocInfoNF(); - xref->setModifiedObject(infoObj, infoObjRef.getRef()); -} - -void PDFDoc::setDocInfoStringEntry(const char *key, GooString *value) -{ - GBool removeEntry = !value || value->getLength() == 0 || value->hasJustUnicodeMarker(); - if (removeEntry) { - delete value; - } - - Object infoObj = getDocInfo(); - if (infoObj.isNull() && removeEntry) { - // No info dictionary, so no entry to remove. - return; - } - - infoObj = createDocInfoIfNoneExists(); - if (removeEntry) { - infoObj.dictSet(key, Object(objNull)); - } else { - infoObj.dictSet(key, Object(value)); - } - - - if (infoObj.dictGetLength() == 0) { - // Info dictionary is empty. Remove it altogether. - removeDocInfo(); - } else { - setDocInfoModified(&infoObj); - } -} - -GooString *PDFDoc::getDocInfoStringEntry(const char *key) { - Object infoObj = getDocInfo(); - if (!infoObj.isDict()) { - return NULL; - } - - Object entryObj = infoObj.dictLookup(key); - - GooString *result; - - if (entryObj.isString()) { - result = entryObj.takeString(); - } else { - result = NULL; - } - - return result; -} - -static GBool -get_id (GooString *encodedidstring, GooString *id) { - const char *encodedid = encodedidstring->getCString(); - char pdfid[pdfIdLength + 1]; - int n; - - if (encodedidstring->getLength() != pdfIdLength / 2) - return gFalse; - - 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, 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); - if (n != pdfIdLength) - return gFalse; - - id->Set(pdfid, pdfIdLength); - return gTrue; -} - -GBool PDFDoc::getID(GooString *permanent_id, GooString *update_id) { - Object obj = xref->getTrailerDict()->dictLookup ("ID"); - - if (obj.isArray() && obj.arrayGetLength() == 2) { - if (permanent_id) { - Object obj2 = obj.arrayGet(0); - if (obj2.isString()) { - if (!get_id (obj2.getString(), permanent_id)) { - return gFalse; - } - } else { - error(errSyntaxError, -1, "Invalid permanent ID"); - return gFalse; - } - } - - if (update_id) { - Object obj2 = obj.arrayGet(1); - if (obj2.isString()) { - if (!get_id (obj2.getString(), update_id)) { - return gFalse; - } - } else { - error(errSyntaxError, -1, "Invalid update ID"); - return gFalse; - } - } - - return gTrue; - } - - return gFalse; -} - -Hints *PDFDoc::getHints() -{ - if (!hints && isLinearized()) { - hints = new Hints(str, getLinearization(), getXRef(), secHdlr); - } - - return hints; -} - -int PDFDoc::savePageAs(GooString *name, int pageNo) -{ - FILE *f; - OutStream *outStr; - XRef *yRef, *countRef; - int rootNum = getXRef()->getNumObjects() + 1; - - // Make sure that special flags are set, because we are going to read - // all objects, including Unencrypted ones. - xref->scanSpecialFlags(); - - Guchar *fileKey; - CryptAlgorithm encAlgorithm; - int keyLength; - xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength); - - if (pageNo < 1 || pageNo > getNumPages() || !getCatalog()->getPage(pageNo)) { - error(errInternal, -1, "Illegal pageNo: {0:d}({1:d})", pageNo, getNumPages() ); - return errOpenFile; - } - PDFRectangle *cropBox = NULL; - if (getCatalog()->getPage(pageNo)->isCropped()) { - cropBox = getCatalog()->getPage(pageNo)->getCropBox(); - } - replacePageDict(pageNo, - getCatalog()->getPage(pageNo)->getRotate(), - getCatalog()->getPage(pageNo)->getMediaBox(), - cropBox); - Ref *refPage = getCatalog()->getPageRef(pageNo); - Object page = getXRef()->fetch(refPage->num, refPage->gen); - - if (!(f = fopen(name->getCString(), "wb"))) { - error(errIO, -1, "Couldn't open file '{0:t}'", name); - return errOpenFile; - } - outStr = new FileOutStream(f,0); - - yRef = new XRef(getXRef()->getTrailerDict()); - - if (secHdlr != NULL && !secHdlr->isUnencrypted()) { - yRef->setEncryption(secHdlr->getPermissionFlags(), - secHdlr->getOwnerPasswordOk(), fileKey, keyLength, secHdlr->getEncVersion(), secHdlr->getEncRevision(), encAlgorithm); - } - countRef = new XRef(); - Object *trailerObj = getXRef()->getTrailerDict(); - if (trailerObj->isDict()) { - markPageObjects(trailerObj->getDict(), yRef, countRef, 0, refPage->num, rootNum + 2); - } - yRef->add(0, 65535, 0, gFalse); - writeHeader(outStr, getPDFMajorVersion(), getPDFMinorVersion()); - - // get and mark info dict - Object infoObj = getXRef()->getDocInfo(); - if (infoObj.isDict()) { - Dict *infoDict = infoObj.getDict(); - markPageObjects(infoDict, yRef, countRef, 0, refPage->num, rootNum + 2); - if (trailerObj->isDict()) { - Dict *trailerDict = trailerObj->getDict(); - Object ref = trailerDict->lookupNF("Info"); - if (ref.isRef()) { - yRef->add(ref.getRef().num, ref.getRef().gen, 0, gTrue); - if (getXRef()->getEntry(ref.getRef().num)->type == xrefEntryCompressed) { - yRef->getEntry(ref.getRef().num)->type = xrefEntryCompressed; - } - } - } - } - - // get and mark output intents etc. - Object catObj = getXRef()->getCatalog(); - Dict *catDict = catObj.getDict(); - Object pagesObj = catDict->lookup("Pages"); - Object afObj = catDict->lookupNF("AcroForm"); - if (!afObj.isNull()) { - markAcroForm(&afObj, yRef, countRef, 0, refPage->num, rootNum + 2); - } - Dict *pagesDict = pagesObj.getDict(); - Object resourcesObj = pagesDict->lookup("Resources"); - if (resourcesObj.isDict()) - markPageObjects(resourcesObj.getDict(), yRef, countRef, 0, refPage->num, rootNum + 2); - markPageObjects(catDict, yRef, countRef, 0, refPage->num, rootNum + 2); - - Dict *pageDict = page.getDict(); - if (resourcesObj.isNull() && !pageDict->hasKey("Resources")) { - Object *resourceDictObject = getCatalog()->getPage(pageNo)->getResourceDictObject(); - if (resourceDictObject->isDict()) { - resourcesObj = resourceDictObject->copy(); - markPageObjects(resourcesObj.getDict(), yRef, countRef, 0, refPage->num, rootNum + 2); - } - } - markPageObjects(pageDict, yRef, countRef, 0, refPage->num, rootNum + 2); - Object annotsObj = pageDict->lookupNF("Annots"); - if (!annotsObj.isNull()) { - markAnnotations(&annotsObj, yRef, countRef, 0, refPage->num, rootNum + 2); - } - yRef->markUnencrypted(); - writePageObjects(outStr, yRef, 0); - - yRef->add(rootNum,0,outStr->getPos(),gTrue); - outStr->printf("%d 0 obj\n", rootNum); - outStr->printf("<< /Type /Catalog /Pages %d 0 R", rootNum + 1); - for (int j = 0; j < catDict->getLength(); j++) { - const char *key = catDict->getKey(j); - if (strcmp(key, "Type") != 0 && - strcmp(key, "Catalog") != 0 && - strcmp(key, "Pages") != 0) - { - if (j > 0) outStr->printf(" "); - Object value = catDict->getValNF(j); - outStr->printf("/%s ", key); - writeObject(&value, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0); - } - } - outStr->printf(">>\nendobj\n"); - - yRef->add(rootNum + 1,0,outStr->getPos(),gTrue); - outStr->printf("%d 0 obj\n", rootNum + 1); - outStr->printf("<< /Type /Pages /Kids [ %d 0 R ] /Count 1 ", rootNum + 2); - if (resourcesObj.isDict()) { - outStr->printf("/Resources "); - writeObject(&resourcesObj, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0); - } - outStr->printf(">>\n"); - outStr->printf("endobj\n"); - - yRef->add(rootNum + 2,0,outStr->getPos(),gTrue); - outStr->printf("%d 0 obj\n", rootNum + 2); - outStr->printf("<< "); - for (int n = 0; n < pageDict->getLength(); n++) { - if (n > 0) outStr->printf(" "); - const char *key = pageDict->getKey(n); - Object value = pageDict->getValNF(n); - if (strcmp(key, "Parent") == 0) { - outStr->printf("/Parent %d 0 R", rootNum + 1); - } else { - outStr->printf("/%s ", key); - writeObject(&value, outStr, getXRef(), 0, NULL, cryptRC4, 0, 0, 0); - } - } - outStr->printf(" >>\nendobj\n"); - - Goffset uxrefOffset = outStr->getPos(); - Ref ref; - ref.num = rootNum; - ref.gen = 0; - Object trailerDict = createTrailerDict(rootNum + 3, gFalse, 0, &ref, getXRef(), - name->getCString(), uxrefOffset); - writeXRefTableTrailer(std::move(trailerDict), yRef, gFalse /* do not write unnecessary entries */, - uxrefOffset, outStr, getXRef()); - - outStr->close(); - fclose(f); - delete yRef; - delete countRef; - delete outStr; - - return errNone; -} - -int PDFDoc::saveAs(GooString *name, PDFWriteMode mode) { - FILE *f; - OutStream *outStr; - int res; - - if (!(f = fopen(name->getCString(), "wb"))) { - error(errIO, -1, "Couldn't open file '{0:t}'", name); - return errOpenFile; - } - outStr = new FileOutStream(f,0); - res = saveAs(outStr, mode); - delete outStr; - fclose(f); - return res; -} - -int PDFDoc::saveAs(OutStream *outStr, PDFWriteMode mode) { - if (!xref->isModified() && mode == writeStandard) { - // simply copy the original file - saveWithoutChangesAs (outStr); - } else if (mode == writeForceRewrite) { - saveCompleteRewrite(outStr); - } else { - saveIncrementalUpdate(outStr); - } - - return errNone; -} - -int PDFDoc::saveWithoutChangesAs(GooString *name) { - FILE *f; - OutStream *outStr; - int res; - - if (!(f = fopen(name->getCString(), "wb"))) { - error(errIO, -1, "Couldn't open file '{0:t}'", name); - return errOpenFile; - } - - outStr = new FileOutStream(f,0); - res = saveWithoutChangesAs(outStr); - delete outStr; - - fclose(f); - - return res; -} - -int PDFDoc::saveWithoutChangesAs(OutStream *outStr) { - int c; - - BaseStream *copyStr = str->copy(); - copyStr->reset(); - while ((c = copyStr->getChar()) != EOF) { - outStr->put(c); - } - copyStr->close(); - delete copyStr; - - return errNone; -} - -void PDFDoc::saveIncrementalUpdate (OutStream* outStr) -{ - XRef *uxref; - int c; - //copy the original file - BaseStream *copyStr = str->copy(); - copyStr->reset(); - while ((c = copyStr->getChar()) != EOF) { - outStr->put(c); - } - copyStr->close(); - delete copyStr; - - Guchar *fileKey; - CryptAlgorithm encAlgorithm; - int keyLength; - xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength); - - uxref = new XRef(); - uxref->add(0, 65535, 0, gFalse); - xref->lock(); - for(int i=0; i<xref->getNumObjects(); i++) { - if ((xref->getEntry(i)->type == xrefEntryFree) && - (xref->getEntry(i)->gen == 0)) //we skip the irrelevant free objects - continue; - - if (xref->getEntry(i)->getFlag(XRefEntry::Updated)) { //we have an updated object - Ref ref; - ref.num = i; - ref.gen = xref->getEntry(i)->type == xrefEntryCompressed ? 0 : xref->getEntry(i)->gen; - if (xref->getEntry(i)->type != xrefEntryFree) { - Object obj1 = xref->fetch(ref.num, ref.gen, 1); - Goffset offset = writeObjectHeader(&ref, outStr); - writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen); - writeObjectFooter(outStr); - uxref->add(ref.num, ref.gen, offset, gTrue); - } else { - uxref->add(ref.num, ref.gen, 0, gFalse); - } - } - } - xref->unlock(); - // because of "uxref->add(0, 65535, 0, gFalse);" uxref->getNumObjects() will - // always be >= 1; if it is 1, it means there is nothing to update - if (uxref->getNumObjects() == 1) { - delete uxref; - return; - } - - Goffset uxrefOffset = outStr->getPos(); - int numobjects = xref->getNumObjects(); - const char *fileNameA = fileName ? fileName->getCString() : NULL; - Ref rootRef, uxrefStreamRef; - rootRef.num = getXRef()->getRootNum(); - rootRef.gen = getXRef()->getRootGen(); - - // Output a xref stream if there is a xref stream already - GBool xRefStream = xref->isXRefStream(); - - if (xRefStream) { - // Append an entry for the xref stream itself - uxrefStreamRef.num = numobjects++; - uxrefStreamRef.gen = 0; - uxref->add(uxrefStreamRef.num, uxrefStreamRef.gen, uxrefOffset, gTrue); - } - - Object trailerDict = createTrailerDict(numobjects, gTrue, getStartXRef(), &rootRef, getXRef(), fileNameA, uxrefOffset); - if (xRefStream) { - writeXRefStreamTrailer(std::move(trailerDict), uxref, &uxrefStreamRef, uxrefOffset, outStr, getXRef()); - } else { - writeXRefTableTrailer(std::move(trailerDict), uxref, gFalse, uxrefOffset, outStr, getXRef()); - } - - delete uxref; -} - -void PDFDoc::saveCompleteRewrite (OutStream* outStr) -{ - // Make sure that special flags are set, because we are going to read - // all objects, including Unencrypted ones. - xref->scanSpecialFlags(); - - Guchar *fileKey; - CryptAlgorithm encAlgorithm; - int keyLength; - xref->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength); - - outStr->printf("%%PDF-%d.%d\r\n",pdfMajorVersion,pdfMinorVersion); - XRef *uxref = new XRef(); - uxref->add(0, 65535, 0, gFalse); - xref->lock(); - for(int i=0; i<xref->getNumObjects(); i++) { - Ref ref; - XRefEntryType type = xref->getEntry(i)->type; - if (type == xrefEntryFree) { - ref.num = i; - ref.gen = xref->getEntry(i)->gen; - /* the XRef class adds a lot of irrelevant free entries, we only want the significant one - and we don't want the one with num=0 because it has already been added (gen = 65535)*/ - if (ref.gen > 0 && ref.num > 0) - uxref->add(ref.num, ref.gen, 0, gFalse); - } else if (xref->getEntry(i)->getFlag(XRefEntry::DontRewrite)) { - // This entry must not be written, put a free entry instead (with incremented gen) - ref.num = i; - ref.gen = xref->getEntry(i)->gen + 1; - uxref->add(ref.num, ref.gen, 0, gFalse); - } else if (type == xrefEntryUncompressed){ - ref.num = i; - ref.gen = xref->getEntry(i)->gen; - Object obj1 = xref->fetch(ref.num, ref.gen, 1); - Goffset offset = writeObjectHeader(&ref, outStr); - // Write unencrypted objects in unencrypted form - if (xref->getEntry(i)->getFlag(XRefEntry::Unencrypted)) { - writeObject(&obj1, outStr, NULL, cryptRC4, 0, 0, 0); - } else { - writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen); - } - writeObjectFooter(outStr); - uxref->add(ref.num, ref.gen, offset, gTrue); - } else if (type == xrefEntryCompressed) { - ref.num = i; - ref.gen = 0; //compressed entries have gen == 0 - Object obj1 = xref->fetch(ref.num, ref.gen, 1); - Goffset offset = writeObjectHeader(&ref, outStr); - writeObject(&obj1, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen); - writeObjectFooter(outStr); - uxref->add(ref.num, ref.gen, offset, gTrue); - } - } - xref->unlock(); - Goffset uxrefOffset = outStr->getPos(); - writeXRefTableTrailer(uxrefOffset, uxref, gTrue /* write all entries */, - uxref->getNumObjects(), outStr, gFalse /* complete rewrite */); - delete uxref; -} - -void PDFDoc::writeDictionnary (Dict* dict, OutStream* outStr, XRef *xRef, Guint numOffset, Guchar *fileKey, - CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen, std::set<Dict*> *alreadyWrittenDicts) -{ - bool deleteSet = false; - if (!alreadyWrittenDicts) { - alreadyWrittenDicts = new std::set<Dict*>; - deleteSet = true; - } - - if (alreadyWrittenDicts->find(dict) != alreadyWrittenDicts->end()) { - error(errSyntaxWarning, -1, "PDFDoc::writeDictionnary: Found recursive dicts"); - if (deleteSet) delete alreadyWrittenDicts; - return; - } else { - alreadyWrittenDicts->insert(dict); - } - - outStr->printf("<<"); - for (int i=0; i<dict->getLength(); i++) { - GooString keyName(dict->getKey(i)); - GooString *keyNameToPrint = keyName.sanitizedName(gFalse /* non ps mode */); - outStr->printf("/%s ", keyNameToPrint->getCString()); - delete keyNameToPrint; - Object obj1 = dict->getValNF(i); - writeObject(&obj1, outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen, alreadyWrittenDicts); - } - outStr->printf(">> "); - - if (deleteSet) { - delete alreadyWrittenDicts; - } -} - -void PDFDoc::writeStream (Stream* str, OutStream* outStr) -{ - outStr->printf("stream\r\n"); - str->reset(); - for (int c=str->getChar(); c!= EOF; c=str->getChar()) { - outStr->printf("%c", c); - } - outStr->printf("\r\nendstream\r\n"); -} - -void PDFDoc::writeRawStream (Stream* str, OutStream* outStr) -{ - Object obj1 = str->getDict()->lookup("Length"); - if (!obj1.isInt() && !obj1.isInt64()) { - error (errSyntaxError, -1, "PDFDoc::writeRawStream, no Length in stream dict"); - return; - } - - Goffset length; - if (obj1.isInt()) - length = obj1.getInt(); - else - length = obj1.getInt64(); - - outStr->printf("stream\r\n"); - str->unfilteredReset(); - for (Goffset i = 0; i < length; i++) { - int c = str->getUnfilteredChar(); - if (unlikely(c == EOF)) { - error (errSyntaxError, -1, "PDFDoc::writeRawStream: EOF reading stream"); - break; - } - outStr->printf("%c", c); - } - str->reset(); - outStr->printf("\r\nendstream\r\n"); -} - -void PDFDoc::writeString (GooString* s, OutStream* outStr, Guchar *fileKey, - CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen) -{ - // Encrypt string if encryption is enabled - GooString *sEnc = NULL; - if (fileKey) { - EncryptStream *enc = new EncryptStream(new MemStream(s->getCString(), 0, s->getLength(), Object(objNull)), - fileKey, encAlgorithm, keyLength, objNum, objGen); - sEnc = new GooString(); - int c; - enc->reset(); - while ((c = enc->getChar()) != EOF) { - sEnc->append((char)c); - } - - delete enc; - s = sEnc; - } - - // Write data - if (s->hasUnicodeMarker()) { - //unicode string don't necessary end with \0 - const char* c = s->getCString(); - outStr->printf("("); - for(int i=0; i<s->getLength(); i++) { - char unescaped = *(c+i)&0x000000ff; - //escape if needed - if (unescaped == '(' || unescaped == ')' || unescaped == '\\') - outStr->printf("%c", '\\'); - outStr->printf("%c", unescaped); - } - outStr->printf(") "); - } else { - const char* c = s->getCString(); - outStr->printf("("); - for(int i=0; i<s->getLength(); i++) { - char unescaped = *(c+i)&0x000000ff; - //escape if needed - if (unescaped == '\r') - outStr->printf("\\r"); - else if (unescaped == '\n') - outStr->printf("\\n"); - else { - if (unescaped == '(' || unescaped == ')' || unescaped == '\\') { - outStr->printf("%c", '\\'); - } - outStr->printf("%c", unescaped); - } - } - outStr->printf(") "); - } - - delete sEnc; -} - -Goffset PDFDoc::writeObjectHeader (Ref *ref, OutStream* outStr) -{ - Goffset offset = outStr->getPos(); - outStr->printf("%i %i obj ", ref->num, ref->gen); - return offset; -} - -void PDFDoc::writeObject (Object* obj, OutStream* outStr, XRef *xRef, Guint numOffset, Guchar *fileKey, - CryptAlgorithm encAlgorithm, int keyLength, int objNum, int objGen, std::set<Dict*> *alreadyWrittenDicts) -{ - Array *array; - - switch (obj->getType()) { - case objBool: - outStr->printf("%s ", obj->getBool()?"true":"false"); - break; - case objInt: - outStr->printf("%i ", obj->getInt()); - break; - case objInt64: - outStr->printf("%lli ", obj->getInt64()); - break; - case objReal: - { - GooString s; - s.appendf("{0:.10g}", obj->getReal()); - outStr->printf("%s ", s.getCString()); - break; - } - case objString: - writeString(obj->getString(), outStr, fileKey, encAlgorithm, keyLength, objNum, objGen); - break; - case objName: - { - GooString name(obj->getName()); - GooString *nameToPrint = name.sanitizedName(gFalse /* non ps mode */); - outStr->printf("/%s ", nameToPrint->getCString()); - delete nameToPrint; - break; - } - case objNull: - outStr->printf( "null "); - break; - case objArray: - array = obj->getArray(); - outStr->printf("["); - for (int i=0; i<array->getLength(); i++) { - Object obj1 = array->getNF(i); - writeObject(&obj1, outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen); - } - outStr->printf("] "); - break; - case objDict: - writeDictionnary (obj->getDict(), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen, alreadyWrittenDicts); - break; - case objStream: - { - //We can't modify stream with the current implementation (no write functions in Stream API) - // => the only type of streams which that have been modified are internal streams (=strWeird) - Stream *stream = obj->getStream(); - if (stream->getKind() == strWeird || stream->getKind() == strCrypt) { - //we write the stream unencoded => TODO: write stream encoder - - // Encrypt stream - EncryptStream *encStream = NULL; - GBool removeFilter = gTrue; - if (stream->getKind() == strWeird && fileKey) { - Object filter = stream->getDict()->lookup("Filter"); - if (!filter.isName("Crypt")) { - if (filter.isArray()) { - for (int i = 0; i < filter.arrayGetLength(); i++) { - Object filterEle = filter.arrayGet(i); - if (filterEle.isName("Crypt")) { - removeFilter = gFalse; - break; - } - } - if (removeFilter) { - encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, objNum, objGen); - encStream->setAutoDelete(gFalse); - stream = encStream; - } - } else { - encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, objNum, objGen); - encStream->setAutoDelete(gFalse); - stream = encStream; - } - } else { - removeFilter = gFalse; - } - } else if (fileKey != NULL) { // Encrypt stream - encStream = new EncryptStream(stream, fileKey, encAlgorithm, keyLength, objNum, objGen); - encStream->setAutoDelete(gFalse); - stream = encStream; - } - - stream->reset(); - //recalculate stream length - Goffset tmp = 0; - for (int c=stream->getChar(); c!=EOF; c=stream->getChar()) { - tmp++; - } - stream->getDict()->set("Length", Object(tmp)); - - //Remove Stream encoding - if (removeFilter) { - stream->getDict()->remove("Filter"); - } - stream->getDict()->remove("DecodeParms"); - - writeDictionnary (stream->getDict(),outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen, alreadyWrittenDicts); - writeStream (stream,outStr); - delete encStream; - } else { - //raw stream copy - FilterStream *fs = dynamic_cast<FilterStream*>(stream); - if (fs) { - BaseStream *bs = fs->getBaseStream(); - if (bs) { - Goffset streamEnd; - if (xRef->getStreamEnd(bs->getStart(), &streamEnd)) { - Goffset val = streamEnd - bs->getStart(); - stream->getDict()->set("Length", Object(val)); - } - } - } - writeDictionnary (stream->getDict(), outStr, xRef, numOffset, fileKey, encAlgorithm, keyLength, objNum, objGen, alreadyWrittenDicts); - writeRawStream (stream, outStr); - } - break; - } - case objRef: - outStr->printf("%i %i R ", obj->getRef().num + numOffset, obj->getRef().gen); - break; - case objCmd: - outStr->printf("%s\n", obj->getCmd()); - break; - case objError: - outStr->printf("error\r\n"); - break; - case objEOF: - outStr->printf("eof\r\n"); - break; - case objNone: - outStr->printf("none\r\n"); - break; - default: - error(errUnimplemented, -1,"Unhandled objType : {0:d}, please report a bug with a testcase\r\n", obj->getType()); - break; - } -} - -void PDFDoc::writeObjectFooter (OutStream* outStr) -{ - outStr->printf("endobj\r\n"); -} - -Object PDFDoc::createTrailerDict(int uxrefSize, GBool incrUpdate, Goffset startxRef, - Ref *root, XRef *xRef, const char *fileName, Goffset fileSize) -{ - Dict *trailerDict = new Dict(xRef); - trailerDict->set("Size", Object(uxrefSize)); - - //build a new ID, as recommended in the reference, uses: - // - current time - // - file name - // - file size - // - values of entry in information dictionnary - GooString message; - char buffer[256]; - sprintf(buffer, "%i", (int)time(NULL)); - message.append(buffer); - - if (fileName) - message.append(fileName); - - sprintf(buffer, "%lli", (long long)fileSize); - message.append(buffer); - - //info dict -- only use text string - if (!xRef->getTrailerDict()->isNone()) { - Object docInfo = xRef->getDocInfo(); - if (docInfo.isDict()) { - for(int i=0; i<docInfo.getDict()->getLength(); i++) { - Object obj2 = docInfo.getDict()->getVal(i); - if (obj2.isString()) { - message.append(obj2.getString()); - } - } - } - } - - GBool hasEncrypt = gFalse; - if (!xRef->getTrailerDict()->isNone()) { - Object obj2 = xRef->getTrailerDict()->dictLookupNF("Encrypt"); - if (!obj2.isNull()) { - trailerDict->set("Encrypt", std::move(obj2)); - hasEncrypt = gTrue; - } - } - - //calculate md5 digest - Guchar digest[16]; - md5((Guchar*)message.getCString(), message.getLength(), digest); - - //create ID array - // In case of encrypted files, the ID must not be changed because it's used to calculate the key - if (incrUpdate || hasEncrypt) { - //only update the second part of the array - Object obj4 = xRef->getTrailerDict()->getDict()->lookup("ID"); - if (!obj4.isArray()) { - error(errSyntaxWarning, -1, "PDFDoc::createTrailerDict original file's ID entry isn't an array. Trying to continue"); - } else { - Array *array = new Array(xRef); - //Get the first part of the ID - array->add(obj4.arrayGet(0)); - array->add(Object(new GooString((const char*)digest, 16))); - trailerDict->set("ID", Object(array)); - } - } else { - //new file => same values for the two identifiers - Array *array = new Array(xRef); - array->add(Object(new GooString((const char*)digest, 16))); - array->add(Object(new GooString((const char*)digest, 16))); - trailerDict->set("ID", Object(array)); - } - - trailerDict->set("Root", Object(root->num, root->gen)); - - if (incrUpdate) { - trailerDict->set("Prev", Object(startxRef)); - } - - if (!xRef->getTrailerDict()->isNone()) { - Object obj5 = xRef->getDocInfoNF(); - if (!obj5.isNull()) { - trailerDict->set("Info", std::move(obj5)); - } - } - - return Object(trailerDict); -} - -void PDFDoc::writeXRefTableTrailer(Object &&trailerDict, XRef *uxref, GBool writeAllEntries, Goffset uxrefOffset, OutStream* outStr, XRef *xRef) -{ - uxref->writeTableToFile( outStr, writeAllEntries ); - outStr->printf( "trailer\r\n"); - writeDictionnary(trailerDict.getDict(), outStr, xRef, 0, NULL, cryptRC4, 0, 0, 0, nullptr); - outStr->printf( "\r\nstartxref\r\n"); - outStr->printf( "%lli\r\n", uxrefOffset); - outStr->printf( "%%%%EOF\r\n"); -} - -void PDFDoc::writeXRefStreamTrailer (Object &&trailerDict, XRef *uxref, Ref *uxrefStreamRef, Goffset uxrefOffset, OutStream* outStr, XRef *xRef) -{ - GooString stmData; - - // Fill stmData and some trailerDict fields - uxref->writeStreamToBuffer(&stmData, trailerDict.getDict(), xRef); - - // Create XRef stream object and write it - MemStream *mStream = new MemStream( stmData.getCString(), 0, stmData.getLength(), std::move(trailerDict) ); - writeObjectHeader(uxrefStreamRef, outStr); - Object obj1(static_cast<Stream*>(mStream)); - writeObject(&obj1, outStr, xRef, 0, NULL, cryptRC4, 0, 0, 0); - writeObjectFooter(outStr); - - outStr->printf( "startxref\r\n"); - outStr->printf( "%lli\r\n", uxrefOffset); - outStr->printf( "%%%%EOF\r\n"); -} - -void PDFDoc::writeXRefTableTrailer(Goffset uxrefOffset, XRef *uxref, GBool writeAllEntries, - int uxrefSize, OutStream* outStr, GBool incrUpdate) -{ - const char *fileNameA = fileName ? fileName->getCString() : NULL; - // file size (doesn't include the trailer) - unsigned int fileSize = 0; - int c; - str->reset(); - while ((c = str->getChar()) != EOF) { - fileSize++; - } - str->close(); - Ref ref; - ref.num = getXRef()->getRootNum(); - ref.gen = getXRef()->getRootGen(); - Object trailerDict = createTrailerDict(uxrefSize, incrUpdate, getStartXRef(), &ref, - getXRef(), fileNameA, fileSize); - writeXRefTableTrailer(std::move(trailerDict), uxref, writeAllEntries, uxrefOffset, outStr, getXRef()); -} - -void PDFDoc::writeHeader(OutStream *outStr, int major, int minor) -{ - outStr->printf("%%PDF-%d.%d\n", major, minor); - outStr->printf("%%\xE2\xE3\xCF\xD3\n"); -} - -void PDFDoc::markDictionnary (Dict* dict, XRef * xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum, std::set<Dict*> *alreadyMarkedDicts) -{ - bool deleteSet = false; - if (!alreadyMarkedDicts) { - alreadyMarkedDicts = new std::set<Dict*>; - deleteSet = true; - } - - if (alreadyMarkedDicts->find(dict) != alreadyMarkedDicts->end()) { - error(errSyntaxWarning, -1, "PDFDoc::markDictionnary: Found recursive dicts"); - if (deleteSet) delete alreadyMarkedDicts; - return; - } else { - alreadyMarkedDicts->insert(dict); - } - - Object obj1; - for (int i=0; i<dict->getLength(); i++) { - const char *key = dict->getKey(i); - if (strcmp(key, "Annots") != 0) { - Object obj1 = dict->getValNF(i); - markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); - } else { - Object annotsObj = dict->getValNF(i); - if (!annotsObj.isNull()) { - markAnnotations(&annotsObj, xRef, countRef, 0, oldRefNum, newRefNum, alreadyMarkedDicts); - } - } - } - - if (deleteSet) { - delete alreadyMarkedDicts; - } -} - -void PDFDoc::markObject (Object* obj, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum, std::set<Dict*> *alreadyMarkedDicts) -{ - Array *array; - - switch (obj->getType()) { - case objArray: - array = obj->getArray(); - for (int i=0; i<array->getLength(); i++) { - Object obj1 = array->getNF(i); - markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum); - } - break; - case objDict: - markDictionnary (obj->getDict(), xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); - break; - case objStream: - { - Stream *stream = obj->getStream(); - markDictionnary (stream->getDict(), xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); - } - break; - case objRef: - { - if (obj->getRef().num + (int) numOffset >= xRef->getNumObjects() || xRef->getEntry(obj->getRef().num + numOffset)->type == xrefEntryFree) { - if (getXRef()->getEntry(obj->getRef().num)->type == xrefEntryFree) { - return; // already marked as free => should be replaced - } - xRef->add(obj->getRef().num + numOffset, obj->getRef().gen, 0, gTrue); - if (getXRef()->getEntry(obj->getRef().num)->type == xrefEntryCompressed) { - xRef->getEntry(obj->getRef().num + numOffset)->type = xrefEntryCompressed; - } - } - if (obj->getRef().num + (int) numOffset >= countRef->getNumObjects() || - countRef->getEntry(obj->getRef().num + numOffset)->type == xrefEntryFree) - { - countRef->add(obj->getRef().num + numOffset, 1, 0, gTrue); - } else { - XRefEntry *entry = countRef->getEntry(obj->getRef().num + numOffset); - entry->gen++; - if (entry->gen > 9) - break; - } - Object obj1 = getXRef()->fetch(obj->getRef().num, obj->getRef().gen); - markObject(&obj1, xRef, countRef, numOffset, oldRefNum, newRefNum); - } - break; - default: - break; - } -} - -void PDFDoc::replacePageDict(int pageNo, int rotate, - PDFRectangle *mediaBox, - PDFRectangle *cropBox) -{ - Ref *refPage = getCatalog()->getPageRef(pageNo); - Object page = getXRef()->fetch(refPage->num, refPage->gen); - Dict *pageDict = page.getDict(); - pageDict->remove("MediaBoxssdf"); - pageDict->remove("MediaBox"); - pageDict->remove("CropBox"); - pageDict->remove("ArtBox"); - pageDict->remove("BleedBox"); - pageDict->remove("TrimBox"); - pageDict->remove("Rotate"); - Array *mediaBoxArray = new Array(getXRef()); - mediaBoxArray->add(Object(mediaBox->x1)); - mediaBoxArray->add(Object(mediaBox->y1)); - mediaBoxArray->add(Object(mediaBox->x2)); - mediaBoxArray->add(Object(mediaBox->y2)); - Object mediaBoxObject(mediaBoxArray); - Object trimBoxObject = mediaBoxObject.copy(); - pageDict->add(copyString("MediaBox"), std::move(mediaBoxObject)); - if (cropBox != NULL) { - Array *cropBoxArray = new Array(getXRef()); - cropBoxArray->add(Object(cropBox->x1)); - cropBoxArray->add(Object(cropBox->y1)); - cropBoxArray->add(Object(cropBox->x2)); - cropBoxArray->add(Object(cropBox->y2)); - Object cropBoxObject(cropBoxArray); - trimBoxObject = cropBoxObject.copy(); - pageDict->add(copyString("CropBox"), std::move(cropBoxObject)); - } - pageDict->add(copyString("TrimBox"), std::move(trimBoxObject)); - pageDict->add(copyString("Rotate"), Object(rotate)); - getXRef()->setModifiedObject(&page, *refPage); -} - -void PDFDoc::markPageObjects(Dict *pageDict, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum, std::set<Dict*> *alreadyMarkedDicts) -{ - pageDict->remove("OpenAction"); - pageDict->remove("Outlines"); - pageDict->remove("StructTreeRoot"); - - for (int n = 0; n < pageDict->getLength(); n++) { - const char *key = pageDict->getKey(n); - Object value = pageDict->getValNF(n); - 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) { - markObject(&value, xRef, countRef, numOffset, oldRefNum, newRefNum, alreadyMarkedDicts); - } - } -} - -GBool PDFDoc::markAnnotations(Object *annotsObj, XRef *xRef, XRef *countRef, Guint numOffset, int oldPageNum, int newPageNum, std::set<Dict*> *alreadyMarkedDicts) { - GBool modified = gFalse; - Object annots = annotsObj->fetch(getXRef()); - if (annots.isArray()) { - Array *array = annots.getArray(); - for (int i=array->getLength() - 1; i >= 0; i--) { - Object obj1 = array->get(i); - if (obj1.isDict()) { - Dict *dict = obj1.getDict(); - Object type = dict->lookup("Type"); - if (type.isName() && strcmp(type.getName(), "Annot") == 0) { - Object obj2 = dict->lookupNF("P"); - if (obj2.isRef()) { - if (obj2.getRef().num == oldPageNum) { - Object obj3 = array->getNF(i); - if (obj3.isRef()) { - dict->set("P", Object(newPageNum, 0)); - getXRef()->setModifiedObject(&obj1, obj3.getRef()); - } - } else if (obj2.getRef().num == newPageNum) { - continue; - } else { - Object page = getXRef()->fetch(obj2.getRef().num, obj2.getRef().gen); - if (page.isDict()) { - Dict *dict = page.getDict(); - Object pagetype = dict->lookup("Type"); - if (!pagetype.isName() || strcmp(pagetype.getName(), "Page") != 0) { - continue; - } - } - array->remove(i); - modified = gTrue; - continue; - } - } - } - markPageObjects(dict, xRef, countRef, numOffset, oldPageNum, newPageNum, alreadyMarkedDicts); - } - obj1 = array->getNF(i); - if (obj1.isRef()) { - if (obj1.getRef().num + (int) numOffset >= xRef->getNumObjects() || xRef->getEntry(obj1.getRef().num + numOffset)->type == xrefEntryFree) { - if (getXRef()->getEntry(obj1.getRef().num)->type == xrefEntryFree) { - continue; // already marked as free => should be replaced - } - xRef->add(obj1.getRef().num + numOffset, obj1.getRef().gen, 0, gTrue); - if (getXRef()->getEntry(obj1.getRef().num)->type == xrefEntryCompressed) { - xRef->getEntry(obj1.getRef().num + numOffset)->type = xrefEntryCompressed; - } - } - if (obj1.getRef().num + (int) numOffset >= countRef->getNumObjects() || - countRef->getEntry(obj1.getRef().num + numOffset)->type == xrefEntryFree) - { - countRef->add(obj1.getRef().num + numOffset, 1, 0, gTrue); - } else { - XRefEntry *entry = countRef->getEntry(obj1.getRef().num + numOffset); - entry->gen++; - } - } - } - } - if (annotsObj->isRef()) { - if (annotsObj->getRef().num + (int) numOffset >= xRef->getNumObjects() || xRef->getEntry(annotsObj->getRef().num + numOffset)->type == xrefEntryFree) { - if (getXRef()->getEntry(annotsObj->getRef().num)->type == xrefEntryFree) { - return modified; // already marked as free => should be replaced - } - xRef->add(annotsObj->getRef().num + numOffset, annotsObj->getRef().gen, 0, gTrue); - if (getXRef()->getEntry(annotsObj->getRef().num)->type == xrefEntryCompressed) { - xRef->getEntry(annotsObj->getRef().num + numOffset)->type = xrefEntryCompressed; - } - } - if (annotsObj->getRef().num + (int) numOffset >= countRef->getNumObjects() || - countRef->getEntry(annotsObj->getRef().num + numOffset)->type == xrefEntryFree) - { - countRef->add(annotsObj->getRef().num + numOffset, 1, 0, gTrue); - } else { - XRefEntry *entry = countRef->getEntry(annotsObj->getRef().num + numOffset); - entry->gen++; - } - getXRef()->setModifiedObject(&annots, annotsObj->getRef()); - } - return modified; -} - -void PDFDoc::markAcroForm(Object *afObj, XRef *xRef, XRef *countRef, Guint numOffset, int oldRefNum, int newRefNum) { - GBool modified = gFalse; - Object acroform = afObj->fetch(getXRef()); - if (acroform.isDict()) { - Dict *dict = acroform.getDict(); - for (int i=0; i < dict->getLength(); i++) { - if (strcmp(dict->getKey(i), "Fields") == 0) { - Object fields = dict->getValNF(i); - modified = markAnnotations(&fields, xRef, countRef, numOffset, oldRefNum, newRefNum); - } else { - Object obj = dict->getValNF(i); - markObject(&obj, xRef, countRef, numOffset, oldRefNum, newRefNum); - } - } - } - if (afObj->isRef()) { - if (afObj->getRef().num + (int) numOffset >= xRef->getNumObjects() || xRef->getEntry(afObj->getRef().num + numOffset)->type == xrefEntryFree) { - if (getXRef()->getEntry(afObj->getRef().num)->type == xrefEntryFree) { - return; // already marked as free => should be replaced - } - xRef->add(afObj->getRef().num + numOffset, afObj->getRef().gen, 0, gTrue); - if (getXRef()->getEntry(afObj->getRef().num)->type == xrefEntryCompressed) { - xRef->getEntry(afObj->getRef().num + numOffset)->type = xrefEntryCompressed; - } - } - if (afObj->getRef().num + (int) numOffset >= countRef->getNumObjects() || - countRef->getEntry(afObj->getRef().num + numOffset)->type == xrefEntryFree) - { - countRef->add(afObj->getRef().num + numOffset, 1, 0, gTrue); - } else { - XRefEntry *entry = countRef->getEntry(afObj->getRef().num + numOffset); - entry->gen++; - } - if (modified){ - getXRef()->setModifiedObject(&acroform, afObj->getRef()); - } - } - return; -} - -Guint PDFDoc::writePageObjects(OutStream *outStr, XRef *xRef, Guint numOffset, GBool combine) -{ - Guint objectsCount = 0; //count the number of objects in the XRef(s) - Guchar *fileKey; - CryptAlgorithm encAlgorithm; - int keyLength; - xRef->getEncryptionParameters(&fileKey, &encAlgorithm, &keyLength); - - for (int n = numOffset; n < xRef->getNumObjects(); n++) { - if (xRef->getEntry(n)->type != xrefEntryFree) { - Ref ref; - ref.num = n; - ref.gen = xRef->getEntry(n)->gen; - objectsCount++; - Object obj = getXRef()->fetch(ref.num - numOffset, ref.gen); - Goffset offset = writeObjectHeader(&ref, outStr); - if (combine) { - writeObject(&obj, outStr, getXRef(), numOffset, NULL, cryptRC4, 0, 0, 0); - } else if (xRef->getEntry(n)->getFlag(XRefEntry::Unencrypted)) { - writeObject(&obj, outStr, NULL, cryptRC4, 0, 0, 0); - } else { - writeObject(&obj, outStr, fileKey, encAlgorithm, keyLength, ref.num, ref.gen); - } - writeObjectFooter(outStr); - xRef->add(ref.num, ref.gen, offset, gTrue); - } - } - return objectsCount; -} - -#ifndef DISABLE_OUTLINE -Outline *PDFDoc::getOutline() -{ - if (!outline) { - pdfdocLocker(); - // read outline - outline = new Outline(catalog->getOutline(), xref); - } - - return outline; -} -#endif - -PDFDoc *PDFDoc::ErrorPDFDoc(int errorCode, GooString *fileNameA) -{ - PDFDoc *doc = new PDFDoc(); - doc->errCode = errorCode; - doc->fileName = fileNameA; - - return doc; -} - -long long PDFDoc::strToLongLong(char *s) { - long long x, d; - char *p; - - x = 0; - for (p = s; *p && isdigit(*p & 0xff); ++p) { - d = *p - '0'; - if (x > (LLONG_MAX - d) / 10) { - break; - } - x = 10 * x + d; - } - return x; -} - -// Read the 'startxref' position. -Goffset PDFDoc::getStartXRef(GBool tryingToReconstruct) -{ - if (startXRefPos == -1) { - - if (isLinearized(tryingToReconstruct)) { - char buf[linearizationSearchSize+1]; - int c, n, i; - - str->setPos(0); - for (n = 0; n < linearizationSearchSize; ++n) { - if ((c = str->getChar()) == EOF) { - break; - } - buf[n] = c; - } - buf[n] = '\0'; - - // find end of first obj (linearization dictionary) - startXRefPos = 0; - for (i = 0; i < n; i++) { - if (!strncmp("endobj", &buf[i], 6)) { - i += 6; - //skip whitespace - while (buf[i] && Lexer::isSpace(buf[i])) ++i; - startXRefPos = i; - break; - } - } - } else { - char buf[xrefSearchSize+1]; - char *p; - int c, n, i; - - // read last xrefSearchSize bytes - int segnum = 0; - int maxXRefSearch = 24576; - if (str->getLength() < maxXRefSearch) maxXRefSearch = str->getLength(); - for (; (xrefSearchSize - 16) * segnum < maxXRefSearch; segnum++) { - str->setPos((xrefSearchSize - 16) * segnum + xrefSearchSize, -1); - for (n = 0; n < xrefSearchSize; ++n) { - if ((c = str->getChar()) == EOF) { - break; - } - buf[n] = c; - } - buf[n] = '\0'; - - // find startxref - for (i = n - 9; i >= 0; --i) { - if (!strncmp(&buf[i], "startxref", 9)) { - break; - } - } - if (i < 0) { - startXRefPos = 0; - } else { - for (p = &buf[i + 9]; isspace(*p); ++p); - startXRefPos = strToLongLong(p); - break; - } - } - } - - } - - return startXRefPos; -} - -Goffset PDFDoc::getMainXRefEntriesOffset(GBool tryingToReconstruct) -{ - Guint mainXRefEntriesOffset = 0; - - if (isLinearized(tryingToReconstruct)) { - mainXRefEntriesOffset = getLinearization()->getMainXRefEntriesOffset(); - } - - return mainXRefEntriesOffset; -} - -int PDFDoc::getNumPages() -{ - if (isLinearized()) { - int n; - if ((n = getLinearization()->getNumPages())) { - return n; - } - } - - return catalog->getNumPages(); -} - -Page *PDFDoc::parsePage(int page) -{ - Ref pageRef; - - pageRef.num = getHints()->getPageObjectNum(page); - if (!pageRef.num) { - error(errSyntaxWarning, -1, "Failed to get object num from hint tables for page {0:d}", page); - return NULL; - } - - // check for bogus ref - this can happen in corrupted PDF files - if (pageRef.num < 0 || pageRef.num >= xref->getNumObjects()) { - error(errSyntaxWarning, -1, "Invalid object num ({0:d}) for page {1:d}", pageRef.num, page); - return NULL; - } - - pageRef.gen = xref->getEntry(pageRef.num)->gen; - Object obj = xref->fetch(pageRef.num, pageRef.gen); - if (!obj.isDict("Page")) { - error(errSyntaxWarning, -1, "Object ({0:d} {1:d}) is not a pageDict", pageRef.num, pageRef.gen); - return NULL; - } - Dict *pageDict = obj.getDict(); - - return new Page(this, page, &obj, pageRef, - new PageAttrs(NULL, pageDict), catalog->getForm()); -} - -Page *PDFDoc::getPage(int page) -{ - if ((page < 1) || page > getNumPages()) return NULL; - - if (isLinearized() && checkLinearization()) { - pdfdocLocker(); - if (!pageCache) { - pageCache = (Page **) gmallocn(getNumPages(), sizeof(Page *)); - for (int i = 0; i < getNumPages(); i++) { - pageCache[i] = NULL; - } - } - if (!pageCache[page-1]) { - pageCache[page-1] = parsePage(page); - } - if (pageCache[page-1]) { - return pageCache[page-1]; - } else { - error(errSyntaxWarning, -1, "Failed parsing page {0:d} using hint tables", page); - } - } - - return catalog->getPage(page); -} -- GitLab