Commit 7fb22740e131d997fb68bc113b8d9b4472e2c908

Authored by Jay Berkenbilt
1 parent b48a0ff0

Add operator ""_qpdf for creating QPDFObjectHandle literals

ChangeLog
1 2022-02-05 Jay Berkenbilt <ejb@ql.org> 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 * Expose QPDF::emptyPDF to the C API as qpdf_empty_pdf() 9 * Expose QPDF::emptyPDF to the C API as qpdf_empty_pdf()
4 10
5 * Add comments letting people know that the version string 11 * Add comments letting people know that the version string
@@ -11,9 +11,6 @@ @@ -11,9 +11,6 @@
11 11
12 * QPDFObjectHandle: getValueAsX methods, getKeyIfDict. Plus C API. 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 * See if this has been done or is trivial with C++11 local static 14 * See if this has been done or is trivial with C++11 local static
18 initializers: Secure random number generation could be made more 15 initializers: Secure random number generation could be made more
19 efficient by using a local static to ensure a single random device 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,16 +36,16 @@ static void process(char const* infilename, char const* password,
36 QPDF q; 36 QPDF q;
37 q.processFile(infilename, password); 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 auto f1 = q.makeIndirectObject( 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 // Create a resources dictionary with fonts. This uses the new 50 // Create a resources dictionary with fonts. This uses the new
51 // parse introduced in qpdf 10.2 that takes a QPDF* and allows 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,7 +93,7 @@ static void process(char const* infilename, char const* password,
93 apdict.replaceKey("/Resources", QPDFObjectHandle::newDictionary()); 93 apdict.replaceKey("/Resources", QPDFObjectHandle::newDictionary());
94 apdict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject")); 94 apdict.replaceKey("/Type", QPDFObjectHandle::newName("/XObject"));
95 apdict.replaceKey("/Subtype", QPDFObjectHandle::newName("/Form")); 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 auto annot = q.makeIndirectObject( 97 auto annot = q.makeIndirectObject(
98 QPDFObjectHandle::parse( 98 QPDFObjectHandle::parse(
99 &q, 99 &q,
examples/pdf-create.cc
@@ -182,12 +182,11 @@ void add_page(QPDFPageDocumentHelper&amp; dh, QPDFObjectHandle font, @@ -182,12 +182,11 @@ void add_page(QPDFPageDocumentHelper&amp; dh, QPDFObjectHandle font,
182 size_t width = p->getWidth(); 182 size_t width = p->getWidth();
183 size_t height = p->getHeight(); 183 size_t height = p->getHeight();
184 QPDFObjectHandle image = QPDFObjectHandle::newStream(&pdf); 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 QPDFObjectHandle image_dict = image.getDict(); 190 QPDFObjectHandle image_dict = image.getDict();
192 image_dict.replaceKey("/ColorSpace", newName(color_space)); 191 image_dict.replaceKey("/ColorSpace", newName(color_space));
193 image_dict.replaceKey("/Width", newInteger(width)); 192 image_dict.replaceKey("/Width", newInteger(width));
@@ -199,8 +198,7 @@ void add_page(QPDFPageDocumentHelper&amp; dh, QPDFObjectHandle font, @@ -199,8 +198,7 @@ void add_page(QPDFPageDocumentHelper&amp; dh, QPDFObjectHandle font,
199 QPDFObjectHandle::newNull()); 198 QPDFObjectHandle::newNull());
200 199
201 // Create direct objects as needed by the page dictionary. 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 QPDFObjectHandle rfont = QPDFObjectHandle::newDictionary(); 203 QPDFObjectHandle rfont = QPDFObjectHandle::newDictionary();
206 rfont.replaceKey("/F1", font); 204 rfont.replaceKey("/F1", font);
@@ -384,14 +382,13 @@ static void create_pdf(char const* filename) @@ -384,14 +382,13 @@ static void create_pdf(char const* filename)
384 // Add an indirect object to contain a font descriptor for the 382 // Add an indirect object to contain a font descriptor for the
385 // built-in Helvetica font. 383 // built-in Helvetica font.
386 QPDFObjectHandle font = pdf.makeIndirectObject( 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 std::vector<std::string> color_spaces; 393 std::vector<std::string> color_spaces;
397 color_spaces.push_back("/DeviceCMYK"); 394 color_spaces.push_back("/DeviceCMYK");
examples/pdf-overlay-page.cc
@@ -65,8 +65,7 @@ static void stamp_page(char const* infile, @@ -65,8 +65,7 @@ static void stamp_page(char const* infile,
65 // Append the content to the page's content. Surround the 65 // Append the content to the page's content. Surround the
66 // original content with q...Q to the new content from the 66 // original content with q...Q to the new content from the
67 // page's original content. 67 // page's original content.
68 - resources.mergeResources(  
69 - QPDFObjectHandle::parse("<< /XObject << >> >>")); 68 + resources.mergeResources("<< /XObject << >> >>"_qpdf);
70 resources.getKey("/XObject").replaceKey(name, stamp_fo); 69 resources.getKey("/XObject").replaceKey(name, stamp_fo);
71 ph.addPageContents( 70 ph.addPageContents(
72 QPDFObjectHandle::newStream(&inpdf, "q\n"), true); 71 QPDFObjectHandle::newStream(&inpdf, "q\n"), true);
include/qpdf/QPDFObjectHandle.hh
@@ -395,7 +395,7 @@ class QPDFObjectHandle @@ -395,7 +395,7 @@ class QPDFObjectHandle
395 // object syntax (obj gen R) will cause a logic_error exception to 395 // object syntax (obj gen R) will cause a logic_error exception to
396 // be thrown. If object_description is provided, it will appear 396 // be thrown. If object_description is provided, it will appear
397 // in the message of any QPDFExc exception thrown for invalid 397 // in the message of any QPDFExc exception thrown for invalid
398 - // syntax. 398 + // syntax. See also the global `operator ""_qpdf` defined below.
399 QPDF_DLL 399 QPDF_DLL
400 static QPDFObjectHandle parse(std::string const& object_str, 400 static QPDFObjectHandle parse(std::string const& object_str,
401 std::string const& object_description = ""); 401 std::string const& object_description = "");
@@ -1450,6 +1450,17 @@ class QPDFObjectHandle @@ -1450,6 +1450,17 @@ class QPDFObjectHandle
1450 bool reserved; 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 class QPDFObjectHandle::QPDFDictItems 1464 class QPDFObjectHandle::QPDFDictItems
1454 { 1465 {
1455 // This class allows C++-style iteration, including range-for 1466 // This class allows C++-style iteration, including range-for
libqpdf/QPDFFormFieldObjectHelper.cc
@@ -981,8 +981,7 @@ QPDFFormFieldObjectHelper::generateTextAppearance( @@ -981,8 +981,7 @@ QPDFFormFieldObjectHelper::generateTextAppearance(
981 AS.getDict().replaceKey("/Resources", resources); 981 AS.getDict().replaceKey("/Resources", resources);
982 } 982 }
983 // Use mergeResources to force /Font to be local 983 // Use mergeResources to force /Font to be local
984 - resources.mergeResources(  
985 - QPDFObjectHandle::parse("<< /Font << >> >>")); 984 + resources.mergeResources("<< /Font << >> >>"_qpdf);
986 resources.getKey("/Font").replaceKey(font_name, font); 985 resources.getKey("/Font").replaceKey(font_name, font);
987 } 986 }
988 987
libqpdf/QPDFJob.cc
@@ -2281,8 +2281,7 @@ QPDFJob::doUnderOverlayForPage( @@ -2281,8 +2281,7 @@ QPDFJob::doUnderOverlayForPage(
2281 from_page, cm, dest_afdh, make_afdh(from_page)); 2281 from_page, cm, dest_afdh, make_afdh(from_page));
2282 if (! new_content.empty()) 2282 if (! new_content.empty())
2283 { 2283 {
2284 - resources.mergeResources(  
2285 - QPDFObjectHandle::parse("<< /XObject << >> >>")); 2284 + resources.mergeResources("<< /XObject << >> >>"_qpdf);
2286 auto xobject = resources.getKey("/XObject"); 2285 auto xobject = resources.getKey("/XObject");
2287 if (xobject.isDictionary()) 2286 if (xobject.isDictionary())
2288 { 2287 {
libqpdf/QPDFNameTreeObjectHelper.cc
@@ -61,8 +61,7 @@ QPDFNameTreeObjectHelper @@ -61,8 +61,7 @@ QPDFNameTreeObjectHelper
61 QPDFNameTreeObjectHelper::newEmpty(QPDF& qpdf, bool auto_repair) 61 QPDFNameTreeObjectHelper::newEmpty(QPDF& qpdf, bool auto_repair)
62 { 62 {
63 return QPDFNameTreeObjectHelper( 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 QPDFNameTreeObjectHelper::iterator::iterator( 67 QPDFNameTreeObjectHelper::iterator::iterator(
libqpdf/QPDFNumberTreeObjectHelper.cc
@@ -58,8 +58,7 @@ QPDFNumberTreeObjectHelper @@ -58,8 +58,7 @@ QPDFNumberTreeObjectHelper
58 QPDFNumberTreeObjectHelper::newEmpty(QPDF& qpdf, bool auto_repair) 58 QPDFNumberTreeObjectHelper::newEmpty(QPDF& qpdf, bool auto_repair)
59 { 59 {
60 return QPDFNumberTreeObjectHelper( 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 QPDFNumberTreeObjectHelper::iterator::iterator( 64 QPDFNumberTreeObjectHelper::iterator::iterator(
libqpdf/QPDFObjectHandle.cc
@@ -3666,3 +3666,10 @@ QPDFObjectHandle::QPDFArrayItems::end() @@ -3666,3 +3666,10 @@ QPDFObjectHandle::QPDFArrayItems::end()
3666 { 3666 {
3667 return iterator(oh, false); 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,8 +161,7 @@ QPDFPageDocumentHelper::flattenAnnotationsForPage(
161 name, rotate, required_flags, forbidden_flags); 161 name, rotate, required_flags, forbidden_flags);
162 if (! content.empty()) 162 if (! content.empty())
163 { 163 {
164 - resources.mergeResources(  
165 - QPDFObjectHandle::parse("<< /XObject << >> >>")); 164 + resources.mergeResources("<< /XObject << >> >>"_qpdf);
166 resources.getKey("/XObject").replaceKey(name, as); 165 resources.getKey("/XObject").replaceKey(name, as);
167 ++next_fx; 166 ++next_fx;
168 } 167 }
libqpdf/QPDFPageObjectHelper.cc
@@ -500,8 +500,7 @@ QPDFPageObjectHelper::externalizeInlineImages(size_t min_size, bool shallow) @@ -500,8 +500,7 @@ QPDFPageObjectHelper::externalizeInlineImages(size_t min_size, bool shallow)
500 QPDFObjectHandle resources = getAttribute("/Resources", true); 500 QPDFObjectHandle resources = getAttribute("/Resources", true);
501 // Calling mergeResources also ensures that /XObject becomes 501 // Calling mergeResources also ensures that /XObject becomes
502 // direct and is not shared with other pages. 502 // direct and is not shared with other pages.
503 - resources.mergeResources(  
504 - QPDFObjectHandle::parse("<< /XObject << >> >>")); 503 + resources.mergeResources("<< /XObject << >> >>"_qpdf);
505 InlineImageTracker iit(this->oh.getOwningQPDF(), min_size, resources); 504 InlineImageTracker iit(this->oh.getOwningQPDF(), min_size, resources);
506 Pl_Buffer b("new page content"); 505 Pl_Buffer b("new page content");
507 bool filtered = false; 506 bool filtered = false;
qpdf/test_driver.cc
@@ -1255,10 +1255,8 @@ static void test_31(QPDF&amp; pdf, char const* arg2) @@ -1255,10 +1255,8 @@ static void test_31(QPDF&amp; pdf, char const* arg2)
1255 { 1255 {
1256 // Test object parsing from a string. The input file is not used. 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 std::cout << o1.unparse() << std::endl; 1260 std::cout << o1.unparse() << std::endl;
1263 QPDFObjectHandle o2 = QPDFObjectHandle::parse(" 12345 \f "); 1261 QPDFObjectHandle o2 = QPDFObjectHandle::parse(" 12345 \f ");
1264 assert(o2.isInteger() && (o2.getIntValue() == 12345)); 1262 assert(o2.isInteger() && (o2.getIntValue() == 12345));