Commit eb481eb698947d88be0724e84f518a70a0468cc9
1 parent
c95f0211
Prepare release notes for 10.6 (so far)
Showing
8 changed files
with
424 additions
and
17 deletions
ChangeLog
| @@ -68,7 +68,7 @@ | @@ -68,7 +68,7 @@ | ||
| 68 | object. | 68 | object. |
| 69 | 69 | ||
| 70 | * A light C API around basic QPDFJob functionality is in | 70 | * A light C API around basic QPDFJob functionality is in |
| 71 | - include/qpdf/qpdf-job-c.h.p | 71 | + include/qpdf/qpdfjob-c.h.p |
| 72 | 72 | ||
| 73 | * Add new functions version of QUtil::call_main_from_wmain that | 73 | * Add new functions version of QUtil::call_main_from_wmain that |
| 74 | takes a constant argv array. | 74 | takes a constant argv array. |
| @@ -79,10 +79,10 @@ | @@ -79,10 +79,10 @@ | ||
| 79 | description to --help and the manual. | 79 | description to --help and the manual. |
| 80 | 80 | ||
| 81 | * The --json flag now takes a version number as an optional | 81 | * The --json flag now takes a version number as an optional |
| 82 | - parameter. The default will remain version 1 for compatibility. | ||
| 83 | - This enables future code to use --json=latest to always get the | ||
| 84 | - latest version or to use a specific version. At this time, there's | ||
| 85 | - only version 1, but a version 2 may appear in a future qpdf. | 82 | + parameter. The default will remain version 1 for compatibility |
| 83 | + until the release of qpdf 11, after which it will become "latest". | ||
| 84 | + At this time, there's only version 1, but a version 2 may appear | ||
| 85 | + in a future qpdf. | ||
| 86 | 86 | ||
| 87 | 2022-01-28 Jay Berkenbilt <ejb@ql.org> | 87 | 2022-01-28 Jay Berkenbilt <ejb@ql.org> |
| 88 | 88 |
TODO
| @@ -9,15 +9,6 @@ | @@ -9,15 +9,6 @@ | ||
| 9 | make qpdf more contributor-friendly. Look | 9 | make qpdf more contributor-friendly. Look |
| 10 | https://bestpractices.coreinfrastructure.org/en | 10 | https://bestpractices.coreinfrastructure.org/en |
| 11 | 11 | ||
| 12 | -* Remember for release notes: starting in qpdf 11, the default value | ||
| 13 | - for the --json keyword will be "latest". If you are depending on | ||
| 14 | - version 1, change your code to specify --json=1, which works | ||
| 15 | - starting with 10.6.0. | ||
| 16 | - | ||
| 17 | -* Write up something about preparing for the PointerHolder to | ||
| 18 | - shared_ptr migration. Clearly document the deprecations and how to | ||
| 19 | - deal with them. | ||
| 20 | - | ||
| 21 | Output JSON v2 | 12 | Output JSON v2 |
| 22 | ============== | 13 | ============== |
| 23 | 14 | ||
| @@ -332,6 +323,9 @@ Other notes: | @@ -332,6 +323,9 @@ Other notes: | ||
| 332 | PointerHolder to std::shared_ptr | 323 | PointerHolder to std::shared_ptr |
| 333 | ================================ | 324 | ================================ |
| 334 | 325 | ||
| 326 | +Remember to update the smart-pointers section of the manual in | ||
| 327 | +design.rst. | ||
| 328 | + | ||
| 335 | Once all deprecation warnings are cleared up (changing getPointer() to | 329 | Once all deprecation warnings are cleared up (changing getPointer() to |
| 336 | get() and getRefcount() to use_count()), the only real issues are that | 330 | get() and getRefcount() to use_count()), the only real issues are that |
| 337 | implicit assignment of a pointer to a shared_ptr doesn't work while it | 331 | implicit assignment of a pointer to a shared_ptr doesn't work while it |
cSpell.json
job.sums
| @@ -14,4 +14,4 @@ libqpdf/qpdf/auto_job_json_decl.hh c5e3fd38a3b0c569eb0c6b4c60953a09cd6bc7d3361a3 | @@ -14,4 +14,4 @@ libqpdf/qpdf/auto_job_json_decl.hh c5e3fd38a3b0c569eb0c6b4c60953a09cd6bc7d3361a3 | ||
| 14 | libqpdf/qpdf/auto_job_json_init.hh b070350d304d137ba594c1ba40b373137e8459735f04b8ca0f8a2ffd1908c69e | 14 | libqpdf/qpdf/auto_job_json_init.hh b070350d304d137ba594c1ba40b373137e8459735f04b8ca0f8a2ffd1908c69e |
| 15 | libqpdf/qpdf/auto_job_schema.hh 18a3780671d95224cb9a27dcac627c421cae509d59f33a63e6bda0ab53cce923 | 15 | libqpdf/qpdf/auto_job_schema.hh 18a3780671d95224cb9a27dcac627c421cae509d59f33a63e6bda0ab53cce923 |
| 16 | manual/_ext/qpdf.py e9ac9d6c70642a3d29281ee5ad92ae2422dee8be9306fb8a0bc9dba0ed5e28f3 | 16 | manual/_ext/qpdf.py e9ac9d6c70642a3d29281ee5ad92ae2422dee8be9306fb8a0bc9dba0ed5e28f3 |
| 17 | -manual/cli.rst 3746df6c4f115387cca0d921f25619a6b8407fc10b0e4c9dcf40b0b1656c6f8a | 17 | +manual/cli.rst 2dd5e5a9c0440aea65ed0a2bf6239aa6662afdb463224aafdc116a8a676dbc20 |
manual/cli.rst
| @@ -3154,7 +3154,10 @@ Related Options | @@ -3154,7 +3154,10 @@ Related Options | ||
| 3154 | supported value is ``1``, but it's possible that a new JSON output | 3154 | supported value is ``1``, but it's possible that a new JSON output |
| 3155 | version will be added in a future version. You can also specify | 3155 | version will be added in a future version. You can also specify |
| 3156 | ``latest`` to use the latest JSON version. For backward | 3156 | ``latest`` to use the latest JSON version. For backward |
| 3157 | - compatibility, the default value is ``1``. Use the | 3157 | + compatibility, the default value will remain ``1`` until qpdf |
| 3158 | + version 11, after which point it will become ``latest``. In all | ||
| 3159 | + case, you can tell what version of the JSON output you have from | ||
| 3160 | + the ``"version"`` key in the output. Use the | ||
| 3158 | :qpdf:ref:`--json-help` option to get a description of the JSON | 3161 | :qpdf:ref:`--json-help` option to get a description of the JSON |
| 3159 | object. | 3162 | object. |
| 3160 | 3163 |
manual/design.rst
| @@ -745,3 +745,221 @@ C API object handle methods returned error codes like the other methods | @@ -745,3 +745,221 @@ C API object handle methods returned error codes like the other methods | ||
| 745 | and set return values in passed-in pointers, but this would complicate | 745 | and set return values in passed-in pointers, but this would complicate |
| 746 | both the implementation and the use of the library for a case that is | 746 | both the implementation and the use of the library for a case that is |
| 747 | actually quite rare and largely avoidable. | 747 | actually quite rare and largely avoidable. |
| 748 | + | ||
| 749 | +.. _smart-pointers: | ||
| 750 | + | ||
| 751 | +Smart Pointers | ||
| 752 | +-------------- | ||
| 753 | + | ||
| 754 | +This section describes changes to the use of smart pointers in qpdf in | ||
| 755 | +versions 10.6.0 and 11.0.0. | ||
| 756 | + | ||
| 757 | +Starting in qpdf 11, ``PointerHolder`` will be replaced with | ||
| 758 | +``std::shared_ptr`` in qpdf's public API. A backward-compatible | ||
| 759 | +``PointerHolder`` will be provided that should make it possible for | ||
| 760 | +most code to remain unchanged. This new ``PointerHolder`` will be | ||
| 761 | +marked deprecated but will provide a way to suppress the deprecation | ||
| 762 | +warnings. Code that works with containers of ``PointerHolder`` may | ||
| 763 | +have to be modified, though no qpdf interfaces do this. | ||
| 764 | + | ||
| 765 | +The remainder of this section describes how to prepare if you want to | ||
| 766 | +eliminate ``PointerHolder`` from your code or what to do if you want | ||
| 767 | +to stick with the old interfaces. | ||
| 768 | + | ||
| 769 | +Changes in 10.6.0 | ||
| 770 | +~~~~~~~~~~~~~~~~~ | ||
| 771 | + | ||
| 772 | +In qpdf 10.6.0, two ``PointerHolder`` methods have been deprecated and | ||
| 773 | +replaced with methods that are compatible with ``std::shared_ptr``: | ||
| 774 | + | ||
| 775 | +- ``getPointer()`` -- use ``get()`` instead | ||
| 776 | + | ||
| 777 | +- ``getRefcount()`` -- use ``use_count()`` instead | ||
| 778 | + | ||
| 779 | +If you build your code with deprecation warnings enabled and you want | ||
| 780 | +to suppress these deprecation warnings for now, you can ``#define | ||
| 781 | +NO_POINTERHOLDER_DEPRECATION`` before including any qpdf header files. | ||
| 782 | +It may be possible to leave it this way long-term to facilitate | ||
| 783 | +supporting older versions of qpdf without conditional compilation. | ||
| 784 | + | ||
| 785 | +``PointerHolder`` has had a long-standing bug: a ``const | ||
| 786 | +PointerHolder<T>`` would only provide a ``T const*`` with its | ||
| 787 | +``getPointer`` method. This is incorrect and is now how standard C++ | ||
| 788 | +smart pointers or regular pointers behave. The correct semantics | ||
| 789 | +would be that a ``const PointerHolder<T>`` would not accept a new | ||
| 790 | +pointer after being created but would still allow you to modify the | ||
| 791 | +item being pointed to. If you don't want to mutate the thing it points | ||
| 792 | +to, use ``PointerHolder<T const>`` instead. The new ``get()`` method | ||
| 793 | +behaves correctly. It is therefore not exactly the same as | ||
| 794 | +``getPointer()``, but it does behave the way ``get()`` behaves with | ||
| 795 | +``std::shared_ptr``. This shouldn't make any difference to any | ||
| 796 | +correctly written code. | ||
| 797 | + | ||
| 798 | + | ||
| 799 | +How to Prepare | ||
| 800 | +~~~~~~~~~~~~~~ | ||
| 801 | + | ||
| 802 | +If you don't need to support versions of qpdf prior to 10.6, you can | ||
| 803 | +just replace all occurrences of ``getPointer()`` with ``get()`` and | ||
| 804 | +all occurrences of ``getRefcount()`` with ``use_count()``. That's | ||
| 805 | +about all you will be able to do prior to qpdf 11. | ||
| 806 | + | ||
| 807 | +If you need to support older versions, you have two choices: | ||
| 808 | + | ||
| 809 | +- ``#define NO_POINTERHOLDER_DEPRECATION`` and leave everything the | ||
| 810 | + way it was. You can just wait until qpdf 11. | ||
| 811 | + | ||
| 812 | +- Write code that uses ``get()`` but falls back to ``getPointer()`` if | ||
| 813 | + ``QPDF_MAJOR_VERSION`` is not defined. The symbols | ||
| 814 | + ``QPDF_MAJOR_VERSION``, ``QPDF_MINOR_VERSION``, and | ||
| 815 | + ``QPDF_PATCH_VERSION`` were introduced with 10.6.0, so just checking | ||
| 816 | + for whether ``QPDF_MAJOR_VERSION`` is defined is sufficient for | ||
| 817 | + telling if you're running a version before 10.6.0. If you do this, | ||
| 818 | + once qpdf 11 comes out, you will already know all the places that | ||
| 819 | + have to be handled specially. | ||
| 820 | + | ||
| 821 | +If you are somehow relying on the fact that a ``const | ||
| 822 | +PointerHolder<T>`` always gave back a ``T const*`` and are | ||
| 823 | +dereferencing a ``const PointerHolder<T>`` to call methods that only | ||
| 824 | +have ``const`` versions in ``T``, you may have to change from | ||
| 825 | +``const PointerHolder<T>`` to ``PointerHolder<T const>``. This won't | ||
| 826 | +be an issue for anything in the qpdf API, and if you are using qpdf | ||
| 827 | +``PointerHolder`` objects for any other reason, you should just | ||
| 828 | +replace them with ``std::shared_ptr``. | ||
| 829 | + | ||
| 830 | +What to Expect | ||
| 831 | +~~~~~~~~~~~~~~ | ||
| 832 | + | ||
| 833 | +Note: if you are reading this in the 10.6 manual and 11 is out, you | ||
| 834 | +should read it in the manual for qpdf 11 instead. Some early tests | ||
| 835 | +have been done to try to ensure the accuracy of this information, but | ||
| 836 | +it may change once the work is actually completed. | ||
| 837 | + | ||
| 838 | +When ``PointerHolder`` disappears from qpdf's API in qpdf 11, you will | ||
| 839 | +have a few options: | ||
| 840 | + | ||
| 841 | +- Use the new ``PointerHolder``, which is derived from | ||
| 842 | + ``std::shared_ptr`` and which has methods to make it | ||
| 843 | + interchangeable. For things that use ``PointerHolder<T>`` directly, | ||
| 844 | + this should "just work," though you will have to ``#define | ||
| 845 | + NO_POINTERHOLDER_DEPRECATION`` if you don't want deprecation | ||
| 846 | + warnings. | ||
| 847 | + | ||
| 848 | +- Replace all uses of ``PointerHolder<T>`` with ``std::shared_ptr<T>`` | ||
| 849 | + and deal with the required changes, outlined below. This is the | ||
| 850 | + recommended course of action. You will need conditional compilation | ||
| 851 | + if you want to simultaneously support order code. Stay tuned for the | ||
| 852 | + qpdf 11 documentation for specifics. | ||
| 853 | + | ||
| 854 | +While ``PointerHolder<T>`` and ``std::shared_ptr<T>`` will be mutually | ||
| 855 | +assignable and convertible, this does not apply to containers of those | ||
| 856 | +objects. The qpdf API doesn't have any containers of | ||
| 857 | +``PointerHolder``, so this would have to be in your own code. You can | ||
| 858 | +prepare yourself for the change by using ``auto`` and ``decltype`` | ||
| 859 | +whenever possible so that a change to the underlying type of something | ||
| 860 | +won't require source changes. | ||
| 861 | + | ||
| 862 | +Required Changes in qpdf 11 | ||
| 863 | +~~~~~~~~~~~~~~~~~~~~~~~~~~~ | ||
| 864 | + | ||
| 865 | +This section describes unavoidable changes when replacing | ||
| 866 | +``PointerHolder`` with ``std::shared_ptr`` rather than continuing to | ||
| 867 | +use the backward compatible API. Nothing here is needed (or can be | ||
| 868 | +done) prior to qpdf 11, so consider this to be a preview. | ||
| 869 | + | ||
| 870 | +- Change ``getPointer`` to ``get`` and ``getRefcount`` to | ||
| 871 | + ``use_count`` as above. If your starting point is no deprecation | ||
| 872 | + warnings with qpdf 10.6, this will already be true. | ||
| 873 | + | ||
| 874 | +- Array allocations will have to be rewritten. | ||
| 875 | + | ||
| 876 | + To allocate a ``PointerHolder`` to an array: | ||
| 877 | + | ||
| 878 | + .. code-block:: c++ | ||
| 879 | + | ||
| 880 | + PointerHolder<X> p(true, new X[n]); | ||
| 881 | + | ||
| 882 | + To allocate a ``std::shared_ptr`` to an array: | ||
| 883 | + | ||
| 884 | + .. code-block:: c++ | ||
| 885 | + | ||
| 886 | + auto p = std::shared_ptr<X>(new X[n], std::default_delete<X[]>()); | ||
| 887 | + | ||
| 888 | + To allocate a ``std::unique_ptr`` to an array: | ||
| 889 | + | ||
| 890 | + .. code-block:: c++ | ||
| 891 | + | ||
| 892 | + auto p = std::make_unique<X[]>(n); | ||
| 893 | + // or | ||
| 894 | + auto p = std::unique_ptr<X[]>(new X[n]); | ||
| 895 | + | ||
| 896 | + The second form may be needed if ``X`` has a private constructor | ||
| 897 | + from this context. | ||
| 898 | + | ||
| 899 | + C++-17 has a better way to allocate ``std::shared_ptr`` to an array, | ||
| 900 | + but qpdf is still allowing C++-14 to be used. You can use whatever | ||
| 901 | + method to handle shared arrays that is supported in your | ||
| 902 | + environment. There are no shared arrays in qpdf's public API except | ||
| 903 | + for some ``QUtil`` helper methods that are not essential for use of | ||
| 904 | + qpdf features. | ||
| 905 | + | ||
| 906 | +- ``PointerHolder<T>`` can have plain pointers directly assigned to | ||
| 907 | + it, while ``std::shared_ptr<T>`` cannot. This makes code like this | ||
| 908 | + possible: | ||
| 909 | + | ||
| 910 | + .. code-block:: c++ | ||
| 911 | + | ||
| 912 | + PointerHolder<X> x_p; | ||
| 913 | + X* x = new X(); | ||
| 914 | + x_p = x; | ||
| 915 | + | ||
| 916 | + It also makes it possible to pass a plain pointer to a function | ||
| 917 | + expecting a ``PointerHolder``, thereby transferring "ownership" of | ||
| 918 | + the pointer into the function. | ||
| 919 | + | ||
| 920 | + Code like that is a risky because you can leak memory if an | ||
| 921 | + exception is thrown between creation of the X and assignment of it | ||
| 922 | + into the ``PointerHolder``. In any case, ``std::shared_ptr`` does | ||
| 923 | + not allow that, so you need one of these instead: | ||
| 924 | + | ||
| 925 | + .. code-block:: c++ | ||
| 926 | + | ||
| 927 | + auto x_p = std::make_shared<X>(); | ||
| 928 | + X* x = x_p.get(); | ||
| 929 | + // or, less safe, but closer: | ||
| 930 | + std::shared_ptr<X> x_p; | ||
| 931 | + X* x = new X(); | ||
| 932 | + x_p = std::shared_ptr<X>(x); | ||
| 933 | + | ||
| 934 | + Also, code like this: | ||
| 935 | + | ||
| 936 | + .. code-block:: c++ | ||
| 937 | + | ||
| 938 | + PointerHolder<Base> base_p; | ||
| 939 | + Derived* derived = new Derived(); | ||
| 940 | + base_p = derived; | ||
| 941 | + | ||
| 942 | + needs to be replaced with something like this instead: | ||
| 943 | + | ||
| 944 | + .. code-block:: c++ | ||
| 945 | + | ||
| 946 | + std::shared_ptr<Base> base_p; | ||
| 947 | + Derived* derived = new Derived(); | ||
| 948 | + base_p = std::shared_ptr<Base>(derived); | ||
| 949 | + | ||
| 950 | +Historical Background | ||
| 951 | +~~~~~~~~~~~~~~~~~~~~~ | ||
| 952 | + | ||
| 953 | +Since its inception, the qpdf library used its own smart pointer | ||
| 954 | +class, ``PointerHolder``. The ``PointerHolder`` class was originally | ||
| 955 | +created long before ``std::shared_ptr`` existed, and qpdf itself | ||
| 956 | +didn't start requiring a C++-11 compiler version 9.1.0 released in | ||
| 957 | +late 2019. | ||
| 958 | + | ||
| 959 | +``PointerHolder`` is a reference-counted smart pointer with semantics | ||
| 960 | +almost identical to ``std::shared_ptr`` except that it is not | ||
| 961 | +thread-safe. It has a few interface differences that prevent | ||
| 962 | +``std::shared_ptr`` from being a drop-in replacement. However, given | ||
| 963 | +the value of using standard library smart pointers, qpdf is taking the | ||
| 964 | +plunge for version 11 and switching over to standard library smart | ||
| 965 | +pointers. |
manual/qpdf-job.rst
| @@ -14,7 +14,10 @@ executable is available from inside the C++ library using the | @@ -14,7 +14,10 @@ executable is available from inside the C++ library using the | ||
| 14 | 14 | ||
| 15 | - Use from the C++ API with ``QPDFJob::initializeFromArgv`` | 15 | - Use from the C++ API with ``QPDFJob::initializeFromArgv`` |
| 16 | 16 | ||
| 17 | - - Use from the C API with ``qpdfjob_run_from_argv`` from :file:`qpdfjob-c.h` | 17 | + - Use from the C API with ``qpdfjob_run_from_argv`` from |
| 18 | + :file:`qpdfjob-c.h`. If you are calling from a Windows-style main | ||
| 19 | + and have an argv array of ``wchar_t``, you can use | ||
| 20 | + ``qpdfjob_run_from_wide_argv``. | ||
| 18 | 21 | ||
| 19 | - The job JSON file format | 22 | - The job JSON file format |
| 20 | 23 | ||
| @@ -135,6 +138,13 @@ C++ code: | @@ -135,6 +138,13 @@ C++ code: | ||
| 135 | return 0; | 138 | return 0; |
| 136 | } | 139 | } |
| 137 | 140 | ||
| 141 | +Note the ``QPDFUsage`` exception above. This is thrown whenever a | ||
| 142 | +configuration error occurs. These exactly correspond to usage messages | ||
| 143 | +issued by the :command:`qpdf` CLI for things like omitting an output | ||
| 144 | +file, specifying `--pages` multiple times, or other invalid | ||
| 145 | +combinations of options. ``QPDFUsage`` is thrown by the argv and JSON | ||
| 146 | +interfaces as well as the native ``QPDFJob`` interface. | ||
| 147 | + | ||
| 138 | It is also possible to mix and match command-line options and JSON | 148 | It is also possible to mix and match command-line options and JSON |
| 139 | from the CLI. For example, you could create a file called | 149 | from the CLI. For example, you could create a file called |
| 140 | :file:`my-options.json` containing the following: | 150 | :file:`my-options.json` containing the following: |
manual/release-notes.rst
| @@ -6,6 +6,187 @@ Release Notes | @@ -6,6 +6,187 @@ Release Notes | ||
| 6 | For a detailed list of changes, please see the file | 6 | For a detailed list of changes, please see the file |
| 7 | :file:`ChangeLog` in the source distribution. | 7 | :file:`ChangeLog` in the source distribution. |
| 8 | 8 | ||
| 9 | +10.6.0: XXX | ||
| 10 | + - Deprecations/future replacement of ``PointerHolder`` | ||
| 11 | + | ||
| 12 | + The next major release of qpdf will replace ``PointerHolder`` with | ||
| 13 | + ``std::shared_ptr`` across all of qpdf's public API. In | ||
| 14 | + preparation for this change, the following ``PointerHolder`` | ||
| 15 | + methods have been deprecated in favor of interfaces that more | ||
| 16 | + closely match ``std::shared_ptr``: | ||
| 17 | + | ||
| 18 | + - ``getPointer()`` -- use ``get()`` instead; this also fixes | ||
| 19 | + ``const`` semantics as discussed in | ||
| 20 | + :file:`include/qpdf/PointerHolder.hh`. | ||
| 21 | + | ||
| 22 | + - ``getRefcount()`` -- use ``use_count()`` instead | ||
| 23 | + | ||
| 24 | + If you build your code with deprecation warnings enabled and you | ||
| 25 | + want to suppress these deprecation warnings for now, you can | ||
| 26 | + ``#define NO_POINTERHOLDER_DEPRECATION`` before including any qpdf | ||
| 27 | + header files. Code that does this will *require no changes* prior | ||
| 28 | + to qpdf 11 and may or may not require changes after qpdf 11. | ||
| 29 | + | ||
| 30 | + For a detailed discussion of this change and how to prepare for | ||
| 31 | + it, see :ref:`smart-pointers`. | ||
| 32 | + | ||
| 33 | + - Preparation for a new JSON output version | ||
| 34 | + | ||
| 35 | + - The :qpdf:ref:`--json` option takes an optional parameter | ||
| 36 | + indicating the version of the JSON output. At present, there is | ||
| 37 | + only one JSON version (``1``), but there are plans for an | ||
| 38 | + updated version in a coming release. Until the release of qpdf | ||
| 39 | + 11, the default value of ``--json`` is ``1`` for compatibility. | ||
| 40 | + Once qpdf 11 is out, the default version will be ``latest``. If | ||
| 41 | + you are depending on the exact format of ``--json`` for code, | ||
| 42 | + you should start using ``--json=1`` in preparation. | ||
| 43 | + | ||
| 44 | + - New QPDFJob API exposes CLI functionality | ||
| 45 | + | ||
| 46 | + Prior to qpdf 10.6, a lot of the functionality implemented by the | ||
| 47 | + qpdf CLI executable was built into the executable itself and not | ||
| 48 | + available from the library. qpdf 10.6 introduces a new object, | ||
| 49 | + ``QPDFJob``, that exposes all of the command-line functionality. | ||
| 50 | + This includes a native ``QPDFJob`` API with fluent interfaces that | ||
| 51 | + mirror the command-line syntax, a JSON syntax for specifying the | ||
| 52 | + equivalent of a command-line invocation, and the ability to run a | ||
| 53 | + qpdf "job" by passing a null-terminated array of qpdf command-line | ||
| 54 | + options. The command-line argument array and JSON methods of | ||
| 55 | + invoking ``QPDFJob`` are also exposed to the C API. For details, | ||
| 56 | + see :ref:`qpdf-job`. | ||
| 57 | + | ||
| 58 | + - Other Library Enhancements | ||
| 59 | + | ||
| 60 | + - New ``QPDFObjectHandle`` literal syntax using C++'s user-defined | ||
| 61 | + literal syntax. You can use | ||
| 62 | + | ||
| 63 | + .. code-block:: c++ | ||
| 64 | + | ||
| 65 | + auto oh = "<</Some (valid) /PDF (object)>>"_qpdf; | ||
| 66 | + | ||
| 67 | + to create a QPDFObjectHandle. It is a shorthand for | ||
| 68 | + ``QPDFObjectHandle::parse``. | ||
| 69 | + | ||
| 70 | + - Preprocessor symbols ``QPDF_MAJOR_VERSION``, | ||
| 71 | + ``QPDF_MINOR_VERSION``, and ``QPDF_PATCH_VERSION`` are now | ||
| 72 | + available and can be used to make it easier to write code that | ||
| 73 | + supports multiple versions of qpdf. You don't have to include | ||
| 74 | + any new header files to get these, which makes it possible to | ||
| 75 | + write code like this: | ||
| 76 | + | ||
| 77 | + .. code-block:: c++ | ||
| 78 | + | ||
| 79 | + #if !defined(QPDF_MAJOR_VERSION) || QPDF_MAJOR_VERSION < 11 | ||
| 80 | + // do something using qpdf 10 or older API | ||
| 81 | + #else | ||
| 82 | + // do something using qpdf 11 or newer API | ||
| 83 | + #endif | ||
| 84 | + | ||
| 85 | + Since this was introduced only in qpdf version 10.6.0, testing | ||
| 86 | + for an undefined value of ``QPDF_MAJOR_VERSION`` is equivalent | ||
| 87 | + to detecting a version prior to 10.6.0. | ||
| 88 | + | ||
| 89 | + The symbol ``QPDF_VERSION`` is also defined as a string | ||
| 90 | + containing the same version number that is returned by | ||
| 91 | + ``QPDF::QPDFVersion``. Note that ``QPDF_VERSION`` may differ | ||
| 92 | + from ``QPDF::QPDFVersion()`` if your header files and library | ||
| 93 | + are out of sync with each other. | ||
| 94 | + | ||
| 95 | + - The method ``QPDF::QPDFVersion`` and corresponding C API call | ||
| 96 | + ``qpdf_get_qpdf_version`` are now both guaranteed to return a | ||
| 97 | + reference (or pointer) to a static string, so you don't have to | ||
| 98 | + copy these if you are using them in your software. They have | ||
| 99 | + always returned static values. Now the fact that they return | ||
| 100 | + static values is part of the API contract and can be safely | ||
| 101 | + relied upon. | ||
| 102 | + | ||
| 103 | + - New accessor methods for ``QPDFObjectHandle``. In addition to | ||
| 104 | + the traditional ones, such as ``getIntValue``, ``getName``, | ||
| 105 | + etc., there are a family of new accessors whose names are of the | ||
| 106 | + form ``getValueAsX``. The difference in behavior is as follows: | ||
| 107 | + | ||
| 108 | + - The older accessor methods, which will continue to be | ||
| 109 | + supported, return the value of the object if it is the | ||
| 110 | + expected type. Otherwise, they return a fallback value and | ||
| 111 | + issue a warning. | ||
| 112 | + | ||
| 113 | + - The newer accessor methods return a boolean indicating whether | ||
| 114 | + or not the object is of the expected type. If it is, a | ||
| 115 | + reference of the correct type is returned. | ||
| 116 | + | ||
| 117 | + In many cases, the new interfaces will enable more compact code | ||
| 118 | + and will also never generate type warnings. Thanks to M. Holger | ||
| 119 | + for contributing these accessors. Search for ``getValueAs`` in | ||
| 120 | + :file:`include/qpdf/QPDFObjectHandle.hh` for a complete list. | ||
| 121 | + | ||
| 122 | + These are also exposed in the C API in functions whose names | ||
| 123 | + start with ``qpdf_oh_get_value_as``. | ||
| 124 | + | ||
| 125 | + - New convenience methods in ``QPDFObjectHandle``: | ||
| 126 | + ``isDictionaryOfType``, ``isStreamOfType``, and | ||
| 127 | + ``isNameAndEquals`` allow more compact querying of dictionaries. | ||
| 128 | + Also added to the C API: ``qpdf_oh_is_dictionary_of_type`` and | ||
| 129 | + ``qpdf_oh_is_name_and_equals``. Thanks to M. Holger for the | ||
| 130 | + contribution. | ||
| 131 | + | ||
| 132 | + - New functions added to ``QUtil``: ``make_shared_cstr`` and | ||
| 133 | + ``make_unique_cstr`` copy ``std::string`` to | ||
| 134 | + ``std::shared_ptr<char>`` and ``std::unique_ptr<char[]>``. These | ||
| 135 | + are alternatives to the existing ``QUtil::copy_string`` function | ||
| 136 | + which offer other ways to get a C string with safer memory | ||
| 137 | + management. | ||
| 138 | + | ||
| 139 | + - New function ``QUtil::file_can_be_opened`` tests to see whether | ||
| 140 | + a file can actually be opened by attempting to open it and close | ||
| 141 | + it again. | ||
| 142 | + | ||
| 143 | + - There is a new version of ``QUtil::call_main_from_wmain`` that | ||
| 144 | + takes a ``const`` argv array and calls a main that takes a | ||
| 145 | + ``const`` argv array. | ||
| 146 | + | ||
| 147 | + - ``QPDF::emptyPDF`` has been exposed to the C API as | ||
| 148 | + ``qpdf_empty_pdf``. This makes it possible to create PDF from | ||
| 149 | + scratch with the C API. | ||
| 150 | + | ||
| 151 | + - New C API functions ``qpdf_oh_get_binary_utf8_value`` and | ||
| 152 | + ``qpdf_oh_new_binary_unicode_string`` take length parameters, | ||
| 153 | + which makes it possible to handle UTF-8-encoded C strings with | ||
| 154 | + embedded NUL characters. Thanks to M. Holger for the | ||
| 155 | + contribution. | ||
| 156 | + | ||
| 157 | + - The ``JSON`` object in the qpdf library has been enhanced to | ||
| 158 | + include a parser and the ability to get values out of the | ||
| 159 | + ``JSON`` object. Previously it was a write-only interface. Even | ||
| 160 | + so, qpdf's ``JSON`` object is not intended to be a | ||
| 161 | + general-purpose JSON implementation as discussed in | ||
| 162 | + :file:`include/qpdf/JSON.hh`. | ||
| 163 | + | ||
| 164 | + - The ``JSON`` object's "schema" checking functionality now allows | ||
| 165 | + for optional keys. Note that this "schema" functionality doesn't | ||
| 166 | + conform to any type of standard. It's just there to help with | ||
| 167 | + error reporting with qpdf's own JSON support. | ||
| 168 | + | ||
| 169 | + - Documentation Enhancements | ||
| 170 | + | ||
| 171 | + - Documentation for the command-line tool has been completely | ||
| 172 | + rewritten. This includes a top-to-bottom rewrite of :ref:`using` | ||
| 173 | + in the manual. Command-line arguments are now indexed, and | ||
| 174 | + internal links can appear to them within the documentation. | ||
| 175 | + | ||
| 176 | + - The output of ``qpdf --help`` is generated from the manual and | ||
| 177 | + is divided into help topics that parallel the sections of the | ||
| 178 | + manual. When you run ``qpdf --help``, instead of getting a Great | ||
| 179 | + Wall of Text, you are given basic usage information and a list | ||
| 180 | + of help topics. It is possible to request help for any | ||
| 181 | + individual topic or any specific command-line option, or you can | ||
| 182 | + get a dump of all available help text. The manual continues to | ||
| 183 | + contain a greater level of detail and more examples. | ||
| 184 | + | ||
| 185 | + - Bug Fixes | ||
| 186 | + | ||
| 187 | + - Some characters were not correctly translated from PDF doc | ||
| 188 | + encoding to Unicode. | ||
| 189 | + | ||
| 9 | 10.5.0: December 21, 2021 | 190 | 10.5.0: December 21, 2021 |
| 10 | - Packaging changes | 191 | - Packaging changes |
| 11 | 192 |