diff -Nru qpdf-7.0~b1/ChangeLog qpdf-7.0.0/ChangeLog --- qpdf-7.0~b1/ChangeLog 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/ChangeLog 2017-09-16 17:22:15.000000000 +0000 @@ -1,3 +1,39 @@ +2017-09-15 Jay Berkenbilt + + * 7.0.0: release + +2017-09-12 Jay Berkenbilt + + * Relicense qpdf under version 2.0 of the Apache License rather + than version 2.0 of the Artistic License. Both are fine, but the + Apache License is in more widespread use, and I like it a little + better than Artistic-2.0. It is my intention that there be no + change in what you can or can't do with qpdf. Versions of qpdf + prior to version 7 were released under the terms of version 2.0 of + the Artistic License. At your option, you may continue to consider + qpdf to be licensed under those terms. Please see the manual for + additional information. + + * Improve the error message that is issued when QPDFWriter + encounters a stream that can't be decoded. In particular, mention + that the stream will be copied without filtering to avoid data + loss. + + * Add new methods to the C API to correspond to new additions to + QPDFWriter: + - qpdf_set_compress_streams + - qpdf_set_decode_level + - qpdf_set_preserve_unreferenced_objects + - qpdf_set_newline_before_endstream + +2017-08-25 Jay Berkenbilt + + * Re-implement parser iteratively to avoid stack overflow on very + deeply nested arrays and dictionaries. Fixes #146. + + * Detect infinite loop while finding additional xref tables. Fixes + #149. + 2017-08-22 Jay Berkenbilt * 7.0.b1: release diff -Nru qpdf-7.0~b1/configure qpdf-7.0.0/configure --- qpdf-7.0~b1/configure 2017-08-22 20:51:11.000000000 +0000 +++ qpdf-7.0.0/configure 2017-09-16 17:23:22.000000000 +0000 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for qpdf 7.0.b1. +# Generated by GNU Autoconf 2.69 for qpdf 7.0.0. # # # 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='7.0.b1' -PACKAGE_STRING='qpdf 7.0.b1' +PACKAGE_VERSION='7.0.0' +PACKAGE_STRING='qpdf 7.0.0' PACKAGE_BUGREPORT='' PACKAGE_URL='' @@ -1330,7 +1330,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 7.0.b1 to adapt to many kinds of systems. +\`configure' configures qpdf 7.0.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1396,7 +1396,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of qpdf 7.0.b1:";; + short | recursive ) echo "Configuration of qpdf 7.0.0:";; esac cat <<\_ACEOF @@ -1542,7 +1542,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -qpdf configure 7.0.b1 +qpdf configure 7.0.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2082,7 +2082,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 7.0.b1, which was +It was created by qpdf $as_me 7.0.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -15457,9 +15457,9 @@ # * Otherwise, increment LT_REVISION # LT = libtool -LT_CURRENT=18 +LT_CURRENT=19 +LT_AGE=1 LT_REVISION=0 -LT_AGE=0 @@ -17266,7 +17266,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 7.0.b1, which was +This file was extended by qpdf $as_me 7.0.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -17332,7 +17332,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 7.0.b1 +qpdf config.status 7.0.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -Nru qpdf-7.0~b1/configure.ac qpdf-7.0.0/configure.ac --- qpdf-7.0~b1/configure.ac 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/configure.ac 2017-09-16 17:22:15.000000000 +0000 @@ -2,7 +2,7 @@ dnl This config.in requires autoconf 2.5 or greater. AC_PREREQ([2.68]) -AC_INIT([qpdf],[7.0.b1]) +AC_INIT([qpdf],[7.0.0]) AC_CONFIG_MACRO_DIR([m4]) AC_CONFIG_FILES([autoconf.mk]) @@ -29,9 +29,9 @@ # * Otherwise, increment LT_REVISION # LT = libtool -LT_CURRENT=18 +LT_CURRENT=19 +LT_AGE=1 LT_REVISION=0 -LT_AGE=0 AC_SUBST(LT_CURRENT) AC_SUBST(LT_REVISION) AC_SUBST(LT_AGE) diff -Nru qpdf-7.0~b1/debian/changelog qpdf-7.0.0/debian/changelog --- qpdf-7.0~b1/debian/changelog 2017-08-25 01:40:57.000000000 +0000 +++ qpdf-7.0.0/debian/changelog 2017-09-16 03:12:59.000000000 +0000 @@ -1,3 +1,9 @@ +qpdf (7.0.0-1) unstable; urgency=medium + + * New upstream release. + + -- Jay Berkenbilt Fri, 15 Sep 2017 23:12:59 -0400 + qpdf (7.0~b1-3) experimental; urgency=medium * Redo debian rules to use dh over cdbs. diff -Nru qpdf-7.0~b1/debian/copyright qpdf-7.0.0/debian/copyright --- qpdf-7.0~b1/debian/copyright 2017-08-25 01:40:57.000000000 +0000 +++ qpdf-7.0.0/debian/copyright 2017-09-16 03:12:59.000000000 +0000 @@ -64,12 +64,41 @@ documentation and/or software. ---------------------------------------------------------------------- +QPDF embeds a copy of qtest (http://qtest.qbilt.org), which has the +same author as qpdf. qtest has the following copyright: + +Copyright 1993-2007, Jay Berkenbilt + +QTest is distributed under the terms of version 2.0 of the Artistic +license, which may be found at +https://opensource.org/licenses/Artistic-2.0 and which also appears +below. + +---------------------------------------------------------------------- + For everything else, the following copyright applies: Copyright (C) 2005-2017 Jay Berkenbilt -This software is distributed under the terms of version 2.0 of the -Artistic license, the text of which appears below. +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 + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Versions of qpdf prior to version 7 were released under the terms of +version 2.0 of the Artistic License. At your option, you may continue +to consider qpdf to be licensed under those terms. The text of the +Artistic License version 2.0 is included below. + +For the text of the Apache license version 2.0, see +/usr/share/common-licenses/Apache-2.0 ---------------------------------------------------------------------- diff -Nru qpdf-7.0~b1/doc/qpdf-manual.html qpdf-7.0.0/doc/qpdf-manual.html --- qpdf-7.0~b1/doc/qpdf-manual.html 2017-08-22 20:51:36.000000000 +0000 +++ qpdf-7.0.0/doc/qpdf-manual.html 2017-09-16 17:23:49.000000000 +0000 @@ -1,12 +1,30 @@ -QPDF Manual

QPDF Manual

For QPDF Version 7.0.b1, August 22, 2017

Jay Berkenbilt


General Information

+QPDF Manual

QPDF Manual

For QPDF Version 7.0.0, September 15, 2017

Jay Berkenbilt


General Information

QPDF is a program that does structural, content-preserving transformations on PDF files. QPDF's website is located at http://qpdf.sourceforge.net/. QPDF's source code is hosted on github at https://github.com/qpdf/qpdf.

- QPDF has been released under the terms of Version - 2.0 of the Artistic License, a copy of which appears in the - file Artistic-2.0 in the source distribution. + QPDF is licensed under the Apache + License, Version 2.0 (the "License"). Unless required by + applicable law or agreed to in writing, software distributed under + the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + OR CONDITIONS OF ANY KIND, either express or implied. See the + License for the specific language governing permissions and + limitations under the License. +

+ Versions of qpdf prior to version 7 were released under the terms + of the + Artistic License, version 2.0. At your option, you may + continue to consider qpdf to be licensed under those terms. The + Apache License 2.0 permits everything that the Artistic License 2.0 + permits but is slightly less restrictive. Allowing the Artistic + License to continue being used is primary to help people who may + have to get specific approval to use qpdf in their products. +

+ QPDF is intentionally released with a permissive license. However, + if there is some reason that the licensing terms don't work for + your requirements, please feel free to contact the copyright holder + to make other arrangements.

QPDF was originally created in 2001 and modified periodically between 2001 and 2005 during my employment at Apex CoVantage. Upon my @@ -72,8 +90,8 @@ -u.

  • A C++ compiler that works well with STL and has the long - long type. Most modern C++ compilers should fit the - bill fine. QPDF is tested with gcc and Microsoft Visual C++. + long type. Most modern C++ compilers should fit the bill + fine. QPDF is tested with gcc, clang, and Microsoft Visual C++.

  • Part of qpdf's test suite does comparisons of the contents PDF @@ -170,14 +188,16 @@ treated as a command-line argument. The @- option allows arguments to be read from standard input. This allows qpdf to be invoked with an arbitrary number of arbitrarily long - arguments. + arguments. It is also very useful for avoiding having to pass + passwords on the command line.

    outfilename does not have to be seekable, even when generating linearized files. Specifying - “--” as outfilename + “-” as outfilename means to write to standard output. However, you can't specify the same file as both the input and the output because qpdf reads data - from the input file as it writes to the output file. + from the input file as it writes to the output file. QPDF attempts + to detect this case and fail without overwriting the output file.

    Most options require an output file, but some testing or inspection commands do not. These are specifically noted. @@ -299,12 +319,11 @@ encoded in ISO-8859-1 and your terminal is configured to use UTF-8, the password you supply may not work properly. There are various approaches to handling this. For example, if you are - using Linux and have the iconv executable (part of the ICU - package) installed, you could pass --password=`echo - password | iconv -t - iso-8859-1` to qpdf where + using Linux and have the iconv executable installed, you could + pass --password=`echo password + | iconv -t iso-8859-1` to qpdf where password is a password specified in - your terminal's locale. A detailed discussion of this is out of + your terminal's locale. A detailed discussion of this is out of scope for this manual, but just be aware of this issue if you have trouble with a password that contains 8-bit characters.

    3.3. Encryption Options

    @@ -540,7 +559,10 @@ supported generalized filters: /LZWDecode, /FlateDecode, /ASCII85Decode, and - /ASCIIHexDecode + /ASCIIHexDecode. We define generalized + filters as those to be used for general-purpose compression + or encoding, as opposed to filters specifically designed + for image data.

  • specialized: in addition to generalized, decode streams with supported non-lossy specialized @@ -567,9 +589,9 @@ equivalent to --compress-streams=n --decode-level=none

  • - uncompress: uncompress stream data when - possible; equivalent to - --compress-streams=n + uncompress: uncompress stream data + compressed with generalized filters when possible; + equivalent to --compress-streams=n --decode-level=generalized

  • --normalize-content=[yn]

    @@ -671,16 +693,6 @@ results in smaller files. This behavior may also be explicitly requested with --stream-data=compress.

    - When --stream-data=preserve is specified, qpdf - will never attempt to change the filtering of any stream data. -

    - When --stream-data=uncompress is specified, qpdf - will attempt to remove any non-lossy filters that it supports. - This includes /FlateDecode, - /LZWDecode, /ASCII85Decode, - and /ASCIIHexDecode. This can be very useful - for inspecting the contents of various streams. -

    When --normalize-content=y is specified, qpdf will attempt to normalize whitespace and newlines in page content streams. This is generally safe but could, in some cases, cause @@ -827,7 +839,14 @@ conditions that --check detects. These are issued as warnings instead of errors. If qpdf finds no errors but finds warnings, it will exit with a status of 3 (as of - version 2.0.4). + version 2.0.4). When --check is combined + with other options, checks are always performed before any + other options are processed. For erroneous files, + --check will cause qpdf to attempt to + recover, after which other options are effectively operating + on the recovered file. Combining --check with + other options in this way can be useful for manually + recovering severely damaged files.

    The --raw-stream-data and @@ -1114,7 +1133,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. - [1] + [1] QPDF will allow recovery of a user password given an owner password. The input PDF file must be seekable. (Output files written by QPDFWriter need @@ -1601,7 +1620,7 @@ filter should write to whatever type of output is required. The QPDF class has an interface to write raw or filtered stream contents to a given pipeline. -





    [1] 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, @@ -1964,7 +1983,128 @@

    Appendix A. Release Notes

    For a detailed list of changes, please see the file ChangeLog in the source distribution. -

    6.0.0: November 10, 2015
    • +

      7.0.0: September 15, 2017
      • + Packaging and Distribution Changes +

        • + QPDF's primary license is now version 2.0 + of the Apache License rather than version 2.0 of the + Artistic License. You may still, at your option, consider + qpdf to be licensed with version 2.0 of the Artistic + license. +

        • + QPDF no longer has a dependency on the PCRE (Perl-Compatible + Regular Expression) library. QPDF now has an added + dependency on the JPEG library. +

      • + Bug Fixes +

        • + This release contains many bug fixes for various infinite + loops, memory leaks, and other memory errors that could be + encountered with specially crafted or otherwise erroneous + PDF files. +

      • + New Features +

        • + QPDF now supports reading and writing streams encoded with + JPEG or RunLength encoding. Library API enhancements and + command-line options have been added to control this + behavior. See command-line options + --compress-streams and + --decode-level and methods + QPDFWriter::setCompressStreams and + QPDFWriter::setDecodeLevel. +

        • + QPDF is much better at recovering from broken files. In most + cases, qpdf will skip invalid objects and will preserve + broken stream data by not attempting to filter broken + streams. QPDF is now able to recover or at least not crash + on dozens of broken test files I have received over the past + few years. +

        • + Page rotation is now supported and accessible from both the + library and the command line. +

        • + QPDFWriter supports writing files in + a way that preserves PCLm compliance in support of + driverless printing. This is very specialized and is only + useful to applications that already know how to create PCLm + files. +

      • + Enhancements to the qpdf Command-line Tool. + All new options listed here are documented in more detail in + Chapter 3, Running QPDF. +

        • + Command-line arguments can now be read from files or + standard input using @file or + @- syntax. Please see Section 3.1, “Basic Invocation”. +

        • + --rotate: request page rotation +

        • + --newline-before-endstream: ensure that a + newline appears before every endstream + keyword in the file; used to prevent qpdf from breaking + PDF/A compliance on already compliant files. +

        • + --preserve-unreferenced: preserve + unreferenced objects in the input PDF +

        • + --split-pages: break output into chunks + with fixed numbers of pages +

        • + --verbose: print the name of each output + file that is created +

        • + --compress-streams and + --decode-level replace + --stream-data for improving granularity of + controlling compression and decompression of stream data. + The --stream-data option will remain + available. +

        • + When running qpdf --check with other + options, checks are always run first. This enables qpdf to + perform its full recovery logic before outputting other + information. This can be especially useful when manually + recovering broken files, looking at qpdf's regenerated cross + reference table, or other similar operations. +

        • + Process --pages earlier so that other + options like --show-pages or + --split-pages can operate on the file after + page splitting/merging has occurred. +

      • + API Changes. All new API calls are documented in their + respective classes' header files. +

        • + QPDFObjectHandle::rotatePage: apply + rotation to a page object +

        • + QPDFWriter::setNewlineBeforeEndstream: + force newline to appear before endstream +

        • + QPDFWriter::setPreserveUnreferencedObjects: + preserve unreferenced objects that appear in the input PDF. + The default behavior is to discard them. +

        • + New Pipeline types + Pl_RunLength and + Pl_DCT are available for developers + who wish to produce or consume RunLength or DCT stream data + directly. The examples/pdf-create.cc + example illustrates their use. +

        • + QPDFWriter::setCompressStreams and + QPDFWriter::setDecodeLevel methods + control handling of different types of stream compression. +

        • + Add new C API functions + qpdf_set_compress_streams, + qpdf_set_decode_level, + qpdf_set_preserve_unreferenced_objects, + and qpdf_set_newline_before_endstream + corresponding to the new QPDFWriter + methods. +

      6.0.0: November 10, 2015
      • Implement --deterministic-id command-line option and QPDFWriter::setDeterministicID as well as C API function Binary files /tmp/tmpcoUyou/wZ0QBlPrkH/qpdf-7.0~b1/doc/qpdf-manual.pdf and /tmp/tmpcoUyou/_ONANmi6lb/qpdf-7.0.0/doc/qpdf-manual.pdf differ diff -Nru qpdf-7.0~b1/examples/pdf-parse-content.cc qpdf-7.0.0/examples/pdf-parse-content.cc --- qpdf-7.0~b1/examples/pdf-parse-content.cc 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/examples/pdf-parse-content.cc 2017-09-16 17:22:15.000000000 +0000 @@ -62,7 +62,7 @@ usage(); } char const* filename = argv[1]; - int pageno = atoi(argv[2]); + int pageno = QUtil::string_to_int(argv[2]); try { diff -Nru qpdf-7.0~b1/include/qpdf/Buffer.hh qpdf-7.0.0/include/qpdf/Buffer.hh --- qpdf-7.0~b1/include/qpdf/Buffer.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/Buffer.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __BUFFER_HH__ #define __BUFFER_HH__ diff -Nru qpdf-7.0~b1/include/qpdf/BufferInputSource.hh qpdf-7.0.0/include/qpdf/BufferInputSource.hh --- qpdf-7.0~b1/include/qpdf/BufferInputSource.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/BufferInputSource.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,10 +1,23 @@ -/* Copyright (c) 2005-2017 Jay Berkenbilt - * - * This file is part of qpdf. This software may be distributed under - * the terms of version 2 of the Artistic License which may be found - * in the source distribution. It is provided "as is" without express - * or implied warranty. - */ +// Copyright (c) 2005-2017 Jay Berkenbilt +// +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __QPDF_BUFFERINPUTSOURCE_HH__ #define __QPDF_BUFFERINPUTSOURCE_HH__ diff -Nru qpdf-7.0~b1/include/qpdf/Constants.h qpdf-7.0.0/include/qpdf/Constants.h --- qpdf-7.0~b1/include/qpdf/Constants.h 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/Constants.h 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ /* Copyright (c) 2005-2017 Jay Berkenbilt * - * This file is part of qpdf. This software may be distributed under - * the terms of version 2 of the Artistic License which may be found - * in the source distribution. It is provided "as is" without express - * or implied warranty. + * This file is part of qpdf. + * + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Versions of qpdf prior to version 7 were released under the terms + * of version 2.0 of the Artistic License. At your option, you may + * continue to consider qpdf to be licensed under those terms. Please + * see the manual for additional information. */ #ifndef __QPDFCONSTANTS_H__ diff -Nru qpdf-7.0~b1/include/qpdf/DLL.h qpdf-7.0.0/include/qpdf/DLL.h --- qpdf-7.0~b1/include/qpdf/DLL.h 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/DLL.h 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ /* Copyright (c) 2005-2017 Jay Berkenbilt * - * This file is part of qpdf. This software may be distributed under - * the terms of version 2 of the Artistic License which may be found - * in the source distribution. It is provided "as is" without express - * or implied warranty. + * This file is part of qpdf. + * + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Versions of qpdf prior to version 7 were released under the terms + * of version 2.0 of the Artistic License. At your option, you may + * continue to consider qpdf to be licensed under those terms. Please + * see the manual for additional information. */ #ifndef __QPDF_DLL_HH__ diff -Nru qpdf-7.0~b1/include/qpdf/FileInputSource.hh qpdf-7.0.0/include/qpdf/FileInputSource.hh --- qpdf-7.0~b1/include/qpdf/FileInputSource.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/FileInputSource.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,10 +1,23 @@ -/* Copyright (c) 2005-2017 Jay Berkenbilt - * - * This file is part of qpdf. This software may be distributed under - * the terms of version 2 of the Artistic License which may be found - * in the source distribution. It is provided "as is" without express - * or implied warranty. - */ +// Copyright (c) 2005-2017 Jay Berkenbilt +// +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __QPDF_FILEINPUTSOURCE_HH__ #define __QPDF_FILEINPUTSOURCE_HH__ diff -Nru qpdf-7.0~b1/include/qpdf/InputSource.hh qpdf-7.0.0/include/qpdf/InputSource.hh --- qpdf-7.0~b1/include/qpdf/InputSource.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/InputSource.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,10 +1,23 @@ -/* Copyright (c) 2005-2017 Jay Berkenbilt - * - * This file is part of qpdf. This software may be distributed under - * the terms of version 2 of the Artistic License which may be found - * in the source distribution. It is provided "as is" without express - * or implied warranty. - */ +// Copyright (c) 2005-2017 Jay Berkenbilt +// +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __QPDF_INPUTSOURCE_HH__ #define __QPDF_INPUTSOURCE_HH__ diff -Nru qpdf-7.0~b1/include/qpdf/Pipeline.hh qpdf-7.0.0/include/qpdf/Pipeline.hh --- qpdf-7.0~b1/include/qpdf/Pipeline.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/Pipeline.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. // Generalized Pipeline interface. By convention, subclasses of // Pipeline are called Pl_Something. diff -Nru qpdf-7.0~b1/include/qpdf/Pl_Buffer.hh qpdf-7.0.0/include/qpdf/Pl_Buffer.hh --- qpdf-7.0~b1/include/qpdf/Pl_Buffer.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/Pl_Buffer.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __PL_BUFFER_HH__ #define __PL_BUFFER_HH__ diff -Nru qpdf-7.0~b1/include/qpdf/Pl_Concatenate.hh qpdf-7.0.0/include/qpdf/Pl_Concatenate.hh --- qpdf-7.0~b1/include/qpdf/Pl_Concatenate.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/Pl_Concatenate.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,10 +1,23 @@ -/* Copyright (c) 2005-2017 Jay Berkenbilt - * - * This file is part of qpdf. This software may be distributed under - * the terms of version 2 of the Artistic License which may be found - * in the source distribution. It is provided "as is" without express - * or implied warranty. - */ +// Copyright (c) 2005-2017 Jay Berkenbilt +// +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __PL_CONCATENATE_HH__ #define __PL_CONCATENATE_HH__ diff -Nru qpdf-7.0~b1/include/qpdf/Pl_Count.hh qpdf-7.0.0/include/qpdf/Pl_Count.hh --- qpdf-7.0~b1/include/qpdf/Pl_Count.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/Pl_Count.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __PL_COUNT_HH__ #define __PL_COUNT_HH__ diff -Nru qpdf-7.0~b1/include/qpdf/Pl_DCT.hh qpdf-7.0.0/include/qpdf/Pl_DCT.hh --- qpdf-7.0~b1/include/qpdf/Pl_DCT.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/Pl_DCT.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __PL_DCT_HH__ #define __PL_DCT_HH__ @@ -49,8 +63,8 @@ virtual void finish(); private: - void compress(void* cinfo, PointerHolder); - void decompress(void* cinfo, PointerHolder); + void compress(void* cinfo, Buffer*); + void decompress(void* cinfo, Buffer*); enum action_e { a_compress, a_decompress }; diff -Nru qpdf-7.0~b1/include/qpdf/Pl_Discard.hh qpdf-7.0.0/include/qpdf/Pl_Discard.hh --- qpdf-7.0~b1/include/qpdf/Pl_Discard.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/Pl_Discard.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __PL_DISCARD_HH__ #define __PL_DISCARD_HH__ diff -Nru qpdf-7.0~b1/include/qpdf/Pl_Flate.hh qpdf-7.0.0/include/qpdf/Pl_Flate.hh --- qpdf-7.0~b1/include/qpdf/Pl_Flate.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/Pl_Flate.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __PL_FLATE_HH__ #define __PL_FLATE_HH__ diff -Nru qpdf-7.0~b1/include/qpdf/Pl_RunLength.hh qpdf-7.0.0/include/qpdf/Pl_RunLength.hh --- qpdf-7.0~b1/include/qpdf/Pl_RunLength.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/Pl_RunLength.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __PL_RUNLENGTH_HH__ #define __PL_RUNLENGTH_HH__ diff -Nru qpdf-7.0~b1/include/qpdf/Pl_StdioFile.hh qpdf-7.0.0/include/qpdf/Pl_StdioFile.hh --- qpdf-7.0~b1/include/qpdf/Pl_StdioFile.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/Pl_StdioFile.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. // End-of-line pipeline that simply writes its data to a stdio FILE* object. diff -Nru qpdf-7.0~b1/include/qpdf/PointerHolder.hh qpdf-7.0.0/include/qpdf/PointerHolder.hh --- qpdf-7.0~b1/include/qpdf/PointerHolder.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/PointerHolder.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __POINTERHOLDER_HH__ #define __POINTERHOLDER_HH__ diff -Nru qpdf-7.0~b1/include/qpdf/qpdf-c.h qpdf-7.0.0/include/qpdf/qpdf-c.h --- qpdf-7.0~b1/include/qpdf/qpdf-c.h 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/qpdf-c.h 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ /* Copyright (c) 2005-2017 Jay Berkenbilt * - * This file is part of qpdf. This software may be distributed under - * the terms of version 2 of the Artistic License which may be found - * in the source distribution. It is provided "as is" without express - * or implied warranty. + * This file is part of qpdf. + * + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Versions of qpdf prior to version 7 were released under the terms + * of version 2.0 of the Artistic License. At your option, you may + * continue to consider qpdf to be licensed under those terms. Please + * see the manual for additional information. */ #ifndef __QPDF_C_H__ @@ -319,6 +333,21 @@ enum qpdf_stream_data_e mode); QPDF_DLL + void qpdf_set_compress_streams(qpdf_data qpdf, QPDF_BOOL value); + + + QPDF_DLL + void qpdf_set_decode_level(qpdf_data qpdf, + enum qpdf_stream_decode_level_e level); + + QPDF_DLL + void qpdf_set_preserve_unreferenced_objects( + qpdf_data qpdf, QPDF_BOOL value); + + QPDF_DLL + void qpdf_set_newline_before_endstream(qpdf_data qpdf, QPDF_BOOL value); + + QPDF_DLL void qpdf_set_content_normalization(qpdf_data qpdf, QPDF_BOOL value); QPDF_DLL diff -Nru qpdf-7.0~b1/include/qpdf/QPDFExc.hh qpdf-7.0.0/include/qpdf/QPDFExc.hh --- qpdf-7.0~b1/include/qpdf/QPDFExc.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/QPDFExc.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __QPDFEXC_HH__ #define __QPDFEXC_HH__ diff -Nru qpdf-7.0~b1/include/qpdf/QPDF.hh qpdf-7.0.0/include/qpdf/QPDF.hh --- qpdf-7.0~b1/include/qpdf/QPDF.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/QPDF.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __QPDF_HH__ #define __QPDF_HH__ @@ -554,11 +568,13 @@ static bool pipeStreamData(QPDF* qpdf, int objid, int generation, qpdf_offset_t offset, size_t length, QPDFObjectHandle dict, - Pipeline* pipeline, bool suppress_warnings) + Pipeline* pipeline, + bool suppress_warnings, + bool will_retry) { return qpdf->pipeStreamData( objid, generation, offset, length, dict, pipeline, - suppress_warnings); + suppress_warnings, will_retry); } }; friend class Pipe; @@ -688,7 +704,8 @@ qpdf_offset_t offset, size_t length, QPDFObjectHandle dict, Pipeline* pipeline, - bool suppress_warnings); + bool suppress_warnings, + bool will_retry); // For QPDFWriter: diff -Nru qpdf-7.0~b1/include/qpdf/QPDFObjectHandle.hh qpdf-7.0.0/include/qpdf/QPDFObjectHandle.hh --- qpdf-7.0~b1/include/qpdf/QPDFObjectHandle.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/QPDFObjectHandle.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __QPDFOBJECTHANDLE_HH__ #define __QPDFOBJECTHANDLE_HH__ @@ -420,12 +434,21 @@ // configured filters. QPDFWriter handles this by attempting to // get the stream data without filtering, but callers should // consider a false return value when decode_level is not - // qpdf_dl_none to be a potential loss of data. + // qpdf_dl_none to be a potential loss of data. If you intend to + // retry in that case, pass true as the value of will_retry. This + // changes the warning issued by the library to indicate that the + // operation will be retried without filtering to avoid data loss. QPDF_DLL bool pipeStreamData(Pipeline*, unsigned long encode_flags, qpdf_stream_decode_level_e decode_level, bool suppress_warnings = false); + QPDF_DLL + bool pipeStreamData(Pipeline*, + unsigned long encode_flags, + qpdf_stream_decode_level_e decode_level, + bool suppress_warnings, + bool will_retry); // Legacy pipeStreamData. This maps to the the flags-based // pipeStreamData as follows: @@ -597,6 +620,7 @@ { friend class QPDF_Dictionary; friend class QPDF_Array; + friend class QPDF_Stream; private: static void releaseResolved(QPDFObjectHandle& o) { @@ -652,6 +676,16 @@ QPDFObjectHandle(QPDF*, int objid, int generation); QPDFObjectHandle(QPDFObject*); + enum parser_state_e + { + st_top, + st_start, + st_stop, + st_eof, + st_dictionary, + st_array + }; + // Private object factory methods static QPDFObjectHandle newIndirect(QPDF*, int objid, int generation); static QPDFObjectHandle newStream( @@ -667,7 +701,6 @@ std::string const& object_description, QPDFTokenizer& tokenizer, bool& empty, StringDecrypter* decrypter, QPDF* context, - bool in_array, bool in_dictionary, bool content_stream); static void parseContentStream_internal( PointerHolder stream_data, diff -Nru qpdf-7.0~b1/include/qpdf/QPDFObject.hh qpdf-7.0.0/include/qpdf/QPDFObject.hh --- qpdf-7.0~b1/include/qpdf/QPDFObject.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/QPDFObject.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __QPDFOBJECT_HH__ #define __QPDFOBJECT_HH__ diff -Nru qpdf-7.0~b1/include/qpdf/QPDFObjGen.hh qpdf-7.0.0/include/qpdf/QPDFObjGen.hh --- qpdf-7.0~b1/include/qpdf/QPDFObjGen.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/QPDFObjGen.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __QPDFOBJGEN_HH__ #define __QPDFOBJGEN_HH__ diff -Nru qpdf-7.0~b1/include/qpdf/QPDFTokenizer.hh qpdf-7.0.0/include/qpdf/QPDFTokenizer.hh --- qpdf-7.0~b1/include/qpdf/QPDFTokenizer.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/QPDFTokenizer.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __QPDFTOKENIZER_HH__ #define __QPDFTOKENIZER_HH__ diff -Nru qpdf-7.0~b1/include/qpdf/QPDFWriter.hh qpdf-7.0.0/include/qpdf/QPDFWriter.hh --- qpdf-7.0~b1/include/qpdf/QPDFWriter.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/QPDFWriter.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. // This class implements a simple writer for saving QPDF objects to // new PDF files. See comments through the header file for additional diff -Nru qpdf-7.0~b1/include/qpdf/QPDFXRefEntry.hh qpdf-7.0.0/include/qpdf/QPDFXRefEntry.hh --- qpdf-7.0~b1/include/qpdf/QPDFXRefEntry.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/QPDFXRefEntry.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __QPDFXREFENTRY_HH__ #define __QPDFXREFENTRY_HH__ diff -Nru qpdf-7.0~b1/include/qpdf/QTC.hh qpdf-7.0.0/include/qpdf/QTC.hh --- qpdf-7.0~b1/include/qpdf/QTC.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/QTC.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __QTC_HH__ #define __QTC_HH__ diff -Nru qpdf-7.0~b1/include/qpdf/QUtil.hh qpdf-7.0.0/include/qpdf/QUtil.hh --- qpdf-7.0~b1/include/qpdf/QUtil.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/QUtil.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ // Copyright (c) 2005-2017 Jay Berkenbilt // -// This file is part of qpdf. This software may be distributed under -// the terms of version 2 of the Artistic License which may be found -// in the source distribution. It is provided "as is" without express -// or implied warranty. +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __QUTIL_HH__ #define __QUTIL_HH__ @@ -29,8 +43,12 @@ QPDF_DLL std::string double_to_string(double, int decimal_places = 0); + // These string to number methods throw std::runtime_error on + // underflow/overflow. QPDF_DLL long long string_to_ll(char const* str); + QPDF_DLL + int string_to_int(char const* str); // Pipeline's write method wants unsigned char*, but we often have // some other type of string. These methods do combinations of diff -Nru qpdf-7.0~b1/include/qpdf/RandomDataProvider.hh qpdf-7.0.0/include/qpdf/RandomDataProvider.hh --- qpdf-7.0~b1/include/qpdf/RandomDataProvider.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/RandomDataProvider.hh 2017-09-16 17:22:15.000000000 +0000 @@ -1,10 +1,23 @@ -/* Copyright (c) 2005-2017 Jay Berkenbilt - * - * This file is part of qpdf. This software may be distributed under - * the terms of version 2 of the Artistic License which may be found - * in the source distribution. It is provided "as is" without express - * or implied warranty. - */ +// Copyright (c) 2005-2017 Jay Berkenbilt +// +// This file is part of qpdf. +// +// 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 +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Versions of qpdf prior to version 7 were released under the terms +// of version 2.0 of the Artistic License. At your option, you may +// continue to consider qpdf to be licensed under those terms. Please +// see the manual for additional information. #ifndef __RANDOMDATAPROVIDER_HH__ #define __RANDOMDATAPROVIDER_HH__ diff -Nru qpdf-7.0~b1/include/qpdf/Types.h qpdf-7.0.0/include/qpdf/Types.h --- qpdf-7.0~b1/include/qpdf/Types.h 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/include/qpdf/Types.h 2017-09-16 17:22:15.000000000 +0000 @@ -1,9 +1,23 @@ /* Copyright (c) 2005-2017 Jay Berkenbilt * - * This file is part of qpdf. This software may be distributed under - * the terms of version 2 of the Artistic License which may be found - * in the source distribution. It is provided "as is" without express - * or implied warranty. + * This file is part of qpdf. + * + * 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 + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Versions of qpdf prior to version 7 were released under the terms + * of version 2.0 of the Artistic License. At your option, you may + * continue to consider qpdf to be licensed under those terms. Please + * see the manual for additional information. */ #ifndef __QPDFTYPES_H__ diff -Nru qpdf-7.0~b1/ispell-words qpdf-7.0.0/ispell-words --- qpdf-7.0~b1/ispell-words 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/ispell-words 2017-09-16 17:22:15.000000000 +0000 @@ -389,6 +389,7 @@ eol epub eq +ERANGE eraseItem Erdelsky's errno @@ -1162,6 +1163,7 @@ resolveLiteral resolveObjectsInStream ResolveRecorder +resync retargeted retested reverseResolved diff -Nru qpdf-7.0~b1/libqpdf/Pl_DCT.cc qpdf-7.0.0/libqpdf/Pl_DCT.cc --- qpdf-7.0~b1/libqpdf/Pl_DCT.cc 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/libqpdf/Pl_DCT.cc 2017-09-16 17:22:15.000000000 +0000 @@ -1,6 +1,7 @@ #include #include +#include #include #include #include @@ -66,7 +67,20 @@ Pl_DCT::finish() { this->buf.finish(); - PointerHolder b = this->buf.getBuffer(); + + // Using a PointerHolder here and passing it into compress + // and decompress causes a memory leak with setjmp/longjmp. Just + // use a pointer and delete it. + Buffer* b = this->buf.getBuffer(); + if (b->getSize() == 0) + { + // Special case: empty data will never succeed and probably + // means we're calling finish a second time from an exception + // handler. + delete b; + this->getNext()->finish(); + return; + } struct jpeg_compress_struct cinfo_compress; struct jpeg_decompress_struct cinfo_decompress; @@ -77,21 +91,35 @@ jerr.pub.error_exit = error_handler; bool error = false; + // The jpeg library is a "C" library, so we use setjmp and longjmp + // for exception handling. if (setjmp(jerr.jmpbuf) == 0) { - if (this->action == a_compress) + try { - compress(reinterpret_cast(&cinfo_compress), b); + if (this->action == a_compress) + { + compress(reinterpret_cast(&cinfo_compress), b); + } + else + { + decompress(reinterpret_cast(&cinfo_decompress), b); + } } - else + catch (std::exception& e) { - decompress(reinterpret_cast(&cinfo_decompress), b); + // Convert an exception back to a longjmp so we can ensure + // that the right cleanup happens. This will get converted + // back to an exception. + jerr.msg = e.what(); + longjmp(jerr.jmpbuf, 1); } } else { error = true; } + delete b; if (this->action == a_compress) { @@ -107,27 +135,121 @@ } } -class Freer +struct dct_pipeline_dest +{ + struct jpeg_destination_mgr pub; /* public fields */ + unsigned char* buffer; + size_t size; + Pipeline* next; +}; + +static void +init_pipeline_destination(j_compress_ptr) +{ +} + +static boolean +empty_pipeline_output_buffer(j_compress_ptr cinfo) +{ + QTC::TC("libtests", "Pl_DCT empty_pipeline_output_buffer"); + dct_pipeline_dest* dest = + reinterpret_cast(cinfo->dest); + dest->next->write(dest->buffer, dest->size); + dest->pub.next_output_byte = dest->buffer; + dest->pub.free_in_buffer = dest->size; + return TRUE; +} + +static void +term_pipeline_destination(j_compress_ptr cinfo) +{ + QTC::TC("libtests", "Pl_DCT term_pipeline_destination"); + dct_pipeline_dest* dest = + reinterpret_cast(cinfo->dest); + dest->next->write(dest->buffer, dest->size - dest->pub.free_in_buffer); +} + +static void +jpeg_pipeline_dest(j_compress_ptr cinfo, + unsigned char* outbuffer, size_t size, + Pipeline* next) +{ + cinfo->dest = static_cast( + (*cinfo->mem->alloc_small)(reinterpret_cast(cinfo), + JPOOL_PERMANENT, + sizeof(dct_pipeline_dest))); + dct_pipeline_dest* dest = + reinterpret_cast(cinfo->dest); + dest->pub.init_destination = init_pipeline_destination; + dest->pub.empty_output_buffer = empty_pipeline_output_buffer; + dest->pub.term_destination = term_pipeline_destination; + dest->pub.next_output_byte = dest->buffer = outbuffer; + dest->pub.free_in_buffer = dest->size = size; + dest->next = next; +} + +static void +init_buffer_source(j_decompress_ptr) { - public: - Freer(unsigned char** p) : - p(p) +} + +static boolean +fill_buffer_input_buffer(j_decompress_ptr) +{ + // The whole JPEG data is expected to reside in the supplied memory + // buffer, so any request for more data beyond the given buffer size + // is treated as an error. + throw std::runtime_error("invalid jpeg data reading from buffer"); + return TRUE; +} + +static void +skip_buffer_input_data(j_decompress_ptr cinfo, long num_bytes) +{ + if (num_bytes < 0) { + throw std::runtime_error( + "reading jpeg: jpeg library requested" + " skipping a negative number of bytes"); } - ~Freer() + size_t to_skip = static_cast(num_bytes); + if ((to_skip > 0) && (to_skip <= cinfo->src->bytes_in_buffer)) { - if (*p) - { - free(*p); - } + cinfo->src->next_input_byte += to_skip; + cinfo->src->bytes_in_buffer -= to_skip; } + else if (to_skip != 0) + { + cinfo->src->next_input_byte += cinfo->src->bytes_in_buffer; + cinfo->src->bytes_in_buffer = 0; + } +} - private: - unsigned char** p; -}; +static void +term_buffer_source(j_decompress_ptr) +{ +} + +static void +jpeg_buffer_src(j_decompress_ptr cinfo, Buffer* buffer) +{ + cinfo->src = reinterpret_cast( + (*cinfo->mem->alloc_small)(reinterpret_cast(cinfo), + JPOOL_PERMANENT, + sizeof(jpeg_source_mgr))); + + jpeg_source_mgr* src = cinfo->src; + src->init_source = init_buffer_source; + src->fill_input_buffer = fill_buffer_input_buffer; + src->skip_input_data = skip_buffer_input_data; + src->resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->term_source = term_buffer_source; + src->bytes_in_buffer = buffer->getSize(); + src->next_input_byte = buffer->getBuffer(); +} void -Pl_DCT::compress(void* cinfo_p, PointerHolder b) +Pl_DCT::compress(void* cinfo_p, Buffer* b) { struct jpeg_compress_struct* cinfo = reinterpret_cast(cinfo_p); @@ -142,10 +264,11 @@ defined(__clang__)) # pragma GCC diagnostic pop #endif - unsigned char* outbuffer = 0; - Freer freer(&outbuffer); - unsigned long outsize = 0; - jpeg_mem_dest(cinfo, &outbuffer, &outsize); + static int const BUF_SIZE = 65536; + PointerHolder outbuffer_ph( + true, new unsigned char[BUF_SIZE]); + unsigned char* outbuffer = outbuffer_ph.getPointer(); + jpeg_pipeline_dest(cinfo, outbuffer, BUF_SIZE, this->getNext()); cinfo->image_width = this->image_width; cinfo->image_height = this->image_height; @@ -178,12 +301,11 @@ (void) jpeg_write_scanlines(cinfo, row_pointer, 1); } jpeg_finish_compress(cinfo); - this->getNext()->write(outbuffer, outsize); this->getNext()->finish(); } void -Pl_DCT::decompress(void* cinfo_p, PointerHolder b) +Pl_DCT::decompress(void* cinfo_p, Buffer* b) { struct jpeg_decompress_struct* cinfo = reinterpret_cast(cinfo_p); @@ -198,7 +320,7 @@ defined(__clang__)) # pragma GCC diagnostic pop #endif - jpeg_mem_src(cinfo, b->getBuffer(), b->getSize()); + jpeg_buffer_src(cinfo, b); (void) jpeg_read_header(cinfo, TRUE); (void) jpeg_calc_output_dimensions(cinfo); diff -Nru qpdf-7.0~b1/libqpdf/Pl_Flate.cc qpdf-7.0.0/libqpdf/Pl_Flate.cc --- qpdf-7.0~b1/libqpdf/Pl_Flate.cc 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/libqpdf/Pl_Flate.cc 2017-09-16 17:22:15.000000000 +0000 @@ -35,6 +35,20 @@ delete [] this->outbuf; this->outbuf = 0; } + + if (this->initialized) + { + z_stream& zstream = *(static_cast(this->zdata)); + if (action == a_deflate) + { + deflateEnd(&zstream); + } + else + { + inflateEnd(&zstream); + } + } + delete static_cast(this->zdata); this->zdata = 0; } @@ -174,6 +188,7 @@ { err = inflateEnd(&zstream); } + this->initialized = false; checkError("End", err); } diff -Nru qpdf-7.0~b1/libqpdf/Pl_PNGFilter.cc qpdf-7.0.0/libqpdf/Pl_PNGFilter.cc --- qpdf-7.0~b1/libqpdf/Pl_PNGFilter.cc 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/libqpdf/Pl_PNGFilter.cc 2017-09-16 17:22:15.000000000 +0000 @@ -1,6 +1,7 @@ #include #include #include +#include Pl_PNGFilter::Pl_PNGFilter(char const* identifier, Pipeline* next, action_e action, unsigned int columns, @@ -14,6 +15,11 @@ buf2(0), pos(0) { + if ((columns == 0) || (columns > UINT_MAX - 1)) + { + throw std::runtime_error( + "PNGFilter created with invalid columns value"); + } this->buf1 = new unsigned char[columns + 1]; this->buf2 = new unsigned char[columns + 1]; this->cur_row = buf1; diff -Nru qpdf-7.0~b1/libqpdf/qpdf/QPDF_Stream.hh qpdf-7.0.0/libqpdf/qpdf/QPDF_Stream.hh --- qpdf-7.0~b1/libqpdf/qpdf/QPDF_Stream.hh 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/libqpdf/qpdf/QPDF_Stream.hh 2017-09-16 17:22:15.000000000 +0000 @@ -25,7 +25,7 @@ bool pipeStreamData(Pipeline*, unsigned long encode_flags, qpdf_stream_decode_level_e decode_level, - bool suppress_warnings); + bool suppress_warnings, bool will_retry); PointerHolder getStreamData(qpdf_stream_decode_level_e); PointerHolder getRawStreamData(); void replaceStreamData(PointerHolder data, @@ -43,6 +43,9 @@ // when adding streams to files. void setObjGen(int objid, int generation); + protected: + virtual void releaseResolved(); + private: static std::map filter_abbreviations; diff -Nru qpdf-7.0~b1/libqpdf/QPDF.cc qpdf-7.0.0/libqpdf/QPDF.cc --- qpdf-7.0~b1/libqpdf/QPDF.cc 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/libqpdf/QPDF.cc 2017-09-16 17:22:15.000000000 +0000 @@ -19,7 +19,7 @@ #include #include -std::string QPDF::qpdf_version = "7.0.b1"; +std::string QPDF::qpdf_version = "7.0.0"; static char const* EMPTY_PDF = "%PDF-1.3\n" @@ -440,8 +440,8 @@ (t3 == QPDFTokenizer::Token(QPDFTokenizer::tt_word, "obj"))) { in_obj = true; - int obj = atoi(t1.getValue().c_str()); - int gen = atoi(t2.getValue().c_str()); + int obj = QUtil::string_to_int(t1.getValue().c_str()); + int gen = QUtil::string_to_int(t2.getValue().c_str()); insertXrefEntry(obj, 1, token_start, gen, true); } } @@ -491,8 +491,10 @@ QPDF::read_xref(qpdf_offset_t xref_offset) { std::map free_table; + std::set visited; while (xref_offset) { + visited.insert(xref_offset); char buf[7]; memset(buf, 0, sizeof(buf)); this->m->file->seek(xref_offset, SEEK_SET); @@ -520,6 +522,10 @@ { xref_offset = read_xrefStream(xref_offset); } + if (visited.count(xref_offset) != 0) + { + xref_offset = 0; + } } if (! this->m->trailer.isInitialized()) @@ -604,8 +610,8 @@ ++p; } bytes = p - start; - obj = atoi(obj_str.c_str()); - num = atoi(num_str.c_str()); + obj = QUtil::string_to_int(obj_str.c_str()); + num = QUtil::string_to_int(num_str.c_str()); return true; } @@ -700,7 +706,7 @@ } f1 = QUtil::string_to_ll(f1_str.c_str()); - f2 = atoi(f2_str.c_str()); + f2 = QUtil::string_to_int(f2_str.c_str()); return true; } @@ -1564,8 +1570,8 @@ this->m->last_object_description, offset, "expected n n obj"); } - objid = atoi(tobjid.getValue().c_str()); - generation = atoi(tgen.getValue().c_str()); + objid = QUtil::string_to_int(tobjid.getValue().c_str()); + generation = QUtil::string_to_int(tgen.getValue().c_str()); if (objid == 0) { @@ -1849,7 +1855,7 @@ "expected integer in object stream header"); } - int num = atoi(tnum.getValue().c_str()); + int num = QUtil::string_to_int(tnum.getValue().c_str()); int offset = QUtil::string_to_ll(toffset.getValue().c_str()); offsets[num] = offset + first; } @@ -2376,7 +2382,8 @@ qpdf_offset_t offset, size_t length, QPDFObjectHandle stream_dict, Pipeline* pipeline, - bool suppress_warnings) + bool suppress_warnings, + bool will_retry) { bool success = false; std::vector > to_delete; @@ -2424,6 +2431,13 @@ "error decoding stream data for object " + QUtil::int_to_string(objid) + " " + QUtil::int_to_string(generation) + ": " + e.what())); + if (will_retry) + { + warn(QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), + "", this->m->file->getLastOffset(), + "stream will be re-processed without" + " filtering to avoid data loss")); + } } } if (! success) diff -Nru qpdf-7.0~b1/libqpdf/qpdf-c.cc qpdf-7.0.0/libqpdf/qpdf-c.cc --- qpdf-7.0~b1/libqpdf/qpdf-c.cc 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/libqpdf/qpdf-c.cc 2017-09-16 17:22:15.000000000 +0000 @@ -502,6 +502,30 @@ qpdf->qpdf_writer->setObjectStreamMode(mode); } +void qpdf_set_compress_streams(qpdf_data qpdf, QPDF_BOOL value) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_set_compress_streams"); + qpdf->qpdf_writer->setCompressStreams(value); +} + +void qpdf_set_decode_level(qpdf_data qpdf, qpdf_stream_decode_level_e level) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_set_decode_level"); + qpdf->qpdf_writer->setDecodeLevel(level); +} + +void qpdf_set_preserve_unreferenced_objects(qpdf_data qpdf, QPDF_BOOL value) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_set_preserve_unreferenced_objects"); + qpdf->qpdf_writer->setPreserveUnreferencedObjects(value); +} + +void qpdf_set_newline_before_endstream(qpdf_data qpdf, QPDF_BOOL value) +{ + QTC::TC("qpdf", "qpdf-c called qpdf_set_newline_before_endstream"); + qpdf->qpdf_writer->setNewlineBeforeEndstream(value); +} + void qpdf_set_stream_data_mode(qpdf_data qpdf, qpdf_stream_data_e mode) { QTC::TC("qpdf", "qpdf-c called qpdf_set_stream_data_mode"); diff -Nru qpdf-7.0~b1/libqpdf/QPDF_encryption.cc qpdf-7.0.0/libqpdf/QPDF_encryption.cc --- qpdf-7.0~b1/libqpdf/QPDF_encryption.cc 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/libqpdf/QPDF_encryption.cc 2017-09-16 17:22:15.000000000 +0000 @@ -479,6 +479,8 @@ char upass[key_bytes]; pad_or_truncate_password_V4(user_password, upass); + std::string k1(reinterpret_cast(O_key), OU_key_bytes_V4); + pad_short_parameter(k1, data.getLengthBytes()); iterate_rc4(QUtil::unsigned_char_pointer(upass), key_bytes, O_key, data.getLengthBytes(), (data.getR() >= 3) ? 20 : 1, false); @@ -495,6 +497,7 @@ std::string k1 = QPDF::compute_encryption_key(user_password, data); char udata[key_bytes]; pad_or_truncate_password_V4("", udata); + pad_short_parameter(k1, data.getLengthBytes()); iterate_rc4(QUtil::unsigned_char_pointer(udata), key_bytes, QUtil::unsigned_char_pointer(k1), data.getLengthBytes(), 1, false); @@ -516,6 +519,7 @@ data.getId1().length()); MD5::Digest digest; md5.digest(digest); + pad_short_parameter(k1, data.getLengthBytes()); iterate_rc4(digest, sizeof(MD5::Digest), QUtil::unsigned_char_pointer(k1), data.getLengthBytes(), 20, false); @@ -591,7 +595,10 @@ compute_O_rc4_key(user_password, owner_password, data, key); unsigned char O_data[key_bytes]; memcpy(O_data, QUtil::unsigned_char_pointer(data.getO()), key_bytes); - iterate_rc4(O_data, key_bytes, key, data.getLengthBytes(), + std::string k1(reinterpret_cast(key), OU_key_bytes_V4); + pad_short_parameter(k1, data.getLengthBytes()); + iterate_rc4(O_data, key_bytes, QUtil::unsigned_char_pointer(k1), + data.getLengthBytes(), (data.getR() >= 3) ? 20 : 1, true); std::string new_user_password = std::string(reinterpret_cast(O_data), key_bytes); @@ -886,6 +893,7 @@ if (V < 5) { + // These must be exactly the right number of bytes. pad_short_parameter(O, key_bytes); pad_short_parameter(U, key_bytes); if (! ((O.length() == key_bytes) && (U.length() == key_bytes))) @@ -913,24 +921,12 @@ UE = encryption_dict.getKey("/UE").getStringValue(); Perms = encryption_dict.getKey("/Perms").getStringValue(); + // These may be longer than the minimum number of bytes. pad_short_parameter(O, OU_key_bytes_V5); pad_short_parameter(U, OU_key_bytes_V5); pad_short_parameter(OE, OUE_key_bytes_V5); pad_short_parameter(UE, OUE_key_bytes_V5); pad_short_parameter(Perms, Perms_key_bytes_V5); - if ((O.length() < OU_key_bytes_V5) || - (U.length() < OU_key_bytes_V5) || - (OE.length() < OUE_key_bytes_V5) || - (UE.length() < OUE_key_bytes_V5) || - (Perms.length() < Perms_key_bytes_V5)) - { - throw QPDFExc(qpdf_e_damaged_pdf, this->m->file->getName(), - "encryption dictionary", - this->m->file->getLastOffset(), - "incorrect length for some of" - " /O, /U, /OE, /UE, or /Perms in" - " encryption dictionary"); - } } int Length = 40; diff -Nru qpdf-7.0~b1/libqpdf/QPDFObjectHandle.cc qpdf-7.0.0/libqpdf/QPDFObjectHandle.cc --- qpdf-7.0~b1/libqpdf/QPDFObjectHandle.cc 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/libqpdf/QPDFObjectHandle.cc 2017-09-16 17:22:15.000000000 +0000 @@ -501,9 +501,19 @@ qpdf_stream_decode_level_e decode_level, bool suppress_warnings) { + return pipeStreamData( + p, encode_flags, decode_level, suppress_warnings, false); +} + +bool +QPDFObjectHandle::pipeStreamData(Pipeline* p, + unsigned long encode_flags, + qpdf_stream_decode_level_e decode_level, + bool suppress_warnings, bool will_retry) +{ assertStream(); return dynamic_cast(obj.getPointer())->pipeStreamData( - p, encode_flags, decode_level, suppress_warnings); + p, encode_flags, decode_level, suppress_warnings, will_retry); } bool @@ -883,8 +893,7 @@ while (static_cast(input->tell()) < length) { QPDFObjectHandle obj = - parseInternal(input, "content", tokenizer, empty, - 0, 0, false, false, true); + parseInternal(input, "content", tokenizer, empty, 0, 0, true); if (! obj.isInitialized()) { // EOF @@ -945,7 +954,7 @@ StringDecrypter* decrypter, QPDF* context) { return parseInternal(input, object_description, tokenizer, empty, - decrypter, context, false, false, false); + decrypter, context, false); } QPDFObjectHandle @@ -953,7 +962,6 @@ std::string const& object_description, QPDFTokenizer& tokenizer, bool& empty, StringDecrypter* decrypter, QPDF* context, - bool in_array, bool in_dictionary, bool content_stream) { // This method must take care not to resolve any objects. Don't @@ -962,22 +970,22 @@ // of reading the object and changing the file pointer. empty = false; - if (in_dictionary && in_array) - { - // Although dictionaries and arrays arbitrarily nest, these - // variables indicate what is at the top of the stack right - // now, so they can, by definition, never both be true. - throw std::logic_error( - "INTERNAL ERROR: parseInternal: in_dict && in_array"); - } QPDFObjectHandle object; - qpdf_offset_t offset = input->tell(); - std::vector olist; + std::vector > olist_stack; + olist_stack.push_back(std::vector()); + std::vector state_stack; + state_stack.push_back(st_top); + std::vector offset_stack; + offset_stack.push_back(input->tell()); bool done = false; while (! done) { + std::vector& olist = olist_stack.back(); + parser_state_e state = state_stack.back(); + qpdf_offset_t offset = offset_stack.back(); + object = QPDFObjectHandle(); QPDFTokenizer::Token token = @@ -988,8 +996,7 @@ case QPDFTokenizer::tt_eof: if (content_stream) { - // Return uninitialized object to indicate EOF - return object; + state = st_eof; } else { @@ -1012,9 +1019,9 @@ break; case QPDFTokenizer::tt_array_close: - if (in_array) + if (state == st_array) { - done = true; + state = st_stop; } else { @@ -1029,9 +1036,9 @@ break; case QPDFTokenizer::tt_dict_close: - if (in_dictionary) + if (state == st_dictionary) { - done = true; + state = st_stop; } else { @@ -1046,15 +1053,13 @@ break; case QPDFTokenizer::tt_array_open: - object = parseInternal( - input, object_description, tokenizer, empty, - decrypter, context, true, false, content_stream); - break; - case QPDFTokenizer::tt_dict_open: - object = parseInternal( - input, object_description, tokenizer, empty, - decrypter, context, false, true, content_stream); + olist_stack.push_back(std::vector()); + state = st_start; + offset_stack.push_back(input->tell()); + state_stack.push_back( + (token.getType() == QPDFTokenizer::tt_array_open) ? + st_array : st_dictionary); break; case QPDFTokenizer::tt_bool: @@ -1084,12 +1089,12 @@ { object = QPDFObjectHandle::newOperator(value); } - else if ((value == "R") && (in_array || in_dictionary) && - (olist.size() >= 2) && - (! olist.at(olist.size() - 1).isIndirect()) && - (olist.at(olist.size() - 1).isInteger()) && - (! olist.at(olist.size() - 2).isIndirect()) && - (olist.at(olist.size() - 2).isInteger())) + else if ((value == "R") && (state != st_top) && + (olist.size() >= 2) && + (! olist.at(olist.size() - 1).isIndirect()) && + (olist.at(olist.size() - 1).isInteger()) && + (! olist.at(olist.size() - 2).isIndirect()) && + (olist.at(olist.size() - 2).isInteger())) { if (context == 0) { @@ -1106,8 +1111,7 @@ olist.pop_back(); olist.pop_back(); } - else if ((value == "endobj") && - (! (in_array || in_dictionary))) + else if ((value == "endobj") && (state == st_top)) { // We just saw endobj without having read // anything. Treat this as a null and do not move @@ -1153,93 +1157,132 @@ break; } - if (in_dictionary || in_array) - { - if (! done) - { - olist.push_back(object); - } - } - else if (! object.isInitialized()) - { - warn(context, - QPDFExc(qpdf_e_damaged_pdf, input->getName(), - object_description, - input->getLastOffset(), - "parse error while reading object")); + if ((! object.isInitialized()) && + (! ((state == st_start) || + (state == st_stop) || + (state == st_eof)))) + { + throw std::logic_error( + "QPDFObjectHandle::parseInternal: " + "unexpected uninitialized object"); object = newNull(); - } - else - { - done = true; - } - } + } - if (in_array) - { - object = newArray(olist); - } - else if (in_dictionary) - { - // Convert list to map. Alternating elements are keys. Attempt - // to recover more or less gracefully from invalid - // dictionaries. - std::set names; - for (std::vector::iterator iter = olist.begin(); - iter != olist.end(); ++iter) + switch (state) { - if ((! (*iter).isIndirect()) && (*iter).isName()) + case st_eof: + if (state_stack.size() > 1) { - names.insert((*iter).getName()); + warn(context, + QPDFExc(qpdf_e_damaged_pdf, input->getName(), + object_description, + input->getLastOffset(), + "parse error while reading object")); } - } + done = true; + // Leave object uninitialized to indicate EOF + break; - std::map dict; - int next_fake_key = 1; - for (unsigned int i = 0; i < olist.size(); ++i) - { - QPDFObjectHandle key_obj = olist.at(i); - QPDFObjectHandle val; - if (key_obj.isIndirect() || (! key_obj.isName())) + case st_dictionary: + case st_array: + olist.push_back(object); + break; + + case st_top: + done = true; + break; + + case st_start: + break; + + case st_stop: + if ((state_stack.size() < 2) || (olist_stack.size() < 2)) { - bool found_fake = false; - std::string candidate; - while (! found_fake) + throw std::logic_error( + "QPDFObjectHandle::parseInternal: st_stop encountered" + " with insufficient elements in stack"); + } + parser_state_e old_state = state_stack.back(); + state_stack.pop_back(); + if (old_state == st_array) + { + object = newArray(olist); + } + else if (old_state == st_dictionary) + { + // Convert list to map. Alternating elements are keys. + // Attempt to recover more or less gracefully from + // invalid dictionaries. + std::set names; + for (std::vector::iterator iter = + olist.begin(); + iter != olist.end(); ++iter) + { + if ((! (*iter).isIndirect()) && (*iter).isName()) + { + names.insert((*iter).getName()); + } + } + + std::map dict; + int next_fake_key = 1; + for (unsigned int i = 0; i < olist.size(); ++i) { - candidate = - "/QPDFFake" + QUtil::int_to_string(next_fake_key++); - found_fake = (names.count(candidate) == 0); - QTC::TC("qpdf", "QPDFObjectHandle found fake", - (found_fake ? 0 : 1)); + QPDFObjectHandle key_obj = olist.at(i); + QPDFObjectHandle val; + if (key_obj.isIndirect() || (! key_obj.isName())) + { + bool found_fake = false; + std::string candidate; + while (! found_fake) + { + candidate = + "/QPDFFake" + + QUtil::int_to_string(next_fake_key++); + found_fake = (names.count(candidate) == 0); + QTC::TC("qpdf", "QPDFObjectHandle found fake", + (found_fake ? 0 : 1)); + } + warn(context, + QPDFExc( + qpdf_e_damaged_pdf, + input->getName(), object_description, offset, + "expected dictionary key but found" + " non-name object; inserting key " + + candidate)); + val = key_obj; + key_obj = newName(candidate); + } + else if (i + 1 >= olist.size()) + { + QTC::TC("qpdf", "QPDFObjectHandle no val for last key"); + warn(context, + QPDFExc( + qpdf_e_damaged_pdf, + input->getName(), object_description, offset, + "dictionary ended prematurely; " + "using null as value for last key")); + val = newNull(); + } + else + { + val = olist.at(++i); + } + dict[key_obj.getName()] = val; } - warn(context, - QPDFExc( - qpdf_e_damaged_pdf, - input->getName(), object_description, offset, - "expected dictionary key but found" - " non-name object; inserting key " + - candidate)); - val = key_obj; - key_obj = newName(candidate); + object = newDictionary(dict); } - else if (i + 1 >= olist.size()) + olist_stack.pop_back(); + offset_stack.pop_back(); + if (state_stack.back() == st_top) { - QTC::TC("qpdf", "QPDFObjectHandle no val for last key"); - warn(context, - QPDFExc( - qpdf_e_damaged_pdf, - input->getName(), object_description, offset, - "dictionary ended prematurely; using null as value" - " for last key")); - val = newNull(); + done = true; } else { - val = olist.at(++i); + olist_stack.back().push_back(object); } - dict[key_obj.getName()] = val; } - object = newDictionary(dict); } return object; diff -Nru qpdf-7.0~b1/libqpdf/QPDF_Stream.cc qpdf-7.0.0/libqpdf/QPDF_Stream.cc --- qpdf-7.0~b1/libqpdf/QPDF_Stream.cc 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/libqpdf/QPDF_Stream.cc 2017-09-16 17:22:15.000000000 +0000 @@ -45,6 +45,13 @@ } void +QPDF_Stream::releaseResolved() +{ + this->stream_provider = 0; + QPDFObjectHandle::ReleaseResolver::releaseResolved(this->stream_dict); +} + +void QPDF_Stream::setObjGen(int objid, int generation) { if (! ((this->objid == 0) && (this->generation == 0))) @@ -87,7 +94,7 @@ QPDF_Stream::getStreamData(qpdf_stream_decode_level_e decode_level) { Pl_Buffer buf("stream data buffer"); - if (! pipeStreamData(&buf, 0, decode_level, false)) + if (! pipeStreamData(&buf, 0, decode_level, false, false)) { throw std::logic_error("getStreamData called on unfilterable stream"); } @@ -99,7 +106,7 @@ QPDF_Stream::getRawStreamData() { Pl_Buffer buf("stream data buffer"); - pipeStreamData(&buf, 0, qpdf_dl_none, false); + pipeStreamData(&buf, 0, qpdf_dl_none, false, false); QTC::TC("qpdf", "QPDF_Stream getRawStreamData"); return buf.getBuffer(); } @@ -366,7 +373,7 @@ QPDF_Stream::pipeStreamData(Pipeline* pipeline, unsigned long encode_flags, qpdf_stream_decode_level_e decode_level, - bool suppress_warnings) + bool suppress_warnings, bool will_retry) { std::vector filters; int predictor = 1; @@ -533,7 +540,8 @@ if (! QPDF::Pipe::pipeStreamData(this->qpdf, this->objid, this->generation, this->offset, this->length, this->stream_dict, pipeline, - suppress_warnings)) + suppress_warnings, + will_retry)) { filter = false; } diff -Nru qpdf-7.0~b1/libqpdf/QPDFWriter.cc qpdf-7.0.0/libqpdf/QPDFWriter.cc --- qpdf-7.0~b1/libqpdf/QPDFWriter.cc 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/libqpdf/QPDFWriter.cc 2017-09-16 17:22:15.000000000 +0000 @@ -661,8 +661,10 @@ } else { - int V = atoi(this->m->encryption_dictionary["/V"].c_str()); - int R = atoi(this->m->encryption_dictionary["/R"].c_str()); + int V = QUtil::string_to_int( + this->m->encryption_dictionary["/V"].c_str()); + int R = QUtil::string_to_int( + this->m->encryption_dictionary["/R"].c_str()); if (compareVersions(major, minor, 1, 4) < 0) { if ((V > 1) || (R > 2)) @@ -705,12 +707,12 @@ QPDFWriter::parseVersion(std::string const& version, int& major, int& minor) const { - major = atoi(version.c_str()); + major = QUtil::string_to_int(version.c_str()); minor = 0; size_t p = version.find('.'); if ((p != std::string::npos) && (version.length() > p)) { - minor = atoi(version.substr(p + 1).c_str()); + minor = QUtil::string_to_int(version.substr(p + 1).c_str()); } std::string tmp = QUtil::int_to_string(major) + "." + QUtil::int_to_string(minor); @@ -1621,7 +1623,7 @@ ((filter && compress) ? qpdf_ef_compress : 0)), (filter ? (uncompress ? qpdf_dl_all : this->m->stream_decode_level) - : qpdf_dl_none)); + : qpdf_dl_none), false, (attempt == 1)); popPipelineStack(&stream_data); if (filter && (! filtered)) { diff -Nru qpdf-7.0~b1/libqpdf/QUtil.cc qpdf-7.0.0/libqpdf/QUtil.cc --- qpdf-7.0~b1/libqpdf/QUtil.cc 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/libqpdf/QUtil.cc 2017-09-16 17:22:15.000000000 +0000 @@ -81,11 +81,40 @@ long long QUtil::string_to_ll(char const* str) { + errno = 0; #ifdef _MSC_VER - return _strtoi64(str, 0, 10); + long long result = _strtoi64(str, 0, 10); #else - return strtoll(str, 0, 10); + long long result = strtoll(str, 0, 10); #endif + if (errno == ERANGE) + { + throw std::runtime_error( + std::string("overflow/underflow converting ") + str + + " to 64-bit integer"); + } + return result; +} + +int +QUtil::string_to_int(char const* str) +{ + errno = 0; + long long_val = strtol(str, 0, 10); + if (errno == ERANGE) + { + throw std::runtime_error( + std::string("overflow/underflow converting ") + str + + " to long integer"); + } + int result = static_cast(long_val); + if (static_cast(result) != long_val) + { + throw std::runtime_error( + std::string("overflow/underflow converting ") + str + + " to integer"); + } + return result; } unsigned char* diff -Nru qpdf-7.0~b1/libtests/dct_compress.cc qpdf-7.0.0/libtests/dct_compress.cc --- qpdf-7.0~b1/libtests/dct_compress.cc 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/libtests/dct_compress.cc 2017-09-16 17:22:15.000000000 +0000 @@ -42,8 +42,8 @@ char* infilename = argv[1]; char* outfilename = argv[2]; - unsigned int width = atoi(argv[3]); - unsigned int height = atoi(argv[4]); + int width = QUtil::string_to_int(argv[3]); + int height = QUtil::string_to_int(argv[4]); char* colorspace = argv[5]; J_COLOR_SPACE cs = ((strcmp(colorspace, "rgb") == 0) ? JCS_RGB : diff -Nru qpdf-7.0~b1/libtests/libtests.testcov qpdf-7.0.0/libtests/libtests.testcov --- qpdf-7.0~b1/libtests/libtests.testcov 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/libtests/libtests.testcov 2017-09-16 17:22:15.000000000 +0000 @@ -27,3 +27,5 @@ Pl_RunLength: switch to run 1 Pl_RunLength flush full buffer 1 Pl_RunLength flush empty buffer 0 +Pl_DCT empty_pipeline_output_buffer 0 +Pl_DCT term_pipeline_destination 0 diff -Nru qpdf-7.0~b1/libtests/png_filter.cc qpdf-7.0.0/libtests/png_filter.cc --- qpdf-7.0~b1/libtests/png_filter.cc 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/libtests/png_filter.cc 2017-09-16 17:22:15.000000000 +0000 @@ -61,7 +61,7 @@ } bool encode = (strcmp(argv[1], "encode") == 0); char* filename = argv[2]; - int columns = atoi(argv[3]); + int columns = QUtil::string_to_int(argv[3]); try { Binary files /tmp/tmpcoUyou/wZ0QBlPrkH/qpdf-7.0~b1/libtests/qtest/dct/big-rawdata and /tmp/tmpcoUyou/_ONANmi6lb/qpdf-7.0.0/libtests/qtest/dct/big-rawdata differ diff -Nru qpdf-7.0~b1/libtests/qtest/dct.test qpdf-7.0.0/libtests/qtest/dct.test --- qpdf-7.0~b1/libtests/qtest/dct.test 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/libtests/qtest/dct.test 2017-09-16 17:22:15.000000000 +0000 @@ -16,38 +16,45 @@ cleanup(); -$td->runtest("compress", - {$td->COMMAND => "dct_compress rawdata a.jpg 400 256 gray"}, - {$td->STRING => "", $td->EXIT_STATUS => 0}); -$td->runtest("decompress", - {$td->COMMAND => "dct_uncompress a.jpg out"}, - {$td->STRING => "", $td->EXIT_STATUS => 0}); -# Compare -my @raw = get_data('rawdata'); -my @processed = get_data('out'); my $checked_data = 0; -if ($td->runtest("bytes in data", - {$td->STRING => scalar(@processed)}, - {$td->STRING => scalar(@raw)})) +foreach my $d (['rawdata', '400 256 gray', 0], + ['big-rawdata', '1024 576 rgb', 0.2]) { - my $mismatch = 0; - for (my $i = 0; $i < scalar(@raw); ++$i) + my ($in, $args, $mismatch_fraction) = @$d; + $td->runtest("compress", + {$td->COMMAND => "dct_compress $in a.jpg $args"}, + {$td->STRING => "", $td->EXIT_STATUS => 0}); + $td->runtest("decompress", + {$td->COMMAND => "dct_uncompress a.jpg out"}, + {$td->STRING => "", $td->EXIT_STATUS => 0}); + # Compare + my @raw = get_data($in); + my @processed = get_data('out'); + my $bytes = scalar(@raw); + if ($td->runtest("bytes in data", + {$td->STRING => scalar(@processed)}, + {$td->STRING => $bytes})) { - $checked_data = 1; - my $delta = abs(ord($raw[$i]) - ord($processed[$i])); - if ($delta > 10) + ++$checked_data; + my $mismatch = 0; + for (my $i = 0; $i < scalar(@raw); ++$i) { - ++$mismatch; + my $delta = abs(ord($raw[$i]) - ord($processed[$i])); + if ($delta > 10) + { + ++$mismatch; + } } + my $threshold = int($mismatch_fraction * $bytes); + $td->runtest("data is close enough", + {$td->STRING => $mismatch <= $threshold ? 'pass' : 'fail'}, + {$td->STRING => 'pass'}); } - $td->runtest("data is close enough", - {$td->STRING => $mismatch}, - {$td->STRING => '0'}); } cleanup(); -$td->report(3 + $checked_data); +$td->report(6 + $checked_data); sub cleanup { diff -Nru qpdf-7.0~b1/libtests/qtest/qutil/qutil.out qpdf-7.0.0/libtests/qtest/qutil/qutil.out --- qpdf-7.0~b1/libtests/qtest/qutil/qutil.out 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/libtests/qtest/qutil/qutil.out 2017-09-16 17:22:15.000000000 +0000 @@ -14,6 +14,14 @@ one 7 compare okay +-2147483648 to int: PASSED +2147483647 to int: PASSED +2147483648 to int threw: PASSED +-2147483649 to int threw: PASSED +9999999999999999999999999 to int threw: PASSED +2147483648 to int: PASSED +-2147483649 to int: PASSED +99999999999999999999999999999999999999999999999999 to int threw: PASSED ---- before remove exception: remove file: No such file or directory diff -Nru qpdf-7.0~b1/libtests/qutil.cc qpdf-7.0.0/libtests/qutil.cc --- qpdf-7.0~b1/libtests/qutil.cc 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/libtests/qutil.cc 2017-09-16 17:22:15.000000000 +0000 @@ -6,6 +6,7 @@ #include #include #include +#include #ifdef _WIN32 # include @@ -13,6 +14,57 @@ # include #endif +template +void test_to_number(char const* str, int_T wanted, bool error, + int_T (*fn)(char const*)) +{ + bool threw = false; + bool worked = false; + int_T result = 0; + try + { + result = fn(str); + worked = (wanted == result); + } + catch (std::runtime_error) + { + threw = true; + } + if (threw) + { + if (error) + { + std::cout << str << " to int threw: PASSED" << std::endl; + } + else + { + std::cout << str << " to int threw but wanted " + << wanted << std::endl; + } + } + else + { + if (worked) + { + std::cout << str << " to int: PASSED" << std::endl; + } + else + { + std::cout << str << " to int failed; got " << result << std::endl; + } + } +} + +void test_to_int(char const* str, int wanted, bool error) +{ + test_to_number(str, wanted, error, QUtil::string_to_int); +} + +void test_to_ll(char const* str, long long wanted, bool error) +{ + test_to_number(str, wanted, error, QUtil::string_to_ll); +} + void string_conversion_test() { std::cout << QUtil::int_to_string(16059) << std::endl @@ -44,6 +96,21 @@ std::cout << "compare failed" << std::endl; } delete [] tmp; + + std::string int_max_str = QUtil::int_to_string(INT_MAX); + std::string int_min_str = QUtil::int_to_string(INT_MIN); + long long int_max_plus_1 = static_cast(INT_MAX) + 1; + long long int_min_minus_1 = static_cast(INT_MIN) - 1; + std::string int_max_plus_1_str = QUtil::int_to_string(int_max_plus_1); + std::string int_min_minus_1_str = QUtil::int_to_string(int_min_minus_1); + test_to_int(int_min_str.c_str(), INT_MIN, false); + test_to_int(int_max_str.c_str(), INT_MAX, false); + test_to_int(int_max_plus_1_str.c_str(), 0, true); + test_to_int(int_min_minus_1_str.c_str(), 0, true); + test_to_int("9999999999999999999999999", 0, true); + test_to_ll(int_max_plus_1_str.c_str(), int_max_plus_1, false); + test_to_ll(int_min_minus_1_str.c_str(), int_min_minus_1, false); + test_to_ll("99999999999999999999999999999999999999999999999999", 0, true); } void os_wrapper_test() diff -Nru qpdf-7.0~b1/LICENSE.txt qpdf-7.0.0/LICENSE.txt --- qpdf-7.0~b1/LICENSE.txt 1970-01-01 00:00:00.000000000 +0000 +++ qpdf-7.0.0/LICENSE.txt 2017-09-16 17:22:15.000000000 +0000 @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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 + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff -Nru qpdf-7.0~b1/make/exec-z qpdf-7.0.0/make/exec-z --- qpdf-7.0~b1/make/exec-z 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/make/exec-z 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -#!/bin/sh -# This script is used for valgrind testing. See README-maintainer.md. - -# Create a suppressions file. This can be updated by running valgrind -# with --gen-suppressions=yes. -test -f /tmp/a.supp || cat > /tmp/a.supp < - - + + ]> @@ -30,10 +30,30 @@ url="https://github.com/qpdf/qpdf">https://github.com/qpdf/qpdf. - QPDF has been released under the terms of Version - 2.0 of the Artistic License, a copy of which appears in the - file Artistic-2.0 in the source distribution. + QPDF is licensed under the Apache + License, Version 2.0 (the "License"). Unless required by + applicable law or agreed to in writing, software distributed under + the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES + OR CONDITIONS OF ANY KIND, either express or implied. See the + License for the specific language governing permissions and + limitations under the License. + + + Versions of qpdf prior to version 7 were released under the terms + of the + Artistic License, version 2.0. At your option, you may + continue to consider qpdf to be licensed under those terms. The + Apache License 2.0 permits everything that the Artistic License 2.0 + permits but is slightly less restrictive. Allowing the Artistic + License to continue being used is primary to help people who may + have to get specific approval to use qpdf in their products. + + + QPDF is intentionally released with a permissive license. However, + if there is some reason that the licensing terms don't work for + your requirements, please feel free to contact the copyright holder + to make other arrangements. QPDF was originally created in 2001 and modified periodically @@ -134,8 +154,8 @@ A C++ compiler that works well with STL and has the long - long type. Most modern C++ compilers should fit the - bill fine. QPDF is tested with gcc and Microsoft Visual C++. + long type. Most modern C++ compilers should fit the bill + fine. QPDF is tested with gcc, clang, and Microsoft Visual C++. @@ -263,15 +283,17 @@ treated as a command-line argument. The option allows arguments to be read from standard input. This allows qpdf to be invoked with an arbitrary number of arbitrarily long - arguments. + arguments. It is also very useful for avoiding having to pass + passwords on the command line. does not have to be seekable, even when generating linearized files. Specifying - “” as + “” as means to write to standard output. However, you can't specify the same file as both the input and the output because qpdf reads data - from the input file as it writes to the output file. + from the input file as it writes to the output file. QPDF attempts + to detect this case and fail without overwriting the output file. Most options require an output file, but some testing or @@ -487,12 +509,11 @@ encoded in ISO-8859-1 and your terminal is configured to use UTF-8, the password you supply may not work properly. There are various approaches to handling this. For example, if you are - using Linux and have the iconv executable (part of the ICU - package) installed, you could pass to qpdf where + using Linux and have the iconv executable installed, you could + pass to qpdf where password is a password specified in - your terminal's locale. A detailed discussion of this is out of + your terminal's locale. A detailed discussion of this is out of scope for this manual, but just be aware of this issue if you have trouble with a password that contains 8-bit characters. @@ -884,7 +905,10 @@ supported generalized filters: , , , and - + . We define generalized + filters as those to be used for general-purpose compression + or encoding, as opposed to filters specifically designed + for image data. @@ -933,9 +957,9 @@ - : uncompress stream data when - possible; equivalent to - + : uncompress stream data + compressed with generalized filters when possible; + equivalent to @@ -1111,18 +1135,6 @@ requested with . - When is specified, qpdf - will never attempt to change the filtering of any stream data. - - - When is specified, qpdf - will attempt to remove any non-lossy filters that it supports. - This includes /FlateDecode, - /LZWDecode, /ASCII85Decode, - and /ASCIIHexDecode. This can be very useful - for inspecting the contents of various streams. - - When is specified, qpdf will attempt to normalize whitespace and newlines in page content streams. This is generally safe but could, in some cases, cause @@ -1366,7 +1378,14 @@ conditions that detects. These are issued as warnings instead of errors. If qpdf finds no errors but finds warnings, it will exit with a status of 3 (as of - version 2.0.4). + version 2.0.4). When is combined + with other options, checks are always performed before any + other options are processed. For erroneous files, + will cause qpdf to attempt to + recover, after which other options are effectively operating + on the recovered file. Combining with + other options in this way can be useful for manually + recovering severely damaged files. @@ -2906,6 +2925,237 @@ + 7.0.0: September 15, 2017 + + + + + Packaging and Distribution Changes + + + + + QPDF's primary license is now version 2.0 + of the Apache License rather than version 2.0 of the + Artistic License. You may still, at your option, consider + qpdf to be licensed with version 2.0 of the Artistic + license. + + + + + QPDF no longer has a dependency on the PCRE (Perl-Compatible + Regular Expression) library. QPDF now has an added + dependency on the JPEG library. + + + + + + + + + Bug Fixes + + + + + This release contains many bug fixes for various infinite + loops, memory leaks, and other memory errors that could be + encountered with specially crafted or otherwise erroneous + PDF files. + + + + + + + + + New Features + + + + + QPDF now supports reading and writing streams encoded with + JPEG or RunLength encoding. Library API enhancements and + command-line options have been added to control this + behavior. See command-line options + and + and methods + QPDFWriter::setCompressStreams and + QPDFWriter::setDecodeLevel. + + + + + QPDF is much better at recovering from broken files. In most + cases, qpdf will skip invalid objects and will preserve + broken stream data by not attempting to filter broken + streams. QPDF is now able to recover or at least not crash + on dozens of broken test files I have received over the past + few years. + + + + + Page rotation is now supported and accessible from both the + library and the command line. + + + + + QPDFWriter supports writing files in + a way that preserves PCLm compliance in support of + driverless printing. This is very specialized and is only + useful to applications that already know how to create PCLm + files. + + + + + + + + + Enhancements to the qpdf Command-line Tool. + All new options listed here are documented in more detail in + . + + + + + Command-line arguments can now be read from files or + standard input using @file or + @- syntax. Please see . + + + + + : request page rotation + + + + + : ensure that a + newline appears before every endstream + keyword in the file; used to prevent qpdf from breaking + PDF/A compliance on already compliant files. + + + + + : preserve + unreferenced objects in the input PDF + + + + + : break output into chunks + with fixed numbers of pages + + + + + : print the name of each output + file that is created + + + + + and + replace + for improving granularity of + controlling compression and decompression of stream data. + The option will remain + available. + + + + + When running qpdf --check with other + options, checks are always run first. This enables qpdf to + perform its full recovery logic before outputting other + information. This can be especially useful when manually + recovering broken files, looking at qpdf's regenerated cross + reference table, or other similar operations. + + + + + Process --pages earlier so that other + options like or + can operate on the file after + page splitting/merging has occurred. + + + + + + + + + API Changes. All new API calls are documented in their + respective classes' header files. + + + + + QPDFObjectHandle::rotatePage: apply + rotation to a page object + + + + + QPDFWriter::setNewlineBeforeEndstream: + force newline to appear before endstream + + + + + QPDFWriter::setPreserveUnreferencedObjects: + preserve unreferenced objects that appear in the input PDF. + The default behavior is to discard them. + + + + + New Pipeline types + Pl_RunLength and + Pl_DCT are available for developers + who wish to produce or consume RunLength or DCT stream data + directly. The examples/pdf-create.cc + example illustrates their use. + + + + + QPDFWriter::setCompressStreams and + QPDFWriter::setDecodeLevel methods + control handling of different types of stream compression. + + + + + Add new C API functions + qpdf_set_compress_streams, + qpdf_set_decode_level, + qpdf_set_preserve_unreferenced_objects, + and qpdf_set_newline_before_endstream + corresponding to the new QPDFWriter + methods. + + + + + + + + + + 6.0.0: November 10, 2015 diff -Nru qpdf-7.0~b1/NOTICE.md qpdf-7.0.0/NOTICE.md --- qpdf-7.0~b1/NOTICE.md 1970-01-01 00:00:00.000000000 +0000 +++ qpdf-7.0.0/NOTICE.md 2017-09-16 17:22:15.000000000 +0000 @@ -0,0 +1,42 @@ +QPDF is copyright (c) 2005-2017 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 + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +Versions of qpdf prior to version 7 were released under the terms of version 2.0 of the Artistic License. At your option, you may continue to consider qpdf to be licensed under those terms. Please see the manual for additional information. + +The qpdf distribution includes a copy of [qtest](http://qtest.qbilt.org), which is released under the terms of the [version 2.0 of the Artistic license](https://opensource.org/licenses/Artistic-2.0), which can be found at https://opensource.org/licenses/Artistic-2.0. + +The Rijndael encryption implementation used as the basis for AES encryption and decryption support comes from Philip J. Erdelsky's public domain implementation. The files `libqpdf/rijndael.cc` and `libqpdf/qpdf/rijndael.h` remain in the public domain. They were obtained from +* http://www.efgh.com/software/rijndael.htm +* http://www.efgh.com/software/rijndael.txt + +The embedded sha2 code comes from sphlib 3.0 +* http://www.saphir2.com/sphlib/ + +That code has the following license: + ``` + Copyright (c) 2007-2011 Projet RNRT SAPHIR + + Permission is hereby granted, free of charge, to any person obtaining + a copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sublicense, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: + + The above copyright notice and this permission notice shall be included + in all copies or substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY + CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + ``` diff -Nru qpdf-7.0~b1/qpdf/pdf_from_scratch.cc qpdf-7.0.0/qpdf/pdf_from_scratch.cc --- qpdf-7.0~b1/qpdf/pdf_from_scratch.cc 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/qpdf/pdf_from_scratch.cc 2017-09-16 17:22:15.000000000 +0000 @@ -107,7 +107,7 @@ try { - int n = atoi(argv[1]); + int n = QUtil::string_to_int(argv[1]); runtest(n); } catch (std::exception& e) diff -Nru qpdf-7.0~b1/qpdf/qpdf.cc qpdf-7.0.0/qpdf/qpdf.cc --- qpdf-7.0~b1/qpdf/qpdf.cc 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/qpdf/qpdf.cc 2017-09-16 17:22:15.000000000 +0000 @@ -1127,7 +1127,7 @@ if (p2 && *(p2 + 1)) { *p2++ = '\0'; - extension_level = atoi(p2); + extension_level = QUtil::string_to_int(p2); } version = v; } @@ -1170,13 +1170,37 @@ // 12345678901234567890123456789012345678901234567890123456789012345678901234567890 std::cout << whoami << " version " << QPDF::QPDFVersion() << std::endl + << std::endl << "Copyright (c) 2005-2017 Jay Berkenbilt" << std::endl - << "This software may be distributed under the terms of version 2 of the" + << "QPDF is licensed under the Apache License, Version 2.0 (the \"License\");" + << std::endl + << "not use this file except in compliance with the License." + << std::endl + << "You may obtain a copy of the License at" + << std::endl + << std::endl + << " http://www.apache.org/licenses/LICENSE-2.0" + << std::endl + << std::endl + << "Unless required by applicable law or agreed to in writing, software" + << std::endl + << "distributed under the License is distributed on an \"AS IS\" BASIS," + << std::endl + << "WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied." << std::endl - << "Artistic License which may be found in the source distribution. It is" + << "See the License for the specific language governing permissions and" << std::endl - << "provided \"as is\" without express or implied warranty." + << "limitations under the License." + << std::endl + << std::endl + << "Versions of qpdf prior to version 7 were released under the terms" + << std::endl + << "of version 2.0 of the Artistic License. At your option, you may" + << std::endl + << "continue to consider qpdf to be licensed under those terms. Please" + << std::endl + << "see the manual for additional information." << std::endl; exit(0); } @@ -1233,7 +1257,7 @@ if (range_valid && ((angle_str == "90") || (angle_str == "180") || (angle_str == "270"))) { - int angle = atoi(angle_str.c_str()); + int angle = QUtil::string_to_int(angle_str.c_str()); if (relative == -1) { angle = -angle; @@ -1337,6 +1361,11 @@ } else if (strcmp(arg, "rotate") == 0) { + if (parameter == 0) + { + usage("--rotate must be given as" + " --rotate=[+|-]angle:page-range"); + } parse_rotation_parameter(o, parameter); } else if (strcmp(arg, "stream-data") == 0) @@ -1492,7 +1521,8 @@ } else if (strcmp(arg, "split-pages") == 0) { - int n = ((parameter == 0) ? 1 : atoi(parameter)); + int n = ((parameter == 0) ? 1 : + QUtil::string_to_int(parameter)); o.split_pages = n; } else if (strcmp(arg, "verbose") == 0) @@ -1547,9 +1577,9 @@ if ((gen = strchr(obj, ',')) != 0) { *gen++ = 0; - o.show_gen = atoi(gen); + o.show_gen = QUtil::string_to_int(gen); } - o.show_obj = atoi(obj); + o.show_obj = QUtil::string_to_int(obj); o.require_outfile = false; } else if (strcmp(arg, "raw-stream-data") == 0) diff -Nru qpdf-7.0~b1/qpdf/qpdf-ctest.c qpdf-7.0.0/qpdf/qpdf-ctest.c --- qpdf-7.0~b1/qpdf/qpdf-ctest.c 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/qpdf/qpdf-ctest.c 2017-09-16 17:22:15.000000000 +0000 @@ -228,6 +228,7 @@ qpdf_set_object_stream_mode(qpdf, qpdf_o_generate); qpdf_write(qpdf); report_errors(); + free(buf); } static void test07(char const* infile, @@ -439,6 +440,50 @@ report_errors(); } +static void test20(char const* infile, + char const* password, + char const* outfile, + char const* outfile2) +{ + qpdf_read(qpdf, infile, password); + qpdf_init_write(qpdf, outfile); + qpdf_set_static_ID(qpdf, QPDF_TRUE); + qpdf_set_static_aes_IV(qpdf, QPDF_TRUE); + qpdf_set_compress_streams(qpdf, QPDF_FALSE); + qpdf_set_decode_level(qpdf, qpdf_dl_specialized); + qpdf_write(qpdf); + report_errors(); +} + +static void test21(char const* infile, + char const* password, + char const* outfile, + char const* outfile2) +{ + qpdf_read(qpdf, infile, password); + qpdf_init_write(qpdf, outfile); + qpdf_set_static_ID(qpdf, QPDF_TRUE); + qpdf_set_static_aes_IV(qpdf, QPDF_TRUE); + qpdf_set_preserve_unreferenced_objects(qpdf, QPDF_TRUE); + qpdf_write(qpdf); + report_errors(); +} + +static void test22(char const* infile, + char const* password, + char const* outfile, + char const* outfile2) +{ + qpdf_read(qpdf, infile, password); + qpdf_init_write(qpdf, outfile); + qpdf_set_static_ID(qpdf, QPDF_TRUE); + qpdf_set_static_aes_IV(qpdf, QPDF_TRUE); + qpdf_set_compress_streams(qpdf, QPDF_FALSE); + qpdf_set_newline_before_endstream(qpdf, QPDF_TRUE); + qpdf_write(qpdf); + report_errors(); +} + int main(int argc, char* argv[]) { char* p = 0; @@ -498,6 +543,9 @@ (n == 17) ? test17 : (n == 18) ? test18 : (n == 19) ? test19 : + (n == 20) ? test20 : + (n == 21) ? test21 : + (n == 22) ? test22 : 0); if (fn == 0) diff -Nru qpdf-7.0~b1/qpdf/qpdf.testcov qpdf-7.0.0/qpdf/qpdf.testcov --- qpdf-7.0~b1/qpdf/qpdf.testcov 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/qpdf/qpdf.testcov 2017-09-16 17:22:15.000000000 +0000 @@ -297,3 +297,7 @@ QPDFObjectHandle found old angle 1 QPDF_Stream special filters 3 QPDFTokenizer block long token 0 +qpdf-c called qpdf_set_decode_level 0 +qpdf-c called qpdf_set_compress_streams 0 +qpdf-c called qpdf_set_preserve_unreferenced_objects 0 +qpdf-c called qpdf_set_newline_before_endstream 0 diff -Nru qpdf-7.0~b1/qpdf/qtest/qpdf/bad-data.out qpdf-7.0.0/qpdf/qtest/qpdf/bad-data.out --- qpdf-7.0~b1/qpdf/qtest/qpdf/bad-data.out 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/qpdf/qtest/qpdf/bad-data.out 2017-09-16 17:22:15.000000000 +0000 @@ -1,2 +1,3 @@ WARNING: bad-data.pdf (file position 319): error decoding stream data for object 4 0: LZWDecoder: bad code received +WARNING: bad-data.pdf (file position 319): stream will be re-processed without filtering to avoid data loss qpdf: operation succeeded with warnings; resulting file may have some problems diff -Nru qpdf-7.0~b1/qpdf/qtest/qpdf/bad-jpeg-check.out qpdf-7.0.0/qpdf/qtest/qpdf/bad-jpeg-check.out --- qpdf-7.0~b1/qpdf/qtest/qpdf/bad-jpeg-check.out 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/qpdf/qtest/qpdf/bad-jpeg-check.out 2017-09-16 17:22:15.000000000 +0000 @@ -3,3 +3,4 @@ File is not encrypted File is not linearized WARNING: bad-jpeg.pdf (file position 735): error decoding stream data for object 6 0: Not a JPEG file: starts with 0x77 0x77 +WARNING: bad-jpeg.pdf (file position 735): stream will be re-processed without filtering to avoid data loss diff -Nru qpdf-7.0~b1/qpdf/qtest/qpdf/bad-jpeg.out qpdf-7.0.0/qpdf/qtest/qpdf/bad-jpeg.out --- qpdf-7.0~b1/qpdf/qtest/qpdf/bad-jpeg.out 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/qpdf/qtest/qpdf/bad-jpeg.out 2017-09-16 17:22:15.000000000 +0000 @@ -1,2 +1,3 @@ WARNING: bad-jpeg.pdf (file position 735): error decoding stream data for object 6 0: Not a JPEG file: starts with 0x77 0x77 +WARNING: bad-jpeg.pdf (file position 735): stream will be re-processed without filtering to avoid data loss qpdf: operation succeeded with warnings; resulting file may have some problems diff -Nru qpdf-7.0~b1/qpdf/qtest/qpdf/damaged-stream-c-check.out qpdf-7.0.0/qpdf/qtest/qpdf/damaged-stream-c-check.out --- qpdf-7.0~b1/qpdf/qtest/qpdf/damaged-stream-c-check.out 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/qpdf/qtest/qpdf/damaged-stream-c-check.out 2017-09-16 17:22:15.000000000 +0000 @@ -3,3 +3,8 @@ file: damaged-stream.pdf pos : 426 text: error decoding stream data for object 5 0: LZWDecoder: bad code received +warning: damaged-stream.pdf (file position 426): stream will be re-processed without filtering to avoid data loss + code: 5 + file: damaged-stream.pdf + pos : 426 + text: stream will be re-processed without filtering to avoid data loss diff -Nru qpdf-7.0~b1/qpdf/qtest/qpdf/damaged-stream.out qpdf-7.0.0/qpdf/qtest/qpdf/damaged-stream.out --- qpdf-7.0~b1/qpdf/qtest/qpdf/damaged-stream.out 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/qpdf/qtest/qpdf/damaged-stream.out 2017-09-16 17:22:15.000000000 +0000 @@ -3,3 +3,4 @@ File is not encrypted File is not linearized WARNING: damaged-stream.pdf (file position 426): error decoding stream data for object 5 0: LZWDecoder: bad code received +WARNING: damaged-stream.pdf (file position 426): stream will be re-processed without filtering to avoid data loss diff -Nru qpdf-7.0~b1/qpdf/qtest/qpdf/issue-106.out qpdf-7.0.0/qpdf/qtest/qpdf/issue-106.out --- qpdf-7.0~b1/qpdf/qtest/qpdf/issue-106.out 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/qpdf/qtest/qpdf/issue-106.out 2017-09-16 17:22:15.000000000 +0000 @@ -2,4 +2,5 @@ WARNING: issue-106.pdf (file position 809): xref not found WARNING: issue-106.pdf: Attempting to reconstruct cross-reference table WARNING: issue-106.pdf (file position 965): error decoding stream data for object 8 0: stream inflate: inflate: data: incorrect data check +WARNING: issue-106.pdf (file position 965): stream will be re-processed without filtering to avoid data loss qpdf: operation succeeded with warnings; resulting file may have some problems diff -Nru qpdf-7.0~b1/qpdf/qtest/qpdf/issue-146.out qpdf-7.0.0/qpdf/qtest/qpdf/issue-146.out --- qpdf-7.0~b1/qpdf/qtest/qpdf/issue-146.out 1970-01-01 00:00:00.000000000 +0000 +++ qpdf-7.0.0/qpdf/qtest/qpdf/issue-146.out 2017-09-16 17:22:15.000000000 +0000 @@ -0,0 +1,5 @@ +WARNING: issue-146.pdf: file is damaged +WARNING: issue-146.pdf: can't find startxref +WARNING: issue-146.pdf: Attempting to reconstruct cross-reference table +WARNING: issue-146.pdf (trailer, file position 20728): unknown token while reading object; treating as string +issue-146.pdf (trailer, file position 20732): EOF while reading token diff -Nru qpdf-7.0~b1/qpdf/qtest/qpdf/issue-146.pdf qpdf-7.0.0/qpdf/qtest/qpdf/issue-146.pdf --- qpdf-7.0~b1/qpdf/qtest/qpdf/issue-146.pdf 1970-01-01 00:00:00.000000000 +0000 +++ qpdf-7.0.0/qpdf/qtest/qpdf/issue-146.pdf 2017-09-16 17:22:15.000000000 +0000 @@ -0,0 +1,20 @@ +%PDF-1.4 0 obj + +1 0 obj +<>0 R>1>> +endobj + +7 0 obj +<> +endo> +endobj 9 +0n +trailer +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[< ] +/Dum / +>> +EOF diff -Nru qpdf-7.0~b1/qpdf/qtest/qpdf/issue-147.out qpdf-7.0.0/qpdf/qtest/qpdf/issue-147.out --- qpdf-7.0~b1/qpdf/qtest/qpdf/issue-147.out 1970-01-01 00:00:00.000000000 +0000 +++ qpdf-7.0.0/qpdf/qtest/qpdf/issue-147.out 2017-09-16 17:22:15.000000000 +0000 @@ -0,0 +1,8 @@ +WARNING: issue-147.pdf: can't find PDF header +WARNING: issue-147.pdf: file is damaged +WARNING: issue-147.pdf: can't find startxref +WARNING: issue-147.pdf: Attempting to reconstruct cross-reference table +WARNING: issue-147.pdf (trailer, file position 9): expected dictionary key but found non-name object; inserting key /QPDFFake1 +WARNING: issue-147.pdf (object 62 0, file position 88): expected endobj +WARNING: issue-147.pdf (trailer, file position 90): invalid /ID in trailer dictionary +issue-147.pdf: invalid password diff -Nru qpdf-7.0~b1/qpdf/qtest/qpdf/issue-147.pdf qpdf-7.0.0/qpdf/qtest/qpdf/issue-147.pdf --- qpdf-7.0~b1/qpdf/qtest/qpdf/issue-147.pdf 1970-01-01 00:00:00.000000000 +0000 +++ qpdf-7.0.0/qpdf/qtest/qpdf/issue-147.pdf 2017-09-16 17:22:15.000000000 +0000 @@ -0,0 +1,2 @@ +trailer<<<>/Encrypt 62 0 R>> +62 0 obj</P 0/R 3/U<>/V 2>>0 0 \ No newline at end of file diff -Nru qpdf-7.0~b1/qpdf/qtest/qpdf/issue-148.out qpdf-7.0.0/qpdf/qtest/qpdf/issue-148.out --- qpdf-7.0~b1/qpdf/qtest/qpdf/issue-148.out 1970-01-01 00:00:00.000000000 +0000 +++ qpdf-7.0.0/qpdf/qtest/qpdf/issue-148.out 2017-09-16 17:22:15.000000000 +0000 @@ -0,0 +1,7 @@ +WARNING: issue-148.pdf: can't find PDF header +WARNING: issue-148.pdf (xref stream: object 8 0, file position 26): stream dictionary lacks /Length key +WARNING: issue-148.pdf (xref stream: object 8 0, file position 73): attempting to recover stream length +WARNING: issue-148.pdf (xref stream: object 8 0, file position 73): recovered stream length: 2 +WARNING: issue-148.pdf (xref stream: object 8 0, file position 85): expected endobj +WARNING: issue-148.pdf (file position 73): error decoding stream data for object 8 0: stream inflate: inflate: data: incorrect header check +getStreamData called on unfilterable stream Binary files /tmp/tmpcoUyou/wZ0QBlPrkH/qpdf-7.0~b1/qpdf/qtest/qpdf/issue-148.pdf and /tmp/tmpcoUyou/_ONANmi6lb/qpdf-7.0.0/qpdf/qtest/qpdf/issue-148.pdf differ diff -Nru qpdf-7.0~b1/qpdf/qtest/qpdf/issue-149.out qpdf-7.0.0/qpdf/qtest/qpdf/issue-149.out --- qpdf-7.0~b1/qpdf/qtest/qpdf/issue-149.out 1970-01-01 00:00:00.000000000 +0000 +++ qpdf-7.0.0/qpdf/qtest/qpdf/issue-149.out 2017-09-16 17:22:15.000000000 +0000 @@ -0,0 +1,2 @@ +WARNING: issue-149.pdf: reported number of objects (11) inconsistent with actual number of objects (7) +qpdf: operation succeeded with warnings; resulting file may have some problems diff -Nru qpdf-7.0~b1/qpdf/qtest/qpdf/issue-149.pdf qpdf-7.0.0/qpdf/qtest/qpdf/issue-149.pdf --- qpdf-7.0~b1/qpdf/qtest/qpdf/issue-149.pdf 1970-01-01 00:00:00.000000000 +0000 +++ qpdf-7.0.0/qpdf/qtest/qpdf/issue-149.pdf 2017-09-16 17:22:15.000000000 +0000 @@ -0,0 +1,120 @@ +%PDF-1.7 +%Á∑·∂ +% vim: set tw=76 ts=2 et : +% convert with: +% ./fixlengths < hello.txt > hello.pdf ; ./genxref hello.pdf +1 0 obj + << /Type /Catalog + /Outlines 6 0 R + /Pages 2 0 R + >> +endobj + +2 0 obj + << /Type /Pages + /Kids [3 0 R] + /Count 1 + >> +endobj + +3 0 obj + << /Type /Page + /Parent 2 0 R + /MediaBox [0 0 595.276 841.89] + /Contents 4 0 R + /Resources << + /ProcSet [/PDF /Text] + /Font << /F1 5 0 R >> + >> + >> +endobj + +4 0 obj + << /Length 36 >> +stream + BT 80 100 Td /F1 48 Tf (foo) Tj ET +endstream +endobj + +5 0 obj + << /Type /Font + /Subtype /Type1 + /Name /F1 + /BaseFont /Helvetica + /Encoding /MacRomanEncoding + >> +endobj + +6 0 obj + << /Type /Outlines + /Count 0 + >> +endobj + +xref +0 7 +0000000000 65535 f +0000000125 00000 n +0000000208 00000 n +0000000283 00000 n +0000000492 00000 n +0000000583 00000 n +0000000721 00000 n + +trailer + << /Size 7 + /Prev 1516 + /Root 1 0 R + >> +startxref +779%%EOF + +% %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +1 1 obj + << /Type /Catalog + /Outlines 6 0 R + /Pages 2 1 R + >> +endobj + +2 1 obj + << /Type /Pages + /Kids [3 1 R] + /Count 1 + >> +endobj + +3 1 obj + << /Type /Page + /Parent 2 1 R + /MediaBox [0 0 595.276 841.89] + /Contents 4 1 R + /Resources << + /ProcSet [/PDF /Text] + /Font << /F1 5 0 R >> + >> + >> +endobj + +4 1 obj + << /Length 36 >> +stream + BT 80 100 Td /F1 48 Tf (bar) Tj ET +endstream +endobj + +xref +1 4 +0000001058 00001 n +0000001141 00001 n +0000001216 00001 n +0000001425 00001 n + +trailer + << /Size 11 + /Prev 779 + /Root 1 1 R + >> +startxref +1516 +%%EOF diff -Nru qpdf-7.0~b1/qpdf/qtest/qpdf/issue-150.out qpdf-7.0.0/qpdf/qtest/qpdf/issue-150.out --- qpdf-7.0~b1/qpdf/qtest/qpdf/issue-150.out 1970-01-01 00:00:00.000000000 +0000 +++ qpdf-7.0.0/qpdf/qtest/qpdf/issue-150.out 2017-09-16 17:22:15.000000000 +0000 @@ -0,0 +1,2 @@ +WARNING: issue-150.pdf: can't find PDF header +overflow/underflow converting 9900000000000000000 to 64-bit integer diff -Nru qpdf-7.0~b1/qpdf/qtest/qpdf/issue-150.pdf qpdf-7.0.0/qpdf/qtest/qpdf/issue-150.pdf --- qpdf-7.0~b1/qpdf/qtest/qpdf/issue-150.pdf 1970-01-01 00:00:00.000000000 +0000 +++ qpdf-7.0.0/qpdf/qtest/qpdf/issue-150.pdf 2017-09-16 17:22:15.000000000 +0000 @@ -0,0 +1,4 @@ +00008 0 obj<>/W[0 2 0]/Size 0>>stream +xc0endobj +startxref +4 \ No newline at end of file diff -Nru qpdf-7.0~b1/qpdf/qtest/qpdf/split-content-stream-errors.out qpdf-7.0.0/qpdf/qtest/qpdf/split-content-stream-errors.out --- qpdf-7.0~b1/qpdf/qtest/qpdf/split-content-stream-errors.out 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/qpdf/qtest/qpdf/split-content-stream-errors.out 2017-09-16 17:22:15.000000000 +0000 @@ -3,6 +3,7 @@ File is not encrypted File is not linearized WARNING: split-content-stream-errors.pdf (file position 557): error decoding stream data for object 6 0: LZWDecoder: bad code received +WARNING: split-content-stream-errors.pdf (file position 557): stream will be re-processed without filtering to avoid data loss WARNING: content stream: ignoring non-stream while parsing content streams WARNING: split-content-stream-errors.pdf (file position 557): error decoding stream data for object 6 0: LZWDecoder: bad code received WARNING: content stream (content stream object 6 0): errors while decoding content stream diff -Nru qpdf-7.0~b1/qpdf/qtest/qpdf.test qpdf-7.0.0/qpdf/qtest/qpdf.test --- qpdf-7.0~b1/qpdf/qtest/qpdf.test 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/qpdf/qtest/qpdf.test 2017-09-16 17:22:15.000000000 +0000 @@ -221,6 +221,11 @@ ["141a", "/W entry size 0", 2], ["141b", "/W entry size 0", 2], ["143", "self-referential ostream", 3], + ["146", "very deeply nested array", 2], + ["147", "previously caused memory error", 2], + ["148", "free memory on bad flate", 2], + ["149", "xref prev pointer loop", 3], + ["150", "integer overflow", 2], ); $n_tests += scalar(@bug_tests); foreach my $d (@bug_tests) @@ -682,7 +687,7 @@ show_ntests(); # ---------- $td->notify("--- Newline before endstream ---"); -$n_tests += 8; +$n_tests += 10; # From issue 133, http://verapdf.org/software/ is an open source # package that can verify PDF/A compliance. This could potentially be @@ -711,6 +716,16 @@ {$td->FILE => "a.pdf", $td->EXIT_STATUS => 0}); } } + +$td->runtest("newline before endstream (C)", + {$td->COMMAND => + "qpdf-ctest 22 streams-with-newlines.pdf '' a.pdf"}, + {$td->STRING => "", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); +$td->runtest("check output", + {$td->FILE => "a.pdf"}, + {$td->FILE => "newline-before-endstream-nl.pdf"}); + show_ntests(); # ---------- $td->notify("--- Split Pages ---"); @@ -944,7 +959,7 @@ show_ntests(); # ---------- $td->notify("--- Decode levels ---"); -$n_tests += 12; +$n_tests += 14; # image-streams.pdf is the output of examples/pdf-create. # examples/pdf-create validates the actual image data. @@ -962,6 +977,17 @@ $td->NORMALIZE_NEWLINES); } +# C API +$td->runtest("image-streams: C", + {$td->COMMAND => "qpdf-ctest 20 image-streams.pdf '' a.pdf"}, + {$td->STRING => "", $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); +$td->runtest("check image-streams: C", + {$td->COMMAND => "test_driver 39 a.pdf"}, + {$td->FILE => "image-streams-specialized.out", + $td->EXIT_STATUS => 0}, + $td->NORMALIZE_NEWLINES); + # Bad JPEG data $td->runtest("check finds bad jpeg data", {$td->COMMAND => "qpdf --check bad-jpeg.pdf"}, @@ -985,7 +1011,7 @@ show_ntests(); # ---------- $td->notify("--- Preserve unreferenced objects ---"); -$n_tests += 4; +$n_tests += 6; $td->runtest("drop unused objects", {$td->COMMAND => "qpdf --static-id unreferenced-objects.pdf a.pdf"}, @@ -999,6 +1025,13 @@ {$td->STRING => "", $td->EXIT_STATUS => 0}); $td->runtest("check output", {$td->FILE => "a.pdf"}, + {$td->FILE => "unreferenced-preserved.pdf"}); +$td->runtest("keep unused objects (C)", + {$td->COMMAND => + "qpdf-ctest 21 unreferenced-objects.pdf '' a.pdf"}, + {$td->STRING => "", $td->EXIT_STATUS => 0}); +$td->runtest("check output", + {$td->FILE => "a.pdf"}, {$td->FILE => "unreferenced-preserved.pdf"}); show_ntests(); # ---------- diff -Nru qpdf-7.0~b1/qpdf/test_driver.cc qpdf-7.0.0/qpdf/test_driver.cc --- qpdf-7.0~b1/qpdf/test_driver.cc 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/qpdf/test_driver.cc 2017-09-16 17:22:15.000000000 +0000 @@ -1383,7 +1383,7 @@ try { - int n = atoi(argv[1]); + int n = QUtil::string_to_int(argv[1]); char const* filename1 = argv[2]; char const* arg2 = argv[3]; runtest(n, filename1, arg2); diff -Nru qpdf-7.0~b1/README-maintainer.md qpdf-7.0.0/README-maintainer.md --- qpdf-7.0~b1/README-maintainer.md 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/README-maintainer.md 2017-09-16 17:22:15.000000000 +0000 @@ -1,5 +1,9 @@ # Release Reminders +* For debugging: + ``` + ./configure CFLAGS="-g" CXXFLAGS="-g" --enable-werror --disable-shared + ``` * Test for binary compatibility. The easiest way to do this is to check out the last release, run the test suite, check out the new release, run `make build_libqpdf`, check out the old release, and run `make check NO_REBUILD=1`. * When making a release, always remember to run large file tests and image comparison tests (`--enable-test-compare-images` `--with-large-file-test-path=/path`). For Windows, use a Windows style path, not an MSYS path for large files. For a major release, consider running a spelling checker over the source code to catch errors in variable names, strings, and comments. Use `ispell -p ispell-words`. * Run tests with sanitize address enabled: @@ -9,16 +13,11 @@ LDFLAGS="-fsanitize=address" \ --enable-werror --disable-shared ``` - As of gcc 6.3.0, this exposes some good things but appears to also have some false positive leak reports. Valgrind is more reliable but also may miss some things that this catches. -* Consider running tests with latest gcc and/or valgrind. To test with valgrind: - ``` - ./configure --disable-shared - make -j8 -k VALGRIND=1 - make -k check NO_REBUILD=1 - ``` - This moves each binary into a subdirectory and replaces it with a link to make/exec-z. See make/exec-z. + The test suite should run clean with this. This seems to be more reliable than valgrind. +* Test with clang. Pass `CC=clang CXX=clang++` to `./configure`. * Check all open issues in the sourceforge trackers and on github. * If any interfaces were added or changed, check C API to see whether changes are appropriate there as well. If necessary, review the casting policy in the manual, and ensure that integer types are properly handled. +* Avoid atoi. Use QUtil::string_to_int instead. It does overflow/underflow checking. * Remember to avoid using `operator[]` with `std::string` or `std::vector`. Instead, use `at()`. See README-hardening.md for details. * Increment shared library version information as needed (`LT_*` in `configure.ac`) * Update release notes in manual. Look at diffs and ChangeLog. @@ -78,7 +77,7 @@ If you want to run `make maintainer-clean`, `make distclean`, or `make autofiles.zip` and you haven't run `./configure`, you can pass `CLEAN=1` to make on the command line to prevent it from complaining about configure not having been run. -If you want to run checks without rerunning the build, pass `NO_REBUILD=1` to make. This can be useful for special testing scenarios such as valgrind or binary compatibility. +If you want to run checks without rerunning the build, pass `NO_REBUILD=1` to make. This can be useful for special testing scenarios such as validation of memory fixes or binary compatibility. # Local Windows Testing Procedure diff -Nru qpdf-7.0~b1/README.md qpdf-7.0.0/README.md --- qpdf-7.0~b1/README.md 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/README.md 2017-09-16 17:22:15.000000000 +0000 @@ -2,7 +2,15 @@ QPDF is copyright (c) 2005-2017 Jay Berkenbilt -This software may be distributed under the terms of version 2 of the Artistic License which may be found in the source distribution as "Artistic-2.0". It is provided "as is" without express or implied warranty. +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 + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. + +You may also see the license in the file [LICENSE.txt](LICENSE.txt) in the source distribution. + +Versions of qpdf prior to version 7 were released under the terms of version 2.0 of the Artistic License. At your option, you may continue to consider qpdf to be licensed under those terms. Please see the manual for additional information. The Artistic License appears in the file [Artistic-2.0](Artistic-2.0) in the source distribution. # Prerequisites @@ -14,36 +22,7 @@ QPDF makes use of zlib and jpeg libraries for its functionality. These packages can be downloaded separately from their own download locations, or they can be downloaded in the external-libs area of the qpdf download site. -The Rijndael encryption implementation used as the basis for AES encryption and decryption support comes from Philip J. Erdelsky's public domain implementation. The files `libqpdf/rijndael.cc` and `libqpdf/qpdf/rijndael.h` remain in the public domain. They were obtained from -* http://www.efgh.com/software/rijndael.htm -* http://www.efgh.com/software/rijndael.txt - -The embedded sha2 code comes from sphlib 3.0 -* http://www.saphir2.com/sphlib/ - -That code has the following license: - ``` - Copyright (c) 2007-2011 Projet RNRT SAPHIR - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be included - in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. - IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY - CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - ``` +Please see the [NOTICE](NOTICE.md) file for information on licenses of embedded software. # Building from a pristine checkout diff -Nru qpdf-7.0~b1/TODO qpdf-7.0.0/TODO --- qpdf-7.0~b1/TODO 2017-08-22 20:50:48.000000000 +0000 +++ qpdf-7.0.0/TODO 2017-09-16 17:22:15.000000000 +0000 @@ -1,10 +1,3 @@ -Before final 7.0.0 -================== - - * Update C API - - * Create release notes - Soon ====