Commit eb481eb698947d88be0724e84f518a70a0468cc9

Authored by Jay Berkenbilt
1 parent c95f0211

Prepare release notes for 10.6 (so far)

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
@@ -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
@@ -74,6 +74,7 @@ @@ -74,6 +74,7 @@
74 "cxxflags", 74 "cxxflags",
75 "cygwin", 75 "cygwin",
76 "dctdecode", 76 "dctdecode",
  77 + "decltype",
77 "decrypter", 78 "decrypter",
78 "deduplicating", 79 "deduplicating",
79 "deps", 80 "deps",
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