Commit 7fb22740e131d997fb68bc113b8d9b4472e2c908

Authored by Jay Berkenbilt
1 parent b48a0ff0

Add operator ""_qpdf for creating QPDFObjectHandle literals

ChangeLog
1 1 2022-02-05 Jay Berkenbilt <ejb@ql.org>
2 2  
  3 + * Add a global user-defined string literal "_qpdf" as a shorthand
  4 + for QPDFObjectHandle::parse, allowing you to create
  5 + QPDFObjectHandle objects with
  6 +
  7 + QPDFObjectHandle oh = "<</Some (PDF)>>"_qpdf;
  8 +
3 9 * Expose QPDF::emptyPDF to the C API as qpdf_empty_pdf()
4 10  
5 11 * Add comments letting people know that the version string
... ...
... ... @@ -11,9 +11,6 @@
11 11  
12 12 * QPDFObjectHandle: getValueAsX methods, getKeyIfDict. Plus C API.
13 13  
14   -* Add user-defined initializer `QPDFObjectHandle operator ""_qpdf` to
15   - be like QPDFObjectHandle::parse: `auto oh = "<< /a (b) >>"_qpdf;`
16   -
17 14 * See if this has been done or is trivial with C++11 local static
18 15 initializers: Secure random number generation could be made more
19 16 efficient by using a local static to ensure a single random device
... ...
examples/pdf-attach-file.cc
... ... @@ -36,16 +36,16 @@ static void process(char const* infilename, char const* password,
36 36 QPDF q;
37 37 q.processFile(infilename, password);
38 38  
39   - // Create an indirect object for the built-in Helvetica font.
  39 + // Create an indirect object for the built-in Helvetica font. This
  40 + // uses the qpdf literal syntax introduced in qpdf 10.6.
40 41 auto f1 = q.makeIndirectObject(
41   - QPDFObjectHandle::parse(
42   - "<<"
43   - " /Type /Font"
44   - " /Subtype /Type1"
45   - " /Name /F1"
46   - " /BaseFont /Helvetica"
47   - " /Encoding /WinAnsiEncoding"
48   - ">>"));
  42 + "<<"
  43 + " /Type /Font"
  44 + " /Subtype /Type1"
  45 + " /Name /F1"
  46 + " /BaseFont /Helvetica"
  47 + " /Encoding /WinAnsiEncoding"
  48 + ">>"_qpdf);
49 49  
50 50 // Create a resources dictionary with fonts. This uses the new
51 51 // parse introduced in qpdf 10.2 that takes a QPDF* and allows
... ... @@ -93,7 +93,7 @@ static void process(char const* infilename, char const* password,
93 93 apdict.replaceKey("/Resources", QPDFObjectHandle::newDictionary());
94 94 apdict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject"));
95 95 apdict.replaceKey("/Subtype", QPDFObjectHandle::newName("/Form"));
96   - apdict.replaceKey("/BBox", QPDFObjectHandle::parse("[ 0 0 20 20 ]"));
  96 + apdict.replaceKey("/BBox", "[ 0 0 20 20 ]"_qpdf);
97 97 auto annot = q.makeIndirectObject(
98 98 QPDFObjectHandle::parse(
99 99 &q,
... ...
examples/pdf-create.cc
... ... @@ -182,12 +182,11 @@ void add_page(QPDFPageDocumentHelper&amp; dh, QPDFObjectHandle font,
182 182 size_t width = p->getWidth();
183 183 size_t height = p->getHeight();
184 184 QPDFObjectHandle image = QPDFObjectHandle::newStream(&pdf);
185   - image.replaceDict(QPDFObjectHandle::parse(
186   - "<<"
187   - " /Type /XObject"
188   - " /Subtype /Image"
189   - " /BitsPerComponent 8"
190   - ">>"));
  185 + image.replaceDict("<<"
  186 + " /Type /XObject"
  187 + " /Subtype /Image"
  188 + " /BitsPerComponent 8"
  189 + ">>"_qpdf);
191 190 QPDFObjectHandle image_dict = image.getDict();
192 191 image_dict.replaceKey("/ColorSpace", newName(color_space));
193 192 image_dict.replaceKey("/Width", newInteger(width));
... ... @@ -199,8 +198,7 @@ void add_page(QPDFPageDocumentHelper&amp; dh, QPDFObjectHandle font,
199 198 QPDFObjectHandle::newNull());
200 199  
201 200 // Create direct objects as needed by the page dictionary.
202   - QPDFObjectHandle procset = QPDFObjectHandle::parse(
203   - "[/PDF /Text /ImageC]");
  201 + QPDFObjectHandle procset = "[/PDF /Text /ImageC]"_qpdf;
204 202  
205 203 QPDFObjectHandle rfont = QPDFObjectHandle::newDictionary();
206 204 rfont.replaceKey("/F1", font);
... ... @@ -384,14 +382,13 @@ static void create_pdf(char const* filename)
384 382 // Add an indirect object to contain a font descriptor for the
385 383 // built-in Helvetica font.
386 384 QPDFObjectHandle font = pdf.makeIndirectObject(
387   - QPDFObjectHandle::parse(
388   - "<<"
389   - " /Type /Font"
390   - " /Subtype /Type1"
391   - " /Name /F1"
392   - " /BaseFont /Helvetica"
393   - " /Encoding /WinAnsiEncoding"
394   - ">>"));
  385 + "<<"
  386 + " /Type /Font"
  387 + " /Subtype /Type1"
  388 + " /Name /F1"
  389 + " /BaseFont /Helvetica"
  390 + " /Encoding /WinAnsiEncoding"
  391 + ">>"_qpdf);
395 392  
396 393 std::vector<std::string> color_spaces;
397 394 color_spaces.push_back("/DeviceCMYK");
... ...
examples/pdf-overlay-page.cc
... ... @@ -65,8 +65,7 @@ static void stamp_page(char const* infile,
65 65 // Append the content to the page's content. Surround the
66 66 // original content with q...Q to the new content from the
67 67 // page's original content.
68   - resources.mergeResources(
69   - QPDFObjectHandle::parse("<< /XObject << >> >>"));
  68 + resources.mergeResources("<< /XObject << >> >>"_qpdf);
70 69 resources.getKey("/XObject").replaceKey(name, stamp_fo);
71 70 ph.addPageContents(
72 71 QPDFObjectHandle::newStream(&inpdf, "q\n"), true);
... ...
include/qpdf/QPDFObjectHandle.hh
... ... @@ -395,7 +395,7 @@ class QPDFObjectHandle
395 395 // object syntax (obj gen R) will cause a logic_error exception to
396 396 // be thrown. If object_description is provided, it will appear
397 397 // in the message of any QPDFExc exception thrown for invalid
398   - // syntax.
  398 + // syntax. See also the global `operator ""_qpdf` defined below.
399 399 QPDF_DLL
400 400 static QPDFObjectHandle parse(std::string const& object_str,
401 401 std::string const& object_description = "");
... ... @@ -1450,6 +1450,17 @@ class QPDFObjectHandle
1450 1450 bool reserved;
1451 1451 };
1452 1452  
  1453 +#ifndef QPDF_NO_QPDF_STRING
  1454 +// This is short for QPDFObjectHandle::parse, so you can do
  1455 +
  1456 +// auto oh = "<< /Key (value) >>"_qpdf;
  1457 +
  1458 +// If this is causing problems in your code, define
  1459 +// QPDF_NO_QPDF_STRING to prevent the declaration from being here.
  1460 +QPDF_DLL
  1461 +QPDFObjectHandle operator ""_qpdf(char const* v, size_t len);
  1462 +#endif // QPDF_NO_QPDF_STRING
  1463 +
1453 1464 class QPDFObjectHandle::QPDFDictItems
1454 1465 {
1455 1466 // This class allows C++-style iteration, including range-for
... ...
libqpdf/QPDFFormFieldObjectHelper.cc
... ... @@ -981,8 +981,7 @@ QPDFFormFieldObjectHelper::generateTextAppearance(
981 981 AS.getDict().replaceKey("/Resources", resources);
982 982 }
983 983 // Use mergeResources to force /Font to be local
984   - resources.mergeResources(
985   - QPDFObjectHandle::parse("<< /Font << >> >>"));
  984 + resources.mergeResources("<< /Font << >> >>"_qpdf);
986 985 resources.getKey("/Font").replaceKey(font_name, font);
987 986 }
988 987  
... ...
libqpdf/QPDFJob.cc
... ... @@ -2281,8 +2281,7 @@ QPDFJob::doUnderOverlayForPage(
2281 2281 from_page, cm, dest_afdh, make_afdh(from_page));
2282 2282 if (! new_content.empty())
2283 2283 {
2284   - resources.mergeResources(
2285   - QPDFObjectHandle::parse("<< /XObject << >> >>"));
  2284 + resources.mergeResources("<< /XObject << >> >>"_qpdf);
2286 2285 auto xobject = resources.getKey("/XObject");
2287 2286 if (xobject.isDictionary())
2288 2287 {
... ...
libqpdf/QPDFNameTreeObjectHelper.cc
... ... @@ -61,8 +61,7 @@ QPDFNameTreeObjectHelper
61 61 QPDFNameTreeObjectHelper::newEmpty(QPDF& qpdf, bool auto_repair)
62 62 {
63 63 return QPDFNameTreeObjectHelper(
64   - qpdf.makeIndirectObject(
65   - QPDFObjectHandle::parse("<< /Names [] >>")), qpdf, auto_repair);
  64 + qpdf.makeIndirectObject("<< /Names [] >>"_qpdf), qpdf, auto_repair);
66 65 }
67 66  
68 67 QPDFNameTreeObjectHelper::iterator::iterator(
... ...
libqpdf/QPDFNumberTreeObjectHelper.cc
... ... @@ -58,8 +58,7 @@ QPDFNumberTreeObjectHelper
58 58 QPDFNumberTreeObjectHelper::newEmpty(QPDF& qpdf, bool auto_repair)
59 59 {
60 60 return QPDFNumberTreeObjectHelper(
61   - qpdf.makeIndirectObject(
62   - QPDFObjectHandle::parse("<< /Nums [] >>")), qpdf, auto_repair);
  61 + qpdf.makeIndirectObject("<< /Nums [] >>"_qpdf), qpdf, auto_repair);
63 62 }
64 63  
65 64 QPDFNumberTreeObjectHelper::iterator::iterator(
... ...
libqpdf/QPDFObjectHandle.cc
... ... @@ -3666,3 +3666,10 @@ QPDFObjectHandle::QPDFArrayItems::end()
3666 3666 {
3667 3667 return iterator(oh, false);
3668 3668 }
  3669 +
  3670 +QPDFObjectHandle
  3671 +operator ""_qpdf(char const* v, size_t len)
  3672 +{
  3673 + return QPDFObjectHandle::parse(
  3674 + std::string(v, len), "QPDFObjectHandle literal");
  3675 +}
... ...
libqpdf/QPDFPageDocumentHelper.cc
... ... @@ -161,8 +161,7 @@ QPDFPageDocumentHelper::flattenAnnotationsForPage(
161 161 name, rotate, required_flags, forbidden_flags);
162 162 if (! content.empty())
163 163 {
164   - resources.mergeResources(
165   - QPDFObjectHandle::parse("<< /XObject << >> >>"));
  164 + resources.mergeResources("<< /XObject << >> >>"_qpdf);
166 165 resources.getKey("/XObject").replaceKey(name, as);
167 166 ++next_fx;
168 167 }
... ...
libqpdf/QPDFPageObjectHelper.cc
... ... @@ -500,8 +500,7 @@ QPDFPageObjectHelper::externalizeInlineImages(size_t min_size, bool shallow)
500 500 QPDFObjectHandle resources = getAttribute("/Resources", true);
501 501 // Calling mergeResources also ensures that /XObject becomes
502 502 // direct and is not shared with other pages.
503   - resources.mergeResources(
504   - QPDFObjectHandle::parse("<< /XObject << >> >>"));
  503 + resources.mergeResources("<< /XObject << >> >>"_qpdf);
505 504 InlineImageTracker iit(this->oh.getOwningQPDF(), min_size, resources);
506 505 Pl_Buffer b("new page content");
507 506 bool filtered = false;
... ...
qpdf/test_driver.cc
... ... @@ -1255,10 +1255,8 @@ static void test_31(QPDF&amp; pdf, char const* arg2)
1255 1255 {
1256 1256 // Test object parsing from a string. The input file is not used.
1257 1257  
1258   - QPDFObjectHandle o1 =
1259   - QPDFObjectHandle::parse(
1260   - "[/name 16059 3.14159 false\n"
1261   - " << /key true /other [ (string1) (string2) ] >> null]");
  1258 + auto o1 = "[/name 16059 3.14159 false\n"
  1259 + " << /key true /other [ (string1) (string2) ] >> null]"_qpdf;
1262 1260 std::cout << o1.unparse() << std::endl;
1263 1261 QPDFObjectHandle o2 = QPDFObjectHandle::parse(" 12345 \f ");
1264 1262 assert(o2.isInteger() && (o2.getIntValue() == 12345));
... ...