Commit 7fb22740e131d997fb68bc113b8d9b4472e2c908
1 parent
b48a0ff0
Add operator ""_qpdf for creating QPDFObjectHandle literals
Showing
14 changed files
with
57 additions
and
48 deletions
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 |
TODO
| @@ -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& dh, QPDFObjectHandle font, | @@ -182,12 +182,11 @@ void add_page(QPDFPageDocumentHelper& 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& dh, QPDFObjectHandle font, | @@ -199,8 +198,7 @@ void add_page(QPDFPageDocumentHelper& 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& pdf, char const* arg2) | @@ -1255,10 +1255,8 @@ static void test_31(QPDF& 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)); |