Bug#929252: unblock: qpdf/8.4.2-1
Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: unblock
Please unblock package qpdf
Note that I am both upstream and the debian maintainer for qpdf.
This is a non-critical but low-risk request. If it is too far into the
freeze to grant the request, I understand. The version in testing is
release-worthy but contains a few bugs that I have subsequently fixed.
The changes between qpdf 8.4.0 and 8.4.2 are bug fixes, but I am
asking for consideration because this update includes fixes to a
serious performance bug (CLI), a CLI non-compatibility bug, and a
library fix that could cause data loss in rare cases. These bugs are
all in the part of the code concerned with splitting and merging
documents, which is one of the main things people use the qpdf CLI
for. While these changes are not critical, it would be disappointing
if the version of qpdf in the next debian stable has these
already-fixed bugs.
I am including two debdiffs. First is one containing only changes to
non-test source code and debian files. Second is the complete debdiff,
which includes changes to automatically generated files, test code,
documentation, and a few other files that are not part of any
executable packages.
----------------------------------------------------------------------
source debdiff, relevant parts
diff -Nru qpdf-8.4.0/ChangeLog qpdf-8.4.2/ChangeLog
--- qpdf-8.4.0/ChangeLog 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/ChangeLog 2019-05-18 09:00:08.000000000 -0400
@@ -1,3 +1,59 @@
+2019-05-18 Jay Berkenbilt <ejb@ql.org>
+
+ * 8.4.2: release
+
+2019-05-16 Jay Berkenbilt <ejb@ql.org>
+
+ * Fix memory error in Windows-only code from typo. Fixes #330.
+
+2019-04-27 Jay Berkenbilt <ejb@ql.org>
+
+ * 8.4.1: release
+
+2019-04-20 Jay Berkenbilt <ejb@ql.org>
+
+ * When qpdf --version is run, it will detect if the qpdf CLI was
+ built with a different version of qpdf than the library. This
+ usually indicates that multiple versions of qpdf are installed and
+ that the library path is not set up properly. This situation
+ sometimes causes confusing behavior for users who are not actually
+ running the version of qpdf they think they are running.
+
+ * Add parameter --remove-page-labels to remove page labels from
+ output. In qpdf 8.3.0, the behavior changed so that page labels
+ were preserved when merging and splitting files. Some users were
+ relying on the fact that if you ran qpdf --empty --pages ... all
+ page labels were dropped. This option makes it possible to get
+ that behavior if it is explicitly desired. Fixes #317.
+
+ * Add parameter --keep-files-open-threshold to override the
+ maximum number of files that qpdf will allow to be kept open at
+ once. Fixes #288.
+
+ * Handle Unicode characters in filenames properly on Windows. The
+ changes to support Unicode on the CLI in Windows broke Unicode
+ filenames on that platform. Fixes #298.
+
+ * Slightly tighten logic that determines whether an object is a
+ page. The previous logic was sometimes failing to preserve
+ annotations because they were passing the overly loose test for
+ whether something was a page. This fix has a slight risk of
+ causing some extraneous objects to be copied during page splitting
+ and merging for erroneous PDF files whose page objects contain
+ invalid types or are missing the /Type key entirely, both of which
+ would be invalid according to the PDF specification.
+
+ * Revert change that included preservation of outlines (bookmarks)
+ in --split-pages. The way it was implemented caused a very
+ significant performance penalty when splitting pages with
+ outlines. We need a better solution that only copies the relevant
+ items, not the whole tree.
+
+2019-03-11 Jay Berkenbilt <ejb@ql.org>
+
+ * JSON serialization: add missing leading 0 to decimal values
+ between -1 and 1. Fixes #308.
+
2019-02-01 Jay Berkenbilt <ejb@ql.org>
* 8.4.0: release
diff -Nru qpdf-8.4.0/configure.ac qpdf-8.4.2/configure.ac
--- qpdf-8.4.0/configure.ac 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/configure.ac 2019-05-18 09:00:08.000000000 -0400
@@ -2,7 +2,7 @@
dnl This config.in requires autoconf 2.5 or greater.
AC_PREREQ([2.68])
-AC_INIT([qpdf],[8.4.0])
+AC_INIT([qpdf],[8.4.2])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_FILES([autoconf.mk])
@@ -53,7 +53,7 @@
# LT = libtool
LT_CURRENT=25
LT_AGE=4
-LT_REVISION=0
+LT_REVISION=2
AC_SUBST(LT_CURRENT)
AC_SUBST(LT_REVISION)
AC_SUBST(LT_AGE)
diff -Nru qpdf-8.4.0/debian/changelog qpdf-8.4.2/debian/changelog
--- qpdf-8.4.0/debian/changelog 2019-02-08 17:43:33.000000000 -0500
+++ qpdf-8.4.2/debian/changelog 2019-05-18 09:55:37.000000000 -0400
@@ -1,3 +1,16 @@
+qpdf (8.4.2-1) unstable; urgency=medium
+
+ * Update standards to 4.3.0. No changes required.
+ * New upstream release.
+
+ -- Jay Berkenbilt <qjb@debian.org> Sat, 18 May 2019 09:55:37 -0400
+
+qpdf (8.4.1-1) unstable; urgency=medium
+
+ * New upstream release.
+
+ -- Jay Berkenbilt <qjb@debian.org> Sat, 27 Apr 2019 22:13:00 -0400
+
qpdf (8.4.0-2) unstable; urgency=medium
* Stop having library packages recommend binary packages. I'm not sure
diff -Nru qpdf-8.4.0/debian/control qpdf-8.4.2/debian/control
--- qpdf-8.4.0/debian/control 2019-02-08 17:43:33.000000000 -0500
+++ qpdf-8.4.2/debian/control 2019-05-18 09:55:37.000000000 -0400
@@ -3,7 +3,7 @@
Priority: optional
Build-Depends: debhelper (>> 10.3~), libjpeg-dev, zlib1g-dev
Maintainer: Jay Berkenbilt <qjb@debian.org>
-Standards-Version: 4.2.0
+Standards-Version: 4.3.0
Homepage: http://qpdf.sourceforge.net
Package: libqpdf21
diff -Nru qpdf-8.4.0/examples/pdf-split-pages.cc qpdf-8.4.2/examples/pdf-split-pages.cc
--- qpdf-8.4.0/examples/pdf-split-pages.cc 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/examples/pdf-split-pages.cc 2019-05-18 09:00:08.000000000 -0400
@@ -8,9 +8,10 @@
#include <qpdf/QPDFPageDocumentHelper.hh>
#include <qpdf/QPDFWriter.hh>
#include <qpdf/QUtil.hh>
-#include <string>
+
#include <iostream>
-#include <cstdlib>
+#include <stdlib.h>
+#include <string>
static char const* whoami = 0;
static bool static_id = false;
diff -Nru qpdf-8.4.0/include/qpdf/DLL.h qpdf-8.4.2/include/qpdf/DLL.h
--- qpdf-8.4.0/include/qpdf/DLL.h 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/include/qpdf/DLL.h 2019-05-18 09:00:08.000000000 -0400
@@ -25,8 +25,13 @@
#if defined(_WIN32) && defined(DLL_EXPORT)
# define QPDF_DLL __declspec(dllexport)
+# define QPDF_DLL_EXCEPTION
+#elif __GNUC__ >= 4
+# define QPDF_DLL __attribute__ ((visibility ("default")))
+# define QPDF_DLL_EXCEPTION __attribute__ ((visibility ("default")))
#else
# define QPDF_DLL
+# define QPDF_DLL_EXCEPTION
#endif
#endif /* QPDF_DLL_HH */
diff -Nru qpdf-8.4.0/include/qpdf/QPDFExc.hh qpdf-8.4.2/include/qpdf/QPDFExc.hh
--- qpdf-8.4.0/include/qpdf/QPDFExc.hh 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/include/qpdf/QPDFExc.hh 2019-05-18 09:00:08.000000000 -0400
@@ -29,7 +29,7 @@
#include <string>
#include <stdexcept>
-class QPDFExc: public std::runtime_error
+class QPDF_DLL_EXCEPTION QPDFExc: public std::runtime_error
{
public:
QPDF_DLL
diff -Nru qpdf-8.4.0/include/qpdf/QPDF.hh qpdf-8.4.2/include/qpdf/QPDF.hh
--- qpdf-8.4.0/include/qpdf/QPDF.hh 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/include/qpdf/QPDF.hh 2019-05-18 09:00:08.000000000 -0400
@@ -30,8 +30,10 @@
#include <map>
#include <list>
#include <iostream>
+#include <vector>
#include <qpdf/QPDFExc.hh>
+#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/QPDFObjGen.hh>
#include <qpdf/QPDFXRefEntry.hh>
#include <qpdf/QPDFObjectHandle.hh>
@@ -1298,6 +1300,7 @@
class Members
{
friend class QPDF;
+ friend class ResolveRecorder;
public:
QPDF_DLL
diff -Nru qpdf-8.4.0/include/qpdf/QPDFObjectHandle.hh qpdf-8.4.2/include/qpdf/QPDFObjectHandle.hh
--- qpdf-8.4.0/include/qpdf/QPDFObjectHandle.hh 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/include/qpdf/QPDFObjectHandle.hh 2019-05-18 09:00:08.000000000 -0400
@@ -1028,6 +1028,7 @@
class Members
{
+ friend class ObjAccessor;
friend class QPDFObjectHandle;
public:
diff -Nru qpdf-8.4.0/include/qpdf/QPDFSystemError.hh qpdf-8.4.2/include/qpdf/QPDFSystemError.hh
--- qpdf-8.4.0/include/qpdf/QPDFSystemError.hh 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/include/qpdf/QPDFSystemError.hh 2019-05-18 09:00:08.000000000 -0400
@@ -29,7 +29,7 @@
#include <string>
#include <stdexcept>
-class QPDFSystemError: public std::runtime_error
+class QPDF_DLL_EXCEPTION QPDFSystemError: public std::runtime_error
{
public:
QPDF_DLL
diff -Nru qpdf-8.4.0/libqpdf/Pl_DCT.cc qpdf-8.4.2/libqpdf/Pl_DCT.cc
--- qpdf-8.4.0/libqpdf/Pl_DCT.cc 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/libqpdf/Pl_DCT.cc 2019-05-18 09:00:08.000000000 -0400
@@ -2,10 +2,11 @@
#include <qpdf/QUtil.hh>
#include <qpdf/QTC.hh>
+
#include <setjmp.h>
-#include <string>
#include <stdexcept>
-#include <cstdlib>
+#include <stdlib.h>
+#include <string>
#if BITS_IN_JSAMPLE != 8
# error "qpdf does not support libjpeg built with BITS_IN_JSAMPLE != 8"
diff -Nru qpdf-8.4.0/libqpdf/QPDF.cc qpdf-8.4.2/libqpdf/QPDF.cc
--- qpdf-8.4.0/libqpdf/QPDF.cc 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/libqpdf/QPDF.cc 2019-05-18 09:00:08.000000000 -0400
@@ -4,6 +4,7 @@
#include <vector>
#include <map>
#include <algorithm>
+#include <stdlib.h>
#include <string.h>
#include <memory.h>
@@ -20,7 +21,7 @@
#include <qpdf/QPDF_Dictionary.hh>
#include <qpdf/QPDF_Stream.hh>
-std::string QPDF::qpdf_version = "8.4.0";
+std::string QPDF::qpdf_version = "8.4.2";
static char const* EMPTY_PDF =
"%PDF-1.3\n"
diff -Nru qpdf-8.4.0/libqpdf/QPDFObjectHandle.cc qpdf-8.4.2/libqpdf/QPDFObjectHandle.cc
--- qpdf-8.4.0/libqpdf/QPDFObjectHandle.cc 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/libqpdf/QPDFObjectHandle.cc 2019-05-18 09:00:08.000000000 -0400
@@ -2524,14 +2524,14 @@
return true;
}
// Files have been seen in the wild that have /Type (Page)
- if (type.isString() && (type.getStringValue() == "Page"))
+ else if (type.isString() && (type.getStringValue() == "Page"))
{
return true;
}
- }
- if (this->hasKey("/Contents"))
- {
- return true;
+ else
+ {
+ return false;
+ }
}
return false;
}
diff -Nru qpdf-8.4.0/libqpdf/QPDF_Real.cc qpdf-8.4.2/libqpdf/QPDF_Real.cc
--- qpdf-8.4.0/libqpdf/QPDF_Real.cc 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/libqpdf/QPDF_Real.cc 2019-05-18 09:00:08.000000000 -0400
@@ -25,7 +25,30 @@
JSON
QPDF_Real::getJSON()
{
- return JSON::makeNumber(this->val);
+ // While PDF allows .x or -.x, JSON does not. Rather than
+ // converting from string to double and back, just handle this as a
+ // special case for JSON.
+ std::string result;
+ if (this->val.length() == 0)
+ {
+ // Can't really happen...
+ result = "0";
+ }
+ else if (this->val.at(0) == '.')
+ {
+ result = "0" + this->val;
+ }
+ else if ((this->val.length() >= 2) &&
+ (this->val.at(0) == '-') &&
+ (this->val.at(1) == '.'))
+ {
+ result = "-0." + this->val.substr(2);
+ }
+ else
+ {
+ result = this->val;
+ }
+ return JSON::makeNumber(result);
}
QPDFObject::object_type_e
diff -Nru qpdf-8.4.0/libqpdf/QPDFTokenizer.cc qpdf-8.4.2/libqpdf/QPDFTokenizer.cc
--- qpdf-8.4.0/libqpdf/QPDFTokenizer.cc 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/libqpdf/QPDFTokenizer.cc 2019-05-18 09:00:08.000000000 -0400
@@ -10,8 +10,8 @@
#include <qpdf/QPDFObjectHandle.hh>
#include <stdexcept>
+#include <stdlib.h>
#include <string.h>
-#include <cstdlib>
static bool is_delimiter(char ch)
{
diff -Nru qpdf-8.4.0/libqpdf/QUtil.cc qpdf-8.4.2/libqpdf/QUtil.cc
--- qpdf-8.4.0/libqpdf/QUtil.cc 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/libqpdf/QUtil.cc 2019-05-18 09:00:08.000000000 -0400
@@ -354,11 +354,42 @@
QUtil::safe_fopen(char const* filename, char const* mode)
{
FILE* f = 0;
+#ifdef _WIN32
+ // Convert the utf-8 encoded filename argument to wchar_t*. First,
+ // convert to utf16, then to wchar_t*. Note that u16 will start
+ // with the UTF16 marker, which we skip.
+ std::string u16 = utf8_to_utf16(filename);
+ size_t len = u16.length();
+ size_t wlen = (len / 2) - 1;
+ PointerHolder<wchar_t> wfilenamep(true, new wchar_t[wlen + 1]);
+ wchar_t* wfilename = wfilenamep.getPointer();
+ wfilename[wlen] = 0;
+ for (unsigned int i = 2; i < len; i += 2)
+ {
+ wfilename[(i/2) - 1] =
+ static_cast<wchar_t>(
+ (static_cast<unsigned char>(u16.at(i)) << 8) +
+ static_cast<unsigned char>(u16.at(i+1)));
+ }
+ PointerHolder<wchar_t> wmodep(true, new wchar_t[strlen(mode) + 1]);
+ wchar_t* wmode = wmodep.getPointer();
+ wmode[strlen(mode)] = 0;
+ for (size_t i = 0; i < strlen(mode); ++i)
+ {
+ wmode[i] = mode[i];
+ }
+
#ifdef _MSC_VER
- errno_t err = fopen_s(&f, filename, mode);
+ errno_t err = _wfopen_s(&f, wfilename, wmode);
if (err != 0)
{
errno = err;
+ }
+#else
+ f = _wfopen(wfilename, wmode);
+#endif
+ if (f == 0)
+ {
throw_system_error(std::string("open ") + filename);
}
#else
@@ -529,7 +560,9 @@
void
QUtil::binary_stdout()
{
-#ifdef _WIN32
+#if defined(_WIN32) && defined(__BORLANDC__)
+ setmode(_fileno(stdout), _O_BINARY);
+#elif defined(_WIN32)
_setmode(_fileno(stdout), _O_BINARY);
#endif
}
@@ -537,7 +570,9 @@
void
QUtil::binary_stdin()
{
-#ifdef _WIN32
+#if defined(_WIN32) && defined(__BORLANDC__)
+ setmode(_fileno(stdin), _O_BINARY);
+#elif defined(_WIN32)
_setmode(_fileno(stdin), _O_BINARY);
#endif
}
@@ -918,7 +953,9 @@
int
QUtil::strcasecmp(char const *s1, char const *s2)
{
-#ifdef _WIN32
+#if defined(_WIN32) && defined(__BORLANDC__)
+ return stricmp(s1, s2);
+#elif defined(_WIN32)
return _stricmp(s1, s2);
#else
return ::strcasecmp(s1, s2);
diff -Nru qpdf-8.4.0/qpdf/qpdf.cc qpdf-8.4.2/qpdf/qpdf.cc
--- qpdf-8.4.0/qpdf/qpdf.cc 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/qpdf/qpdf.cc 2019-05-18 09:00:08.000000000 -0400
@@ -30,6 +30,8 @@
static char const* whoami = 0;
+static std::string expected_version = "8.4.2";
+
struct PageSpec
{
PageSpec(std::string const& filename,
@@ -134,6 +136,7 @@
preserve_unreferenced_page_resources(false),
keep_files_open(true),
keep_files_open_set(false),
+ keep_files_open_threshold(200), // default known in help and docs
newline_before_endstream(false),
coalesce_contents(false),
flatten_annotations(false),
@@ -163,6 +166,7 @@
optimize_images(false),
externalize_inline_images(false),
keep_inline_images(false),
+ remove_page_labels(false),
oi_min_width(128), // Default values for these
oi_min_height(128), // oi flags are in --help
oi_min_area(16384), // and in the manual.
@@ -225,6 +229,7 @@
bool preserve_unreferenced_page_resources;
bool keep_files_open;
bool keep_files_open_set;
+ size_t keep_files_open_threshold;
bool newline_before_endstream;
std::string linearize_pass1;
bool coalesce_contents;
@@ -259,6 +264,7 @@
bool optimize_images;
bool externalize_inline_images;
bool keep_inline_images;
+ bool remove_page_labels;
size_t oi_min_width;
size_t oi_min_height;
size_t oi_min_area;
@@ -634,6 +640,7 @@
void argPreserveUnreferenced();
void argPreserveUnreferencedResources();
void argKeepFilesOpen(char* parameter);
+ void argKeepFilesOpenThreshold(char* parameter);
void argNewlineBeforeEndstream();
void argLinearizePass1(char* parameter);
void argCoalesceContents();
@@ -667,6 +674,7 @@
void argOptimizeImages();
void argExternalizeInlineImages();
void argKeepInlineImages();
+ void argRemovePageLabels();
void argOiMinWidth(char* parameter);
void argOiMinHeight(char* parameter);
void argOiMinArea(char* parameter);
@@ -857,6 +865,8 @@
&ArgParser::argPreserveUnreferencedResources);
(*t)["keep-files-open"] = oe_requiredChoices(
&ArgParser::argKeepFilesOpen, yn);
+ (*t)["keep-files-open-threshold"] = oe_requiredParameter(
+ &ArgParser::argKeepFilesOpenThreshold, "count");
(*t)["newline-before-endstream"] = oe_bare(
&ArgParser::argNewlineBeforeEndstream);
(*t)["linearize-pass1"] = oe_requiredParameter(
@@ -906,6 +916,7 @@
(*t)["externalize-inline-images"] =
oe_bare(&ArgParser::argExternalizeInlineImages);
(*t)["keep-inline-images"] = oe_bare(&ArgParser::argKeepInlineImages);
+ (*t)["remove-page-labels"] = oe_bare(&ArgParser::argRemovePageLabels);
(*t)["oi-min-width"] = oe_requiredParameter(
&ArgParser::argOiMinWidth, "minimum-width");
(*t)["oi-min-height"] = oe_requiredParameter(
@@ -984,6 +995,17 @@
void
ArgParser::argVersion()
{
+ if (expected_version != QPDF::QPDFVersion())
+ {
+ std::cerr << "***\n"
+ << "WARNING: qpdf CLI from version " << expected_version
+ << " is using library version " << QPDF::QPDFVersion()
+ << ".\n"
+ << "This probably means you have multiple versions of qpdf installed\n"
+ << "and don't have your library path configured correctly.\n"
+ << "***"
+ << std::endl;
+ }
std::cout
<< whoami << " version " << QPDF::QPDFVersion() << std::endl
<< "Run " << whoami << " --copyright to see copyright and license information."
@@ -1209,6 +1231,7 @@
<< "starting point, but its pages are replaced with pages as specified.\n"
<< "\n"
<< "--keep-files-open=[yn]\n"
+ << "--keep-files-open-threshold=count\n"
<< "--pages file [ --password=password ] [ page-range ] ... --\n"
<< "\n"
<< "For each file that pages should be taken from, specify the file, a\n"
@@ -1227,7 +1250,8 @@
<< "files will be kept open at the same time. This behavior can be overridden\n"
<< "by specifying --keep-files-open=[yn]. Closing and opening files can have\n"
<< "very high overhead on certain file systems, especially networked file\n"
- << "systems.\n"
+ << "systems. The threshold of 200 can be modified with\n"
+ << "--keep-files-open-threshold\n"
<< "\n"
<< "The page range is a set of numbers separated by commas, ranges of\n"
<< "numbers separated dashes, or combinations of those. The character\n"
@@ -1328,6 +1352,7 @@
<< "--ii-min-bytes=bytes specify minimum size of inline images to be\n"
<< " converted to regular images\n"
<< "--keep-inline-images exclude inline images from image optimization\n"
+ << "--remove-page-labels remove any page labels present in the output file\n"
<< "--qdf turns on \"QDF mode\" (below)\n"
<< "--linearize-pass1=file write intermediate pass of linearized file\n"
<< " for debugging\n"
@@ -1378,7 +1403,8 @@
<< " including DCT (JPEG)\n"
<< "\n"
<< "In qdf mode, by default, content normalization is turned on, and the\n"
- << "stream data mode is set to uncompress.\n"
+ << "stream data mode is set to uncompress. QDF mode does not support\n"
+ << "linearized files. The --linearize flag disables qdf mode.\n"
<< "\n"
<< "Setting the minimum PDF version of the output file may raise the version\n"
<< "but will never lower it. Forcing the PDF version of the output file may\n"
@@ -1781,6 +1807,13 @@
}
void
+ArgParser::argKeepFilesOpenThreshold(char* parameter)
+{
+ o.keep_files_open_threshold =
+ static_cast<size_t>(QUtil::string_to_int(parameter));
+}
+
+void
ArgParser::argNewlineBeforeEndstream()
{
o.newline_before_endstream = true;
@@ -1998,6 +2031,12 @@
}
void
+ArgParser::argRemovePageLabels()
+{
+ o.remove_page_labels = true;
+}
+
+void
ArgParser::argOiMinWidth(char* parameter)
{
o.oi_min_width = QUtil::string_to_int(parameter);
@@ -3836,7 +3875,7 @@
h_obj.isInteger() ? h_obj.getIntValue() : h_obj.getNumericValue());
std::string colorspace = (colorspace_obj.isName() ?
colorspace_obj.getName() :
- "");
+ std::string());
int components = 0;
J_COLOR_SPACE cs = JCS_UNKNOWN;
if (colorspace == "/DeviceRGB")
@@ -4320,6 +4359,10 @@
(*iter).coalesceContentStreams();
}
}
+ if (o.remove_page_labels)
+ {
+ pdf.getRoot().removeKey("/PageLabels");
+ }
}
static void handle_page_specs(QPDF& pdf, Options& o)
@@ -4351,9 +4394,7 @@
PageSpec& page_spec = *iter;
filenames.insert(page_spec.filename);
}
- // NOTE: The number 200 for this threshold is in the help
- // message and manual and is baked into the test suite.
- if (filenames.size() > 200)
+ if (filenames.size() > o.keep_files_open_threshold)
{
QTC::TC("qpdf", "qpdf disable keep files open");
if (o.verbose)
@@ -4966,30 +5007,6 @@
"/Nums", QPDFObjectHandle::newArray(labels));
outpdf.getRoot().replaceKey("/PageLabels", page_labels);
}
- // Copying the outlines tree, names table, and any
- // outdated Dests key from the original file will make
- // some things work in the split files. It is not a
- // complete solution, but at least outlines whose
- // destinations are on pages that have been preserved will
- // work normally. There are other top-level structures
- // that should be copied as well. This will be improved in
- // the future.
- std::list<std::string> to_copy;
- to_copy.push_back("/Names");
- to_copy.push_back("/Dests");
- to_copy.push_back("/Outlines");
- for (std::list<std::string>::iterator iter = to_copy.begin();
- iter != to_copy.end(); ++iter)
- {
- QPDFObjectHandle orig = pdf.getRoot().getKey(*iter);
- if (! orig.isIndirect())
- {
- orig = pdf.makeIndirectObject(orig);
- }
- outpdf.getRoot().replaceKey(
- *iter,
- outpdf.copyForeignObject(orig));
- }
std::string page_range = QUtil::int_to_string(first, pageno_len);
if (o.split_pages > 1)
{
----------------------------------------------------------------------
source debdiff, complete
diff -Nru qpdf-8.4.0/autofiles.sums qpdf-8.4.2/autofiles.sums
--- qpdf-8.4.0/autofiles.sums 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/autofiles.sums 2019-05-18 09:00:08.000000000 -0400
@@ -1,4 +1,4 @@
-f77e14ac842b239e57d5b49ced4260a69e93dcea01c002ff7606170ab1535ea8 configure.ac
+ba2adf968b787efe32cd4396a5cfeceeb52d2c48686bdc21a3b03edae169632c configure.ac
35bc5c645dc42d47f2daeea06f8f3e767c8a1aee6a35eb2b4854fd2ce66c3413 m4/ax_random_device.m4
37f8897d5f68d7d484e5457832a8f190ddb7507fa2a467cb7ee2be40a4364643 m4/libtool.m4
e77ebba8361b36f14b4d0927173a034b98c5d05049697a9ded84d85eb99a7990 m4/ltoptions.m4
diff -Nru qpdf-8.4.0/ChangeLog qpdf-8.4.2/ChangeLog
--- qpdf-8.4.0/ChangeLog 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/ChangeLog 2019-05-18 09:00:08.000000000 -0400
@@ -1,3 +1,59 @@
+2019-05-18 Jay Berkenbilt <ejb@ql.org>
+
+ * 8.4.2: release
+
+2019-05-16 Jay Berkenbilt <ejb@ql.org>
+
+ * Fix memory error in Windows-only code from typo. Fixes #330.
+
+2019-04-27 Jay Berkenbilt <ejb@ql.org>
+
+ * 8.4.1: release
+
+2019-04-20 Jay Berkenbilt <ejb@ql.org>
+
+ * When qpdf --version is run, it will detect if the qpdf CLI was
+ built with a different version of qpdf than the library. This
+ usually indicates that multiple versions of qpdf are installed and
+ that the library path is not set up properly. This situation
+ sometimes causes confusing behavior for users who are not actually
+ running the version of qpdf they think they are running.
+
+ * Add parameter --remove-page-labels to remove page labels from
+ output. In qpdf 8.3.0, the behavior changed so that page labels
+ were preserved when merging and splitting files. Some users were
+ relying on the fact that if you ran qpdf --empty --pages ... all
+ page labels were dropped. This option makes it possible to get
+ that behavior if it is explicitly desired. Fixes #317.
+
+ * Add parameter --keep-files-open-threshold to override the
+ maximum number of files that qpdf will allow to be kept open at
+ once. Fixes #288.
+
+ * Handle Unicode characters in filenames properly on Windows. The
+ changes to support Unicode on the CLI in Windows broke Unicode
+ filenames on that platform. Fixes #298.
+
+ * Slightly tighten logic that determines whether an object is a
+ page. The previous logic was sometimes failing to preserve
+ annotations because they were passing the overly loose test for
+ whether something was a page. This fix has a slight risk of
+ causing some extraneous objects to be copied during page splitting
+ and merging for erroneous PDF files whose page objects contain
+ invalid types or are missing the /Type key entirely, both of which
+ would be invalid according to the PDF specification.
+
+ * Revert change that included preservation of outlines (bookmarks)
+ in --split-pages. The way it was implemented caused a very
+ significant performance penalty when splitting pages with
+ outlines. We need a better solution that only copies the relevant
+ items, not the whole tree.
+
+2019-03-11 Jay Berkenbilt <ejb@ql.org>
+
+ * JSON serialization: add missing leading 0 to decimal values
+ between -1 and 1. Fixes #308.
+
2019-02-01 Jay Berkenbilt <ejb@ql.org>
* 8.4.0: release
diff -Nru qpdf-8.4.0/configure qpdf-8.4.2/configure
--- qpdf-8.4.0/configure 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/configure 2019-05-18 09:00:08.000000000 -0400
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for qpdf 8.4.0.
+# Generated by GNU Autoconf 2.69 for qpdf 8.4.2.
#
#
# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -587,8 +587,8 @@
# Identity of this package.
PACKAGE_NAME='qpdf'
PACKAGE_TARNAME='qpdf'
-PACKAGE_VERSION='8.4.0'
-PACKAGE_STRING='qpdf 8.4.0'
+PACKAGE_VERSION='8.4.2'
+PACKAGE_STRING='qpdf 8.4.2'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1339,7 +1339,7 @@
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures qpdf 8.4.0 to adapt to many kinds of systems.
+\`configure' configures qpdf 8.4.2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1405,7 +1405,7 @@
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of qpdf 8.4.0:";;
+ short | recursive ) echo "Configuration of qpdf 8.4.2:";;
esac
cat <<\_ACEOF
@@ -1558,7 +1558,7 @@
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-qpdf configure 8.4.0
+qpdf configure 8.4.2
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2098,7 +2098,7 @@
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by qpdf $as_me 8.4.0, which was
+It was created by qpdf $as_me 8.4.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -15647,7 +15647,7 @@
# LT = libtool
LT_CURRENT=25
LT_AGE=4
-LT_REVISION=0
+LT_REVISION=2
@@ -17539,7 +17539,7 @@
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by qpdf $as_me 8.4.0, which was
+This file was extended by qpdf $as_me 8.4.2, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -17605,7 +17605,7 @@
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-qpdf config.status 8.4.0
+qpdf config.status 8.4.2
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
diff -Nru qpdf-8.4.0/configure.ac qpdf-8.4.2/configure.ac
--- qpdf-8.4.0/configure.ac 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/configure.ac 2019-05-18 09:00:08.000000000 -0400
@@ -2,7 +2,7 @@
dnl This config.in requires autoconf 2.5 or greater.
AC_PREREQ([2.68])
-AC_INIT([qpdf],[8.4.0])
+AC_INIT([qpdf],[8.4.2])
AC_CONFIG_MACRO_DIR([m4])
AC_CONFIG_FILES([autoconf.mk])
@@ -53,7 +53,7 @@
# LT = libtool
LT_CURRENT=25
LT_AGE=4
-LT_REVISION=0
+LT_REVISION=2
AC_SUBST(LT_CURRENT)
AC_SUBST(LT_REVISION)
AC_SUBST(LT_AGE)
diff -Nru qpdf-8.4.0/debian/changelog qpdf-8.4.2/debian/changelog
--- qpdf-8.4.0/debian/changelog 2019-02-08 17:43:33.000000000 -0500
+++ qpdf-8.4.2/debian/changelog 2019-05-18 09:55:37.000000000 -0400
@@ -1,3 +1,16 @@
+qpdf (8.4.2-1) unstable; urgency=medium
+
+ * Update standards to 4.3.0. No changes required.
+ * New upstream release.
+
+ -- Jay Berkenbilt <qjb@debian.org> Sat, 18 May 2019 09:55:37 -0400
+
+qpdf (8.4.1-1) unstable; urgency=medium
+
+ * New upstream release.
+
+ -- Jay Berkenbilt <qjb@debian.org> Sat, 27 Apr 2019 22:13:00 -0400
+
qpdf (8.4.0-2) unstable; urgency=medium
* Stop having library packages recommend binary packages. I'm not sure
diff -Nru qpdf-8.4.0/debian/control qpdf-8.4.2/debian/control
--- qpdf-8.4.0/debian/control 2019-02-08 17:43:33.000000000 -0500
+++ qpdf-8.4.2/debian/control 2019-05-18 09:55:37.000000000 -0400
@@ -3,7 +3,7 @@
Priority: optional
Build-Depends: debhelper (>> 10.3~), libjpeg-dev, zlib1g-dev
Maintainer: Jay Berkenbilt <qjb@debian.org>
-Standards-Version: 4.2.0
+Standards-Version: 4.3.0
Homepage: http://qpdf.sourceforge.net
Package: libqpdf21
diff -Nru qpdf-8.4.0/doc/qpdf-manual.html qpdf-8.4.2/doc/qpdf-manual.html
--- qpdf-8.4.0/doc/qpdf-manual.html 2019-02-02 09:08:08.000000000 -0500
+++ qpdf-8.4.2/doc/qpdf-manual.html 2019-05-18 09:06:12.000000000 -0400
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>QPDF Manual</title><link rel="stylesheet" type="text/css" href="stylesheet.css" /><meta name="generator" content="DocBook XSL Stylesheets V1.79.1" /></head><body><div class="book"><div class="titlepage"><div><div><h1 class="title"><a id="idm46094354123872"></a>QPDF Manual</h1></div><div><h2 class="subtitle">For QPDF Version 8.4.0, February 1, 2019</h2></div><div><div class="author"><h3 class="author"><span class="firstname">Jay</span> <span class="surname">Berkenbilt</span></h3></div></div><div><p class="copyright">Copyright © 2005–2019 Jay Berkenbilt</p></div></div><hr /></div><div class="toc"><p><strong>Table of Contents</strong></p><dl class="toc"><dt><span class="preface"><a href="#acknowledgments">General Information</a></span></dt><dt><span class="chapter"><a href="#ref.overview">1. What is QPDF?</a></span></dt><dt><span class="chapter"><a href="#ref.installing">2. Building and Installing QPDF</a></span></dt><dd><dl><dt><span class="sect1"><a href="#ref.prerequisites">2.1. System Requirements</a></span></dt><dt><span class="sect1"><a href="#ref.building">2.2. Build Instructions</a></span></dt><dt><span class="sect1"><a href="#ref.packaging">2.3. Notes for Packagers</a></span></dt></dl></dd><dt><span class="chapter"><a href="#ref.using">3. Running QPDF</a></span></dt><dd><dl><dt><span class="sect1"><a href="#ref.invocation">3.1. Basic Invocation</a></span></dt><dt><span class="sect1"><a href="#ref.shell-completion">3.2. Shell Completion</a></span></dt><dt><span class="sect1"><a href="#ref.basic-options">3.3. Basic Options</a></span></dt><dt><span class="sect1"><a href="#ref.encryption-options">3.4. Encryption Options</a></span></dt><dt><span class="sect1"><a href="#ref.page-selection">3.5. Page Selection Options</a></span></dt><dt><span class="sect1"><a href="#ref.overlay-underlay">3.6. Overlay and Underlay Options</a></span></dt><dt><span class="sect1"><a href="#ref.advanced-parsing">3.7. Advanced Parsing Options</a></span></dt><dt><span class="sect1"><a href="#ref.advanced-transformation">3.8. Advanced Transformation Options</a></span></dt><dt><span class="sect1"><a href="#ref.testing-options">3.9. Testing, Inspection, and Debugging Options</a></span></dt><dt><span class="sect1"><a href="#ref.unicode-passwords">3.10. Unicode Passwords</a></span></dt></dl></dd><dt><span class="chapter"><a href="#ref.qdf">4. QDF Mode</a></span></dt><dt><span class="chapter"><a href="#ref.using-library">5. Using the QPDF Library</a></span></dt><dd><dl><dt><span class="sect1"><a href="#ref.using.from-cxx">5.1. Using QPDF from C++</a></span></dt><dt><span class="sect1"><a href="#ref.using.other-languages">5.2. Using QPDF from other languages</a></span></dt></dl></dd><dt><span class="chapter"><a href="#ref.json">6. QPDF JSON</a></span></dt><dd><dl><dt><span class="sect1"><a href="#ref.json-overview">6.1. Overview</a></span></dt><dt><span class="sect1"><a href="#ref.json-guarantees">6.2. JSON Guarantees</a></span></dt><dt><span class="sect1"><a href="#json.limitations">6.3. Limitations of JSON Representation</a></span></dt><dt><span class="sect1"><a href="#json.considerations">6.4. JSON: Special Considerations</a></span></dt></dl></dd><dt><span class="chapter"><a href="#ref.design">7. Design and Library Notes</a></span></dt><dd><dl><dt><span class="sect1"><a href="#ref.design.intro">7.1. Introduction</a></span></dt><dt><span class="sect1"><a href="#ref.design-goals">7.2. Design Goals</a></span></dt><dt><span class="sect1"><a href="#ref.helper-classes">7.3. Helper Classes</a></span></dt><dt><span class="sect1"><a href="#ref.implementation-notes">7.4. Implementation Notes</a></span></dt><dt><span class="sect1"><a href="#ref.casting">7.5. Casting Policy</a></span></dt><dt><span class="sect1"><a href="#ref.encryption">7.6. Encryption</a></span></dt><dt><span class="sect1"><a href="#ref.random-numbers">7.7. Random Number Generation</a></span></dt><dt><span class="sect1"><a href="#ref.adding-and-remove-pages">7.8. Adding and Removing Pages</a></span></dt><dt><span class="sect1"><a href="#ref.reserved-objects">7.9. Reserving Object Numbers</a></span></dt><dt><span class="sect1"><a href="#ref.foreign-objects">7.10. Copying Objects From Other PDF Files</a></span></dt><dt><span class="sect1"><a href="#ref.rewriting">7.11. Writing PDF Files</a></span></dt><dt><span class="sect1"><a href="#ref.filtered-streams">7.12. Filtered Streams</a></span></dt></dl></dd><dt><span class="chapter"><a href="#ref.linearization">8. Linearization</a></span></dt><dd><dl><dt><span class="sect1"><a href="#ref.linearization-strategy">8.1. Basic Strategy for Linearization</a></span></dt><dt><span class="sect1"><a href="#ref.linearized.preparation">8.2. Preparing For Linearization</a></span></dt><dt><span class="sect1"><a href="#ref.optimization">8.3. Optimization</a></span></dt><dt><span class="sect1"><a href="#ref.linearization.writing">8.4. Writing Linearized Files</a></span></dt><dt><span class="sect1"><a href="#ref.linearization-data">8.5. Calculating Linearization Data</a></span></dt><dt><span class="sect1"><a href="#ref.linearization-issues">8.6. Known Issues with Linearization</a></span></dt><dt><span class="sect1"><a href="#ref.linearization-debugging">8.7. Debugging Note</a></span></dt></dl></dd><dt><span class="chapter"><a href="#ref.object-and-xref-streams">9. Object and Cross-Reference Streams</a></span></dt><dd><dl><dt><span class="sect1"><a href="#ref.object-streams">9.1. Object Streams</a></span></dt><dt><span class="sect1"><a href="#ref.xref-streams">9.2. Cross-Reference Streams</a></span></dt><dd><dl><dt><span class="sect2"><a href="#ref.xref-stream-data">9.2.1. Cross-Reference Stream Data</a></span></dt></dl></dd><dt><span class="sect1"><a href="#ref.object-streams-linearization">9.3. Implications for Linearized Files</a></span></dt><dt><span class="sect1"><a href="#ref.object-stream-implementation">9.4. Implementation Notes</a></span></dt></dl></dd><dt><span class="appendix"><a href="#ref.release-notes">A. Release Notes</a></span></dt><dt><span class="appendix"><a href="#ref.upgrading-to-2.1">B. Upgrading from 2.0 to 2.1</a></span></dt><dt><span class="appendix"><a href="#ref.upgrading-to-3.0">C. Upgrading to 3.0</a></span></dt><dt><span class="appendix"><a href="#ref.upgrading-to-4.0">D. Upgrading to 4.0</a></span></dt></dl></div><div class="preface"><div class="titlepage"><div><div><h1 class="title"><a id="acknowledgments"></a>General Information</h1></div></div></div><p>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>QPDF Manual</title><link rel="stylesheet" type="text/css" href="stylesheet.css" /><meta name="generator" content="DocBook XSL Stylesheets V1.79.1" /></head><body><div class="book"><div class="titlepage"><div><div><h1 class="title"><a id="idm45124393972512"></a>QPDF Manual</h1></div><div><h2 class="subtitle">For QPDF Version 8.4.2, May 18, 2019</h2></div><div><div class="author"><h3 class="author"><span class="firstname">Jay</span> <span class="surname">Berkenbilt</span></h3></div></div><div><p class="copyright">Copyright © 2005–2019 Jay Berkenbilt</p></div></div><hr /></div><div class="toc"><p><strong>Table of Contents</strong></p><dl class="toc"><dt><span class="preface"><a href="#acknowledgments">General Information</a></span></dt><dt><span class="chapter"><a href="#ref.overview">1. What is QPDF?</a></span></dt><dt><span class="chapter"><a href="#ref.installing">2. Building and Installing QPDF</a></span></dt><dd><dl><dt><span class="sect1"><a href="#ref.prerequisites">2.1. System Requirements</a></span></dt><dt><span class="sect1"><a href="#ref.building">2.2. Build Instructions</a></span></dt><dt><span class="sect1"><a href="#ref.packaging">2.3. Notes for Packagers</a></span></dt></dl></dd><dt><span class="chapter"><a href="#ref.using">3. Running QPDF</a></span></dt><dd><dl><dt><span class="sect1"><a href="#ref.invocation">3.1. Basic Invocation</a></span></dt><dt><span class="sect1"><a href="#ref.shell-completion">3.2. Shell Completion</a></span></dt><dt><span class="sect1"><a href="#ref.basic-options">3.3. Basic Options</a></span></dt><dt><span class="sect1"><a href="#ref.encryption-options">3.4. Encryption Options</a></span></dt><dt><span class="sect1"><a href="#ref.page-selection">3.5. Page Selection Options</a></span></dt><dt><span class="sect1"><a href="#ref.overlay-underlay">3.6. Overlay and Underlay Options</a></span></dt><dt><span class="sect1"><a href="#ref.advanced-parsing">3.7. Advanced Parsing Options</a></span></dt><dt><span class="sect1"><a href="#ref.advanced-transformation">3.8. Advanced Transformation Options</a></span></dt><dt><span class="sect1"><a href="#ref.testing-options">3.9. Testing, Inspection, and Debugging Options</a></span></dt><dt><span class="sect1"><a href="#ref.unicode-passwords">3.10. Unicode Passwords</a></span></dt></dl></dd><dt><span class="chapter"><a href="#ref.qdf">4. QDF Mode</a></span></dt><dt><span class="chapter"><a href="#ref.using-library">5. Using the QPDF Library</a></span></dt><dd><dl><dt><span class="sect1"><a href="#ref.using.from-cxx">5.1. Using QPDF from C++</a></span></dt><dt><span class="sect1"><a href="#ref.using.other-languages">5.2. Using QPDF from other languages</a></span></dt><dt><span class="sect1"><a href="#ref.unicode-files">5.3. A Note About Unicode File Names</a></span></dt></dl></dd><dt><span class="chapter"><a href="#ref.json">6. QPDF JSON</a></span></dt><dd><dl><dt><span class="sect1"><a href="#ref.json-overview">6.1. Overview</a></span></dt><dt><span class="sect1"><a href="#ref.json-guarantees">6.2. JSON Guarantees</a></span></dt><dt><span class="sect1"><a href="#json.limitations">6.3. Limitations of JSON Representation</a></span></dt><dt><span class="sect1"><a href="#json.considerations">6.4. JSON: Special Considerations</a></span></dt></dl></dd><dt><span class="chapter"><a href="#ref.design">7. Design and Library Notes</a></span></dt><dd><dl><dt><span class="sect1"><a href="#ref.design.intro">7.1. Introduction</a></span></dt><dt><span class="sect1"><a href="#ref.design-goals">7.2. Design Goals</a></span></dt><dt><span class="sect1"><a href="#ref.helper-classes">7.3. Helper Classes</a></span></dt><dt><span class="sect1"><a href="#ref.implementation-notes">7.4. Implementation Notes</a></span></dt><dt><span class="sect1"><a href="#ref.casting">7.5. Casting Policy</a></span></dt><dt><span class="sect1"><a href="#ref.encryption">7.6. Encryption</a></span></dt><dt><span class="sect1"><a href="#ref.random-numbers">7.7. Random Number Generation</a></span></dt><dt><span class="sect1"><a href="#ref.adding-and-remove-pages">7.8. Adding and Removing Pages</a></span></dt><dt><span class="sect1"><a href="#ref.reserved-objects">7.9. Reserving Object Numbers</a></span></dt><dt><span class="sect1"><a href="#ref.foreign-objects">7.10. Copying Objects From Other PDF Files</a></span></dt><dt><span class="sect1"><a href="#ref.rewriting">7.11. Writing PDF Files</a></span></dt><dt><span class="sect1"><a href="#ref.filtered-streams">7.12. Filtered Streams</a></span></dt></dl></dd><dt><span class="chapter"><a href="#ref.linearization">8. Linearization</a></span></dt><dd><dl><dt><span class="sect1"><a href="#ref.linearization-strategy">8.1. Basic Strategy for Linearization</a></span></dt><dt><span class="sect1"><a href="#ref.linearized.preparation">8.2. Preparing For Linearization</a></span></dt><dt><span class="sect1"><a href="#ref.optimization">8.3. Optimization</a></span></dt><dt><span class="sect1"><a href="#ref.linearization.writing">8.4. Writing Linearized Files</a></span></dt><dt><span class="sect1"><a href="#ref.linearization-data">8.5. Calculating Linearization Data</a></span></dt><dt><span class="sect1"><a href="#ref.linearization-issues">8.6. Known Issues with Linearization</a></span></dt><dt><span class="sect1"><a href="#ref.linearization-debugging">8.7. Debugging Note</a></span></dt></dl></dd><dt><span class="chapter"><a href="#ref.object-and-xref-streams">9. Object and Cross-Reference Streams</a></span></dt><dd><dl><dt><span class="sect1"><a href="#ref.object-streams">9.1. Object Streams</a></span></dt><dt><span class="sect1"><a href="#ref.xref-streams">9.2. Cross-Reference Streams</a></span></dt><dd><dl><dt><span class="sect2"><a href="#ref.xref-stream-data">9.2.1. Cross-Reference Stream Data</a></span></dt></dl></dd><dt><span class="sect1"><a href="#ref.object-streams-linearization">9.3. Implications for Linearized Files</a></span></dt><dt><span class="sect1"><a href="#ref.object-stream-implementation">9.4. Implementation Notes</a></span></dt></dl></dd><dt><span class="appendix"><a href="#ref.release-notes">A. Release Notes</a></span></dt><dt><span class="appendix"><a href="#ref.upgrading-to-2.1">B. Upgrading from 2.0 to 2.1</a></span></dt><dt><span class="appendix"><a href="#ref.upgrading-to-3.0">C. Upgrading to 3.0</a></span></dt><dt><span class="appendix"><a href="#ref.upgrading-to-4.0">D. Upgrading to 4.0</a></span></dt></dl></div><div class="preface"><div class="titlepage"><div><div><h1 class="title"><a id="acknowledgments"></a>General Information</h1></div></div></div><p>
QPDF is a program that does structural, content-preserving
transformations on PDF files. QPDF's website is located at <a class="ulink" href="http://qpdf.sourceforge.net/" target="_top">http://qpdf.sourceforge.net/</a>.
QPDF's source code is hosted on github at <a class="ulink" href="https://github.com/qpdf/qpdf" target="_top">https://github.com/qpdf/qpdf</a>.
@@ -402,6 +402,13 @@
more than the OS limit's number of files from a script and are
not worried about a few seconds additional processing time,
you may want to specify <code class="option">--keep-files-open=n</code>.
+ The threshold for switching may be changed from the default
+ 200 with the <code class="option">--keep-files-open-threshold</code>
+ option.
+ </p></dd><dt><span class="term"><code class="option">--keep-files-open-threshold=<em class="replaceable"><code>count</code></em></code></span></dt><dd><p>
+ If specified, overrides the default value of 200 used as the
+ threshold for qpdf deciding whether or not to keep files open.
+ See <code class="option">--keep-files-open</code> for details.
</p></dd><dt><span class="term"><code class="option">--pages options --</code></span></dt><dd><p>
Select specific pages from one or more input files. See <a class="xref" href="#ref.page-selection" title="3.5. Page Selection Options">Section 3.5, “Page Selection Options”</a> for details on how to do page
selection (splitting and merging).
@@ -1097,9 +1104,12 @@
Prevent inline images from being included in image
optimization. This option has no affect when
<code class="option">--optimize-images</code> is not specified.
+ </p></dd><dt><span class="term"><code class="option">--remove-page-labels</code></span></dt><dd><p>
+ Remove page labels from the output file.
</p></dd><dt><span class="term"><code class="option">--qdf</code></span></dt><dd><p>
Turns on QDF mode. For additional information on QDF, please
- see <a class="xref" href="#ref.qdf" title="Chapter 4. QDF Mode">Chapter 4, <em>QDF Mode</em></a>.
+ see <a class="xref" href="#ref.qdf" title="Chapter 4. QDF Mode">Chapter 4, <em>QDF Mode</em></a>. Note that
+ <code class="option">--linearize</code> disables QDF mode.
</p></dd><dt><span class="term"><code class="option">--min-version=<em class="replaceable"><code>version</code></em></code></span></dt><dd><p>
Forces the PDF version of the output file to be at least
<em class="replaceable"><code>version</code></em>. In other words, if the
@@ -1472,7 +1482,9 @@
some restrictions, in an ordinary text editor. This can be very
useful for experimenting with different PDF constructs or for
making one-off edits to PDF files (though there are other reasons
- why this may not always work).
+ why this may not always work). Note that QDF mode does not support
+ linearized files. If you enable linearization, QDF mode is
+ automatically disabled.
</p><p>
It is ordinarily very difficult to edit PDF files in a text editor
for two reasons: most meaningful data in PDF files is compressed,
@@ -1560,7 +1572,7 @@
the offset to the cross-reference table or cross-reference
stream following the <code class="literal">startxref</code> token
</p></li></ul></div><p>
- </p></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a id="ref.using-library"></a>Chapter 5. Using the QPDF Library</h1></div></div></div><div class="toc"><p><strong>Table of Contents</strong></p><dl class="toc"><dt><span class="sect1"><a href="#ref.using.from-cxx">5.1. Using QPDF from C++</a></span></dt><dt><span class="sect1"><a href="#ref.using.other-languages">5.2. Using QPDF from other languages</a></span></dt></dl></div><div class="sect1"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="ref.using.from-cxx"></a>5.1. Using QPDF from C++</h2></div></div></div><p>
+ </p></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a id="ref.using-library"></a>Chapter 5. Using the QPDF Library</h1></div></div></div><div class="toc"><p><strong>Table of Contents</strong></p><dl class="toc"><dt><span class="sect1"><a href="#ref.using.from-cxx">5.1. Using QPDF from C++</a></span></dt><dt><span class="sect1"><a href="#ref.using.other-languages">5.2. Using QPDF from other languages</a></span></dt><dt><span class="sect1"><a href="#ref.unicode-files">5.3. A Note About Unicode File Names</a></span></dt></dl></div><div class="sect1"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="ref.using.from-cxx"></a>5.1. Using QPDF from C++</h2></div></div></div><p>
The source tree for the qpdf package has an
<code class="filename">examples</code> directory that contains a few
example programs. The <code class="filename">qpdf/qpdf.cc</code> source
@@ -1613,7 +1625,28 @@
file's non-content data. This can facilitate interacting
programmatically with PDF files through qpdf's command line
interface. For more information, please see <a class="xref" href="#ref.json" title="Chapter 6. QPDF JSON">Chapter 6, <em>QPDF JSON</em></a>.
- </p></dd></dl></div></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a id="ref.json"></a>Chapter 6. QPDF JSON</h1></div></div></div><div class="toc"><p><strong>Table of Contents</strong></p><dl class="toc"><dt><span class="sect1"><a href="#ref.json-overview">6.1. Overview</a></span></dt><dt><span class="sect1"><a href="#ref.json-guarantees">6.2. JSON Guarantees</a></span></dt><dt><span class="sect1"><a href="#json.limitations">6.3. Limitations of JSON Representation</a></span></dt><dt><span class="sect1"><a href="#json.considerations">6.4. JSON: Special Considerations</a></span></dt></dl></div><div class="sect1"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="ref.json-overview"></a>6.1. Overview</h2></div></div></div><p>
+ </p></dd></dl></div></div><div class="sect1"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="ref.unicode-files"></a>5.3. A Note About Unicode File Names</h2></div></div></div><p>
+ When strings are passed to qpdf library routines either as
+ <code class="literal">char*</code> or as <code class="literal">std::string</code>,
+ they are treated as byte arrays except where otherwise noted. When
+ Unicode is desired, qpdf wants UTF-8 unless otherwise noted in
+ comments in header files. In modern UNIX/Linux environments, this
+ generally does the right thing. In Windows, it's a bit more
+ complicated. Starting in qpdf 8.4.0, passwords that contain
+ Unicode characters are handled much better, and starting in qpdf
+ 8.4.1, the library attempts to properly handle Unicode characters
+ in filenames. In particular, in Windows, if a UTF-8 encoded string
+ is used as a filename in either <code class="classname">QPDF</code> or
+ <code class="classname">QPDFWriter</code>, it is internally converted to
+ <code class="literal">wchar_t*</code>, and Unicode-aware Windows APIs are
+ used. As such, qpdf will generally operate properly on files with
+ non-ASCII characters in their names as long as the filenames are
+ UTF-8 encoded for passing into the qpdf library API, but there are
+ still some rough edges, such as the encoding of the filenames in
+ error messages our CLI output messages. Patches or bug reports are
+ welcome for any continuing issues with Unicode file names in
+ Windows.
+ </p></div></div><div class="chapter"><div class="titlepage"><div><div><h1 class="title"><a id="ref.json"></a>Chapter 6. QPDF JSON</h1></div></div></div><div class="toc"><p><strong>Table of Contents</strong></p><dl class="toc"><dt><span class="sect1"><a href="#ref.json-overview">6.1. Overview</a></span></dt><dt><span class="sect1"><a href="#ref.json-guarantees">6.2. JSON Guarantees</a></span></dt><dt><span class="sect1"><a href="#json.limitations">6.3. Limitations of JSON Representation</a></span></dt><dt><span class="sect1"><a href="#json.considerations">6.4. JSON: Special Considerations</a></span></dt></dl></div><div class="sect1"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a id="ref.json-overview"></a>6.1. Overview</h2></div></div></div><p>
Beginning with qpdf version 8.3.0, the <span class="command"><strong>qpdf</strong></span>
command-line program can produce a JSON representation of the
non-content data in a PDF file. It includes a dump in JSON format
@@ -1879,7 +1912,7 @@
password-protected files. QPDF does not enforce encryption
parameters and will treat user and owner passwords equivalently.
Either password may be used to access an encrypted file.
- <a href="#ftn.idm46094347359200" class="footnote" id="idm46094347359200"><sup class="footnote">[1]</sup></a>
+ <a href="#ftn.idm45124387202432" class="footnote" id="idm45124387202432"><sup class="footnote">[1]</sup></a>
<code class="classname">QPDF</code> will allow recovery of a user password
given an owner password. The input PDF file must be seekable.
(Output files written by <code class="classname">QPDFWriter</code> need
@@ -2530,7 +2563,7 @@
filter should write to whatever type of output is required. The
<code class="classname">QPDF</code> class has an interface to write raw or
filtered stream contents to a given pipeline.
- </p></div><div class="footnotes"><br /><hr style="width:100; text-align:left;margin-left: 0" /><div id="ftn.idm46094347359200" class="footnote"><p><a href="#idm46094347359200" class="para"><sup class="para">[1] </sup></a>
+ </p></div><div class="footnotes"><br /><hr style="width:100; text-align:left;margin-left: 0" /><div id="ftn.idm45124387202432" class="footnote"><p><a href="#idm45124387202432" class="para"><sup class="para">[1] </sup></a>
As pointed out earlier, the intention is not for qpdf to be used
to bypass security on files. but as any open source PDF consumer
may be easily modified to bypass basic PDF document security,
@@ -2893,7 +2926,57 @@
</p></div></div><div class="appendix"><div class="titlepage"><div><div><h1 class="title"><a id="ref.release-notes"></a>Appendix A. Release Notes</h1></div></div></div><p>
For a detailed list of changes, please see the file
<code class="filename">ChangeLog</code> in the source distribution.
- </p><div class="variablelist"><dl class="variablelist"><dt><span class="term">8.4.0: February 1, 2019</span></dt><dd><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>
+ </p><div class="variablelist"><dl class="variablelist"><dt><span class="term">8.4.2: May 18, 2019</span></dt><dd><p>
+ This release has just one change: correction of a buffer overrun
+ in the Windows code used to open files. Windows users should
+ take this update. There are no code changes that affect
+ non-Windows releases.
+ </p></dd><dt><span class="term">8.4.1: April 27, 2019</span></dt><dd><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>
+ Enhancements
+ </p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem"><p>
+ When <span class="command"><strong>qpdf --version</strong></span> is run, it will
+ detect if the qpdf CLI was built with a different version of
+ qpdf than the library, which may indicate a problem with the
+ installation.
+ </p></li><li class="listitem"><p>
+ New option <code class="option">--remove-page-labels</code> will remove page
+ labels before generating output. This used to happen if you
+ ran <span class="command"><strong>qpdf --empty --pages .. --</strong></span>, but the
+ behavior changed in qpdf 8.3.0. This option enables people
+ who were relying on the old behavior to get it again.
+ </p></li><li class="listitem"><p>
+ New option
+ <code class="option">--keep-files-open-threshold=<em class="replaceable"><code>count</code></em></code>
+ can be used to override number of files that qpdf will use
+ to trigger the behavior of not keeping all files open when
+ merging files. This may be necessary if your system allows
+ fewer than the default value of 200 files to be open at the
+ same time.
+ </p></li></ul></div></li><li class="listitem"><p>
+ Bug Fixes
+ </p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem"><p>
+ Handle Unicode characters in filenames on Windows. The
+ changes to support Unicode on the CLI in Windows broke
+ Unicode filenames for Windows.
+ </p></li><li class="listitem"><p>
+ Slightly tighten logic that determines whether an object is
+ a page. This should resolve problems in some rare files
+ where some non-page objects were passing qpdf's test for
+ whether something was a page, thus causing them to be
+ erroneously lost during page splitting operations.
+ </p></li><li class="listitem"><p>
+ Revert change that included preservation of outlines
+ (bookmarks) in <code class="option">--split-pages</code>. The way it
+ was implemented in 8.3.0 and 8.4.0 caused a very significant
+ degradation of performance for splitting certain files. A
+ future release of qpdf may re-introduce the behavior in a
+ more performant and also more correct fashion.
+ </p></li><li class="listitem"><p>
+ In JSON mode, add missing leading 0 to decimal values
+ between -1 and 1 even if not present in the input. The JSON
+ specification requires the leading 0. The PDF specification
+ does not.
+ </p></li></ul></div></li></ul></div></dd><dt><span class="term">8.4.0: February 1, 2019</span></dt><dd><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>
Command-line Enhancements
</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: circle; "><li class="listitem"><p>
<span class="emphasis"><em>Non-compatible CLI change:</em></span> The qpdf
Binary files /tmp/_vHMae8e6Y/qpdf-8.4.0/doc/qpdf-manual.pdf and /tmp/83GJmS7ZTn/qpdf-8.4.2/doc/qpdf-manual.pdf differ
diff -Nru qpdf-8.4.0/examples/pdf-split-pages.cc qpdf-8.4.2/examples/pdf-split-pages.cc
--- qpdf-8.4.0/examples/pdf-split-pages.cc 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/examples/pdf-split-pages.cc 2019-05-18 09:00:08.000000000 -0400
@@ -8,9 +8,10 @@
#include <qpdf/QPDFPageDocumentHelper.hh>
#include <qpdf/QPDFWriter.hh>
#include <qpdf/QUtil.hh>
-#include <string>
+
#include <iostream>
-#include <cstdlib>
+#include <stdlib.h>
+#include <string>
static char const* whoami = 0;
static bool static_id = false;
diff -Nru qpdf-8.4.0/include/qpdf/DLL.h qpdf-8.4.2/include/qpdf/DLL.h
--- qpdf-8.4.0/include/qpdf/DLL.h 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/include/qpdf/DLL.h 2019-05-18 09:00:08.000000000 -0400
@@ -25,8 +25,13 @@
#if defined(_WIN32) && defined(DLL_EXPORT)
# define QPDF_DLL __declspec(dllexport)
+# define QPDF_DLL_EXCEPTION
+#elif __GNUC__ >= 4
+# define QPDF_DLL __attribute__ ((visibility ("default")))
+# define QPDF_DLL_EXCEPTION __attribute__ ((visibility ("default")))
#else
# define QPDF_DLL
+# define QPDF_DLL_EXCEPTION
#endif
#endif /* QPDF_DLL_HH */
diff -Nru qpdf-8.4.0/include/qpdf/QPDFExc.hh qpdf-8.4.2/include/qpdf/QPDFExc.hh
--- qpdf-8.4.0/include/qpdf/QPDFExc.hh 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/include/qpdf/QPDFExc.hh 2019-05-18 09:00:08.000000000 -0400
@@ -29,7 +29,7 @@
#include <string>
#include <stdexcept>
-class QPDFExc: public std::runtime_error
+class QPDF_DLL_EXCEPTION QPDFExc: public std::runtime_error
{
public:
QPDF_DLL
diff -Nru qpdf-8.4.0/include/qpdf/QPDF.hh qpdf-8.4.2/include/qpdf/QPDF.hh
--- qpdf-8.4.0/include/qpdf/QPDF.hh 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/include/qpdf/QPDF.hh 2019-05-18 09:00:08.000000000 -0400
@@ -30,8 +30,10 @@
#include <map>
#include <list>
#include <iostream>
+#include <vector>
#include <qpdf/QPDFExc.hh>
+#include <qpdf/QPDFObjectHandle.hh>
#include <qpdf/QPDFObjGen.hh>
#include <qpdf/QPDFXRefEntry.hh>
#include <qpdf/QPDFObjectHandle.hh>
@@ -1298,6 +1300,7 @@
class Members
{
friend class QPDF;
+ friend class ResolveRecorder;
public:
QPDF_DLL
diff -Nru qpdf-8.4.0/include/qpdf/QPDFObjectHandle.hh qpdf-8.4.2/include/qpdf/QPDFObjectHandle.hh
--- qpdf-8.4.0/include/qpdf/QPDFObjectHandle.hh 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/include/qpdf/QPDFObjectHandle.hh 2019-05-18 09:00:08.000000000 -0400
@@ -1028,6 +1028,7 @@
class Members
{
+ friend class ObjAccessor;
friend class QPDFObjectHandle;
public:
diff -Nru qpdf-8.4.0/include/qpdf/QPDFSystemError.hh qpdf-8.4.2/include/qpdf/QPDFSystemError.hh
--- qpdf-8.4.0/include/qpdf/QPDFSystemError.hh 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/include/qpdf/QPDFSystemError.hh 2019-05-18 09:00:08.000000000 -0400
@@ -29,7 +29,7 @@
#include <string>
#include <stdexcept>
-class QPDFSystemError: public std::runtime_error
+class QPDF_DLL_EXCEPTION QPDFSystemError: public std::runtime_error
{
public:
QPDF_DLL
diff -Nru qpdf-8.4.0/ispell-words qpdf-8.4.2/ispell-words
--- qpdf-8.4.0/ispell-words 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/ispell-words 2019-05-18 09:00:08.000000000 -0400
@@ -117,6 +117,7 @@
argJsonKey
argJsonObject
argKeepFilesOpen
+argKeepFilesOpenThreshold
argKeepInlineImages
argLinearize
argLinearizePass
@@ -142,6 +143,7 @@
argProgress
argQdf
argRawStreamData
+argRemovePageLabels
argRotate
args
argShowEncryption
@@ -400,7 +402,6 @@
csoe
css
cstdio
-cstdlib
cstr
cstring
ctest
@@ -689,6 +690,7 @@
fullpad
func
fv
+fvisibility
fweimer
fwrite
fx
@@ -1451,6 +1453,7 @@
pdh
pdlin
pe
+performant
perl
persistAcrossFinish
Pfeifle
@@ -2045,15 +2048,21 @@
wcslen
Weimer
werror
+wfilename
+wfilenamep
WFLAGS
+wfopen
whoami
WinAnsi
winansi
WinAnsiEncoding
wincrypt
WindowsCryptProvider
+wlen
wmain
wmatrix
+wmode
+wmodep
Wold
wrapInArray
writeAppearance
diff -Nru qpdf-8.4.0/libqpdf/Pl_DCT.cc qpdf-8.4.2/libqpdf/Pl_DCT.cc
--- qpdf-8.4.0/libqpdf/Pl_DCT.cc 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/libqpdf/Pl_DCT.cc 2019-05-18 09:00:08.000000000 -0400
@@ -2,10 +2,11 @@
#include <qpdf/QUtil.hh>
#include <qpdf/QTC.hh>
+
#include <setjmp.h>
-#include <string>
#include <stdexcept>
-#include <cstdlib>
+#include <stdlib.h>
+#include <string>
#if BITS_IN_JSAMPLE != 8
# error "qpdf does not support libjpeg built with BITS_IN_JSAMPLE != 8"
diff -Nru qpdf-8.4.0/libqpdf/QPDF.cc qpdf-8.4.2/libqpdf/QPDF.cc
--- qpdf-8.4.0/libqpdf/QPDF.cc 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/libqpdf/QPDF.cc 2019-05-18 09:00:08.000000000 -0400
@@ -4,6 +4,7 @@
#include <vector>
#include <map>
#include <algorithm>
+#include <stdlib.h>
#include <string.h>
#include <memory.h>
@@ -20,7 +21,7 @@
#include <qpdf/QPDF_Dictionary.hh>
#include <qpdf/QPDF_Stream.hh>
-std::string QPDF::qpdf_version = "8.4.0";
+std::string QPDF::qpdf_version = "8.4.2";
static char const* EMPTY_PDF =
"%PDF-1.3\n"
diff -Nru qpdf-8.4.0/libqpdf/QPDFObjectHandle.cc qpdf-8.4.2/libqpdf/QPDFObjectHandle.cc
--- qpdf-8.4.0/libqpdf/QPDFObjectHandle.cc 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/libqpdf/QPDFObjectHandle.cc 2019-05-18 09:00:08.000000000 -0400
@@ -2524,14 +2524,14 @@
return true;
}
// Files have been seen in the wild that have /Type (Page)
- if (type.isString() && (type.getStringValue() == "Page"))
+ else if (type.isString() && (type.getStringValue() == "Page"))
{
return true;
}
- }
- if (this->hasKey("/Contents"))
- {
- return true;
+ else
+ {
+ return false;
+ }
}
return false;
}
diff -Nru qpdf-8.4.0/libqpdf/QPDF_Real.cc qpdf-8.4.2/libqpdf/QPDF_Real.cc
--- qpdf-8.4.0/libqpdf/QPDF_Real.cc 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/libqpdf/QPDF_Real.cc 2019-05-18 09:00:08.000000000 -0400
@@ -25,7 +25,30 @@
JSON
QPDF_Real::getJSON()
{
- return JSON::makeNumber(this->val);
+ // While PDF allows .x or -.x, JSON does not. Rather than
+ // converting from string to double and back, just handle this as a
+ // special case for JSON.
+ std::string result;
+ if (this->val.length() == 0)
+ {
+ // Can't really happen...
+ result = "0";
+ }
+ else if (this->val.at(0) == '.')
+ {
+ result = "0" + this->val;
+ }
+ else if ((this->val.length() >= 2) &&
+ (this->val.at(0) == '-') &&
+ (this->val.at(1) == '.'))
+ {
+ result = "-0." + this->val.substr(2);
+ }
+ else
+ {
+ result = this->val;
+ }
+ return JSON::makeNumber(result);
}
QPDFObject::object_type_e
diff -Nru qpdf-8.4.0/libqpdf/QPDFTokenizer.cc qpdf-8.4.2/libqpdf/QPDFTokenizer.cc
--- qpdf-8.4.0/libqpdf/QPDFTokenizer.cc 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/libqpdf/QPDFTokenizer.cc 2019-05-18 09:00:08.000000000 -0400
@@ -10,8 +10,8 @@
#include <qpdf/QPDFObjectHandle.hh>
#include <stdexcept>
+#include <stdlib.h>
#include <string.h>
-#include <cstdlib>
static bool is_delimiter(char ch)
{
diff -Nru qpdf-8.4.0/libqpdf/QUtil.cc qpdf-8.4.2/libqpdf/QUtil.cc
--- qpdf-8.4.0/libqpdf/QUtil.cc 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/libqpdf/QUtil.cc 2019-05-18 09:00:08.000000000 -0400
@@ -354,11 +354,42 @@
QUtil::safe_fopen(char const* filename, char const* mode)
{
FILE* f = 0;
+#ifdef _WIN32
+ // Convert the utf-8 encoded filename argument to wchar_t*. First,
+ // convert to utf16, then to wchar_t*. Note that u16 will start
+ // with the UTF16 marker, which we skip.
+ std::string u16 = utf8_to_utf16(filename);
+ size_t len = u16.length();
+ size_t wlen = (len / 2) - 1;
+ PointerHolder<wchar_t> wfilenamep(true, new wchar_t[wlen + 1]);
+ wchar_t* wfilename = wfilenamep.getPointer();
+ wfilename[wlen] = 0;
+ for (unsigned int i = 2; i < len; i += 2)
+ {
+ wfilename[(i/2) - 1] =
+ static_cast<wchar_t>(
+ (static_cast<unsigned char>(u16.at(i)) << 8) +
+ static_cast<unsigned char>(u16.at(i+1)));
+ }
+ PointerHolder<wchar_t> wmodep(true, new wchar_t[strlen(mode) + 1]);
+ wchar_t* wmode = wmodep.getPointer();
+ wmode[strlen(mode)] = 0;
+ for (size_t i = 0; i < strlen(mode); ++i)
+ {
+ wmode[i] = mode[i];
+ }
+
#ifdef _MSC_VER
- errno_t err = fopen_s(&f, filename, mode);
+ errno_t err = _wfopen_s(&f, wfilename, wmode);
if (err != 0)
{
errno = err;
+ }
+#else
+ f = _wfopen(wfilename, wmode);
+#endif
+ if (f == 0)
+ {
throw_system_error(std::string("open ") + filename);
}
#else
@@ -529,7 +560,9 @@
void
QUtil::binary_stdout()
{
-#ifdef _WIN32
+#if defined(_WIN32) && defined(__BORLANDC__)
+ setmode(_fileno(stdout), _O_BINARY);
+#elif defined(_WIN32)
_setmode(_fileno(stdout), _O_BINARY);
#endif
}
@@ -537,7 +570,9 @@
void
QUtil::binary_stdin()
{
-#ifdef _WIN32
+#if defined(_WIN32) && defined(__BORLANDC__)
+ setmode(_fileno(stdin), _O_BINARY);
+#elif defined(_WIN32)
_setmode(_fileno(stdin), _O_BINARY);
#endif
}
@@ -918,7 +953,9 @@
int
QUtil::strcasecmp(char const *s1, char const *s2)
{
-#ifdef _WIN32
+#if defined(_WIN32) && defined(__BORLANDC__)
+ return stricmp(s1, s2);
+#elif defined(_WIN32)
return _stricmp(s1, s2);
#else
return ::strcasecmp(s1, s2);
diff -Nru qpdf-8.4.0/libtests/json.cc qpdf-8.4.2/libtests/json.cc
--- qpdf-8.4.0/libtests/json.cc 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/libtests/json.cc 2019-05-18 09:00:08.000000000 -0400
@@ -3,7 +3,7 @@
#include <iostream>
#include <assert.h>
-static void check(JSON& j, std::string const& exp)
+static void check(JSON const& j, std::string const& exp)
{
if (exp != j.unparse())
{
@@ -69,6 +69,10 @@
" ],\n"
" \"yes\": false\n"
"}");
+ check(QPDFObjectHandle::newReal("0.12").getJSON(), "0.12");
+ check(QPDFObjectHandle::newReal(".34").getJSON(), "0.34");
+ check(QPDFObjectHandle::newReal("-0.56").getJSON(), "-0.56");
+ check(QPDFObjectHandle::newReal("-.78").getJSON(), "-0.78");
}
static void check_schema(JSON& obj, JSON& schema, bool exp,
diff -Nru qpdf-8.4.0/make_dist qpdf-8.4.2/make_dist
--- qpdf-8.4.0/make_dist 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/make_dist 2019-05-18 09:00:08.000000000 -0400
@@ -63,6 +63,7 @@
my $config_version = get_version_from_configure();
my $code_version = get_version_from_source();
my $doc_version = get_version_from_manual();
+my $cli_version = get_version_from_cli();
my $version_error = 0;
if ($version ne $config_version)
@@ -80,6 +81,11 @@
print "$whoami: qpdf-manual.xml version = $doc_version\n";
$version_error = 1;
}
+if ($version ne $cli_version)
+{
+ print "$whoami: qpdf.cc version = $cli_version\n";
+ $version_error = 1;
+}
if ($version_error)
{
die "$whoami: version numbers are not consistent\n";
@@ -161,6 +167,22 @@
$doc_version;
}
+sub get_version_from_cli
+{
+ my $fh = safe_open("qpdf/qpdf.cc");
+ my $cli_version = 'unknown';
+ while (<$fh>)
+ {
+ if (m/expected_version = \"([^\"]+)\"/)
+ {
+ $cli_version = $1;
+ last;
+ }
+ }
+ $fh->close();
+ $cli_version;
+}
+
sub safe_open
{
my $file = shift;
diff -Nru qpdf-8.4.0/manual/qpdf-manual.xml qpdf-8.4.2/manual/qpdf-manual.xml
--- qpdf-8.4.0/manual/qpdf-manual.xml 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/manual/qpdf-manual.xml 2019-05-18 09:00:08.000000000 -0400
@@ -5,8 +5,8 @@
<!ENTITY mdash "—">
<!ENTITY ndash "–">
<!ENTITY nbsp " ">
-<!ENTITY swversion "8.4.0">
-<!ENTITY lastreleased "February 1, 2019">
+<!ENTITY swversion "8.4.2">
+<!ENTITY lastreleased "May 18, 2019">
]>
<book>
<bookinfo>
@@ -652,6 +652,19 @@
more than the OS limit's number of files from a script and are
not worried about a few seconds additional processing time,
you may want to specify <option>--keep-files-open=n</option>.
+ The threshold for switching may be changed from the default
+ 200 with the <option>--keep-files-open-threshold</option>
+ option.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term><option>--keep-files-open-threshold=<replaceable>count</replaceable></option></term>
+ <listitem>
+ <para>
+ If specified, overrides the default value of 200 used as the
+ threshold for qpdf deciding whether or not to keep files open.
+ See <option>--keep-files-open</option> for details.
</para>
</listitem>
</varlistentry>
@@ -1784,9 +1797,6 @@
</para>
</listitem>
</varlistentry>
-
-
-
<varlistentry>
<term><option>--externalize-inline-images</option></term>
<listitem>
@@ -1822,11 +1832,20 @@
</listitem>
</varlistentry>
<varlistentry>
+ <term><option>--remove-page-labels</option></term>
+ <listitem>
+ <para>
+ Remove page labels from the output file.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term><option>--qdf</option></term>
<listitem>
<para>
Turns on QDF mode. For additional information on QDF, please
- see <xref linkend="ref.qdf"/>.
+ see <xref linkend="ref.qdf"/>. Note that
+ <option>--linearize</option> disables QDF mode.
</para>
</listitem>
</varlistentry>
@@ -2364,7 +2383,9 @@
some restrictions, in an ordinary text editor. This can be very
useful for experimenting with different PDF constructs or for
making one-off edits to PDF files (though there are other reasons
- why this may not always work).
+ why this may not always work). Note that QDF mode does not support
+ linearized files. If you enable linearization, QDF mode is
+ automatically disabled.
</para>
<para>
It is ordinarily very difficult to edit PDF files in a text editor
@@ -2591,6 +2612,31 @@
</varlistentry>
</variablelist>
</sect1>
+ <sect1 id="ref.unicode-files">
+ <title>A Note About Unicode File Names</title>
+ <para>
+ When strings are passed to qpdf library routines either as
+ <literal>char*</literal> or as <literal>std::string</literal>,
+ they are treated as byte arrays except where otherwise noted. When
+ Unicode is desired, qpdf wants UTF-8 unless otherwise noted in
+ comments in header files. In modern UNIX/Linux environments, this
+ generally does the right thing. In Windows, it's a bit more
+ complicated. Starting in qpdf 8.4.0, passwords that contain
+ Unicode characters are handled much better, and starting in qpdf
+ 8.4.1, the library attempts to properly handle Unicode characters
+ in filenames. In particular, in Windows, if a UTF-8 encoded string
+ is used as a filename in either <classname>QPDF</classname> or
+ <classname>QPDFWriter</classname>, it is internally converted to
+ <literal>wchar_t*</literal>, and Unicode-aware Windows APIs are
+ used. As such, qpdf will generally operate properly on files with
+ non-ASCII characters in their names as long as the filenames are
+ UTF-8 encoded for passing into the qpdf library API, but there are
+ still some rough edges, such as the encoding of the filenames in
+ error messages our CLI output messages. Patches or bug reports are
+ welcome for any continuing issues with Unicode file names in
+ Windows.
+ </para>
+ </sect1>
</chapter>
<chapter id="ref.json">
<title>QPDF JSON</title>
@@ -4302,6 +4348,100 @@
</para>
<variablelist>
<varlistentry>
+ <term>8.4.2: May 18, 2019</term>
+ <listitem>
+ <para>
+ This release has just one change: correction of a buffer overrun
+ in the Windows code used to open files. Windows users should
+ take this update. There are no code changes that affect
+ non-Windows releases.
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>8.4.1: April 27, 2019</term>
+ <listitem>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Enhancements
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ When <command>qpdf --version</command> is run, it will
+ detect if the qpdf CLI was built with a different version of
+ qpdf than the library, which may indicate a problem with the
+ installation.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ New option <option>--remove-page-labels</option> will remove page
+ labels before generating output. This used to happen if you
+ ran <command>qpdf --empty --pages .. --</command>, but the
+ behavior changed in qpdf 8.3.0. This option enables people
+ who were relying on the old behavior to get it again.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ New option
+ <option>--keep-files-open-threshold=<replaceable>count</replaceable></option>
+ can be used to override number of files that qpdf will use
+ to trigger the behavior of not keeping all files open when
+ merging files. This may be necessary if your system allows
+ fewer than the default value of 200 files to be open at the
+ same time.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ <listitem>
+ <para>
+ Bug Fixes
+ </para>
+ <itemizedlist>
+ <listitem>
+ <para>
+ Handle Unicode characters in filenames on Windows. The
+ changes to support Unicode on the CLI in Windows broke
+ Unicode filenames for Windows.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Slightly tighten logic that determines whether an object is
+ a page. This should resolve problems in some rare files
+ where some non-page objects were passing qpdf's test for
+ whether something was a page, thus causing them to be
+ erroneously lost during page splitting operations.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ Revert change that included preservation of outlines
+ (bookmarks) in <option>--split-pages</option>. The way it
+ was implemented in 8.3.0 and 8.4.0 caused a very significant
+ degradation of performance for splitting certain files. A
+ future release of qpdf may re-introduce the behavior in a
+ more performant and also more correct fashion.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ In JSON mode, add missing leading 0 to decimal values
+ between -1 and 1 even if not present in the input. The JSON
+ specification requires the leading 0. The PDF specification
+ does not.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </itemizedlist>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
<term>8.4.0: February 1, 2019</term>
<listitem>
<itemizedlist>
diff -Nru qpdf-8.4.0/qpdf/build.mk qpdf-8.4.2/qpdf/build.mk
--- qpdf-8.4.0/qpdf/build.mk 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/qpdf/build.mk 2019-05-18 09:00:08.000000000 -0400
@@ -5,7 +5,8 @@
test_large_file \
test_pdf_doc_encoding \
test_pdf_unicode \
- test_tokenizer
+ test_tokenizer \
+ test_unicode_filenames
CBINS_qpdf = qpdf-ctest
TARGETS_qpdf = $(foreach B,$(BINS_qpdf) $(CBINS_qpdf),qpdf/$(OUTPUT_DIR)/$(call binname,$(B)))
@@ -20,6 +21,8 @@
XCXXFLAGS_qpdf_qpdf := $(WINDOWS_WMAIN_COMPILE)
XLDFLAGS_qpdf_qpdf := $(WINDOWS_WMAIN_LINK)
+XCXXFLAGS_qpdf_test_unicode_filenames := $(WINDOWS_WMAIN_COMPILE)
+XLDFLAGS_qpdf_test_unicode_filenames := $(WINDOWS_WMAIN_LINK)
$(foreach B,$(BINS_qpdf),$(eval \
OBJS_$(B) = $(call src_to_obj,qpdf/$(B).cc)))
diff -Nru qpdf-8.4.0/qpdf/qpdf.cc qpdf-8.4.2/qpdf/qpdf.cc
--- qpdf-8.4.0/qpdf/qpdf.cc 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/qpdf/qpdf.cc 2019-05-18 09:00:08.000000000 -0400
@@ -30,6 +30,8 @@
static char const* whoami = 0;
+static std::string expected_version = "8.4.2";
+
struct PageSpec
{
PageSpec(std::string const& filename,
@@ -134,6 +136,7 @@
preserve_unreferenced_page_resources(false),
keep_files_open(true),
keep_files_open_set(false),
+ keep_files_open_threshold(200), // default known in help and docs
newline_before_endstream(false),
coalesce_contents(false),
flatten_annotations(false),
@@ -163,6 +166,7 @@
optimize_images(false),
externalize_inline_images(false),
keep_inline_images(false),
+ remove_page_labels(false),
oi_min_width(128), // Default values for these
oi_min_height(128), // oi flags are in --help
oi_min_area(16384), // and in the manual.
@@ -225,6 +229,7 @@
bool preserve_unreferenced_page_resources;
bool keep_files_open;
bool keep_files_open_set;
+ size_t keep_files_open_threshold;
bool newline_before_endstream;
std::string linearize_pass1;
bool coalesce_contents;
@@ -259,6 +264,7 @@
bool optimize_images;
bool externalize_inline_images;
bool keep_inline_images;
+ bool remove_page_labels;
size_t oi_min_width;
size_t oi_min_height;
size_t oi_min_area;
@@ -634,6 +640,7 @@
void argPreserveUnreferenced();
void argPreserveUnreferencedResources();
void argKeepFilesOpen(char* parameter);
+ void argKeepFilesOpenThreshold(char* parameter);
void argNewlineBeforeEndstream();
void argLinearizePass1(char* parameter);
void argCoalesceContents();
@@ -667,6 +674,7 @@
void argOptimizeImages();
void argExternalizeInlineImages();
void argKeepInlineImages();
+ void argRemovePageLabels();
void argOiMinWidth(char* parameter);
void argOiMinHeight(char* parameter);
void argOiMinArea(char* parameter);
@@ -857,6 +865,8 @@
&ArgParser::argPreserveUnreferencedResources);
(*t)["keep-files-open"] = oe_requiredChoices(
&ArgParser::argKeepFilesOpen, yn);
+ (*t)["keep-files-open-threshold"] = oe_requiredParameter(
+ &ArgParser::argKeepFilesOpenThreshold, "count");
(*t)["newline-before-endstream"] = oe_bare(
&ArgParser::argNewlineBeforeEndstream);
(*t)["linearize-pass1"] = oe_requiredParameter(
@@ -906,6 +916,7 @@
(*t)["externalize-inline-images"] =
oe_bare(&ArgParser::argExternalizeInlineImages);
(*t)["keep-inline-images"] = oe_bare(&ArgParser::argKeepInlineImages);
+ (*t)["remove-page-labels"] = oe_bare(&ArgParser::argRemovePageLabels);
(*t)["oi-min-width"] = oe_requiredParameter(
&ArgParser::argOiMinWidth, "minimum-width");
(*t)["oi-min-height"] = oe_requiredParameter(
@@ -984,6 +995,17 @@
void
ArgParser::argVersion()
{
+ if (expected_version != QPDF::QPDFVersion())
+ {
+ std::cerr << "***\n"
+ << "WARNING: qpdf CLI from version " << expected_version
+ << " is using library version " << QPDF::QPDFVersion()
+ << ".\n"
+ << "This probably means you have multiple versions of qpdf installed\n"
+ << "and don't have your library path configured correctly.\n"
+ << "***"
+ << std::endl;
+ }
std::cout
<< whoami << " version " << QPDF::QPDFVersion() << std::endl
<< "Run " << whoami << " --copyright to see copyright and license information."
@@ -1209,6 +1231,7 @@
<< "starting point, but its pages are replaced with pages as specified.\n"
<< "\n"
<< "--keep-files-open=[yn]\n"
+ << "--keep-files-open-threshold=count\n"
<< "--pages file [ --password=password ] [ page-range ] ... --\n"
<< "\n"
<< "For each file that pages should be taken from, specify the file, a\n"
@@ -1227,7 +1250,8 @@
<< "files will be kept open at the same time. This behavior can be overridden\n"
<< "by specifying --keep-files-open=[yn]. Closing and opening files can have\n"
<< "very high overhead on certain file systems, especially networked file\n"
- << "systems.\n"
+ << "systems. The threshold of 200 can be modified with\n"
+ << "--keep-files-open-threshold\n"
<< "\n"
<< "The page range is a set of numbers separated by commas, ranges of\n"
<< "numbers separated dashes, or combinations of those. The character\n"
@@ -1328,6 +1352,7 @@
<< "--ii-min-bytes=bytes specify minimum size of inline images to be\n"
<< " converted to regular images\n"
<< "--keep-inline-images exclude inline images from image optimization\n"
+ << "--remove-page-labels remove any page labels present in the output file\n"
<< "--qdf turns on \"QDF mode\" (below)\n"
<< "--linearize-pass1=file write intermediate pass of linearized file\n"
<< " for debugging\n"
@@ -1378,7 +1403,8 @@
<< " including DCT (JPEG)\n"
<< "\n"
<< "In qdf mode, by default, content normalization is turned on, and the\n"
- << "stream data mode is set to uncompress.\n"
+ << "stream data mode is set to uncompress. QDF mode does not support\n"
+ << "linearized files. The --linearize flag disables qdf mode.\n"
<< "\n"
<< "Setting the minimum PDF version of the output file may raise the version\n"
<< "but will never lower it. Forcing the PDF version of the output file may\n"
@@ -1781,6 +1807,13 @@
}
void
+ArgParser::argKeepFilesOpenThreshold(char* parameter)
+{
+ o.keep_files_open_threshold =
+ static_cast<size_t>(QUtil::string_to_int(parameter));
+}
+
+void
ArgParser::argNewlineBeforeEndstream()
{
o.newline_before_endstream = true;
@@ -1998,6 +2031,12 @@
}
void
+ArgParser::argRemovePageLabels()
+{
+ o.remove_page_labels = true;
+}
+
+void
ArgParser::argOiMinWidth(char* parameter)
{
o.oi_min_width = QUtil::string_to_int(parameter);
@@ -3836,7 +3875,7 @@
h_obj.isInteger() ? h_obj.getIntValue() : h_obj.getNumericValue());
std::string colorspace = (colorspace_obj.isName() ?
colorspace_obj.getName() :
- "");
+ std::string());
int components = 0;
J_COLOR_SPACE cs = JCS_UNKNOWN;
if (colorspace == "/DeviceRGB")
@@ -4320,6 +4359,10 @@
(*iter).coalesceContentStreams();
}
}
+ if (o.remove_page_labels)
+ {
+ pdf.getRoot().removeKey("/PageLabels");
+ }
}
static void handle_page_specs(QPDF& pdf, Options& o)
@@ -4351,9 +4394,7 @@
PageSpec& page_spec = *iter;
filenames.insert(page_spec.filename);
}
- // NOTE: The number 200 for this threshold is in the help
- // message and manual and is baked into the test suite.
- if (filenames.size() > 200)
+ if (filenames.size() > o.keep_files_open_threshold)
{
QTC::TC("qpdf", "qpdf disable keep files open");
if (o.verbose)
@@ -4966,30 +5007,6 @@
"/Nums", QPDFObjectHandle::newArray(labels));
outpdf.getRoot().replaceKey("/PageLabels", page_labels);
}
- // Copying the outlines tree, names table, and any
- // outdated Dests key from the original file will make
- // some things work in the split files. It is not a
- // complete solution, but at least outlines whose
- // destinations are on pages that have been preserved will
- // work normally. There are other top-level structures
- // that should be copied as well. This will be improved in
- // the future.
- std::list<std::string> to_copy;
- to_copy.push_back("/Names");
- to_copy.push_back("/Dests");
- to_copy.push_back("/Outlines");
- for (std::list<std::string>::iterator iter = to_copy.begin();
- iter != to_copy.end(); ++iter)
- {
- QPDFObjectHandle orig = pdf.getRoot().getKey(*iter);
- if (! orig.isIndirect())
- {
- orig = pdf.makeIndirectObject(orig);
- }
- outpdf.getRoot().replaceKey(
- *iter,
- outpdf.copyForeignObject(orig));
- }
std::string page_range = QUtil::int_to_string(first, pageno_len);
if (o.split_pages > 1)
{
diff -Nru qpdf-8.4.0/qpdf/qtest/qpdf/check-unicode-filename-1.out qpdf-8.4.2/qpdf/qtest/qpdf/check-unicode-filename-1.out
--- qpdf-8.4.0/qpdf/qtest/qpdf/check-unicode-filename-1.out 1969-12-31 19:00:00.000000000 -0500
+++ qpdf-8.4.2/qpdf/qtest/qpdf/check-unicode-filename-1.out 2019-05-18 09:00:08.000000000 -0400
@@ -0,0 +1,6 @@
+checking auto-ü.pdf
+PDF Version: 1.3
+File is not encrypted
+File is not linearized
+No syntax or stream encoding errors found; the file may still contain
+errors that qpdf cannot detect
diff -Nru qpdf-8.4.0/qpdf/qtest/qpdf/check-unicode-filename-2.out qpdf-8.4.2/qpdf/qtest/qpdf/check-unicode-filename-2.out
--- qpdf-8.4.0/qpdf/qtest/qpdf/check-unicode-filename-2.out 1969-12-31 19:00:00.000000000 -0500
+++ qpdf-8.4.2/qpdf/qtest/qpdf/check-unicode-filename-2.out 2019-05-18 09:00:08.000000000 -0400
@@ -0,0 +1,6 @@
+checking auto-öπ.pdf
+PDF Version: 1.3
+File is not encrypted
+File is not linearized
+No syntax or stream encoding errors found; the file may still contain
+errors that qpdf cannot detect
diff -Nru qpdf-8.4.0/qpdf/qtest/qpdf/disable-kfo.out qpdf-8.4.2/qpdf/qtest/qpdf/disable-kfo.out
--- qpdf-8.4.0/qpdf/qtest/qpdf/disable-kfo.out 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/qpdf/qtest/qpdf/disable-kfo.out 2019-05-18 09:00:08.000000000 -0400
@@ -50,156 +50,6 @@
qpdf: processing 049-kfo.pdf
qpdf: processing 050-kfo.pdf
qpdf: processing 051-kfo.pdf
-qpdf: processing 052-kfo.pdf
-qpdf: processing 053-kfo.pdf
-qpdf: processing 054-kfo.pdf
-qpdf: processing 055-kfo.pdf
-qpdf: processing 056-kfo.pdf
-qpdf: processing 057-kfo.pdf
-qpdf: processing 058-kfo.pdf
-qpdf: processing 059-kfo.pdf
-qpdf: processing 060-kfo.pdf
-qpdf: processing 061-kfo.pdf
-qpdf: processing 062-kfo.pdf
-qpdf: processing 063-kfo.pdf
-qpdf: processing 064-kfo.pdf
-qpdf: processing 065-kfo.pdf
-qpdf: processing 066-kfo.pdf
-qpdf: processing 067-kfo.pdf
-qpdf: processing 068-kfo.pdf
-qpdf: processing 069-kfo.pdf
-qpdf: processing 070-kfo.pdf
-qpdf: processing 071-kfo.pdf
-qpdf: processing 072-kfo.pdf
-qpdf: processing 073-kfo.pdf
-qpdf: processing 074-kfo.pdf
-qpdf: processing 075-kfo.pdf
-qpdf: processing 076-kfo.pdf
-qpdf: processing 077-kfo.pdf
-qpdf: processing 078-kfo.pdf
-qpdf: processing 079-kfo.pdf
-qpdf: processing 080-kfo.pdf
-qpdf: processing 081-kfo.pdf
-qpdf: processing 082-kfo.pdf
-qpdf: processing 083-kfo.pdf
-qpdf: processing 084-kfo.pdf
-qpdf: processing 085-kfo.pdf
-qpdf: processing 086-kfo.pdf
-qpdf: processing 087-kfo.pdf
-qpdf: processing 088-kfo.pdf
-qpdf: processing 089-kfo.pdf
-qpdf: processing 090-kfo.pdf
-qpdf: processing 091-kfo.pdf
-qpdf: processing 092-kfo.pdf
-qpdf: processing 093-kfo.pdf
-qpdf: processing 094-kfo.pdf
-qpdf: processing 095-kfo.pdf
-qpdf: processing 096-kfo.pdf
-qpdf: processing 097-kfo.pdf
-qpdf: processing 098-kfo.pdf
-qpdf: processing 099-kfo.pdf
-qpdf: processing 100-kfo.pdf
-qpdf: processing 101-kfo.pdf
-qpdf: processing 102-kfo.pdf
-qpdf: processing 103-kfo.pdf
-qpdf: processing 104-kfo.pdf
-qpdf: processing 105-kfo.pdf
-qpdf: processing 106-kfo.pdf
-qpdf: processing 107-kfo.pdf
-qpdf: processing 108-kfo.pdf
-qpdf: processing 109-kfo.pdf
-qpdf: processing 110-kfo.pdf
-qpdf: processing 111-kfo.pdf
-qpdf: processing 112-kfo.pdf
-qpdf: processing 113-kfo.pdf
-qpdf: processing 114-kfo.pdf
-qpdf: processing 115-kfo.pdf
-qpdf: processing 116-kfo.pdf
-qpdf: processing 117-kfo.pdf
-qpdf: processing 118-kfo.pdf
-qpdf: processing 119-kfo.pdf
-qpdf: processing 120-kfo.pdf
-qpdf: processing 121-kfo.pdf
-qpdf: processing 122-kfo.pdf
-qpdf: processing 123-kfo.pdf
-qpdf: processing 124-kfo.pdf
-qpdf: processing 125-kfo.pdf
-qpdf: processing 126-kfo.pdf
-qpdf: processing 127-kfo.pdf
-qpdf: processing 128-kfo.pdf
-qpdf: processing 129-kfo.pdf
-qpdf: processing 130-kfo.pdf
-qpdf: processing 131-kfo.pdf
-qpdf: processing 132-kfo.pdf
-qpdf: processing 133-kfo.pdf
-qpdf: processing 134-kfo.pdf
-qpdf: processing 135-kfo.pdf
-qpdf: processing 136-kfo.pdf
-qpdf: processing 137-kfo.pdf
-qpdf: processing 138-kfo.pdf
-qpdf: processing 139-kfo.pdf
-qpdf: processing 140-kfo.pdf
-qpdf: processing 141-kfo.pdf
-qpdf: processing 142-kfo.pdf
-qpdf: processing 143-kfo.pdf
-qpdf: processing 144-kfo.pdf
-qpdf: processing 145-kfo.pdf
-qpdf: processing 146-kfo.pdf
-qpdf: processing 147-kfo.pdf
-qpdf: processing 148-kfo.pdf
-qpdf: processing 149-kfo.pdf
-qpdf: processing 150-kfo.pdf
-qpdf: processing 151-kfo.pdf
-qpdf: processing 152-kfo.pdf
-qpdf: processing 153-kfo.pdf
-qpdf: processing 154-kfo.pdf
-qpdf: processing 155-kfo.pdf
-qpdf: processing 156-kfo.pdf
-qpdf: processing 157-kfo.pdf
-qpdf: processing 158-kfo.pdf
-qpdf: processing 159-kfo.pdf
-qpdf: processing 160-kfo.pdf
-qpdf: processing 161-kfo.pdf
-qpdf: processing 162-kfo.pdf
-qpdf: processing 163-kfo.pdf
-qpdf: processing 164-kfo.pdf
-qpdf: processing 165-kfo.pdf
-qpdf: processing 166-kfo.pdf
-qpdf: processing 167-kfo.pdf
-qpdf: processing 168-kfo.pdf
-qpdf: processing 169-kfo.pdf
-qpdf: processing 170-kfo.pdf
-qpdf: processing 171-kfo.pdf
-qpdf: processing 172-kfo.pdf
-qpdf: processing 173-kfo.pdf
-qpdf: processing 174-kfo.pdf
-qpdf: processing 175-kfo.pdf
-qpdf: processing 176-kfo.pdf
-qpdf: processing 177-kfo.pdf
-qpdf: processing 178-kfo.pdf
-qpdf: processing 179-kfo.pdf
-qpdf: processing 180-kfo.pdf
-qpdf: processing 181-kfo.pdf
-qpdf: processing 182-kfo.pdf
-qpdf: processing 183-kfo.pdf
-qpdf: processing 184-kfo.pdf
-qpdf: processing 185-kfo.pdf
-qpdf: processing 186-kfo.pdf
-qpdf: processing 187-kfo.pdf
-qpdf: processing 188-kfo.pdf
-qpdf: processing 189-kfo.pdf
-qpdf: processing 190-kfo.pdf
-qpdf: processing 191-kfo.pdf
-qpdf: processing 192-kfo.pdf
-qpdf: processing 193-kfo.pdf
-qpdf: processing 194-kfo.pdf
-qpdf: processing 195-kfo.pdf
-qpdf: processing 196-kfo.pdf
-qpdf: processing 197-kfo.pdf
-qpdf: processing 198-kfo.pdf
-qpdf: processing 199-kfo.pdf
-qpdf: processing 200-kfo.pdf
-qpdf: processing 201-kfo.pdf
qpdf: removing unreferenced pages from primary input
qpdf: adding pages from 001-kfo.pdf
qpdf: adding pages from 002-kfo.pdf
@@ -252,154 +102,4 @@
qpdf: adding pages from 049-kfo.pdf
qpdf: adding pages from 050-kfo.pdf
qpdf: adding pages from 051-kfo.pdf
-qpdf: adding pages from 052-kfo.pdf
-qpdf: adding pages from 053-kfo.pdf
-qpdf: adding pages from 054-kfo.pdf
-qpdf: adding pages from 055-kfo.pdf
-qpdf: adding pages from 056-kfo.pdf
-qpdf: adding pages from 057-kfo.pdf
-qpdf: adding pages from 058-kfo.pdf
-qpdf: adding pages from 059-kfo.pdf
-qpdf: adding pages from 060-kfo.pdf
-qpdf: adding pages from 061-kfo.pdf
-qpdf: adding pages from 062-kfo.pdf
-qpdf: adding pages from 063-kfo.pdf
-qpdf: adding pages from 064-kfo.pdf
-qpdf: adding pages from 065-kfo.pdf
-qpdf: adding pages from 066-kfo.pdf
-qpdf: adding pages from 067-kfo.pdf
-qpdf: adding pages from 068-kfo.pdf
-qpdf: adding pages from 069-kfo.pdf
-qpdf: adding pages from 070-kfo.pdf
-qpdf: adding pages from 071-kfo.pdf
-qpdf: adding pages from 072-kfo.pdf
-qpdf: adding pages from 073-kfo.pdf
-qpdf: adding pages from 074-kfo.pdf
-qpdf: adding pages from 075-kfo.pdf
-qpdf: adding pages from 076-kfo.pdf
-qpdf: adding pages from 077-kfo.pdf
-qpdf: adding pages from 078-kfo.pdf
-qpdf: adding pages from 079-kfo.pdf
-qpdf: adding pages from 080-kfo.pdf
-qpdf: adding pages from 081-kfo.pdf
-qpdf: adding pages from 082-kfo.pdf
-qpdf: adding pages from 083-kfo.pdf
-qpdf: adding pages from 084-kfo.pdf
-qpdf: adding pages from 085-kfo.pdf
-qpdf: adding pages from 086-kfo.pdf
-qpdf: adding pages from 087-kfo.pdf
-qpdf: adding pages from 088-kfo.pdf
-qpdf: adding pages from 089-kfo.pdf
-qpdf: adding pages from 090-kfo.pdf
-qpdf: adding pages from 091-kfo.pdf
-qpdf: adding pages from 092-kfo.pdf
-qpdf: adding pages from 093-kfo.pdf
-qpdf: adding pages from 094-kfo.pdf
-qpdf: adding pages from 095-kfo.pdf
-qpdf: adding pages from 096-kfo.pdf
-qpdf: adding pages from 097-kfo.pdf
-qpdf: adding pages from 098-kfo.pdf
-qpdf: adding pages from 099-kfo.pdf
-qpdf: adding pages from 100-kfo.pdf
-qpdf: adding pages from 101-kfo.pdf
-qpdf: adding pages from 102-kfo.pdf
-qpdf: adding pages from 103-kfo.pdf
-qpdf: adding pages from 104-kfo.pdf
-qpdf: adding pages from 105-kfo.pdf
-qpdf: adding pages from 106-kfo.pdf
-qpdf: adding pages from 107-kfo.pdf
-qpdf: adding pages from 108-kfo.pdf
-qpdf: adding pages from 109-kfo.pdf
-qpdf: adding pages from 110-kfo.pdf
-qpdf: adding pages from 111-kfo.pdf
-qpdf: adding pages from 112-kfo.pdf
-qpdf: adding pages from 113-kfo.pdf
-qpdf: adding pages from 114-kfo.pdf
-qpdf: adding pages from 115-kfo.pdf
-qpdf: adding pages from 116-kfo.pdf
-qpdf: adding pages from 117-kfo.pdf
-qpdf: adding pages from 118-kfo.pdf
-qpdf: adding pages from 119-kfo.pdf
-qpdf: adding pages from 120-kfo.pdf
-qpdf: adding pages from 121-kfo.pdf
-qpdf: adding pages from 122-kfo.pdf
-qpdf: adding pages from 123-kfo.pdf
-qpdf: adding pages from 124-kfo.pdf
-qpdf: adding pages from 125-kfo.pdf
-qpdf: adding pages from 126-kfo.pdf
-qpdf: adding pages from 127-kfo.pdf
-qpdf: adding pages from 128-kfo.pdf
-qpdf: adding pages from 129-kfo.pdf
-qpdf: adding pages from 130-kfo.pdf
-qpdf: adding pages from 131-kfo.pdf
-qpdf: adding pages from 132-kfo.pdf
-qpdf: adding pages from 133-kfo.pdf
-qpdf: adding pages from 134-kfo.pdf
-qpdf: adding pages from 135-kfo.pdf
-qpdf: adding pages from 136-kfo.pdf
-qpdf: adding pages from 137-kfo.pdf
-qpdf: adding pages from 138-kfo.pdf
-qpdf: adding pages from 139-kfo.pdf
-qpdf: adding pages from 140-kfo.pdf
-qpdf: adding pages from 141-kfo.pdf
-qpdf: adding pages from 142-kfo.pdf
-qpdf: adding pages from 143-kfo.pdf
-qpdf: adding pages from 144-kfo.pdf
-qpdf: adding pages from 145-kfo.pdf
-qpdf: adding pages from 146-kfo.pdf
-qpdf: adding pages from 147-kfo.pdf
-qpdf: adding pages from 148-kfo.pdf
-qpdf: adding pages from 149-kfo.pdf
-qpdf: adding pages from 150-kfo.pdf
-qpdf: adding pages from 151-kfo.pdf
-qpdf: adding pages from 152-kfo.pdf
-qpdf: adding pages from 153-kfo.pdf
-qpdf: adding pages from 154-kfo.pdf
-qpdf: adding pages from 155-kfo.pdf
-qpdf: adding pages from 156-kfo.pdf
-qpdf: adding pages from 157-kfo.pdf
-qpdf: adding pages from 158-kfo.pdf
-qpdf: adding pages from 159-kfo.pdf
-qpdf: adding pages from 160-kfo.pdf
-qpdf: adding pages from 161-kfo.pdf
-qpdf: adding pages from 162-kfo.pdf
-qpdf: adding pages from 163-kfo.pdf
-qpdf: adding pages from 164-kfo.pdf
-qpdf: adding pages from 165-kfo.pdf
-qpdf: adding pages from 166-kfo.pdf
-qpdf: adding pages from 167-kfo.pdf
-qpdf: adding pages from 168-kfo.pdf
-qpdf: adding pages from 169-kfo.pdf
-qpdf: adding pages from 170-kfo.pdf
-qpdf: adding pages from 171-kfo.pdf
-qpdf: adding pages from 172-kfo.pdf
-qpdf: adding pages from 173-kfo.pdf
-qpdf: adding pages from 174-kfo.pdf
-qpdf: adding pages from 175-kfo.pdf
-qpdf: adding pages from 176-kfo.pdf
-qpdf: adding pages from 177-kfo.pdf
-qpdf: adding pages from 178-kfo.pdf
-qpdf: adding pages from 179-kfo.pdf
-qpdf: adding pages from 180-kfo.pdf
-qpdf: adding pages from 181-kfo.pdf
-qpdf: adding pages from 182-kfo.pdf
-qpdf: adding pages from 183-kfo.pdf
-qpdf: adding pages from 184-kfo.pdf
-qpdf: adding pages from 185-kfo.pdf
-qpdf: adding pages from 186-kfo.pdf
-qpdf: adding pages from 187-kfo.pdf
-qpdf: adding pages from 188-kfo.pdf
-qpdf: adding pages from 189-kfo.pdf
-qpdf: adding pages from 190-kfo.pdf
-qpdf: adding pages from 191-kfo.pdf
-qpdf: adding pages from 192-kfo.pdf
-qpdf: adding pages from 193-kfo.pdf
-qpdf: adding pages from 194-kfo.pdf
-qpdf: adding pages from 195-kfo.pdf
-qpdf: adding pages from 196-kfo.pdf
-qpdf: adding pages from 197-kfo.pdf
-qpdf: adding pages from 198-kfo.pdf
-qpdf: adding pages from 199-kfo.pdf
-qpdf: adding pages from 200-kfo.pdf
-qpdf: adding pages from 201-kfo.pdf
qpdf: wrote file a.pdf
diff -Nru qpdf-8.4.0/qpdf/qtest/qpdf/enable-kfo.out qpdf-8.4.2/qpdf/qtest/qpdf/enable-kfo.out
--- qpdf-8.4.0/qpdf/qtest/qpdf/enable-kfo.out 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/qpdf/qtest/qpdf/enable-kfo.out 2019-05-18 09:00:08.000000000 -0400
@@ -1,203 +1,23 @@
qpdf: selecting --keep-open-files=y
-qpdf: processing 100-kfo.pdf
-qpdf: processing 101-kfo.pdf
-qpdf: processing 102-kfo.pdf
-qpdf: processing 103-kfo.pdf
-qpdf: processing 104-kfo.pdf
-qpdf: processing 105-kfo.pdf
-qpdf: processing 106-kfo.pdf
-qpdf: processing 107-kfo.pdf
-qpdf: processing 108-kfo.pdf
-qpdf: processing 109-kfo.pdf
-qpdf: processing 110-kfo.pdf
-qpdf: processing 111-kfo.pdf
-qpdf: processing 112-kfo.pdf
-qpdf: processing 113-kfo.pdf
-qpdf: processing 114-kfo.pdf
-qpdf: processing 115-kfo.pdf
-qpdf: processing 116-kfo.pdf
-qpdf: processing 117-kfo.pdf
-qpdf: processing 118-kfo.pdf
-qpdf: processing 119-kfo.pdf
-qpdf: processing 120-kfo.pdf
-qpdf: processing 121-kfo.pdf
-qpdf: processing 122-kfo.pdf
-qpdf: processing 123-kfo.pdf
-qpdf: processing 124-kfo.pdf
-qpdf: processing 125-kfo.pdf
-qpdf: processing 126-kfo.pdf
-qpdf: processing 127-kfo.pdf
-qpdf: processing 128-kfo.pdf
-qpdf: processing 129-kfo.pdf
-qpdf: processing 130-kfo.pdf
-qpdf: processing 131-kfo.pdf
-qpdf: processing 132-kfo.pdf
-qpdf: processing 133-kfo.pdf
-qpdf: processing 134-kfo.pdf
-qpdf: processing 135-kfo.pdf
-qpdf: processing 136-kfo.pdf
-qpdf: processing 137-kfo.pdf
-qpdf: processing 138-kfo.pdf
-qpdf: processing 139-kfo.pdf
-qpdf: processing 140-kfo.pdf
-qpdf: processing 141-kfo.pdf
-qpdf: processing 142-kfo.pdf
-qpdf: processing 143-kfo.pdf
-qpdf: processing 144-kfo.pdf
-qpdf: processing 145-kfo.pdf
-qpdf: processing 146-kfo.pdf
-qpdf: processing 147-kfo.pdf
-qpdf: processing 148-kfo.pdf
-qpdf: processing 149-kfo.pdf
-qpdf: processing 150-kfo.pdf
-qpdf: processing 151-kfo.pdf
-qpdf: processing 152-kfo.pdf
-qpdf: processing 153-kfo.pdf
-qpdf: processing 154-kfo.pdf
-qpdf: processing 155-kfo.pdf
-qpdf: processing 156-kfo.pdf
-qpdf: processing 157-kfo.pdf
-qpdf: processing 158-kfo.pdf
-qpdf: processing 159-kfo.pdf
-qpdf: processing 160-kfo.pdf
-qpdf: processing 161-kfo.pdf
-qpdf: processing 162-kfo.pdf
-qpdf: processing 163-kfo.pdf
-qpdf: processing 164-kfo.pdf
-qpdf: processing 165-kfo.pdf
-qpdf: processing 166-kfo.pdf
-qpdf: processing 167-kfo.pdf
-qpdf: processing 168-kfo.pdf
-qpdf: processing 169-kfo.pdf
-qpdf: processing 170-kfo.pdf
-qpdf: processing 171-kfo.pdf
-qpdf: processing 172-kfo.pdf
-qpdf: processing 173-kfo.pdf
-qpdf: processing 174-kfo.pdf
-qpdf: processing 175-kfo.pdf
-qpdf: processing 176-kfo.pdf
-qpdf: processing 177-kfo.pdf
-qpdf: processing 178-kfo.pdf
-qpdf: processing 179-kfo.pdf
-qpdf: processing 180-kfo.pdf
-qpdf: processing 181-kfo.pdf
-qpdf: processing 182-kfo.pdf
-qpdf: processing 183-kfo.pdf
-qpdf: processing 184-kfo.pdf
-qpdf: processing 185-kfo.pdf
-qpdf: processing 186-kfo.pdf
-qpdf: processing 187-kfo.pdf
-qpdf: processing 188-kfo.pdf
-qpdf: processing 189-kfo.pdf
-qpdf: processing 190-kfo.pdf
-qpdf: processing 191-kfo.pdf
-qpdf: processing 192-kfo.pdf
-qpdf: processing 193-kfo.pdf
-qpdf: processing 194-kfo.pdf
-qpdf: processing 195-kfo.pdf
-qpdf: processing 196-kfo.pdf
-qpdf: processing 197-kfo.pdf
-qpdf: processing 198-kfo.pdf
-qpdf: processing 199-kfo.pdf
+qpdf: processing 010-kfo.pdf
+qpdf: processing 011-kfo.pdf
+qpdf: processing 012-kfo.pdf
+qpdf: processing 013-kfo.pdf
+qpdf: processing 014-kfo.pdf
+qpdf: processing 015-kfo.pdf
+qpdf: processing 016-kfo.pdf
+qpdf: processing 017-kfo.pdf
+qpdf: processing 018-kfo.pdf
+qpdf: processing 019-kfo.pdf
qpdf: removing unreferenced pages from primary input
-qpdf: adding pages from 100-kfo.pdf
-qpdf: adding pages from 101-kfo.pdf
-qpdf: adding pages from 102-kfo.pdf
-qpdf: adding pages from 103-kfo.pdf
-qpdf: adding pages from 104-kfo.pdf
-qpdf: adding pages from 105-kfo.pdf
-qpdf: adding pages from 106-kfo.pdf
-qpdf: adding pages from 107-kfo.pdf
-qpdf: adding pages from 108-kfo.pdf
-qpdf: adding pages from 109-kfo.pdf
-qpdf: adding pages from 110-kfo.pdf
-qpdf: adding pages from 111-kfo.pdf
-qpdf: adding pages from 112-kfo.pdf
-qpdf: adding pages from 113-kfo.pdf
-qpdf: adding pages from 114-kfo.pdf
-qpdf: adding pages from 115-kfo.pdf
-qpdf: adding pages from 116-kfo.pdf
-qpdf: adding pages from 117-kfo.pdf
-qpdf: adding pages from 118-kfo.pdf
-qpdf: adding pages from 119-kfo.pdf
-qpdf: adding pages from 120-kfo.pdf
-qpdf: adding pages from 121-kfo.pdf
-qpdf: adding pages from 122-kfo.pdf
-qpdf: adding pages from 123-kfo.pdf
-qpdf: adding pages from 124-kfo.pdf
-qpdf: adding pages from 125-kfo.pdf
-qpdf: adding pages from 126-kfo.pdf
-qpdf: adding pages from 127-kfo.pdf
-qpdf: adding pages from 128-kfo.pdf
-qpdf: adding pages from 129-kfo.pdf
-qpdf: adding pages from 130-kfo.pdf
-qpdf: adding pages from 131-kfo.pdf
-qpdf: adding pages from 132-kfo.pdf
-qpdf: adding pages from 133-kfo.pdf
-qpdf: adding pages from 134-kfo.pdf
-qpdf: adding pages from 135-kfo.pdf
-qpdf: adding pages from 136-kfo.pdf
-qpdf: adding pages from 137-kfo.pdf
-qpdf: adding pages from 138-kfo.pdf
-qpdf: adding pages from 139-kfo.pdf
-qpdf: adding pages from 140-kfo.pdf
-qpdf: adding pages from 141-kfo.pdf
-qpdf: adding pages from 142-kfo.pdf
-qpdf: adding pages from 143-kfo.pdf
-qpdf: adding pages from 144-kfo.pdf
-qpdf: adding pages from 145-kfo.pdf
-qpdf: adding pages from 146-kfo.pdf
-qpdf: adding pages from 147-kfo.pdf
-qpdf: adding pages from 148-kfo.pdf
-qpdf: adding pages from 149-kfo.pdf
-qpdf: adding pages from 150-kfo.pdf
-qpdf: adding pages from 151-kfo.pdf
-qpdf: adding pages from 152-kfo.pdf
-qpdf: adding pages from 153-kfo.pdf
-qpdf: adding pages from 154-kfo.pdf
-qpdf: adding pages from 155-kfo.pdf
-qpdf: adding pages from 156-kfo.pdf
-qpdf: adding pages from 157-kfo.pdf
-qpdf: adding pages from 158-kfo.pdf
-qpdf: adding pages from 159-kfo.pdf
-qpdf: adding pages from 160-kfo.pdf
-qpdf: adding pages from 161-kfo.pdf
-qpdf: adding pages from 162-kfo.pdf
-qpdf: adding pages from 163-kfo.pdf
-qpdf: adding pages from 164-kfo.pdf
-qpdf: adding pages from 165-kfo.pdf
-qpdf: adding pages from 166-kfo.pdf
-qpdf: adding pages from 167-kfo.pdf
-qpdf: adding pages from 168-kfo.pdf
-qpdf: adding pages from 169-kfo.pdf
-qpdf: adding pages from 170-kfo.pdf
-qpdf: adding pages from 171-kfo.pdf
-qpdf: adding pages from 172-kfo.pdf
-qpdf: adding pages from 173-kfo.pdf
-qpdf: adding pages from 174-kfo.pdf
-qpdf: adding pages from 175-kfo.pdf
-qpdf: adding pages from 176-kfo.pdf
-qpdf: adding pages from 177-kfo.pdf
-qpdf: adding pages from 178-kfo.pdf
-qpdf: adding pages from 179-kfo.pdf
-qpdf: adding pages from 180-kfo.pdf
-qpdf: adding pages from 181-kfo.pdf
-qpdf: adding pages from 182-kfo.pdf
-qpdf: adding pages from 183-kfo.pdf
-qpdf: adding pages from 184-kfo.pdf
-qpdf: adding pages from 185-kfo.pdf
-qpdf: adding pages from 186-kfo.pdf
-qpdf: adding pages from 187-kfo.pdf
-qpdf: adding pages from 188-kfo.pdf
-qpdf: adding pages from 189-kfo.pdf
-qpdf: adding pages from 190-kfo.pdf
-qpdf: adding pages from 191-kfo.pdf
-qpdf: adding pages from 192-kfo.pdf
-qpdf: adding pages from 193-kfo.pdf
-qpdf: adding pages from 194-kfo.pdf
-qpdf: adding pages from 195-kfo.pdf
-qpdf: adding pages from 196-kfo.pdf
-qpdf: adding pages from 197-kfo.pdf
-qpdf: adding pages from 198-kfo.pdf
-qpdf: adding pages from 199-kfo.pdf
+qpdf: adding pages from 010-kfo.pdf
+qpdf: adding pages from 011-kfo.pdf
+qpdf: adding pages from 012-kfo.pdf
+qpdf: adding pages from 013-kfo.pdf
+qpdf: adding pages from 014-kfo.pdf
+qpdf: adding pages from 015-kfo.pdf
+qpdf: adding pages from 016-kfo.pdf
+qpdf: adding pages from 017-kfo.pdf
+qpdf: adding pages from 018-kfo.pdf
+qpdf: adding pages from 019-kfo.pdf
qpdf: wrote file a.pdf
diff -Nru qpdf-8.4.0/qpdf/qtest/qpdf/exceptions.out qpdf-8.4.2/qpdf/qtest/qpdf/exceptions.out
--- qpdf-8.4.0/qpdf/qtest/qpdf/exceptions.out 1969-12-31 19:00:00.000000000 -0500
+++ qpdf-8.4.2/qpdf/qtest/qpdf/exceptions.out 2019-05-18 09:00:08.000000000 -0400
@@ -0,0 +1,5 @@
+Caught QPDFExc as expected
+Caught QPDFSystemError as expected
+Caught logic_error as expected
+Caught runtime_error as expected
+test 61 done
Binary files /tmp/_vHMae8e6Y/qpdf-8.4.0/qpdf/qtest/qpdf/remove-labels.pdf and /tmp/83GJmS7ZTn/qpdf-8.4.2/qpdf/qtest/qpdf/remove-labels.pdf differ
diff -Nru qpdf-8.4.0/qpdf/qtest/qpdf.test qpdf-8.4.2/qpdf/qtest/qpdf.test
--- qpdf-8.4.0/qpdf/qtest/qpdf.test 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/qpdf/qtest/qpdf.test 2019-05-18 09:00:08.000000000 -0400
@@ -170,6 +170,27 @@
show_ntests();
# ----------
+$td->notify("--- Unicode Filenames ---");
+$n_tests += 3;
+
+$td->runtest("create unicode filenames",
+ {$td->COMMAND => "test_unicode_filenames"},
+ {$td->STRING => "created Unicode filenames\n",
+ $td->EXIT_STATUS => 0},
+ $td->NORMALIZE_NEWLINES);
+
+foreach my $d (['auto-ü', 1], ['auto-öπ', 2])
+{
+ my ($u, $n) = @$d;
+ $td->runtest("unicode filename $u",
+ {$td->COMMAND => "qpdf --check $u.pdf"},
+ {$td->FILE => "check-unicode-filename-$n.out",
+ $td->EXIT_STATUS => 0},
+ $td->NORMALIZE_NEWLINES);
+}
+
+show_ntests();
+# ----------
$td->notify("--- Final Version ---");
$n_tests += 1;
@@ -180,6 +201,16 @@
show_ntests();
# ----------
+$td->notify("--- Exceptions ---");
+$n_tests += 1;
+
+$td->runtest("check exception handling",
+ {$td->COMMAND => "test_driver 61 -"},
+ {$td->FILE => "exceptions.out", $td->EXIT_STATUS => 0},
+ $td->NORMALIZE_NEWLINES);
+
+show_ntests();
+# ----------
$td->notify("--- Dangling Refs ---");
my @dangling = (qw(minimal dangling-refs));
$n_tests += 2 * scalar(@dangling);
@@ -647,7 +678,7 @@
$td->runtest("qpdf version",
{$td->COMMAND => "qpdf --version"},
- {$td->REGEXP => "qpdf version \\S+\n.*", $td->EXIT_STATUS => 0},
+ {$td->REGEXP => ".*qpdf version \\S+\n.*", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("qpdf copyright contains version too",
{$td->COMMAND => "qpdf --copyright"},
@@ -757,8 +788,6 @@
compare_pdfs("$file.pdf", "a.pdf");
}
-# QXXXQ externalize tests with min size
-
show_ntests();
# ----------
$td->notify("--- Tokenizer ---");
@@ -1584,6 +1613,8 @@
{$td->FILE => "labels-split-$i.pdf"});
}
+# See comments in TODO about these expected failures. Search for
+# "split page with outlines".
$td->runtest("split page with outlines",
{$td->COMMAND => "qpdf --qdf --static-id --split-pages=10".
" outlines-with-actions.pdf split-out-outlines.pdf"},
@@ -1592,7 +1623,8 @@
{
$td->runtest("check output ($i)",
{$td->FILE => "split-out-outlines-$i.pdf"},
- {$td->FILE => "outlines-split-$i.pdf"});
+ {$td->FILE => "outlines-split-$i.pdf"},
+ $td->EXPECT_FAILURE)
}
foreach my $d (@sp_cases)
@@ -1662,23 +1694,25 @@
binmode F;
my $content = <F>;
close(F);
- for (my $i = 1; $i <= 201; ++$i)
+ for (my $i = 1; $i <= 51; ++$i)
{
open(F, sprintf(">%03d-kfo.pdf", $i)) or die;
+ binmode F;
print F $content;
close(F);
}
}
-$td->runtest("disable keep files open",
+$td->runtest("automatic disable keep files open",
{$td->COMMAND =>
"qpdf --verbose --static-id --empty" .
+ " --keep-files-open-threshold=50" .
" --pages *kfo.pdf -- a.pdf"},
{$td->FILE => "disable-kfo.out", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("don't disable keep files open",
{$td->COMMAND =>
"qpdf --verbose --static-id --empty" .
- " --pages 1*kfo.pdf -- a.pdf"},
+ " --pages 01*kfo.pdf -- a.pdf"},
{$td->FILE => "enable-kfo.out", $td->EXIT_STATUS => 0},
$td->NORMALIZE_NEWLINES);
$td->runtest("explict keep files open",
@@ -1852,7 +1886,7 @@
show_ntests();
# ----------
$td->notify("--- Merging and Splitting ---");
-$n_tests += 22;
+$n_tests += 24;
# Select pages from the same file multiple times including selecting
# twice from an encrypted file and specifying the password only the
@@ -1919,6 +1953,18 @@
$td->runtest("check output",
{$td->FILE => "a.pdf"},
{$td->FILE => "merge-multiple-labels.pdf"});
+$td->runtest("remove labels",
+ {$td->COMMAND =>
+ "qpdf --empty a.pdf" .
+ " --remove-page-labels" .
+ " --pages 11-pages-with-labels.pdf 8-11" .
+ " minimal.pdf " .
+ " page-labels-and-outlines.pdf 17-19 --" .
+ " --static-id"},
+ {$td->STRING => "", $td->EXIT_STATUS => 0});
+$td->runtest("check output",
+ {$td->FILE => "a.pdf"},
+ {$td->FILE => "remove-labels.pdf"});
$td->runtest("split with shared resources",
{$td->COMMAND =>
@@ -4079,5 +4125,5 @@
sub cleanup
{
system("rm -rf *.ps *.pnm ?.pdf ?.qdf *.enc* tif1 tif2 tiff-cache");
- system("rm -rf *split-out* ???-kfo.pdf *.tmpout \@file.pdf");
+ system("rm -rf *split-out* ???-kfo.pdf *.tmpout \@file.pdf auto-*.pdf");
}
diff -Nru qpdf-8.4.0/qpdf/test_driver.cc qpdf-8.4.2/qpdf/test_driver.cc
--- qpdf-8.4.0/qpdf/test_driver.cc 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/qpdf/test_driver.cc 2019-05-18 09:00:08.000000000 -0400
@@ -16,6 +16,7 @@
#include <qpdf/Pl_Buffer.hh>
#include <qpdf/Pl_Flate.hh>
#include <qpdf/QPDFWriter.hh>
+#include <qpdf/QPDFSystemError.hh>
#include <iostream>
#include <sstream>
#include <algorithm>
@@ -269,6 +270,10 @@
pdf.processMemoryFile((std::string(filename1) + ".pdf").c_str(),
p, size);
}
+ else if (n == 61)
+ {
+ // Ignore filename argument entirely
+ }
else if (n % 2 == 0)
{
if (n % 4 == 0)
@@ -1626,7 +1631,7 @@
QPDFFormFieldObjectHelper parent(node.getParent());
std::cout << " Parent: "
<< (parent.isNull()
- ? "none"
+ ? std::string("none")
: parent.getObjectHandle().unparse())
<< std::endl;
node = parent;
@@ -2046,6 +2051,45 @@
w.setStaticID(true);
w.write();
}
+ else if (n == 61)
+ {
+ // Test to make sure exceptions can be caught properly across
+ // shared library boundaries.
+ pdf.setAttemptRecovery(false);
+ pdf.setSuppressWarnings(true);
+ try
+ {
+ pdf.processMemoryFile("empty", "", 0);
+ }
+ catch (QPDFExc& e)
+ {
+ std::cout << "Caught QPDFExc as expected" << std::endl;
+ }
+ try
+ {
+ QUtil::safe_fopen("/does/not/exist", "r");
+ }
+ catch (QPDFSystemError& e)
+ {
+ std::cout << "Caught QPDFSystemError as expected" << std::endl;
+ }
+ try
+ {
+ QUtil::int_to_string_base(0, 12);
+ }
+ catch (std::logic_error& e)
+ {
+ std::cout << "Caught logic_error as expected" << std::endl;
+ }
+ try
+ {
+ QUtil::toUTF8(0xffffffff);
+ }
+ catch (std::runtime_error& e)
+ {
+ std::cout << "Caught runtime_error as expected" << std::endl;
+ }
+ }
else
{
throw std::runtime_error(std::string("invalid test ") +
diff -Nru qpdf-8.4.0/qpdf/test_unicode_filenames.cc qpdf-8.4.2/qpdf/test_unicode_filenames.cc
--- qpdf-8.4.0/qpdf/test_unicode_filenames.cc 1969-12-31 19:00:00.000000000 -0500
+++ qpdf-8.4.2/qpdf/test_unicode_filenames.cc 2019-05-18 09:00:08.000000000 -0400
@@ -0,0 +1,81 @@
+#ifdef _WIN32
+#include <windows.h>
+#include <direct.h>
+#include <io.h>
+#endif
+
+#include <iostream>
+#include <stdlib.h>
+#include <stdio.h>
+
+static void do_copy(FILE* in, FILE* out)
+{
+ if ((in == 0) || (out == 0))
+ {
+ std::cerr << "errors opening files" << std::endl;
+ exit(2);
+ }
+ char buf[10240];
+ size_t len = 0;
+ while ((len = fread(buf, 1, sizeof(buf), in)) > 0)
+ {
+ fwrite(buf, 1, len, out);
+ }
+ if (len != 0)
+ {
+ std::cerr << "errors reading or writing" << std::endl;
+ exit(2);
+ }
+ fclose(in);
+ fclose(out);
+}
+
+#ifdef WINDOWS_WMAIN
+
+void copy(wchar_t const* outname)
+{
+#ifdef _MSC_VER
+ FILE* in = 0;
+ _wfopen_s(&in, L"minimal.pdf", L"rb");
+ FILE* out = 0;
+ _wfopen_s(&out, outname, L"wb");
+#else
+ FILE* in = _wfopen(L"minimal.pdf", L"rb");
+ FILE* out = _wfopen(outname, L"wb");
+#endif
+ do_copy(in, out);
+}
+
+extern "C"
+int wmain(int argc, wchar_t* argv[])
+{
+ // Unicode
+ wchar_t const* f1 = L"auto-\xfc.pdf";
+ wchar_t const* f2 = L"auto-\xf6\x03c0.pdf";
+ copy(f1);
+ copy(f2);
+ std::cout << "created Unicode filenames" << std::endl;
+ return 0;
+}
+
+#else
+
+void copy(char const* outname)
+{
+ FILE* in = fopen("minimal.pdf", "rb");
+ FILE* out = fopen(outname, "wb");
+ do_copy(in, out);
+}
+
+int main(int argc, char* argv[])
+{
+ // Explicit UTF-8 encoding
+ char const* f1 = "auto-\xc3\xbc.pdf";
+ char const* f2 = "auto-\xc3\xb6\xcf\x80.pdf";
+ copy(f1);
+ copy(f2);
+ std::cout << "created Unicode filenames" << std::endl;
+ return 0;
+}
+
+#endif
diff -Nru qpdf-8.4.0/README-maintainer qpdf-8.4.2/README-maintainer
--- qpdf-8.4.0/README-maintainer 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/README-maintainer 2019-05-18 09:00:08.000000000 -0400
@@ -103,6 +103,7 @@
* configure.ac
* libqpdf/QPDF.cc
* manual/qpdf-manual.xml
+ * qpdf/qpdf.cc
`make_dist` verifies this consistency.
* Add a release entry to ChangeLog.
@@ -129,7 +130,7 @@
\rm -f *.{md5,sha1,sha512}
files=(*)
for i in md5 sha1 sha512; do
- ${i}sum $files >| qpdf-$version.$i
+ ${i}sum ${files[*]} >| qpdf-$version.$i
gpg --clearsign --armor qpdf-$version.$i
mv qpdf-$version.$i.asc qpdf-$version.$i
done
@@ -157,7 +158,7 @@
# Create release
TOKEN=$(cat ~/.github-token)
-function gcurl() { curl -H "Authorization: token $TOKEN" ${1+"$@"} }
+function gcurl() { curl -H "Authorization: token $TOKEN" ${1+"$@"}; }
url=$(gcurl -s -XPOST https://api.github.com/repos/qpdf/qpdf/releases -d'{"tag_name": "release-qpdf-'$version'", "name": "qpdf '$version'", "draft": true}' | jq -r '.url')
# Get upload url
diff -Nru qpdf-8.4.0/README.md qpdf-8.4.2/README.md
--- qpdf-8.4.0/README.md 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/README.md 2019-05-18 09:00:08.000000000 -0400
@@ -7,6 +7,12 @@
This is the QPDF package. Information about it can be found at http://qpdf.sourceforge.net. The source code repository is hosted at github: https://github.com/qpdf/qpdf.
+# Verifying Distributions
+
+The public key used to sign qpdf source distributions has fingerprint `C2C9 6B10 011F E009 E6D1 DF82 8A75 D109 9801 2C7E` and can be found at https://q.ql.org/pubkey.asc or downloaded from a public key server.
+
+# Copyright, License
+
QPDF is copyright (c) 2005-2019 Jay Berkenbilt
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
diff -Nru qpdf-8.4.0/TODO qpdf-8.4.2/TODO
--- qpdf-8.4.0/TODO 2019-02-02 09:00:50.000000000 -0500
+++ qpdf-8.4.2/TODO 2019-05-18 09:00:08.000000000 -0400
@@ -3,6 +3,10 @@
* Set up OSS-Fuzz (Google). See starred email in qpdf label.
+ * Investigate whether there is a way to automate the memory checker
+ tests for Windows, and consider running the memory checks in the
+ automated test pipeline.
+
Next ABI
========
@@ -22,6 +26,15 @@
* Remove version of QPDFTokenizer::expectInlineImage with no
arguments.
+ * Consider whether to build with -fvisibility=hidden by default. See
+ #302 for discussion.
+
+ * Consider dealing with integer sizes in the API. Build with
+ -Wconversion -Wsign-conversion to see warnings. We won't be able to
+ resolve all, but we can possibly convert some things from int to
+ either size_t or qpdf_offset_t. Only do this if it doesn't break
+ source compatibility.
+
Lexical
=======
@@ -62,6 +75,17 @@
* make sure conflicting named destinations work possibly test by
including the same file by two paths in a merge
+ Note: original implementation of bookmark preservation for split
+ pages caused a very high performance hit. The problem was
+ introduced in 313ba081265f69ac9a0324f9fe87087c72918191 and reverted
+ in the commit that adds this paragraph. The revert includes marking
+ a few tests cases as $td->EXPECT_FAILURE. When properly coded, the
+ test cases will need to be adjusted to only include the parts of
+ the outlines that are actually copied. The tests in question are
+ "split page with outlines". When implementing properly, ensure that
+ the performance is not adversely affected by timing split-pages on
+ a large file with complex outlines such as the PDF specification.
+
When pruning outlines, keep all outlines in the hierarchy that are
above an outline for a page we care about. If one of the ancestor
outlines points to a non-existent page, clear its dest. If an
@@ -144,6 +168,14 @@
* Pl_TIFFPredictor is pretty slow.
+ * Support for handling file names with Unicode characters in Windows
+ is incomplete. qpdf seems to support them okay from a functionality
+ standpoint, and the right thing happens if you pass in UTF-8
+ encoded filenames to QPDF library routines in Windows (they are
+ converted internally to wchar_t*), but file names are encoded in
+ UTF-8 on output, which doesn't produce nice error messages or
+ output on Windows in some cases.
+
* If we ever wanted to do anything more with character encoding, see
../misc/character-encoding/, which includes machine-readable dump
of table D.2 in the ISO-32000 PDF spec. This shows the mapping
----------------------------------------------------------------------
unblock qpdf/8.4.0-2
Reply to: